-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsimple-plasmid-construction.aq
1 lines (1 loc) · 429 KB
/
simple-plasmid-construction.aq
1
{"config":{"title":"UW BIOFAB Simple Plasmid Construction","description":"A workflow for constructing plasmids","copyright":"University of Washington","version":"0.0.1","authors":[{"name":"Tileli Amimeur","affiliation":"University of Washington"},{"name":"Nick Bolten","affilation":"","affiliation":"University of Washington"},{"name":"Leandra Brettner","affilation":"","affiliation":"University of Washington"},{"name":"Cameron Cordray","affilation":"","affiliation":"University of Washington"},{"name":"Miles Gander","affilation":"","affiliation":"University of Washington"},{"name":"Samer Halabiya","affilation":"","affiliation":"University of Washington"},{"name":"Seunghee Jang","affilation":"","affiliation":"University of Washington"},{"name":"Yokesh Jayakumar","affilation":"","affiliation":"University of Washington"},{"name":"Jon Luntzel","affilation":"","affiliation":"University of Washington"},{"name":"Abraham Miller","affilation":"","affiliation":"University of Washington"},{"name":"Garrett Newman","affilation":"","affiliation":"University of Washington"},{"name":"Michelle Parks","affilation":"","affiliation":"University of Washington"},{"name":"Sundipta Rao","affilation":"","affiliation":"University of Washington"},{"name":"Ayesha Saleem","affilation":"","affiliation":"University of Washington"},{"name":"Chris Takahashi","affilation":"","affiliation":"University of Washington"},{"name":"Yaoyu Yang","affilation":"","affiliation":"University of Washington"},{"name":"David Younger","affilation":"","affiliation":"University of Washington"}],"maintainer":{"name":"Ben Keller","email":"[email protected]"},"acknowledgements":[{"name":"Devin Strickland","affiliation":"University of Washington"}],"github":{"user":"bjkeller","repo":"simple-plasmid-construction","organization":"klavinslab"},"keywords":["Cloning, molecular biology, plasmid, DNA"],"aquadoc_version":"1.0.0","aquarium_version":"\u003c%= Bioturk::Application.config.aquarium_version %\u003e"},"components":[{"sample_types":[{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":1,"parent_id":1,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":2,"parent_id":1,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":3,"parent_id":1,"name":"Template","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":1,"field_type_id":3,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":2,"field_type_id":3,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":3,"field_type_id":3,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":4,"field_type_id":3,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":5,"field_type_id":3,"sample_type_id":6,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Plasmid","E coli strain","Fragment","Yeast Strain","DNA Library"],"object_types":[null,null,null,null,null]},{"id":4,"parent_id":1,"name":"Forward Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":6,"field_type_id":4,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":7,"field_type_id":4,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":5,"parent_id":1,"name":"Reverse Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":8,"field_type_id":5,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":9,"field_type_id":5,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":6,"parent_id":1,"name":"Restriction Enzyme(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":7,"parent_id":1,"name":"Yeast Marker","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":8,"parent_id":1,"name":"Fragment Mix Array","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":10,"field_type_id":8,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":11,"field_type_id":8,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]}]},{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":9,"parent_id":2,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":10,"parent_id":2,"name":"Sequence Verification","ftype":"url","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":11,"parent_id":2,"name":"Bacterial Marker","ftype":"string","choices":"Amp,Kan,Amp + Kan,Spec,Kan + Spec,Chlor,Tet,NA,Other","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":12,"parent_id":2,"name":"Yeast Marker","ftype":"string","choices":"HIS,TRP,URA,LEU,NatMX,KanMX,HygMX,BleoMX,5FOA,NA,Other","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":12,"field_type_id":12,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":13,"parent_id":2,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":14,"parent_id":2,"name":"Sequencing Primers","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":13,"field_type_id":14,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":15,"parent_id":2,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":14,"field_type_id":15,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":16,"parent_id":2,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":15,"field_type_id":16,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":17,"parent_id":2,"name":"QC_length","ftype":"number","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":18,"parent_id":2,"name":"Transformation Temperature","ftype":"number","choices":"37,30","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":19,"parent_id":3,"name":"Overhang Sequence","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":20,"parent_id":3,"name":"Anneal Sequence","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":21,"parent_id":3,"name":"T Anneal","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":22,"parent_id":4,"name":"Parent","ftype":"sample","choices":null,"array":null,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":16,"field_type_id":22,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["E coli strain"],"object_types":[null]}]},{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":23,"parent_id":5,"name":"Parent","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":17,"field_type_id":23,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]},{"id":24,"parent_id":5,"name":"Integrant","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":18,"field_type_id":24,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":19,"field_type_id":24,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid","Fragment"],"object_types":[null,null]},{"id":25,"parent_id":5,"name":"Plasmid","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":20,"field_type_id":25,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid"],"object_types":[null]},{"id":26,"parent_id":5,"name":"Integrated Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":27,"parent_id":5,"name":"Plasmid Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":28,"parent_id":5,"name":"Mating Type","ftype":"string","choices":"MATa,MATalpha,Diploid","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":29,"parent_id":5,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":21,"field_type_id":29,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":30,"parent_id":5,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":22,"field_type_id":30,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":31,"parent_id":5,"name":"QC_length","ftype":"number","choices":"","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":32,"parent_id":5,"name":"Comp_cell_limit","ftype":"string","choices":"Yes,No","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":33,"parent_id":5,"name":"Media","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":34,"parent_id":5,"name":"Has this strain passed QC?","ftype":"string","choices":"No,Yes","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":35,"parent_id":5,"name":"Haploids","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":23,"field_type_id":35,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]}]},{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":36,"parent_id":6,"name":"Oligo Pool","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":24,"field_type_id":36,"sample_type_id":7,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Oligo Pool"],"object_types":[null]}]},{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":37,"parent_id":7,"name":"Manufacturer","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":38,"parent_id":7,"name":"Oligo Library ID","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":39,"parent_id":7,"name":"inner forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":25,"field_type_id":39,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":40,"parent_id":7,"name":"inner reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":26,"field_type_id":40,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":41,"parent_id":7,"name":"sublibrary forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":27,"field_type_id":41,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":42,"parent_id":7,"name":"sublibrary reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":28,"field_type_id":42,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":43,"parent_id":7,"name":"min length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":44,"parent_id":7,"name":"max length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":45,"parent_id":7,"name":"variants (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":46,"parent_id":7,"name":"sublibrary name (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":47,"parent_id":7,"name":"forward priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":48,"parent_id":7,"name":"reverse priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]}],"object_types":[{"id":3,"name":"Fragment Stock","description":"Fragment stock in 1.5 mL tube, usually stored in M20 fridge.","min":0,"max":1000,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Fragment","cost":50.0,"release_method":"return","release_description":"","sample_type_id":1,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Fragment"},{"id":4,"name":"Gibson Reaction Result","description":"A plasmid that was made from Gibson reaction and stayed in the Gibson reaction tube. One can use this to do transform and extract the plasmid.","min":0,"max":1000,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":10.0,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"}],"operation_type":{"name":"Assemble Plasmid Gibson","category":"Cloning","deployed":false,"on_the_fly":false,"field_types":[{"ftype":"sample","role":"input","name":"Fragment","sample_types":["Fragment"],"object_types":["Fragment Stock"],"part":false,"array":true,"routing":"F","preferred_operation_type_id":24,"preferred_field_type_id":109,"choices":null},{"ftype":"sample","role":"output","name":"Assembled Plasmid","sample_types":["Plasmid"],"object_types":["Gibson Reaction Result"],"part":false,"array":false,"routing":"P","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"# Author: Ayesha Saleem\n# December 20, 2016\n\nrequire 'matrix'\nneeds \"Cloning Libs/Special Days\"\nneeds \"Cloning Libs/Cloning\"\nneeds \"Standard Libs/Feedback\"\n# For calculating equimolar concentrations, Yaoyu has written up a great explanation: \n\n # math behind the equimolar volume calculation\n # Assume that there are n fragment stocks, each with concentrations c1,..., cn, and lengths l1,...,ln. The volumes of each fragment stocks to add in the Gibson reaction is denoted as v1,...,vn. Assuming that the molecular weight (g/mol) of the fragment is proportional to the lenght of the fragment, to ensure equimolar of these n fragment stocks, the following must satisfy:\n # v1 + ... + vn = 5 (the total gibson reaction volume)\n # v1 * c1 / l1 = ... = vn * cn / ln (they're equimolar)\n # unit of v is uL, unit of c is g/uL, unit of l1 (molecular weight) is g/mol\n # thus v * c / l represent the moles of the fragment stock, and esuring v1 * c1 / l1 = ... = vn * cn / ln lead to equimolar fragment stocks.\n # These mathmatical constraints can be reformated as:\n # v1 + ... + vn = 5\n # v1 * c1 / l1 - v2 * c2 / l2 = 0\n # v1 * c1 / l1 - v3 * c3 / l3 = 0\n # ...\n # v1 * c1 / l1 - vn * cn / ln = 0\n # The following matrix equations hold:\n # coefficient_matrix * fragment_volumes = total_vector,\n # where \n # coefficient_matrix = [\n # [1, 1, ..., 1]\n # [c1 / l1, -c2 / l2, ..., 0]\n # [c1 / l1, 0, - c3 / l3 ..., 0]\n # ...\n # [c1 / l1, 0, ..., - vn * cn / ln]\n # ] (n x n matrix)\n # fragment_volumes = [[v1], [v2], ..., [vn]] (n x 1 matrix)\n # total_vector = [[5], [0], ..., [0]] (n x 1 matrix)\n # matrix multiplication\n # coefficient_matrix.inv * coefficient_matrix * fragment_volumes = coefficient_matrix.inv * total_vector\n # Therefore we have\n # fragment_volumes = coefficient_matrix.inv * total_vector\n\n# NEED TO TEST: \n # ensuring volume\n # replacing fragment stock\n\nclass Protocol\n include Cloning, Feedback, SpecialDays\n debug = false\n \n # this builds a matrix with 1's in the first row\n # the concentration over length (c / l) of the fragment when row = column\n # (with alternating sign) and 0's everywhere else\n def main\n \n # Check for valid fragment lengths\n operations.each do |op|\n fragments_fv = op.input_array(\"Fragment\")\n fragments_fv.each do |fragment|\n if fragment.item.sample.properties[\"Length\"].nil?\n op.error :invalid_length, \"This fragment's length is not valid.\"\n end\n end\n end\n \n # Take fragments\n operations.retrieve\n operations.make\n\n check_concentration operations, \"Fragment\"\n \n temp = operations.running\n operations = temp\n \n #TODO: refactor gibson batch finding algorithm, gib_batch instantiation is uneccessarily long\n # determine which batches to grab gibson aliquots from\n gib_batch = Collection.where(object_type_id: ObjectType.find_by_name(\"Gibson Aliquot Batch\").id).where('location != ?', \"deleted\").first\n if gib_batch.nil?\n operations.each { |op| op.error :not_enough_gibson, \"There were not enough gibson aliquots to complete the operation.\" }\n raise \"not enough gibson\"\n end\n batch_id_array = [gib_batch.id]\n total_aliquots = gib_batch.num_samples\n aliquots_needed = operations.length\n i = 0\n while total_aliquots \u003c aliquots_needed\n gib_batch.mark_as_deleted \n i += 1\n gib_batch = Collection.where(object_type_id: ObjectType.find_by_name(\"Gibson Aliquot Batch\").id).where('location != ?', \"deleted\").first\n if gib_batch.nil?\n operations.each { |op| op.error :not_enough_gibson, \"There were not enough gibson aliquots to complete the operation.\" }\n raise \"Aquarium cannot find any gibson aliquot batches in the system\"\n end\n batch_id_array.push(gib_batch.id)\n total_aliquots += gib_batch.num_samples\n end\n \n #fetch gibson aliquots\n get_gibson_aliquots batch_id_array\n \n # Go through and pipette fragments into aliquots\n to_discard = []\n \n # Keep track of fragment stocks to return on errored ops.\n to_return = [];\n \n operations.each do |op|# calculate how much of each fragment is needed in aliquot\n tot_f_vol, f_vol = calc_gibson_volumes op\n vol_table = [[\"Fragment Stock IDs\", \"Volume\"]].concat(op.input_array(\"Fragment\").items.collect { |f| f.id}.zip f_vol.map { |v| { content: v, check: true }})\n \n # ask tech if there is enough volume\n vol_checking = show do \n title \"Checking Volumes\"\n tot_f_vol.each do |id, v|\n select [\"Yes\", \"No\"], var: \"v#{id}\", label: \"Does #{id} have at least #{v} uL?\", default: 0\n end\n end\n \n # find replacements\n replacement = {}\n \n tot_f_vol.each do |id, v|\n if vol_checking[\"v#{id}\".to_sym] == \"No\"\n find_replacements replacement, to_discard, id, v\n end\n end\n \n # associate replacements with operation inputs\n find_replacement = []\n associate_replacements find_replacement, replacement, op\n \n if op.status != \"error\"\n # take find_replacement, interactive: true if find_replacement.any?\n check_concentration [op], \"Fragment\"\n \n #feature addition: make an extra column for this table to show whether a p2 pipette is required depending on if vol \u003c 0.5\n if find_replacement.any?\n tot_f_vol, f_vol = calc_gibson_volumes op\n vol_table = [[\"Fragment Stock IDs\", \"Volume\"]].concat(op.input_array(\"Fragment\").items.collect { |f| f.id}.zip f_vol.map { |v| { content: v, check: true }})\n end\n load_gibson_reaction op, vol_table\n else\n \n # Keep track of what items need to be returned in the case of an error.\n current_fv = op.input_array(\"Fragment\")\n current_fv.each do |fv|\n if fv.item.location != \"deleted\"\n to_return.push(fv.item)\n end\n end\n \n show do\n title \"Gibson canceled\"\n note \"Sorry it had to be this way. :/\"\n end\n end\n end\n \n # put on heat block\n heat_block\n \n #return gibson aliquots\n data = return_gibson_aliquots aliquots_needed, batch_id_array\n aliquots_returned = data[:n]\n \n #updating gibson batches\n gibsons_used = aliquots_needed - aliquots_returned.to_i\n update_gibson_batches gibsons_used, batch_id_array\n \n # return aluminum tube rack, ice block\n return_aluminumTubeRack_and_iceBlock\n \n # return fragments\n release(to_return, interactive: true)\n operations.store(io: \"input\", interactive: true, method: \"boxes\")\n \n show do\n title \"Discard depleted stocks\"\n note \"Discard the following stocks: #{to_discard.map { |s| s.id }}\"\n end if to_discard.any?\n \n get_protocol_feedback()\n give_happy_birthday\n \n return {}\n end\n \n def gibson_coefficients row, col, conc_over_length\n # TODO fix this commented out section (only causes error when not debugging)\n # if !debug\n if row == 0\n return 1\n elsif col == 0\n return conc_over_length[0]\n elsif row == col\n return -conc_over_length[row]\n else\n return 0\n end\n # end\n end\n\n # this creates the \"total_volume\" row vector\n def gibson_vector row\n if row == 0\n return 5.0\n else\n return 0\n end\n end\n \n def calc_gibson_volumes op\n tot_f_vol = Hash.new(0)\n \n conc_over_length = op.input_array(\"Fragment\").items.collect { |f| f.get(:concentration).to_f / f.sample.properties[\"Length\"]}\n \n n = conc_over_length.length\n total_vec = Matrix.build(n, 1) { |r, c| gibson_vector r }\n coef_m = Matrix.build(n, n) { |r, c| gibson_coefficients r, c, conc_over_length }\n vol_vec = (coef_m.inv * total_vec).each.to_a.collect! { |x| x.round(2) }\n f_vol = vol_vec.each.to_a.collect! { |x| x \u003c 0.20 ? 0.20 : x }\n \n # this is to ensure that the rxn isn't \u003e 5uL\n max = f_vol.max\n total = f_vol.reduce(:+)\n f_vol[f_vol.index(max)] = (max - (total - 5)).round(2) if total \u003e 5\n \n # collect all volumes to ask tech if enough stock is present \n op.input_array(\"Fragment\").items.each_with_index do |f, i|\n tot_f_vol[f.id] = f_vol[i]\n end\n \n return tot_f_vol, f_vol\n end\n\n \n def heat_block\n if operations.running.any?\n show do \n title \"Put Reactions on Heat Block\"\n warning \"Vortex and spin all Gibson Reactions before putting them on the heat block!\"\n note \"Put all #{operations.running.length} on the 50 C heat block\"\n note\"\u003ca href='https://www.google.com/search?q=1+hr+timer\u0026oq=1+hr+timer\u0026aqs=chrome..69i57j0l5.1684j0j7\u0026sourceid=chrome\u0026es_sm=122\u0026ie=UTF-8#q=1+hour+timer' target='_blank'\u003e\n Set a 1 hr timer on Google\u003c/a\u003e to set a reminder to start the ecoli_transformation protocol and retrieve the Gibson Reactions.\"\n end\n end\n end\n \n def find_replacements replacement, to_discard, id, v\n f = Item.find(id)\n replacement[f.id] = f\n is_bad_replacement = true\n \n # Keep finding replacements if previous replacement doesn't have enough volume\n while(is_bad_replacement)\n to_discard.push replacement[f.id]\n replacement[f.id].move_to(\"deleted\")\n replacement[f.id].save \n replacement[f.id] = Item.where(sample_id: f.sample_id).where(object_type_id: f.object_type_id).where(\"location != ?\", \"deleted\").to_a.first\n # Only do this if there exists a replacement\n # has the tech confirm if the new replacement has enough volume\n if replacement[f.id]\n loop_check = show do\n title \"Find replacements\"\n note \"Retrieve #{replacement[f.id].id} from #{replacement[f.id].location}\"\n select [\"Yes\", \"No\"], var: \"v#{id}\", label: \"Does #{replacement[f.id].id} have at least #{v} uL?\", default: 0\n end\n is_bad_replacement = !(loop_check[\"v#{id}\".to_sym] == \"Yes\")\n else #exit the loop if there are no replacements available\n show do\n title \"We couldnt find replacements.\"\n end\n is_bad_replacement = false;\n end\n end \n end\n \n def get_gibson_aliquots batch_id_array\n show do\n title \"Grab Gibson aliquots\"\n note \"Grab an ice block and aluminum tray from the fridge\"\n note \"Grab #{operations.length} Gibson aliquots from batch#{\"es\" if batch_id_array.length \u003e 1} #{batch_id_array}, located in the M20\"\n end\n end\n \n def load_gibson_reaction op, vol_table\n show do\n title \"Load Gibson Reaction #{op.output(\"Assembled Plasmid\").item.id}\"\n note \"Label an unused aliquot with #{op.output(\"Assembled Plasmid\").item.id}\"\n note \"Make sure the Gibson aliquot is thawed before pipetting\"\n warning \"Please use the P2 for any volumes below 0.5 uL\"\n table vol_table\n end\n end \n \n def return_aluminumTubeRack_and_iceBlock\n show do\n title \"Return ice block and aluminum tube rack\"\n check \"Return the ice block and aluminum tube rack.\"\n check \"discard the used up gibson aliquot batch.\"\n end \n end\n \n def return_gibson_aliquots aliquots_needed, batch_id_array\n data = show do\n title \"Return unused gibson aliquots\"\n note \"#{aliquots_needed} aliquots were needed for this protocol, but you might have not used all of them.\"\n note \"Return any unused aliquots to batch#{\"es\" if batch_id_array.length \u003e 1} #{batch_id_array.reverse} in the M20\"\n get \"number\", var: \"n\", label: \"How many gibson aliquots will be returned?\", default: \"0\"\n note \"If you used more aliquots than predicted, indicate with a negative value.\"\n end\n data #return\n end\n \n def associate_replacements find_replacement, replacement, op\n replacement.each do |id, item|\n\n if item\n\n op.input_array(\"Fragment\").find { |fv| fv.item.id == id }.set item: item\n find_replacement.push(item)\n else\n op.error :volume, \"Insufficient fragment stock volume for Gibson reaction.\" \n break\n end\n end\n end\n \n def update_gibson_batches gibsons_used, batch_id_array\n i = 0\n gib_batch = Collection.find batch_id_array[i]\n while gibsons_used \u003e 0\n if gib_batch.empty?\n gib_batch.mark_as_deleted\n i += 1\n gib_batch = Collection.find batch_id_array[i]\n end\n \n gibsons_used -= 1\n gib_batch.remove_one\n end\n gib_batch\n end\nend","precondition":"def precondition(op)\n \n if op.input_array(\"Fragment\").length \u003c 2\n op.error :more_fragments, \"You usually shouldn't do a gibson assembly with less than 2 fragments. Was this intentional?\"\n return true\n end\n \n \n op.input_array(\"Fragment\").each do |f|\n if f.sample.properties[\"Length\"] == 0.0\n op.error :need_fragment_length, \"Your fragment #{f.sample.name} needs a valid length for assembly.\"\n \n return false\n end\n end\n \n return true\nend","cost_model":"# Assemble Plasmid/Gibson Cost Model\n\ndef cost(op)\n {\n materials: 3.87,\n labor: 6.16 \n } \nend","documentation":"Assembles Plasmid.\n\nThe technician combines the input array of fragments and, using Gibson Assembly, assembles a plasmid. Each Gibson reaction is fixed at a volume of 5 uL, and so the volume of each fragment is calculated using an algorithm that takes in the number of total fragments in the Gibson reaction and the concentration in ng/uL of each individual fragment. The lower bounds for volume is 0.2 uL; if any fragment is below 0.2 uL, or if the overall reaction is greater than 5 uL, the volumes are tweaked for each fragment until the reaction is once more balanced. The reaction is then placed on a 42 F heat block for one hour.\n\nRan after **Make PCR Fragment** (if the fragment is not already in inventory) and is a precursor to **Transform Cells**.","test":"","timing":{"start":690,"stop":750,"days":"[\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\"]","active":true}}},{"sample_types":[{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":9,"parent_id":2,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":10,"parent_id":2,"name":"Sequence Verification","ftype":"url","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":11,"parent_id":2,"name":"Bacterial Marker","ftype":"string","choices":"Amp,Kan,Amp + Kan,Spec,Kan + Spec,Chlor,Tet,NA,Other","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":12,"parent_id":2,"name":"Yeast Marker","ftype":"string","choices":"HIS,TRP,URA,LEU,NatMX,KanMX,HygMX,BleoMX,5FOA,NA,Other","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":12,"field_type_id":12,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":13,"parent_id":2,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":14,"parent_id":2,"name":"Sequencing Primers","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":13,"field_type_id":14,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":15,"parent_id":2,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":14,"field_type_id":15,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":16,"parent_id":2,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":15,"field_type_id":16,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":17,"parent_id":2,"name":"QC_length","ftype":"number","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":18,"parent_id":2,"name":"Transformation Temperature","ftype":"number","choices":"37,30","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":19,"parent_id":3,"name":"Overhang Sequence","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":20,"parent_id":3,"name":"Anneal Sequence","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":21,"parent_id":3,"name":"T Anneal","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":1,"parent_id":1,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":2,"parent_id":1,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":3,"parent_id":1,"name":"Template","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":1,"field_type_id":3,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":2,"field_type_id":3,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":3,"field_type_id":3,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":4,"field_type_id":3,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":5,"field_type_id":3,"sample_type_id":6,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Plasmid","E coli strain","Fragment","Yeast Strain","DNA Library"],"object_types":[null,null,null,null,null]},{"id":4,"parent_id":1,"name":"Forward Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":6,"field_type_id":4,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":7,"field_type_id":4,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":5,"parent_id":1,"name":"Reverse Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":8,"field_type_id":5,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":9,"field_type_id":5,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":6,"parent_id":1,"name":"Restriction Enzyme(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":7,"parent_id":1,"name":"Yeast Marker","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":8,"parent_id":1,"name":"Fragment Mix Array","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":10,"field_type_id":8,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":11,"field_type_id":8,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]}]},{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":22,"parent_id":4,"name":"Parent","ftype":"sample","choices":null,"array":null,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":16,"field_type_id":22,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["E coli strain"],"object_types":[null]}]},{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":23,"parent_id":5,"name":"Parent","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":17,"field_type_id":23,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]},{"id":24,"parent_id":5,"name":"Integrant","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":18,"field_type_id":24,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":19,"field_type_id":24,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid","Fragment"],"object_types":[null,null]},{"id":25,"parent_id":5,"name":"Plasmid","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":20,"field_type_id":25,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid"],"object_types":[null]},{"id":26,"parent_id":5,"name":"Integrated Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":27,"parent_id":5,"name":"Plasmid Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":28,"parent_id":5,"name":"Mating Type","ftype":"string","choices":"MATa,MATalpha,Diploid","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":29,"parent_id":5,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":21,"field_type_id":29,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":30,"parent_id":5,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":22,"field_type_id":30,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":31,"parent_id":5,"name":"QC_length","ftype":"number","choices":"","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":32,"parent_id":5,"name":"Comp_cell_limit","ftype":"string","choices":"Yes,No","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":33,"parent_id":5,"name":"Media","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":34,"parent_id":5,"name":"Has this strain passed QC?","ftype":"string","choices":"No,Yes","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":35,"parent_id":5,"name":"Haploids","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":23,"field_type_id":35,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]}]},{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":36,"parent_id":6,"name":"Oligo Pool","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":24,"field_type_id":36,"sample_type_id":7,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Oligo Pool"],"object_types":[null]}]},{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":37,"parent_id":7,"name":"Manufacturer","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":38,"parent_id":7,"name":"Oligo Library ID","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":39,"parent_id":7,"name":"inner forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":25,"field_type_id":39,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":40,"parent_id":7,"name":"inner reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":26,"field_type_id":40,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":41,"parent_id":7,"name":"sublibrary forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":27,"field_type_id":41,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":42,"parent_id":7,"name":"sublibrary reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":28,"field_type_id":42,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":43,"parent_id":7,"name":"min length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":44,"parent_id":7,"name":"max length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":45,"parent_id":7,"name":"variants (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":46,"parent_id":7,"name":"sublibrary name (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":47,"parent_id":7,"name":"forward priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":48,"parent_id":7,"name":"reverse priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]}],"object_types":[{"id":10,"name":"Plasmid Stock","description":"A 1.5 mL tube containing purified plasmid DNA","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"concentration:","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":2.0,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":3,"name":"Fragment Stock","description":"Fragment stock in 1.5 mL tube, usually stored in M20 fridge.","min":0,"max":1000,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Fragment","cost":50.0,"release_method":"return","release_description":"","sample_type_id":1,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Fragment"},{"id":15,"name":"Unverified Plasmid Stock","description":"A plasmid stock that has yet to be sequenced verified","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:58.000-07:00","unit":"Plasmid","cost":0.01,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":29,"name":"Golden Gate Stripwell","description":"Golden Gate Stripwell","min":0,"max":10000,"handler":"collection","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-04-01T14:15:20.000-07:00","updated_at":"2019-04-01T14:15:20.000-07:00","unit":"stripwell","cost":0.01,"release_method":"query","release_description":"","sample_type_id":null,"image":null,"prefix":"","rows":1,"columns":12,"sample_type_name":null}],"operation_type":{"name":"Assemble Plasmid Golden Gate","category":"Cloning","deployed":false,"on_the_fly":false,"field_types":[{"ftype":"sample","role":"input","name":"Backbone","sample_types":["Plasmid","Fragment","Plasmid"],"object_types":["Plasmid Stock","Fragment Stock","Unverified Plasmid Stock"],"part":false,"array":false,"routing":"B","preferred_operation_type_id":24,"preferred_field_type_id":109,"choices":null},{"ftype":"sample","role":"input","name":"Inserts","sample_types":["Plasmid","Fragment","Plasmid"],"object_types":["Plasmid Stock","Fragment Stock","Unverified Plasmid Stock"],"part":false,"array":true,"routing":"I","preferred_operation_type_id":24,"preferred_field_type_id":109,"choices":null},{"ftype":"sample","role":"output","name":"Plasmid","sample_types":["Plasmid"],"object_types":["Golden Gate Stripwell"],"part":true,"array":false,"routing":"AP","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"# Protocol: Golden Gate Assembly\n# Author: Justin Vrana\n# Description: Golden Gate with BsaI using NEB Golden Gate Mix\n# Revision: 2017-07-19, refactored to fix errors; Justin Vrana\n# To Do:\n# 1. Add creation of 40 fmol/ul stocks\n# 2. Add parameter indicating whether finding replacements is OK\n# 3. Error out protocols if there isn't enough volume and there isn't a replacement\nneeds \"Standard Libs/Feedback\"\nclass Protocol\n include Feedback\n # IO\n INSERTS = \"Inserts\"\n BACKBONE = \"Backbone\"\n PLASMID = \"Plasmid\"\n \n # Config\n INSERT_TO_BACKBONE = 2.0\n TVOL = 10.0\n BACKBONE_FMOL_PER_UL = 2.0\n BACKBONE_FMOL = BACKBONE_FMOL_PER_UL * TVOL\n \n # 1-4 inserts \u003e\u003e 37C, 1hr \u003e 55C, 5min\n # 5-10 inserts \u003e\u003e (37C 1 min, 16C 1 min) X 30 \u003e 55C, 5 min\n # 11-20 inserts \u003e\u003e (37C 5 min, 16C 5 min) X 30 \u003e 55C, 5 min\n THERMOCYCLER_CONDITIONS = {\n 0=\u003e{\n :condition=\u003e Proc.new { |op| op.input_array(INSERTS).size.between?(1,4) },\n :steps=\u003e\n [\n {:temp=\u003e37, :min=\u003e60}, \n {:temp=\u003e55, :min=\u003e5},\n ]\n },\n 1=\u003e{\n :condition =\u003e Proc.new { |op| op.input_array(INSERTS).size.between?(5,10) },\n :steps =\u003e\n [\n {:temp=\u003e37, :min=\u003e1}, \n {:temp=\u003e16, :min=\u003e1}, \n {:goto=\u003e1, :times=\u003e30}, \n {:temp=\u003e55, :min=\u003e5},\n ]\n },\n 2=\u003e{\n :condition =\u003e Proc.new { |op| op.input_array(INSERTS).size.between?(11,20) },\n :steps =\u003e\n [\n {:temp=\u003e37, :min=\u003e5}, \n {:temp=\u003e16, :min=\u003e5}, \n {:goto=\u003e1, :times=\u003e30}, \n {:temp=\u003e55, :min=\u003e5},\n ]\n }\n }\n AVAILABLE_THERMOCYCLERS = [\"T1\", \"T2\", \"T3\"]\n REPLACEMENTS_OK = false # whether its ok to find replacements for dnas whose volume has run out\n \n # testing configuration\n RUN_WITH_PRECHECK_ERRORS = false # errors out myops in debug mode in precheck if true\n RANDOMIZE_THERMOCYCLER_GROUPS = true # randomizes thermocycler groups in debug mode if true\n RUN_WITH_POSTCHECK_ERRORS = false # errors out some operation in post check to test\n TEST_NOT_ENOUGH_THERMOCYCLERS = false\n TEST_ITEM_REPLACEMENT = false # replaces first item in operation\n SIMULATE_SAME_BACKBONE = true # simulates the situation in which the same backbone is used for all myops\n \n # Protocol Methods\n def ng_to_fmol(ng, length)\n ng * (1.0/660.0) * 10**6 * (1.0/length)\n # fmol = ng * 1pmol/660pg * 1000pg/1ng * 1/N * 1000fmol/1pmol\n end\n\n def main\n # DEBUG: Show Protocol Configuration\n if debug\n show do\n title \"DEBUG: Protocol Configuration\"\n\n note \"RUN_WITH_PRECHECK_ERRORS = #{RUN_WITH_PRECHECK_ERRORS}\"\n note \"RANDOMIZE_THERMOCYCLER_GROUPS = #{RANDOMIZE_THERMOCYCLER_GROUPS}\"\n note \"TEST_NOT_ENOUGH_THERMOCYCLERS = #{TEST_NOT_ENOUGH_THERMOCYCLERS}\"\n note \"TEST_ITEM_REPLACEMENT = #{TEST_ITEM_REPLACEMENT}\"\n note \"SIMULATE_SAME_BACKBONE = #{SIMULATE_SAME_BACKBONE}\"\n end\n end\n \n \n \n # Estimate total thermocycler time\n estimated_time = Hash.new\n \n \n THERMOCYCLER_CONDITIONS.keys.each do |tgroup|\n tinfo = THERMOCYCLER_CONDITIONS[tgroup]\n steps = tinfo[:steps]\n steps_dup = steps.map { |step| step.dup } # duplicate steps\n curr_step = 1\n cumulative_time = 0 # cumulative thermocycler time\n counter = 0 # failsafe to prevent infinite loops that kills Krill\n while curr_step.between?(0,steps.size) and counter \u003c 200\n counter += 1\n step_index = curr_step-1\n step = steps[step_index]\n if step[:min]\n cumulative_time += step[:min]\n elsif step[:goto] and step[:times]\n if step[:times] \u003e 0\n curr_step = step[:goto] - 1\n steps_dup[step_index][:times] -= 1\n end\n end\n curr_step += 1\n end\n estimated_time[tgroup] = cumulative_time\n end\n \n operations.retrieve interactive: true\n \n # Define virtual operations \n dna_inputs = operations.running.map { |op| [op.input(BACKBONE), op.input_array(INSERTS)] }.flatten\n dna = dna_inputs.map { |di| di.item }.uniq\n \n # fix data associations\n dna.each do |d|\n d.associate :volume, d.get(:volume).to_f\n d.associate :concentration, d.get(:concentration).to_f\n end\n \n myops = operations.running\n \n \n # Calculations\n myops.each do |op|\n # Lengths\n bb = op.input(BACKBONE).sample\n inserts = op.input_array(INSERTS).map { |insert| insert.sample }\n op.temporary[:backbone_length] = bb.properties['Length'].to_f || 0\n op.temporary[:insert_lengths] = inserts.map do |insert| \n insert.properties['Length'].to_f || 0\n end\n \n # Markers\n op.temporary[:backbone_marker] = bb.properties['Bacterial Marker']\n op.temporary[:insert_markers] = inserts.map do |insert|\n insert.properties['Bacterial Marker']\n end\n op.temporary[:plasmid_marker] = op.output(PLASMID).sample.properties['Bacterial Marker']\n \n # Concentrations\n # Attempt to grab legacy data and add it as a data association\n # op.temporary[:backbone_concentration] = op.input(BACKBONE).item.get(:concentration).to_f\n # op.temporary[:insert_concentrations] = op.input_array(INSERTS).map { |i| i.item.get(:concentration).to_f }\n \n # Thermocycler Groups\n THERMOCYCLER_CONDITIONS.each do |tgroup, info|\n myops.running.select(\u0026info[:condition]).each do |op|\n op.temporary[:thermocycler_group] = tgroup\n end\n end\n end\n \n # Validate Lengths\n myops.each do |op|\n dna_inputs = [op.input(BACKBONE)] + op.input_array(INSERTS) # an array of backbone + inserts\n\n lengths = [op.temporary[:backbone_length]] + op.temporary[:insert_lengths]\n lengths.map! { |x| x.to_f }\n lengths.zip(dna_inputs).each.with_index do |ld, index|\n length, d = ld\n if length \u003c= 0\n err_key = \"no_length_for_#{d.sample.name}\".to_sym\n err_msg = \"The input dna #{d.sample.name} has an invalid DNA length. Please input \\\n a valid length in the sample definition.\"\n if debug\n if RUN_WITH_PRECHECK_ERRORS\n op.error err_key, err_msg\n elsif # Assign random length in debug mode\n if index == 0\n op.temporary[:backbone_length] = rand(1000...10000)\n else\n op.temporary[:insert_lengths][index-1] = rand(1000...10000)\n end\n end\n else\n op.error err_key, err_msg\n end\n end\n end\n end\n \n dna_inputs = operations.running.map { |op| [op.input(BACKBONE), op.input_array(INSERTS)] }.flatten\n dna = dna_inputs.map { |di| di.item }.uniq\n vops = dna.map { |i|\n insert_operation operations.length, VirtualOperation.new\n vop = operations.last\n vop.temporary[:item] = i\n vop\n }\n \n myops = operations.select { |op| !op.virtual? }\n \n if myops.empty?\n show do\n title \"There are no operations\"\n \n check \"All the operations have errored out.\"\n end\n end\n \n # DEBUG: \n if debug and SIMULATE_SAME_BACKBONE\n backbone = nil\n myops.running.each do |op|\n if not backbone\n backbone = op.input(BACKBONE).item\n else\n fv = op.input(BACKBONE)\n fv.child_item_id = backbone.id\n fv.save\n end\n end\n end\n\n # You may know beforehand that you don't have enough volume but need a replacement\n # add additional items here\n \n # Measure Concentrations\n def concentration_invalid item\n invalid = false\n if item.get(:concentration).nil? or item.get(:concentration).to_f \u003c= 0.0\n invalid = true\n end\n invalid\n end\n \n dna_to_be_measured = dna.select { |d| concentration_invalid(d) }\n \n # Loop if any concentrations are invalid\n counter = 0 # failsafe to prevent infinite loops that wreck Krill\n while dna_to_be_measured.any? { |d| concentration_invalid(d) } and counter \u003c 5\n \n counter += 1\n temp_op = myops.first\n message = nil\n if counter \u003e 1\n message = \"One or more concentrations you've entered are invalid! \\\n Please correct the concentration of highlighted item.\"\n end\n # Ask technician to nanodrop each plasmid\n show do\n title \"Go to the nanodrop and measure the concentrations.\"\n warning message if message\n check \"For each concentration, write the concentration on the side of the tube\"\n note \"Enter the concentrations in the table below.\"\n \n css_incorrect = {style: {color: \"white\", \"background-color\"=\u003e\"red\"}}\n # Make IO Table\n item_id_rows, conc_rows = [], []\n dna_to_be_measured.map do |dna|\n item_id_row = { content: dna.id, check: true }\n item_id_row.merge!(css_incorrect) if concentration_invalid(dna) and message\n item_id_rows.push(item_id_row)\n \n conc_row = {\n type: 'number', \n key: \"#{dna.id}_concentration\", \n operation_id: temp_op.id, \n default: concentration_invalid(dna) ? -1 : dna.get(:concentration)\n }\n conc_row.merge!(css_incorrect) if concentration_invalid(dna)\n conc_rows.push(conc_row)\n end\n \n io_table = Table.new\n io_table.add_column(\"Item id\", item_id_rows)\n io_table.add_column(\"Concentration (ng/ul)\", conc_rows)\n table io_table\n end\n \n # Concentration data associations\n dna_to_be_measured.each do |dna|\n key = \"#{dna.id}_concentration\".to_sym\n dna.associate :concentration, temp_op.temporary[key].to_f\n dna.save\n temp_op.temporary.delete(key)\n end\n \n # Debug test\n if debug\n dna_to_be_measured.each do |dna|\n dna.associate :concentration, rand(100...1000)\n end\n if counter == 1\n dna_to_be_measured.first.associate :concentration, -1\n end\n end\n \n # Update remove valid dnas from measurement lists\n # dna_to_be_measured.reject! { |d| !concentration_invalid(d.item) }\n end\n \n # Find item replacements\n if debug and TEST_ITEM_REPLACEMENT\n # replace first operation\n fmol_stock = ObjectType.find_by_name(\"40 fmole/uL Plasmid Stock\")\n fv = myops.running.first.input(BACKBONE)\n child_sample = fv.child_sample\n new_item = Item.make( {quantity: 1, inuse: 0}, sample: child_sample, object_type: fmol_stock )\n fv.child_item_id = new_item.id\n fv.save\n \n show do\n title \"DEBUG: Item Replacement\"\n note \"#{new_item.id}\"\n table myops.running.start_table\n .custom_column(heading: \"Field Value Type\") { |op| op.input(BACKBONE).object_type.name }\n .custom_column(heading: \"Item Type\") { |op| op.input(BACKBONE).item.object_type.name }\n .input_item(BACKBONE)\n .end_table\n end\n end\n \n # Volume Calculations\n myops.running.each do |op|\n # Volumes\n \n recipe = Hash.new\n # Backbone volume\n \n bb_fmol_per_uL = ng_to_fmol(op.input(BACKBONE).item.get(:concentration), op.temporary[:backbone_length])\n recipe[op.input(BACKBONE).item] = BACKBONE_FMOL / bb_fmol_per_uL\n \n # Insert volumes\n ics = op.input_array(INSERTS).map { |insert| insert.item.get(:concentration) }\n ils = op.temporary[:insert_lengths]\n op.input_array(INSERTS).zip(ils).map do |insert_input, l|\n c = insert_input.item.get(:concentration)\n fmol_per_ul = ng_to_fmol(c, l)\n recipe[insert_input.item] = (INSERT_TO_BACKBONE * BACKBONE_FMOL).to_f / (fmol_per_ul).to_f\n end\n \n # Buffer volume\n recipe[:buffer] = TVOL * 0.1\n \n # Enzyme volume\n recipe[:enzyme] = TVOL * 0.05\n \n # H20 volumes\n total_vol = recipe.inject(0) { |sum, x| sum + x[1] }\n adjustment = total_vol / TVOL\n if adjustment \u003e 1.0\n recipe.each do |k, v|\n recipe[k] = v / adjustment\n end\n end\n total_vol = recipe.inject(0) { |sum, x| sum + x[1] }\n recipe[:water] = TVOL - total_vol\n \n # Round\n recipe.each do |k, v|\n recipe[k] = recipe[k]\n end\n \n # Recipe\n op.temporary[:recipe] = recipe\n \n # Adjustments\n end\n \n \n \n # DEBUG: Volume Calculation Table\n if debug\n show do\n title \"DEBUG: Volume Calculations\"\n table myops.running.start_table\n .custom_column(heading: \"Backbone Vol\") { |op| op.temporary[:recipe][op.input(BACKBONE).item] }\n .custom_column(heading: \"Insert Vols\") { |op| op.input_array(INSERTS).map { |i| op.temporary[:recipe][i.item] } }\n .custom_column(heading: \"Backbone Length\") { |op| op.temporary[:backbone_length] }\n .custom_column(heading: \"Insert Lengths\") { |op| op.temporary[:insert_lengths] }\n .custom_column(heading: \"Backbone Conc\") { |op| op.input(BACKBONE).item.get(:concentration) }\n .custom_column(heading: \"Insert Conc\") { |op| op.input_array(INSERTS).map { |insert| insert.item.get(:concentration) } }\n .end_table\n end\n end\n \n # Validate volumes\n # vol_hash = validate_volumes(myops.running, debug_mode=RUN_WITH_POSTCHECK_ERRORS, BACKBONE, INSERTS)\n vol_hash = Hash.new # h[d] = { :total_vol, :ops }\n input_names = [INSERTS, BACKBONE]\n myops.running.each do |op|\n inputs = input_names.map { |name| op.input_array(name) }.flatten # array of all fields\n items = inputs.map { |input| input.item }.uniq # list of unique items\n req_vols = items.map { |item| op.temporary[:recipe][item] }\n items.zip(req_vols).each do |i, v|\n item_info = vol_hash[i] || { :total_vol=\u003e0, :ops=\u003e[] }\n item_info[:total_vol] += v\n item_info[:ops].push(op)\n vol_hash[i] = item_info # {total_vol: total_volume_required, ops: ops_associated_with_this_item}\n end\n end\n \n # Check volumes\n volume_table = Proc.new { |ops|\n ops.start_table\n .custom_column(heading: \"Item\") { |op| op.temporary[:item].id }\n .custom_column(heading: \"Total vol req. for batch\") { |op| vol_hash[op.temporary[:item]][:total_vol] }\n .custom_column(heading: \"Num Times Used\") { |op| vol_hash[op.temporary[:item]][:ops].size }\n .custom_input(:volume, heading: \"Volume (ul)\", type: \"number\") { |op|\n default_volume = op.temporary[:item].get(:volume) || 10.0\n if debug and default_volume == 0.0\n default_volume = rand(10..100)\n end\n default_volume\n }\n .validate(:volume) { |op,v| v.between?(0,10000) }\n .end_table.all\n }\n \n show_with_input_table(vops, volume_table) do\n title \"Check volumes\"\n \n check \"For each item, estimate the volume in the tube\"\n end\n \n # Associate volumes\n vops.each do |op| \n op.temporary[:item].associate :volume, op.temporary[:volume]\n end\n \n vol_remaining_hash = vol_hash.map { |item, vol| [item, item.get(:volume)] }.to_h # simulated volume remaining for each item\n requires_replacement = [] # items that require replacement\n replacement_reasons = [] # reason for replacement\n \n myops.running.each do |op|\n op.temporary[:replace] = []\n input_names = [BACKBONE, INSERTS]\n input_fields = input_names.map { |n| op.input_array(n) }.flatten # all inputs\n items = input_fields.map { |input| input.item }.uniq # uniq items for the inputs\n recipe = op.temporary[:recipe] # recipe detailing how much vol is needed for each item\n items.each do |item|\n \n # Contamination check\n if item[:contamination] == true\n op.temporary[:replace].push(item)\n \"Item #{item.id} was contaminated. Please see associated notes.\"\n end\n\n # Volume check\n req_vol = recipe[item]\n vol_remaining = vol_remaining_hash[item]\n vol_remaining_hash[item] -= req_vol\n if vol_remaining_hash[item] \u003c 0\n op.temporary[:replace].push(item)\n op.error :not_enough_volume, \"Item #{item.id} did not have enough volume to complete operation #{op.id}.\"\n end\n end\n op.temporary[:replace].uniq!\n end\n \n myops.running.each do |op|\n items_to_be_replaced = op.temporary[:replace]\n end\n \n requires_replacement = requires_replacement.uniq\n \n # ops_to_be_diluted = vol_hash.select { |item, info| info[:total_vol]\n \n \n # allowable_objects = \n \n # ft = myops.first.input(\"Input\").field_type\n # allowable_ft = ft.allowable_field_types\n # allowable_objects = allowable_ft.map { |f| ObjectType.find_by_id(f.object_type_id) }\n # x = FieldType.find_by_id(x)\n # note \"#{allowable_objects.map { |x| x.name } }\"\n \n \n # retrieve the replacement items\n # re-validate volumes for those items\n # if there's not enough, repeat\n # if there's no more items, error out the operation\n \n \n # if replacements are ok\n # treat all dnas as a pool\n # if contaminated\n # find replacment item\n # notify user of replacement\n # if not enough volume between entire pool\n # error out some myops\n \n # for volumes below pipetting threshold\n # create a 40 fmol/stock\n # set input item to 40 fmol/stock\n # notify user of replacement\n \n # Custom Make\n if debug and \n # Tests to make sure thermocycler grouping is working properly\n myops.running.each do |op|\n op.temporary[:thermocycler_group] = THERMOCYCLER_CONDITIONS.keys.sample\n end\n end\n \n thermocycler_groups = myops.running.group_by { |op| op.temporary[:thermocycler_group] }\n \n thermocycler_groups.each do |gn, op_group|\n fo = op_group.first.output(PLASMID)\n rows = fo.object_type.rows\n columns = fo.object_type.columns\n size = rows * columns\n new_collection = op_group.first.output(PLASMID).make_collection\n op_group.each.with_index do |op, i|\n fv = op.output(PLASMID)\n fv.make_part(new_collection,(i%size)/columns,(i%size)%columns)\n end\n end\n \n if debug\n show do\n title \"DEBUG: Output Collections\"\n table myops.running.start_table\n .output_collection(PLASMID)\n .output_column(PLASMID)\n .end_table\n end\n end\n \n # Group myops by stripwells\n stripwells = myops.running.map { |op| op.output(PLASMID).collection }.uniq\n \n grouped_by_stripwells = stripwells.map do |stripwell|\n grouped_ops = myops.running.select do |op| \n op.output(PLASMID).collection == stripwell\n end\n [stripwell, grouped_ops]\n end.to_h\n \n \n # Prepare Golden Gate Master Mix\n # For NEB reaction, we just grab it from the stock (BsaI only)\n # For other enzymes, we have to make this fresh each time...\n \n # Gather and label stripwells\n show do\n title \"Gather and label #{stripwells.size} stripwell(s)\"\n \n note \"Gather #{stripwells.size} stripwell(s) and label them according to the table:\"\n \n t = Table.new\n t.add_column(\"Stripwell IDs\", stripwells.map { |s| s.id })\n table t\n end\n \n # Pipette H20\n grouped_by_stripwells.each do |stripwell, ops|\n show do\n title \"Pipette sterile H20 into stripwell #{stripwell}\" \n note \"Display a nice table indicating which stripwells...\"\n table ops.start_table\n .output_collection(PLASMID, heading: \"Stripwell\")\n .output_column(PLASMID, heading: \"Well\", checkable: true)\n .custom_column(heading: \"H20 (uL)\") { |op| op.temporary[:recipe][:water] }\n .end_table\n end\n end\n \n # Pipette Buffer\n # for non-NEB, we don't need to add buffer since it will be in the assembly mix...\n grouped_by_stripwells.each do |stripwell, ops|\n buffer = \"NEB Golden Gate Buffer\"\n show do \n title \"Pipette #{buffer} into each well\"\n \n table ops.start_table\n .output_collection(PLASMID, heading: \"Stripwell\")\n .output_column(PLASMID, checkable: true, heading: \"Well\")\n .custom_column(heading: \"Vol (ul)\") { |op| op.temporary[:recipe][:buffer] }\n .end_table\n end\n end\n \n # Pipette DNA\n grouped_by_stripwells.each do |stripwell, ops|\n ops.running.each do |op|\n show do\n title \"Add DNA to well #{op.output(PLASMID).column} of stripwell #{op.output(PLASMID).collection}\"\n note \"Stripwell: #{op.output(PLASMID).collection}\"\n note \"Well: #{op.output(PLASMID).column}\"\n \n these_dna = op.input_array(BACKBONE) + op.input_array(INSERTS)\n \n t = Table.new\n t.add_column( \"Item id\", these_dna.map { |d| { content: d.item.id, check: true } } )\n t.add_column(\"Vol (ul)\", these_dna.map { |d| op.temporary[:recipe][d.item] } )\n table t\n end\n \n # note \"UPDATE VOLUMES HERE\"\n # note \"CREATE A TRANSFER METHOD FOR TRANSFERS BETWEEN ITEMS\"\n end\n end\n \n # Pipette Assembly Mix\n assembly_mix = \"NEB Golden Gate Assembly Mix\"\n show do \n title \"Pipette #{assembly_mix} into each well\"\n \n table myops.running.start_table\n .output_collection(PLASMID, heading: \"Stripwell\")\n .output_column(PLASMID, checkable: true, heading: \"Well\")\n .custom_column(heading: \"Vol (ul)\") { |op| op.temporary[:recipe][:enzyme] }\n .end_table\n end\n \n # Put in thermocyclers\n thermocycler_ids = thermocycler_groups.keys.sort\n available_thermocyclers = AVAILABLE_THERMOCYCLERS.dup\n if debug and TEST_NOT_ENOUGH_THERMOCYCLERS\n available_thermocyclers = []\n end\n thermocycler_ids.each do |group_id|\n op_group = thermocycler_groups[group_id] # myops grouped into this thermocycler\n stripwells = op_group.map { |op| op.output(PLASMID).collection }.uniq # stripwells for this thermocycler\n \n thermocycler = :unknown_location # thermocycler location\n if available_thermocyclers.any?\n thermocycler = available_thermocyclers.slice!(0)\n end\n steps = THERMOCYCLER_CONDITIONS[group_id][:steps] # thermocycler steps\n \n new_thermocycler_loc = show do\n if thermocycler == :unknown_location\n title \"Find a thermocycler to place stripwells in\"\n \n warning \"There are no available thermocyclers for these stripwells!\"\n check \"Please find an available thermocycler to place this golden gate in.\"\n check \"Please write down new location in the text box below!\"\n \n get \"text\", var: \"location\", label: \"New stripwell location:\", default: thermocycler\n else\n title \"Place stripwells into thermocycler #{thermocycler}\"\n end\n \n separator\n # Est Time\n note \"\u003cb\u003eTiming\u003c/b\u003e\"\n note \"Estimated duration: \u003cb\u003e#{estimated_time[group_id]} minutes\u003c/b\u003e\"\n ready = Time.now + 60.0*estimated_time[group_id]\n note \"Thermocycler ready at: \u003cb\u003e#{ready.strftime(\"%a %m/%d/%y %I:%M%p\")}\u003c/b\u003e\"\n \n separator\n # Stripwell table\n note \"\u003cb\u003eStripwells\u003c/b\u003e\"\n st = Table.new\n st.add_column(\"Stripwells\", stripwells.map { |x| x.id })\n table st\n \n step_strs = steps.map do |step|\n str = step.to_s\n if step[:temp] and step[:min]\n str = \"#{step[:temp]}C for #{step[:min]} minutes\"\n elsif step[:goto] and step[:times]\n str = \"GOTO Step #{step[:goto]} X#{step[:times]}\"\n end\n str\n end\n \n separator\n # Thermocycler table\n note \"\u003cb\u003eThermocycler Protocol\u003c/b\u003e\"\n tt = Table.new\n tt.add_column(\"Step\", steps.map.with_index { |x, i| i+1 } )\n tt.add_column(\"Protocol\", step_strs)\n table tt\n end\n \n # Update stripwell locations\n thermocycler = new_thermocycler_loc[:location]\n stripwells.each do |stripwell|\n stripwell.move thermocycler\n end\n end\n \n # Delete items whose volumes are now zero\n # code here\n \n # Return items\n myops.running.store(io: \"input\")\n myops.running.store(io: \"output\", interactive: false)\n \n get_protocol_feedback()\n \n return {}\n end\nend","precondition":"def precondition(op)\n true\nend","cost_model":"def cost(op)\n { labor: 9.37, materials: 11.55 }\nend","documentation":"Assembles fragments with a Golden Gate master mix.\n\nIt combines fragments with a Golden Gate master mix according to calculated concentrations and then tells\nthe technician to place the mixture into a thermocycler to run.\n\nRan after *Make PCR Fragment* and before *Transform Cells*.","test":"","timing":{"start":630,"stop":750,"days":"[\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\"]","active":true}}},{"sample_types":[{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":9,"parent_id":2,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":10,"parent_id":2,"name":"Sequence Verification","ftype":"url","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":11,"parent_id":2,"name":"Bacterial Marker","ftype":"string","choices":"Amp,Kan,Amp + Kan,Spec,Kan + Spec,Chlor,Tet,NA,Other","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":12,"parent_id":2,"name":"Yeast Marker","ftype":"string","choices":"HIS,TRP,URA,LEU,NatMX,KanMX,HygMX,BleoMX,5FOA,NA,Other","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":12,"field_type_id":12,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":13,"parent_id":2,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":14,"parent_id":2,"name":"Sequencing Primers","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":13,"field_type_id":14,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":15,"parent_id":2,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":14,"field_type_id":15,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":16,"parent_id":2,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":15,"field_type_id":16,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":17,"parent_id":2,"name":"QC_length","ftype":"number","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":18,"parent_id":2,"name":"Transformation Temperature","ftype":"number","choices":"37,30","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":19,"parent_id":3,"name":"Overhang Sequence","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":20,"parent_id":3,"name":"Anneal Sequence","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":21,"parent_id":3,"name":"T Anneal","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]}],"object_types":[{"id":5,"name":"E coli Plate of Plasmid","description":"A plate containing E. coli transformed with a plasmid","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":0.01,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"DFP","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":6,"name":"Checked E coli Plate of Plasmid","description":"It's a checked plate","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"plate","cost":0.01,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"","rows":null,"columns":null,"sample_type_name":"Plasmid"}],"operation_type":{"name":"Check Plate","category":"Cloning","deployed":false,"on_the_fly":false,"field_types":[{"ftype":"sample","role":"input","name":"Plate","sample_types":["Plasmid"],"object_types":["E coli Plate of Plasmid"],"part":false,"array":false,"routing":"P","preferred_operation_type_id":27,"preferred_field_type_id":116,"choices":null},{"ftype":"sample","role":"output","name":"Plate","sample_types":["Plasmid"],"object_types":["Checked E coli Plate of Plasmid"],"part":false,"array":false,"routing":"P","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"# Author: Ayesha Saleem\r\n# December 20, 2016\r\n\r\n# TO DO: \r\n # Create option for \"there are baby colonies but they're not big enough for protocols\" case--put back in incubator\r\n # Re-streak the plate if there's too much contamination--fire check plate again in 24 hrs, probably collection\r\nneeds \"Standard Libs/Feedback\"\r\nclass Protocol\r\n include Feedback\r\n def main\r\n # Take plates \r\n operations.retrieve\r\n \r\n # Count the number of colonies\r\n info = get_colony_numbers\r\n \r\n # Update plate data\r\n update_item_data info\r\n \r\n # Delete and discard any plates that have 0 colonies\r\n discard_bad_plates if operations.any? { |op| op.temporary[:delete] }\r\n \r\n # Parafilm and label plates \r\n parafilm_plates\r\n \r\n # Return plates\r\n operations.store\r\n \r\n # Get feedback\r\n get_protocol_feedback()\r\n return {}\r\n end\r\n \r\n \r\n \r\n # Count the number of colonies and select whether the growth is normal, contaminated, or a lawn\r\n def get_colony_numbers\r\n show do\r\n title \"Estimate colony numbers\"\r\n \r\n operations.each do |op|\r\n plate = op.input(\"Plate\").item\r\n get \"number\", var: \"n#{plate.id}\", label: \"Estimate how many colonies are on #{plate}\", default: 5\r\n select [\"normal\", \"contamination\", \"lawn\"], var: \"s#{plate}\", label: \"Choose whether there is contamination, a lawn, or whether it's normal.\"\r\n end\r\n end \r\n end\r\n \r\n # Alter data of the virtual item to represent its actual state\r\n def update_item_data info\r\n operations.each do |op|\r\n plate = op.input(\"Plate\").item\r\n if info[\"n#{plate.id}\".to_sym] == 0\r\n plate.mark_as_deleted\r\n plate.save\r\n op.temporary[:delete] = true\r\n op.error :no_colonies, \"There are no colonies for plate #{plate.id}\"\r\n else\r\n plate.associate :num_colonies, info[\"n#{plate.id}\".to_sym]\r\n plate.associate :status, info[\"s#{plate.id}\".to_sym]\r\n \r\n checked_ot = ObjectType.find_by_name(\"Checked E coli Plate of Plasmid\")\r\n plate.store if plate.object_type_id != checked_ot.id\r\n plate.object_type_id = checked_ot.id\r\n plate.save\r\n op.output(\"Plate\").set item: plate\r\n \r\n op.plan.associate \"plate_#{op.input(\"Plate\").sample.id}\", plate.id\r\n end\r\n end\r\n end\r\n \r\n # discard any plates that have 0 colonies\r\n def discard_bad_plates\r\n show do \r\n title \"Discard Plates\"\r\n \r\n discard_plate_ids = operations.select { |op| op.temporary[:delete] }.map { |op| op.input(\"Plate\").item.id }\r\n note \"Discard the following plates with 0 colonies: #{discard_plate_ids}\"\r\n end\r\n end\r\n \r\n # Parafilm and label any plates that have suitable growth\r\n def parafilm_plates\r\n show do \r\n title \"Label and Parafilm\"\r\n \r\n plates_to_parafilm = operations.reject { |op| op.temporary[:delete] }.map { |op| op.input(\"Plate\").item.id }\r\n note \"Perform the steps with the following plates: #{plates_to_parafilm}\"\r\n note \"Label the plates with their item ID numbers on the side, and parafilm each one.\"\r\n note \"Labelling the plates on the side makes it easier to retrieve them from the fridge.\"\r\n end\r\n end\r\nend","precondition":"eval Library.find_by_name(\"Preconditions\").code(\"source\").content\nextend Preconditions\n\ndef precondition(op) \n time_elapsed op, \"Plate\", hours: 8\n true\nend","cost_model":"# Check Plate/Imaging Cost Model\n\ndef cost(op)\n {\n materials: 0.02,\n labor: 0.68 \n } \nend","documentation":"Checks plates for growth and contamination.\n\nThe plates are pulled from the 37 F incubator and checked for growth and contamination. If there is no growth, the plate is thrown out and the user is notified.\n\nRan the day after **Plate Transformed Cells** and is a precursor to **Make Overnight Suspension**.","test":"","timing":{"start":480,"stop":510,"days":"[\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\"]","active":true}}},{"sample_types":[{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":1,"parent_id":1,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":2,"parent_id":1,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":3,"parent_id":1,"name":"Template","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":1,"field_type_id":3,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":2,"field_type_id":3,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":3,"field_type_id":3,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":4,"field_type_id":3,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":5,"field_type_id":3,"sample_type_id":6,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Plasmid","E coli strain","Fragment","Yeast Strain","DNA Library"],"object_types":[null,null,null,null,null]},{"id":4,"parent_id":1,"name":"Forward Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":6,"field_type_id":4,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":7,"field_type_id":4,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":5,"parent_id":1,"name":"Reverse Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":8,"field_type_id":5,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":9,"field_type_id":5,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":6,"parent_id":1,"name":"Restriction Enzyme(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":7,"parent_id":1,"name":"Yeast Marker","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":8,"parent_id":1,"name":"Fragment Mix Array","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":10,"field_type_id":8,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":11,"field_type_id":8,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]}]},{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":9,"parent_id":2,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":10,"parent_id":2,"name":"Sequence Verification","ftype":"url","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":11,"parent_id":2,"name":"Bacterial Marker","ftype":"string","choices":"Amp,Kan,Amp + Kan,Spec,Kan + Spec,Chlor,Tet,NA,Other","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":12,"parent_id":2,"name":"Yeast Marker","ftype":"string","choices":"HIS,TRP,URA,LEU,NatMX,KanMX,HygMX,BleoMX,5FOA,NA,Other","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":12,"field_type_id":12,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":13,"parent_id":2,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":14,"parent_id":2,"name":"Sequencing Primers","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":13,"field_type_id":14,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":15,"parent_id":2,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":14,"field_type_id":15,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":16,"parent_id":2,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":15,"field_type_id":16,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":17,"parent_id":2,"name":"QC_length","ftype":"number","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":18,"parent_id":2,"name":"Transformation Temperature","ftype":"number","choices":"37,30","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":19,"parent_id":3,"name":"Overhang Sequence","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":20,"parent_id":3,"name":"Anneal Sequence","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":21,"parent_id":3,"name":"T Anneal","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":22,"parent_id":4,"name":"Parent","ftype":"sample","choices":null,"array":null,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":16,"field_type_id":22,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["E coli strain"],"object_types":[null]}]},{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":23,"parent_id":5,"name":"Parent","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":17,"field_type_id":23,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]},{"id":24,"parent_id":5,"name":"Integrant","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":18,"field_type_id":24,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":19,"field_type_id":24,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid","Fragment"],"object_types":[null,null]},{"id":25,"parent_id":5,"name":"Plasmid","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":20,"field_type_id":25,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid"],"object_types":[null]},{"id":26,"parent_id":5,"name":"Integrated Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":27,"parent_id":5,"name":"Plasmid Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":28,"parent_id":5,"name":"Mating Type","ftype":"string","choices":"MATa,MATalpha,Diploid","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":29,"parent_id":5,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":21,"field_type_id":29,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":30,"parent_id":5,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":22,"field_type_id":30,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":31,"parent_id":5,"name":"QC_length","ftype":"number","choices":"","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":32,"parent_id":5,"name":"Comp_cell_limit","ftype":"string","choices":"Yes,No","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":33,"parent_id":5,"name":"Media","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":34,"parent_id":5,"name":"Has this strain passed QC?","ftype":"string","choices":"No,Yes","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":35,"parent_id":5,"name":"Haploids","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":23,"field_type_id":35,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]}]},{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":36,"parent_id":6,"name":"Oligo Pool","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":24,"field_type_id":36,"sample_type_id":7,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Oligo Pool"],"object_types":[null]}]},{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":37,"parent_id":7,"name":"Manufacturer","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":38,"parent_id":7,"name":"Oligo Library ID","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":39,"parent_id":7,"name":"inner forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":25,"field_type_id":39,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":40,"parent_id":7,"name":"inner reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":26,"field_type_id":40,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":41,"parent_id":7,"name":"sublibrary forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":27,"field_type_id":41,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":42,"parent_id":7,"name":"sublibrary reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":28,"field_type_id":42,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":43,"parent_id":7,"name":"min length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":44,"parent_id":7,"name":"max length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":45,"parent_id":7,"name":"variants (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":46,"parent_id":7,"name":"sublibrary name (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":47,"parent_id":7,"name":"forward priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":48,"parent_id":7,"name":"reverse priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]}],"object_types":[{"id":7,"name":"50 mL 0.8 Percent Agarose Gel in Gel Box","description":"Used to run gels;","min":0,"max":100,"handler":"collection","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"box","cost":0.01,"release_method":"return","release_description":"Return this item","sample_type_id":null,"image":null,"prefix":"","rows":1,"columns":12,"sample_type_name":null},{"id":8,"name":"Gel Slice","description":"Gel Slice cut from a gel lane after gel was run. Often placed in a 1.5 mL tube.","min":0,"max":1000,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Fragment","cost":10.0,"release_method":"dispose","release_description":"","sample_type_id":1,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Fragment"}],"operation_type":{"name":"Extract Gel Slice","category":"Cloning","deployed":false,"on_the_fly":false,"field_types":[{"ftype":"sample","role":"input","name":"Fragment","sample_types":["Fragment","Plasmid"],"object_types":["50 mL 0.8 Percent Agarose Gel in Gel Box","50 mL 0.8 Percent Agarose Gel in Gel Box"],"part":true,"array":false,"routing":"F","preferred_operation_type_id":15,"preferred_field_type_id":86,"choices":null},{"ftype":"sample","role":"output","name":"Fragment","sample_types":["Fragment","Plasmid"],"object_types":["Gel Slice","Gel Slice"],"part":false,"array":false,"routing":"F","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"# Extract Fragment Protocol\n# V1.0.2; 2017-07-17 JV\n# Written by Ayesha Saleem\n# Revised by Justin Vrana 2017-07-13; corrected upload issue\n# Revised by Justin Vrana 2017-07-17; unique upload table\nneeds \"Standard Libs/UploadHelper\"\nneeds \"Standard Libs/AssociationManagement\"\nneeds \"Standard Libs/Feedback\"\nclass Protocol\n include Feedback\n include UploadHelper, AssociationManagement\n \n # I/O\n FRAGMENT=\"Fragment\"\n FRAGMENT_OUT=\"Fragment\"\n \n # upload stuff\n DIRNAME=\"\u003cwhere are gel files on computer\u003e\"\n TRIES=3\n \n # gel stuff\n MIN_WEIGHT = 0.0\n MAX_WEIGHT = 10.0\n CORRECT=[\"y\",\"n\"] # values for debug\n\n def main\n \n # Sort operations by gels and columns (these can get out of order from PCR)\n operations.sort! do |op1, op2| \n fv1 = op1.input(FRAGMENT)\n fv2 = op2.input(FRAGMENT)\n [fv1.item.id, fv1.row, fv1.column] \u003c=\u003e [fv2.item.id, fv2.row, fv2.column]\n end\n \n operations.retrieve(interactive: false)\n \n # get gel images\n gels = operations.map { |op| op.input(FRAGMENT).collection}.uniq\n gels.each { |gel|\n \n grouped_ops=operations.select { |op| op.input(FRAGMENT).collection == gel }\n image_name = \"gel_#{gel.id}\"\n \n # image gel\n image_gel gel, image_name\n\n \n # upload image\n ups = uploadData(\"#{DIRNAME}/#{image_name}\", 1, TRIES) # 1 file per gel\n ups = [Upload.find(1)] if debug\n \n # associate to gel, plan, op \n # can't associate to outputs yet because they are only made if lengths are verified\n up=nil\n if(!(ups.nil?))\n up=ups[0]\n\n gel_item = Item.find(gel.id)\n\n # associate gel image to gel\n gel_item.associate image_name, \"successfully imaged gel\", up\n \n grouped_ops.each do |op| # associate to all operations connected to gel\n # description of where this op is in the gel, to be used as desc tag for image upload\n location_in_gel = \"#{op.input(FRAGMENT).sample.name} is in row #{op.input(FRAGMENT).row + 1} and column #{op.input(FRAGMENT).column + 1}\"\n \n # associate image to op with a location description\n op.associate image_name, location_in_gel, up\n \n # associate image to plan, or append new location to description if association already exists\n existing_assoc = op.plan.get(image_name)\n if existing_assoc \u0026\u0026 op.plan.upload(image_name) == up\n op.plan.modify(image_name, existing_assoc.to_s + \"\\n\" + location_in_gel, up)\n else\n op.plan.associate image_name, location_in_gel , up\n end\n end\n end\n \n # check lengths of fragments in gel\n check_frag_length gel, grouped_ops\n # grouped_ops.map { |op| op.temporary[:correct] = CORRECT.rotate!.first } if debug\n \n \n # check whether fragment matched length\n grouped_ops.each { |op|\n if(op.temporary[:correct].upcase.start_with?(\"N\"))\n op.error :incorrect_length, \"The fragment did not match the expected length.\"\n end\n }\n \n # get grouped_ops that have not errored\n \n grouped_ops.select! { |op| op.status == \"running\" }\n\n # show { note \"Making the following ops: #{grouped_ops.map { |op| op.id }}\"}\n grouped_ops.make # contains only running ops from here on !!!\n # show { note \"#{grouped_ops.map { |op| op.output(FRAGMENT_OUT).item }}\" }\n\n \n if(grouped_ops.any?)\n # cut fragments\n cut_fragments grouped_ops \n\n # weigh fragments\n weigh_fragments grouped_ops\n \n # associate gel image, fragment lane with fragment and weight with the gel slices to output\n grouped_ops.each { |op|\n op.output(FRAGMENT_OUT).item.associate(image_name, \"Your fragment is in row #{op.input(FRAGMENT).row + 1} and column #{op.input(FRAGMENT).column + 1}\", up) \n op.output(FRAGMENT_OUT).item.associate(:weight, op.temporary[:weight]) \n }\n \n else \n # do we want this? ask cami/sam\n show {\n title \"Your lucky day!\"\n note \"No fragments to extract from gel #{gel}.\"\n }\n end # grouped_ops.any?\n \n # clean up after gel\n clean_up gel, gels\n \n # delete collection\n gel.mark_as_deleted\n \n } # gels.each\n \n ok_ops=operations.running\n operations=ok_ops\n \n # are we cleaning from gel now?\n choice = show {\n title \"What Next?\"\n select [\"Yes\", \"No\"], var: \"choice\", label: \"Would you like to purify the gel slices immediately?\", default: 0\n }\n plans = operations.map { |op| op.plan }.uniq\n plans.each { |plan|\n plan.associate :choice, choice[:choice]\n }\n if(choice[:choice] == \"Yes\")\n show {\n title \"Keep Gel Slices\"\n note \"Keep the gel slices #{operations.map{ |op| op.output(FRAGMENT_OUT).item}.to_sentence} on your bench to use in the next protocol.\"\n }\n else\n operations.store\n end\n \n get_protocol_feedback\n return {}\n end\n \n # This method instructs the technician to image the given gel.\n def image_gel gel, image_name\n show do\n title \"Image gel #{gel}\"\n check \"Clean the transilluminator with ethanol.\"\n check \"Put the gel #{gel} on the transilluminator.\"\n check \"Turn off the room lights before turning on the transilluminator.\"\n check \"Put the camera hood on, turn on the transilluminator and take a picture using the camera control interface on computer.\"\n check \"Check to see if the picture matches the gel before uploading.\"\n check \"Rename the picture you just took exactly as \u003cb\u003e#{image_name}\u003c/b\u003e.\"\n end\n end\n \n # This method tells the technician to verify fragment lengths for the given gel.\n def check_frag_length gel, grouped_ops\n show {\n title \"Verify Fragment Lengths for gel #{gel}\"\n table grouped_ops.start_table\n .custom_column(heading: \"Gel ID\") { |op| op.input(FRAGMENT).item.id }\n .custom_column(heading: \"Row\") { |op| op.input(FRAGMENT).row + 1 }\n .custom_column(heading: \"Column\", checkable: true) { |op| op.input(FRAGMENT).column + 1 }\n .custom_column(heading: \"Expected Length\") { |op| op.output(FRAGMENT_OUT).sample.properties[\"Length\"] }\n .get(:correct, type: 'text', heading: \"Does the band match the expected length? (y/n)\", default: 'y')\n .custom_column(heading: \"User\") { |op| op.user.name }\n .custom_column(heading: \"Fragment Name\") { |op| op.output(FRAGMENT_OUT).sample.name }\n .end_table\n }\n end \n \n # This method instructs the technician to cut out fragments associated to the given operations.\n def cut_fragments grouped_ops \n show {\n title \"Cut Out Fragments\"\n note \"Take out #{grouped_ops.length} 1.5 mL tubes and label accordingly: #{grouped_ops.map { |op| \"#{op.output(\"Fragment\").item}\" }.to_sentence}\"\n note \"Now, cut out the bands and place them into the 1.5 mL tubes according to the following table:\"\n table grouped_ops.start_table \n .custom_column(heading: \"Gel ID\") { |op| \"#{op.input(FRAGMENT).item}\" }\n .custom_column(heading: \"Row\") { |op| op.input(FRAGMENT).row + 1 }\n .custom_column(heading: \"Column\", checkable: true) { |op| op.input(FRAGMENT).column + 1 }\n .custom_column(heading: \"1.5 mL Tube ID\") { |op| \"#{op.output(FRAGMENT_OUT).item}\" }\n .custom_column(heading: \"Length\") { |op| op.output(FRAGMENT_OUT).sample.properties[\"Length\"] }\n .end_table\n }\n end\n \n # This method instructs the technician to weigh gel slices.\n def weigh_fragments grouped_ops\n show {\n title \"Weigh Gel Slices\"\n note \"Perform this step using the scale inside the gel room.\"\n check \"Zero the scale with an empty 1.5 mL tube.\"\n check \"Weigh each slice and enter the weights in the following table:\"\n table grouped_ops.start_table\n .custom_column(heading: \"1.5 mL Tube ID\") { |op| \"#{op.output(FRAGMENT_OUT).item}\" }\n .get(:weight, type: 'number', heading: \"Weight (g)\", default: MIN_WEIGHT)\n .end_table\n }\n end\n \n # This method instructs the technician to clean up and dispose of gels.\n def clean_up gel, gels\n show {\n title \"Clean Up\"\n check \"Turn off the transilluminator.\"\n check \"Dispose of the gel #{gel} and any gel parts by placing it in the waste container. Spray the surface of the transilluminator with ethanol and wipe until dry using a paper towel.\"\n check \"Clean up the gel box and casting tray by rinsing with water. Return them to the gel station.\"\n if(gel==gels.last)\n check \"Dispose gloves after leaving the room.\"\n end\n }\n end\nend","precondition":"def precondition(op)\n true\nend","cost_model":"# Extract Fragment from Gel Cost Model\n\ndef cost(op)\n {\n materials: 0.20,\n labor: 3.02 \n } \nend","documentation":"Extracts a gel fragment from a gel.\n\nA gel, after gel electrophoresis has been run, is imaged, and the technician uploads both the gel image and verifies whether or not the fragment matches the expected size. If the fragment is the correct length, the fragment is extracted from the gel; if it isn't, the operation errors out and the fragment is thrown out.\n\nRan after **Run Gel** and is a precursor to **Make PCR Fragment**. ","test":"","timing":{"start":600,"stop":630,"days":"[\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\"]","active":true}}},{"sample_types":[{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":9,"parent_id":2,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":10,"parent_id":2,"name":"Sequence Verification","ftype":"url","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":11,"parent_id":2,"name":"Bacterial Marker","ftype":"string","choices":"Amp,Kan,Amp + Kan,Spec,Kan + Spec,Chlor,Tet,NA,Other","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":12,"parent_id":2,"name":"Yeast Marker","ftype":"string","choices":"HIS,TRP,URA,LEU,NatMX,KanMX,HygMX,BleoMX,5FOA,NA,Other","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":12,"field_type_id":12,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":13,"parent_id":2,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":14,"parent_id":2,"name":"Sequencing Primers","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":13,"field_type_id":14,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":15,"parent_id":2,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":14,"field_type_id":15,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":16,"parent_id":2,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":15,"field_type_id":16,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":17,"parent_id":2,"name":"QC_length","ftype":"number","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":18,"parent_id":2,"name":"Transformation Temperature","ftype":"number","choices":"37,30","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":19,"parent_id":3,"name":"Overhang Sequence","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":20,"parent_id":3,"name":"Anneal Sequence","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":21,"parent_id":3,"name":"T Anneal","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]}],"object_types":[{"id":9,"name":"TB Overnight of Plasmid","description":"An overnight of E. coli transformed with a plasmid in TB + antibiotic","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":0.01,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"DFO","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":10,"name":"Plasmid Stock","description":"A 1.5 mL tube containing purified plasmid DNA","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"concentration:","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":2.0,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"}],"operation_type":{"name":"Make Miniprep","category":"Cloning","deployed":false,"on_the_fly":false,"field_types":[{"ftype":"sample","role":"input","name":"Plasmid","sample_types":["Plasmid"],"object_types":["TB Overnight of Plasmid"],"part":false,"array":false,"routing":"P","preferred_operation_type_id":29,"preferred_field_type_id":120,"choices":null},{"ftype":"sample","role":"output","name":"Plasmid","sample_types":["Plasmid"],"object_types":["Plasmid Stock"],"part":false,"array":false,"routing":"P","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"needs \"Cloning Libs/Cloning\"\nneeds \"Standard Libs/Feedback\"\n\nclass Protocol\n include Feedback\n include Cloning\n\n def main\n # Find all overnights and take them\n operations.retrieve\n\n # Verify whether each overnight has growth\n verify_growth = show do\n title \"Check if overnights have growth\"\n note \"Choose No for the overnight that does not have growth and throw them away or put in the clean station.\"\n operations.each do |op|\n item_id = op.input(\"Plasmid\").child_item.id\n select [\"Yes\", \"No\"], var: \"#{item_id}\", label: \"Does tube #{item_id} have growth?\"\n end\n end\n \n # if no growth, delete the overnight \n operations.each do |op|\n item = op.input(\"Plasmid\").child_item\n if verify_growth[\"#{item.id}\".to_sym] == \"No\"\n item.mark_as_deleted\n op.error :no_growth, \"The overnight has no growth.\" \n end\n end\n \n operations.running.make\n \n #transfer each overnight into 1.5 mL tube\n show do \n title \"Transfer Overnights into 1.5 mL Tubes\"\n note \"Grab #{operations.length} 1.5 mL tubes and label from 1 to #{operations.length}\"\n note \"Transfer 1.5 mL of the overnight into the corresponding 1.5 mL tube.\"\n index = 0\n table operations.start_table\n .input_item(\"Plasmid\")\n .custom_column(heading: \"Tube Number\") { index = index + 1 }\n .end_table\n end\n \n #Spin down cells and remove supernatant\n show do \n title \"Spin down the cells\"\n check \"Spin at 5,800 xg for 2 minutes, make sure to balance.\"\n check \"Remove the supernatant. Pour off the supernatant into liquid waste, being sure not to upset the pellet. Pipette out the residual supernatant.\"\n end\n \n # Resuspend in P1, P2, N3\n show do\n title \"Resuspend in P1, P2, N3\"\n check \"Add 250 uL of P1 into each tube and vortex strongly to resuspend.\"\n check \"Add 250 uL of P2 and gently invert 5-10 times to mix, tube contents should turn blue.\"\n check \"Pipette 350 uL of N3 into each tube and gently invert 5-10 times to mix. Tube contents should turn colorless.\"\n warning \"Time between adding P2 and N3 should be minimized. Cells should not be exposed to active P2 for more than 5 minutes\"\n end\n\n # Centrifuge and add to miniprep columns \n show do\n title \"Centrifuge and add to columns\"\n check \"Spin tubes at 17,000 xg for 10 minutes\"\n warning \"Make sure to balance the centrifuge.\"\n check \"Grab #{operations.running.length} blue miniprep spin columns and label with 1 to #{operations.running.length}.\"\n check \"Remove the tubes from centrifuge and carefully pipette the supernatant (up to 750 uL) into the same labeled columns.\"\n warning \"Be careful not to disturb the pellet.\"\n check \"Discard the used 1.5 mL tubes into waste bin.\"\n end\n \n # Spin and wash \n show do \n title \"Spin and Wash\"\n check \"Spin all columns at 17,000 xg for 1 minute. Make sure to balance.\"\n check \"Remove the columns from the centrifuge and discard the flow through into a liquid waste container\"\n check \"Add 750 uL of PE buffer to each column. Make sure the PE bottle that you are using has ethanol added!\"\n check \"Spin the columns at 17,000 xg for 1 minute\"\n check \"Remove the columns from the centrifuge and discard the flow through into a liquid waste container.\"\n check \"Perform a final spin: spin all columns at 17,000 xg for 1 minute.\"\n end\n\n #Elute w water\n show do \n title \"Elute with water\"\n check \"Grab #{operations.length} new 1.5 mL tubes and label top of the tube with 1 to #{operations.length}.\"\n check \"Remove the columns from the centrifuge\"\n check \"Inidividually take each column out of the flowthrough collector and put it into the labeled 1.5 mL tube with the same number, discard the flowthrough collector.\"\n warning \"For this step, use a new pipette tip for each sample to avoid cross contamination\"\n check \"Pipette 50 uL of water into the CENTER of each column\"\n check \"Let the tubes sit on the bench for 2 minutes\"\n check \"Spin the columns at 17,000 xg for 1 minute\"\n check \"Remove the tubes and discard the columns\" \n end \n \n # Relabel tubes w output ids\n show do \n title \"Relabel Tubes\"\n note \"Relabel each tube with the corresponding item ID\"\n index = 0\n table operations.start_table \n .custom_column(heading: \"Tube Number\") { index = index + 1 }\n .output_item(\"Plasmid\")\n .end_table\n end\n \n # nanodrop and get concentration\n show do \n title \"Nanodrop and Enter Concentration\"\n note \"Nanodrop each plasmid and enter the concentration below\"\n table operations.start_table\n .output_item(\"Plasmid\")\n .get(:concentration, type: \"number\", heading: \"Concentration\", default: 200)\n .end_table\n end\n \n # set concentration of plasmid stock and change location of overnights\n operations.running.each do | op |\n op.set_output_data \"Plasmid\", :concentration, op.temporary[:concentration]\n op.set_output_data \"Plasmid\", :from, op.input(\"Plasmid\").item.id\n op.plan.associate \"overnight_#{op.input(\"Plasmid\").sample.id}\", op.input(\"Plasmid\").item.id\n op.plan.associate :plasmid, op.output(\"Plasmid\").item.id\n op.input(\"Plasmid\").child_item.store\n \n pass_data \"sequencing results\", \"sequence_verified\", from: op.input(\"Plasmid\").item, to: op.output(\"Plasmid\").item\n end\n \n operations.running.store\n \n get_protocol_feedback()\n \n return {}\n \n end\n\nend\n","precondition":"def precondition(op)\n true\nend","cost_model":"def cost(op)\n { labor: 11.65, materials: 1.53 }\nend","documentation":"Purifies overnight and creates an unverified plasmid stock for later use.\n\nThe overnight is purified by the technician, an the end product is an unverified plasmid stock, which will be sent out for sequencing. The overnight is stored in the fridge, for use later in **Make Glycerol Stock**.\n\nRan the day after **Make Overnight Suspension** and is a precursor to **Send to Sequencing**.","test":"","timing":{"start":495,"stop":570,"days":"[\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\",\"Sa\"]","active":true}}},{"sample_types":[{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":9,"parent_id":2,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":10,"parent_id":2,"name":"Sequence Verification","ftype":"url","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":11,"parent_id":2,"name":"Bacterial Marker","ftype":"string","choices":"Amp,Kan,Amp + Kan,Spec,Kan + Spec,Chlor,Tet,NA,Other","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":12,"parent_id":2,"name":"Yeast Marker","ftype":"string","choices":"HIS,TRP,URA,LEU,NatMX,KanMX,HygMX,BleoMX,5FOA,NA,Other","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":12,"field_type_id":12,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":13,"parent_id":2,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":14,"parent_id":2,"name":"Sequencing Primers","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":13,"field_type_id":14,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":15,"parent_id":2,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":14,"field_type_id":15,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":16,"parent_id":2,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":15,"field_type_id":16,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":17,"parent_id":2,"name":"QC_length","ftype":"number","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":18,"parent_id":2,"name":"Transformation Temperature","ftype":"number","choices":"37,30","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":19,"parent_id":3,"name":"Overhang Sequence","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":20,"parent_id":3,"name":"Anneal Sequence","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":21,"parent_id":3,"name":"T Anneal","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]}],"object_types":[{"id":6,"name":"Checked E coli Plate of Plasmid","description":"It's a checked plate","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"plate","cost":0.01,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":11,"name":"Plasmid Glycerol Stock","description":"Glycerol Stock of E. coli (usually DH5alpha) containing plasmid DNA stock","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":5.0,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M80","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":9,"name":"TB Overnight of Plasmid","description":"An overnight of E. coli transformed with a plasmid in TB + antibiotic","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":0.01,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"DFO","rows":null,"columns":null,"sample_type_name":"Plasmid"}],"operation_type":{"name":"Make Overnight Suspension","category":"Cloning","deployed":false,"on_the_fly":false,"field_types":[{"ftype":"sample","role":"input","name":"Plasmid","sample_types":["Plasmid","Plasmid"],"object_types":["Checked E coli Plate of Plasmid","Plasmid Glycerol Stock"],"part":false,"array":false,"routing":"P","preferred_operation_type_id":28,"preferred_field_type_id":118,"choices":null},{"ftype":"sample","role":"output","name":"Overnight","sample_types":["Plasmid"],"object_types":["TB Overnight of Plasmid"],"part":false,"array":false,"routing":"P","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"# Note: This change (08/22/2018) reverts back to July 26, 2018 version\n\nneeds \"Cloning Libs/Cloning\"\nneeds \"Standard Libs/Debug\"\nneeds \"Standard Libs/Feedback\"\n\nclass Protocol\n\n include Feedback \n include Cloning\n include Debug\n\n def main\n \n operations.retrieve(interactive: false)\n \n # Increase the number of colonies picked the plate. If no picked number is present,\n # set it equal to one. Note that setting the status to \"error\" will remove the operation\n # from operations.running, so it will not be listed in tables, etc.\n operations.select { |op| op.input(\"Plasmid\").item.object_type_id == ObjectType.where(name: \"Checked E coli Plate of Plasmid\").first.id }.each do |op|\n nc = (op.input_data \"Plasmid\", :num_colonies).to_i\n np = (op.input_data \"Plasmid\", :num_picked).to_i\n if debug \u0026\u0026 !nc \u0026\u0026 rand(2) == 1\n op.set_input_data \"Plasmid\", :num_colonies, 1\n op.set_input_data \"Plasmid\", :num_picked, 1\n elsif !nc || nc == 0 || ( np \u0026\u0026 np \u003e= nc )\n op.error :missing_data, \"No colonies left on plate or colony number not defined\"\n else\n op.set_input_data \"Plasmid\", :num_picked, (np || 0) + 1\n end\n end\n \n # Error out operations whose samples don't have bacterial marker data. Tell technician\n # which ones are not being used. Quit if there are no samples left.\n operations.each do |op|\n unless op.input(\"Plasmid\").child_sample.properties[\"Bacterial Marker\"]\n if debug \u0026\u0026 rand(2) == 1\n op.input(\"Plasmid\").child_sample.set_property \"Bacterial Marker\", \"Amp\"\n else\n op.set_status \"error\"\n op.associate :missing_marker, \"No bacterial marker associated with plasmid\"\n end\n end\n end\n \n operations.make\n \n p_ot = ObjectType.where(name: \"Checked E coli Plate of Plasmid\").first \n \n raise \"Could not find object type 'Checked E coli Plate of Plasmid'\" unless p_ot\n \n plate_inputs = operations.running.select { |op| op.input(\"Plasmid\").item.object_type_id == p_ot.id }\n \n g_ot = ObjectType.where(name: \"Plasmid Glycerol Stock\").first \n \n raise \"Could not find object type 'Plasmid Glycerol Stock'\" unless g_ot \n \n glycerol_stock_inputs = operations.running.select { |op| op.input(\"Plasmid\").item.object_type_id == g_ot.id }\n \n overnight_steps plate_inputs, \"Checked E coli Plate of Plasmid\" if plate_inputs.any?\n overnight_steps glycerol_stock_inputs, \"Plasmid Glycerol Stock\" if glycerol_stock_inputs.any?\n \n # Associate input id with from data for overnight.\n operations.running.each do |op|\n gs = op.input(\"Plasmid\").item\n on = op.output(\"Overnight\").item\n \n on.associate :from, gs.id\n pass_data \"sequencing results\", \"sequence_verified\", from: gs, to: on\n end\n \n operations.running.each do |op|\n op.output(\"Overnight\").child_item.move \"37 C shaker incubator\"\n end\n \n operations.store\n \n return {}\n\n end \n \n # This method sorts operations by the bacterial marker attribute and then\n # starts overnight steps by calling the methods label_load_tubes and inoculate.\n def overnight_steps(ops, ot)\n if ot == \"Plasmid Glycerol Stock\"\n ops.retrieve interactive: false\n else\n ops.retrieve\n end\n \n # Sorting ops by the bacterial marker attribute\n temp = ops.sort do |op1,op2|\n op1.input(\"Plasmid\").child_sample.properties[\"Bacterial Marker\"].upcase \u003c=\u003e op2.input(\"Plasmid\").child_sample.properties[\"Bacterial Marker\"].upcase\n end\n ops = temp\n \n ops.extend(OperationList)\n \n #Label and load overnight tubes \n label_load_tubes ops\n\n #Inoculation\n inoculate ot, ops\n \n end\n \n # Given operations, tells the technician to label and load the tubes the tubes\n def label_load_tubes ops\n show do\n title \"Label and load overnight tubes\"\n note \"In the Media Bay, collect #{ops.length} 14mL tubes\"\n note \"Write the overnight id on the corresponding tube and load with the correct media type.\"\n table ops.start_table\n .output_item(\"Overnight\", checkable: true)\n .custom_column(heading: \"Media\") { |op| \"TB+\" + op.input(\"Plasmid\").child_sample.properties[\"Bacterial Marker\"].upcase }\n .custom_column(heading: \"Quantity\") { |op| \"3 mL\" }\n .end_table\n end\n end\n \n # Tells the technician to inoculate colonies from plate into 14 ml tubes.\n def inoculate ot, ops\n show {\n title \"Inoculation from #{ot}\"\n note \"Use 10 uL sterile tips to inoculate colonies from plate into 14 mL tubes according to the following table.\" if ot == \"Checked E coli Plate of Plasmid\"\n check \"Mark each colony on the plate with corresponding overnight id. If the same plate id appears more than once in the table, inoculate different isolated colonies on that plate.\" if ot == \"Checked E coli Plate of Plasmid\"\n note \"Use 100 uL pipette to inoculate cells from glycerol stock into the 14 mL tube according to the following table.\" if ot == \"Plasmid Glycerol Stock\"\n table ops.start_table\n .input_item(\"Plasmid\", heading: ot)\n .custom_column(heading: \"#{ot} Location\") { |op| op.input(\"Plasmid\").item.location }\n .output_item(\"Overnight\", checkable: true)\n .end_table \n } \n end\nend ","precondition":"def precondition(op)\n true\nend","cost_model":"#TODO: Multiple overnight suspension/plate protocols\n#Specific to Miniprep(?)\ndef cost(op)\n { labor: 3.88, materials: 0.86 }\nend","documentation":"Selects a colony from a transformed E. coli plate of cells and makes overnight suspension.\n\nOnce the plate with transformed E. coli cells has been checked, the technician will pick out a colony and suspend it in either TB + Amp or TB + Kan. The suspension is then inoculated overnight in the 37 F shaker incubator.\n\nRan after **Check Plate** and is a precursor to **Make Miniprep**.","test":"","timing":{"start":900,"stop":1050,"days":"[\"Su\",\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\"]","active":true}}},{"sample_types":[{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":19,"parent_id":3,"name":"Overhang Sequence","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":20,"parent_id":3,"name":"Anneal Sequence","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":21,"parent_id":3,"name":"T Anneal","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":9,"parent_id":2,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":10,"parent_id":2,"name":"Sequence Verification","ftype":"url","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":11,"parent_id":2,"name":"Bacterial Marker","ftype":"string","choices":"Amp,Kan,Amp + Kan,Spec,Kan + Spec,Chlor,Tet,NA,Other","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":12,"parent_id":2,"name":"Yeast Marker","ftype":"string","choices":"HIS,TRP,URA,LEU,NatMX,KanMX,HygMX,BleoMX,5FOA,NA,Other","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":12,"field_type_id":12,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":13,"parent_id":2,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":14,"parent_id":2,"name":"Sequencing Primers","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":13,"field_type_id":14,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":15,"parent_id":2,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":14,"field_type_id":15,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":16,"parent_id":2,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":15,"field_type_id":16,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":17,"parent_id":2,"name":"QC_length","ftype":"number","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":18,"parent_id":2,"name":"Transformation Temperature","ftype":"number","choices":"37,30","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":1,"parent_id":1,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":2,"parent_id":1,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":3,"parent_id":1,"name":"Template","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":1,"field_type_id":3,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":2,"field_type_id":3,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":3,"field_type_id":3,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":4,"field_type_id":3,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":5,"field_type_id":3,"sample_type_id":6,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Plasmid","E coli strain","Fragment","Yeast Strain","DNA Library"],"object_types":[null,null,null,null,null]},{"id":4,"parent_id":1,"name":"Forward Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":6,"field_type_id":4,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":7,"field_type_id":4,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":5,"parent_id":1,"name":"Reverse Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":8,"field_type_id":5,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":9,"field_type_id":5,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":6,"parent_id":1,"name":"Restriction Enzyme(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":7,"parent_id":1,"name":"Yeast Marker","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":8,"parent_id":1,"name":"Fragment Mix Array","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":10,"field_type_id":8,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":11,"field_type_id":8,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]}]},{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":22,"parent_id":4,"name":"Parent","ftype":"sample","choices":null,"array":null,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":16,"field_type_id":22,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["E coli strain"],"object_types":[null]}]},{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":23,"parent_id":5,"name":"Parent","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":17,"field_type_id":23,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]},{"id":24,"parent_id":5,"name":"Integrant","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":18,"field_type_id":24,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":19,"field_type_id":24,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid","Fragment"],"object_types":[null,null]},{"id":25,"parent_id":5,"name":"Plasmid","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":20,"field_type_id":25,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid"],"object_types":[null]},{"id":26,"parent_id":5,"name":"Integrated Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":27,"parent_id":5,"name":"Plasmid Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":28,"parent_id":5,"name":"Mating Type","ftype":"string","choices":"MATa,MATalpha,Diploid","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":29,"parent_id":5,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":21,"field_type_id":29,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":30,"parent_id":5,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":22,"field_type_id":30,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":31,"parent_id":5,"name":"QC_length","ftype":"number","choices":"","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":32,"parent_id":5,"name":"Comp_cell_limit","ftype":"string","choices":"Yes,No","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":33,"parent_id":5,"name":"Media","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":34,"parent_id":5,"name":"Has this strain passed QC?","ftype":"string","choices":"No,Yes","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":35,"parent_id":5,"name":"Haploids","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":23,"field_type_id":35,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]}]},{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":36,"parent_id":6,"name":"Oligo Pool","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":24,"field_type_id":36,"sample_type_id":7,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Oligo Pool"],"object_types":[null]}]},{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":37,"parent_id":7,"name":"Manufacturer","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":38,"parent_id":7,"name":"Oligo Library ID","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":39,"parent_id":7,"name":"inner forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":25,"field_type_id":39,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":40,"parent_id":7,"name":"inner reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":26,"field_type_id":40,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":41,"parent_id":7,"name":"sublibrary forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":27,"field_type_id":41,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":42,"parent_id":7,"name":"sublibrary reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":28,"field_type_id":42,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":43,"parent_id":7,"name":"min length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":44,"parent_id":7,"name":"max length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":45,"parent_id":7,"name":"variants (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":46,"parent_id":7,"name":"sublibrary name (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":47,"parent_id":7,"name":"forward priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":48,"parent_id":7,"name":"reverse priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]}],"object_types":[{"id":12,"name":"Primer Aliquot","description":"Primers at low concentration (10uM) for every day use","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"{ \"measure\": { \"type\": \"concentration\", \"unit\": \"micromolar\" } }","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Primer","cost":0.01,"release_method":"return","release_description":"","sample_type_id":3,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Primer"},{"id":13,"name":"1 ng/µL Plasmid Stock","description":"Diluted stock for use as a template in PCR","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":0.01,"release_method":"query","release_description":"If this is an aliquot for the \"Transformation Efficiency Project\", dispose of it. Otherwise, return it.","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":3,"name":"Fragment Stock","description":"Fragment stock in 1.5 mL tube, usually stored in M20 fridge.","min":0,"max":1000,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Fragment","cost":50.0,"release_method":"return","release_description":"","sample_type_id":1,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Fragment"},{"id":10,"name":"Plasmid Stock","description":"A 1.5 mL tube containing purified plasmid DNA","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"concentration:","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":2.0,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":14,"name":"1 ng/µL Fragment Stock","description":"A diluted fragment stock to use as a PCR template","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:58.000-07:00","unit":"Fragment","cost":0.01,"release_method":"return","release_description":"","sample_type_id":1,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Fragment"},{"id":15,"name":"Unverified Plasmid Stock","description":"A plasmid stock that has yet to be sequenced verified","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:58.000-07:00","unit":"Plasmid","cost":0.01,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":4,"name":"Gibson Reaction Result","description":"A plasmid that was made from Gibson reaction and stayed in the Gibson reaction tube. One can use this to do transform and extract the plasmid.","min":0,"max":1000,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":10.0,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":16,"name":"50X PCR Template","description":"DNA at an appropriate concentration to be used at 1 µl in a 50 µl PCR","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:58.000-07:00","unit":"DNA Library","cost":0.01,"release_method":"return","release_description":"","sample_type_id":6,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"DNA Library"},{"id":17,"name":"Unverified PCR Fragment","description":"An amplicon that has not been verified after a polymerization experiment","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:58.000-07:00","unit":"Fragment","cost":0.01,"release_method":"return","release_description":"","sample_type_id":3,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Primer"},{"id":18,"name":"Stripwell","description":"Stripwell","min":0,"max":10000,"handler":"collection","safety":"No safety information","cleanup":"No cleanup information","data":" {\r\n \"materials\": 10.48,\r\n \"labor\": 10\r\n }","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"stripwell","cost":1.0,"release_method":"query","release_description":"","sample_type_id":null,"image":null,"prefix":"","rows":1,"columns":12,"sample_type_name":null}],"operation_type":{"name":"Make PCR Fragment","category":"Cloning","deployed":false,"on_the_fly":false,"field_types":[{"ftype":"sample","role":"input","name":"Forward Primer","sample_types":["Primer"],"object_types":["Primer Aliquot"],"part":false,"array":false,"routing":"FP","preferred_operation_type_id":22,"preferred_field_type_id":102,"choices":null},{"ftype":"sample","role":"input","name":"Reverse Primer","sample_types":["Primer"],"object_types":["Primer Aliquot"],"part":false,"array":false,"routing":"RP","preferred_operation_type_id":22,"preferred_field_type_id":102,"choices":null},{"ftype":"sample","role":"input","name":"Template","sample_types":["Plasmid","Fragment","Plasmid","Fragment","Plasmid","Plasmid","DNA Library","Fragment"],"object_types":["1 ng/µL Plasmid Stock","Fragment Stock","Plasmid Stock","1 ng/µL Fragment Stock","Unverified Plasmid Stock","Gibson Reaction Result","50X PCR Template","Unverified PCR Fragment"],"part":false,"array":false,"routing":"T","preferred_operation_type_id":30,"preferred_field_type_id":122,"choices":null},{"ftype":"sample","role":"output","name":"Fragment","sample_types":["Fragment"],"object_types":["Stripwell"],"part":true,"array":false,"routing":"F","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"needs \"Cloning Libs/Cloning\"\nneeds 'PCR Libs/GradientPcrBatching'\nneeds 'Standard Libs/Debug'\nneeds 'Standard Libs/Feedback'\n\nclass Protocol\n \n # I/O\n FWD = \"Forward Primer\"\n REV = \"Reverse Primer\"\n TEMPLATE = \"Template\"\n FRAGMENT = \"Fragment\"\n \n # other\n SEC_PER_KB = 30 # sec, extension timer per KB for KAPA\n \n # get the gradient PCR magic\n include Cloning\n include GradientPcrBatching\n include Debug\n include Feedback\n\n def main\n \n # grab all necessary items\n dilute_stocks_and_retrieve TEMPLATE\n kapa_stock_item = find(:sample, name: \"Kapa HF Master Mix\")[0].in(\"Enzyme Stock\")[0]\n take [kapa_stock_item], interactive: true, method: \"boxes\"\n \n #check the volumes of input primers for all operations, and ensure they are sufficient\n operations.each { |op| op.temporary[:primer_vol] = 2.5 }\n check_volumes [FWD, REV], :primer_vol, :make_aliquots_from_stock, check_contam: true\n \n # build a pcrs hash that groups pcr by T Anneal\n pcrs = build_pcrs_hash\n\n # show the result of the binning algorithm\n pcrs.each_with_index do |pcr, idx|\n show { title \"pcr #{idx}\"}\n log_bin_info pcr\n end if debug\n\n # generate a table for stripwells\n stripwell_tab = build_stripwell_table pcrs\n \n # prepare and label stripwells for PCR\n prepare_stripwells stripwell_tab\n \n # add templates to stripwells for pcr\n load_templates pcrs\n \n # add primers to stripwells\n load_primers pcrs\n\n # add kapa master mix to stripwells\n add_mix stripwell_tab, kapa_stock_item\n \n # run the thermocycler\n start_pcr pcrs\n \n # store \n operations.running.store io: \"input\", interactive: true, method: \"boxes\"\n release [kapa_stock_item], interactive: true\n \n get_protocol_feedback\n \n return {batches: pcrs}\n end\n \n # dilute to 1ng/uL stocks if necessary\n def dilute_stocks_and_retrieve input\n \n # only use inputs that haven't been diluted and that don't have diluted stocks already\n ops_w_undiluted_template = operations.reject { true }\n operations.each do |op|\n next if op.input(input).object_type.name.include?(\"1 ng/L\") || op.input(input).object_type.name.include?(\"50X PCR Template\") || op.input(input).object_type.name.include?(\"Unverified PCR Fragment\")\n \n sample = op.input(input).sample\n ot_name = op.input(input).object_type.name.include?(\"Unverified\") ? \"1 ng/L Plasmid Stock\" : \"1 ng/L \" + sample.sample_type.name + \" Stock\"\n diluted_stock = sample.in(ot_name).first\n \n if diluted_stock\n op.input(input).set item: diluted_stock\n else\n new_stock = produce new_sample sample.name, of: sample.sample_type.name, as: ot_name\n op.temporary[:diluted_stock] = new_stock\n \n ops_w_undiluted_template.push op\n end\n end\n \n # retrieve operation inputs (doesn't include the stocks replaced by diluted stocks above)\n ops_w_undiluted_template.retrieve\n \n # all stocks may be diluted already\n if ops_w_undiluted_template.empty?\n operations.retrieve\n return\n end\n \n # ensure concentrations\n check_concentration ops_w_undiluted_template, input\n \n # dilute stocks\n show do\n title \"Make 1 ng/L Template Stocks\"\n \n check \"Grab #{ops_w_undiluted_template.length} 1.5 mL tubes, label them with #{ops_w_undiluted_template.map { |op| op.temporary[:diluted_stock].id }.join(\", \")}\"\n check \"Add template stocks and water into newly labeled 1.5 mL tubes following the table below\"\n \n table ops_w_undiluted_template\n .start_table\n .custom_column(heading: \"Newly-labeled tube\") { |op| op.temporary[:diluted_stock].id }\n .input_item(input, heading: \"Template stock, 1 uL\", checkable: true)\n .custom_column(heading: \"Water volume\", checkable: true) { |op| op.input(input).item.get(:concentration).to_f - 1 }\n .end_table\n check \"Vortex and then spin down for a few seconds\"\n end\n \n # Add association from which item the 1ng/ul dilution came from\n ops_w_undiluted_template.map { |op| op.temporary[:diluted_stock].associate(:diluted_from, op.input(input).item.id) }\n \n\n # return input stocks\n release ops_w_undiluted_template.map { |op| op.input(input).item }, interactive: true, method: \"boxes\"\n \n # retrieve the rest of the inputs\n operations.reject { |op| ops_w_undiluted_template.include? op }.retrieve\n \n # set diluted stocks as inputs\n ops_w_undiluted_template.each { |op| op.input(input).set item: op.temporary[:diluted_stock] }\n end\n \n \n # TODO dilute from stock if item is aliquot\n # Callback for check_volume.\n # takes in lists of all ops that have input aliquots with insufficient volume, sorted by item,\n # and takes in the inputs which were checked for those ops.\n # Deletes bad items and remakes each from primer stock\n def make_aliquots_from_stock bad_ops_by_item, inputs\n # bad_ops_by_item is accessible by bad_ops_by_item[item] = [op1, op2, op3...]\n # where each op has a bad volume reading for the given item\n \n # Construct list of all stocks needed for making aliquots. Error ops for which no primer stock is available\n # for every non-errored op that has low item volume,\n # replace the old aliquot item with a new one. \n aliquots_to_make = 0\n stocks = []\n ops_by_fresh_item = Hash.new(0)\n stock_table = [[\"Primer Stock ID\", \"Primer Aliquot ID\"]]\n transfer_table = [[\"Old Aliquot ID\", \"New Aliquot ID\"]]\n bad_ops_by_item.each do |item, ops|\n stock = item.sample.in(\"Primer Stock\").first ######## items is a string?\n if stock.nil?\n ops.each { |op| op.error :no_primer, \"You need to order a primer stock for primer sample #{item.sample.id}.\" }\n bad_ops_by_item.except! item\n else\n stocks.push stock\n aliquots_to_make += 1\n item.mark_as_deleted\n fresh_item = produce new_sample item.sample.name, of: item.sample.sample_type.name, as: item.object_type.name\n bad_ops_by_item.except! item\n ops_by_fresh_item[fresh_item] = ops\n ops.each do |op| \n input = inputs.find { |input| op.input(input).item == item }\n op.input(input).set item: fresh_item\n end\n stock_table.push [stock.id, {content: fresh_item.id, check: true}]\n if item.get(:contaminated) != \"Yes\"\n transfer_table.push [item.id, {content: fresh_item.id, check: true}] \n end\n end\n end\n \n bad_ops_by_item.merge! ops_by_fresh_item\n take stocks, interactive: true\n \n # label new aliquot tubes and dilute\n show do \n title \"Grab 1.5 mL tubes\"\n \n note \"Grab #{aliquots_to_make} 1.5 mL tubes\"\n note \"Label each tube with the following ids: #{bad_ops_by_item.keys.map { |item| item.id }.sort.to_sentence}\"\n note \"Using the 100 uL pipette, pipette 90uL of water into each tube\"\n end\n \n # make new aliquots\n show do \n title \"Transfer primer stock into primer aliquot\"\n \n note \"Pipette 10 uL of the primer stock into the primer aliquot according to the following table:\"\n table stock_table\n end\n \n \n if transfer_table.length \u003e 1\n show do\n title \"Transfer Residual Primer\"\n \n note \"Transfer primer residue from the low volume aliquots into the fresh aliquots according to the following table:\"\n table transfer_table\n end\n end\n \n release stocks, interactive: true\n end\n \n # build a pcrs hash that groups pcr by T Anneal\n def build_pcrs_hash\n \n pcr_operations = operations.map do |op|\n PcrOperation.new({\n extension_time: op.output(FRAGMENT).sample.properties[\"Length\"] * SEC_PER_KB / 1000,\n anneal_temp: min(op.input(FWD).sample.properties[\"T Anneal\"], op.input(REV).sample.properties[\"T Anneal\"]),\n unique_id: op.id\n })\n end\n\n result_hash = batch(pcr_operations)\n pcr_reactions = []\n result_hash.each do |thermocycler_group, row_groups|\n reaction = {}\n extension_time = thermocycler_group.max_extension + 60\n reaction[:mm], reaction[:ss] = (extension_time.to_i).divmod(60)\n reaction[:mm] = \"0#{reaction[:mm]}\" if reaction[:mm].between?(0, 9)\n reaction[:ss] = \"0#{reaction[:ss]}\" if reaction[:ss].between?(0, 9)\n \n reaction[:ops_by_bin] = {}\n sorted_rows = row_groups.to_a.sort { |a,b| a.min_anneal \u003c=\u003e b.min_anneal }\n sorted_rows.each do |row_group|\n reaction[:ops_by_bin][row_group.min_anneal.round(1)] = [].extend(OperationList)\n row_group.members.sort { |a,b| a.anneal_temp \u003c=\u003e b.anneal_temp }.each do |pcr_op|\n reaction[:ops_by_bin][row_group.min_anneal.round(1)] \u003c\u003c (Operation.find(pcr_op.unique_id))\n end\n end\n \n # trim bin if we cant fit all rows into one thermocycler\n while reaction[:ops_by_bin].keys.size \u003e 8\n extra_ops = reaction[:ops_by_bin][reaction[:ops_by_bin].keys.last]\n extra_ops.each do |op|\n op.error :batching_issue, \"We weren't able to batch this operation into a running thermocycler for this Job, try again.\"\n end\n reaction[:ops_by_bin].except(reaction[:ops_by_bin].keys.last)\n end\n \n reaction[:bins] = reaction[:ops_by_bin].keys\n reaction[:stripwells] = []\n reaction[:ops_by_bin].each do |bin, ops|\n ops.make\n reaction[:stripwells] += ops.output_collections[FRAGMENT]\n end\n pcr_reactions \u003c\u003c reaction\n end\n pcr_reactions\n end\n \n # generate a table for stripwells\n def build_stripwell_table pcrs\n stripwells = pcrs.collect { |pcr| pcr[:stripwells] }.flatten\n stripwell_tab = [[\"Stripwell\", \"Wells to pipette\"]] + stripwells.map { |sw| [\"#{sw.id} (#{sw.num_samples \u003c= 6 ? 6 : 12} wells)\", { content: sw.non_empty_string, check: true }] }\n end\n \n # prepare and label stripwells for PCR\n def prepare_stripwells stripwell_tab\n show do\n title \"Label and prepare stripwells\"\n \n note \"Label stripwells, and pipette 19 uL of molecular grade water into each based on the following table:\"\n table stripwell_tab\n stripwell_tab\n end\n end\n \n # add templates to stripwells for pcr\n def load_templates pcrs\n pcrs.each_with_index do |pcr, idx|\n show do\n title \"Load templates for PCR ##{idx + 1}\"\n \n pcr[:ops_by_bin].each do |bin, ops|\n table ops\n .start_table\n .output_collection(FRAGMENT, heading: \"Stripwell\")\n .custom_column(heading: \"Well\") { |op| op.output(FRAGMENT).column + 1 }\n .input_item(TEMPLATE, heading: \"Template, 1 uL\", checkable: true)\n .end_table\n end\n warning \"Use a fresh pipette tip for each transfer.\".upcase\n end\n end\n end\n \n # add primers to stripwells\n def load_primers pcrs\n pcrs.each_with_index do |pcr, idx|\n show do\n title \"Load primers for PCR ##{idx + 1}\"\n \n pcr[:ops_by_bin].each do |bin, ops|\n table ops.start_table\n .output_collection(FRAGMENT, heading: \"Stripwell\")\n .custom_column(heading: \"Well\") { |op| op.output(FRAGMENT).column + 1 }\n .input_item(FWD, heading: \"Forward Primer, 2.5 uL\", checkable: true)\n .input_item(REV, heading: \"Reverse Primer, 2.5 uL\", checkable: true)\n .end_table\n end\n warning \"Use a fresh pipette tip for each transfer.\".upcase\n end\n end\n end\n \n # add kapa master mix to stripwells\n def add_mix stripwell_tab, kapa_stock_item\n show do\n title \"Add Master Mix\"\n \n note \"Pipette 25 uL of master mix (#{kapa_stock_item}) into stripwells based on the following table:\"\n table stripwell_tab\n warning \"USE A NEW PIPETTE TIP FOR EACH WELL AND PIPETTE UP AND DOWN TO MIX.\"\n check \"Cap each stripwell. Press each one very hard to make sure it is sealed.\"\n end\n end\n \n # run the thermocycler and update the positions of the stripwells\n def start_pcr pcrs\n pcrs.each_with_index do |pcr, idx|\n is_gradient = pcr[:bins].length \u003e 1\n # log_bin_info pcr # use for debugging bad binning behavior\n resp = show do\n if !is_gradient\n title \"Start PCR ##{idx + 1} at #{pcr[:bins].first} C\"\n \n check \"Place the stripwell(s) #{pcr[:stripwells].collect { |sw| \"#{sw}\" }.join(\", \")} into an available thermal cycler and close the lid.\"\n get \"text\", var: \"name\", label: \"Enter the name of the thermocycler used\", default: \"TC1\"\n check \"Click 'Home' then click 'Saved Protocol'. Choose 'YY' and then 'CLONEPCR'.\"\n check \"Set the anneal temperature to \u003cb\u003e#{pcr[:bins].first} C\u003c/b\u003e. This is the 3rd temperature.\"\n else\n title \"Start PCR ##{idx + 1} (gradient) over range #{pcr[:bins].first}-#{pcr[:bins].last} C\"\n check \"Click 'Home' then click 'Saved Protocol'. Choose 'YY' and then 'CLONEPCR'.\"\n check \"Click on annealing temperature -\u003e options, and check the gradient checkbox.\"\n check \"Set the annealing temperature range to be #{pcr[:bins].first}-#{pcr[:bins].last} C.\"\n note \"Cancel this PCR batch if something doesn't look right, for example if the thermocycler does not allow this temperature range.\"\n select [\"yes\", \"no\"], var: \"batching_bad\", label: \"Cancel this batch?\", default: 1\n note \"The following stripwells are ordered front to back.\"\n \n pcr[:stripwells].map.with_index do |sw, idx|\n temp = pcr[:ops_by_bin].keys[idx].to_f\n check \"Place the stripwell #{sw} into a row of the thermocycler with the temperature as close as possible to \u003cb\u003e#{temp} C\u003c/b\u003e\"\n end\n get \"text\", var: \"name\", label: \"Enter the name of the thermocycler used\", default: \"TC1\"\n end\n check \"Set the 4th time (extension time) to be #{pcr[:mm]}:#{pcr[:ss]}.\"\n check \"Press 'Run' and select 50 uL.\"\n end\n \n impossible_pcr_handler(pcr) if resp.get_response(:batching_bad) == \"yes\"\n \n # set the location of the stripwell\n pcr[:stripwells].flatten.each do |sw|\n sw.move resp[:name]\n end\n end\n end\n \n def impossible_pcr_handler(pcr)\n pcr[:ops_by_bin].each do |bin, ops|\n ops.each do |op|\n op.error :batching_issue, \"We weren't able to batch this operation into a running thermocycler for this Job, try again.\"\n end\n end\n pcr[:stripwells].each do |sw|\n sw.mark_as_deleted\n end\n \n show do\n title 'Reaction Canceled'\n note \"All operations in this pcr reaction are canceled, try them again in a seperate job.\"\n note \"The other Reactions will go forward as planned.\"\n end\n end\n\n def log_bin_info pcr\n show do\n title \"bin info\"\n note \"ops_by_bin\"\n pcr[:ops_by_bin].each do |bin, ops|\n opids = ops.map { |op| op.id }\n check \"#{bin.to_s} =\u003e #{opids.to_s}\"\n end\n\n note \"bins\"\n pcr[:bins].each do |bin|\n check \"#{bin.to_s}\"\n end\n end\n end\nend","precondition":"def validate_property sample, field_name\r\n validation_block = Proc.new\r\n property = sample.properties[field_name]\r\n if property.nil?\r\n raise \"Could not find property #{field_name}\"\r\n end\r\n validation_block.call(sample, property)\r\nend\r\n\r\n# Appends associates msgs to plan and operation\r\ndef precondition_warnings op, msgs, key=:precondition_warnings, sep=\";\"\r\n plan = op.plan\r\n if plan\r\n plan_msg = op.plan.get key\r\n plan_msgs = plan_msg.split(sep).map { |x| x.strip } if plan_msg\r\n end\r\n plan_msgs ||= []\r\n op_msgs = []\r\n\r\n msgs.each { |valid, m|\r\n if valid\r\n plan_msgs.delete(m)\r\n else\r\n plan_msgs \u003c\u003c m\r\n op_msgs \u003c\u003c m\r\n end\r\n }\r\n op_msgs.uniq!\r\n plan_msgs.uniq!\r\n\r\n op.associate key, op_msgs.join(sep + \" \")\r\n op.plan.associate key, plan_msgs.join(sep + \" \") if op.plan\r\nend\r\n\r\ndef precondition(op)\r\n ready = true\r\n msgs = []\r\n \r\n #output fragment must have length!\r\n if op.output(\"Fragment\").sample.properties[\"Length\"].nil? || op.output(\"Fragment\").sample.properties[\"Length\"] \u003c= 0\r\n op.associate(\"Output Fragment must have a defined length!\", \"\")\r\n return false\r\n end\r\n\r\n # Validate sample, valid_block, valid_message\r\n [\"Forward Primer\", \"Reverse Primer\"].each do |n|\r\n sample = op.input(n).sample\r\n\r\n msgs \u003c\u003c validate_property(sample, \"T Anneal\") { |s, property|\r\n validator = Proc.new { |p| p.to_f.between?(0.01, 100) }\r\n msg = \"T Anneal #{property} for Primer \\\"#{s.name}\\\" is invalid\"\r\n [validator.call(property), msg]\r\n }\r\n end\r\n msgs.select! { |valid, m| !valid }\r\n msgs.compact!\r\n precondition_warnings op, msgs\r\n ready = false if msgs.any?\r\n ready\r\nend","cost_model":"# Make PCR Fragment Cost Model\n\ndef cost(op)\n {\n materials: 1.23,\n labor: 6.45\n } \nend","documentation":"Makes PCR fragment from primers.\n\nIn this protocol, the technician combines primers and templates with a master mix\nin a stripwell. They then run the PCR in a thermocycler.\n\nRan after **Extract Fragment** and before **Assemble Plasmid**.\n","test":"","timing":{"start":870,"stop":930,"days":"[\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\"]","active":true}}},{"sample_types":[{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":9,"parent_id":2,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":10,"parent_id":2,"name":"Sequence Verification","ftype":"url","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":11,"parent_id":2,"name":"Bacterial Marker","ftype":"string","choices":"Amp,Kan,Amp + Kan,Spec,Kan + Spec,Chlor,Tet,NA,Other","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":12,"parent_id":2,"name":"Yeast Marker","ftype":"string","choices":"HIS,TRP,URA,LEU,NatMX,KanMX,HygMX,BleoMX,5FOA,NA,Other","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":12,"field_type_id":12,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":13,"parent_id":2,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":14,"parent_id":2,"name":"Sequencing Primers","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":13,"field_type_id":14,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":15,"parent_id":2,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":14,"field_type_id":15,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":16,"parent_id":2,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":15,"field_type_id":16,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":17,"parent_id":2,"name":"QC_length","ftype":"number","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":18,"parent_id":2,"name":"Transformation Temperature","ftype":"number","choices":"37,30","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":19,"parent_id":3,"name":"Overhang Sequence","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":20,"parent_id":3,"name":"Anneal Sequence","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":21,"parent_id":3,"name":"T Anneal","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]}],"object_types":[{"id":19,"name":"Transformed E. coli Aliquot","description":"An aliquot containing transformed E. coli - usually in a 1.5 mL tube","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:58.000-07:00","updated_at":"2019-03-14T14:16:58.000-07:00","unit":"Plasmid","cost":0.01,"release_method":"dispose","release_description":"","sample_type_id":2,"image":null,"prefix":"","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":5,"name":"E coli Plate of Plasmid","description":"A plate containing E. coli transformed with a plasmid","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":0.01,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"DFP","rows":null,"columns":null,"sample_type_name":"Plasmid"}],"operation_type":{"name":"Plate Transformed Cells","category":"Cloning","deployed":false,"on_the_fly":false,"field_types":[{"ftype":"sample","role":"input","name":"Plasmid","sample_types":["Plasmid"],"object_types":["Transformed E. coli Aliquot"],"part":false,"array":false,"routing":"P","preferred_operation_type_id":26,"preferred_field_type_id":113,"choices":null},{"ftype":"sample","role":"output","name":"Plate","sample_types":["Plasmid"],"object_types":["E coli Plate of Plasmid"],"part":false,"array":false,"routing":"P","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"# Author: Ayesha Saleem\r\n# December 23, 2016\r\n\r\n# TO DO \r\n # Fire different antibiotic plate depending on which antibiotic it is (e.g., Amp: 30 min, Kan: 1 hr, etc.)\r\nneeds \"Standard Libs/Feedback\"\r\nclass Protocol\r\n include Feedback\r\n \r\n def name_initials str\r\n full_name = str.split\r\n begin\r\n cap_initials = full_name[0][0].upcase + full_name[1][0].upcase\r\n rescue\r\n cap_initials = \"\"\r\n end\r\n return cap_initials\r\n end\r\n \r\n def grab_plates plates, batch_num, ids, k\r\n show do\r\n title \"Grab #{plates.length} of #{k} plates\"\r\n note \"Grab #{plates.length} plates from batch #{batch_num.join(\"and\")}\"\r\n check \"Label the top of the plates with your intials, the date, and the following ids: #{ids.join(\", \")}\"\r\n end\r\n end\r\n\r\n def plate_transformed_aliquots k, aliquots, plates\r\n # plates_checkable = []\r\n # plates.each do |plate|\r\n # plates_checkable.add({content: plate, check: true})\r\n # end\r\n \r\n plates.each_with_index do |plate, i|\r\n plates[i] = ({content: plates[i], check: true})\r\n end\r\n \r\n show do \r\n title \"Plate transformed E coli aliquots\"\r\n check \"Use sterile beads to plate THE ENTIRE VOLUME (~200 uL) from the transformed aliquots (1.5 mL tubes) onto the plates, following the table below.\"\r\n warning \"Note the change in plating volume!\"\r\n check \"Discard used transformed aliquots after plating.\"\r\n table [[\"1.5 mL tube\", \"#{k} Plate\"]].concat(aliquots.zip plates)\r\n end\r\n end\r\n \r\n def spin_tubes\r\n show do\r\n title \"Spin down tubes and resuspend\"\r\n check \"Remove the transformed cells in 1.5 mL tubes from the 250 mL flask.\"\r\n check \"Centrifuge for 4,000 x g for 1 minute.\"\r\n check \"Carefully remove most of the supernatant using a P1000 pipette. Leave 200uL of supernatant in each tube.\"\r\n check \" Resuspend the cells in the remaining supernatant by vortexing.\"\r\n end\r\n end\r\n \r\n def group_plates_and_aliquots markers_new\r\n operations.each do | op | \r\n p = op.input(\"Plasmid\").item\r\n marker_key = \"LB\"\r\n p.sample.properties[\"Bacterial Marker\"].split(/[+,]/).each do |marker|\r\n marker_key = marker_key + \" + \" + marker.strip[0, 3].capitalize\r\n end\r\n \r\n if Sample.find_by_name(marker_key)\r\n markers_new[marker_key][p] = op.output(\"Plate\").item\r\n else\r\n show do \r\n note \"#{marker_key}\"\r\n end\r\n op.error :no_marker, \"There is no marker associated with this sample, so we can't plate it. Please input a marker.\"\r\n end\r\n end\r\n markers_new\r\n end \r\n \r\n def calculate_and_operate markers\r\n markers.each do | k, v| \r\n aliquots = []\r\n plates = []\r\n ids = []\r\n \r\n v.each do | al, pl|\r\n ids.push(\"#{pl.id} \" + name_initials(pl.sample.user.name))\r\n aliquots.push(al.id)\r\n al.mark_as_deleted\r\n plates.push(pl.id)\r\n pl.location = \"#{operations[0].input(\"Plasmid\").sample.properties[\"Transformation Temperature\"]} C incubator\"\r\n end\r\n \r\n b = Collection.where(object_type_id: ObjectType.find_by_name(\"Agar Plate Batch\").id)\r\n .select { |b| !b.empty? \u0026\u0026 !b.deleted? \u0026\u0026 (b.matrix[0].include? Sample.find_by_name(k).id) }.first\r\n\r\n if b.nil? # no agar plate batches exist\r\n raise \"No agar plate batches for #{k} could be found in the Inventory. Pour some plates before continuing (Manager/Pour Plates)\"\r\n end\r\n batch_num = [b.id]\r\n n = b.num_samples\r\n num_p = plates.length\r\n if n \u003c num_p\r\n num_p = num_p - n\r\n b.apportion 10, 10\r\n b = Collection.where(object_type_id: ObjectType.find_by_name(\"Agar Plate Batch\").id)\r\n .select { |b| !b.empty? \u0026\u0026 !b.deleted? \u0026\u0026 (b.matrix[0].include? Sample.find_by_name(k).id) }.first\r\n n = b.num_samples\r\n batch_num.push(b.id)\r\n end\r\n \r\n m = b.matrix\r\n x = 0\r\n \r\n (0..m.length-1).reverse_each do |i|\r\n (0..m[i].length-1).reverse_each do |j|\r\n if m[i][j] != -1 \u0026\u0026 x \u003c num_p\r\n m[i][j] = -1\r\n x += 1\r\n end\r\n end\r\n end\r\n \r\n # Grab and label plates\r\n grab_plates plates, batch_num, ids, k\r\n \r\n # Spin down tubes and resuspend\r\n spin_tubes\r\n \r\n # Plate transformed E. coli aliquots\r\n plate_transformed_aliquots k, aliquots, plates\r\n end\r\n end\r\n \r\n def main\r\n operations.retrieve.make\r\n markers_new = Hash.new { | h, k | h[k] = {} } \r\n \r\n # group plates + transformed aliquots \r\n markers = group_plates_and_aliquots markers_new\r\n \r\n # tell tech to grab x amount of plates and plate the aliquots\r\n # also detract from plate batches\r\n calculate_and_operate markers\r\n operations.store(io: \"output\", interactive: true)\r\n \r\n get_protocol_feedback\r\n return {}\r\n \r\n end\r\n\r\nend","precondition":"def precondition(op)\n true\nend","cost_model":"# Make PCR Fragment Cost Model\n\ndef cost(op)\n {\n materials: 0.92,\n labor: 2.27 \n } \nend","documentation":"Plates transforms cells and incubates them.\n\nThe transformed E. coli cells are plated on either LB + Amp or LB + Kan and incubated at 37 F.\n\nRan after **Transform Cells** and is a precursor to **Check Plate**.","test":"","timing":{"start":780,"stop":900,"days":"[\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\"]","active":true}}},{"sample_types":[],"object_types":[],"operation_type":{"name":"Pour Gel","category":"Cloning","deployed":false,"on_the_fly":true,"field_types":[{"ftype":"sample","role":"output","name":"Lane","sample_types":[],"object_types":[],"part":true,"array":false,"routing":"G","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"needs \"Standard Libs/Feedback\"\nclass Protocol\n include Feedback\n def main\n num_ops = operations.length\n o = operations.first.output(\"Lane\").object_type\n lanes_per_gel = o.rows * o.columns\n \n gels_needed = ( num_ops / 8.0 ).ceil # since four lanes are reserved for ladder\n \n ladder_lanes = ( num_ops / 4.0 ).ceil # since four lanes are reserved for ladder\n \n volume = 35.0\n percentage = 1.0\n mass = ((percentage / 100) * volume).round 2\n error = ( mass * 0.05 ).round 5 \n \n #insert virtual operations at 0, 6, 12, 18, ...\n (0...ladder_lanes).each do |l|\n insert_operation 6*l, VirtualOperation.new\n insert_operation 6*l + 1, VirtualOperation.new\n end\n \n operations.make\n \n # Add the top and bottom combs\n top_bottom_combs\n \n # Given the number of gels needed, mass, and margin of error, pour gels\n pour_gels gels_needed, mass, error\n \n # Add GelGreen\n add_gel_green \n \n # Pour and label the gels\n pour_label_gels\n \n operations.store(io: \"output\") \n #get_protocol_feedback\n return {}\n \n end\n \n # Instructs the technician to set up the gel box and add top and bottom combs.\n def top_bottom_combs\n show do\n title \"Set up gel box, and add top and bottom combs\"\n check \"Set up a 49 mL Gel Box With Casting Tray (clean)\"\n check \"Retrieve two 6-well purple combs from A7.325\"\n check \"Position the gel box with the electrodes facing away from you. Add a purple comb to the side and center of the casting tray nearest the side of the gel box.\"\n check \"Put the thick side of the comb down.\"\n note \"Make sure the comb is well-situated in the groove of the casting tray.\"\n # image \"gel_comb_placement\"\n end \n end\n \n # Tells the technician to mix agarose powder and 1X TAE in a graduated cylinder.\n def pour_gels gels_needed, mass, error\n show do\n title \"Pour #{gels_needed} gel(s)\"\n check \"Grab a flask from on top of the microwave M2.\"\n check \"Using a digital scale, measure out #{mass} g (+/- #{error} g) of agarose powder and add it to the flask.\"\n check \"Get a graduated cylinder from on top of the microwave. Measure and add 50 mL of 1X TAE from jug J2 to the flask.\"\n check \"Microwave 70 seconds on high in microwave M2, then swirl. The agarose should now be in solution.\"\n note \"If it is not in solution, microwave 7 seconds on high, then swirl. Repeat until dissolved.\"\n warning \"Work in the gel room, wear gloves and eye protection all the time\"\n end\n end\n \n # Tells the technician to add GelGreen to each gel.\n def add_gel_green\n show do\n title \"For each gel, Add 5 L GelGreen\"\n note \"Using a 10 L pipetter, take up 5 L of GelGreen into the pipet tip. Expel the GelGreen directly into the molten agar (under the surface), then swirl to mix.\"\n warning \"GelGreen is supposedly safe, but stains DNA and can transit cell membranes (limit your exposure).\"\n warning \"GelGreen is photolabile. Limit its exposure to light by putting it back in the box.\"\n # image \"gel_add_gelgreen\"\n end\n end\n \n # Tells the technician to pour and label each gel.\n def pour_label_gels\n show do\n title \"Pour and label the gel(s)\"\n note \"Using a gel pouring autoclave glove, pour agarose from one flask into the casting tray. \n Pour slowly and in a corner for best results. Pop any bubbles with a 10 L pipet tip. Repeat for each gel\"\n operations.output_collections[\"Lane\"].each_with_index do | gel, i |\n check \"Write id #{gel.id} on piece of lab tape and affix it to the side of the gel box.\"\n end\n note \"Leave the gel to solidify.\"\n # image \"gel_pouring\"\n end\n end\n\nend\n","precondition":"def precondition(op)\n if op.plan\n pcrs = op.plan.operations.select { |o|\n o.operation_type.name == \"Make PCR Fragment\"\n }\n pcrs.length == 0 || pcrs[0].status == 'done'\n else\n true\n end\nend","cost_model":"# Pour Gel Cost Model\n# On the fly protocol, and only evaluated when the gel is cut so no cost is accrued\n\ndef cost(op)\n { materials: 0.86, labor: 0.84 }\nend","documentation":"Pours a a mixture composing of a gel and GelGreen into a casting tray.\n\nIn this protocol, a gel is poured into a flask and is then GelGreen\nis added to it. Finally, the gels get poured into a casting tray and then gets labeled on the side of\nthe gel box.\n\nIs a precursor to **Run Gel**. ","test":"","timing":{"start":480,"stop":495,"days":"[\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\"]","active":true}}},{"sample_types":[{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":1,"parent_id":1,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":2,"parent_id":1,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":3,"parent_id":1,"name":"Template","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":1,"field_type_id":3,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":2,"field_type_id":3,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":3,"field_type_id":3,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":4,"field_type_id":3,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":5,"field_type_id":3,"sample_type_id":6,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Plasmid","E coli strain","Fragment","Yeast Strain","DNA Library"],"object_types":[null,null,null,null,null]},{"id":4,"parent_id":1,"name":"Forward Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":6,"field_type_id":4,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":7,"field_type_id":4,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":5,"parent_id":1,"name":"Reverse Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":8,"field_type_id":5,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":9,"field_type_id":5,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":6,"parent_id":1,"name":"Restriction Enzyme(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":7,"parent_id":1,"name":"Yeast Marker","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":8,"parent_id":1,"name":"Fragment Mix Array","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":10,"field_type_id":8,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":11,"field_type_id":8,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]}]},{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":9,"parent_id":2,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":10,"parent_id":2,"name":"Sequence Verification","ftype":"url","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":11,"parent_id":2,"name":"Bacterial Marker","ftype":"string","choices":"Amp,Kan,Amp + Kan,Spec,Kan + Spec,Chlor,Tet,NA,Other","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":12,"parent_id":2,"name":"Yeast Marker","ftype":"string","choices":"HIS,TRP,URA,LEU,NatMX,KanMX,HygMX,BleoMX,5FOA,NA,Other","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":12,"field_type_id":12,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":13,"parent_id":2,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":14,"parent_id":2,"name":"Sequencing Primers","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":13,"field_type_id":14,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":15,"parent_id":2,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":14,"field_type_id":15,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":16,"parent_id":2,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":15,"field_type_id":16,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":17,"parent_id":2,"name":"QC_length","ftype":"number","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":18,"parent_id":2,"name":"Transformation Temperature","ftype":"number","choices":"37,30","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":19,"parent_id":3,"name":"Overhang Sequence","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":20,"parent_id":3,"name":"Anneal Sequence","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":21,"parent_id":3,"name":"T Anneal","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":22,"parent_id":4,"name":"Parent","ftype":"sample","choices":null,"array":null,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":16,"field_type_id":22,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["E coli strain"],"object_types":[null]}]},{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":23,"parent_id":5,"name":"Parent","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":17,"field_type_id":23,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]},{"id":24,"parent_id":5,"name":"Integrant","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":18,"field_type_id":24,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":19,"field_type_id":24,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid","Fragment"],"object_types":[null,null]},{"id":25,"parent_id":5,"name":"Plasmid","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":20,"field_type_id":25,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid"],"object_types":[null]},{"id":26,"parent_id":5,"name":"Integrated Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":27,"parent_id":5,"name":"Plasmid Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":28,"parent_id":5,"name":"Mating Type","ftype":"string","choices":"MATa,MATalpha,Diploid","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":29,"parent_id":5,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":21,"field_type_id":29,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":30,"parent_id":5,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":22,"field_type_id":30,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":31,"parent_id":5,"name":"QC_length","ftype":"number","choices":"","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":32,"parent_id":5,"name":"Comp_cell_limit","ftype":"string","choices":"Yes,No","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":33,"parent_id":5,"name":"Media","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":34,"parent_id":5,"name":"Has this strain passed QC?","ftype":"string","choices":"No,Yes","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":35,"parent_id":5,"name":"Haploids","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":23,"field_type_id":35,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]}]},{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":36,"parent_id":6,"name":"Oligo Pool","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":24,"field_type_id":36,"sample_type_id":7,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Oligo Pool"],"object_types":[null]}]},{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":37,"parent_id":7,"name":"Manufacturer","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":38,"parent_id":7,"name":"Oligo Library ID","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":39,"parent_id":7,"name":"inner forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":25,"field_type_id":39,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":40,"parent_id":7,"name":"inner reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":26,"field_type_id":40,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":41,"parent_id":7,"name":"sublibrary forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":27,"field_type_id":41,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":42,"parent_id":7,"name":"sublibrary reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":28,"field_type_id":42,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":43,"parent_id":7,"name":"min length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":44,"parent_id":7,"name":"max length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":45,"parent_id":7,"name":"variants (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":46,"parent_id":7,"name":"sublibrary name (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":47,"parent_id":7,"name":"forward priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":48,"parent_id":7,"name":"reverse priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]}],"object_types":[{"id":8,"name":"Gel Slice","description":"Gel Slice cut from a gel lane after gel was run. Often placed in a 1.5 mL tube.","min":0,"max":1000,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Fragment","cost":10.0,"release_method":"dispose","release_description":"","sample_type_id":1,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Fragment"},{"id":3,"name":"Fragment Stock","description":"Fragment stock in 1.5 mL tube, usually stored in M20 fridge.","min":0,"max":1000,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Fragment","cost":50.0,"release_method":"return","release_description":"","sample_type_id":1,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Fragment"},{"id":10,"name":"Plasmid Stock","description":"A 1.5 mL tube containing purified plasmid DNA","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"concentration:","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":2.0,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"}],"operation_type":{"name":"Purify Gel Slice","category":"Cloning","deployed":false,"on_the_fly":false,"field_types":[{"ftype":"sample","role":"input","name":"Gel","sample_types":["Fragment","Plasmid"],"object_types":["Gel Slice","Gel Slice"],"part":false,"array":false,"routing":"F","preferred_operation_type_id":16,"preferred_field_type_id":88,"choices":null},{"ftype":"sample","role":"output","name":"Fragment","sample_types":["Fragment","Plasmid"],"object_types":["Fragment Stock","Plasmid Stock"],"part":false,"array":false,"routing":"F","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"# Purify Gel Protocol\n\n# This protocol purfies gel slices into DNA fragment stocks.\nneeds \"Standard Libs/Feedback\"\nclass Protocol\n include Feedback\n # TODO refactor density parameter name? (see qg_volumes and iso_volumes definitions)\n DENSITY1 = 1.0 / 3000.0\n DENSITY2 = 1.0 / 1000.0\n \n def main\n \n if debug\n operations.shuffle! \n end\n \n keep_gel_slices = operations.first.plan.get(:choice) == \"Yes\"\n \n operations.retrieve interactive: (!keep_gel_slices)\n operations.sort! { |op1, op2| op1.input(\"Gel\").item.id \u003c=\u003e op2.input(\"Gel\").item.id }\n operations.make\n \n # While testing, assign a random weight value\n operations.each{ |op| op.set_input_data(\"Gel\", :weight, Random.rand / 2 + 0.1) } if debug\n\n operations.each do |op|\n op.temporary[:qg_volume] = (op.input_data(\"Gel\", :weight).to_f / DENSITY1).floor\n op.temporary[:iso_volume] = (op.input_data(\"Gel\", :weight).to_f / DENSITY2).floor\n op.temporary[:iso_volume] = 0 if op.input(\"Gel\").sample.properties[\"Length\"].between?(500, 4000)\n op.temporary[:total_volume] = op.temporary[:qg_volume] + op.temporary[:iso_volume]\n op.temporary[:is_divided] = op.temporary[:total_volume] \u003e= 2000\n end\n \n move_gel_slices_to_tubes\n \n add_QG_buffer\n \n # Place tubes in a 50 degree heat block\n heat_block\n \n # Distribute melted gel slices between tubes\n distribute_gels\n \n # Add isopropanol\n add_isopropanol\n \n # Prepare the centrifuge\n prepare_centrifuge\n \n # Use the centrifuge to bind DNA to the columns\n centrifuge\n \n # Label the new 1.5 mL tubes\n use_label_printer\n \n # Transfer to the 1.5 ml tube\n transfer_to_tube\n \n #Measure the DNA concentration\n measure_DNA\n \n operations.each do |op|\n # need to check the case where its \u003e 10\n #if operations.output_item(\"Fragment\")\n op.set_output_data(\"Fragment\", :concentration, op.temporary[:conc])\n op.output(\"Fragment\").item.notes = op.temporary[:note]\n end\n \n # table operations.start_table\n # .output_item(\"Fragment\")\n # .get(:conc, type: 'number', heading: \"Concentration (ng/uL)\", default: 7)\n # .get(:note, type: 'text', heading: \"Notes\")\n # .end_table\n\n # Decide whether or not to keep the dilute stocks\n choices = get_choices\n\n discard_fragment_stocks choices\n \n # Let the tech select what concentrations were too low to continue, and mark the gels as deleted.\n select_as_deleted choices\n \n operations.store\n \n get_protocol_feedback\n return {}\n \n end\n \n # This method lets the technician decide whether or not to discard\n # any of the fragment stocks and returns their choices.\n def get_choices\n choices = show do\n title \"Decide whether to keep dilute stocks\"\n note \"The below stocks have a concentration of less than 10 ng/uL.\"\n note \"Talk to a lab manager to decide whether or not to discard the following stocks.\"\n operations.select{ |op| op.output_data(\"Fragment\", :concentration) \u003c 10}.each do |op|\n select [\"Yes\", \"No\"], var: \"d#{op.output(\"Fragment\").item.id}\", label: \"Discard Fragment Stock #{op.output(\"Fragment\").item.id}\", default: 1\n end\n end if operations.any?{ |op| op.output_data(\"Fragment\", :concentration) \u003c 10}\n choices #return\n end\n\n # This method tells the technician to move the gel slices to new tubes.\n def move_gel_slices_to_tubes\n show do\n title \"Move gel slices to new tubes\"\n note \"Please carefully transfer the gel slices in the following tubes each to a new 2.0 mL tube using a pipette tip:\"\n table operations.select{|op| op.temporary[:total_volume].between?(1500, 2000)}.start_table\n .input_item(\"Gel\")\n .end_table\n note \"Label the new tubes accordingly, and discard the old 1.5 mL tubes.\"\n end if operations.any? {|op| op.temporary[:total_volume].between?(1500, 2000)}\n end\n \n # This method displays a table of gels and tells the technician to add QG buffer\n # to the corresponding tubes.\n def add_QG_buffer\n show do\n title \"Add the following volumes of QG buffer to the corresponding tube.\"\n table operations.start_table\n .input_item(\"Gel\")\n .custom_column(heading: \"QG Volume in uL\", checkable: true) { |op| op.temporary[:qg_volume]}\n .end_table\n end\n end\n \n # This method tells the technician to place all tubes in a heat block.\n def heat_block\n show do\n title \"Place all tubes in 50 degree heat block\"\n timer initial: { hours: 0, minutes: 10, seconds: 0}\n note \"Vortex every few minutes to speed up the process.\"\n note \"Retrieve after 10 minutes or until the gel slice is competely dissovled.\"\n end\n end\n \n # This method tells the technician to distribute melted gel slices equally\n # between tubes. They then need to label the new tubes and discard the old tubes.\n def distribute_gels\n show do\n title \"Equally distribute melted gel slices between tubes\"\n note \"Please equally distribute the volume of the following tubes each between two 1.5 mL tubes:\"\n table operations.select{ |op| op.temporary[:is_divided]}.start_table\n .input_item(\"Gel\")\n .end_table\n note \"Label the new tubes accordingly, and discard the old 1.5 mL tubes.\"\n end if operations.any? { |op| op.temporary[:is_divided] }\n end\n \n # This method tells the technician to add isopropanol evenly between two tubes.\n def add_isopropanol\n show do\n title \"Add isopropanol\"\n note \"Add isopropanol according to the following table. Pipette up and down to mix.\"\n warning \"Divide the isopropanol volume evenly between two 1.5 mL tubes #{operations.select{ |op| op.temporary[:is_divided]}.map{ |op| op.input(\"Gel\").item.id}} since you divided one tube's volume into two earlier.\" if operations.any?{ |op| op.temporary[:is_divided]}\n table operations.select{ |op| op.temporary[:iso_volume] \u003e 0 }.start_table\n .input_item(\"Gel\")\n .custom_column(heading: \"Isopropanol (uL)\", checkable: true) { |op| op.temporary[:iso_volume]}\n .end_table\n end if operations.any? { |op| op.temporary[:iso_volume] \u003e 0}\n end\n \n # This method tells the technician to prepare the centrifuge.\n def prepare_centrifuge\n show do\n title \"Prepare the centrifuge\"\n check \"Grab #{operations.length} pink Qiagen columns, label with 1 to #{operations.length} on the top.\"\n check \"Add tube contents to LABELED pink Qiagen columns using the following table.\"\n check \"Be sure not to add more than 750 uL to each pink column.\"\n warning \"Vortex QG mixture thoroughly before adding to pink column!\".upcase\n table operations.start_table\n .input_item(\"Gel\")\n .custom_column(heading: \"Qiagen column\") { |op| operations.index(op) + 1}\n .end_table\n end\n end\n \n # This method gives instructions on how to operate the centrifuge.\n def centrifuge\n show do\n title \"Centrifuge\"\n check \"Spin at 17.0 xg for 1 minute to bind DNA to columns\"\n check \"Empty collection columns by pouring liquid waste into liquid waste container.\"\n warning \"Add the remaining QG mixtures to their corresponding columns, and repeat these first two steps for all tubes with remaining mixture!\"\n check \"Add 750 uL PE buffer to columns and wait five minutes\"\n check \"Spin at 17.0 xg for 30 seconds to wash columns.\"\n check \"Empty collection tubes.\"\n check \"Add 500 uL PE buffer to columns and wait five minutes\"\n check \"Spin at 17.0 xg for 30 seconds to wash columns\"\n check \"Empty collection tubes.\"\n check \"Spin at 17.0 xg for 1 minute to remove all PE buffer from columns\"\n end\n \n end \n \n # This method tells the technician how to use the label printer.\n def use_label_printer\n show do\n title \"Use label printer to label new 1.5 mL tubes\"\n check \"Ensure that the B33-143-492 labels are loaded in the printer. This number should be displayed on the printer. If not, check with a lab manager.\"\n check \"Open the LabelMark 6 software.\"\n check \"Select \\\"Open\\\" --\u003e \\\"File\\\" --\u003e \\\"Serialized data top labels\\\"\"\n note \"If an error about the printer appears, press \\\"Okay\\\"\"\n check \"Select the first label graphic, and click on the number in the middle of the label graphic.\"\n check \"On the toolbar on the left, select \\\"Edit serialized data\\\"\"\n check \"Enter #{operations.first.output(\"Fragment\").item.id} for the Start number and #{operations.length} for the Total number, and select \\\"Finish\\\"\"\n check \"Select \\\"File\\\" --\u003e \\\"Print\\\" and select \\\"BBP33\\\" as the printer option.\"\n check \"Press \\\"Print\\\" and collect the labels.\"\n image \"purify_gel_edit_serialized_data\"\n image \"purify_gel_sequential\"\n end \n end\n \n # This method tells the technician to transfer pink columns to labeled tubes.\n def transfer_to_tube\n show do\n title \"Transfer to 1.5 mL tube\"\n check \"Grab #{operations.length} 1.5 mL tube(s).\"\n check \"Apply the labels to the tubes.\"\n check \"Transfer pink columns to the labeled tubes using the following table.\"\n table operations.start_table\n .custom_column(heading: \"Qiagen column\") { |op| operations.index(op) + 1 }\n .output_item(\"Fragment\", heading: \"1.5 mL tube\", checkable: true)\n .end_table\n check \"Add 30 uL molecular grade water or EB elution buffer to center of the column.\"\n warning \"Be very careful to not pipette on the wall of the tube.\"\n end\n end\n \n # This method tells the technician to measure the DNA concentration.\n def measure_DNA\n show do\n title \"Measure DNA Concentration\"\n check \"Elute DNA into 1.5 mL tubes by spinning at 17.0 xg for one minute, keep the columns.\"\n check \"Pipette the flow through (30 uL) onto the center of the column, spin again at 17.0 xg for one minute. Discard the columns this time.\"\n # check \"Go to B9 and nanodrop all of 1.5 mL tubes, enter DNA concentrations for all tubes in the following:\"\n table operations.start_table\n .output_item(\"Fragment\")\n .get(:conc, type: 'number', heading: \"Concentration (ng/uL)\", default: 7)\n .get(:note, type: 'text', heading: \"Notes\")\n .end_table\n end\n end\n \n # This method takes in a group of fragment stocks and tells the technician to discard\n # any of the fragment stocks that the technician earlier said that needed to be removed.\n def discard_fragment_stocks choices\n if !choices.nil? \u0026\u0026 choices.any? { |key, val| val == \"Yes\"}\n show do\n title \"Discard fragment stocks\"\n note \"Discard the following fragment stocks:\"\n note operations.select{ |op| choices[\"d#{op.output(\"Fragment\").item.id}\".to_sym] == \"Yes\"}\n .map{ |op| op.output(\"Fragment\").item.id}\n .join(\", \")\n end\n end\n end\n \n # This method takes in a group of fragment stocks and errors the operations\n # that include fragment stocks that have too low of concentrations.\n def select_as_deleted choices\n if !choices.nil?\n operations.select { |op| choices[\"d#{op.output(\"Fragment\").item.id}\".to_sym] == \"Yes\" }.each do |op|\n frag = op.output(\"Fragment\").item\n op.error :low_concentration, \"The concentration of #{frag} was too low to continue\"\n frag.mark_as_deleted\n end\n end\n \n operations.each do |op|\n op.input(\"Gel\").item.mark_as_deleted\n end\n end\nend\n\n","precondition":"def precondition(op)\n true\nend","cost_model":"# Purify Gel Slice Cost Model\n\ndef cost(op)\n {\n materials: 1.86,\n labor: 7.43\n } \nend","documentation":"Purifies an input gel slice that has been extracted.\n\nDissolves the extracted gel slice in a QG Buffer and purifies the fragment on a spin column. It then tells\nthe technician to determine the concentration using a Nanodrop and to record it.\n\nRan after *Extract Fragment* and before *Make PCR Fragment*","test":"","timing":{"start":630,"stop":720,"days":"[\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\"]","active":true}}},{"sample_types":[{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":1,"parent_id":1,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":2,"parent_id":1,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":3,"parent_id":1,"name":"Template","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":1,"field_type_id":3,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":2,"field_type_id":3,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":3,"field_type_id":3,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":4,"field_type_id":3,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":5,"field_type_id":3,"sample_type_id":6,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Plasmid","E coli strain","Fragment","Yeast Strain","DNA Library"],"object_types":[null,null,null,null,null]},{"id":4,"parent_id":1,"name":"Forward Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":6,"field_type_id":4,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":7,"field_type_id":4,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":5,"parent_id":1,"name":"Reverse Primer","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":8,"field_type_id":5,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":9,"field_type_id":5,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]},{"id":6,"parent_id":1,"name":"Restriction Enzyme(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":7,"parent_id":1,"name":"Yeast Marker","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":8,"parent_id":1,"name":"Fragment Mix Array","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":10,"field_type_id":8,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}},{"id":11,"field_type_id":8,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Primer","Fragment"],"object_types":[null,null]}]},{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":9,"parent_id":2,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":10,"parent_id":2,"name":"Sequence Verification","ftype":"url","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":11,"parent_id":2,"name":"Bacterial Marker","ftype":"string","choices":"Amp,Kan,Amp + Kan,Spec,Kan + Spec,Chlor,Tet,NA,Other","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":12,"parent_id":2,"name":"Yeast Marker","ftype":"string","choices":"HIS,TRP,URA,LEU,NatMX,KanMX,HygMX,BleoMX,5FOA,NA,Other","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":12,"field_type_id":12,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":13,"parent_id":2,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":14,"parent_id":2,"name":"Sequencing Primers","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":13,"field_type_id":14,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":15,"parent_id":2,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":14,"field_type_id":15,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":16,"parent_id":2,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":15,"field_type_id":16,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":17,"parent_id":2,"name":"QC_length","ftype":"number","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":18,"parent_id":2,"name":"Transformation Temperature","ftype":"number","choices":"37,30","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":19,"parent_id":3,"name":"Overhang Sequence","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":20,"parent_id":3,"name":"Anneal Sequence","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":21,"parent_id":3,"name":"T Anneal","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":22,"parent_id":4,"name":"Parent","ftype":"sample","choices":null,"array":null,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":16,"field_type_id":22,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["E coli strain"],"object_types":[null]}]},{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":23,"parent_id":5,"name":"Parent","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":17,"field_type_id":23,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]},{"id":24,"parent_id":5,"name":"Integrant","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":18,"field_type_id":24,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}},{"id":19,"field_type_id":24,"sample_type_id":1,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":1,"name":"Fragment","description":"A linear double stranded piece of DNA from PCR or Restriction Digest","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid","Fragment"],"object_types":[null,null]},{"id":25,"parent_id":5,"name":"Plasmid","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":20,"field_type_id":25,"sample_type_id":2,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00"}}],"sample_types":["Plasmid"],"object_types":[null]},{"id":26,"parent_id":5,"name":"Integrated Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":27,"parent_id":5,"name":"Plasmid Marker(s)","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":28,"parent_id":5,"name":"Mating Type","ftype":"string","choices":"MATa,MATalpha,Diploid","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":29,"parent_id":5,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":21,"field_type_id":29,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":30,"parent_id":5,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":22,"field_type_id":30,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":31,"parent_id":5,"name":"QC_length","ftype":"number","choices":"","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":32,"parent_id":5,"name":"Comp_cell_limit","ftype":"string","choices":"Yes,No","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":33,"parent_id":5,"name":"Media","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":34,"parent_id":5,"name":"Has this strain passed QC?","ftype":"string","choices":"No,Yes","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":35,"parent_id":5,"name":"Haploids","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":23,"field_type_id":35,"sample_type_id":5,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":5,"name":"Yeast Strain","description":"A strain of yeast distinguished from others by genomic or plasmid modifications","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Yeast Strain"],"object_types":[null]}]},{"id":6,"name":"DNA Library","description":"A sample that contains a pool of DNA molecules with many unique sequences","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":36,"parent_id":6,"name":"Oligo Pool","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":24,"field_type_id":36,"sample_type_id":7,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Oligo Pool"],"object_types":[null]}]},{"id":7,"name":"Oligo Pool","description":"Pool or library of ssDNA oligos. May contain one or more sublibraries. In array fields, the n-th position corresponds to n-th sublibrary. \"forward priming site\" and \"reverse priming site\" are read as primer sequences.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":37,"parent_id":7,"name":"Manufacturer","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":38,"parent_id":7,"name":"Oligo Library ID","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":39,"parent_id":7,"name":"inner forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":25,"field_type_id":39,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":40,"parent_id":7,"name":"inner reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":26,"field_type_id":40,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":41,"parent_id":7,"name":"sublibrary forward primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":27,"field_type_id":41,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":42,"parent_id":7,"name":"sublibrary reverse primer (array)","ftype":"sample","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":28,"field_type_id":42,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":43,"parent_id":7,"name":"min length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":44,"parent_id":7,"name":"max length (nt) (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":45,"parent_id":7,"name":"variants (array)","ftype":"number","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":46,"parent_id":7,"name":"sublibrary name (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":47,"parent_id":7,"name":"forward priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":48,"parent_id":7,"name":"reverse priming site (array)","ftype":"string","choices":null,"array":true,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]}],"object_types":[{"id":18,"name":"Stripwell","description":"Stripwell","min":0,"max":10000,"handler":"collection","safety":"No safety information","cleanup":"No cleanup information","data":" {\r\n \"materials\": 10.48,\r\n \"labor\": 10\r\n }","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"stripwell","cost":1.0,"release_method":"query","release_description":"","sample_type_id":null,"image":null,"prefix":"","rows":1,"columns":12,"sample_type_name":null},{"id":20,"name":"Stripwell of Digested Plasmid","description":"A stripwell from Restriction Digest used for gel protocols, fragment analyzing, etc.","min":0,"max":1000,"handler":"collection","safety":"No safety information","cleanup":"No cleanup information","data":"{ \"materials\": 10.48, \"labor\": 10 }","vendor":"No vendor information","created_at":"2019-03-14T14:16:58.000-07:00","updated_at":"2019-03-14T14:16:58.000-07:00","unit":"stripwell","cost":1.0,"release_method":"return","release_description":"","sample_type_id":null,"image":null,"prefix":"Bench","rows":1,"columns":12,"sample_type_name":null},{"id":7,"name":"50 mL 0.8 Percent Agarose Gel in Gel Box","description":"Used to run gels;","min":0,"max":100,"handler":"collection","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"box","cost":0.01,"release_method":"return","release_description":"Return this item","sample_type_id":null,"image":null,"prefix":"","rows":1,"columns":12,"sample_type_name":null}],"operation_type":{"name":"Run Gel","category":"Cloning","deployed":false,"on_the_fly":false,"field_types":[{"ftype":"sample","role":"input","name":"Fragment","sample_types":["Fragment","Plasmid"],"object_types":["Stripwell","Stripwell of Digested Plasmid"],"part":true,"array":false,"routing":"F","preferred_operation_type_id":23,"preferred_field_type_id":107,"choices":null},{"ftype":"sample","role":"input","name":"Gel","sample_types":[],"object_types":[],"part":true,"array":false,"routing":"L","preferred_operation_type_id":17,"preferred_field_type_id":89,"choices":null},{"ftype":"sample","role":"output","name":"Fragment","sample_types":["Fragment","Plasmid"],"object_types":["50 mL 0.8 Percent Agarose Gel in Gel Box","50 mL 0.8 Percent Agarose Gel in Gel Box"],"part":true,"array":false,"routing":"F","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"#TO DO: 100 BP LADDER ONLY WHEN A FRAGMENT LESS THAN 500 BP ONLY \r\nneeds \"Standard Libs/Feedback\"\r\nneeds \"Standard Libs/Units\"\r\n\r\nclass Protocol\r\n include Feedback\r\n def main\r\n \r\n operations.retrieve interactive: false\r\n \r\n # manually set input and outputs so that they ascend in parrellel for id, row, column\r\n # also returns sorted operationslist\r\n sorted_ops = align_input_and_output_indicies operations\r\n operations = sorted_ops\r\n \r\n gels = operations.map { |op| op.input(\"Gel\").collection }.uniq\r\n stripwells = operations.map { |op| op.input(\"Fragment\").collection }.uniq.sort { |sw1, sw2| sw1.id \u003c=\u003e sw2.id }\r\n \r\n # Find a ladder\r\n ladder_100 = Sample.find_by_name(\"100 bp Ladder\")\r\n ladder_1k = Sample.find_by_name(\"1 kb Ladder\")\r\n dye = Sample.find_by_name(\"6X Loading Dye\")\r\n items = [ladder_100.in(\"Ladder Aliquot\").first,\r\n ladder_1k.in(\"Ladder Aliquot\").first,\r\n Item.where(sample_id: dye.id).select { |i| !i.deleted? }.first]\r\n \r\n take items + gels.collect { |i| Item.find_by_id(i.id) } + stripwells.collect { |i| Item.find_by_id(i.id) }, interactive: true\r\n \r\n setup_power_supply\r\n \r\n setup_gel_box\r\n \r\n add_dye stripwells\r\n \r\n #ONLY DO 100 BP IF THERE IS FRAGMENT W LENGTH \u003c 500 BP\r\n add_ladders_to_gel gels, ladder_1k, ladder_100\r\n\r\n # TO DO: Fix loading if ladders exist\r\n transfer_result_to_lane\r\n \r\n start_electrophoresis\r\n\r\n discard_stripwells\r\n \r\n release items, interactive: true\r\n \r\n set_timer\r\n get_protocol_feedback\r\n return {}\r\n \r\n end\r\n \r\n # Change the input and output field values so that their item ids, row, and column\r\n # are all strictly ascending (in that sort order). The mapping from input-\u003eoutput\r\n # is manually made to enforce this parrellel\r\n def align_input_and_output_indicies ops\r\n # Sort operations by gels and columns (these can get out of order from PCR)\r\n ops.sort! do |op1, op2| \r\n fv1 = op1.input(\"Fragment\")\r\n fv2 = op2.input(\"Fragment\")\r\n [fv1.item.id, fv1.column] \u003c=\u003e [fv2.item.id, fv2.column]\r\n end\r\n \r\n gels = ops.map { |op| op.input(\"Gel\").collection }.uniq.sort { |g1, g2| g1.id \u003c=\u003e g2.id }\r\n gel_size = gels.first.object_type.rows * gels.first.object_type.columns\r\n gel_columns = gels.first.object_type.columns\r\n \r\n # spots already taken up by the ladder in gel:\r\n ###############\r\n # 1 1 0 0 0 0 #\r\n # 1 1 0 0 0 0 #\r\n ###############\r\n size_adjusted_for_lader = gel_size - 4\r\n columns_adjusted_for_ladder = gel_columns - 2\r\n column_start_adjusted_for_ladder = 2\r\n \r\n # associate operations with new gel, row \u0026 column\r\n ops.each_with_index do |op, idx|\r\n gel_idx = idx / size_adjusted_for_lader\r\n lane = idx % size_adjusted_for_lader\r\n row = lane / columns_adjusted_for_ladder\r\n column = (lane % columns_adjusted_for_ladder) + column_start_adjusted_for_ladder\r\n \r\n gel_fv = op.input(\"Gel\")\r\n gel_fv.set collection: gels[gel_idx]\r\n gel_fv.row = row\r\n gel_fv.column = column\r\n gel_fv.save\r\n # show { note \"op #{idx}: col: #{op.input(\"Gel\").collection.id}, row: #{op.input(\"Gel\").row}, column: #{op.input(\"Gel\").column}\" }\r\n end\r\n\r\n # Don't use generic operations.make\r\n ops.each do |op|\r\n op.output(\"Fragment\").make_part(\r\n op.input(\"Gel\").collection,\r\n op.input(\"Gel\").row,\r\n op.input(\"Gel\").column\r\n )\r\n end\r\n ops\r\n end\r\n \r\n # This method tells the technician to set up the power supply.\r\n def setup_power_supply\r\n show do\r\n title \"Set up the power supply\"\r\n \r\n note \"In the gel room, obtain a power supply and set it to 80 V and with a 40 minute timer.\"\r\n note \"Attach the electrodes of an appropriate gel box lid to the power supply.\"\r\n \r\n image \"Items/gel_power_settings.JPG\" \r\n end\r\n end\r\n \r\n # This method tells the technician to set up the power supply.\r\n def setup_gel_box\r\n show do\r\n title \"Set up the gel box(s).\"\r\n \r\n check \"Remove the casting tray(s) (with gel(s)) and place it(them) on the bench.\"\r\n check \"Using the graduated cylinder, fill the gel box(s) with 200 mL of 1X TAE. TAE should just cover the center of the gel box(s).\"\r\n check \"With the gel box(s) electrodes facing away from you, place the casting tray(s) (with gel(s)) back in the gel box(s). The top lane(s) should be on your left, as the DNA will move to the right.\"\r\n check \"Using the graduated cylinder, add 50 mL of 1X TAE so that the surface of the gel is covered.\"\r\n check \"Remove the comb(s) and place them in the appropriate box(s).\"\r\n check \"Put the graduated cylinder back.\"\r\n \r\n image \"Items/gel_fill_TAE_to_line.JPG\"\r\n end \r\n end\r\n \r\n # This method tells the technician to transfer PCR results into their indicated gel lanes.\r\n def transfer_result_to_lane\r\n show do \r\n title \"Transfer 50 uL of each PCR result into indicated gel lane\"\r\n note \"Transfer samples from each stripwell to the gel(s) according to the following table:\"\r\n table operations.reject { |op| op.virtual? }.sort { |op1, op2| op1.input(\"Fragment\").item.id \u003c=\u003e op2.input(\"Fragment\").item.id }.extend(OperationList).start_table\r\n .input_collection(\"Fragment\", heading: \"Stripwell\")\r\n .custom_column(heading: \"Well Number\") { |op| (op.input(\"Fragment\").column + 1) }\r\n .input_collection(\"Gel\", heading: \"Gel\")\r\n .custom_column(heading: \"Gel Row\") { |op| (op.input(\"Gel\").row + 1) }\r\n .custom_column(heading: \"Gel Column\", checkable: true) { |op| (op.input(\"Gel\").column + 1) }\r\n .end_table\r\n end\r\n end\r\n \r\n # This method tells the technician to start electrophoresis\r\n def start_electrophoresis\r\n show do\r\n title \"Start Electrophoresis\"\r\n note \"Carefully attach the gel box lid(s) to the gel box(es). Attach the red electrode to the red terminal of the power supply, and the black electrode to the neighboring black terminal. Hit the start button on the gel boxes.\"\r\n note \"Make sure the power supply is not erroring (no E* messages) and that there are bubbles emerging from the platinum wires in the bottom corners of the gel box.\"\r\n image \"Items/gel_check_for_bubbles.JPG\"\r\n end\r\n end\r\n \r\n # Tells the technician to discard stripwells\r\n def discard_stripwells\r\n show do \r\n title \"Discard Stripwells\"\r\n note \"Discard all the empty stripwells\"\r\n operations.each do |op|\r\n #if op.input(\"Fragment\").item != nil\r\n op.input(\"Fragment\").item.mark_as_deleted\r\n #else\r\n # show do\r\n # note \"Item you are trying to delete is nil. Cannot discard.\" #{op.input(\"Fragment\").item.id}\r\n # end\r\n #end\r\n end\r\n end\r\n end\r\n \r\n # Tells the technician to set a timer.\r\n def set_timer\r\n show do\r\n title \"Set a timer\"\r\n \r\n check \"When you get back to your bench, set a 40 minute timer.\" \r\n check \"When the 40 minute timer is up, grab a lab manager to check on the gel. The lab manager may have you set another timer after checking the gel.\"\r\n end\r\n end\r\n \r\n # Tells the technician to add dye to each well.\r\n def add_dye stripwells\r\n show do \r\n title \"Add Dye to Each Well\"\r\n stripwells.each do |s|\r\n note \"Add 10 uL dye to stripwell #{s.id} from wells #{s.non_empty_string}\"\r\n end\r\n end\r\n end\r\n \r\n # This method tells the technician to add ladders to gells.\r\n def add_ladders_to_gel gels, ladder_1k, ladder_100\r\n gels.each do |gel|\r\n gel.set 0,0,ladder_1k.id\r\n gel.set 0,1, ladder_100.id\r\n gel.set 1,0, ladder_1k.id\r\n gel.set 1,1, ladder_100.id\r\n show do\r\n title \"Add Ladders to Gel\"\r\n note \"Pipette 10 uL of the 1 kb ladder to positions (1,1) and (2,1) of gel #{gel.id}\"\r\n note \"Pipette 10 uL of the 100bp ladder to positions (1,2) and (2,2) of gel #{gel.id}\"\r\n end\r\n end\r\n end\r\nend","precondition":"def precondition(op)\n true\nend","cost_model":"# Run Gel Cost Model\n\ndef cost(op)\n {\n materials: 0.27,\n labor: 2.03\n } \nend","documentation":"Runs a selected gel through gel electrophoresis.\n\nA 50 mL 1 percent Agarose Gel is loaded with the input samples in preparation for gel electrophoresis. \nThe gel is then run at 100 Volts for 40 minutes. This operation type creates \"Pour Gel\" and\n\"Extract Fragment\" operation associations for later use.\n\nRan after *Pour Gel* and is a precursor to *Extract Fragment*.","test":"","timing":{"start":510,"stop":540,"days":"[\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\"]","active":true}}},{"sample_types":[{"id":2,"name":"Plasmid","description":"A circular piece of double stranded DNA","created_at":"2019-03-14T14:16:56.000-07:00","updated_at":"2019-03-14T14:16:56.000-07:00","field_types":[{"id":9,"parent_id":2,"name":"Sequence","ftype":"url","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":10,"parent_id":2,"name":"Sequence Verification","ftype":"url","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":11,"parent_id":2,"name":"Bacterial Marker","ftype":"string","choices":"Amp,Kan,Amp + Kan,Spec,Kan + Spec,Chlor,Tet,NA,Other","array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":12,"parent_id":2,"name":"Yeast Marker","ftype":"string","choices":"HIS,TRP,URA,LEU,NatMX,KanMX,HygMX,BleoMX,5FOA,NA,Other","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":12,"field_type_id":12,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":13,"parent_id":2,"name":"Length","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":14,"parent_id":2,"name":"Sequencing Primers","ftype":"sample","choices":null,"array":true,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":13,"field_type_id":14,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":15,"parent_id":2,"name":"QC Primer1","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":14,"field_type_id":15,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":16,"parent_id":2,"name":"QC Primer2","ftype":"sample","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":15,"field_type_id":16,"sample_type_id":3,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["Primer"],"object_types":[null]},{"id":17,"parent_id":2,"name":"QC_length","ftype":"number","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":18,"parent_id":2,"name":"Transformation Temperature","ftype":"number","choices":"37,30","array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":3,"name":"Primer","description":"A short double stranded piece of DNA for PCR and sequencing","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":19,"parent_id":3,"name":"Overhang Sequence","ftype":"string","choices":null,"array":false,"required":false,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":20,"parent_id":3,"name":"Anneal Sequence","ftype":"string","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]},{"id":21,"parent_id":3,"name":"T Anneal","ftype":"number","choices":null,"array":false,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[],"sample_types":[],"object_types":[]}]},{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","field_types":[{"id":22,"parent_id":4,"name":"Parent","ftype":"sample","choices":null,"array":null,"required":true,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","parent_class":"SampleType","role":null,"part":null,"routing":null,"preferred_operation_type_id":null,"preferred_field_type_id":null,"allowable_field_types":[{"id":16,"field_type_id":22,"sample_type_id":4,"object_type_id":null,"created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","sample_type":{"id":4,"name":"E coli strain","description":"A strain of E coli distinguished from others by genomic (not plasmid) modifications.","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00"}}],"sample_types":["E coli strain"],"object_types":[null]}]}],"object_types":[{"id":4,"name":"Gibson Reaction Result","description":"A plasmid that was made from Gibson reaction and stayed in the Gibson reaction tube. One can use this to do transform and extract the plasmid.","min":0,"max":1000,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":10.0,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":21,"name":"Ligation product","description":"A low concentration, possibly multi-species, product of a ligation reaction. Suitable for transformation or use as a PCR template. ","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:58.000-07:00","updated_at":"2019-03-14T14:16:58.000-07:00","unit":"Plasmid stock","cost":0.01,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":10,"name":"Plasmid Stock","description":"A 1.5 mL tube containing purified plasmid DNA","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"concentration:","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":2.0,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":13,"name":"1 ng/µL Plasmid Stock","description":"Diluted stock for use as a template in PCR","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:57.000-07:00","updated_at":"2019-03-14T14:16:57.000-07:00","unit":"Plasmid","cost":0.01,"release_method":"query","release_description":"If this is an aliquot for the \"Transformation Efficiency Project\", dispose of it. Otherwise, return it.","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":22,"name":"DNA Mix","description":"Mix of DNA fragments (e.g. for E coli gap repair or yeast homologous recombination)","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:58.000-07:00","updated_at":"2019-03-14T14:16:58.000-07:00","unit":"Plasmid","cost":0.01,"release_method":"return","release_description":"","sample_type_id":2,"image":null,"prefix":"M20","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":19,"name":"Transformed E. coli Aliquot","description":"An aliquot containing transformed E. coli - usually in a 1.5 mL tube","min":0,"max":1,"handler":"sample_container","safety":"No safety information","cleanup":"No cleanup information","data":"No data","vendor":"No vendor information","created_at":"2019-03-14T14:16:58.000-07:00","updated_at":"2019-03-14T14:16:58.000-07:00","unit":"Plasmid","cost":0.01,"release_method":"dispose","release_description":"","sample_type_id":2,"image":null,"prefix":"","rows":null,"columns":null,"sample_type_name":"Plasmid"},{"id":23,"name":"E. coli Comp Cell Batch","description":"E. coli Comp Cell Batch","min":0,"max":100,"handler":"collection","safety":"No safety information","cleanup":"No cleanup information","data":"{ \"samples\": [ \r\n {\"name\": \"DH5alpha\", \"materials\": 0.58, \"labor\": 2.39, \"unit\": \"cell\" }\r\n] }","vendor":"No vendor information","created_at":"2019-03-14T14:16:58.000-07:00","updated_at":"2019-03-14T14:16:58.000-07:00","unit":"batch","cost":0.01,"release_method":"return","release_description":"","sample_type_id":null,"image":null,"prefix":"","rows":1,"columns":12,"sample_type_name":null}],"operation_type":{"name":"Transform Cells","category":"Cloning","deployed":false,"on_the_fly":false,"field_types":[{"ftype":"sample","role":"input","name":"Plasmid","sample_types":["Plasmid","Plasmid","Plasmid","Plasmid","Plasmid"],"object_types":["Gibson Reaction Result","Ligation product","Plasmid Stock","1 ng/µL Plasmid Stock","DNA Mix"],"part":false,"array":false,"routing":"P","preferred_operation_type_id":25,"preferred_field_type_id":111,"choices":null},{"ftype":"sample","role":"output","name":"Transformed E Coli","sample_types":["Plasmid"],"object_types":["Transformed E. coli Aliquot"],"part":false,"array":false,"routing":"P","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null},{"ftype":"sample","role":"input","name":"Comp Cells","sample_types":["E coli strain"],"object_types":["E. coli Comp Cell Batch"],"part":true,"array":false,"routing":"C","preferred_operation_type_id":null,"preferred_field_type_id":null,"choices":null}],"protocol":"# Author: Ayesha Saleem\r\n# November 5, 2016\r\n# Revision: Justin Vrana, 2017-07-21 (corrected index error, refactored collection removal proceedure, added batch replacement, added plasimd stock dilution)\r\n# Revision: Orlando do Lange, 2017-09-12 (Added precondition that if the input is a Ligation product that item must be at least 2 hours old)\r\n\r\nneeds \"Cloning Libs/Special Days\"\r\nneeds \"Standard Libs/Debug\"\r\nneeds \"Standard Libs/Feedback\"\r\n\r\nclass Protocol\r\n include Feedback\r\n include SpecialDays\r\n include Debug\r\n \r\n # io\r\n CELLS = \"Comp Cells\"\r\n INPUT = \"Plasmid\"\r\n OUTPUT = \"Transformed E Coli\"\r\n \r\n # debug\r\n DEBUG_WITH_REPLACEMENT = true\r\n \r\n # specs\r\n RESUSPENSION_VOL = 900 # how much to resuspend transformed cells in\r\n \r\n def main\r\n # Detract comp cells from batches, store how many of each type of comp cell there are, and figure out how many Amp vs Kan plates will be needed \r\n \r\n # Determine replacements of e coli comp cell batch\r\n determine_replacements\r\n\r\n # Detract from running batches\r\n operations.running.each { |op| op.input(CELLS).collection.remove_one op.input(CELLS).sample }\r\n\r\n # Exit early if there are no more running operations\r\n if operations.empty?\r\n show do\r\n title \"All operations have errored\"\r\n note \"All operations have errored out.\"\r\n end\r\n return {}\r\n end\r\n \r\n # Make \r\n operations.running.retrieve(only: [\"Plasmid\"]).make\r\n \r\n # Prepare electroporator \r\n prepare_electroporator\r\n \r\n # Measure plasmid stock concentrations\r\n ops_for_dilution = operations.running.select { |op| op.input(INPUT).object_type.name == \"Plasmid Stock\" }\r\n ops_for_measurement = ops_for_dilution.select { |op| op.input(INPUT).item.get(:concentration).to_f == 0.0 }\r\n measure_plasmid_stock ops_for_measurement\r\n\r\n # Dilute plasmid stocks\r\n dilute_plasmid_stocks ops_for_dilution\r\n \r\n # Get comp cells and cuvettes \r\n get_cold_items \r\n \r\n # Label aliquots\r\n label_aliquots \r\n \r\n index = 0\r\n \r\n # Display table to tech\r\n display_table index\r\n \r\n #plate pre heating\r\n plate_preheating \r\n \r\n # Incubate transformants\r\n incubate_transformants \r\n\r\n # Clean up\r\n clean_up\r\n \r\n # Move items\r\n operations.running.each do |op|\r\n op.output(OUTPUT).item.move \"37C shaker\"\r\n end\r\n \r\n give_happy_birthday\r\n \r\n # Store dna stocks\r\n all_stocks = operations.running.map { |op| [op.input(INPUT).item, op.temporary[:old_stock]] }.flatten.uniq\r\n all_stocks.compact!\r\n release all_stocks, interactive: true, method: \"boxes\"\r\n \r\n return {}\r\n end\r\n \r\n # This method tells the technician to prepare the electroporator and bench\r\n def prepare_electroporator\r\n show do\r\n title \"Prepare bench\"\r\n note \"If the electroporator is off (no numbers displayed), turn it on using the ON/STDBY button.\"\r\n note \"Set the voltage to 1250V by clicking the up and down buttons.\"\r\n note \" Click the time constant button to show 0.0.\"\r\n image \"Actions/Transformation/initialize_electroporator.jpg\"\r\n check \"Retrieve and label #{operations.running.length} 1.5 mL tubes with the following ids: #{operations.running.collect { |op| \"#{op.output(OUTPUT).item.id}\"}.join(\",\")} \"\r\n check \"Set your 3 pipettors to be 2 uL, 42 uL, and 900 uL.\"\r\n check \"Prepare 10 uL, 100 uL, and 1000 uL pipette tips.\" \r\n check \"Grab a Bench SOC liquid aliquot (sterile) and loosen the cap.\"\r\n end\r\n end\r\n \r\n # takes in array of operations and asks the technician\r\n # to measure the concentrations of the input items.\r\n # \r\n # @param ops_for_measurement [Array] the ops that contain the items we are measuring\r\n def measure_plasmid_stock ops_for_measurement\r\n if ops_for_measurement.any?\r\n conc_table = Proc.new { |ops|\r\n ops.start_table\r\n .input_item(INPUT)\r\n .custom_input(:concentration, heading: \"Concentration (ng/ul)\", type: \"number\") { |op| \r\n x = op.temporary[:concentration] || -1\r\n x = rand(10..100) if debug\r\n x\r\n }\r\n .validate(:concentration) { |op, v| v.between?(0,10000) }\r\n .validation_message(:concentration) { |op, k, v| \"Concentration must be non-zero!\" }\r\n .end_table.all\r\n }\r\n \r\n show_with_input_table(ops_for_measurement, conc_table) do\r\n title \"Measure concentrations\"\r\n note \"The concentrations of some plasmid stocks are unknown.\"\r\n check \"Go to the nanodrop and measure the concentrations for the following items.\"\r\n check \"Write the concentration on the side of each tube\"\r\n end\r\n \r\n ops_for_measurement.each do |op|\r\n op.input(INPUT).item.associate :concentration, op.temporary[:concentration]\r\n end\r\n end\r\n end\r\n \r\n # This method tells the technician to get cold items.\r\n def get_cold_items \r\n show do \r\n title \"Get cold items\"\r\n note \"Retrieve a styrofoam ice block and an aluminum tube rack. Put the aluminum tube rack on top of the ice block.\"\r\n image \"arrange_cold_block\"\r\n check \"Retrieve #{operations.length} cuvettes and put inside the styrofoam touching ice block.\"\r\n note \"Retrieve the following electrocompetent aliquots from the M80 and place them on an aluminum tube rack: \"\r\n operations.group_by { |op| op.input(CELLS).item }.each do |batch, grouped_ops|\r\n check \"#{grouped_ops.size} aliquot(s) of #{grouped_ops.first.input(CELLS).sample.name} from batch #{batch.id}\"\r\n end\r\n image \"Actions/Transformation/handle_electrocompetent_cells.jpg\"\r\n end\r\n end\r\n \r\n # This method tells the technician to label aliquots.\r\n def label_aliquots \r\n show do \r\n title \"Label aliquots\"\r\n aliquotsLabeled = 0\r\n operations.group_by { |op| op.input(CELLS).item }.each do |batch, grouped_ops|\r\n if grouped_ops.size == 1\r\n check \"Label the electrocompetent aliquot of #{grouped_ops.first.input(CELLS).sample.name} as #{aliquotsLabeled + 1}.\"\r\n else\r\n check \"Label each electrocompetent aliquot of #{grouped_ops.first.input(CELLS).sample.name} from #{aliquotsLabeled + 1}-#{grouped_ops.size + aliquotsLabeled}.\"\r\n end\r\n aliquotsLabeled += grouped_ops.size\r\n end\r\n note \"If still frozen, wait till the cells have thawed to a slushy consistency.\"\r\n warning \"Transformation efficiency depends on keeping electrocompetent cells ice-cold until electroporation.\"\r\n warning \"Do not wait too long\"\r\n image \"Actions/Transformation/thawed_electrocompotent_cells.jpg\"\r\n end\r\n end\r\n \r\n # This method tells the technician to add plasmid to the electrocompetent aliquot, electroporate, and rescue.\r\n def display_table index\r\n show do\r\n title \"Add plasmid to electrocompetent aliquot, electroporate and rescue \"\r\n note \"Repeat for each row in the table:\"\r\n check \"Pipette 2 uL plasmid/gibson result into labeled electrocompetent aliquot, swirl the tip to mix and place back on the aluminum rack after mixing.\"\r\n check \"Transfer 42 uL of e-comp cells to electrocuvette with P100\"\r\n check \"Slide into electroporator, press PULSE button twice, and QUICKLY add #{RESUSPENSION_VOL} uL of SOC\"\r\n check \"pipette cells up and down 3 times, then transfer #{RESUSPENSION_VOL} uL to appropriate 1.5 mL tube with P1000\"\r\n table operations.running.start_table \r\n .input_item(\"Plasmid\")\r\n .custom_column(heading: \"Electrocompetent Aliquot\") { index = index + 1 }\r\n .output_item(\"Transformed E Coli\", checkable: true)\r\n .end_table\r\n end\r\n end\r\n \r\n # This method tells the technician to incubate the E. coli transformants.\r\n def incubate_transformants \r\n show do \r\n title \"Incubate transformants\"\r\n check \"Grab a glass flask\"\r\n check \"Place E. coli transformants inside flask laying sideways and place flask into shaking #{operations[0].input(\"Plasmid\").sample.properties[\"Transformation Temperature\"].to_i} C incubator.\"\r\n #Open google timer in new window\r\n note \"Transformants with an AMP marker should incubate for only 30 minutes. Transformants with a KAN, SPEC, or CHLOR marker needs to incubate for 60 minutes.\"\r\n note \"\u003ca href=\\'https://www.google.com/search?q=30%20minute%20timer\\' target=\\'_blank\\'\u003eUse a 30 minute Google timer\u003c/a\u003e or \u003ca href=\\'https://www.google.com/search?q=60%20minute%20timer\\' target=\\'_blank\\'\u003ea 60 minute Google timer\u003c/a\u003e to set a reminder to retrieve the transformants, at which point you will start the \\'Plate Transformed Cells\\' protocol.\"\r\n image \"Actions/Transformation/37_c_shaker_incubator.jpg\"\r\n note \"While the transformants incubate, finish this protocol by completing the remaining tasks.\"\r\n end\r\n end\r\n \r\n # This method tells the technician to pre-heat the plates for later use.\r\n def plate_preheating \r\n show do \r\n title \"Pre-heat plates\"\r\n note \"Retrieve the following plates, and place into still #{operations[0].input(\"Plasmid\").sample.properties[\"Transformation Temperature\"].to_i} C incubator.\" \r\n grouped_by_marker = operations.running.group_by { |op|\r\n op.input(INPUT).sample.properties[\"Bacterial Marker\"].upcase\r\n }\r\n grouped_by_marker.each do |marker, ops|\r\n check \"#{ops.size} LB + #{marker} plates\"\r\n end\r\n image \"Actions/Plating/put_plate_incubator.JPG\"\r\n end\r\n end\r\n \r\n # This method tells the technician to clean up items used in this protocol.\r\n def clean_up\r\n show do\r\n title \"Clean up\"\r\n check \"Put all cuvettes into biohazardous waste.\"\r\n check \"Discard empty electrocompetent aliquot tubes into waste bin.\"\r\n check \"Return the styrofoam ice block and the aluminum tube rack.\"\r\n image \"Actions/Transformation/dump_dirty_cuvettes.jpg\"\r\n end\r\n end\r\n \r\n # This method determines and finds replacement batches if the current batch is empty.\r\n # If there are no replacement batches available, that batch's operation errors.\r\n def determine_replacements\r\n operations.running.each do |op|\r\n # If current batch is empty\r\n if op.input(CELLS).collection.empty? || (debug and DEBUG_WITH_REPLACEMENT)\r\n old_batch = op.input(CELLS).collection\r\n \r\n # Find replacement batches\r\n all_batches = Collection.where(object_type_id: old_batch.object_type.id).select { |b| !b.empty? \u0026\u0026 !b.deleted? \u0026\u0026 (b.matrix[0].include? op.input(CELLS).sample.id) }\r\n # batches_of_cells = all_batches.select { |b| b.include? op.input(CELLS).sample \u0026\u0026 !b.deleted? }.sort { |x| x.num_samples }\r\n batches_of_cells = all_batches.reject { |b| b == old_batch }.sort { |x| x.num_samples } # debug specific rejection to force replacement\r\n \r\n # Error if not enough\r\n if batches_of_cells.empty?\r\n op.error :not_enough_comp_cells, \"There were not enough comp cells of #{op.input(CELLS).sample.name} to complete the operation.\"\r\n else\r\n # Set input to new batch\r\n \r\n op.input(CELLS).set collection: batches_of_cells.last\r\n # Display warning\r\n op.associate :comp_cell_batch_replaced, \"There were not enough comp cells for this operation. Replaced batch #{old_batch.id} with batch #{op.input(CELLS).collection.id}\"\r\n end\r\n end\r\n end\r\n end\r\n \r\n # This method tells the technician to dilute plasmid stocks.\r\n def dilute_plasmid_stocks ops_for_dilution\r\n if ops_for_dilution.any?\r\n show do\r\n title \"Prepare plasmid stocks\"\r\n \r\n ops_for_dilution.each do |op|\r\n i = produce new_sample op.input(INPUT).sample.name, of: op.input(INPUT).sample_type, as: \"1 ng/L Plasmid Stock\"\r\n \r\n op.temporary[:old_stock] = op.input(INPUT).item\r\n op.input(INPUT).item.associate :from, op.temporary[:old_stock].id\r\n vol = 0.5\r\n c = op.temporary[:old_stock].get(:concentration).to_f\r\n op.temporary[:water_vol] = (vol * c).round(1)\r\n op.temporary[:vol] = vol\r\n op.input(INPUT).set item: i\r\n op.associate :plasmid_stock_diluted, \"Plasmid stock #{op.temporary[:old_stock].id} was diluted and a 1 ng/ul Plasmid Stock was created: #{op.input(INPUT).item.id}\"\r\n end\r\n \r\n check \"Grab \u003cb\u003e#{ops_for_dilution.size}\u003c/b\u003e 1.5 mL tubes and place in rack\"\r\n note \"According to the table below:\"\r\n check \"Label all tubes with the corresponding Tube id\"\r\n check \"Pipette MG H20\"\r\n check \"Pipette DNA\"\r\n table ops_for_dilution.start_table\r\n .input_item(INPUT, heading: \"Tube id\", checkable: true)\r\n .custom_column(heading: \"MG H20\", checkable: true) { |op| \"#{op.temporary[:water_vol]} ul\" }\r\n .custom_column(heading: \"Plasmid Stock (ul)\", checkable: true) { |op| \"#{op.temporary[:vol]} ul of #{op.temporary[:old_stock].id}\" }\r\n .end_table\r\n end\r\n \r\n show do\r\n title \"Set aside old plasmid stocks\"\r\n \r\n note \"The following plasmid stocks will no longer be needed for this protocol.\"\r\n check \"Set aside the old plasmid stocks:\"\r\n ops_for_dilution.each do |op|\r\n check \"#{op.temporary[:old_stock]}\"\r\n end\r\n end\r\n end\r\n end\r\nend ","precondition":"eval Library.find_by_name(\"Preconditions\").code(\"source\").content\nextend Preconditions\n\ndef precondition(op) \n if op.input(\"Plasmid\").object_type.name == \"Ligation Product\" \n return time_elapsed op, \"Plasmid\", hours: 2\n else\n return true\n end\n \n if op.input(\"Plasmid\").sample.properties[\"Bacterial Marker\"].nil? || op.input(\"Plasmid\").sample.properties[\"Bacterial Marker\"] == \"\"\n return false\n end\nend","cost_model":"# Transform Ecoli Cells Cost Model\n\ndef cost(op)\n {\n materials: 3.57,\n labor: 6.68 \n } \nend","documentation":"Transforms input cells.\n\nThe technician retrieves the input plasmid and, using DH5a E. coli competent cells, performs electroporation. The electeroporated cells are then inoculated in LB for an hour.\n\nRan after **Assemble Plasmid** and is a precursor to **Plate Transformed Cells**.","test":"","timing":{"start":810,"stop":840,"days":"[\"Mo\",\"Tu\",\"We\",\"Th\",\"Fr\"]","active":true}}},{"library":{"name":"Cloning","category":"Cloning Libs","code_source":"module Cloning\n \n def check_concentration operations, input_name\n items = operations.collect { |op| op.input_array(input_name).items.select { |i| i.get(:concentration).nil? } }.flatten.uniq\n \n cc = show do \n title \"Please nanodrop the following #{items.first.object_type.name.pluralize}\"\n note \"Please nanodrop the following #{items.first.object_type.name.pluralize}:\"\n items.each do |i|\n get \"number\", var: \"c#{i.id}\", label: \"#{i} item\", default: 42\n end\n end if items.any?\n \n items.each do |i|\n i.associate :concentration, cc[\"c#{i.id}\".to_sym]\n end\n end\n \n \n # The check_volumes method will have the lab tech ensure that the given input item volumes are above a certain minimum amount, \n # for each operation. The inputs to check are specified in an array parameter. \n # The minimum volume is specified in mL on a per-operation basis using the the value stored in op.temporary[\u003cvol_sym\u003e],\n # where vol_sym is a symbol name of your choice. \n # Contamination can be checked for too, with the additional option parameter check_contam: true\n # After determining which inputs for which ops are low volume, this method passes off a hash of 'items -\u003e lists of ops' to your rebuilder function specified by name as string or symbol in the callback argument.\n # when the callback method returns, check_volumes loops back and checks the volumes again of the newly assigned unverified input items, and repeats this loop until all given inputs for all ops are verified for their volume.\n # for a detailed example of how this method can be used, look at the method call in make PCR fragment, and the callback function make_aliquots_from_stock\n def check_volumes inputs, vol_sym, callback, options = {} \n \n ops_by_item = Hash.new(0)\n operations.running.each do |op|\n inputs.each do |input|\n if ops_by_item.keys.include? op.input(input).item\n ops_by_item[op.input(input).item].push op\n else\n ops_by_item[op.input(input).item] = [op] \n end\n end\n end\n \n # while any operations for any of the specified inputs are unverified, check the volumes again and send any bad op/input combos to rebuilder function\n while ops_by_item.keys.any?\n verify_data = show do\n title \"Verify enough volume of each #{inputs.to_sentence(last_word_connector: \", or\")} exists#{options[:check_contam] ? \", or note if contamination is present\" : \"\"}\"\n \n ops_by_item.each do |item, ops| \n volume = 0.0\n ops.each { |op| volume += op.temporary[vol_sym] }\n volume = (volume*100).round / 100.0\n choices = options[:check_contam] ? [\"Yes\", \"No\", \"Contamination is present\"] : [\"Yes\", \"No\"]\n select choices, var: \"#{item.id}\", label: \"Is there at least #{volume} L of #{item.id}?\", default: 0\n end\n end\n ops_by_item.each do |item, ops|\n if verify_data[\"#{item.id}\".to_sym] == \"Yes\"\n ops_by_item.except! item\n elsif verify_data[\"#{item.id}\".to_sym] == \"Contamination is present\"\n item.associate(:contaminated, \"Yes\")\n end\n end\n method(callback.to_sym).call(ops_by_item, inputs) if ops_by_item.keys.any?\n end\n end\n \n # a common callback for check_volume.\n # takes in lists of all ops that have input aliquots with insufficient volume, sorted by item,\n # and takes in the inputs which were checked for those ops.\n # Deletes bad items and remakes each primer aliquots from primer stock\n def make_aliquots_from_stock bad_ops_by_item, inputs\n # bad_ops_by_item is accessible by bad_ops_by_item[item] = [op1, op2, op3...]\n # where each op has a bad volume reading for the given item\n \n # Construct list of all stocks needed for making aliquots. Error ops for which no primer stock is available\n # for every non-errored op that has low item volume,\n # replace the old aliquot item with a new one. \n aliquots_to_make = 0\n stocks = []\n ops_by_fresh_item = Hash.new(0)\n found_items = []\n stock_table = [[\"Primer Stock ID\", \"Primer Aliquot ID\"]]\n transfer_table = [[\"Old Aliquot ID\", \"New Aliquot ID\"]]\n bad_ops_by_item.each do |item, ops|\n \n #first, check to see if there is a replacement aliquot availalbe in the inventory\n fresh_item = item.sample.in(\"Primer Aliquot\").reject {|i| i == item }.first\n \n if fresh_item\n #if a replacement item was found in the inventory, snag it\n found_items.push fresh_item\n else\n # no replacement, found, lets try making one.\n stock = item.sample.in(\"Primer Stock\").first\n if stock.nil?\n # no stock found, replacement could not be made or found: erroring operation\n ops.each { |op| op.error :no_primer_stock, \"aliquot #{item.id} was bad and a replacement could not be made. You need to order a primer stock for primer sample #{item.sample.id}.\" }\n bad_ops_by_item.except! item\n else\n stocks.push stock\n aliquots_to_make += 1\n fresh_item = produce new_sample item.sample.name, of: item.sample.sample_type.name, as: item.object_type.name\n stock_table.push [stock.id, {content: fresh_item.id, check: true}]\n end\n end\n \n if fresh_item\n # for the items where a replacement is able to be found or made, update op item info\n item.mark_as_deleted\n bad_ops_by_item.except! item\n ops_by_fresh_item[fresh_item] = ops\n ops.each do |op| \n input = inputs.find { |input| op.input(input).item == item }\n op.input(input).set item: fresh_item\n end\n if item.get(:contaminated) != \"Yes\"\n transfer_table.push [item.id, {content: fresh_item.id, check: true}] \n end\n end\n end\n \n take found_items, interactive: true if found_items.any?\n #items are guilty untill proven innocent. all the fresh items will be put back into the list of items to check for volume\n bad_ops_by_item.merge! ops_by_fresh_item\n take stocks, interactive: true if stocks.any?\n \n # label new aliquot tubes and dilute\n show do \n title \"Grab 1.5 mL tubes\"\n \n note \"Grab #{aliquots_to_make} 1.5 mL tubes\"\n note \"Label each tube with the following ids: #{bad_ops_by_item.keys.reject { |item| found_items.include? item }.map { |item| item.id }.sort.to_sentence}\"\n note \"Using the 100 uL pipette, pipette 90uL of water into each tube\"\n end if bad_ops_by_item.keys.reject { |item| found_items.include? item }.any?\n \n # make new aliquots\n show do \n title \"Transfer primer stock into primer aliquot\"\n \n note \"Pipette 10 uL of the primer stock into the primer aliquot according to the following table:\"\n table stock_table\n end if stocks.any?\n \n \n if transfer_table.length \u003e 1\n show do\n title \"Transfer Residual Primer\"\n \n note \"Transfer primer residue from the low volume aliquots into the fresh aliquots according to the following table:\"\n table transfer_table\n end\n end\n \n release stocks, interactive: true if stocks.any?\n end\n \n def incubate operations, shaker, input_name, output_name\n operations.each { |op|\n op.output(output_name).item.move \"#{op.input(input_name).sample.properties[\"Transformation Temperature\"].to_i} C #{shaker} incubator\"\n }\n end\n \n \n \n # Associates specified associations + uploads from :from to :to. This is used primarily to pass sequencing results through items in a plasmid's lineage\n # e.g., pass_data \"sequence_verified\", \"sequencing results\", from: overnight, to: glycerol_stock\n # This will copy all sequencing results and the sequence_verified associations from the overnight to the glycerol stock\n def pass_data *names, **kwargs\n from = kwargs[:from]\n to = kwargs[:to]\n names.each do |name|\n keys = from.associations.keys.select { |k| k.include? name }\n keys.each do |k|\n to.associate k, from.get(k), from.upload(k)\n end\n end\n end\n \nend\n\n "}},{"library":{"name":"Centrifuge","category":"Standard Libs","code_source":"# [email protected]\r\n# This module is made to cover all common cases of directing the tech to\r\n# centrifuge, decant, and resuspend multiple batches of tubes.\r\n# centrifuge_resuspend_cycle is the public method of this module.\r\n# It allows staggered centrifuging so that the tech can be resuspending\r\n# the previous batch while the next batch is centrifuging.\r\nmodule Centrifuge\r\n class Batch\r\n attr_reader :marker, :tubes\r\n\r\n def initialize(args)\r\n @marker = args[:marker]\r\n @tubes = args[:tubes]\r\n end\r\n\r\n # Partition the given tubes list into batches.\r\n # Returns a list of Batch objects, each having a letter marker, and a list\r\n # of tubes.\r\n def self.initialize_batches(tubes, centrifuge_slots, protocol)\r\n @@protocol = protocol # we need this to use show commands in Batch methods\r\n @@batch_size = centrifuge_slots\r\n tube_batches = tubes.each_slice(centrifuge_slots).to_a\r\n batches = []\r\n tube_batches.each_with_index do |tube_batch, i|\r\n batch_id = [(i + 65).chr]\r\n batches.push Batch.new(marker: batch_id, tubes: tube_batch)\r\n end\r\n batches\r\n end\r\n \r\n def self.batch_size\r\n @@batch_size\r\n end\r\n\r\n # returns a new list of batches produced by reducing the amount of tubes in\r\n # each batch and then combining batches, Batches.size will be halved.\r\n def self.combine_batches(batches)\r\n paired_batches = batches.each_slice(2).to_a\r\n batches = []\r\n paired_batches.each do |pair|\r\n pair.each_with_index do |batch, i|\r\n pair[i] = batch.combine_tubes\r\n end\r\n batches.push(pair[0].combine_with(pair[1]))\r\n end\r\n batches\r\n end\r\n\r\n # Instructs tech to reduce the number of tubes in the given batch by a power\r\n # of 2, combining tubes of the same sample. This only shows the instructions\r\n # and does not alter the state of batches[].\r\n # (that happens in combine_batches)\r\n def combine_tubes_instructions()\r\n batch = self\r\n @@protocol.show do\r\n title 'Combine Tubes'\r\n if batch.marker.length == 1\r\n note 'Reduce the number of tubes in '\\\r\n \"\u003cb\u003ebatch #{batch.marker.to_sentence}\u003c/b\u003e from #{batch.tubes.length} \"\\\r\n \"to #{batch.tubes.length / 2} by combining tubes.\"\r\n else\r\n note \"Together, \u003cb\u003ebatches #{batch.marker.to_sentence}\u003c/b\u003e have a \"\\\r\n \"total of #{batch.tubes.length} tubes. Reduce the sum of tubes to \"\\\r\n \"#{batch.tubes.length / 2} by combining tubes from \"\\\r\n \"#{batch.marker.length == 2 ? 'both' : 'all'} batches.\"\r\n end\r\n note 'Combine tubes by carefully pouring one tube into tube '\\\r\n 'that shares the same id.'\r\n note 'All tubes after combination should have the same volume. '\\\r\n 'Do not \"double combine\" any tubes.'\r\n batch.tubes.uniq.each do |tube|\r\n note \"Combine each tube labeled \u003cb\u003e#{tube}\u003c/b\u003e \"\\\r\n \"with another tube labeled \u003cb\u003e#{tube}\u003c/b\u003e.\"\r\n end\r\n if Cycle.cold?\r\n warning 'Once finished with combining, '\\\r\n 'immediately place tubes in ice bath.'\r\n end\r\n end\r\n end\r\n\r\n # instructions to place tubes from batch into the centrifuge\r\n def centrifuge(centrifuge_instructions)\r\n rpm = centrifuge_instructions[:rpm]\r\n time = centrifuge_instructions[:time]\r\n temp = centrifuge_instructions[:temp]\r\n batch = self\r\n @@protocol.show do\r\n title 'centrifuge tubes'\r\n note \"Set the centrifuge to #{rpm} rpm for #{time} minutes at \"\\\r\n \"#{temp} C. Ensure correct centrifuge tube holders are in place.\"\r\n note \"Move all tubes from \u003cb\u003e#{'batch'.pluralize(batch.marker.length)} \"\\\r\n \"#{batch.marker.to_sentence}\u003c/b\u003e to centrifuge and press start.\"\r\n if batch.tubes.length.odd?\r\n warning 'Balance the centrifuge with a dummy tube that is filled '\\\r\n 'with the same volume of liquid as the other tubes.'\r\n end\r\n end\r\n end\r\n\r\n # instructions to remove tubes from the centrifuge\r\n # after it has finished a spin\r\n def remove_tubes()\r\n batch = self\r\n @@protocol.show do\r\n title 'Remove Tubes from Centrifuge'\r\n note 'Wait for centrifuge to finish'\r\n note 'Once the centrifuge has finished its spin, '\\\r\n 'remove tubes from centrifuge.'\r\n note \"The removed tubes should be marked as \"\\\r\n \"\u003cb\u003e#{'batch'.pluralize(batch.marker.length)} \"\\\r\n \"#{batch.marker.to_sentence}\u003c/b\u003e.\"\r\n if Cycle.cold?\r\n warning 'Once removed from centrifuge, '\\\r\n 'immediately place tubes in ice bath.'\r\n end\r\n end\r\n end\r\n\r\n # instructions to resuspend tubes\r\n def resuspend(resuspend_instructions)\r\n volume = resuspend_instructions[:volume]\r\n media = resuspend_instructions[:media]\r\n\r\n decant()\r\n\r\n batch = self\r\n @@protocol.show do\r\n title \"Resuspend cells in #{volume}mL of #{media}\"\r\n note \"Grab bottle of #{media} from fridge.\"\r\n note \"Carefully pour #{volume}mL of #{media} into each tube from \u003cb\u003e\"\\\r\n \"#{'batch'.pluralize(batch.marker.length)} #{batch.marker.to_sentence}\u003c/b\u003e.\"\r\n note 'Shake and vortex tubes until pellet is completely resuspended.'\r\n warning 'When not actively shaking or vortexing keep tubes in ice, '\\\r\n 'and place all tubes in ice once resuspended.' if Cycle.cold?\r\n note \"At next opportunity, bring #{media} back to fridge, \"\\\r\n 'or to dishwasher if empty.'\r\n end\r\n end\r\n\r\n def decant()\r\n batch = self\r\n @@protocol.show do\r\n title 'Decant tubes'\r\n note \"Take #{Cycle.cold? ? 'ice bucket' : 'tubes'} to the \"\\\r\n \"dishwasing station, and pour out supernatant of tubes from \u003cb\u003e\"\\\r\n \"#{'batch'.pluralize(batch.marker.length)} #{batch.marker.to_sentence}\u003c/b\u003e.\"\r\n note 'Place tubes in ice immediately after decanting.' if Cycle.cold?\r\n end\r\n end\r\n\r\n # returns new batch which is the combination of this batch\r\n # and the other batch\r\n # helper for combine_batches\r\n def combine_with(other)\r\n if other\r\n new_marker = marker.concat other.marker\r\n new_tubes = tubes.concat other.tubes\r\n return Batch.new(marker: new_marker, tubes: new_tubes)\r\n else\r\n return self\r\n end\r\n end\r\n\r\n # returns a new batch with a half the tubes, where like tubes have been\r\n # combined.\r\n # helper for combine_batches\r\n def combine_tubes\r\n new_tubes = []\r\n new_tubes.concat(tubes)\r\n batch = Batch.new(marker: marker,tubes: [])\r\n tubes.uniq.each do |short_id|\r\n sameids = new_tubes.select { |tube| tube == short_id }\r\n batch.tubes.concat(sameids[0, sameids.length / 2])\r\n end\r\n batch\r\n end\r\n end\r\n\r\n class Cycle\r\n attr_reader :centrifuge_instructions, :resuspend_instructions\r\n def initialize(cycle_instructions)\r\n @centrifuge_instructions = { temp: cycle_instructions[:cent_temp],\r\n rpm: cycle_instructions[:cent_rpm],\r\n time: cycle_instructions[:cent_time] }\r\n\r\n @resuspend_instructions = { media: cycle_instructions[:sus_media],\r\n volume: cycle_instructions[:sus_volume] }\r\n\r\n @combine = cycle_instructions[:combine]\r\n end\r\n\r\n def self.initialize_cycles(cycles_data, cold)\r\n @@cold = cold\r\n cycles = cycles_data.map do |cycle_data|\r\n Cycle.new(cycle_data)\r\n end\r\n cycles\r\n end\r\n\r\n def self.cold?\r\n @@cold\r\n end\r\n\r\n def combine?\r\n @combine\r\n end\r\n end\r\n\r\n ##\r\n # @param [Hash] opts The parameters which indicate cycling behaivor\r\n # @option [Array\u003cItem\u003e] items The array of items for which each will\r\n # be split into smaller tubes and then centrifuge cycled on.\r\n # @option [Float] start_vol Volume of liquid that each item begins with.\r\n # @option [Float] tube_vol Volume of centrifuge tubes that\r\n # start_vol will be divided amongst\r\n # @option [Integer] centrifuge_slots Number of slots in the centrifuge.\r\n # Must be an even number.\r\n # @option [Array\u003cHash\u003e] cycles Instructions for each cycle of centrifuging.\r\n # Cycles.length indicates how many centrifuge/wash cycles.\r\n # Elements of cycles contain instructions for the centrifuging\r\n # and resuspension settings for that cycle.\r\n # @option [Boolean] :cold Indicate if centrifuge cycling is done on ice.\r\n # Default: no\r\n # @option [Symbol] :cb_extra_instructions Extra instructions for tech\r\n # while waiting for final centrifuge batch to finish,\r\n # for example, tidying up workspace. Default: none\r\n # @effects This method Instructs tech to do cycles of centrifuging,\r\n # decanting, and resuspending on each item\r\n # as per the instructions stored in cycles.\r\n def centrifuge_resuspend_cycle(opts = {})\r\n # Bench setup is required before we begin centrifuging\r\n # During setup, the items will be aliquoted into tubes,\r\n # and each aliquoted tube will be marked with a short id.\r\n # This maps tubes to the item they originated from, and will\r\n # keep track of which tubes contain the same substance.\r\n # the index of the parent item in the items[] is used\r\n # for the short id.\r\n # Also, tubes are grouped into batches that will fit in centrifuge,\r\n # and marked with a capital letter batch identifier, in addition to their\r\n # short id that indicates their ancestry.\r\n\r\n # computation\r\n tubes = initialize_tubes(opts)\r\n batches = Batch.initialize_batches(tubes, opts[:centrifuge_slots], self)\r\n cycles = Cycle.initialize_cycles(opts[:cycles], opts[:cold])\r\n\r\n # tech instructions\r\n setup_steps(cycles, batches,\r\n opts[:start_vol], opts[:tube_vol], opts[:items])\r\n\r\n # Loop through each cycle of centrifuging and resuspending found in cycles[]\r\n # and perform that cycle on each batch of tubes in found in batches[]\r\n this_batch = nil\r\n cycles.each_with_index do |cycle, i|\r\n prev_cycle = cycles[i - 1]\r\n \r\n # Reconfigure batches array to be shortened by combing batches\r\n # so each batch has enough tubes to fill centrifuge.\r\n batches = Batch.combine_batches(batches) if prev_cycle.combine?\r\n\r\n batch_iterator = batches.each\r\n first_batch = batch_iterator.next\r\n if i.zero?\r\n # first batch of first cycle, the centrifuge is empty\r\n first_batch.centrifuge(cycle.centrifuge_instructions)\r\n else\r\n this_batch.remove_tubes\r\n if batches.length == 1\r\n # this_batch == first_batch || first_batch contains this_batch\r\n this_batch.resuspend(prev_cycle.resuspend_instructions)\r\n this_batch.combine_tubes_instructions if prev_cycle.combine?\r\n first_batch.centrifuge(cycle.centrifuge_instructions)\r\n else\r\n # first_batch and this_batch are not associated,\r\n # we can start centrifuging first_batch before we resuspend this_batch\r\n first_batch.centrifuge(cycle.centrifuge_instructions)\r\n this_batch.resuspend(prev_cycle.resuspend_instructions)\r\n this_batch.combine_tubes_instructions if prev_cycle.combine?\r\n end\r\n end\r\n\r\n this_batch = first_batch\r\n while has_next? batch_iterator\r\n next_batch = batch_iterator.next\r\n this_batch.remove_tubes\r\n next_batch.centrifuge(cycle.centrifuge_instructions)\r\n this_batch.resuspend(cycle.resuspend_instructions)\r\n this_batch.combine_tubes_instructions if cycle.combine?\r\n this_batch = next_batch\r\n end\r\n end\r\n\r\n # Show any extra steps specified by client to do\r\n # while waiting for last spin to finish.\r\n extra_instructions(opts[:cb_extra_instructions])\r\n\r\n final_cycle = cycles.last\r\n this_batch.remove_tubes\r\n this_batch.resuspend(final_cycle.resuspend_instructions)\r\n if final_cycle.combine?\r\n this_batch.combine_tubes_instructions\r\n batches = Batch.combine_batches(batches)\r\n end\r\n\r\n # On remaining tubes,\r\n # replaces the short id with the id of original parent item.\r\n relabel_tubes(batches, opts[:items])\r\n end\r\n\r\n private\r\n\r\n # Ensures state of variables is acceptable\r\n # TODO add more checks\r\n def error_checks(cycles, batches, opts)\r\n raise 'odd slot centrifuge not supported' if Batch.batch_size.odd?\r\n raise 'wrong cycle amount' if cycles.length != opts[:cycles].length\r\n raise 'wrong batch size' if Batch.batch_size != opts[:centrifuge_slots]\r\n end\r\n\r\n # Initializes array of integers that represent tubes\r\n # identified by their short_id which corresponds to the parent item.\r\n # Also returns\r\n def initialize_tubes(opts)\r\n combination_occurs = opts[:cycles].any? { |cycle| cycle[:combine] == true }\r\n tubes_per_item = (opts[:start_vol] / opts[:tube_vol]).floor\r\n tubes_per_item += 1 if tubes_per_item.odd? \u0026\u0026 combination_occurs\r\n tubes = []\r\n opts[:items].each_with_index do |_item, i|\r\n tubes_per_item.times do\r\n tubes.push (i + 1)\r\n end\r\n end\r\n tubes\r\n end\r\n\r\n # Gives the tech instructions to prepare for centrifuging.\r\n def setup_steps(cycles, batches, start_vol, tube_vol, items)\r\n tubes = batches.map { |batch| batch.tubes }.flatten\r\n\r\n fetch_supplies(cycles, tubes.length, tube_vol)\r\n if Cycle.cold?\r\n prepare_ice_bath\r\n chill_tubes(tubes.length, tube_vol)\r\n end\r\n aliquot_items_to_tubes(items, tubes, start_vol, tube_vol)\r\n batch_tubes_instructions(batches)\r\n end\r\n\r\n # Instructs tech to fetch all the media and tubes that will be required.\r\n def fetch_supplies(cycles, num_tubes, tube_vol)\r\n media_to_volume = calculate_media_volumes(cycles, num_tubes)\r\n\r\n media_location = 'on bench'\r\n tube_location = 'on bench'\r\n if Cycle.cold?\r\n media_location = 'in fridge'\r\n tube_location = 'in freezer'\r\n end\r\n\r\n show do\r\n title 'Grab required suspension media'\r\n note 'For the following set of centrifuging instructions, you will need'\\\r\n ' the following supplies: '\r\n media_to_volume.each do |media, volume|\r\n check \"At least #{volume}mL of #{media}\"\r\n end\r\n note \"Place all media bottles #{media_location}\"\\\r\n ' in preparation for centrifuge.'\r\n note \"Place #{num_tubes} #{tube_vol}mL tubes #{tube_location}\"\\\r\n ' in preparation for centrifuge.'\r\n end\r\n end\r\n\r\n def calculate_media_volumes(cycles, num_tubes)\r\n media_to_volume = Hash.new\r\n media_list = cycles.map do |cycle|\r\n cycle.resuspend_instructions[:media]\r\n end.uniq\r\n\r\n media_list.each do |media|\r\n volumes = cycles.select { |cycle|\r\n cycle.resuspend_instructions[:media] == media\r\n }.map { |cycle|\r\n cycle.resuspend_instructions[:volume]\r\n }\r\n total_volume = volumes.sum * num_tubes\r\n media_to_volume[media] = total_volume\r\n end\r\n media_to_volume\r\n end\r\n\r\n # Instructs tech to make an ice bath and immerse empty tubes in it.\r\n def prepare_ice_bath\r\n show do\r\n title 'Go to Bagley to get ice (Skip if you already have ice)'\r\n note 'Walk to ice machine room on the second floor in Bagley with a '\\\r\n 'large red bucket, fill the bucket full with ice.'\r\n note 'If unable to go to Bagley, use ice cubes to make a water bath (of '\\\r\n 'mostly ice) or use the chilled aluminum bead bucket. (if using '\\\r\n 'aluminum bead bucket place it back in freezer between spins)'\r\n end\r\n end\r\n\r\n def chill_tubes(num_tubes, tube_vol)\r\n show do\r\n title 'Prepare chilled tubes'\r\n note \"Take the #{num_tubes} #{tube_vol}mL \"\\\r\n \"#{'tube'.pluralize(num_tubes)} from the freezer \"\\\r\n 'and immerse in ice bath.'\r\n end\r\n end\r\n\r\n # Instructs the tech to divide the volume of each item in items[] into\r\n # equivolume aliquots for centrifuging.\r\n def aliquot_items_to_tubes(items, tubes, start_vol, tube_vol)\r\n tubes_per_item = tubes.length / items.length\r\n aliquot_amount = [start_vol / tubes_per_item, tube_vol].min\r\n\r\n show do\r\n title \"Aliquot items into #{tube_vol}mL tubes for centrifuging\"\r\n note 'You should have '\\\r\n \"#{items.length * tubes_per_item} #{tube_vol}mL tubes.\"\r\n if Cycle.cold?\r\n note 'While labeling and pouring, '\\\r\n 'leave tubes in ice bath as much as possible.'\r\n end\r\n items.each_with_index do |item, i|\r\n note \"Label #{tubes_per_item} tubes with short id: \u003cb\u003e#{i + 1}\u003c/b\u003e\"\r\n note \"Carefully pour #{aliquot_amount}mL from #{item} \"\\\r\n \"into each tube labeled as \u003cb\u003e#{i + 1}\u003c/b\u003e.\"\r\n end\r\n \r\n if Cycle.cold?\r\n note 'Leave tubes to chill for for 30 minutes.'\r\n timer initial: { hours: 0, minutes: 30, seconds: 0}\r\n end\r\n end\r\n end\r\n \r\n # Instructs the tech to group tubes into batches\r\n # that will fit into the centrifuge\r\n def batch_tubes_instructions(batches)\r\n show do\r\n title \"separate tubes into batches of #{Batch.batch_size} or less\"\r\n note 'Group tubes into batches as shown and mark each tube '\\\r\n 'with its alphabetic batch identifier.'\r\n batches.each do |batch|\r\n check \"\u003cb\u003e#{batch.tubes.to_sentence}\u003c/b\u003e: \"\\\r\n \"batch \u003cb\u003e#{batch.marker}\u003c/b\u003e\"\r\n end\r\n end\r\n end\r\n \r\n # Callback which runs client specified method during the time when\r\n # the tech is waiting for the last batch of tubes to finish centrifuging.\r\n def extra_instructions(method_name)\r\n method(method_name.to_sym).call if method_name \u0026\u0026 (method_name != '')\r\n end\r\n\r\n # After centrifuging finishes, instruct tech to relabel the resulting tubes\r\n # with the id of the item that they originated from, for convienence.\r\n def relabel_tubes(batches, items)\r\n result_tubes = batches.map { |batch| batch.tubes }.flatten\r\n show do\r\n title 'Label Finished Tubes'\r\n note 'Tubes with the following ids remain: '\\\r\n \"\u003cb\u003e#{result_tubes.to_sentence}\u003c/b\u003e.\"\r\n note 'Label each tube with the item id '\\\r\n 'of the item that they originated from.'\r\n items.each_with_index do |item, i|\r\n note \"The tube(s) labeled as \u003cb\u003e#{i + 1}\u003c/b\u003e \"\\\r\n \"should be relabeled as \u003cb\u003e#{item.id}\u003c/b\u003e.\"\r\n end\r\n end\r\n end\r\n\r\n # Helper method that allows manual iteration like in java\r\n # when used alongside enumerator.next()\r\n def has_next?(enum)\r\n enum.peek\r\n return true\r\n rescue StopIteration\r\n return false\r\n end\r\nend\r\n"}},{"library":{"name":"Feedback","category":"Standard Libs","code_source":"module Feedback\n CONTAINER_NAME = \"Feedback (Virtual)\"\n SAMPLE_TYPE_NAME = \"Operation Feedback\"\n \n # This method will prompt the technician to write feedback for the operations\n # that they complete on each job. This feedback will be associated to an item\n # that represents each operation type.\n def get_protocol_feedback\n \n # Gets feedback from the user\n if debug\n feedback = \"testing for job id\"\n else\n feedback = ask_for_feedback\n end\n \n if(!feedback.blank?)\n associate_feedback feedback\n end\n \n if debug\n print_association\n end\n \n end\n \n # Associates the feedback entered by the lab technician to the OperationType of the protocol\n # that uses this library.\n #\n # @param [String] the feedback entered by the lab technician.\n def associate_feedback feedback\n operation = OperationType.find(operation_type.id)\n feedback = feedback + \"- job #{jid}\"\n \n feedback_array = []\n if(!operation.get(:feedback).nil?)\n feedback_array = operation.get(:feedback)\n end\n feedback_array.push(feedback)\n operation.associate :feedback, feedback_array\n end\n \n # Debugging method that prints all associations\n def print_association\n operation = OperationType.find(operation_type.id)\n feedback_array = operation.get(:feedback)\n if feedback_array\n show do\n title \"This is printing because debug is on\"\n note \"#{feedback_array}\"\n end\n end\n end\n \n # Returns the feedback entered by a lab technician.\n #\n # @return [Hash] the information returned by the feedback show block\n def ask_for_feedback\n feedback = show do\n title \"We want your feedback\"\n \n note \"Notice anything weird with this protocol? Tell us below!\"\n \n get \"text\", var: \"feedback_user\", label: \"Enter your feedback here\", default: \"\"\n end\n feedback[:feedback_user] # return\n end\n\nend"}},{"library":{"name":"Units","category":"Standard Libs","code_source":"# frozen_string_literal: true\n\nmodule Units\n # Volume\n MICROLITERS = 'µl'\n MILLILITERS = 'ml'\n\n # Weight\n NANOGRAMS = 'ng'\n\n # Concentration\n PICOMOLAR = 'pM'\n NANOMOLAR = 'nM'\n MICROMOLAR = 'µM'\n MILLIMOLAR = 'mM'\n MOLAR = 'M'\n\n # Temperature\n DEGREES_C = '°C'\n\n # Time\n MINUTES = 'min'\n SECONDS = 'sec'\n HOURS = 'hr'\n # Force\n TIMES_G = 'x g'\n\n # R/DNA Length\n BASEPAIRS = 'bp'\n KILOBASEPAIRS = 'kbp'\n MEGABASEPAIRS = 'mbp'\n GIGABASEPAIRS = 'gbp'\n\n # Voltage\n VOLTS = 'V'\n\n def self.qty_display(qty)\n \"#{qty[:qty]} #{qty[:units]}\"\n end\n\n def qty_display(qty)\n \"#{qty[:qty]} #{qty[:units]}\"\n end\n\n def add_qty_display(options)\n new_items = {}\n\n options.each do |key, value|\n key =~ /^(.+_)+([a-z]+)$/\n\n case Regexp.last_match(2)\n when 'microliters'\n units = MICROLITERS\n when 'milliliters'\n units = MILLILITERS\n when 'minutes'\n units = MINUTES\n else\n next\n end\n\n qty = value.to_f\n\n new_items[\"#{Regexp.last_match(1)}qty\".to_sym] = {\n qty: qty, units: units\n }\n end\n\n options.update(new_items)\n end\n\n # Return the unit constant for the the unit name if there is one.\n #\n # @param unit_name [String] the name of the unit\n # @returns the value of the constant with the given name\n # @raises BadUnitNameError if the name is not the name of a defined unit\n def self.get_unit(unit_name:)\n const_get(unit_name.upcase)\n rescue StandardError\n raise BadUnitNameError.new(name: unit_name)\n end\n\n # Exception class for bad unit name arguments to Units::get_unit.\n #\n # @attr_reader [String] name the bad unit name\n class BadUnitNameError \u003c StandardError\n attr_reader :name\n\n def initialize(msg: 'Unknown unit name', name:)\n @name = name\n super(msg)\n end\n end\n\n # Return a key for the measure hash defined on the given object type.\n #\n # The measure hash must be defined in the data property of the object\n # type as JSON.\n # For instance\n #\n # { \"measure\": { \"type\": \"concentration\", \"unit\": \"micromolar\" } }\n #\n # The key is constructed as the type name, an underscore, and the unit name.\n #\n # \"concentration_µM\"\n #\n # @param object_type [ObjectType] the object type\n # @returns the key for the measure of the the object type if there is one\n # @raises MissingObjectTypeMeasure if the object type has no measure data_object\n def self.get_measure_key(object_type:)\n data_object = object_type.data_object\n raise MissingObjectTypeMeasureError.new(name: object_type.name) unless data_object.key?(:measure)\n\n measure = object_type.data_object[:measure]\n type_name = measure[:type]\n unit_name = measure[:unit]\n \"#{type_name}_#{get_unit(unit_name: unit_name)}\"\n end\n\n # Exception class for an object type without a measure hash definition.\n #\n # @attr_reader [String] name the name of the object type\n class MissingObjectTypeMeasureError \u003c StandardError\n attr_reader :name\n\n def initialize(msg: 'ObjectType has no measure in data object', name:)\n @name = name\n super(msg)\n end\n end\nend\n"}}]}