Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Mapping suggestion #757

Open
wants to merge 82 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
82 commits
Select commit Hold shift + click to select a range
ee8d1ed
Added endpoint to Vocabulary
robertisele Dec 13, 2023
6d65301
Added endpoint for benchmarking schema matchers.
robertisele Jan 18, 2024
efbeb1e
Merge remote-tracking branch 'origin/develop' into feature/matchingEx…
robertisele Jan 19, 2024
8adb8c4
Merge branch 'develop' into feature/newMappingSuggestion-CMEM-5433
andreas-schultz Feb 7, 2024
b530118
Add mapping suggestion stub
andreas-schultz Feb 7, 2024
9caca51
Forward ref for CardContent
andreas-schultz Feb 8, 2024
6787a4f
Merge branch 'release/24.1.0' into feature/newMappingSuggestion-CMEM-…
andreas-schultz Feb 13, 2024
0bcacde
Upgrade carbon types dependencies
andreas-schultz Feb 13, 2024
89418aa
Update gui-elements dependency to 23.4.2-rc.1
andreas-schultz Feb 13, 2024
3a766fe
Write custom test helper for RenderResult objects
andreas-schultz Feb 19, 2024
69a45c1
Add some more convenience methods for testing
andreas-schultz Feb 23, 2024
f79d9e9
Add restore action to i18n file
andreas-schultz Feb 23, 2024
fc98504
Added withOperators method to Path classes.
robertisele Feb 28, 2024
21a3b44
Merge branch 'feature/newMappingSuggestion-CMEM-5433' of github.com:s…
robertisele Feb 28, 2024
d6042c1
Extend helper methods for Enzyme render result
andreas-schultz Mar 1, 2024
b88d0dd
Add project and transform task ID to global mapping editor context
andreas-schultz Mar 11, 2024
aeab728
Add onClose to external mapping suggestion component API
andreas-schultz Mar 12, 2024
9c89b05
Merge remote-tracking branch 'origin/develop' into feature/newMapping…
haschek Mar 20, 2024
8cdcf2b
forward gui elements
haschek Mar 21, 2024
e032539
fix imports
haschek Mar 21, 2024
1d0cdd8
Change click test helper function to emit a click event when click fu…
andreas-schultz Mar 21, 2024
851f4de
Merge branch 'feature/newMappingSuggestion-CMEM-5433' of https://gith…
andreas-schultz Mar 21, 2024
5d0f800
forward gui elements, include necessary change for BreadcrumbsList
haschek Mar 26, 2024
48e3e56
add Mapping editor hierarchy to the page breadcrumbs
haschek Mar 26, 2024
dee09fb
do not use the bradcrumb header in the hierarchical mapping editor
haschek Mar 26, 2024
841c7b0
improve visibility of active mapping parent (CMEM-3697)
haschek Mar 26, 2024
b0d1292
forward gui elements, borderless cards now work
haschek Mar 26, 2024
3173c48
forward gui elements, include fix for card display
haschek Mar 27, 2024
f61c213
use mapping creator component as tab view
haschek Mar 27, 2024
d9d3873
enable display order of task view plugins
haschek Mar 27, 2024
6ca7b90
Type retrieveTransformTargetProperties
andreas-schultz Mar 28, 2024
f0b749c
Merge branch 'feature/newMappingSuggestion-CMEM-5433' of https://gith…
andreas-schultz Mar 28, 2024
c3ef322
Add project task tab view context containing the full-screen flag
andreas-schultz Mar 28, 2024
7b31f1e
Support optional label render function in autoCompleteItemRendererFac…
andreas-schultz Mar 28, 2024
1c5323a
forward gui elements, include new flexible layout components
haschek Apr 2, 2024
22a4c2e
forward gui elements, include develop changes
haschek Apr 8, 2024
ba192e7
Add target class auto-completion function to Silk REST API
andreas-schultz Apr 8, 2024
2246c04
forward gui elements
haschek Apr 9, 2024
3e41e23
Add propertiesByClass to Silk REST API
andreas-schultz Apr 9, 2024
c657ff8
Merge branch 'feature/newMappingSuggestion-CMEM-5433' of https://gith…
andreas-schultz Apr 9, 2024
aa90bf7
Resolve class URI in properties/relations by class endpoints
andreas-schultz Apr 9, 2024
f21417d
forward gui element, include color changes
haschek Apr 11, 2024
1e89793
IdentifierGenerator: Fix issue that already unique identifiers have b…
robertisele Apr 23, 2024
d8bd0af
DirectMapping: Should maintain the identifier of the input path.
robertisele Apr 23, 2024
af40e08
Set new DirectMapping.inputId property in tests
robertisele Apr 23, 2024
6eb3035
Add test IDs for mapping rule actions
andreas-schultz Apr 26, 2024
3e0fbe5
Delay re-rendering of example view on blur from value path input
andreas-schultz Apr 26, 2024
db53a28
Make targetTypes endpoint multi word search capable
andreas-schultz May 6, 2024
5940311
Return range info in target properties auto-completion endpoints
andreas-schultz May 7, 2024
a4ebb99
Extend partial source path auto-completion endpoint
andreas-schultz May 15, 2024
9262138
Add endpoint to fetch properties of a source (RDF) type
andreas-schultz May 16, 2024
7462a9d
Sort rule operator parameters like they are ordererd in the plugin sp…
andreas-schultz May 21, 2024
72391f9
Make advanced section in rule editor boxed more compact
andreas-schultz May 21, 2024
511ef18
Create normal request function for project prefixes
andreas-schultz May 24, 2024
4db8b83
Add helper methods to get RDF info for the output task of a transform…
andreas-schultz May 24, 2024
31bde19
Add convenienve method to fetch dataset characteristics for the outpu…
andreas-schultz May 28, 2024
df4372f
Support returning properties with owl:Thing as domain or without doma…
andreas-schultz May 28, 2024
a8278d8
Allow to embed source path infobox directly instead of using a contex…
andreas-schultz May 31, 2024
47581dc
Support supplying example data directly in SourcePathInfoBox
andreas-schultz May 31, 2024
654081c
Add 'revert' to i18n dictionary
andreas-schultz Jun 3, 2024
339e5d3
Merge branch 'develop' into feature/newMappingSuggestion-CMEM-5433
andreas-schultz Aug 27, 2024
501fe85
Merged develop into feature/newMappingSuggestion-CMEM-5433
robertisele Aug 27, 2024
0d71fda
VocabularyManager: Log which plugin is actually used.
robertisele Aug 28, 2024
738a22e
Merge remote-tracking branch 'origin/develop' into feature/newMapping…
robertisele Sep 25, 2024
5c987a7
Fix merge issues
robertisele Sep 25, 2024
0ac12c1
Forward gui-elements
robertisele Sep 25, 2024
f7bc68f
Merge remote-tracking branch 'origin/develop' into feature/newMapping…
haschek Oct 2, 2024
f0b074c
fix gui elements version
haschek Oct 2, 2024
560f808
forward gui elements, include updates from next branch
haschek Oct 7, 2024
745ff1c
use sizes from global config vars
haschek Oct 9, 2024
83c0789
Merge branch 'release/24.3.0' into feature/newMappingSuggestion-CMEM-…
andreas-schultz Dec 5, 2024
4b2a5bf
Fix issues caused by breaking changes
andreas-schultz Dec 30, 2024
9ac98de
Identifier generator should use a default ID if the desired input ID …
andreas-schultz Dec 30, 2024
0372a08
Merge branch 'develop' into feature/newMappingSuggestion-CMEM-5433
robertisele Jan 3, 2025
535f2b3
Merge develop into gui-elements branch
andreas-schultz Jan 9, 2025
a61a316
Extend configuration to allow for other endpoints and models.
robertisele Jan 9, 2025
bee8143
Add 'Magic wand' as icon name
andreas-schultz Jan 10, 2025
35ccfa2
Merge branch 'feature/newMappingSuggestion-CMEM-5433' of https://gith…
andreas-schultz Jan 10, 2025
7466cbc
Refactored JSON serialization for GenericInfo and HierarchicalSchema.…
robertisele Jan 13, 2025
83aa889
Update swagger libraries
robertisele Jan 13, 2025
3d24d60
Fixed incorrect parsing of prefixed names
robertisele Jan 13, 2025
b2633b4
Upgrade sbt and play to latest bugfix versions
robertisele Jan 14, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 6 additions & 6 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ lazy val core = (project in file("silk-core"))
.settings(commonSettings: _*)
.settings(
name := "Silk Core",
libraryDependencies += "com.typesafe" % "config" % "1.4.2", // Should always use the same version as the Play Framework dependency
libraryDependencies += "com.typesafe" % "config" % "1.4.3", // Should always use the same version as the Play Framework dependency
// Additional scala standard libraries
libraryDependencies += "org.scala-lang.modules" %% "scala-xml" % "2.2.0",
libraryDependencies += "org.scala-lang" % "scala-reflect" % scalaVersion.value,
Expand Down Expand Up @@ -207,7 +207,7 @@ lazy val serializationJson = (project in file("silk-plugins/silk-serialization-j
.settings(
name := "Silk Serialization JSON",
libraryDependencies += "com.typesafe.play" %% "play-json" % "2.10.6",
libraryDependencies += "io.swagger.core.v3" % "swagger-annotations" % "2.2.23"
libraryDependencies += "io.swagger.core.v3" % "swagger-annotations" % "2.2.27"
)

lazy val persistentCaching = (project in file("silk-plugins/silk-persistent-caching"))
Expand Down Expand Up @@ -396,9 +396,9 @@ lazy val workbenchOpenApi = (project in file("silk-workbench/silk-workbench-open
.settings(
name := "Silk Workbench OpenAPI",
libraryDependencies += "io.kinoplan" %% "swagger-play" % "0.0.5" exclude("org.scala-lang.modules", "scala-java8-compat_2.13") ,
libraryDependencies += "io.swagger.parser.v3" % "swagger-parser-v3" % "2.1.22",
libraryDependencies += "com.networknt" % "json-schema-validator" % "1.0.78",
libraryDependencies += "org.webjars" % "swagger-ui" % "5.17.14"
libraryDependencies += "io.swagger.parser.v3" % "swagger-parser-v3" % "2.1.24",
libraryDependencies += "com.networknt" % "json-schema-validator" % "1.5.4",
libraryDependencies += "org.webjars" % "swagger-ui" % "5.18.2"
)

lazy val workbench = (project in file("silk-workbench"))
Expand Down Expand Up @@ -427,7 +427,7 @@ lazy val singlemachine = (project in file("silk-tools/silk-singlemachine"))
.settings(commonSettings: _*)
.settings(
name := "Silk SingleMachine",
libraryDependencies += "org.slf4j" % "slf4j-jdk14" % "2.0.5"
libraryDependencies += "org.slf4j" % "slf4j-jdk14" % "2.0.16"
)

//lazy val mapreduce = (project in file("silk-tools/silk-mapreduce"))
Expand Down
2 changes: 1 addition & 1 deletion project/build.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
sbt.version=1.10.5
sbt.version=1.10.7
2 changes: 1 addition & 1 deletion project/plugins.sbt
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// The Play plugin
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.9.5")
addSbtPlugin("com.typesafe.play" % "sbt-plugin" % "2.9.6")

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "2.1.5")

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,13 +48,13 @@ abstract class ConfigValue[T]() {
* @tparam CLASS The class that holds the configuration.
* @tparam T The configuration value type.
*/
abstract class ClassConfigValue[CLASS: ClassTag, T]() extends ConfigValue[T] {
abstract class ClassConfigValue[T: ClassTag]() extends ConfigValue[T] {

/**
* Retrieves the configuration for the given class.
*/
protected override def config: TypesafeConfig = {
DefaultConfig.instance.forClass(implicitly[ClassTag[CLASS]].runtimeClass)
DefaultConfig.instance.forClass(implicitly[ClassTag[T]].runtimeClass)
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ trait Path extends Serializable {
*/
def operators: List[PathOperator]

/**
* Returns a copy with updated operators.
*/
def withOperators(newOperators: List[PathOperator]): Path

/**
* The normalized serialization using the Silk RDF path language.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,10 @@ class PathWithMetadata (
*/
def getOriginalName: String = metadata(PathWithMetadata.META_FIELD_ORIGIN_NAME).toString

override def withOperators(newOperators: List[PathOperator]): PathWithMetadata = {
new PathWithMetadata(newOperators, valueType, metadata)
}

}

object PathWithMetadata{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,10 @@ case class TypedPath(
}

override def toString: String = s"$normalizedSerialization (${valueType.label})"

override def withOperators(newOperators: List[PathOperator]): TypedPath = {
copy(operators = newOperators)
}
}

object TypedPath {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@ class UntypedPath private[entity](val operators: List[PathOperator]) extends Pat

/** Returns an untyped ([[org.silkframework.entity.UntypedValueType]]) [[TypedPath]]. */
def asUntypedValueType: TypedPath = TypedPath(this.operators, ValueType.UNTYPED, isAttribute = false)

override def withOperators(newOperators: List[PathOperator]): UntypedPath = {
new UntypedPath(operators = newOperators)
}
}

object UntypedPath {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,8 @@ object Identifier {
(c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9') || (c == '_') || (c == '-')
}

def filterAllowedChars(str: String): String = str.filter(Identifier.isAllowed)

/**
* Creates a new Identifier only from the allowed characters in a given string.
*
Expand All @@ -71,7 +73,7 @@ object Identifier {
*/
def fromAllowed(str: String, alternative: Option[String] = None): Identifier = {
try {
new Identifier(str.filter(Identifier.isAllowed))
new Identifier(filterAllowedChars(str))
} catch {
case _: IllegalArgumentException if alternative.isDefined =>
Identifier(alternative.get)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,40 +2,49 @@ package org.silkframework.util

/**
* Generates identifiers that are unique in its scope.
* Thread-safe.
*/
class IdentifierGenerator(prefix: String = "") {
class IdentifierGenerator {

/**
* Remembers all existing identifiers and their counts.
*/
private var identifiers = Map[String, Int]()
* Remembers all existing identifiers.
*/
private var identifiers = Set[Identifier]()
// Default identifier if the desired ID contains no allowed characters.
final val UNNAMED_ID = "unnamed_id"

/**
* Generates a new unique identifier.
*
* @param desiredId The desired identifier. Invalid characters will be removed, so it's not required that this is a valid identifier.
* @return If the provided identifier is already unique, it will be returned unchanged. Otherwise, a unique identifier is generated by appending a number.
*/
def generate(identifier: String): Identifier = synchronized {
val (name, num) = split(Identifier.fromAllowed(prefix + identifier))
identifiers.get(name) match {
case Some(count) =>
identifiers += ((name, count + 1))
name + count.toString
case None =>
identifiers += ((name, 1))
name
def generate(desiredId: String): Identifier = synchronized {
val desiredIdOnlyAllowedChars = Identifier.filterAllowedChars(desiredId)
val identifier = Identifier(if(desiredIdOnlyAllowedChars.isEmpty) UNNAMED_ID else desiredIdOnlyAllowedChars)
if(!identifiers.contains(identifier)) {
// Identifier is already unique
identifiers += identifier
identifier
} else {
// Generate a new identifier by adding a unique number
val (name, num) = split(identifier)
for(i <- Iterator.from(num + 1)) {
val newIdentifier = name + i
if(!identifiers.contains(newIdentifier)) {
identifiers += newIdentifier
return newIdentifier
}
}
throw new IllegalStateException()
}
}

/**
* Adds an existing identifier without changing it.
*/
def add(identifier: Identifier): Unit = synchronized {
val (name, num) = split(identifier)
identifiers.get(name.toString) match {
case Some(count) =>
identifiers += ((name, math.max(count, num + 1)))
case None =>
identifiers += ((name, num + 1))
}
identifiers += identifier
}

/**
Expand All @@ -51,3 +60,14 @@ class IdentifierGenerator(prefix: String = "") {
}

}

/**
* Adds a prefix to all generated identifiers.
*/
class PrefixedIdentifierGenerator(prefix: String) extends IdentifierGenerator {

override def generate(desiredId: String): Identifier = {
super.generate(prefix + desiredId)
}

}
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package org.silkframework.workspace

import org.silkframework.config._
import org.silkframework.dataset.rdf.SparqlEndpoint
import org.silkframework.dataset.rdf.{GraphStoreTrait, SparqlEndpoint}
import org.silkframework.runtime.activity.UserContext
import org.silkframework.runtime.plugin.annotations.PluginType
import org.silkframework.runtime.plugin.{AnyPlugin, ParameterValues, PluginContext}
Expand All @@ -16,7 +16,7 @@ import scala.collection.mutable
import scala.language.implicitConversions
import scala.reflect.ClassTag
import scala.util.control.NonFatal
import scala.xml.{Attribute, Elem, Node, Text, Null}
import scala.xml.{Attribute, Elem, Node, Null, Text}

@PluginType()
trait WorkspaceProvider extends AnyPlugin {
Expand Down Expand Up @@ -146,7 +146,7 @@ trait WorkspaceProvider extends AnyPlugin {
* Returns an SPARQL endpoint that allows query access to the projects.
* May return None if the projects are not held as RDF.
*/
def sparqlEndpoint: Option[SparqlEndpoint]
def sparqlEndpoint: Option[SparqlEndpoint with GraphStoreTrait]

private val externalLoadingErrors: mutable.HashMap[String, Vector[TaskLoadingError]] = new mutable.HashMap[String, Vector[TaskLoadingError]]()

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ class IdentifierGeneratorTest extends AnyFlatSpec with Matchers {
generator.generate("person") mustBe Identifier("person2")
generator.generate("person1") mustBe Identifier("person3")
}

it should "not remove trailing numbers if not needed for generating a unique id" in {
val generator = new IdentifierGenerator()
generator.generate("name1") mustBe Identifier("name1")
}
}
2 changes: 1 addition & 1 deletion silk-legacy-ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@
"@testing-library/jest-dom": "^5.11.6",
"@testing-library/react": "^11.1.2",
"@testing-library/user-event": "^12.2.2",
"@types/carbon-components-react": "7.44.1",
"@types/carbon-components-react": "7.55.2",
"@types/codemirror": "0.0.109",
"@types/enzyme": "^3.10.8",
"@types/enzyme-adapter-react-16": "^1.0.6",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package org.silkframework.plugins.dataset.rdf.vocab

import java.util.logging.Logger

import org.apache.jena.query.DatasetFactory
import org.apache.jena.rdf.model.ModelFactory
import org.apache.jena.riot.{RDFDataMgr, RDFLanguages}
import org.silkframework.plugins.dataset.rdf.endpoint.JenaDatasetEndpoint
import org.silkframework.rule.vocab.{Vocabulary, VocabularyManager}
import org.silkframework.runtime.activity.UserContext
import org.silkframework.runtime.plugin.annotations.Plugin
import org.silkframework.runtime.resource.{FileResource, ResourceNotFoundException}
import org.silkframework.runtime.resource.{Resource, ResourceNotFoundException}
import org.silkframework.util.Identifier
import org.silkframework.workspace.WorkspaceFactory

import java.util.logging.Logger

@Plugin(
id = "rdfFiles",
label = "RDF Files",
Expand All @@ -31,20 +31,7 @@ case class RdfFilesVocabularyManager() extends VocabularyManager {
if(vocabularyResource.nonEmpty && vocabularyResource.get.size.nonEmpty &&
!vocabularyResource.get.size.contains(0L)) { // only consider files
val resource = vocabularyResource.get
// Load into Jena model
val model = ModelFactory.createDefaultModel()
val inputStream = resource.inputStream
RDFDataMgr.read(model, inputStream, RDFLanguages.filenameToLang(resource.name))
inputStream.close()

// Create vocabulary loader
val dataset = DatasetFactory.createTxnMem()
dataset.addNamedModel(prefix + uri, model)
val endpoint = new JenaDatasetEndpoint(dataset)
val loader = new VocabularyLoader(endpoint)

// Load vocabulary
loader.retrieveVocabulary(prefix + uri)
loadVocabulary(resource, uri)
} else {
None
}
Expand All @@ -55,6 +42,27 @@ case class RdfFilesVocabularyManager() extends VocabularyManager {
}
}

/**
* Loads a vocabulary from a file.
*/
def loadVocabulary(resource: Resource, uri: String)
(implicit userContext: UserContext): Option[Vocabulary] = {
// Load into Jena model
val model = ModelFactory.createDefaultModel()
val inputStream = resource.inputStream
RDFDataMgr.read(model, inputStream, RDFLanguages.filenameToLang(resource.name))
inputStream.close()

// Create vocabulary loader
val dataset = DatasetFactory.createTxnMem()
dataset.addNamedModel(prefix + uri, model)
val endpoint = new JenaDatasetEndpoint(dataset)
val loader = new VocabularyLoader(endpoint)

// Load vocabulary
loader.retrieveVocabulary(prefix + uri)
}

override def retrieveGlobalVocabularies()(implicit userContext: UserContext): Option[Iterable[String]] = {
// FIXME: Not clear how to automatically decide which RDF files are global vocabularies without registering them.
None
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.silkframework.plugins.dataset.rdf.vocab

import org.silkframework.dataset.rdf.SparqlEndpoint
import org.silkframework.dataset.rdf.{GraphStoreTrait, SparqlEndpoint}
import org.silkframework.rule.vocab.{Vocabulary, VocabularyManager}
import org.silkframework.runtime.activity.UserContext
import org.silkframework.runtime.plugin.annotations.Plugin
Expand All @@ -20,7 +20,7 @@ case class RdfVocabularyManager() extends VocabularyManager {
loader.retrieveVocabulary(uri)
}

private def workspaceSparqlEndpoint(implicit userContext: UserContext): SparqlEndpoint = {
private def workspaceSparqlEndpoint(implicit userContext: UserContext): SparqlEndpoint with GraphStoreTrait = {
WorkspaceFactory().workspace.provider.sparqlEndpoint match {
case Some(endpoint) =>
endpoint
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import org.silkframework.runtime.activity.UserContext
import scala.collection.immutable.SortedMap
import scala.collection.mutable

class VocabularyLoader(endpoint: SparqlEndpoint) {
class VocabularyLoader(endpoint: SparqlEndpoint with GraphStoreTrait) {
final val languageRanking: IndexedSeq[String] = IndexedSeq("en", "de", "es", "fr", "it", "pt")

def retrieveVocabulary(uri: String)(implicit userContext: UserContext): Option[Vocabulary] = {
Expand All @@ -17,7 +17,8 @@ class VocabularyLoader(endpoint: SparqlEndpoint) {
Some(Vocabulary(
info = vocabGenericInfo,
classes = classes.toSeq,
properties = retrieveProperties(uri, classes.toSeq)
properties = retrieveProperties(uri, classes.toSeq),
endpoint = Some(endpoint)
))
}

Expand Down
Loading