Developer documentation

bernstein_eenv.hpp
Go to the documentation of this file.
1 /********************************************************************
2  * This file is part of the source code of the realroot library.
3  * Author(s): J.P. Pavone, GALAAD, INRIA
4  * $Id: eenv.hpp,v 1.1 2005/07/11 10:03:55 jppavone Exp $
5  ********************************************************************/
6 #ifndef realroot_SOLVE_SBDSLV_BERNSTEIN_EENV_H
7 #define realroot_SOLVE_SBDSLV_BERNSTEIN_EENV_H
8 //--------------------------------------------------------------------
9 #include <cstddef>
10 #include <iostream>
15 //--------------------------------------------------------------------
16 namespace mmx {
17 //--------------------------------------------------------------------
18 #ifndef _valueof_
19 #define _valueof_(x) std::cout << #x" = " << (x) << std::endl;
20 #endif
21 
22 namespace bernstein
23 {
24  struct eenv_base
25  {
26  typedef int sz_t;
27  sz_t m_nvr, * m_szs, * m_str;
28  protected:
29  inline void compute_strides()
30  {
31  m_str[m_nvr-1] = 1;
32  for ( int i = m_nvr-2; i >= -1; i-- ) m_str[i] = m_szs[i+1]*m_str[i+1];
33  };
34  public:
35  eenv_base( sz_t nvr = 0 ) { m_nvr = nvr; };
36  inline void set_szs( sz_t * szs ) { m_szs = szs; compute_strides(); };
37  inline sz_t sz( sz_t v ) const { return m_szs[v]; };
38  inline sz_t nvars() const { return m_nvr; };
39  inline sz_t data_size() const { return m_str[-1]; };
40 
41  template<typename real_t>
42  void hodograph( real_t * dst, real_t * src, int v )
43  {
44  int i,j;
45  int k;
46  int kstr = (m_szs[v]-1)*m_str[v];
47  for ( k = i = 0; i < data_size(); i += m_str[v-1], k += kstr )
48  for ( j = 0; j < m_str[v]; j++ )
49  brnops::hodograph(dst+k+j,src+i+j,m_szs[v],m_str[v]);
50  };
51 
52  template<typename X, typename real_t>
53  void copy( X * dst, real_t const * const src ) { std::copy(src, src + data_size(), dst ); };
54 
55  template<typename real_t>
56  real_t eval( real_t * data, const real_t * prm, real_t * chunk = 0 )
57  {
58  sz_t i,j;
59  real_t * tmp;
60  if ( chunk ) tmp = chunk;
61  else tmp = new real_t[ data_size() ];
62  std::copy(data,data+data_size(), tmp );
63  for ( int v = nvars()-1; v >= 0 ; v -- )
64  for ( i = 0; i <data_size(); i += m_str[v-1] )
65  brnops::decasteljau(tmp+i,m_szs[v],prm[v],m_str[v]);
66  real_t val = tmp[0];
67  if ( !chunk ) delete[] tmp;
68  return val;
69  };
70 
71  template<typename real_t, typename X>
72  void spmeval( X& res, real_t* src, X * prm, unsigned * supp, unsigned nsupp ) const
73  {
74  sz_t v, lg, d;
75  unsigned i,add,o;
76  lg = 0;
77  for ( v = 0; v < m_nvr; v ++ ) if ( m_szs[v] > m_szs[lg] ) lg = v;
78  X powers [m_nvr][m_szs[lg]];
79  X acc;
80  for ( v = 0; v < m_nvr; v ++ )
81  for ( powers[v][0] = 1.0, d = 1; d < m_szs[v]; powers[v][d] = prm[v]*powers[v][d-1], d ++ );
82  res = 0;
83  for ( i = 0; i < nsupp; res += acc, i ++ )
84  for ( add = supp[i], acc = src[add], v = m_nvr-1; add; add /= m_szs[v], v -- )
85  acc *= powers[v][add%m_szs[v]];
86  };
87 
88 
89  template<typename real_t,typename X>
90  void meval( X& res, real_t * data, const X * prm ) const
91  {
92  sz_t i;
93  X * tmp = new X[ data_size() ];
94  std::copy(data,data+data_size(),tmp);
95  for ( int v = nvars()-1; v >= 0 ; v -- )
96  for ( i = 0; i < data_size(); i += m_str[v-1] )
97  *(tmp+i) = univariate::horner(tmp+i,m_szs[v],prm[v],m_str[v]);
98  res = tmp[0];
99  delete[] tmp;
100  };
101 
102  template<typename real_t>
103  real_t monoms_eval( real_t * data, const real_t * prm ) const
104  {
105  sz_t i;
106  real_t * tmp = new real_t[ data_size() ];
107  std::copy(data,data+data_size(), tmp );
108  for ( int v = nvars()-1; v >= 0 ; v -- )
109  for ( i = 0; i < data_size(); i += m_str[v-1] )
110  *(tmp+i) = upoldse::horner(tmp+i,m_szs[v],prm[v],m_str[v]);
111  real_t val = tmp[0];
112  delete[] tmp;
113  return val;
114  };
115 
116 
117  template<typename real_t>
118  void mins( real_t * _mins_, real_t const * const data, sz_t v ) const
119  {
120  sz_t p,k,i,j;
121  for ( p = 0, k = 0; k < m_szs[v]; k++, p += m_str[v] )
122  {
123  _mins_[k] = data[p];
124  for ( i = 0; i < data_size(); i += m_str[v-1] )
125  for ( j = i; j < i + m_str[v]; j ++ )
126  if ( data[j+p] < _mins_[k] ) _mins_[k] = data[j+p];
127  };
128  };
129 
130  template<typename real_t>
131  void maxs( real_t * _maxs_, real_t const * const data, sz_t v ) const
132  {
133  sz_t p,k,i,j;
134 
135  for ( p = 0, k = 0; k < m_szs[v]; k++, p += m_str[v] )
136  {
137  _maxs_[k] = data[p];
138  for ( i = 0; i < data_size(); i += m_str[v-1] )
139  for ( j = i; j < i + m_str[v]; j ++ )
140  if ( data[j+p] > _maxs_[k] ) _maxs_[k] = data[j+p];
141  };
142  };
143 
144  template<typename real_t>
145  inline void maxs( real_t * _maxs_, real_t const * const data ) const
146  { for ( sz_t v = 0; v < m_nvr; v ++ ) { maxs(_maxs_,data,v); _maxs_ += m_szs[v];}; };
147 
148  template<typename real_t>
149  inline void mins( real_t * _mins_, real_t const * const data ) const
150  { for ( sz_t v = 0; v < m_nvr; v ++ ) { mins(_mins_,data,v); _mins_ += m_szs[v];}; };
151 
154  template<typename real_t>
155  void split( real_t * left, real_t * right, int v, const real_t& t )
156  {
157  int i,j,k;
158  for ( i = 0; i < data_size(); i += m_str[v-1] )
159  for ( j = i; j < i + m_str[v]; j++ )
160  split(left+j,right+j,m_szs[v],m_str[v],t);
161  };
162 
163  template<typename real_t>
164  void split2( real_t * left, real_t * right, int v )
165  {
166  int i,j;
167  for ( i = 0; i < data_size(); i += m_str[v-1] )
168  for ( j = i; j < i + m_str[v]; j++ )
169  split2(left+j,right+j,m_szs[v],m_str[v]);
170  };
171 
172  template<typename real_t>
173  void lrestrict( real_t * data, int v, const real_t& mn )
174  {
175  sz_t i,j;
176  for ( i = 0; i < data_size(); i += m_str[v-1] )
177  for ( j = i; j < i + m_str[v]; j++ )
178  brnops::lrestrict(data+j,m_szs[v],mn,m_str[v]);
179  };
180 
181  template<typename real_t>
182  void rrestrict( real_t * data, int v, const real_t& mx )
183  {
184  int i,j;
185  for ( i = 0; i < data_size(); i += m_str[v-1] )
186  for ( j = i; j < i + m_str[v]; j++ )
187  brnops::rrestrict(data+j,m_szs[v],mx,m_str[v]);
188  };
189 
190  template<typename real_t>
191  bool sgnchg( real_t * data ) { return vctops::sgnchg(data,data_size()); };
192 
193  template<typename real_t>
194  inline void scale( real_t * data ) { vctops::scale(data,data_size()); };
195 
196 
197  /* conversion sur [0,1]^n */
198 
199  /* monomiale -> bernstein */
200  template< typename real_t > /* conversion partielle */
201  void fromMonoms( real_t * data, sz_t v, bzenv<real_t> * env = bzenv<real_t>::_default_ )
202  {
203  sz_t i,j;
204  for ( i = 0; i < data_size(); i += m_str[v-1] )
205  for ( j = i; j < i + m_str[v]; j++ )
206  env->fromMonoms(data+j,m_szs[v],m_str[v]);
207  };
208  template< typename real_t > /* conversion complete */
209  inline void fromMonoms( real_t * data, bzenv<real_t> * env = bzenv<real_t>::_default_ ) { for ( sz_t v = 0; v < m_nvr; fromMonoms(data,v,env), v++ ); };
210 
211  /* bernstein -> monomiale */
212  template< typename real_t > /* conversion partielle */
213  void toMonoms( real_t * data, sz_t v, bzenv<real_t> * env = bzenv<real_t>::_default_ )
214  {
215  sz_t i,j;
216  for ( i = 0; i < data_size(); i += m_str[v-1] )
217  for ( j = i; j < i + m_str[v]; j++ )
218  env->toMonoms(data+j,m_szs[v],m_str[v]);
219  };
220  template< typename real_t > /* conversion complete */
221  inline void toMonoms( real_t * data, bzenv<real_t> * env = bzenv<real_t>::_default_ ) { for ( sz_t v = 0; v < m_nvr; toMonoms(data,v,env), v ++ ); };
222 
223 // template< typename real_t >
224 // void mshift( real_t * data, real_t * prm )
225 // {
226 // sz_t i,j;
227 // for ( i = 0; i < data_size(); i += m_str[v-1] )
228 // for ( j = i; j < i + m_str[v]; j++ )
229 // upoldse::shift(data+j,m_szs[v],m_str[v],prm[v]);
230 // };
231 
232  template< typename real_t >
233  real_t flatness( real_t * data, int v )
234  {
235  real_t m = 10;
236  sz_t i,j;
237  for ( i = 0; i < data_size(); i += m_str[v-1] )
238  for ( j = i; j < i + m_str[v]; j++ )
239  std::max(m,flatness(data+j,m_szs[v],m_str[v]) );
240  return m;
241  };
242  };
243 
244 
245  // eenv_base + dictionnaire local/global pour les variables
246  struct eenv : public eenv_base
247  {
249  struct add
250  {
251 
252  };
253  sz_t * m_vrs;
254  sz_t * m_pszs;
255  sz_t m_mxvr;
256  void _alloc_( sz_t nvr )
257  {
258  m_nvr = nvr;
259  m_szs = new sz_t[4*m_nvr+2];
260  m_vrs = m_szs + m_nvr;
261  m_str = m_vrs + m_nvr + 1;
262  m_pszs = m_str + m_nvr + 1;
263  };
264  eenv(){};
265  eenv( sz_t szu, sz_t szv )
266  {
267  _alloc_(2);
268  m_szs[0] = szu; m_szs[1] = szv;
269  m_vrs[0] = 0; m_vrs[1] = 1;
270  m_mxvr = 1;
271  compute_strides();
272  m_pszs[-1] = 0;
273  for ( sz_t v = 0; v < m_nvr; v ++ )
274  m_pszs[v] = m_pszs[v-1] + m_szs[v];
275  };
276 
277  eenv( sz_t nvr, sz_t const * szs, sz_t const * vrs )
278  {
279  _alloc_(nvr);
280  std::copy(szs,szs+m_nvr,m_szs);
281  std::copy(vrs,vrs+m_nvr,m_vrs);
282  compute_strides();
283  m_pszs[-1] = 0;
284  m_mxvr = m_vrs[0];
285  for (sz_t v = 0; v < m_nvr; v ++ ) if ( m_vrs[v] > m_mxvr ) m_mxvr = m_vrs[v];
286  for ( sz_t v = 0; v < m_nvr; v ++ )
287  m_pszs[v] = m_pszs[v-1] + m_szs[v];
288  };
289 
290  void swap( eenv& e )
291  {
292  std::swap(m_nvr,e_m.hpp_nvr);
293  std::swap(m_szs,e_m.hpp_szs);
294  std::swap(m_vrs,e_m.hpp_vrs);
295  std::swap(m_pszs,e_m.hpp_pszs);
296  std::swap(m_mxvr,e_m.hpp_mxvr);
297  };
298 
299  sz_t psz(){ return m_pszs[m_nvr-1]; };
300  sz_t psft( sz_t v ) { return m_pszs[v-1];}
301 
303  {
304  if ( nvars() ) delete[] m_szs;
305  m_nvr = 0;
306  };
307 
308  sz_t stride( sz_t v ) const { return m_str[v]; };
309  sz_t var ( sz_t v ) const { return m_vrs[v]; };
310 
311  int indexofvar( sz_t gv ) const
312  {
313  // if ( gv < m_vrs[0] || gv > m_vrs[m_nvr-1] ) return -1;
314  // remplacer par dichotomie ?
315  for ( sz_t v = 0; v < m_nvr; v ++ )
316  if ( m_vrs[v] == gv ) return v;
317  return -1;
318  };
319 
320  /* operations */
321  /* environement de diff(e,v), v est local a e */
322  void diff( eenv * e, sz_t v )
323  {
324  if ( nvars () ) this->~eenv();
325  _alloc_( e->nvars() );
326  std::copy( e->m_vrs, e->m_vrs+e->nvars(), m_vrs );
327  m_mxvr = e->m_mxvr;
328  for ( sz_t i = 0; i < m_nvr; m_szs[i] = e->sz(i), i ++ );
329  m_szs[v]--;
330  compute_strides();
331  };
332 
333  template<typename real_t>
334  static void mdiff( eenv * res, eenv * a, real_t * dst, real_t const * const src, int v )
335  {
336  sz_t is = 0;
337  for ( sz_t i = 0; i < res->data_size(); i += res->m_str[v-1], is += a->m_str[v-1] )
338  for ( sz_t j = 0; j < a->m_str[v]; j ++ )
339  upoldse::diff(dst+i+j,src+is+j,a->sz(v),a->m_str[v]);
340  };
341 
342  template<typename real_t>
343  static void monoms_derivative(eenv * res, eenv * a, real_t ** dst, real_t ** src, int v, int n = 1 )
344  {
345  res->diff(a,v);
346  for ( int c = 0; c < n; c ++ )
347  {
348  dst[c] = new real_t[ res->data_size() ];
349  mdiff( res, a, dst[c], src[c], v );
350  };
351  };
352 
355 
356  template<typename real_t>
357  bool print_monom( std::ostream& o, const real_t& c, sz_t * add, bool first )
358  {
359  if ( c )
360  {
361  if ( c < 0 ) o << "-";
362  else
363  if ( ! first ) o << "+";
364  o << std::abs(c);
365  for ( sz_t v = 0; v < nvars(); v ++ )
366  if ( add[var(v)] ) o << "*x" << var(v) << "^" << add[var(v)];
367  return true;
368  };
369  return false;
370  };
371 
372  template<typename real_t>
373  void monoms_print( std::ostream& o, real_t * src )
374  {
375  unsigned i;
376  unsigned mcount = 0;
377  int c;
378  sz_t add[m_mxvr+1];
379  std::fill(add,add+m_mxvr+1,0);
380  bool first = true;
381  for ( i = 0; i < data_size(); i ++ )
382  {
383  bool b = print_monom(o,src[i],add,first);
384  if ( first && b ) first = false;
385  mcount += b;
386  c = nvars()-1;
387  add[var(c)]++;
388  while ( c >0 && (add[var(c)] == m_szs[c]))
389  {
390  add[var(c)] = 0;
391  c--;
392  add[var(c)]++;
393  };
394  }
395  if ( mcount == 0 ) o << "0";
396  };
397 
398 
399 
400 
401  template<typename real_t>
402  static void elevation( eenv * out, eenv * in )
403  {
404 
405  };
406  template<typename real_t>
407  static void elevation( eenv * out, eenv * in, real_t * dst, real_t * src, bzenv< real_t > * bznv = bzenv<real_t>::_default_ )
408  {
409  sz_t io = 0;
410  sz_t v = 0;
411  for ( sz_t i = 0; i < in->data_size(); i += in->m_str[v-1], io += out->m_str[v-1] )
412  for ( sz_t j = 0; j < in->m_str[v]; j ++ )
413  bznv->elevate( dst + io + j, src + i + j , in->m_szs[v], in->m_str[v], out->m_str[v], out->m_szs[v]-in->m_szs[v] );
414  };
415 
417 
418  };
419 
420 
421  inline std::ostream& operator<<( std::ostream& out, const eenv& env )
422  {
423  out << "eenv:";
424  out << "\n\tszs = ";
425  vctops::print(env_m.hpp_szs,env_m.hpp_nvr,1,out);
426  out << "\n\tvrs = ";
427  vctops::print(env_m.hpp_vrs,env_m.hpp_nvr,1,out);
428  out << "\n";
429  out << "\n\ttsz = " << env.data_size() << std::endl;
430  return out;
431  };
432 };
433 //--------------------------------------------------------------------
434 } //namespace mmx
435 /********************************************************************/
436 #endif //
void hodograph(real_t *dst, real_t const *const src, unsigned sz, int st)
Definition: loops_brnops.hpp:138
sz_t * m_vrs
Definition: bernstein_eenv.hpp:253
void toMonoms(real_t *data, bzenv< real_t > *env=bzenv< real_t >::_default_)
Definition: bernstein_eenv.hpp:221
void fill(C *a, unsigned n, int s, const C &x)
Definition: tensor_vctops.hpp:152
const C & b
Definition: Interval_glue.hpp:25
void monoms_print(std::ostream &o, real_t *src)
Definition: bernstein_eenv.hpp:373
TMPL X
Definition: polynomial_operators.hpp:148
void scale(real_t *data)
Definition: bernstein_eenv.hpp:194
static void elevation(eenv *out, eenv *in)
Definition: bernstein_eenv.hpp:402
sz_t stride(sz_t v) const
Definition: bernstein_eenv.hpp:308
sz_t sz(sz_t v) const
Definition: bernstein_eenv.hpp:37
void compute_strides()
Definition: bernstein_eenv.hpp:29
MP swap(const MP &P, int var_i, int var_j)
Definition: sparse_monomials.hpp:988
static void mdiff(eenv *res, eenv *a, real_t *dst, real_t const *const src, int v)
Definition: bernstein_eenv.hpp:334
void decasteljau(real_t *r, unsigned sz, const real_t &t, int str=1)
Definition: loops_brnops.hpp:23
sz_t var(sz_t v) const
Definition: bernstein_eenv.hpp:309
void swap(eenv &e)
Definition: bernstein_eenv.hpp:290
void maxs(real_t *_maxs_, real_t const *const data, sz_t v) const
Definition: bernstein_eenv.hpp:131
static void elevation(eenv *out, eenv *in, real_t *dst, real_t *src, bzenv< real_t > *bznv=bzenv< real_t >::_default_)
Definition: bernstein_eenv.hpp:407
void toMonoms(real_t *data, sz_t v, bzenv< real_t > *env=bzenv< real_t >::_default_)
Definition: bernstein_eenv.hpp:213
void scale(real_t *src, unsigned sz, const real_t &sc=(real_t)(1.0), int st=1)
Definition: loops_vctops.hpp:216
void rrestrict(real_t *data, int sz, const real_t &t, int st)
Definition: loops_brnops.hpp:132
std::ostream & operator<<(std::ostream &out, const eenv &env)
Definition: bernstein_eenv.hpp:421
eenv_base(sz_t nvr=0)
Definition: bernstein_eenv.hpp:35
real_t eval(real_t *data, const real_t *prm, real_t *chunk=0)
Definition: bernstein_eenv.hpp:56
int indexofvar(sz_t gv) const
Definition: bernstein_eenv.hpp:311
void meval(X &res, real_t *data, const X *prm) const
Definition: bernstein_eenv.hpp:90
void lrestrict(real_t *data, int sz, const real_t &t, int st)
Definition: loops_brnops.hpp:123
sz_t m_nvr
Definition: bernstein_eenv.hpp:27
void fromMonoms(real_t *data, bzenv< real_t > *env=bzenv< real_t >::_default_)
Definition: bernstein_eenv.hpp:209
std::ostream & print(real_t const *const data, unsigned sz, int st=1, std::ostream &out=std::cout)
Definition: loops_vctops.hpp:130
void _alloc_(sz_t nvr)
Definition: bernstein_eenv.hpp:256
~eenv()
Definition: bernstein_eenv.hpp:302
void spmeval(X &res, real_t *src, X *prm, unsigned *supp, unsigned nsupp) const
Definition: bernstein_eenv.hpp:72
int sz_t
Definition: bernstein_eenv.hpp:26
void lrestrict(real_t *data, int v, const real_t &mn)
Definition: bernstein_eenv.hpp:173
void mins(real_t *_mins_, real_t const *const data, sz_t v) const
Definition: bernstein_eenv.hpp:118
Definition: bernstein_eenv.hpp:24
sz_t m_mxvr
Definition: bernstein_eenv.hpp:255
void split(real_t *left, real_t *right, int v, const real_t &t)
Definition: bernstein_eenv.hpp:155
TMPL void copy(Polynomial &r, const Polynomial &a)
Copy of a in r.
Definition: sparse_monomials.hpp:613
sz_t data_size() const
Definition: bernstein_eenv.hpp:39
void mins(real_t *_mins_, real_t const *const data) const
Definition: bernstein_eenv.hpp:149
bool in(const T &x, const Interval< T, r > &y)
Definition: Interval_fcts.hpp:100
void copy(X *dst, real_t const *const src)
Definition: bernstein_eenv.hpp:53
sz_t nvars() const
Definition: bernstein_eenv.hpp:38
eenv(sz_t nvr, sz_t const *szs, sz_t const *vrs)
Definition: bernstein_eenv.hpp:277
bool sgnchg(real_t const *const b, unsigned sz, int st=1)
Definition: loops_vctops.hpp:154
sz_t psft(sz_t v)
Definition: bernstein_eenv.hpp:300
sz_t * m_str
Definition: bernstein_eenv.hpp:27
void abs(Interval< C, r > &x, const Interval< C, r > &a)
Definition: Interval_fcts.hpp:185
real_t monoms_eval(real_t *data, const real_t *prm) const
Definition: bernstein_eenv.hpp:103
void diff(VECTOR1 &res, const VECTOR2 &pol)
Definition: bernstein_univariate.hpp:13
Definition: bernstein_eenv.hpp:246
void rrestrict(real_t *data, int v, const real_t &mx)
Definition: bernstein_eenv.hpp:182
void fromMonoms(real_t *data, sz_t v, bzenv< real_t > *env=bzenv< real_t >::_default_)
Definition: bernstein_eenv.hpp:201
sz_t * m_szs
Definition: bernstein_eenv.hpp:27
const C & c
Definition: Interval_glue.hpp:45
void diff(eenv *e, sz_t v)
Definition: bernstein_eenv.hpp:322
eenv()
Definition: bernstein_eenv.hpp:264
void set_szs(sz_t *szs)
Definition: bernstein_eenv.hpp:36
bool print_monom(std::ostream &o, const real_t &c, sz_t *add, bool first)
Definition: bernstein_eenv.hpp:357
void split2(real_t *left, real_t *right, int v)
Definition: bernstein_eenv.hpp:164
bool sgnchg(real_t *data)
Definition: bernstein_eenv.hpp:191
Definition: bernstein_bzenv.hpp:17
sz_t * m_pszs
Definition: bernstein_eenv.hpp:254
real_t flatness(real_t *data, int v)
Definition: bernstein_eenv.hpp:233
Interval< T, r > max(const Interval< T, r > &a, const Interval< T, r > &b)
Definition: Interval_fcts.hpp:135
Definition: array.hpp:12
sz_t psz()
Definition: bernstein_eenv.hpp:299
void add(dynamic_exp< E > &r, const dynamic_exp< E > &A, const dynamic_exp< E > &B)
Definition: dynamicexp.hpp:295
void maxs(real_t *_maxs_, real_t const *const data) const
Definition: bernstein_eenv.hpp:145
static void monoms_derivative(eenv *res, eenv *a, real_t **dst, real_t **src, int v, int n=1)
Definition: bernstein_eenv.hpp:343
eenv_base::sz_t sz_t
Definition: bernstein_eenv.hpp:248
eenv(sz_t szu, sz_t szv)
Definition: bernstein_eenv.hpp:265
Definition: bernstein_eenv.hpp:249
void horner(parm_t &res, coeff_t const *const mnms, unsigned sz, const parm_t &t, int st=1)
Definition: loops_upoldse.hpp:19
void hodograph(real_t *dst, real_t *src, int v)
Definition: bernstein_eenv.hpp:42
Home