@platforma-open/milaboratories.mixcr-library-builder.workflow 1.3.1 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,13 +1,19 @@
1
1
   WARN  Issue while reading "/home/runner/work/mixcr-library-builder/mixcr-library-builder/.npmrc". Failed to replace env in config: ${NPMJS_TOKEN}
2
2
 
3
- > @platforma-open/milaboratories.mixcr-library-builder.workflow@1.3.1 build /home/runner/work/mixcr-library-builder/mixcr-library-builder/workflow
3
+ > @platforma-open/milaboratories.mixcr-library-builder.workflow@2.0.0 build /home/runner/work/mixcr-library-builder/mixcr-library-builder/workflow
4
4
  > rm -rf dist && pl-tengo check && pl-tengo build
5
5
 
6
+ Processing "src/fasta-generation.tpl.tengo"...
7
+ Processing "src/fasta-to-table.tpl.tengo"...
6
8
  Processing "src/formatText.lib.tengo"...
9
+ Processing "src/json-merging.tpl.tengo"...
7
10
  Processing "src/main.tpl.tengo"...
8
11
  No syntax errors found.
9
12
  info: Compiling 'dist'...
10
13
  info: - writing /home/runner/work/mixcr-library-builder/mixcr-library-builder/workflow/dist/tengo/lib/formatText.lib.tengo
14
+ info: - writing /home/runner/work/mixcr-library-builder/mixcr-library-builder/workflow/dist/tengo/tpl/fasta-generation.plj.gz
15
+ info: - writing /home/runner/work/mixcr-library-builder/mixcr-library-builder/workflow/dist/tengo/tpl/fasta-to-table.plj.gz
16
+ info: - writing /home/runner/work/mixcr-library-builder/mixcr-library-builder/workflow/dist/tengo/tpl/json-merging.plj.gz
11
17
  info: - writing /home/runner/work/mixcr-library-builder/mixcr-library-builder/workflow/dist/tengo/tpl/main.plj.gz
12
18
  info: Template Pack build done.
13
19
  info: Template Pack build done.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,22 @@
1
1
  # @platforma-open/milaboratories.mixcr-library-builder.workflow
2
2
 
3
+ ## 2.0.0
4
+
5
+ ### Major Changes
6
+
7
+ - 5a071f6: Multiple chains reference builder, updated dependecies
8
+
9
+ ### Patch Changes
10
+
11
+ - Updated dependencies [5a071f6]
12
+ - @platforma-open/milaboratories.mixcr-library-builder.software@2.0.0
13
+
14
+ ## 1.4.0
15
+
16
+ ### Minor Changes
17
+
18
+ - fc66573: upport batch system
19
+
3
20
  ## 1.3.1
4
21
 
5
22
  ### Patch Changes
package/dist/index.cjs CHANGED
@@ -1,3 +1,6 @@
1
1
  module.exports = { Templates: {
2
+ 'fasta-generation': { type: 'from-file', path: require.resolve('./tengo/tpl/fasta-generation.plj.gz') },
3
+ 'fasta-to-table': { type: 'from-file', path: require.resolve('./tengo/tpl/fasta-to-table.plj.gz') },
4
+ 'json-merging': { type: 'from-file', path: require.resolve('./tengo/tpl/json-merging.plj.gz') },
2
5
  'main': { type: 'from-file', path: require.resolve('./tengo/tpl/main.plj.gz') }
3
6
  }};
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
1
  declare type TemplateFromFile = { readonly type: "from-file"; readonly path: string; };
2
- declare type TplName = "main";
2
+ declare type TplName = "fasta-generation" | "fasta-to-table" | "json-merging" | "main";
3
3
  declare const Templates: Record<TplName, TemplateFromFile>;
4
4
  export { Templates };
package/dist/index.js CHANGED
@@ -1,4 +1,7 @@
1
1
  import { resolve } from 'node:path';
2
2
  export const Templates = {
3
+ 'fasta-generation': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/fasta-generation.plj.gz') },
4
+ 'fasta-to-table': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/fasta-to-table.plj.gz') },
5
+ 'json-merging': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/json-merging.plj.gz') },
3
6
  'main': { type: 'from-file', path: resolve(import.meta.dirname, './tengo/tpl/main.plj.gz') }
4
7
  };
Binary file
package/package.json CHANGED
@@ -1,14 +1,18 @@
1
1
  {
2
2
  "name": "@platforma-open/milaboratories.mixcr-library-builder.workflow",
3
- "version": "1.3.1",
3
+ "version": "2.0.0",
4
4
  "type": "module",
5
5
  "description": "Block Workflow",
6
6
  "dependencies": {
7
- "@platforma-sdk/workflow-tengo": "^4.7.1"
7
+ "@platforma-sdk/workflow-tengo": "^4.9.3",
8
+ "@platforma-open/milaboratories.software-mixcr": "4.7.0-139-develop",
9
+ "@platforma-open/milaboratories.software-repseqio": "^2.5.0-13-master",
10
+ "@platforma-open/milaboratories.mixcr-library-builder.software": "2.0.0"
8
11
  },
9
12
  "devDependencies": {
10
- "@platforma-sdk/tengo-builder": "^2.1.7",
11
- "@platforma-open/milaboratories.software-mixcr": "4.7.0-139-develop"
13
+ "@platforma-sdk/tengo-builder": "^2.1.12",
14
+ "@platforma-sdk/test": "^1.39.7",
15
+ "vitest": "~2.1.8"
12
16
  },
13
17
  "scripts": {
14
18
  "build": "rm -rf dist && pl-tengo check && pl-tengo build",
@@ -0,0 +1,59 @@
1
+ exec := import("@platforma-sdk/workflow-tengo:exec")
2
+ self := import("@platforma-sdk/workflow-tengo:tpl")
3
+ ll := import("@platforma-sdk/workflow-tengo:ll")
4
+ assets := import("@platforma-sdk/workflow-tengo:assets")
5
+ file := import("@platforma-sdk/workflow-tengo:file")
6
+ text := import("text")
7
+
8
+ repseqioSw := assets.importSoftware("@platforma-open/milaboratories.software-repseqio:main")
9
+
10
+ self.defineOutputs("fasta")
11
+
12
+ self.body(func(inputs) {
13
+ libraryMap := inputs.libraryMap
14
+ config := inputs.config
15
+ coveredRegion := ""
16
+
17
+ fastaMap := {}
18
+
19
+ for name, library in libraryMap {
20
+ for chain, segments in config {
21
+ library_chain_temp := text.split(name, "_")[1]
22
+ library_chain := text.split(library_chain_temp, ".")[0]
23
+ if library_chain == chain {
24
+ for segment, segmentConfig in segments {
25
+ // Skip C segment as it doesn't need FASTA generation
26
+ if segment == "C" {
27
+ continue
28
+ }
29
+
30
+ // Check if this segment has valid configuration
31
+ if !is_undefined(segmentConfig.builtInSpecies) || !is_undefined(segmentConfig.fastaFile) {
32
+ if segment == "V" {
33
+ coveredRegion = segmentConfig.vRegionType
34
+ } else if segment == "J" {
35
+ coveredRegion = "JRegion"
36
+ } else if segment == "D" {
37
+ coveredRegion = "DRegion"
38
+ }
39
+
40
+ // Execute repseqio command only for valid segments
41
+ repseqioCmdBuilder := exec.builder().
42
+ software(repseqioSw).
43
+ arg("fasta").
44
+ arg("-g").arg(coveredRegion).
45
+ arg(name).addFile(name, library).
46
+ arg(segment + "_" + chain + ".fasta").
47
+ saveFile(segment + "_" + chain + ".fasta")
48
+ repseqioCmd := repseqioCmdBuilder.run()
49
+ fasta := repseqioCmd.getFile(segment + "_" + chain + ".fasta")
50
+ fastaMap[segment + "_" + chain + ".fasta"] = fasta
51
+ }
52
+ }
53
+ }
54
+ }
55
+ }
56
+ return {
57
+ fasta: fastaMap
58
+ }
59
+ })
@@ -0,0 +1,95 @@
1
+ exec := import("@platforma-sdk/workflow-tengo:exec")
2
+ self := import("@platforma-sdk/workflow-tengo:tpl")
3
+ assets := import("@platforma-sdk/workflow-tengo:assets")
4
+ pframes := import("@platforma-sdk/workflow-tengo:pframes")
5
+ ll := import("@platforma-sdk/workflow-tengo:ll")
6
+ xsv := import("@platforma-sdk/workflow-tengo:pframes.xsv")
7
+
8
+
9
+
10
+ fastaToTableSw := assets.importSoftware("@platforma-open/milaboratories.mixcr-library-builder.software:fasta_to_table")
11
+
12
+ self.defineOutputs("fastaTable")
13
+
14
+ self.body(func(args) {
15
+ fastaMap := args.fasta
16
+
17
+ cmdBuilder := exec.builder().
18
+ software(fastaToTableSw)
19
+
20
+ // The python script takes an input directory. We add all fasta files to the root of the exec env.
21
+ for name, fastaFile in fastaMap {
22
+ cmdBuilder.addFile(name, fastaFile)
23
+ }
24
+
25
+ // Pass the root directory "." as the input_dir argument.
26
+ cmd := cmdBuilder.arg(".").
27
+ saveFile("combined_table.tsv").
28
+ run()
29
+
30
+ fastaTable := cmd.getFile("combined_table.tsv")
31
+
32
+ // Create column specifications for the fastaTable
33
+ fastaTableSpec := {
34
+ axes: [{
35
+ column: "chain",
36
+ spec: {
37
+ name: "pl7.app/vdj/chain",
38
+ type: "String",
39
+ annotations: {
40
+ "pl7.app/label": "Chain"
41
+ }
42
+ }
43
+ },
44
+ {
45
+ column: "segment",
46
+ spec: {
47
+ name: "pl7.app/vdj/segment",
48
+ type: "String",
49
+ annotations: {
50
+ "pl7.app/label": "Segment"
51
+ }
52
+ }
53
+ },
54
+ {
55
+ column: "gene_name",
56
+ spec: {
57
+ name: "pl7.app/vdj/gene_name",
58
+ type: "String",
59
+ annotations: {
60
+ "pl7.app/label": "Gene Name"
61
+ }
62
+ }
63
+ }],
64
+ columns: [{
65
+ column: "sequence",
66
+ spec: {
67
+ name: "pl7.app/vdj/sequence",
68
+ valueType: "String",
69
+ annotations: {
70
+ "pl7.app/label": "AA Sequence"
71
+ }
72
+ }
73
+ }
74
+ ],
75
+ storageFormat: "Binary",
76
+ partitionKeyLength: 2
77
+ }
78
+
79
+ result := xsv.importFile(
80
+ fastaTable,
81
+ "tsv",
82
+ fastaTableSpec,
83
+ { splitDataAndSpec: true }
84
+ )
85
+
86
+ pf := pframes.pFrameBuilder()
87
+ for id, v in result {
88
+ pf.add(id, v.spec, v.data)
89
+ }
90
+ pf = pf.build()
91
+
92
+ return {
93
+ fastaTable: pframes.exportFrame(pf)
94
+ }
95
+ })
@@ -0,0 +1,32 @@
1
+ exec := import("@platforma-sdk/workflow-tengo:exec")
2
+ self := import("@platforma-sdk/workflow-tengo:tpl")
3
+ ll := import("@platforma-sdk/workflow-tengo:ll")
4
+ assets := import("@platforma-sdk/workflow-tengo:assets")
5
+ file := import("@platforma-sdk/workflow-tengo:file")
6
+
7
+ mergeSw := assets.importSoftware("@platforma-open/milaboratories.mixcr-library-builder.software:main")
8
+
9
+ self.defineOutputs("library")
10
+
11
+ self.body(func(args) {
12
+ libraryMap := args.libraryMap
13
+ //fastaMap := args.fasta
14
+
15
+ mergeCmdBuilder := exec.builder().
16
+ software(mergeSw).
17
+ arg("-o").arg("merged_library.json").
18
+ saveFile("merged_library.json").
19
+ arg("-i")
20
+
21
+ for name, library in libraryMap {
22
+ mergeCmdBuilder.arg(name).
23
+ addFile(name, library)
24
+ }
25
+
26
+ mergeCmd := mergeCmdBuilder.run()
27
+ finalLibrary := mergeCmd.getFile("merged_library.json")
28
+
29
+ return {
30
+ library: finalLibrary
31
+ }
32
+ })
@@ -1,96 +1,159 @@
1
- // "hello world"
2
1
  wf := import("@platforma-sdk/workflow-tengo:workflow")
2
+ render := import("@platforma-sdk/workflow-tengo:render")
3
3
  exec := import("@platforma-sdk/workflow-tengo:exec")
4
4
  ll := import("@platforma-sdk/workflow-tengo:ll")
5
5
  assets := import("@platforma-sdk/workflow-tengo:assets")
6
6
  file := import("@platforma-sdk/workflow-tengo:file")
7
+ maps := import("@platforma-sdk/workflow-tengo:maps")
8
+ smart := import("@platforma-sdk/workflow-tengo:smart")
9
+ pcolumn := import("@platforma-sdk/workflow-tengo:pframes.pcolumn")
10
+ pframes := import("@platforma-sdk/workflow-tengo:pframes")
7
11
  times := import("times")
8
12
  json := import("json")
9
13
  rand := import("rand")
10
14
  text := import("text")
11
15
 
12
16
  mixcrSw := assets.importSoftware("@platforma-open/milaboratories.software-mixcr:main")
13
-
17
+ jsonMergingTpl := assets.importTemplate(":json-merging")
18
+ fastaGenerationTpl := assets.importTemplate(":fasta-generation")
19
+ fatsaToTableTpl := assets.importTemplate(":fasta-to-table")
14
20
  toCamelCase := import(":formatText")
15
21
 
16
- wf.body(func(args) {
22
+ chainInfos := {
23
+ "IGH": "IGHeavy",
24
+ "IGL": "IGLight",
25
+ "IGK": "IGLight",
26
+ "TRB": "TCRBeta",
27
+ "TRA": "TCRAlpha",
28
+ "TRG": "TCRGamma",
29
+ "TRD": "TCRDelta"
30
+ }
17
31
 
32
+ wf.body(func(args) {
18
33
  blockId := wf.blockId().getDataAsJson()
19
-
20
- if is_undefined(args.vFastaFile) && is_undefined(args.vSpecies) {
21
- ll.panic("expected to have either `fastaFile` or `built in`; provided no any")
22
- }
23
-
24
- if is_undefined(args.jFastaFile) && is_undefined(args.jSpecies) {
25
- ll.panic("expected to have either `fastaFile` or `built in`; provided no any")
26
- }
27
-
28
- outputs := {}
29
-
34
+ chainConfigs := args.chainConfigs
30
35
  species := args.species
31
36
  cmdSpecies := toCamelCase.toCamelCase(species) + "_custom"
32
- chain := args.chain
33
-
34
- libraryBuilderCmdBuilder := undefined
35
-
36
37
  taxonId := string(rand.intn(9000) + 1000)
37
- libraryBuilderCmdBuilder = exec.builder().
38
- software(mixcrSw).
39
- secret("MI_LICENSE", "MI_LICENSE").
40
- arg("buildLibrary").
41
- arg("--species").arg(cmdSpecies).
42
- arg("--chain").arg(chain).
43
- arg("--taxon-id").arg(taxonId)
44
- if !is_undefined(args.vFastaFile) {
45
- vImport := file.importFile(args.vFastaFile)
46
- outputs.vImportHandle = vImport.handle
47
- libraryBuilderCmdBuilder.arg("--v-gene-feature").arg("VRegion").
48
- arg("--v-genes-from-fasta").arg("v.fasta").
49
- addFile("v.fasta", vImport.file)
50
- } else {
51
- libraryBuilderCmdBuilder.arg("--v-genes-from-species").arg(args.vSpecies)
38
+ outputs := {}
39
+ fileImports := {}
40
+ libraryMap := {}
41
+ debugOutputMap := {}
42
+ fileImportsProgress := {}
43
+ chains := []
44
+ fivePrimePrimer := args.fivePrimePrimer
45
+
46
+ for chain, chainConfig in chainConfigs {
47
+ libraryBuilderCmdBuilder := exec.builder().
48
+ software(mixcrSw).
49
+ secret("MI_LICENSE", "MI_LICENSE").
50
+ arg("buildLibrary").
51
+ arg("--species").arg(cmdSpecies).
52
+ arg("--chain").arg(chain).
53
+ arg("--taxon-id").arg(taxonId).
54
+ arg("--debug")
55
+
56
+ if chainConfig["V"].sourceType == "built-in" {
57
+ libraryBuilderCmdBuilder.arg("--v-genes-from-species").arg(chainConfig["V"].builtInSpecies)
58
+ } else if chainConfig["V"].sourceType == "fasta" {
59
+ vImport := file.importFile(chainConfig["V"].fastaFile)
60
+ fileImports[chainConfig["V"].fastaFile] = vImport
61
+ fileImportsProgress[chainConfig["V"].fastaFile] = vImport.handle
62
+ libraryBuilderCmdBuilder.arg("--v-gene-feature").arg("VRegion").
63
+ arg("--v-genes-from-fasta").arg("v.fasta").
64
+ addFile("v.fasta", vImport.file)
65
+ }
66
+
67
+ if chainConfig["J"].sourceType == "built-in" {
68
+ libraryBuilderCmdBuilder.arg("--j-genes-from-species").arg(chainConfig["J"].builtInSpecies)
69
+ } else if chainConfig["J"].sourceType == "fasta" {
70
+ jImport := file.importFile(chainConfig["J"].fastaFile)
71
+ fileImports[chainConfig["J"].fastaFile] = jImport
72
+ fileImportsProgress[chainConfig["J"].fastaFile] = jImport.handle
73
+ libraryBuilderCmdBuilder.arg("--j-genes-from-fasta").arg("j.fasta").
74
+ addFile("j.fasta", jImport.file)
75
+ }
76
+
77
+ if chainConfig["D"].builtInSpecies != undefined || chainConfig["D"].fastaFile != undefined {
78
+ if chainConfig["D"].sourceType == "built-in" {
79
+ libraryBuilderCmdBuilder.arg("--d-genes-from-species").arg(chainConfig["D"].builtInSpecies)
80
+ } else if chainConfig["D"].sourceType == "fasta" {
81
+ dImport := file.importFile(chainConfig["D"].fastaFile)
82
+ fileImports[chainConfig["D"].fastaFile] = dImport
83
+ fileImportsProgress[chainConfig["D"].fastaFile] = dImport.handle
84
+ libraryBuilderCmdBuilder.arg("--d-genes-from-fasta").arg("d.fasta").
85
+ addFile("d.fasta", dImport.file)
86
+ }
87
+ }
88
+
89
+ if chainConfig["C"].builtInSpecies != undefined || chainConfig["C"].fastaFile != undefined {
90
+ if chainConfig["C"].sourceType == "built-in" {
91
+ libraryBuilderCmdBuilder.arg("--c-genes-from-species").arg(chainConfig["C"].builtInSpecies)
92
+ } else if chainConfig["C"].sourceType == "fasta" {
93
+ cImport := file.importFile(chainConfig["C"].fastaFile)
94
+ fileImports[chainConfig["C"].fastaFile] = cImport
95
+ fileImportsProgress[chainConfig["C"].fastaFile] = cImport.handle
96
+ libraryBuilderCmdBuilder.arg("--c-genes-from-fasta").arg("c.fasta").
97
+ addFile("c.fasta", cImport.file)
98
+ }
99
+ }
100
+
101
+ libraryBuilderCmdBuilder.arg("library_" + chain + ".json").
102
+ saveFile("library_" + chain + ".json").
103
+ printErrStreamToStdout()
104
+ libraryBuilderCmd := libraryBuilderCmdBuilder.run()
105
+
106
+ debugOutput := libraryBuilderCmd.getStdoutStream()
107
+ library := libraryBuilderCmd.getFile("library_" + chain + ".json")
108
+ libraryMap["library_" + chain + ".json"] = library
109
+ debugOutputMap[chain] = debugOutput
110
+ chains = append(chains, chainInfos[chain])
52
111
  }
53
112
 
54
- if !is_undefined(args.jFastaFile) {
55
- jImport := file.importFile(args.jFastaFile)
56
- outputs.jImportHandle = jImport.handle
57
- libraryBuilderCmdBuilder.arg("--j-genes-from-fasta").arg("j.fasta").
58
- addFile("j.fasta", jImport.file)
59
- } else {
60
- libraryBuilderCmdBuilder.arg("--j-genes-from-species").arg(args.jSpecies)
113
+ seen := {}
114
+ chains_unique := []
115
+ for chain in chains {
116
+ if !seen[chain] {
117
+ seen[chain] = true
118
+ chains_unique = append(chains_unique, chain)
119
+ }
61
120
  }
62
121
 
63
- if !is_undefined(args.dFastaFile) {
64
- dImport := file.importFile(args.dFastaFile)
65
- outputs.dImportHandle = dImport.handle
66
- libraryBuilderCmdBuilder.arg("--d-genes-from-fasta").arg("d.fasta").
67
- addFile("d.fasta", dImport.file)
68
- } else if !is_undefined(args.dSpecies) {
69
- libraryBuilderCmdBuilder.arg("--d-genes-from-species").arg(args.dSpecies)
122
+ // Create logs map using pcolumn.resourceMapBuilder
123
+ debugOutputMapBuilder := pcolumn.resourceMapBuilder(/* keyLength */ 1)
124
+ for chain, debugOutput in debugOutputMap {
125
+ debugOutputMapBuilder.add([chain], debugOutput)
70
126
  }
71
127
 
72
- if !is_undefined(args.cFastaFile) {
73
- cImport := file.importFile(args.cFastaFile)
74
- outputs.cImportHandle = cImport.handle
75
- libraryBuilderCmdBuilder.arg("--c-genes-from-fasta").arg("c.fasta").
76
- addFile("c.fasta", cImport.file)
77
- } else if !is_undefined(args.cSpecies) {
78
- libraryBuilderCmdBuilder.arg("--c-genes-from-species").arg(args.cSpecies)
79
- }
128
+ outputs.debugOutput = debugOutputMapBuilder.build()
129
+
130
+ outputs.fileImports = smart.createMapResource(maps.mapValues(fileImportsProgress, func(handle) {
131
+ return handle
132
+ }))
133
+
134
+ fastaGeneration := render.create(fastaGenerationTpl, {
135
+ libraryMap: libraryMap,
136
+ config: chainConfigs
137
+ })
138
+ fasta := fastaGeneration.output("fasta", 24 * 60 * 60 * 1000)
80
139
 
81
- libraryBuilderCmdBuilder.arg("library.json").
82
- saveFile("library.json").
83
- printErrStreamToStdout()
84
- libraryBuilderCmd := libraryBuilderCmdBuilder.run()
140
+ fastaToTable := render.create(fatsaToTableTpl, {
141
+ fasta: fasta
142
+ })
143
+ fastaTable := fastaToTable.output("fastaTable", 24 * 60 * 60 * 1000)
85
144
 
86
- debugOutput := libraryBuilderCmd.getStdoutStream()
87
- library := libraryBuilderCmd.getFile("library.json")
145
+ mergeResults := render.create(jsonMergingTpl, {
146
+ libraryMap: libraryMap,
147
+ fastaTable: fastaTable
148
+ })
88
149
 
89
- outputs.debugOutput = debugOutput
150
+ finalLibrary := mergeResults.output("library", 24 * 60 * 60 * 1000)
151
+
152
+ outputs.fastaTable = fastaTable
90
153
 
91
154
  exports := {
92
- library : {
93
- data: library,
155
+ library: {
156
+ data: finalLibrary,
94
157
  spec: {
95
158
  kind: "File",
96
159
  name: "pl7.app/vdj/library",
@@ -99,15 +162,15 @@ wf.body(func(args) {
99
162
  },
100
163
  annotations: {
101
164
  "pl7.app/species": cmdSpecies,
102
- "pl7.app/vdj/chain": chain,
165
+ "pl7.app/vdj/chain": string(chains),
103
166
  "pl7.app/vdj/isLibrary": "true",
104
167
  "pl7.app/vdj/libraryFormat": "repseqio.json",
105
- "pl7.app/label": text.split(species, "_custom")[0] + " " + chain + " library"
168
+ "pl7.app/label": text.split(species, "_custom")[0] + " library"
106
169
  }
107
170
  }
108
- }
171
+ }
109
172
  }
110
-
173
+
111
174
  return {
112
175
  outputs: outputs,
113
176
  exports: exports