import hashlib
import asyncio

from . import message
from . import error
from . import interfaces
from . import numbers

def hashing_etag(request, response):
    """Helper function for render_get handlers that allows them to use ETags based
    on the payload's hash value

    Run this on your request and response before returning from render_get; it is
    safe to use this function with all kinds of responses, it will only act on
    2.05 Content. The hash used are the first 8 bytes of the sha1 sum of the
    payload.

    Note that this method is not ideal from a server performance point of view
    (a file server, for example, might want to hash only the stat() result of a
    file instead of reading it in full), but it saves bandwith for the simple
    cases.

    >>> from aiocoap import *
    >>> req = Message(code=GET)
    >>> hash_of_hello = b'\\xaa\\xf4\\xc6\\x1d\\xdc\\xc5\\xe8\\xa2'
    >>> req.opt.etags = [hash_of_hello]
    >>> resp = Message(code=CONTENT)
    >>> resp.payload = b'hello'
    >>> hashing_etag(req, resp)
    >>> resp                                            # doctest: +ELLIPSIS
    <aiocoap.Message at ... 2.03 Valid ... 1 option(s)>
    """

    if response.code != numbers.codes.CONTENT:
        return

    response.opt.etag = hashlib.sha1(response.payload).digest()[:8]
    if request.opt.etags is not None and response.opt.etag in request.opt.etags:
        response.code = numbers.codes.VALID
        response.payload = b''

class _ExposesWellknownAttributes:
    def get_link_description(self):
        ## FIXME which formats are acceptable, and how much escaping and
        # list-to-separated-string conversion needs to happen here
        ret = {}
        if hasattr(self, 'ct'):
            ret['ct'] = str(self.ct)
        if hasattr(self, 'rt'):
            ret['rt'] = self.rt
        if hasattr(self, 'if_'):
            ret['if'] = self.if_
        return ret

class Resource(_ExposesWellknownAttributes, interfaces.Resource):
    """Simple base implementation of the :class:`interfaces.Resource`
    interface

    The render method delegates content creation to ``render_$method`` methods,
    and responds appropriately to unsupported methods.

    Moreover, this class provides a ``get_link_description`` method as used by
    .well-known/core to expose a resource's ``.ct``, ``.rt`` and ``.if_``
    (alternative name for ``if`` as that's a Python keyword) attributes.
    """

    @asyncio.coroutine
    def needs_blockwise_assembly(self, request):
        return True

    @asyncio.coroutine
    def render(self, request):
        if not request.code.is_request():
            raise error.UnsupportedMethod()
        m = getattr(self, 'render_%s' % str(request.code).lower(), None)
        if not m:
            raise error.UnallowedMethod()
        return m(request)

class ObservableResource(Resource, interfaces.ObservableResource):
    def __init__(self):
        super(ObservableResource, self).__init__()
        self._observations = set()

    @asyncio.coroutine
    def add_observation(self, request, serverobservation):
        self._observations.add(serverobservation)
        def _cancel(self=self, obs=serverobservation):
            self._observations.remove(serverobservation)
            self.update_observation_count(len(self._observations))
        serverobservation.accept(_cancel)
        self.update_observation_count(len(self._observations))

    def update_observation_count(self, newcount):
        """Hook into this method to be notified when the number of observations
        on the resource changes."""

    def updated_state(self, response=None):
        """Call this whenever the resource was updated, and a notification
        should be sent to observers."""

        for o in self._observations:
            o.trigger(response)

    def get_link_description(self):
        link = super(ObservableResource, self).get_link_description()
        link['obs'] = None
        return link

class WKCResource(Resource):
    """Read-only dynamic resource list, suitable as .well-known/core.

    This resource renders a link_header.LinkHeader object (which describes a
    collection of resources) as application/link-format (RFC 6690).

    The list to be rendered is obtained from a function passed into the
    constructor; typically, that function would be a bound
    Site.get_resources_as_linkheader() method."""

    ct = 40

    def __init__(self, listgenerator):
        self.listgenerator = listgenerator

    def render_get(self, request):
        links = self.listgenerator()

        filters = []
        for q in request.opt.uri_query:
            try:
                k, v = q.split('=', 1)
            except ValueError:
                continue # no =, not a relevant filter

            if v.endswith('*'):
                matchexp = lambda x: x.startswith(v[:-1])
            else:
                matchexp = lambda x: x == v

            if k in ('rt', 'if'):
                filters.append(lambda link: any(matchexp(part) for part in (" ".join(getattr(link, k))).split(" ")))
            elif k in ('href',): # x.href is single valued
                filters.append(lambda link: matchexp(getattr(link, k)))
            else:
                filters.append(lambda link: any(matchexp(part) for part in getattr(link, k)))

        while filters:
            links.links = filter(filters.pop(), links.links)
        links.links = list(links.links)

        if not links.links and request.remote.is_multicast():
            return message.NoResponse

        serialized = str(links)

        response = message.Message(code=numbers.codes.CONTENT, payload=serialized.encode('utf8'))
        response.opt.content_format = self.ct
        return response

class PathCapable:
    """Class that indicates that a resource promises to parse the uri_path
    option, and can thus be given requests for :meth:`.render`\ ing that
    contain a uri_path"""

class Site(interfaces.ObservableResource, PathCapable):
    """Typical root element that gets passed to a :class:`Context` and contains
    all the resources that can be found when the endpoint gets accessed as a
    server.

    This provides easy registration of statical resources. Add resources at
    absolute locations using the :meth:`.add_resource` method.

    For example, the site at

    >>> site = Site()
    >>> site.add_resource(["hello"], Resource())

    will have requests to </hello> rendered by the new resource.

    You can add another Site (or another instance of :class:`PathCapable`) as
    well, those will be nested and integrally reported in a WKCResource. The
    path of a site should not end with an empty string (ie. a slash in the URI)
    -- the child site's own root resource will then have the trailing slash
    address.  Subsites can not have link-header attributes on their own (eg.
    `rt`) and will never respond to a request that does not at least contain a
    single slash after the the given path part.

    For example,

    >>> batch = Site()
    >>> batch.add_resource(["light1"], Resource())
    >>> batch.add_resource(["light2"], Resource())
    >>> batch.add_resource([], Resource())
    >>> s = Site()
    >>> s.add_resource("batch", batch)

    will have the three created resources rendered at </batch/light1>,
    </batch/light2> and </batch/>.

    If it is necessary to respond to requests to </batch> or report its
    attributes in .well-known/core in addition to the above, a non-PathCapable
    resource can be added with the same path. This is usually considered an odd
    design, not fully supported, and for example doesn't support removal of
    resources from the site.
    """

    def __init__(self):
        self._resources = {}
        self._subsites = {}

    @asyncio.coroutine
    def needs_blockwise_assembly(self, request):
        try:
            child, subrequest = self._find_child_and_pathstripped_message(request)
        except KeyError:
            return True
        else:
            return child.needs_blockwise_assembly(subrequest)

    def _find_child_and_pathstripped_message(self, request):
        """Given a request, find the child that will handle it, and strip all
        path components from the request that are covered by the child's
        position within the site. Returns the child and a request with a path
        shortened by the components in the child's path, or raises a
        KeyError."""

        if request.opt.uri_path in self._resources:
            return self._resources[request.opt.uri_path], request.copy(uri_path=())

        if not request.opt.uri_path:
            raise KeyError()

        remainder = [request.opt.uri_path[-1]]
        path = request.opt.uri_path[:-1]
        while path:
            if path in self._subsites:
                res = self._subsites[path]
                if remainder == [""]:
                    # sub-sites should see their root resource like sites
                    remainder = []
                return res, request.copy(uri_path=remainder)
            remainder.insert(0, path[-1])
            path = path[:-1]
        raise KeyError()

    @asyncio.coroutine
    def render(self, request):
        try:
            child, subrequest = self._find_child_and_pathstripped_message(request)
        except KeyError:
            raise error.NotFound()
        else:
            return child.render(subrequest)

    @asyncio.coroutine
    def add_observation(self, request, serverobservation):
        try:
            child, subrequest = self._find_child_and_pathstripped_message(request)
        except KeyError:
            return

        try:
            yield from child.add_observation(subrequest, serverobservation)
        except AttributeError:
            pass

    def add_resource(self, path, resource):
        if isinstance(resource, PathCapable):
            self._subsites[tuple(path)] = resource
        else:
            self._resources[tuple(path)] = resource

    def remove_resource(self, path):
        try:
            del self._subsites[tuple(path)]
        except KeyError:
            del self._resources[tuple(path)]

    def get_resources_as_linkheader(self):
        import link_header

        links = []

        for path, resource in self._resources.items():
            if hasattr(resource, "get_link_description"):
                details = resource.get_link_description()
            else:
                details = {}
            lh = link_header.Link('/' + '/'.join(path), **details)

            links.append(lh)

        for path, resource in self._subsites.items():
            if hasattr(resource, "get_resources_as_linkheader"):
                for l in resource.get_resources_as_linkheader().links:
                    links.append(link_header.Link('/' + '/'.join(path) + l.href, l.attr_pairs))
        return link_header.LinkHeader(links)


N, K = map(int, input().split())
A = list(map(int, input().split()))
A = sorted(A)
mod = 10**9+7

# conbModに使うfactとfactinvを求める
def factorialMod(n, p):
    fact = [1, 1]
    factinv = [1, 1]
    inv = [0, 1]
    for i in range(2, n + 1):
        fact.append((fact[-1] * i) % p)
        inv.append((-inv[p % i] * (p // i)) % p)
        factinv.append((factinv[-1] * inv[-1]) % p)
    return fact, factinv

# 二項係数を素数で割った余り
def combMod(n, r, fact, factinv, p):
    if (r < 0) or (n < r):
        return 0
    r = min(r, n - r)
    return fact[n] * factinv[r] * factinv[n-r] % p

ans = 0
fact, factinv = factorialMod(N, mod)
for i in range(N):
    num = combMod(i, K-1, fact, factinv, mod) % mod
    ans += num * A[i] % mod
    ans -= num * A[N-i-1] % mod
    ans %= mod

print(ans)


a1=[1,2,4]
a2=[1,2,4,7]
c=0

for i in range(len(a2)):
	if(a1[0]==a2[i]):
		for j in range(len(a1)):
			if(a1[j]==a2[i]):
				i=i+1
				c=c+1
if(c==len(a1)):
	print("subset")
else:
	print("not a subset")


# Pre-requisites
import numpy as np
import time

# Initializing weight matrices from layer sizes

def initializeWeights(layers):
    weights = [np.random.randn(o, i + 1)
               for i, o in zip(layers[:-1], layers[1:])]
    return weights

# Add a bias term to every data point in the input

def addBiasTerms(X):
    # Make the input an np.array()
    X = np.array(X)

    # Forcing 1D vectors to be 2D matrices of 1xlength dimensions
    if X.ndim == 1:
        X = np.reshape(X, (1, len(X)))

    # Inserting bias terms
    X = np.insert(X, 0, 1, axis=1)

    return X

# Sigmoid function

def sigmoid(a):
    return 1 / (1 + np.exp(-a))

# Forward Propagation of outputs

def forwardProp(X, weights):
    # Initializing an empty list of outputs
    outputs = []

    # Assigning a name to reuse as inputs
    inputs = X

    # For each layer
    for w in weights:
        # Add bias term to input
        inputs = addBiasTerms(inputs)

        # Y = Sigmoid ( X .* W^T )
        outputs.append(sigmoid(np.dot(inputs, w.T)))

        # Input of next layer is output of this layer
        inputs = outputs[-1]

    return outputs

# Compute COST (J) of Neural Network

def nnCost(weights, X, Y):
    # Calculate yPred
    yPred = forwardProp(X, weights)[-1]

    # Compute J
    J = 0.5 * np.sum((yPred - Y)**2) / len(Y)

    return J

# Evaluate the accuracy of weights for input X and desired outptut Y

def evaluate(weights, X, Y):
    yPreds = forwardProp(X, weights)[-1]
    # Check if maximum probability is from that neuron corresponding to desired class,
    # AND check if that maximum probability is greater than 0.5
    yes = sum(int((np.argmax(yPreds[i]) == np.argmax(Y[i])) and
                  ((yPreds[i][np.argmax(yPreds[i])] > 0.5) == (Y[i][np.argmax(Y[i])] > 0.5)))
              for i in range(len(Y)))
    return yes

# TRAINING USING MINI-BATCH GRADIENT DESCENT
def trainUsingMinibatchGD(weights, X, Y, minibatchSize, nEpochs, learningRate=1.0,
                          decay=None, decayRate=0.1, optimizer=None, mu=0.9, testX=None, testY=None):
    # If testing data is not provided, check accuracy on training data
    if testX is None:
        testX = X
        testY = Y

    # Check cost and accuracy
    # Initialize cost
    prevCost = nnCost(weights, X, Y)
    yes = evaluate(weights, X, Y)
    print("Before training: " + str(yes) + " of " + str(len(Y)) + " = " + str(round(float(yes / len(Y)), 4)) +
          "; cost=" + str(prevCost))

    if testY is not Y:
        testPrevCost = nnCost(weights, testX, testY)
        testYes = evaluate(weights, testX, testY)
        print("  Val: " + str(testYes) + " of " + str(len(testY)) + " = " + str(round(float(testYes / len(testY)), 4)) +
          "; val cost=" + str(testPrevCost))

    # Backup weights to revert back in case cost increases
    oldWeights = [np.array(w) for w in weights]

    # To count the number of times learning rate had to be halved contiguously
    countLRHalf = 0

    # Initialize index for iteration through epochs
    epoch = 0

    # For nEpochs number of epochs:
    while epoch < nEpochs:
        # clear output
        # clear_output()

        # Make a list of all the indices
        fullIdx = list(range(len(Y)))

        # Shuffle the full index
        np.random.shuffle(fullIdx)

        # Count number of mini-batches
        nOfMinibatches = int(len(X) / minibatchSize)

        # For each mini-batch
        for m in range(nOfMinibatches):

            # Compute the starting index of this mini-batch
            startIdx = m * minibatchSize

            # Declare sampled inputs and outputs
            xSample = X[fullIdx[startIdx:startIdx + minibatchSize]]
            ySample = Y[fullIdx[startIdx:startIdx + minibatchSize]]

            # Run backprop, with an optimizer
            backProp(weights, xSample, ySample, learningRate, optimizer, mu)

        # Check cost and accuracy
        cost = nnCost(weights, X, Y)
        yes = evaluate(weights, X, Y)
        print("\nEpoch " + str(epoch + 1) + " of " + str(nEpochs) + " : " +
              str(yes) + " of " + str(len(Y)) + " = " + str(round(float(yes / len(Y)), 4)) +
              "; cost=" + str(cost), end='')

        if testY is not Y:
            testCost = nnCost(weights, testX, testY)
            testYes = evaluate(weights, testX, testY)
            print("  Val: " + str(testYes) + " of " + str(len(testY)) + " = " +
                str(round(float(testYes / len(testY)), 4)) + "; cost=" + str(testCost))

        # If decay type is 'step', when cost increases, revert back weights and
        # halve learning rate
        if decay is 'step':
            # If cost does not decrease
            if cost >= prevCost:
                # Revert weights back to those at the start of this epoch
                weights = [np.array(w) for w in oldWeights]

                # Recalculate prevCost
                cost = nnCost(weights, testX, testY)

                # Halve the learning rate
                learningRate = learningRate / 2.0

                # Revert iteration number
                epoch -= 1

                # Increment the count of halving learning rate by 1
                countLRHalf += 1

                print("Halving learning rate to: " +
                      str(learningRate) + ", count=" + str(countLRHalf))
            # If cost decreases, reset the count to 0
            else:
                countLRHalf = 0

        # If decay is 'time'
        if decay is 'time':
            learningRate *= np.exp(-decayRate)

        # If learningRate has been halved contiguously for too long, break
        if countLRHalf is 10:
            break

        # Set prevCost for next epoch
        prevCost = cost

        # Set oldWeights for next epoch
        oldWeights = [np.array(w) for w in weights]

        # Increase iteration number for epochs
        epoch += 1

    # If training was stopped because accuracy was not increasing
    if epoch < nEpochs:
        print("Training ended prematurely...")
    # If training ended in correct number of epochs
    else:
        print("Training complete.")

    # Printing training accuracy
    cost = nnCost(weights, X, Y)
    yes = evaluate(weights, X, Y)
    print("TRAINING ACCURACY, COST : " + str(yes) + " of " + str(len(Y)) +
          " = " + str(round(float(yes / len(Y)), 4)) + "; cost=" + str(cost))

    # Printing test accuracy
    if testY is not Y:
        testYes=evaluate(weights, testX, testY)
        print("TEST ACCURACY, COST : " + str(testYes) + " of " + str(len(testY)) +
        " = " + str(round(float(testYes / len(testY)), 4)) + "; cost=" + str(testCost))

# IMPLEMENTING BACK-PROPAGATION WITH LEARNING RATE, MOMENTUM, NAG, ADAGRAD
def backProp(weights, X, Y, learningRate, optimizer=None, mu=0.9):
    # Forward propagate to find outputs
    outputs=forwardProp(X, weights)

    # For the last layer, bpError = error = yPred - Y
    bpError=outputs[-1] - Y

    # Initialize velocity in the shape of weights for use with momentum and NAG
    v=[np.zeros(w.shape) for w in weights]
    prevV=[np.zeros(w.shape) for w in weights]

    # Initialize cache for use with Adagrad
    cache=[np.zeros(w.shape) for w in weights]

    # Back-propagating from the last layer to the first
    for l, w in enumerate(reversed(weights)):

        # Find yPred for this layer
        yPred=outputs[-l - 1]

        # Calculate delta for this layer using bpError from next layer
        delta=np.multiply(np.multiply(bpError, yPred), 1 - yPred)

        # Find input to the layer, by adding bias to the output of the previous layer
        # Take care, l goes from 0 to 1, while the weights are in reverse order
        if l == len(weights) - 1:  # If 1st layer has been reached
            xL=addBiasTerms(X)
        else:
            xL=addBiasTerms(outputs[-l - 2])

        # Calculate the gradient for this layer
        grad=np.dot(delta.T, xL) / len(Y)

        # Calculate bpError for previous layer to be back-propagated
        bpError=np.dot(delta, w)

        # Ignore bias term in bpError
        bpError=bpError[:, 1:]

        # CHANGE WEIGHTS of the current layer (W <- W + eta*deltaW)
        if optimizer is None:
            w += -learningRate * grad

        # Momentum
        if optimizer is 'momentum':
            v[-l - 1]=mu * v[-l - 1] - learningRate * grad
            w += v[-l - 1]

        # Nesterov Momentum
        if optimizer is 'nag':
            prevV[-l - 1]=np.array(v[-l - 1])  # back this up
            v[-l - 1]=mu * v[-l - 1] - learningRate * \
                grad  # velocity update stays the same
            # position update changes form
            w += -mu * prevV[-l - 1] + (1 + mu) * v[-l - 1]

        # Adagrad
        if optimizer is 'adagrad':
            cache[-l - 1] += grad**2
            w += - learningRate * grad / \
                (np.sqrt(cache[-l - 1]) + np.finfo(float).eps)

# Initialize network
layers=[2, 2, 1]
weights=initializeWeights(layers)

print("weights:")
for i in range(len(weights)):
    print(i + 1)
    print(weights[i].shape)
    print(weights[i])

# Declare input and desired output for AND gate
X=np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
Y=np.array([[0], [0], [0], [1]])

# Check current accuracy and cost
print("Cost: " + str(nnCost(weights, X, Y)))
yes=evaluate(weights, X, Y)
print("Accuracy: " + str(yes) + " of " + str(len(Y)) +
      " = " + str(round(float(yes / len(Y)), 4)))
print(forwardProp(X, weights)[-1])


from IsirPythonTools import *

package_name = 'xde_resources'

setup(name='XDE-Resources',
	  version='0.1',
	  description='Urdf & Collada files that are used by XDE-ISIR, but can also be used by other applications',
	  author='Soseph',
	  author_email='hak@isir.upmc.fr',
	  package_dir={package_name:'src'},
	  packages=[package_name],
	  package_data={package_name: ['resources/urdf/*.dae', 'resources/urdf/lwr/*.dae', 'resources/urdf/*.xml']},
	  cmdclass=cmdclass,

	  script_name=script_name,
	  script_args= script_args
	 )


import os, sys
from time import time
import re
def Timer(func):
    def Timer_wrapper(*arg, rtrn:bool=True, prnt:bool=False, **args):
        """ rtrn: return the result if true
            prnt: print -- {the function that is being timed}: {result} -- {time it took}
            *arg and **args contain unnamed and named variables respectably to be passed to the function to be timed"""
        t0 = time()
        out = func(*arg, **args)
        if prnt == True:
            print( f"{str(func.__name__)}: {out}  -- {time()-t0}" )
        if rtrn:
            return out
    return Timer_wrapper

@ Timer
def parse(test:int, *arg, **args):
    r""" imports input file from "AoC2020\Day{day}\{f}"  """

    pattern = re.compile('([\d]+)\s(\w+)')
    path = '\\'.join( os.path.abspath(__file__).split('\\')[:-1] )
    file_loc = f"""{path}\\{f"{f'test_{test}_' if test > 0 else ''}input.txt"}"""
    with open(file_loc) as f:
        lines = [ re.findall(pattern, line) for line in f.readlines()]
    return lines

### supporting functions/classes- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

class Formula:
    def __init__(self,raw_form):
        self.out = { i:int(n) for n,i in [raw_form[-1]] }
        self.inp = { i:int(n) for n,i in raw_form[:-1]  }
        self.name = list(self.out.keys())[0]

        print ( self.name, self.inp, self.out )
    def __repr__(self):

        return f"Form-{self.name}"
    def __str__(self):
        s = f"{self.name} {self.out[self.name]} <= "

        for key,value in self.inp.items():
            s += f"{key} {value}, "

        return s[:-2]

class LookUp:
    def __init__(self, inp):
        print(inp)
        self.formulas = [ Formula(each) for each in inp ]
        self.formulas = { form.name: form for form in self.formulas}
        print(self.formulas)

    def calc_min_ore(self, fuel = 1):
        required = {'FUEL': fuel}
        total_ore = 0
        break_i = 0

        while required and break_i<5:
            key,value = required.popitem()
            print(key, value)
            print(self.formulas[key])
            try:
                for form_key,form_value in self.formulas[key].out.items():
                    try:
                        required[form_key] += value*form_value
                    except:
                        required[form_key] = value*form_value
            except KeyError:
                total_ore += value

            break_i += 1

### - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

@ Timer
def part1(inp,test, **args):
    """ inp = input; **args contains named arguments to be passed to the timer function mostly"""
    test_restults = [0,31,165,13312,180697,2210736][test]

    tree = LookUp(inp)
    tree.calc_min_ore(2)

@ Timer
def part2(inp, **args):
    """ inp = input; **args contains named arguments to be passed to the timer function mostly"""
    pass

if __name__ == "__main__":
    """ files needed
        - input.txt
        - test_{x}_input.txt, with x the test number"""
    t0 = time()
    test = 1; prnt = test != 0
    inp = parse(test, prnt=prnt)
    part1(inp,test, prnt=True)
    # part2(inp, prnt=True)
    print(f"Total time: {time()-t0}")


import numpy as np
import scipy.signal
from scipy.interpolate import CubicSpline
import files

class SplineUpsampling(object):
    def __init__(self,new_size=128):
        self.name="spline"
        self.new_size=new_size

    def __call__(self,feat_i):
        old_size=feat_i.shape[0]
        old_x=np.arange(old_size)
        old_x=old_x.astype(float)
        if(self.new_size):
            step=float(self.new_size)/float(old_size)
            old_x*=step
            cs=CubicSpline(old_x,feat_i)
            new_size=np.arange(self.new_size)
            return cs(new_size)
        else:
            cs=CubicSpline(old_x,feat_i)
            return cs(old_x)

#def ens_upsample(in_path,out_path,size=64):
#    files.make_dir(out_path)
#    for i,in_i in enumerate(files.top_files(in_path)):
#        out_i="%s/nn%d"%(out_path,i)
#        upsample(in_i,out_i,size)

def upsample(in_path,out_path,size=128):
    seq_dict=files.get_seqs(in_path)
    print(len(seq_dict))
    spline=SplineUpsampling(size)
    seq_dict={ name_i:spline(seq_i) for name_i,seq_i in seq_dict.items()}
    files.save_seqs(seq_dict,out_path)

if __name__=="main":
    upsample('../MSR1/seqs','../MSR1/spline')