~ubuntu-branches/debian/sid/scala/sid

« back to all changes in this revision

Viewing changes to test/files/pos/t4579.scala

  • Committer: Package Import Robot
  • Author(s): Emmanuel Bourg, Mehdi Dogguy, Lucas Satabin, Frank S. Thomas, Emmanuel Bourg
  • Date: 2015-06-05 23:52:59 UTC
  • mfrom: (1.2.11)
  • Revision ID: package-import@ubuntu.com-20150605235259-wk00vgk83dh8o19g
Tags: 2.10.5-1
* Team upload.

[ Mehdi Dogguy ]
* New upstream release (Closes: #744278).

[ Lucas Satabin ]
* Update patches
* Update the clean target
* Update paths of elements to install
* Update watch file

[ Frank S. Thomas ]
* Remove myself from Uploaders.

[ Emmanuel Bourg ]
* The package has been adopted by the Java Team (Closes: #754935)
* Patched the build to avoid downloading libraries from the Internet
* Replaced the minified JavaScript files with unobfuscated ones
* No longer build scala-partest.jar until diffutils is packaged or replaced
* debian/watch: Fixed the versions matched (x.y.z instead of x.y.z..z)
* debian/rules:
  - Added the missing get-orig-source target (Closes: #724704)
  - Improved the clean target
* debian/control:
  - Build depend on scala (>= 2.10) and bnd
  - Use canonical URLs for the Vcs-* fields
  - Standards-Version updated to 3.9.6 (no changes)
* Switch to debhelper level 9

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
//############################################################################
 
2
// Lisp interpreter (revived as an optimizer test.)
 
3
//############################################################################
 
4
 
 
5
//############################################################################
 
6
// Lisp Scanner
 
7
 
 
8
class LispTokenizer(s: String) extends Iterator[String] {
 
9
  private var i = 0;
 
10
  private def isDelimiter(ch: Char) = ch <= ' ' || ch == '(' || ch == ')'
 
11
  def hasNext: Boolean = {
 
12
    while (i < s.length() && s.charAt(i) <= ' ') i += 1
 
13
    i < s.length()
 
14
  }
 
15
  def next: String =
 
16
    if (hasNext) {
 
17
      val start = i
 
18
      if (isDelimiter(s charAt i)) i += 1
 
19
      else
 
20
        do i = i + 1
 
21
        while (!isDelimiter(s charAt i))
 
22
      s.substring(start, i)
 
23
    } else sys.error("premature end of string")
 
24
}
 
25
 
 
26
//############################################################################
 
27
// Lisp Interface
 
28
 
 
29
trait Lisp {
 
30
  type Data
 
31
 
 
32
  def string2lisp(s: String): Data
 
33
  def lisp2string(s: Data): String
 
34
 
 
35
  def evaluate(d: Data): Data
 
36
  // !!! def evaluate(s: String): Data = evaluate(string2lisp(s))
 
37
  def evaluate(s: String): Data
 
38
}
 
39
 
 
40
//############################################################################
 
41
// Lisp Implementation Using Case Classes
 
42
 
 
43
object LispCaseClasses extends Lisp {
 
44
 
 
45
  import List.range
 
46
 
 
47
  trait Data {
 
48
    def elemsToString(): String = toString();
 
49
  }
 
50
  case class CONS(car: Data, cdr: Data) extends Data {
 
51
    override def toString() = "(" + elemsToString() + ")";
 
52
    override def elemsToString() = car.toString() + (cdr match {
 
53
      case NIL() => ""
 
54
      case _     => " " + cdr.elemsToString();
 
55
    })
 
56
  }
 
57
  case class NIL() extends Data { // !!! use case object
 
58
    override def toString() = "()";
 
59
  }
 
60
  case class SYM(name: String) extends Data {
 
61
    override def toString() = name;
 
62
  }
 
63
  case class NUM(x: Int) extends Data {
 
64
    override def toString() = x.toString();
 
65
  }
 
66
  case class STR(x: String) extends Data {
 
67
    override def toString() = "\"" + x + "\"";
 
68
  }
 
69
  case class FUN(f: List[Data] => Data) extends Data {
 
70
    override def toString() = "<fn>";
 
71
  }
 
72
 
 
73
  def list(): Data =
 
74
    NIL();
 
75
  def list(x0: Data): Data =
 
76
    CONS(x0, NIL());
 
77
  def list(x0: Data, x1: Data): Data =
 
78
    CONS(x0, list(x1));
 
79
  def list(x0: Data, x1: Data, x2: Data): Data =
 
80
    CONS(x0, list(x1, x2));
 
81
  def list(x0: Data, x1: Data, x2: Data, x3: Data): Data =
 
82
    CONS(x0, list(x1, x2, x3));
 
83
  def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data): Data =
 
84
    CONS(x0, list(x1, x2, x3, x4));
 
85
  def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data): Data =
 
86
    CONS(x0, list(x1, x2, x3, x4, x5));
 
87
  def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data,
 
88
   x6: Data): Data =
 
89
    CONS(x0, list(x1, x2, x3, x4, x5, x6));
 
90
  def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data,
 
91
   x6: Data, x7: Data): Data =
 
92
    CONS(x0, list(x1, x2, x3, x4, x5, x6, x7));
 
93
  def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data,
 
94
   x6: Data, x7: Data, x8: Data): Data =
 
95
    CONS(x0, list(x1, x2, x3, x4, x5, x6, x7, x8));
 
96
  def list(x0: Data, x1: Data, x2: Data, x3: Data, x4: Data, x5: Data,
 
97
   x6: Data, x7: Data, x8: Data, x9: Data): Data =
 
98
    CONS(x0, list(x1, x2, x3, x4, x5, x6, x7, x8, x9));
 
99
 
 
100
  var curexp: Data = null
 
101
  var trace: Boolean = false
 
102
  var indent: Int = 0
 
103
 
 
104
  def lispError[a](msg: String): a =
 
105
    sys.error("error: " + msg + "\n" + curexp);
 
106
 
 
107
  trait Environment {
 
108
    def lookup(n: String): Data;
 
109
    def extendRec(name: String, expr: Environment => Data) =
 
110
      new Environment {
 
111
        def lookup(n: String): Data =
 
112
          if (n == name) expr(this) else Environment.this.lookup(n);
 
113
      }
 
114
    def extend(name: String, v: Data) = extendRec(name, (env1 => v));
 
115
  }
 
116
  val EmptyEnvironment = new Environment {
 
117
    def lookup(n: String): Data = lispError("undefined: " + n);
 
118
  }
 
119
 
 
120
  def toList(x: Data): List[Data] = x match {
 
121
    case NIL() => List()
 
122
    case CONS(y, ys) => y :: toList(ys)
 
123
    case _ => lispError("malformed list: " + x);
 
124
  }
 
125
 
 
126
  def toBoolean(x: Data) = x match {
 
127
    case NUM(0) => false
 
128
    case _ => true
 
129
  }
 
130
 
 
131
  def normalize(x: Data): Data = x match {
 
132
    case CONS(SYM("def"),
 
133
           CONS(CONS(SYM(name), args), CONS(body, CONS(expr, NIL())))) =>
 
134
      normalize(list(SYM("def"),
 
135
        SYM(name), list(SYM("lambda"), args, body), expr))
 
136
    case CONS(SYM("cond"), CONS(CONS(SYM("else"), CONS(expr, NIL())),NIL())) =>
 
137
      normalize(expr)
 
138
    case CONS(SYM("cond"), CONS(CONS(test, CONS(expr, NIL())), rest)) =>
 
139
      normalize(list(SYM("if"), test, expr, CONS(SYM("cond"), rest)))
 
140
    case CONS(h, t) => CONS(normalize(h), normalize(t))
 
141
    case _ => x
 
142
  }
 
143
 
 
144
  def eval(x: Data, env: Environment): Data = {
 
145
    val prevexp = curexp;
 
146
    curexp = x;
 
147
    if (trace) {
 
148
      for (x <- range(1, indent)) Console.print(" ");
 
149
      Console.println("===> " + x);
 
150
      indent = indent + 1;
 
151
    }
 
152
    val result = eval1(x, env);
 
153
    if (trace) {
 
154
      indent = indent - 1;
 
155
      for (x <- range(1, indent)) Console.print(" ");
 
156
      Console.println("<=== " + result);
 
157
    }
 
158
    curexp = prevexp;
 
159
    result
 
160
  }
 
161
 
 
162
  def eval1(x: Data, env: Environment): Data = x match {
 
163
    case SYM(name) =>
 
164
      env lookup name
 
165
    case CONS(SYM("def"), CONS(SYM(name), CONS(y, CONS(z, NIL())))) =>
 
166
      eval(z, env.extendRec(name, (env1 => eval(y, env1))))
 
167
    case CONS(SYM("val"), CONS(SYM(name), CONS(y, CONS(z, NIL())))) =>
 
168
      eval(z, env.extend(name, eval(y, env)))
 
169
    case CONS(SYM("lambda"), CONS(params, CONS(y, NIL()))) =>
 
170
      mkLambda(params, y, env)
 
171
    case CONS(SYM("if"), CONS(c, CONS(t, CONS(e, NIL())))) =>
 
172
      if (toBoolean(eval(c, env))) eval(t, env) else eval(e, env)
 
173
    case CONS(SYM("quote"), CONS(x, NIL())) =>
 
174
      x
 
175
    case CONS(y, xs) =>
 
176
      apply(eval(y, env), toList(xs) map (x => eval(x, env)))
 
177
    case NUM(_) => x
 
178
    case STR(_) => x
 
179
    case FUN(_) => x
 
180
    case _ =>
 
181
      lispError("illegal term")
 
182
    }
 
183
 
 
184
  def apply(fn: Data, args: List[Data]): Data = fn match {
 
185
    case FUN(f) => f(args);
 
186
    case _ => lispError("application of non-function: " + fn);
 
187
  }
 
188
 
 
189
  def mkLambda(params: Data, expr: Data, env: Environment): Data = {
 
190
 
 
191
    def extendEnv(env: Environment,
 
192
                  ps: List[String], args: List[Data]): Environment =
 
193
      Pair(ps, args) match {
 
194
        case Pair(List(), List()) =>
 
195
          env
 
196
        case Pair(p :: ps1, arg :: args1) =>
 
197
          extendEnv(env.extend(p, arg), ps1, args1)
 
198
        case _ =>
 
199
          lispError("wrong number of arguments")
 
200
      }
 
201
 
 
202
    val ps: List[String] = toList(params) map {
 
203
      case SYM(name) => name
 
204
      case _ => sys.error("illegal parameter list");
 
205
    }
 
206
 
 
207
    FUN(args => eval(expr, extendEnv(env, ps, args)))
 
208
  }
 
209
 
 
210
  val globalEnv = EmptyEnvironment
 
211
    .extend("=", FUN({
 
212
      case List(NUM(arg1),NUM(arg2)) => NUM(if (arg1 == arg2) 1 else 0)
 
213
      case List(STR(arg1),STR(arg2)) => NUM(if (arg1 == arg2) 1 else 0)}))
 
214
    .extend("+", FUN({
 
215
      case List(NUM(arg1),NUM(arg2)) => NUM(arg1 + arg2)
 
216
      case List(STR(arg1),STR(arg2)) => STR(arg1 + arg2)}))
 
217
    .extend("-", FUN({
 
218
      case List(NUM(arg1),NUM(arg2)) => NUM(arg1 - arg2)}))
 
219
    .extend("*", FUN({
 
220
      case List(NUM(arg1),NUM(arg2)) => NUM(arg1 * arg2)}))
 
221
    .extend("/", FUN({
 
222
      case List(NUM(arg1),NUM(arg2)) => NUM(arg1 / arg2)}))
 
223
    .extend("car", FUN({
 
224
      case List(CONS(x, xs)) => x}))
 
225
    .extend("cdr", FUN({
 
226
      case List(CONS(x, xs)) => xs}))
 
227
    .extend("null?", FUN({
 
228
      case List(NIL()) => NUM(1)
 
229
      case _ => NUM(0)}))
 
230
    .extend("cons", FUN({
 
231
      case List(x, y) => CONS(x, y)}));
 
232
 
 
233
  def evaluate(x: Data): Data = eval(normalize(x), globalEnv);
 
234
  def evaluate(s: String): Data = evaluate(string2lisp(s));
 
235
 
 
236
  def string2lisp(s: String): Data = {
 
237
    val it = new LispTokenizer(s);
 
238
    def parse(token: String): Data = {
 
239
      if (token == "(") parseList
 
240
      else if (token == ")") sys.error("unbalanced parentheses")
 
241
      else if ('0' <= token.charAt(0) && token.charAt(0) <= '9')
 
242
        NUM(token.toInt)
 
243
      else if (token.charAt(0) == '\"' && token.charAt(token.length()-1)=='\"')
 
244
        STR(token.substring(1,token.length() - 1))
 
245
      else SYM(token)
 
246
    }
 
247
    def parseList: Data = {
 
248
      val token = it.next;
 
249
      if (token == ")") NIL() else CONS(parse(token), parseList)
 
250
    }
 
251
    parse(it.next)
 
252
  }
 
253
 
 
254
  def lisp2string(d: Data): String = d.toString();
 
255
}
 
256
 
 
257
//############################################################################
 
258
// Lisp Implementation Using Any
 
259
 
 
260
object LispAny extends Lisp {
 
261
 
 
262
  import List._;
 
263
 
 
264
  type Data = Any;
 
265
 
 
266
  case class Lambda(f: List[Data] => Data);
 
267
 
 
268
  var curexp: Data = null;
 
269
  var trace: Boolean = false;
 
270
  var indent: Int = 0;
 
271
 
 
272
  def lispError[a](msg: String): a =
 
273
    sys.error("error: " + msg + "\n" + curexp);
 
274
 
 
275
  trait Environment {
 
276
    def lookup(n: String): Data;
 
277
    def extendRec(name: String, expr: Environment => Data) =
 
278
      new Environment {
 
279
        def lookup(n: String): Data =
 
280
          if (n == name) expr(this) else Environment.this.lookup(n);
 
281
      }
 
282
    def extend(name: String, v: Data) = extendRec(name, (env1 => v));
 
283
  }
 
284
  val EmptyEnvironment = new Environment {
 
285
    def lookup(n: String): Data = lispError("undefined: " + n);
 
286
  }
 
287
 
 
288
  def asList(x: Data): List[Data] = x match {
 
289
    case y: List[_] => y
 
290
    case _ => lispError("malformed list: " + x)
 
291
  }
 
292
 
 
293
  def asInt(x: Data): Int = x match {
 
294
    case y: Int => y
 
295
    case _ => lispError("not an integer: " + x)
 
296
  }
 
297
 
 
298
  def asString(x: Data): String = x match {
 
299
    case y: String => y
 
300
    case _ => lispError("not a string: " + x)
 
301
  }
 
302
 
 
303
  def asBoolean(x: Data): Boolean = x != 0
 
304
 
 
305
  def normalize(x: Data): Data = x match {
 
306
    case 'and :: x :: y :: Nil =>
 
307
      normalize('if :: x :: y :: 0 :: Nil)
 
308
    case 'or :: x :: y :: Nil =>
 
309
      normalize('if :: x :: 1 :: y :: Nil)
 
310
    case 'def :: (name :: args) :: body :: expr :: Nil =>
 
311
      normalize('def :: name :: ('lambda :: args :: body :: Nil) :: expr :: Nil)
 
312
    case 'cond :: ('else :: expr :: Nil) :: rest =>
 
313
        normalize(expr);
 
314
    case 'cond :: (test :: expr :: Nil) :: rest =>
 
315
        normalize('if :: test :: expr :: ('cond :: rest) :: Nil)
 
316
    case 'cond :: 'else :: expr :: Nil =>
 
317
      normalize(expr)
 
318
    case h :: t =>
 
319
      normalize(h) :: asList(normalize(t))
 
320
    case _ =>
 
321
      x
 
322
  }
 
323
 
 
324
  def eval(x: Data, env: Environment): Data = {
 
325
    val prevexp = curexp;
 
326
    curexp = x;
 
327
    if (trace) {
 
328
      for (x <- range(1, indent)) Console.print(" ");
 
329
      Console.println("===> " + x);
 
330
      indent += 1;
 
331
    }
 
332
    val result = eval1(x, env);
 
333
    if (trace) {
 
334
      indent -= 1;
 
335
      for (x <- range(1, indent)) Console.print(" ");
 
336
      Console.println("<=== " + result);
 
337
    }
 
338
    curexp = prevexp;
 
339
    result
 
340
  }
 
341
 
 
342
  def eval1(x: Data, env: Environment): Data = x match {
 
343
    case Symbol(name) =>
 
344
      env lookup name
 
345
    case 'def :: Symbol(name) :: y :: z :: Nil =>
 
346
      eval(z, env.extendRec(name, (env1 => eval(y, env1))))
 
347
    case 'val :: Symbol(name) :: y :: z :: Nil =>
 
348
      eval(z, env.extend(name, eval(y, env)))
 
349
    case 'lambda :: params :: y :: Nil =>
 
350
      mkLambda(params, y, env)
 
351
    case 'if :: c :: y :: z :: Nil =>
 
352
      if (asBoolean(eval(c, env))) eval(y, env) else eval(z, env)
 
353
    case 'quote :: y :: Nil =>
 
354
      y
 
355
    case y :: z =>
 
356
      apply(eval(y, env), z map (x => eval(x, env)))
 
357
    case Lambda(_) => x
 
358
    case y: String => x
 
359
    case y: Int => x
 
360
    case y => lispError("illegal term")
 
361
  }
 
362
 
 
363
  def lisp2string(x: Data): String = x match {
 
364
    case Symbol(name) => name
 
365
    case Nil => "()"
 
366
    case y :: ys =>
 
367
      def list2string(xs: List[Data]): String = xs match {
 
368
        case List() => ""
 
369
        case y :: ys => " " + lisp2string(y) + list2string(ys)
 
370
      }
 
371
      "(" + lisp2string(y) + list2string(ys) + ")"
 
372
    case _ => if (x.isInstanceOf[String]) "\"" + x + "\""; else x.toString()
 
373
  }
 
374
 
 
375
  def apply(fn: Data, args: List[Data]): Data = fn match {
 
376
    case Lambda(f) => f(args);
 
377
    case _ => lispError("application of non-function: " + fn + " to " + args);
 
378
  }
 
379
 
 
380
  def mkLambda(params: Data, expr: Data, env: Environment): Data = {
 
381
 
 
382
    def extendEnv(env: Environment,
 
383
                  ps: List[String], args: List[Data]): Environment =
 
384
      Pair(ps, args) match {
 
385
        case Pair(List(), List()) =>
 
386
          env
 
387
        case Pair(p :: ps1, arg :: args1) =>
 
388
          extendEnv(env.extend(p, arg), ps1, args1)
 
389
        case _ =>
 
390
          lispError("wrong number of arguments")
 
391
      }
 
392
 
 
393
    val ps: List[String] = asList(params) map {
 
394
      case Symbol(name) => name
 
395
      case _ => sys.error("illegal parameter list");
 
396
    }
 
397
 
 
398
    Lambda(args => eval(expr, extendEnv(env, ps, args)))
 
399
  }
 
400
 
 
401
  val globalEnv = EmptyEnvironment
 
402
    .extend("=", Lambda{
 
403
      case List(arg1, arg2) => if(arg1 == arg2) 1 else 0})
 
404
    .extend("+", Lambda{
 
405
      case List(arg1: Int, arg2: Int) => arg1 + arg2
 
406
      case List(arg1: String, arg2: String) => arg1 + arg2})
 
407
    .extend("-", Lambda{
 
408
      case List(arg1: Int, arg2: Int) => arg1 - arg2})
 
409
    .extend("*", Lambda{
 
410
      case List(arg1: Int, arg2: Int) => arg1 * arg2})
 
411
    .extend("/", Lambda{
 
412
      case List(arg1: Int, arg2: Int) => arg1 / arg2})
 
413
    .extend("nil", Nil)
 
414
    .extend("cons", Lambda{
 
415
      case List(arg1, arg2) => arg1 :: asList(arg2)})
 
416
    .extend("car", Lambda{
 
417
      case List(x :: xs) => x})
 
418
    .extend("cdr", Lambda{
 
419
      case List(x :: xs) => xs})
 
420
    .extend("null?", Lambda{
 
421
      case List(Nil) => 1
 
422
      case _ => 0});
 
423
 
 
424
  def evaluate(x: Data): Data = eval(normalize(x), globalEnv);
 
425
  def evaluate(s: String): Data = evaluate(string2lisp(s));
 
426
 
 
427
  def string2lisp(s: String): Data = {
 
428
    val it = new LispTokenizer(s);
 
429
    def parse(token: String): Data = {
 
430
      if (token == "(") parseList
 
431
      else if (token == ")") sys.error("unbalanced parentheses")
 
432
      //else if (Character.isDigit(token.charAt(0)))
 
433
      else if (token.charAt(0).isDigit)
 
434
        token.toInt
 
435
      else if (token.charAt(0) == '\"' && token.charAt(token.length()-1)=='\"')
 
436
        token.substring(1,token.length() - 1)
 
437
      else Symbol(token)
 
438
    }
 
439
    def parseList: List[Data] = {
 
440
      val token = it.next;
 
441
      if (token == ")") Nil else parse(token) :: parseList
 
442
    }
 
443
    parse(it.next)
 
444
  }
 
445
}
 
446
 
 
447
//############################################################################
 
448
// List User
 
449
 
 
450
class LispUser(lisp: Lisp) {
 
451
 
 
452
  import lisp._;
 
453
 
 
454
  def evaluate(s: String) = lisp2string(lisp.evaluate(s));
 
455
 
 
456
  def run = {
 
457
 
 
458
    Console.println(string2lisp("(lambda (x) (+ (* x x) 1))").asInstanceOf[AnyRef]);
 
459
    Console.println(lisp2string(string2lisp("(lambda (x) (+ (* x x) 1))")));
 
460
    Console.println;
 
461
 
 
462
    Console.println("(    '(1 2 3)) = " + evaluate("     (quote(1 2 3))"));
 
463
    Console.println("(car '(1 2 3)) = " + evaluate("(car (quote(1 2 3)))"));
 
464
    Console.println("(cdr '(1 2 3)) = " + evaluate("(cdr (quote(1 2 3)))"));
 
465
    Console.println("(null? '(2 3)) = " + evaluate("(null? (quote(2 3)))"));
 
466
    Console.println("(null?    '()) = " + evaluate("(null?    (quote()))"));
 
467
    Console.println;
 
468
 
 
469
    Console.println("faculty(10) = " + evaluate(
 
470
      "(def (faculty n) " +
 
471
        "(if (= n 0) " +
 
472
          "1 " +
 
473
          "(* n (faculty (- n 1)))) " +
 
474
        "(faculty 10))"));
 
475
    Console.println("faculty(10) = " + evaluate(
 
476
      "(def (faculty n) " +
 
477
        "(cond " +
 
478
          "((= n 0) 1) " +
 
479
          "(else (* n (faculty (- n 1))))) " +
 
480
        "(faculty 10))"));
 
481
    Console.println("foobar = " + evaluate(
 
482
      "(def (foo n) " +
 
483
        "(cond " +
 
484
          "((= n 0) \"a\")" +
 
485
          "((= n 1) \"b\")" +
 
486
          "((= (/ n 2) 1) " +
 
487
            "(cond " +
 
488
              "((= n 2) \"c\")" +
 
489
              "(else    \"d\")))" +
 
490
          "(else " +
 
491
            "(def (bar m) " +
 
492
              "(cond " +
 
493
                "((= m 0) \"e\")" +
 
494
                "((= m 1) \"f\")" +
 
495
                "(else    \"z\"))" +
 
496
              "(bar (- n 4)))))" +
 
497
        "(val nil (quote ())" +
 
498
          "(val v1 (foo 0) " +
 
499
            "(val v2 (+ (foo 1) (foo 2)) " +
 
500
              "(val v3 (+ (+ (foo 3) (foo 4)) (foo 5)) " +
 
501
                "(val v4 (foo 6) " +
 
502
                  "(cons v1 (cons v2 (cons v3 (cons v4 nil))))))))))"));
 
503
    Console.println;
 
504
  }
 
505
}
 
506
 
 
507
//############################################################################
 
508
// Main
 
509
 
 
510
object Test {
 
511
  def main(args: Array[String]) {
 
512
    new LispUser(LispCaseClasses).run;
 
513
    new LispUser(LispAny).run;
 
514
    ()
 
515
  }
 
516
}
 
517
 
 
518
//############################################################################