2018-12-21 07:45:59 +03:00
|
|
|
/- *dns, hall
|
2018-06-18 21:43:26 +03:00
|
|
|
!:
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-10-30 07:42:39 +03:00
|
|
|
:: moves and state
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-10-30 07:42:39 +03:00
|
|
|
=> |%
|
|
|
|
+$ move (pair bone card)
|
|
|
|
+$ poke
|
2018-10-30 22:05:42 +03:00
|
|
|
$% [%dns-command command]
|
2018-12-21 07:45:59 +03:00
|
|
|
[%hall-action %phrase audience:hall (list speech:hall)]
|
2018-07-16 00:00:21 +03:00
|
|
|
==
|
2018-10-30 07:42:39 +03:00
|
|
|
+$ card
|
2018-12-21 07:45:59 +03:00
|
|
|
$% [%hiss wire [~ ~] %httr %hiss hiss:eyre]
|
2018-07-16 00:00:21 +03:00
|
|
|
[%poke wire dock poke]
|
|
|
|
[%rule wire %turf %put turf]
|
2018-10-30 22:05:42 +03:00
|
|
|
[%wait wire @da]
|
2018-07-16 00:00:21 +03:00
|
|
|
==
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +state: complete app state
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-10-30 07:42:39 +03:00
|
|
|
+$ state
|
2018-05-07 19:53:31 +03:00
|
|
|
$: :: dom: the set of our bindings
|
|
|
|
::
|
|
|
|
dom=(set turf)
|
|
|
|
:: per: per-dependent ips &c
|
|
|
|
::
|
|
|
|
per=(map ship relay)
|
|
|
|
:: nem: authoritative state
|
|
|
|
::
|
|
|
|
nem=(unit nameserver)
|
2018-06-16 05:45:21 +03:00
|
|
|
==
|
2018-10-30 07:42:39 +03:00
|
|
|
--
|
|
|
|
::
|
|
|
|
:: helpers
|
|
|
|
::
|
|
|
|
=> |%
|
2018-12-21 02:18:21 +03:00
|
|
|
:: +join: join list of cords with separator
|
|
|
|
::
|
|
|
|
:: XX move to zuse?
|
|
|
|
:: XX dedup with lib/pkcs
|
2018-06-18 21:43:26 +03:00
|
|
|
::
|
|
|
|
++ join
|
|
|
|
|= [sep=@t hot=(list @t)]
|
|
|
|
^- @t
|
2018-12-21 02:18:21 +03:00
|
|
|
=| out=(list @t)
|
2018-06-18 21:43:26 +03:00
|
|
|
?> ?=(^ hot)
|
2018-12-21 02:18:21 +03:00
|
|
|
|- ^- @t
|
|
|
|
?~ t.hot
|
|
|
|
(rap 3 [i.hot out])
|
|
|
|
$(out [sep i.hot out], hot t.hot)
|
|
|
|
:: +name: fully-qualified domain name for :ship
|
2018-06-20 23:58:47 +03:00
|
|
|
::
|
|
|
|
++ name
|
2018-12-21 02:18:21 +03:00
|
|
|
|= [=ship =turf]
|
|
|
|
(cat 3 (join '.' (weld turf /(crip +:(scow %p ship)))) '.')
|
|
|
|
:: +endpoint: append :path to :purl
|
2018-06-20 23:58:47 +03:00
|
|
|
::
|
|
|
|
++ endpoint
|
2018-12-21 02:18:21 +03:00
|
|
|
|= [=purl:eyre =path]
|
|
|
|
^+ purl
|
|
|
|
purl(q.q (weld q.q.purl path))
|
2018-12-21 07:45:59 +03:00
|
|
|
:: +print-path: serialize a +path to a +cord
|
|
|
|
::
|
|
|
|
++ print-path
|
|
|
|
|= =path
|
|
|
|
(crip ~(ram re (sell !>(path))))
|
2018-10-30 07:42:39 +03:00
|
|
|
--
|
|
|
|
::
|
|
|
|
:: service providers
|
|
|
|
::
|
|
|
|
=> |%
|
2018-11-06 06:18:54 +03:00
|
|
|
:: |gcloud: provider-specific functions
|
2018-06-16 05:45:21 +03:00
|
|
|
::
|
|
|
|
++ gcloud
|
2018-06-20 23:58:47 +03:00
|
|
|
|_ aut=authority
|
2018-06-18 22:59:36 +03:00
|
|
|
:: +base: provider service endpoint
|
|
|
|
::
|
2018-06-18 21:43:26 +03:00
|
|
|
++ base
|
|
|
|
(need (de-purl:html 'https://www.googleapis.com/dns/v1/projects'))
|
2018-11-06 06:18:54 +03:00
|
|
|
:: +record: JSON-formatted provider-specific dns record
|
2018-06-18 22:59:36 +03:00
|
|
|
::
|
2018-06-18 21:43:26 +03:00
|
|
|
++ record
|
2018-06-20 23:58:47 +03:00
|
|
|
|= [him=ship tar=target]
|
2018-06-18 21:43:26 +03:00
|
|
|
^- json
|
2018-12-21 02:18:21 +03:00
|
|
|
=/ type
|
|
|
|
?:(?=(%direct -.tar) 'A' 'CNAME')
|
|
|
|
=/ data
|
2018-06-18 21:43:26 +03:00
|
|
|
?: ?=(%direct -.tar)
|
2018-12-21 02:18:21 +03:00
|
|
|
[%s (crip +:(scow %if p.tar))]
|
|
|
|
[%s (name p.tar dom.aut)]
|
|
|
|
:- %o
|
|
|
|
%- ~(gas by *(map @t json))
|
|
|
|
:~ ['name' %s (name him dom.aut)]
|
|
|
|
['type' %s type]
|
|
|
|
:: XX make configureable?
|
|
|
|
::
|
|
|
|
['ttl' %n ~.300]
|
|
|
|
['rrdatas' %a data ~]
|
2018-06-18 21:43:26 +03:00
|
|
|
==
|
2018-11-06 06:18:54 +03:00
|
|
|
:: +create: provider-specific record-creation request
|
2018-06-18 22:59:36 +03:00
|
|
|
::
|
2018-11-06 06:18:54 +03:00
|
|
|
++ create
|
2018-06-18 21:43:26 +03:00
|
|
|
=, eyre
|
2018-06-20 23:58:47 +03:00
|
|
|
|= [him=ship tar=target pre=(unit target)]
|
2018-06-18 21:43:26 +03:00
|
|
|
^- hiss
|
|
|
|
=/ url=purl
|
2018-06-20 23:58:47 +03:00
|
|
|
%+ endpoint base
|
|
|
|
/[project.pro.aut]/['managedZones']/[zone.pro.aut]/changes
|
2018-06-18 21:43:26 +03:00
|
|
|
=/ hed=math
|
|
|
|
(my content-type+['application/json' ~] ~)
|
|
|
|
=/ bod=octs
|
|
|
|
%- as-octt:mimes:html
|
|
|
|
%- en-json:html
|
2018-12-21 02:18:21 +03:00
|
|
|
:- %o
|
|
|
|
%- ~(gas by *(map @t json))
|
|
|
|
:- ['additions' %a (record him tar) ~]
|
2018-06-20 23:58:47 +03:00
|
|
|
?~ pre ~
|
2018-12-21 02:18:21 +03:00
|
|
|
[['deletions' %a (record him u.pre) ~] ~]
|
2018-06-18 21:43:26 +03:00
|
|
|
[url %post hed `bod]
|
2018-11-06 06:18:54 +03:00
|
|
|
:: +list: list existing records stored by provider
|
|
|
|
::
|
|
|
|
++ list
|
|
|
|
=, eyre
|
|
|
|
|= page=(unit @t)
|
|
|
|
^- hiss
|
|
|
|
=/ url=purl
|
|
|
|
%+ endpoint base
|
|
|
|
/[project.pro.aut]/['managedZones']/[zone.pro.aut]/rrsets
|
|
|
|
=/ hed=math
|
|
|
|
?~ page ~
|
|
|
|
(~(put by *math) 'pageToken' [u.page]~)
|
|
|
|
[url %get hed ~]
|
|
|
|
:: +parse existing records stored by provider
|
|
|
|
::
|
|
|
|
++ parse
|
|
|
|
=< |= bod=octs
|
|
|
|
=/ jon (de-json:html q.bod)
|
|
|
|
?~ jon [~ ~]
|
|
|
|
(response u.jon)
|
|
|
|
::
|
|
|
|
=, dejs:format
|
|
|
|
|%
|
|
|
|
++ response
|
|
|
|
^- $- json
|
|
|
|
(pair (list (pair ship target)) (unit @t))
|
|
|
|
%- ou :~
|
|
|
|
:: 'kind'^(su (jest "dns#resourceRecordSetsListResponse'))
|
|
|
|
::
|
|
|
|
'rrsets'^(uf ~ record-set)
|
|
|
|
'nextPageToken'^(uf ~ (mu so))
|
|
|
|
==
|
|
|
|
::
|
|
|
|
++ record-set
|
|
|
|
%+ cu
|
|
|
|
|= a=(list (unit (pair ship target)))
|
|
|
|
?~ a ~
|
|
|
|
?: ?| ?=(~ i.a)
|
|
|
|
?=(%czar (clan:title p.u.i.a))
|
|
|
|
==
|
|
|
|
$(a t.a)
|
|
|
|
[u.i.a $(a t.a)]
|
|
|
|
(ar record)
|
|
|
|
::
|
|
|
|
++ record
|
|
|
|
%+ cu
|
|
|
|
|= [typ=@t nam=@t dat=(list @t)]
|
|
|
|
^- (unit (pair ship target))
|
|
|
|
=/ him (name nam)
|
|
|
|
?: ?| ?=(~ him)
|
|
|
|
?=(~ dat)
|
|
|
|
?=(^ t.dat)
|
|
|
|
==
|
|
|
|
~
|
|
|
|
?+ typ
|
|
|
|
~
|
|
|
|
::
|
|
|
|
%'A'
|
|
|
|
=/ adr (rush i.dat lip:ag)
|
|
|
|
?~ adr ~
|
|
|
|
`[u.him %direct %if u.adr]
|
|
|
|
::
|
|
|
|
%'CNAME'
|
|
|
|
=/ for (name i.dat)
|
|
|
|
?~ for ~
|
|
|
|
`[u.him %indirect u.for]
|
|
|
|
==
|
|
|
|
::
|
|
|
|
%- ot :~
|
|
|
|
:: 'kind'^(su (jest "dns#resourceRecordSet'))
|
|
|
|
::
|
|
|
|
'type'^so
|
|
|
|
'name'^so
|
|
|
|
'rrdatas'^(ar so)
|
|
|
|
==
|
|
|
|
::
|
|
|
|
++ name
|
|
|
|
|= nam=@t
|
|
|
|
^- (unit ship)
|
|
|
|
=/ dom=(unit host:eyre)
|
|
|
|
(rush nam ;~(sfix thos:de-purl:html dot))
|
|
|
|
?: ?| ?=(~ dom)
|
|
|
|
?=(%| -.u.dom)
|
|
|
|
?=(~ p.u.dom)
|
|
|
|
==
|
|
|
|
~
|
|
|
|
=/ who
|
|
|
|
(rush (head (flop p.u.dom)) fed:ag)
|
|
|
|
?~ who ~
|
|
|
|
?. =(dom.aut (flop (tail (flop p.u.dom))))
|
|
|
|
~
|
|
|
|
`u.who
|
|
|
|
--
|
2018-06-18 21:43:26 +03:00
|
|
|
--
|
2018-05-07 19:53:31 +03:00
|
|
|
--
|
|
|
|
::
|
2018-06-18 22:59:36 +03:00
|
|
|
:: the app itself
|
|
|
|
::
|
2018-05-07 19:53:31 +03:00
|
|
|
|_ [bow=bowl:gall state]
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +this: is sparta
|
|
|
|
::
|
2018-05-07 19:53:31 +03:00
|
|
|
++ this .
|
2018-11-06 06:18:54 +03:00
|
|
|
:: +request: generic http request
|
|
|
|
::
|
|
|
|
++ request
|
2019-01-09 18:07:09 +03:00
|
|
|
|= [=wire =hiss:eyre]
|
2018-11-06 06:18:54 +03:00
|
|
|
^- card
|
2019-01-09 18:07:09 +03:00
|
|
|
[%hiss wire [~ ~] %httr %hiss hiss]
|
2018-12-21 07:45:59 +03:00
|
|
|
:: +notify: send :hall notification
|
|
|
|
::
|
|
|
|
++ notify
|
|
|
|
|= [=ship =cord =tang]
|
|
|
|
^- card
|
|
|
|
=/ msg=speech:hall
|
|
|
|
:+ %app dap.bow
|
|
|
|
=/ line [%lin & cord]
|
|
|
|
?~(tang line [%fat [%tank tang] line])
|
|
|
|
=/ act
|
|
|
|
[%phrase (sy [ship %inbox] ~) [msg ~]]
|
|
|
|
[%poke / [our.bow %hall] %hall-action act]
|
2019-01-09 18:07:09 +03:00
|
|
|
:: +wait: set a timer
|
|
|
|
::
|
|
|
|
++ wait
|
|
|
|
|= [=wire lull=@dr]
|
|
|
|
^- card
|
|
|
|
[%wait wire (add now.bow lull)]
|
|
|
|
:: +backoff: calculate exponential backoff
|
|
|
|
::
|
|
|
|
++ backoff
|
|
|
|
|= try=@ud
|
|
|
|
^- @dr
|
|
|
|
?: =(0 try) ~s0
|
|
|
|
%+ add
|
|
|
|
(mul ~s1 (bex (dec try)))
|
|
|
|
(mul ~s0..0001 (~(rad og eny.bow) 1.000))
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +poke-noun: debugging
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
|
|
|
++ poke-noun
|
|
|
|
|= a=*
|
2018-06-18 21:43:26 +03:00
|
|
|
^- (quip move _this)
|
2018-06-20 23:06:00 +03:00
|
|
|
~& +<+:this
|
|
|
|
[~ this]
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +sigh-httr: accept http response
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-06-16 05:45:21 +03:00
|
|
|
++ sigh-httr
|
|
|
|
|= [wir=wire rep=httr:eyre]
|
2018-06-18 21:42:57 +03:00
|
|
|
^- (quip move _this)
|
2018-10-30 22:05:42 +03:00
|
|
|
:: at least two segments in every wire
|
|
|
|
::
|
|
|
|
?. ?=([@ @ *] wir)
|
|
|
|
~& [%strange-http-response wire=wir response=rep]
|
|
|
|
[~ this]
|
|
|
|
?+ i.wir
|
|
|
|
:: print and ignore unrecognized responses
|
|
|
|
::
|
2018-11-07 08:25:49 +03:00
|
|
|
~& [%strange-http-response wire=wir response=rep]
|
2018-06-16 05:45:21 +03:00
|
|
|
[~ this]
|
2018-10-30 22:05:42 +03:00
|
|
|
:: responses for a nameserver
|
2018-06-18 21:43:26 +03:00
|
|
|
::
|
2018-10-30 22:05:42 +03:00
|
|
|
%authority
|
2018-06-18 21:43:26 +03:00
|
|
|
?~ nem
|
|
|
|
~& [%strange-authority wire=wir response=rep]
|
|
|
|
[~ this]
|
2018-10-30 22:05:42 +03:00
|
|
|
?+ i.t.wir
|
|
|
|
!!
|
|
|
|
:: response confirming a valid nameserver config
|
|
|
|
::
|
|
|
|
%confirm
|
|
|
|
?. =(200 p.rep)
|
|
|
|
~& [%authority-confirm-fail rep]
|
|
|
|
[~ this(nem ~)]
|
2018-11-06 06:18:54 +03:00
|
|
|
abet:(~(update bind u.nem) ~)
|
2018-10-30 22:05:42 +03:00
|
|
|
:: response to a binding creation request
|
|
|
|
::
|
|
|
|
%create
|
|
|
|
?> ?=([@ %for @ ~] t.t.wir)
|
|
|
|
?. =(200 p.rep)
|
|
|
|
:: XX set a retry timeout?
|
|
|
|
::
|
|
|
|
~& [%authority-create-fail wire=wir response=rep]
|
|
|
|
[~ this]
|
|
|
|
=/ him=ship (slav %p i.t.t.wir)
|
|
|
|
=/ for=ship (slav %p i.t.t.t.t.wir)
|
|
|
|
abet:(~(confirm bind u.nem) for him)
|
2018-11-06 06:18:54 +03:00
|
|
|
:: response to an existing-binding retrieval request
|
|
|
|
::
|
|
|
|
%update
|
|
|
|
?. =(200 p.rep)
|
|
|
|
:: XX retry
|
|
|
|
::
|
|
|
|
[~ this]
|
|
|
|
?~ r.rep
|
|
|
|
[~ this]
|
|
|
|
abet:(~(restore bind u.nem) u.r.rep)
|
2018-10-30 22:05:42 +03:00
|
|
|
==
|
2019-01-09 18:07:09 +03:00
|
|
|
:: responses for a relay
|
|
|
|
::
|
|
|
|
%relay
|
|
|
|
:: XX refactor
|
|
|
|
?> ?=([%relay %him @ *] wir)
|
|
|
|
=/ him=ship (slav %p i.t.t.wir)
|
|
|
|
abet:(http-response:(tell him) t.t.t.wir rep)
|
2018-06-16 05:45:21 +03:00
|
|
|
==
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +sigh-tang: failed to make http request
|
2018-06-19 05:59:50 +03:00
|
|
|
::
|
|
|
|
++ sigh-tang
|
2019-01-09 18:07:09 +03:00
|
|
|
|= [=wire =tang]
|
2018-06-19 05:59:50 +03:00
|
|
|
^- (quip move _this)
|
2019-01-09 18:07:09 +03:00
|
|
|
?+ wire
|
|
|
|
~& [%strange-sigh-tang wire]
|
|
|
|
[((slog tang) ~) this]
|
2018-06-19 05:59:50 +03:00
|
|
|
::
|
|
|
|
[%authority %confirm ~]
|
2018-12-21 07:45:59 +03:00
|
|
|
:_ this(nem ~)
|
2019-01-09 18:07:09 +03:00
|
|
|
[[ost.bow (notify our.bow 'authority confirmation failed' tang)] ~]
|
2018-11-06 06:18:54 +03:00
|
|
|
::
|
2018-12-21 07:45:59 +03:00
|
|
|
[%authority %create *]
|
2018-11-06 06:18:54 +03:00
|
|
|
:: XX retry pending bindings
|
|
|
|
::
|
2018-12-21 07:45:59 +03:00
|
|
|
=/ msg
|
2019-01-09 18:07:09 +03:00
|
|
|
(cat 3 'failed to create binding: ' (print-path t.t.wire))
|
2018-12-21 07:45:59 +03:00
|
|
|
:_ this
|
2019-01-09 18:07:09 +03:00
|
|
|
[[ost.bow (notify our.bow msg tang)] ~]
|
2018-11-06 06:18:54 +03:00
|
|
|
::
|
|
|
|
[%authority %update ~]
|
|
|
|
:: XX retry binding retrieval
|
|
|
|
::
|
2018-12-21 07:45:59 +03:00
|
|
|
:_ this
|
2019-01-09 18:07:09 +03:00
|
|
|
[[ost.bow (notify our.bow 'failed to retrieve bindings' tang)] ~]
|
2018-10-31 01:19:34 +03:00
|
|
|
::
|
2019-01-09 18:07:09 +03:00
|
|
|
[%relay %him @ *]
|
|
|
|
=/ him=ship (slav %p i.t.t.wire)
|
|
|
|
abet:(http-crash:(tell him) t.t.t.wire tang)
|
2018-06-19 05:59:50 +03:00
|
|
|
==
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +wake: timer callback
|
2018-07-16 00:00:21 +03:00
|
|
|
::
|
|
|
|
++ wake
|
2019-01-09 18:07:09 +03:00
|
|
|
|= [=wire ~]
|
2018-07-16 00:00:21 +03:00
|
|
|
^- (quip move _this)
|
2019-01-09 18:07:09 +03:00
|
|
|
?+ wire
|
|
|
|
~& [%strange-wake wire]
|
2018-10-31 01:19:34 +03:00
|
|
|
[~ this]
|
|
|
|
::
|
2019-01-09 18:07:09 +03:00
|
|
|
[%relay %him @ *]
|
|
|
|
=/ him=ship (slav %p i.t.t.wire)
|
|
|
|
abet:(retry:(tell him) t.t.t.wire)
|
2018-10-31 01:19:34 +03:00
|
|
|
==
|
2018-10-30 22:05:42 +03:00
|
|
|
:: +poke-dns-command: act on command
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-10-30 22:05:42 +03:00
|
|
|
++ poke-dns-command
|
|
|
|
|= com=command
|
2018-05-07 19:53:31 +03:00
|
|
|
^- (quip move _this)
|
2018-10-30 22:05:42 +03:00
|
|
|
?- -.com
|
|
|
|
:: configure self as an authority
|
|
|
|
::
|
|
|
|
:: [%authority authority]
|
|
|
|
::
|
|
|
|
%authority
|
|
|
|
~| %authority-reset-wat-do
|
|
|
|
?< ?=(^ nem)
|
|
|
|
abet:(init:bind aut.com)
|
|
|
|
:: create binding (if authority) and forward request
|
|
|
|
::
|
|
|
|
:: [%bind for=ship him=ship target]
|
|
|
|
::
|
|
|
|
%bind
|
|
|
|
=/ rac (clan:title him.com)
|
|
|
|
?: ?=(%czar rac)
|
|
|
|
~|(%bind-galazy !!)
|
|
|
|
?: ?& ?=(%king rac)
|
|
|
|
?=(%indirect -.tar.com)
|
|
|
|
==
|
|
|
|
~|(%bind-indirect-star !!)
|
|
|
|
:: always forward, there may be multiple authorities
|
|
|
|
::
|
|
|
|
=^ zom=(list move) ..this
|
|
|
|
abet:(forward:(tell him.com) [for tar]:com)
|
|
|
|
=^ zam=(list move) ..this
|
|
|
|
?~ nem [~ this]
|
|
|
|
abet:(~(create bind u.nem) [for him tar]:com)
|
|
|
|
[(weld zom zam) this]
|
|
|
|
:: process established dns binding
|
|
|
|
::
|
|
|
|
:: [%bond for=ship him=ship turf]
|
|
|
|
::
|
|
|
|
%bond
|
2018-11-02 23:06:46 +03:00
|
|
|
?: ?& =(our.bow for.com)
|
|
|
|
!=(our.bow src.bow)
|
|
|
|
==
|
2019-01-09 18:07:09 +03:00
|
|
|
abet:(learn:(tell him.com) dom.com)
|
2018-11-07 08:25:49 +03:00
|
|
|
::
|
2018-10-30 22:05:42 +03:00
|
|
|
?: =(our.bow him.com)
|
2018-12-21 07:45:59 +03:00
|
|
|
=/ msg
|
|
|
|
(cat 3 'domain name established at ' (join '.' dom.com))
|
2018-11-07 08:25:49 +03:00
|
|
|
:_ this(dom (~(put in dom) dom.com))
|
2018-12-21 07:45:59 +03:00
|
|
|
:~ [ost.bow (notify our.bow msg ~)]
|
2018-11-07 08:25:49 +03:00
|
|
|
[ost.bow %rule /bound %turf %put dom.com]
|
|
|
|
==
|
|
|
|
::
|
2018-10-30 22:05:42 +03:00
|
|
|
~& [%strange-bond com]
|
|
|
|
[~ this]
|
|
|
|
:: manually set our ip, request direct binding
|
|
|
|
::
|
|
|
|
:: [%ip %if addr=@if]
|
|
|
|
::
|
|
|
|
%ip
|
|
|
|
?. =(our.bow src.bow)
|
|
|
|
~& %dns-ip-no-foreign
|
|
|
|
[~ this]
|
|
|
|
abet:(hear:(tell our.bow) `addr.com)
|
|
|
|
:: meet sponsee, request indirect binding
|
|
|
|
::
|
|
|
|
:: [%meet him=ship]
|
|
|
|
::
|
|
|
|
%meet
|
|
|
|
?. =(our.bow (sein:title our.bow now.bow him.com))
|
2018-12-21 07:45:59 +03:00
|
|
|
~& [%dns-meet-not-sponsored him.com]
|
2018-10-30 22:05:42 +03:00
|
|
|
[~ this]
|
|
|
|
abet:(hear:(tell him.com) ~)
|
|
|
|
==
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +coup: general poke acknowledgement or error
|
2018-06-19 20:19:54 +03:00
|
|
|
::
|
|
|
|
++ coup
|
2019-01-09 18:07:09 +03:00
|
|
|
|= [=wire saw=(unit tang)]
|
2018-06-19 20:19:54 +03:00
|
|
|
?~ saw [~ this]
|
2019-01-09 18:07:09 +03:00
|
|
|
~& [%coup-fallthru wire]
|
2018-06-19 20:19:54 +03:00
|
|
|
[((slog u.saw) ~) this]
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +prep: adapt state
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-11-07 08:25:49 +03:00
|
|
|
:: ++ prep _[~ this]
|
2018-05-07 19:53:31 +03:00
|
|
|
++ prep
|
|
|
|
|= old=(unit state)
|
|
|
|
^- (quip move _this)
|
|
|
|
?^ old
|
|
|
|
[~ this(+<+ u.old)]
|
2018-10-30 22:05:42 +03:00
|
|
|
:: XX print :dns|ip config instructions for stars?
|
|
|
|
::
|
2018-05-07 19:53:31 +03:00
|
|
|
[~ this]
|
2018-10-30 07:42:39 +03:00
|
|
|
:: |bind: acting as zone authority
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-06-18 22:59:36 +03:00
|
|
|
++ bind
|
2018-05-07 19:53:31 +03:00
|
|
|
=| moz=(list move)
|
|
|
|
|_ nam=nameserver
|
|
|
|
++ this .
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +abet: finalize state changes, produce moves
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
|
|
|
++ abet
|
|
|
|
^- (quip move _^this)
|
|
|
|
[(flop moz) ^this(nem `nam)]
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +emit: emit a move
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-06-16 05:44:37 +03:00
|
|
|
++ emit
|
2018-06-18 21:43:26 +03:00
|
|
|
|= car=card
|
2018-06-16 05:44:37 +03:00
|
|
|
^+ this
|
2018-06-18 21:43:26 +03:00
|
|
|
this(moz [[ost.bow car] moz])
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +init: establish zone authority (request confirmation)
|
2018-06-16 05:44:37 +03:00
|
|
|
::
|
2018-05-07 19:53:31 +03:00
|
|
|
++ init
|
|
|
|
|= aut=authority
|
2018-06-16 05:45:21 +03:00
|
|
|
=/ wir=wire /authority/confirm
|
2018-06-20 23:58:47 +03:00
|
|
|
=/ url=purl:eyre
|
|
|
|
%+ endpoint base:gcloud
|
2018-06-18 21:43:26 +03:00
|
|
|
/[project.pro.aut]/['managedZones']/[zone.pro.aut]
|
2018-11-05 20:55:16 +03:00
|
|
|
%- emit(nam [aut ~ ~ ~])
|
2018-11-06 06:18:54 +03:00
|
|
|
(request wir url %get ~ ~)
|
|
|
|
:: +update: retrieve existing remote nameserver records
|
|
|
|
::
|
|
|
|
++ update
|
|
|
|
|= page=(unit @t)
|
|
|
|
^+ this
|
|
|
|
(emit (request /authority/update (~(list gcloud aut.nam) page)))
|
2018-12-21 02:18:21 +03:00
|
|
|
:: +restore: restore existing remote nameserver records
|
2018-11-06 06:18:54 +03:00
|
|
|
::
|
|
|
|
++ restore
|
|
|
|
|= bod=octs
|
|
|
|
=+ ^- [dat=(list (pair ship target)) page=(unit @t)]
|
|
|
|
(~(parse gcloud aut.nam) bod)
|
|
|
|
|- ^+ this
|
|
|
|
?~ dat
|
|
|
|
?~(page this (update page))
|
|
|
|
=/ nob=bound [now.bow q.i.dat ~]
|
|
|
|
$(dat t.dat, bon.nam (~(put by bon.nam) p.i.dat nob))
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +create: bind :him, on behalf of :for
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
|
|
|
++ create
|
2018-06-18 21:43:26 +03:00
|
|
|
|= [for=ship him=ship tar=target]
|
2018-11-05 20:55:16 +03:00
|
|
|
?: ?& ?=(%indirect -.tar)
|
|
|
|
!(~(has by bon.nam) p.tar)
|
2018-06-19 05:07:26 +03:00
|
|
|
==
|
2018-11-05 20:55:16 +03:00
|
|
|
:: defer %indirect where target isn't yet bound
|
|
|
|
::
|
|
|
|
this(dep.nam (~(add ja dep.nam) p.tar [him tar]))
|
2018-11-02 23:14:40 +03:00
|
|
|
:: ignore if binding is pending
|
|
|
|
::
|
|
|
|
=/ pending (~(get by pen.nam) him)
|
|
|
|
?: ?& ?=(^ pending)
|
|
|
|
=(tar u.pending)
|
|
|
|
==
|
|
|
|
this
|
|
|
|
:: re-notify if binding already exists
|
|
|
|
::
|
|
|
|
=/ existing (~(get by bon.nam) him)
|
|
|
|
?: ?& ?=(^ existing)
|
|
|
|
=(tar cur.u.existing)
|
|
|
|
==
|
2018-11-07 08:25:49 +03:00
|
|
|
(bond for him)
|
2018-11-02 23:14:40 +03:00
|
|
|
:: create new or replace existing binding
|
|
|
|
::
|
2018-06-18 21:43:26 +03:00
|
|
|
=/ wir=wire
|
|
|
|
/authority/create/(scot %p him)/for/(scot %p for)
|
2018-06-20 23:58:47 +03:00
|
|
|
=/ pre=(unit target)
|
|
|
|
=/ bon=(unit bound) (~(get by bon.nam) him)
|
|
|
|
?~(bon ~ `cur.u.bon)
|
2018-06-18 21:43:26 +03:00
|
|
|
=/ req=hiss:eyre
|
2018-11-06 06:18:54 +03:00
|
|
|
(~(create gcloud aut.nam) him tar pre)
|
2018-11-07 08:25:49 +03:00
|
|
|
:: XX save :for relay state?
|
|
|
|
::
|
2018-12-21 02:18:21 +03:00
|
|
|
=. pen.nam (~(put by pen.nam) him tar)
|
|
|
|
(emit (request wir req))
|
|
|
|
:: +dependants: process deferred dependant bindings
|
2018-11-05 20:55:16 +03:00
|
|
|
::
|
|
|
|
++ dependants
|
|
|
|
|= for=ship
|
|
|
|
^+ this
|
2018-12-21 02:18:21 +03:00
|
|
|
=/ dep=(list [him=ship tar=target])
|
|
|
|
(~(get ja dep.nam) for)
|
|
|
|
=. dep.nam (~(del by dep.nam) for)
|
|
|
|
|- ^+ ..this
|
|
|
|
?~ dep this
|
|
|
|
$(dep t.dep, ..this (create for him.i.dep tar.i.dep))
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +confirm: successfully bound
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
|
|
|
++ confirm
|
2018-06-18 21:43:26 +03:00
|
|
|
|= [for=ship him=ship]
|
|
|
|
=/ tar=target (~(got by pen.nam) him)
|
|
|
|
=/ bon=(unit bound)
|
|
|
|
(~(get by bon.nam) him)
|
|
|
|
=/ nob=bound
|
|
|
|
[now.bow tar ?~(bon ~ [[wen.u.bon cur.u.bon] hit.u.bon])]
|
2018-12-21 02:18:21 +03:00
|
|
|
=: pen.nam (~(del by pen.nam) him)
|
|
|
|
bon.nam (~(put by bon.nam) him nob)
|
|
|
|
==
|
2018-11-07 08:25:49 +03:00
|
|
|
(dependants:(bond for him) him)
|
|
|
|
:: +bond: send binding confirmation
|
|
|
|
::
|
|
|
|
++ bond
|
|
|
|
|= [for=ship him=ship]
|
2018-06-18 21:43:26 +03:00
|
|
|
=/ wir=wire
|
2018-06-19 20:26:00 +03:00
|
|
|
/bound/(scot %p him)/for/(scot %p for)
|
|
|
|
=/ dom=turf
|
|
|
|
(weld dom.aut.nam /(crip +:(scow %p him)))
|
2018-11-07 08:25:49 +03:00
|
|
|
=/ com=command
|
|
|
|
[%bond for him dom]
|
|
|
|
(emit [%poke wir [for dap.bow] %dns-command com])
|
2018-05-07 19:53:31 +03:00
|
|
|
--
|
2018-10-30 07:42:39 +03:00
|
|
|
:: |tell: acting as planet parent or relay
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-06-18 22:59:36 +03:00
|
|
|
++ tell
|
2018-10-30 22:05:42 +03:00
|
|
|
|= him=ship
|
2018-05-07 19:53:31 +03:00
|
|
|
=| moz=(list move)
|
2018-10-30 22:05:42 +03:00
|
|
|
=/ rel=(unit relay) (~(get by per) him)
|
|
|
|
|%
|
2018-05-07 19:53:31 +03:00
|
|
|
++ this .
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +abet: finalize state changes, produce moves
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
|
|
|
++ abet
|
|
|
|
^- (quip move _^this)
|
|
|
|
:- (flop moz)
|
2018-10-30 22:05:42 +03:00
|
|
|
=? per ?=(^ rel)
|
|
|
|
(~(put by per) him u.rel)
|
|
|
|
^this
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +emit: emit a move
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
|
|
|
++ emit
|
2018-06-18 21:43:26 +03:00
|
|
|
|= car=card
|
2018-05-07 19:53:31 +03:00
|
|
|
^+ this
|
2018-06-18 21:43:26 +03:00
|
|
|
this(moz [[ost.bow car] moz])
|
2019-01-09 18:07:09 +03:00
|
|
|
:: +http-wire: build a wire for a |tell request
|
|
|
|
::
|
|
|
|
++ http-wire
|
|
|
|
|= [try=@ud act=@tas]
|
|
|
|
^- wire
|
|
|
|
/relay/him/(scot %p him)/try/(scot %ud try)/[act]
|
|
|
|
:: +http-crash: handle failed http request
|
|
|
|
::
|
|
|
|
++ http-crash
|
|
|
|
|= [=wire =tang]
|
|
|
|
^+ this
|
|
|
|
?> ?=([%try @ @ ~] wire)
|
|
|
|
=/ try (slav %ud i.t.wire)
|
|
|
|
=* act i.t.t.wire
|
|
|
|
?+ act
|
|
|
|
~&([%tell %unknown-crash act] this)
|
|
|
|
::
|
|
|
|
%check-before
|
|
|
|
:: XX confirm max retries
|
|
|
|
::
|
|
|
|
?: (gth try 3)
|
|
|
|
(fail %crash)
|
|
|
|
=. try +(try)
|
|
|
|
(emit (wait (http-wire try %check-before) (backoff try)))
|
|
|
|
::
|
|
|
|
%check-after
|
|
|
|
=/ msg
|
|
|
|
%+ rap 3
|
|
|
|
:~ 'failed to confirm binding '
|
|
|
|
(print-path t.wire)
|
|
|
|
', retrying in ~m10'
|
|
|
|
==
|
|
|
|
%- emit:(emit (notify our.bow msg tang))
|
|
|
|
:: no max retries, the binding has been created
|
|
|
|
:: XX notify after some number of failures
|
|
|
|
::
|
|
|
|
=. try +(try)
|
|
|
|
(wait (http-wire try %check-after) (max ~h1 (backoff try)))
|
|
|
|
==
|
|
|
|
:: +http-response: handle http response
|
|
|
|
::
|
|
|
|
++ http-response
|
|
|
|
|= [=wire rep=httr:eyre]
|
|
|
|
^+ this
|
|
|
|
?> ?=([%try @ @ ~] wire)
|
|
|
|
=/ try (slav %ud i.t.wire)
|
|
|
|
=* act i.t.t.wire
|
|
|
|
?+ act
|
|
|
|
~&([%tell %unknown-response act rep] this)
|
|
|
|
:: validating a binding target
|
|
|
|
::
|
|
|
|
%check-before
|
|
|
|
?: =(200 p.rep)
|
|
|
|
bind
|
|
|
|
:: cttp timeout
|
|
|
|
::
|
|
|
|
?: =(504 p.rep)
|
|
|
|
%- emit
|
|
|
|
=. try +(try)
|
|
|
|
(wait (http-wire try %check-before) (max ~h1 (backoff try)))
|
|
|
|
:: XX specific messages per status code
|
|
|
|
:: XX above some threshold?
|
|
|
|
::
|
|
|
|
(fail %failed-request)
|
|
|
|
:: validating an established binding
|
|
|
|
::
|
|
|
|
%check-after
|
|
|
|
?: =(200 p.rep)
|
|
|
|
bake
|
|
|
|
:: no max retries, the binding has been created
|
|
|
|
:: XX notify after some number of failures
|
|
|
|
::
|
|
|
|
%- emit
|
|
|
|
=. try +(try)
|
|
|
|
(wait (http-wire try %check-after) (max ~h1 (backoff try)))
|
|
|
|
==
|
|
|
|
:: +retry: re-attempt http request after timer
|
|
|
|
::
|
|
|
|
++ retry
|
|
|
|
|= =wire
|
|
|
|
^+ this
|
|
|
|
?> ?=([%try @ @ ~] wire)
|
|
|
|
=/ try (slav %ud i.t.wire)
|
|
|
|
=* act i.t.t.wire
|
|
|
|
?+ act
|
|
|
|
~&([%tell %unknown-wake act] this)
|
|
|
|
%check-before (check-before try)
|
|
|
|
%check-after (check-after try)
|
|
|
|
==
|
2018-10-30 22:05:42 +03:00
|
|
|
:: +hear: hear ip address, maybe emit binding request
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-06-18 22:59:36 +03:00
|
|
|
++ hear
|
2018-10-30 22:05:42 +03:00
|
|
|
|= addr=(unit @if)
|
2018-05-07 19:53:31 +03:00
|
|
|
^+ this
|
2018-06-16 05:44:37 +03:00
|
|
|
=/ tar=target
|
2018-10-30 22:05:42 +03:00
|
|
|
?: |(?=(~ addr) ?=(%duke (clan:title him)))
|
2018-06-16 05:44:37 +03:00
|
|
|
[%indirect our.bow]
|
2018-10-30 22:05:42 +03:00
|
|
|
[%direct %if u.addr]
|
2018-11-02 23:14:40 +03:00
|
|
|
:: re-notify if binding already exists
|
|
|
|
::
|
2018-12-21 02:18:21 +03:00
|
|
|
:: XX deduplicate with +bake:tell and +bond:bind
|
2018-11-02 23:14:40 +03:00
|
|
|
::
|
|
|
|
?: ?& ?=(^ rel)
|
|
|
|
?=(^ dom.u.rel)
|
|
|
|
=(tar tar.u.rel)
|
|
|
|
==
|
|
|
|
=/ wir=wire
|
|
|
|
/bound/(scot %p him)/for/(scot %p our.bow)
|
2018-11-07 08:25:49 +03:00
|
|
|
=/ com=command
|
|
|
|
[%bond our.bow him u.dom.u.rel]
|
|
|
|
(emit [%poke wir [him dap.bow] %dns-command com])
|
2018-11-02 23:14:40 +03:00
|
|
|
:: check binding target validity, store and forward
|
|
|
|
::
|
2019-01-09 23:08:46 +03:00
|
|
|
=. rel `[wen=now.bow addr dom=~ tar]
|
2019-01-09 18:07:09 +03:00
|
|
|
?: ?=(%indirect -.tar)
|
|
|
|
bind
|
|
|
|
(check-before 0)
|
|
|
|
:: +check-before: confirm %direct target is accessible
|
2018-06-19 20:44:31 +03:00
|
|
|
::
|
2019-01-09 18:07:09 +03:00
|
|
|
++ check-before
|
|
|
|
|= try=@ud
|
2018-06-19 20:44:31 +03:00
|
|
|
^+ this
|
|
|
|
?> ?=(^ rel)
|
|
|
|
?> ?=(%direct -.tar.u.rel)
|
2018-11-03 08:17:34 +03:00
|
|
|
?: (reserved:eyre p.tar.u.rel)
|
2018-06-19 20:44:31 +03:00
|
|
|
(fail %reserved-ip)
|
2019-01-09 18:07:09 +03:00
|
|
|
=/ =wire (http-wire try %check-before)
|
2018-06-19 20:44:31 +03:00
|
|
|
=/ url=purl:eyre
|
|
|
|
:- [sec=| por=~ host=[%| `@if`p.tar.u.rel]]
|
2018-10-31 01:19:34 +03:00
|
|
|
[[ext=`~.umd path=/static] query=~]
|
2019-01-09 18:07:09 +03:00
|
|
|
(emit (request wire url %get ~ ~))
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +fail: %direct target is invalid or inaccessible
|
2018-06-19 20:44:31 +03:00
|
|
|
::
|
|
|
|
++ fail
|
|
|
|
|= err=@tas
|
|
|
|
^+ this
|
|
|
|
?> ?=(^ rel)
|
2018-11-07 08:25:49 +03:00
|
|
|
:: XX add failure-specific messages
|
|
|
|
::
|
2018-12-21 07:45:59 +03:00
|
|
|
=/ msg
|
2018-06-19 20:44:31 +03:00
|
|
|
?+ err
|
2018-12-21 07:45:59 +03:00
|
|
|
'dns binding failed'
|
2018-06-19 20:44:31 +03:00
|
|
|
::
|
|
|
|
%reserved-ip
|
|
|
|
?> ?=(%direct -.tar.u.rel)
|
2018-12-21 07:45:59 +03:00
|
|
|
=/ addr (scot %if p.tar.u.rel)
|
|
|
|
(cat 3 'unable to create dns binding for reserved ip address' addr)
|
2018-06-19 20:44:31 +03:00
|
|
|
==
|
2018-11-07 08:25:49 +03:00
|
|
|
:: XX save failure state?
|
2018-10-31 01:19:34 +03:00
|
|
|
::
|
2018-12-21 07:45:59 +03:00
|
|
|
%- emit:(emit (notify him msg ~))
|
|
|
|
=/ msg
|
|
|
|
(rap 3 (scot %p him) ' fail: ' msg ~)
|
|
|
|
(notify our.bow msg ~)
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +bind: request binding for target
|
2018-06-19 20:44:31 +03:00
|
|
|
::
|
2018-10-30 07:42:39 +03:00
|
|
|
:: Since we may be an authority, we poke ourselves.
|
2018-06-19 20:44:31 +03:00
|
|
|
::
|
|
|
|
++ bind
|
|
|
|
^+ this
|
|
|
|
?> ?=(^ rel)
|
2018-11-07 08:25:49 +03:00
|
|
|
:: XX save binding request state?
|
|
|
|
::
|
2018-06-16 05:44:37 +03:00
|
|
|
=/ wir=wire
|
|
|
|
/bind/(scot %p him)/for/(scot %p our.bow)
|
2018-11-07 08:25:49 +03:00
|
|
|
=/ com=command
|
|
|
|
[%bind our.bow him tar.u.rel]
|
|
|
|
(emit [%poke wir [our.bow dap.bow] %dns-command com])
|
2019-01-09 18:07:09 +03:00
|
|
|
:: +learn: of new binding
|
2018-10-31 01:19:34 +03:00
|
|
|
::
|
2019-01-09 18:07:09 +03:00
|
|
|
++ learn
|
2018-10-31 01:19:34 +03:00
|
|
|
|= dom=turf
|
|
|
|
^+ this
|
|
|
|
?> ?=(^ rel)
|
|
|
|
:: XX track bound-state per-domain
|
|
|
|
::
|
2019-01-09 18:07:09 +03:00
|
|
|
(check-after(dom.u.rel `dom) 0)
|
|
|
|
:: +check-after: confirm binding propagation
|
2018-10-31 01:19:34 +03:00
|
|
|
::
|
2019-01-09 18:07:09 +03:00
|
|
|
++ check-after
|
|
|
|
|= try=@ud
|
2018-10-31 01:19:34 +03:00
|
|
|
^+ this
|
|
|
|
?> ?& ?=(^ rel)
|
|
|
|
?=(^ dom.u.rel)
|
|
|
|
==
|
2019-01-09 18:07:09 +03:00
|
|
|
=* dom u.dom.u.rel
|
|
|
|
=/ =wire (http-wire try %check-after)
|
|
|
|
=/ url=purl:eyre
|
|
|
|
:- [sec=| por=~ host=[%& dom]]
|
|
|
|
[[ext=`~.umd path=/static] query=~]
|
|
|
|
(emit (request wire url %get ~ ~))
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +bake: successfully bound
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-06-18 22:59:36 +03:00
|
|
|
++ bake
|
2018-05-07 19:53:31 +03:00
|
|
|
^+ this
|
|
|
|
?> ?=(^ rel)
|
2018-10-31 01:19:34 +03:00
|
|
|
?> ?=(^ dom.u.rel)
|
2018-06-19 20:26:00 +03:00
|
|
|
=/ wir=wire
|
|
|
|
/forward/bound/(scot %p him)/for/(scot %p our.bow)
|
2018-11-07 08:25:49 +03:00
|
|
|
=* dom u.dom.u.rel
|
|
|
|
=/ com=command
|
|
|
|
[%bond our.bow him dom]
|
2018-12-21 07:45:59 +03:00
|
|
|
=/ msg
|
|
|
|
(cat 3 'relaying new dns binding: ' (join '.' dom))
|
2018-11-07 08:25:49 +03:00
|
|
|
:: XX save notification state?
|
2018-10-31 01:19:34 +03:00
|
|
|
::
|
2018-12-21 07:45:59 +03:00
|
|
|
%- emit:(emit (notify our.bow msg ~))
|
2018-11-07 08:25:49 +03:00
|
|
|
[%poke wir [him dap.bow] %dns-command com]
|
2018-10-30 07:42:39 +03:00
|
|
|
:: +forward: sending binding request up the network
|
2018-05-07 19:53:31 +03:00
|
|
|
::
|
2018-06-18 22:59:36 +03:00
|
|
|
++ forward
|
2018-06-19 05:15:52 +03:00
|
|
|
|= [for=ship tar=target]
|
2018-05-07 19:53:31 +03:00
|
|
|
^+ this
|
2018-11-07 08:25:49 +03:00
|
|
|
?: ?=(%~zod our.bow)
|
2018-05-07 19:53:31 +03:00
|
|
|
this
|
2018-06-16 05:44:37 +03:00
|
|
|
=/ wir=wire
|
2018-06-19 05:15:52 +03:00
|
|
|
/forward/bind/(scot %p him)/for/(scot %p for)
|
2018-11-07 08:25:49 +03:00
|
|
|
=/ com=command
|
|
|
|
[%bind for him tar]
|
|
|
|
=/ to=ship
|
|
|
|
?: ?=(%czar (clan:title our.bow)) ~zod
|
|
|
|
(sein:title [our now our]:bow)
|
|
|
|
(emit [%poke wir [to dap.bow] %dns-command com])
|
2018-05-07 19:53:31 +03:00
|
|
|
--
|
|
|
|
--
|