Пример #1
0
def setcookie(
    name,
    value,
    expires="",
    domain=None,
    secure=False,
    httponly=False,
    path=None,
    samesite=None,
):
    """Sets a cookie."""
    morsel = Morsel()
    name, value = safestr(name), safestr(value)
    morsel.set(name, value, quote(value))
    if isinstance(expires, int) and expires < 0:
        expires = -1000000000
    morsel["expires"] = expires
    morsel["path"] = path or ctx.homepath + "/"
    if domain:
        morsel["domain"] = domain
    if secure:
        morsel["secure"] = secure
    if httponly:
        morsel["httponly"] = True
    value = morsel.OutputString()
    if samesite and samesite.lower() in ("strict", "lax", "none"):
        value += "; SameSite=%s" % samesite
    header("Set-Cookie", value)
Пример #2
0
def test_loose_cookies_types(loop: Any) -> None:
    req = ClientRequest("get", URL("http://python.org"), loop=loop)
    morsel = Morsel()
    morsel.set(key="string", val="Another string", coded_val="really")

    accepted_types = [
        [("str", BaseCookie())],
        [("str", morsel)],
        [
            ("str", "str"),
        ],
        {
            "str": BaseCookie()
        },
        {
            "str": morsel
        },
        {
            "str": "str"
        },
        SimpleCookie(),
    ]

    for loose_cookies_type in accepted_types:
        req.update_cookies(cookies=loose_cookies_type)
def test_updated_cookies(plugin, http_client, backend_client):
    loop = asyncio.get_event_loop()

    user_id = "13"
    persona_id = "19"
    user_name = "Jan"

    cookies = {"cookie": "value"}
    credentials = {"cookies": cookies}

    new_cookies = {"new_cookie": "new_value"}
    morsel = Morsel()
    morsel.set("new_cookie", "new_value", "new_value")
    new_credentials = {"cookies": new_cookies}

    http_client.authenticate.return_value = None

    def get_identity():
        callback = http_client.set_cookies_updated_callback.call_args[0][0]
        callback([morsel])
        return user_id, persona_id, user_name

    backend_client.get_identity.side_effect = get_identity

    with patch.object(plugin, "store_credentials") as store_credentials:
        result = loop.run_until_complete(plugin.authenticate(credentials))
        assert result == Authentication(user_id, user_name)
        store_credentials.assert_called_with(new_credentials)

    http_client.authenticate.assert_called_with(cookies)
    backend_client.get_identity.assert_called_with()
Пример #4
0
 def set_cookie(
     self,
     name: str,
     value: str,
     expires: int = -1,
     domain: str = "",
     secure: str = "false",
     httponly: bool = False,
     path: str = None,
 ):
     """Sets a cookie."""
     morsel = Morsel()
     name, value = str(name), str(value)
     morsel.set(name, value, quote_plus(value))
     if isinstance(expires, int) and expires < 0:
         expires = -1000000000
     morsel["expires"] = expires
     morsel["path"] = path or "/"
     if domain:
         morsel["domain"] = domain
     if secure:
         morsel["secure"] = secure
     if httponly:
         morsel["httponly"] = httponly
     self.headers._list.append(("set-cookie".encode("latin-1"),
                                morsel.OutputString().encode("latin-1")))
Пример #5
0
def make_morsel_from_description(name, descr):
    m = Morsel()
    value = str(descr.pop("value"))
    m.set(name, value, quote(value))
    for option, value in descr.items():
        m[option] = value if option != "expires" else format_expiration_date(
            value)
    return m
Пример #6
0
class TestExpiredCookie(TestCase):
    def setUp(self):
        self.cookie = Morsel()
        self.cookie.set('foo', 'bar', 'bar')
        self.cookie.time_received = time.time() - 1

    def test_no_expiration_information(self):
        assert not is_cookie_expired(self.cookie)

    def test_valid_max_age(self):
        self.cookie['max-age'] = '86400'
        assert not is_cookie_expired(self.cookie)

    def test_valid_max_age_missing_time_received(self):
        self.cookie['max-age'] = '1'
        del self.cookie.time_received
        assert not is_cookie_expired(self.cookie)

    def test_expired_max_age(self):
        self.cookie['max-age'] = '1'
        assert is_cookie_expired(self.cookie)
        self.cookie['max-age'] = '0'
        assert is_cookie_expired(self.cookie)

    def test_expired_max_age_missing_time_received(self):
        self.cookie['max-age'] = '0'
        del self.cookie.time_received
        assert is_cookie_expired(self.cookie)
        self.cookie['max-age'] = '1'
        assert not is_cookie_expired(self.cookie)

    def test_invalid_max_age(self):
        self.cookie['max-age'] = 'invalid'
        assert not is_cookie_expired(self.cookie)

    def test_valid_expires(self):
        self.cookie['expires'] = formatdate(time.time() + 86400,
                                            localtime=True)
        assert not is_cookie_expired(self.cookie)

    def test_expired_expires(self):
        self.cookie['expires'] = formatdate(usegmt=True)
        assert is_cookie_expired(self.cookie)

    def test_invalid_expires(self):
        self.cookie['expires'] = 'invalid'
        assert not is_cookie_expired(self.cookie)

    def test_valid_max_age_and_expired_expires(self):
        self.cookie['max-age'] = '86400'
        self.cookie['expires'] = formatdate(usegmt=True)
        assert not is_cookie_expired(self.cookie)

    def test_expired_max_age_and_valid_expires(self):
        self.cookie['max-age'] = '1'
        self.cookie['expires'] = formatdate(time.time() + 86400,
                                            localtime=True)
        assert is_cookie_expired(self.cookie)
Пример #7
0
 def dumps(self):
     morsel = Morsel()
     morsel.set(self.name, self.value, self.value)
     morsel['expires'] = '' if self.expires is None else self.expires
     morsel['path'] = self.path
     if self.domain: morsel['domain'] = self.domain
     if self.secure: morsel['secure'] = self.secure
     ret = morsel.OutputString()
     if self.httponly: ret += '; httponly'
     return ret
Пример #8
0
 def add_cookie(self, key, value, **attrs):
     """
     Finer control over cookies.  Allow specifying an Morsel arguments.
     """
     if attrs:
         c = Morsel()
         c.set(key, value, **attrs)
         self.cookies[key] = c
     else:
         self.cookies[key] = value
Пример #9
0
 def add_cookie(self, key, value, **attrs):
     '''
     Finer control over cookies.  Allow specifying an Morsel arguments.
     '''
     if attrs:
         c = Morsel()
         c.set(key, value, **attrs)
         self.cookies[key] = c
     else:
         self.cookies[key] = value
Пример #10
0
def dicts_to_morsels(cookies):
    morsels = []
    for cookie in cookies:
        name = cookie["name"]
        value = cookie["value"]
        m = Morsel()
        m.set(name, value, value)
        m["domain"] = cookie.get("domain", "")
        m["path"] = cookie.get("path", "")
        morsels.append(m)
    return morsels
Пример #11
0
    def clear_cookie(self, response, name):
        cookie = Morsel()
        cookie.set(name, 'invalid', 'invalid')
        cookie['httponly'] = True
        cookie['secure'] = not settings.DEBUG
        cookie['path'] = '/'
        cookie['expires'] = 0
        if self.cookie_domain:
            cookie['domain'] = self.cookie_domain

        response.cookies[name] = cookie
Пример #12
0
 def set_cookie(
     self,
     name: str,
     value: typing.Optional[str] = None,
     domain: str = "www.codingame.com",
 ):
     if value is not None:
         morsel = Morsel()
         morsel.set(name, value, cookie_quote(value))
         morsel["domain"] = domain
         self.__session.cookie_jar.update_cookies({name: morsel})
     else:
         self.__session.cookie_jar._cookies.get(domain, {}).pop(name, None)
Пример #13
0
    def set_csrf(self, request, response):
        token = self.get_csrf_token(request)
        if not token:
            return

        cookie = Morsel()
        cookie.set(self.csrf_token_cookie_name, token, token)
        cookie['secure'] = not settings.DEBUG
        cookie['path'] = '/'
        if self.cookie_domain:
            cookie['domain'] = self.cookie_domain

        response.cookies['csrf_token'] = cookie
Пример #14
0
async def test_set_cookies(tab, recordingServer):
    """ Make sure cookies are set properly and only affect the domain they were
    set for """

    logger = Logger()

    url, reqs = recordingServer

    cookies = []
    c = Morsel()
    c.set('foo', 'bar', '')
    c['domain'] = 'localhost'
    cookies.append(c)
    c = Morsel()
    c.set('buz', 'beef', '')
    c['domain'] = 'nonexistent.example'

    settings = ControllerSettings(idleTimeout=1, timeout=60, cookies=cookies)
    controller = SinglePageController(url=url,
                                      logger=logger,
                                      service=Process(),
                                      behavior=[],
                                      settings=settings)
    await asyncio.wait_for(controller.run(), settings.timeout * 2)

    assert len(reqs) == 1
    req = reqs[0]
    reqCookies = SimpleCookie(req.headers['cookie'])
    assert len(reqCookies) == 1
    c = next(iter(reqCookies.values()))
    assert c.key == cookies[0].key
    assert c.value == cookies[0].value
Пример #15
0
async def test_loose_cookies_types() -> None:
    jar = CookieJar()

    accepted_types = [
        [('str', BaseCookie())],
        [('str', Morsel())],
        [('str', 'str'), ],
        {'str': BaseCookie()},
        {'str': Morsel()},
        {'str': 'str'},
        SimpleCookie(),
    ]

    for loose_cookies_type in accepted_types:
        jar.update_cookies(cookies=loose_cookies_type)
Пример #16
0
def set_cookie(pname='', pvalue='', pexpires=3000, pdomain=None,
              psecure=False, phttponly=False, ppath='/'):
    """Sets a cookie."""
    morsel = Morsel()
    name, value = str(pname), str(pvalue)
    morsel.set(name, value, value)
    morsel['expires'] =  (dt.utcnow() + td(seconds=pexpires)).strftime('%a, %d %b %Y %H:%M:%S %Z') 
    if ppath:
        morsel['path'] = ppath
    if pdomain:
        morsel['domain'] = pdomain
    if psecure:
        morsel['secure'] = psecure
    if phttponly:
        morsel['httponly'] = True
    return {name:morsel}
Пример #17
0
    def update_cookies(self, cookies: Optional[LooseCookies]) -> None:
        """Update request cookies header."""
        if not cookies:
            return

        c = SimpleCookie()
        if hdrs.COOKIE in self.headers:
            c.load(self.headers.get(hdrs.COOKIE, ''))
            del self.headers[hdrs.COOKIE]

        if isinstance(cookies, Mapping):
            iter_cookies = cookies.items()
        else:
            iter_cookies = cookies  # type: ignore
        for name, value in iter_cookies:
            if isinstance(value, Morsel):
                # Preserve coded_value
                mrsl_val = value.get(value.key, Morsel())
                mrsl_val.set(value.key, value.value,
                             value.coded_value)  # type: ignore  # noqa
                c[name] = mrsl_val
            else:
                c[name] = value  # type: ignore

        self.headers[hdrs.COOKIE] = c.output(header='', sep=';').strip()
Пример #18
0
    def _force_clear_cookie(self,
                            handler: JupyterHandler,
                            name: str,
                            path: str = "/",
                            domain: str | None = None) -> None:
        """Deletes the cookie with the given name.

        Tornado's cookie handling currently (Jan 2018) stores cookies in a dict
        keyed by name, so it can only modify one cookie with a given name per
        response. The browser can store multiple cookies with the same name
        but different domains and/or paths. This method lets us clear multiple
        cookies with the same name.

        Due to limitations of the cookie protocol, you must pass the same
        path and domain to clear a cookie as were used when that cookie
        was set (but there is no way to find out on the server side
        which values were used for a given cookie).
        """
        name = escape.native_str(name)
        expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)

        morsel: Morsel = Morsel()
        morsel.set(name, "", '""')
        morsel["expires"] = httputil.format_timestamp(expires)
        morsel["path"] = path
        if domain:
            morsel["domain"] = domain
        handler.add_header("Set-Cookie", morsel.OutputString())
Пример #19
0
def _build_cookie_header(session, cookies, cookie_header, url):
    url, _ = strip_auth_from_url(url)
    all_cookies = session._cookie_jar.filter_cookies(url)
    if cookies is not None:
        tmp_cookie_jar = CookieJar()
        tmp_cookie_jar.update_cookies(cookies)
        req_cookies = tmp_cookie_jar.filter_cookies(url)
        if req_cookies:
            all_cookies.load(req_cookies)

    if not all_cookies and not cookie_header:
        return None

    c = SimpleCookie()
    if cookie_header:
        c.load(cookie_header)
    for name, value in all_cookies.items():
        if isinstance(value, Morsel):
            mrsl_val = value.get(value.key, Morsel())
            mrsl_val.set(value.key, value.value, value.coded_value)
            c[name] = mrsl_val
        else:
            c[name] = value

    return c.output(header="", sep=";").strip()
Пример #20
0
 def function1289(self, arg824=URL()):
     "Returns this jar's cookies filtered by their attributes."
     self.function2829()
     arg824 = URL(arg824)
     var3212 = SimpleCookie()
     var1597 = (arg824.raw_host or '')
     var3225 = (arg824.scheme not in ('https', 'wss'))
     for var1573 in self:
         var1329 = var1573.key
         var132 = var1573['domain']
         if (not var132):
             var3212[var1329] = var1573.value
             continue
         if ((not self.attribute1674) and is_ip_address(var1597)):
             continue
         if ((var132, var1329) in self.attribute780):
             if (var132 != var1597):
                 continue
         elif (not self.function2462(var132, var1597)):
             continue
         if (not self.function2032(arg824.path, var1573['path'])):
             continue
         if (is_not_secure and var1573['secure']):
             continue
         var2063 = var1573.get(var1573.key, Morsel())
         var2063.set(var1573.key, var1573.value, var1573.coded_value)
         var3212[var1329] = var2063
     return var3212
Пример #21
0
def test_loose_cookies_types(loop) -> None:
    req = ClientRequest('get', URL('http://python.org'), loop=loop)
    morsel = Morsel()
    morsel.set(key='string', val='Another string', coded_val='really')

    accepted_types = [
        [('str', BaseCookie())],
        [('str', morsel)],
        [('str', 'str'), ],
        {'str': BaseCookie()},
        {'str': morsel},
        {'str': 'str'},
        SimpleCookie(),
    ]

    for loose_cookies_type in accepted_types:
        req.update_cookies(cookies=loose_cookies_type)
Пример #22
0
async def test_loose_cookies_types() -> None:
    jar = CookieJar()

    accepted_types = [
        [("str", BaseCookie())],
        [("str", Morsel())],
        [
            ("str", "str"),
        ],
        {"str": BaseCookie()},
        {"str": Morsel()},
        {"str": "str"},
        SimpleCookie(),
    ]

    for loose_cookies_type in accepted_types:
        jar.update_cookies(cookies=loose_cookies_type)
Пример #23
0
    def cookie_login(self, response, persistent, token):
        if not self.cookie_name:
            raise CookieException(
                'login attempt without a configured cookie name')

        cookie = Morsel()
        cookie.set(self.cookie_name, token, token)
        cookie['httponly'] = True
        cookie['secure'] = not settings.DEBUG
        cookie['path'] = '/'
        if self.cookie_domain:
            cookie['domain'] = self.cookie_domain

        if persistent:
            cookie['expires'] = self.validity_seconds

        response.cookies[self.cookie_name] = cookie
Пример #24
0
def setcookie(name, value, expires = '', domain = None, secure = False, httponly = False, path = None):
    """Sets a cookie."""
    morsel = Morsel()
    name, value = safestr(name), safestr(value)
    morsel.set(name, value, quote(value))
    if isinstance(expires, int) and expires < 0:
        expires = -1000000000
    morsel['expires'] = expires
    morsel['path'] = path or ctx.homepath + '/'
    if domain:
        morsel['domain'] = domain
    if secure:
        morsel['secure'] = secure
    value = morsel.OutputString()
    if httponly:
        value += '; httponly'
    header('Set-Cookie', value)
Пример #25
0
def setcookie(name, value, expires="", domain=None, secure=False, httponly=False, path=None):
    """Sets a cookie."""
    morsel = Morsel()
    name, value = safestr(name), safestr(value)
    morsel.set(name, value, quote(value))
    if isinstance(expires, int) and expires < 0:
        expires = -1_000_000_000
    morsel["expires"] = expires
    morsel["path"] = path or ctx.homepath + "/"
    if domain:
        morsel["domain"] = domain
    if secure:
        morsel["secure"] = secure
    value = morsel.OutputString()
    if httponly:
        value += "; httponly"
    header("Set-Cookie", value)
Пример #26
0
def setcookie(name, value, expires='', domain=None,
              secure=False, httponly=False, path=None):
    """Sets a cookie."""
    morsel = Morsel()
    name, value = safestr(name), safestr(value)
    morsel.set(name, value, quote(value))
    if isinstance(expires, int) and expires < 0:
        expires = -1000000000
    morsel['expires'] = expires
    morsel['path'] = path or ctx.homepath+'/'
    if domain:
        morsel['domain'] = domain
    if secure:
        morsel['secure'] = secure
    value = morsel.OutputString()
    if httponly:
        value += '; httponly'
    header('Set-Cookie', value)
Пример #27
0
async def import_aiohttp_cookies(cookiestxt_filename):
    cookies_obj = MozillaCookieJar(cookiestxt_filename)
    cookies_obj.load(ignore_discard=True, ignore_expires=True)

    cookies = CookieJar()

    cookies_list = []
    for domain in cookies_obj._cookies.values():
        for key, cookie in list(domain.values())[0].items():
            c = Morsel()
            c.set(key, cookie.value, cookie.value)
            c['domain'] = cookie.domain
            c['path'] = cookie.path
            cookies_list.append((key, c))

    cookies.update_cookies(cookies_list)

    return cookies
Пример #28
0
    def filter_cookies(
        self, request_url: URL = URL()
    ) -> Union["BaseCookie[str]", "SimpleCookie[str]"]:
        """Returns this jar's cookies filtered by their attributes."""
        self._do_expiration()
        if not isinstance(request_url, URL):
            warnings.warn(
                "The method accepts yarl.URL instances only, got {}".format(
                    type(request_url)
                ),
                DeprecationWarning,
            )
            request_url = URL(request_url)
        filtered: Union["SimpleCookie[str]", "BaseCookie[str]"] = (
            SimpleCookie() if self._quote_cookie else BaseCookie()
        )
        hostname = request_url.raw_host or ""
        request_origin = URL()
        with contextlib.suppress(ValueError):
            request_origin = request_url.origin()

        is_not_secure = (
            request_url.scheme not in ("https", "wss")
            and request_origin not in self._treat_as_secure_origin
        )

        for cookie in self:
            name = cookie.key
            domain = cookie["domain"]

            # Send shared cookies
            if not domain:
                filtered[name] = cookie.value
                continue

            if not self._unsafe and is_ip_address(hostname):
                continue

            if (domain, name) in self._host_only_cookies:
                if domain != hostname:
                    continue
            elif not self._is_domain_match(domain, hostname):
                continue

            if not self._is_path_match(request_url.path, cookie["path"]):
                continue

            if is_not_secure and cookie["secure"]:
                continue

            # It's critical we use the Morsel so the coded_value
            # (based on cookie version) is preserved
            mrsl_val = cast("Morsel[str]", cookie.get(cookie.key, Morsel()))
            mrsl_val.set(cookie.key, cookie.value, cookie.coded_value)
            filtered[name] = mrsl_val

        return filtered
Пример #29
0
def make_cookie(name,
                value,
                expires='',
                path='',
                domain=None,
                secure=False,
                httponly=False):
    """Make a cookie string"""
    morsel = Morsel()
    morsel.set(name, value, quote(value))
    if isinstance(expires, int) and expires < 0:
        expires = -1000000000
    morsel['expires'] = expires
    morsel['path'] = path
    if domain: morsel['domain'] = domain
    if secure: morsel['secure'] = secure
    value = morsel.OutputString()
    if httponly: value += '; httponly'
    return value
Пример #30
0
 def filter_cookies(self, request_url=URL()):
     """
     Returns this jar's cookies filtered by their attributes
     
     Parameters
     ----------
     request_url : ``URL``
         The url to filter the cookies by.
     
     Returns
     -------
     filtered : ``SimpleCookie``
         Filtered out cookies.
     """
     self._do_expiration()
     
     filtered = SimpleCookie()
     hostname = request_url.raw_host
     if hostname is None:
         hostname = ''
     
     is_not_secure = (request_url.scheme not in ('https', 'wss'))
     
     for cookie in self:
         name = cookie.key
         domain = cookie['domain']
         
         # Send shared cookies
         if not domain:
             filtered[name] = cookie.value
             continue
         
         if not self.unsafe and is_ip_address(hostname):
             continue
         
         if (domain, name) in self.host_only_cookies:
             if domain != hostname:
                 continue
         
         elif not self._is_domain_match(domain, hostname):
             continue
         
         if not self._is_path_match(request_url.path, cookie['path']):
             continue
         
         if is_not_secure and cookie['secure']:
             continue
         
         # It's critical we use the Morsel so the coded_value (based on cookie version) is preserved
         morsel_value = cookie.get(cookie.key, Morsel())
         morsel_value.set(cookie.key, cookie.value, cookie.coded_value)
         filtered[name] = morsel_value
     
     return filtered
Пример #31
0
 def get_morsel(name,
                value,
                expires=-1,
                domain=None,
                secure=False,
                httponly=False,
                path=None):
     morsel = Morsel()
     morsel.set(name, value, quote(value))
     if expires < 0:
         expires = -1000000000
     morsel['expires'] = expires
     morsel['path'] = path
     if domain:
         morsel['domain'] = domain
     if secure:
         morsel['secure'] = secure
     value = morsel.OutputString()
     if httponly:
         value += '; httponly'
     return morsel
Пример #32
0
    def test_morsel_to_cookie(self):
        from time import strftime, localtime
        time_template = "%a, %d-%b-%Y %H:%M:%S GMT"
        m = Morsel()
        m['domain'] = ".yandex"
        m['domain'] = ".yandex.ru"
        m['path'] = "/"
        m['expires'] = "Fri, 27-Aug-2021 17:43:25 GMT"
        m.key = "dj2enbdj3w"
        m.value = "fvjlrwnlkjnf"

        c = morsel_to_cookie(m)
        self.assertEquals(m.key, c.name)
        self.assertEquals(m.value, c.value)
        for x in ('expires', 'path', 'comment', 'domain',
                  'secure', 'version'):
            if x == 'expires':
                self.assertEquals(m[x], strftime(time_template, localtime(getattr(c, x, None))))
            elif x == 'version':
                self.assertTrue(isinstance(getattr(c, x, None), int))
            else:
                self.assertEquals(m[x], getattr(c, x, None))
Пример #33
0
    def test_morsel_to_cookie(self):
        from time import strftime, localtime
        time_template = "%a, %d-%b-%Y %H:%M:%S GMT"
        m = Morsel()
        m['domain'] = ".yandex"
        m['domain'] = ".yandex.ru"
        m['path'] = "/"
        m['expires'] = "Fri, 27-Aug-2021 17:43:25 GMT"
        m.key = "dj2enbdj3w"
        m.value = "fvjlrwnlkjnf"

        c = morsel_to_cookie(m)
        self.assertEqual(m.key, c.name)
        self.assertEqual(m.value, c.value)
        for x in ('expires', 'path', 'comment', 'domain', 'secure', 'version'):
            if x == 'expires':
                self.assertEqual(
                    m[x],
                    strftime(time_template, localtime(getattr(c, x, None))))
            elif x == 'version':
                self.assertTrue(isinstance(getattr(c, x, None), int))
            else:
                self.assertEqual(m[x], getattr(c, x, None))
Пример #34
0
    def force_clear_cookie(self, name, path="/", domain=None):
        """Deletes the cookie with the given name.

        Tornado's cookie handling currently (Jan 2018) stores cookies in a dict
        keyed by name, so it can only modify one cookie with a given name per
        response. The browser can store multiple cookies with the same name
        but different domains and/or paths. This method lets us clear multiple
        cookies with the same name.

        Due to limitations of the cookie protocol, you must pass the same
        path and domain to clear a cookie as were used when that cookie
        was set (but there is no way to find out on the server side
        which values were used for a given cookie).
        """
        name = escape.native_str(name)
        expires = datetime.datetime.utcnow() - datetime.timedelta(days=365)

        morsel = Morsel()
        morsel.set(name, '', '""')
        morsel['expires'] = httputil.format_timestamp(expires)
        morsel['path'] = path
        if domain:
            morsel['domain'] = domain
        self.add_header("Set-Cookie", morsel.OutputString())
Пример #35
0
 def __init__(self, name=None, value=None):
     Morsel.__init__(self)
     if name is not None:
         self.set(name, value, value)