File Coverage

blib/lib/RxPerl/Operators/Creation.pm
Criterion Covered Total %
statement 329 377 87.2
branch 80 150 53.3
condition 18 27 66.6
subroutine 58 65 89.2
pod n/a
total 485 619 78.3


line stmt bran cond sub pod time code
1             package RxPerl::Operators::Creation;
2              
3 5     5   88 use v5.10;
  5         20  
4 5     5   25 use strict;
  5         19  
  5         196  
5 5     5   25 use warnings;
  5         11  
  5         390  
6              
7 5     5   2585 use RxPerl::Observable;
  5         17  
  5         217  
8 5     5   33 use RxPerl::Subscription;
  5         10  
  5         140  
9 5     5   2459 use RxPerl::Utils 'get_timer_subs', 'get_interval_subs';
  5         22  
  5         361  
10 5     5   2689 use RxPerl::Subject;
  5         14  
  5         226  
11 5     5   2469 use RxPerl::BehaviorSubject;
  5         36  
  5         216  
12 5     5   2672 use RxPerl::ReplaySubject;
  5         15  
  5         221  
13              
14 5     5   32 use Carp 'croak';
  5         9  
  5         331  
15 5     5   49 use Scalar::Util qw/ weaken blessed reftype /;
  5         10  
  5         304  
16 5     5   29 use List::Util 'first';
  5         8  
  5         310  
17              
18 5     5   26 use Exporter 'import';
  5         10  
  5         654  
19             our @EXPORT_OK = qw/
20             rx_behavior_subject rx_combine_latest rx_concat rx_defer rx_EMPTY rx_fork_join rx_from rx_from_event
21             rx_from_event_array rx_generate rx_iif rx_interval rx_merge rx_NEVER rx_observable rx_of rx_on_error_resume_next
22             rx_partition rx_race rx_range rx_replay_subject rx_subject rx_throw_error rx_timer rx_zip
23             /;
24             our %EXPORT_TAGS = (all => \@EXPORT_OK);
25              
26             our $VERSION = "v6.29.8";
27              
28 5     5   33 use constant rx_observable => 'RxPerl::Observable';
  5         77  
  5         419  
29 5     5   37 use constant rx_behavior_subject => 'RxPerl::BehaviorSubject';
  5         10  
  5         354  
30 5     5   73 use constant rx_replay_subject => 'RxPerl::ReplaySubject';
  5         10  
  5         313  
31 5     5   26 use constant rx_subject => 'RxPerl::Subject';
  5         9  
  5         28588  
32              
33             sub rx_combine_latest {
34 2     2   26 my ($sources) = @_;
35              
36             return rx_observable->new(sub {
37 2     2   5 my ($subscriber) = @_;
38              
39 2         8 my $sources = [@$sources];
40              
41 2         4 my %own_subscriptions;
42 2         6 my $i = 0;
43 2         7 my %didnt_emit = map {($i++, 1)} @$sources;
  4         19  
44 2         6 my @latest_values;
45 2         8 my $num_active = @$sources;
46              
47             $subscriber->subscription->add(
48 2         8 \%own_subscriptions, sub { undef @$sources },
49 2         151 );
50              
51 2         10 for (my $i = 0; $i < @$sources; $i++) {
52 4         10 my $j = $i;
53 4         10 my $source = $sources->[$j];
54 4         16 my $own_subscription = RxPerl::Subscription->new;
55 4         14 $own_subscriptions{$own_subscription} = $own_subscription;
56             my $own_observer = {
57             new_subscription => $own_subscription,
58             next => sub {
59 14         57 my ($value) = @_;
60              
61 14         31 $latest_values[$j] = $value;
62 14         31 delete $didnt_emit{$j};
63              
64 14 100       40 if (!%didnt_emit) {
65 12 50       62 $subscriber->{next}->([@latest_values]) if defined $subscriber->{next};
66             }
67             },
68             error => $subscriber->{error},
69             complete => sub {
70 4         9 $num_active--;
71 4 100       30 if ($num_active == 0) {
72 2 50       10 $subscriber->{complete}->() if defined $subscriber->{complete};
73             }
74             },
75 4         65 };
76 4         17 $source->subscribe($own_observer);
77             }
78              
79 2         7 return;
80 2         21 });
81             }
82              
83             sub _rx_concat_helper {
84 87     87   189 my ($sources, $subscriber, $active) = @_;
85              
86 87 100       184 if (! @$sources) {
87 5 50       30 $subscriber->{complete}->() if defined $subscriber->{complete};
88 5         14 return;
89             }
90              
91 82         127 my $source = shift @$sources;
92 82         203 my $own_subscription = RxPerl::Subscription->new;
93             my $own_subscriber = {
94             new_subscription => $own_subscription,
95             next => $subscriber->{next},
96             error => $subscriber->{error},
97             complete => sub {
98 47     47   117 _rx_concat_helper($sources, $subscriber, $active);
99             },
100 82         395 };
101 82         195 @$active = ($own_subscription);
102 82         228 $source->subscribe($own_subscriber);
103             }
104              
105             sub rx_concat {
106 32     32   103 my @sources = @_;
107              
108             return rx_observable->new(sub {
109 40     40   72 my ($subscriber) = @_;
110              
111 40         99 my @sources = @sources;
112              
113 40         57 my @active;
114             $subscriber->subscription->add(
115 40         143 \@active, sub { undef @sources },
116 40         96 );
117              
118 40         156 _rx_concat_helper(\@sources, $subscriber, \@active);
119              
120 40         92 return;
121 32         136 });
122             }
123              
124             sub rx_defer {
125 11     11   16 my ($observable_factory) = @_;
126              
127             return rx_observable->new(sub {
128 10     10   16 my ($subscriber) = @_;
129              
130 10         18 my $observable = $observable_factory->();
131              
132 10         25 return $observable->subscribe($subscriber);
133 11         43 });
134             }
135              
136             sub rx_EMPTY {
137             state $rx_EMPTY = rx_observable->new(sub {
138 9     9   15 my ($subscriber) = @_;
139              
140 9 50       33 $subscriber->{complete}->() if defined $subscriber->{complete};
141              
142 9         13 return;
143 9     9   6983 });
144             }
145              
146             sub rx_fork_join {
147 4     4   5 my ($sources) = @_;
148              
149 4   66     17 my $arg_is_array = !(blessed $sources) && (reftype $sources eq 'ARRAY');
150 4   66     9 my $arg_is_hash = !(blessed $sources) && (reftype $sources eq 'HASH');
151              
152 4 50 66     15 croak "argument of rx_fork_join needs to be either an arrayref or a hashref"
153             unless $arg_is_array or $arg_is_hash;
154              
155 4 100       8 if ($arg_is_array) {
156 2         2 my $i = 0;
157 2         4 $sources = { map {($i++, $_)} @$sources };
  7         15  
158             }
159              
160             return rx_observable->new(sub {
161 4     4   6 my ($subscriber) = @_;
162              
163 4         12 my $sources = { %$sources };
164 4         5 my %last_values;
165             my %own_subscriptions;
166 4         8 my @keys = keys %$sources;
167 4 100       13 @keys = sort {$a <=> $b} @keys if $arg_is_array;
  8         14  
168              
169             $subscriber->subscription->add(
170 4         10 \%own_subscriptions, sub { undef @keys },
171 4         9 );
172              
173 4 50       8 if (! @keys) {
174 0 0       0 $subscriber->{complete}->() if defined $subscriber->{complete};
175 0         0 return;
176             }
177              
178 4         9 for (my $i = 0; $i < @keys; $i++) {
179 13         19 my $key = $keys[$i];
180 13         17 my $source = $sources->{$key};
181 13         18 my $own_subscription = RxPerl::Subscription->new;
182 13         26 $own_subscriptions{$own_subscription} = $own_subscription;
183             $source->subscribe({
184             new_subscription => $own_subscription,
185             next => sub {
186 33         75 $last_values{$key} = $_[0];
187             },
188             error => $subscriber->{error},
189             complete => sub {
190 13 100       21 if (exists $last_values{$key}) {
191 11 100       28 if (keys(%last_values) == keys %$sources) {
192 2 100       4 if ($arg_is_array) {
193 1         1 my @ret;
194 1         5 $ret[$_] = $last_values{$_} foreach keys %last_values;
195 1 50       5 $subscriber->{next}->(\@ret) if defined $subscriber->{next};
196             }
197             else {
198 1 50       4 $subscriber->{next}->(\%last_values) if defined $subscriber->{next};
199             }
200 2 50       6 $subscriber->{complete}->() if defined $subscriber->{complete};
201             }
202             } else {
203 2 50       6 $subscriber->{complete}->() if defined $subscriber->{complete};
204             }
205             },
206 13         67 });
207             }
208              
209 4         10 return;
210 4         18 });
211             }
212              
213             sub rx_from {
214 8     8   309895 my ($thing) = @_;
215              
216 8 100 100     153 if (blessed $thing and $thing->isa('RxPerl::Observable')) {
    50 66        
    100 66        
    100 66        
    50 33        
217 1         11 return $thing;
218             }
219              
220             elsif (blessed $thing and $thing->isa('Future')) {
221             return rx_observable->new(sub {
222 0     0   0 my ($subscriber) = @_;
223              
224             $thing->on_done(sub {
225 0 0       0 $subscriber->{next}->(splice @_, 0, 1) if defined $subscriber->{next};
226 0 0       0 $subscriber->{complete}->() if defined $subscriber->{complete};
227 0         0 });
228              
229             $thing->on_fail(sub {
230 0 0       0 $subscriber->{error}->(splice @_, 0, 1) if defined $subscriber->{error};
231 0         0 });
232              
233             $thing->on_ready(sub {
234 0 0       0 if ($thing->is_cancelled) {
235 0 0       0 $subscriber->{complete}->() if defined $subscriber->{complete};
236             }
237 0         0 });
238 0         0 });
239             }
240              
241             elsif (blessed $thing and $thing->can('then')) {
242             return rx_observable->new(sub {
243 5     5   12 my ($subscriber) = @_;
244              
245             $thing->then(
246             sub {
247 5 50       384 $subscriber->{next}->(splice @_, 0, 1) if defined $subscriber->{next};
248 5 100       15 $subscriber->{complete}->() if defined $subscriber->{complete};
249             },
250             sub {
251 0 0       0 $subscriber->{error}->(splice @_, 0, 1) if defined $subscriber->{error};
252             },
253 5         23 );
254              
255 5         248 return;
256 5         22 });
257             }
258              
259             elsif (ref $thing eq 'ARRAY' and ! blessed $thing) {
260 1         7 return rx_of(@$thing);
261             }
262              
263             elsif (defined $thing and ! length(ref $thing)) {
264 1         8 my @letters = split //, $thing;
265 1         83 return rx_of(@letters);
266             }
267              
268             else {
269 0         0 croak "rx_from only accepts arrayrefs, promises, observables, and strings as argument at the moment,";
270             }
271             }
272              
273             # NOTE: rx_from_event and rx_from_event_array keep a weak reference to the
274             # EventEmitter $object. Should this change? TODO: think about that.
275              
276             sub rx_from_event {
277 0     0   0 my ($object, $event_type) = @_;
278              
279 0 0       0 croak 'invalid object type, at rx_from_event' if not $object->isa('Mojo::EventEmitter');
280              
281 0         0 weaken($object);
282             return rx_observable->new(sub {
283 0     0   0 my ($subscriber) = @_;
284              
285             my $cb = sub {
286 0         0 my ($e, @args) = @_;
287              
288 0 0       0 $subscriber->{next}->(splice @args, 0, 1) if defined $subscriber->{next};
289 0         0 };
290              
291             $subscriber->subscription->add(sub {
292 0 0       0 $object->unsubscribe($event_type, $cb) if defined $object;
293 0         0 });
294              
295 0         0 $object->on($event_type, $cb);
296              
297 0         0 return;
298 0         0 });
299             }
300              
301             sub rx_from_event_array {
302 0     0   0 my ($object, $event_type) = @_;
303              
304 0 0       0 croak 'invalid object type, at rx_from_event_array' if not $object->isa('Mojo::EventEmitter');
305              
306 0         0 weaken($object);
307             return rx_observable->new(sub {
308 0     0   0 my ($subscriber) = @_;
309              
310             my $cb = sub {
311 0         0 my ($e, @args) = @_;
312              
313 0 0       0 $subscriber->{next}->([@args]) if defined $subscriber->{next};
314 0         0 };
315              
316             $subscriber->subscription->add(sub {
317 0 0       0 $object->unsubscribe($event_type, $cb) if defined $object;
318 0         0 });
319              
320 0         0 $object->on($event_type, $cb);
321              
322 0         0 return;
323 0         0 });
324             }
325              
326             sub rx_generate {
327 1     1   3450 my ($initial, $condition, $iterate, $result_selector) = @_;
328              
329             return rx_observable->new(sub {
330 1     1   3 my ($subscriber) = @_;
331              
332 1         2 my $must_finish = 0;
333              
334 1         3 $subscriber->subscription->add(sub { $must_finish = 1 });
  1         2  
335              
336 1         2 my $x = $initial;
337 1         2 while (1) {
338 6 50       9 ! $must_finish or last;
339 6         6 my $cond; my $ok = eval { local $_ = $x; $cond = $condition->($x); 1 };
  6         6  
  6         4  
  6         11  
  6         13  
340 6 50       10 if (! $ok) {
341 0 0       0 $subscriber->{error}->($@) if defined $subscriber->{error};
342 0         0 last;
343             }
344 6 100       7 if (! $cond) {
345 1 50       3 $subscriber->{complete}->() if defined $subscriber->{complete};
346 1         3 last;
347             }
348 5 50       6 my $output_val; $ok = eval { local $_ = $x; $output_val = $result_selector ? $result_selector->($x) : $x; 1 };
  5         6  
  5         3  
  5         11  
  5         12  
349 5 50       7 if (! $ok) {
350 0 0       0 $subscriber->{error}->($@) if defined $subscriber->{error};
351 0         0 last;
352             }
353 5 50       14 $subscriber->{next}->($output_val) if defined $subscriber->{next};
354 5         7 $ok = eval { local $_ = $x; $x = $iterate->($x); 1 };
  5         4  
  5         7  
  5         9  
355 5 50       8 if (! $ok) {
356 0 0       0 $subscriber->{error}->($@) if defined $subscriber->{error};
357 0         0 last;
358             }
359             }
360 1         8 });
361             }
362              
363             sub rx_iif {
364 1     1   3 my ($condition, $true_result, $false_result) = @_;
365              
366             return rx_defer(sub {
367 2 100   2   6 return $condition->() ? $true_result : $false_result;
368 1         6 });
369             }
370              
371             sub rx_interval {
372 67     67   342552 my ($after) = @_;
373              
374 67         169 my ($interval_sub, $cancel_interval_sub) = get_interval_subs;
375              
376             return rx_observable->new(sub {
377 51     51   85 my ($subscriber) = @_;
378              
379 51         72 my $counter = 0;
380             my $timer = $interval_sub->($after, sub {
381 185 50       545 $subscriber->{next}->($counter++) if defined $subscriber->{next};
382 51         195 });
383              
384             return sub {
385 51         111 $cancel_interval_sub->($timer);
386 51         178 };
387 67         392 });
388             }
389              
390             sub rx_merge {
391 201     201   504 my @sources = @_;
392              
393             return rx_observable->new(sub {
394 212     212   455 my ($subscriber) = @_;
395              
396 212         483 my @sources = @sources;
397              
398 212         292 my %own_subscriptions;
399             $subscriber->subscription->add(
400             \%own_subscriptions,
401 212         651 sub { @sources = () },
402 212         540 );
403              
404 212         423 my $num_active_subscriptions = @sources;
405 212 50 66     748 $num_active_subscriptions or $subscriber->{complete}->() if defined $subscriber->{complete};
406              
407 212         524 for (my $i = 0; $i < @sources; $i++) {
408 831         1269 my $source = $sources[$i];
409 831         1863 my $own_subscription = RxPerl::Subscription->new;
410 831         2199 $own_subscriptions{$own_subscription} = $own_subscription;
411             my $own_subscriber = {
412             new_subscription => $own_subscription,
413             next => $subscriber->{next},
414             error => $subscriber->{error},
415             complete => sub {
416 753         1833 delete $own_subscriptions{$own_subscription};
417 753 100       1655 if (! --$num_active_subscriptions) {
418 165 50       495 $subscriber->{complete}->() if defined $subscriber->{complete};
419             }
420             },
421 831         4104 };
422 831         2178 $source->subscribe($own_subscriber);
423             }
424              
425 212         496 return;
426 201         994 });
427             }
428              
429             sub rx_NEVER {
430 0     0   0 state $rx_never = rx_observable->new(sub { return });
  0     0   0  
431             }
432              
433             sub rx_of {
434 761     761   90877 my (@values) = @_;
435              
436             return rx_observable->new(sub {
437 814     814   1329 my ($subscriber) = @_;
438              
439 814         1100 my $i = 0;
440              
441 814         1710 $subscriber->subscription->add(sub { $i = @values });
  814         1941  
442              
443 814         1876 for (; $i < @values; $i++) {
444 957 50       3031 $subscriber->{next}->($values[$i]) if defined $subscriber->{next};
445             }
446              
447 814 100       2835 $subscriber->{complete}->() if defined $subscriber->{complete};
448              
449 814         2143 return;
450 761         3990 });
451             }
452              
453             sub _rx_on_error_resume_next_helper {
454 10     10   59 my ($sources, $subscriber, $active) = @_;
455              
456 10 100       17 if (! @$sources) {
457 2 50       7 $subscriber->{complete}->() if defined $subscriber->{complete};
458 2         4 return;
459             }
460              
461 8         10 my $source = shift @$sources;
462 8         18 my $own_subscription = RxPerl::Subscription->new;
463             my $own_subscriber = {
464             new_subscription => $own_subscription,
465             next => $subscriber->{next},
466             error => sub {
467 6     6   12 _rx_on_error_resume_next_helper($sources, $subscriber, $active);
468             },
469             complete => sub {
470 2     2   6 _rx_on_error_resume_next_helper($sources, $subscriber, $active);
471             },
472 8         32 };
473 8         17 @$active = ($own_subscription);
474 8         34 $source->subscribe($own_subscriber);
475             }
476              
477             sub rx_on_error_resume_next {
478 2     2   5 my @sources = @_;
479              
480             return rx_observable->new(sub {
481 2     2   3 my ($subscriber) = @_;
482              
483 2         4 my @sources = @sources;
484              
485 2         3 my @active;
486             $subscriber->subscription->add(
487 2         6 \@active, sub { undef @sources },
488 2         4 );
489              
490 2         6 _rx_on_error_resume_next_helper(\@sources, $subscriber, \@active);
491              
492 2         3 return;
493 2         5 });
494             }
495              
496             sub rx_partition {
497 2     2   14 my ($source, $predicate) = @_;
498              
499 2         8 my $o1 = $source->pipe(
500             RxPerl::Operators::Pipeable::op_filter($predicate),
501             );
502              
503 2         3 my $i = 0;
504             my $o2 = $source->pipe(
505             RxPerl::Operators::Pipeable::op_filter(sub {
506 20     20   49 return not $predicate->($_[0], $i++);
507 2         8 }),
508             );
509              
510 2         13 return ($o1, $o2);
511             }
512              
513             sub rx_race {
514 2     2   12 my (@sources) = @_;
515              
516             return rx_observable->new(sub {
517 2     2   5 my ($subscriber) = @_;
518             # TODO: experiment in the end with passing a second parameter here, an arrayref, called \@early_return_values
519             # TODO: like: my ($subscriber, $early_return_values) = @_; and then push @$early_return_values, sub {...};
520              
521 2         33 my @sources = @sources;
522              
523 2         5 my @own_subscriptions;
524 2         10 $subscriber->subscription->add(\@own_subscriptions);
525              
526 2         10 for (my $i = 0; $i < @sources; $i++) {
527 6         13 my $source = $sources[$i];
528              
529 6         129 my $own_subscription = RxPerl::Subscription->new;
530 6         12 push @own_subscriptions, $own_subscription;
531 6         22 my $own_subscriber = {
532             new_subscription => $own_subscription,
533             };
534              
535 6         18 foreach my $type (qw/ next error complete /) {
536             $own_subscriber->{$type} = sub {
537 9         49 $_->unsubscribe foreach grep $_ ne $own_subscription, @own_subscriptions;
538 9         20 @own_subscriptions = ($own_subscription);
539 9         15 @sources = ();
540 9 50       46 $subscriber->{$type}->(@_) if defined $subscriber->{$type};
541 9         42 @$own_subscriber{qw/ next error complete /} = @$subscriber{qw/ next error complete /};
542 18         108 };
543             }
544              
545 6         22 $source->subscribe($own_subscriber);
546             }
547              
548             # this could be replaced with a 'return undef' at this point
549 2         8 return \@own_subscriptions;
550 2         17 });
551             }
552              
553             sub rx_range {
554 1     1   2275 my ($start, $count) = @_;
555              
556             return rx_observable->new(sub {
557 1     1   2 my ($subscriber) = @_;
558              
559 1         2 my $i = $start;
560              
561 1         2 $subscriber->subscription->add(sub { $i = $start + $count });
  1         3  
562              
563 1         4 for (; $i < $start + $count; $i++) {
564 7 50       11 $subscriber->{next}->($i) if defined $subscriber->{next};
565             }
566              
567 1 50       5 $subscriber->{complete}->() if defined $subscriber->{complete};
568              
569 1         3 return;
570 1         7 });
571             }
572              
573             sub rx_throw_error {
574 33     33   4617 my ($error) = @_;
575              
576             return rx_observable->new(sub {
577 40     40   67 my ($subscriber) = @_;
578              
579 40 50       138 $subscriber->{error}->($error) if defined $subscriber->{error};
580              
581 40         107 return;
582 33         120 });
583             }
584              
585             sub rx_timer {
586 101     101   38318 my ($after, $period) = @_;
587              
588 101         340 my ($timer_sub, $cancel_timer_sub) = get_timer_subs;
589 101         339 my ($interval_sub, $cancel_interval_sub) = get_interval_subs;
590              
591             return rx_observable->new(sub {
592 109     109   236 my ($subscriber) = @_;
593              
594 109         191 my $counter = 0;
595 109         184 my $timer_int;
596             my $timer = $timer_sub->($after, sub {
597 94 100       275 if (defined $period) {
598             $timer_int = $interval_sub->($period, sub {
599 17 50       75 $subscriber->{next}->($counter++) if defined $subscriber->{next};
600 7         75 });
601 7 50       38 $subscriber->{next}->($counter++) if defined $subscriber->{next};
602             } else {
603 87 100       276 $subscriber->{next}->($counter++) if defined $subscriber->{next};
604 87 100       767 $subscriber->{complete}->() if defined $subscriber->{complete};
605             }
606 109         658 });
607              
608             return sub {
609 109         412 $cancel_timer_sub->($timer);
610 109         306 $cancel_interval_sub->($timer_int);
611 109         558 };
612 101         664 });
613             }
614              
615             sub rx_zip {
616 5     5   9 my @sources = @_;
617              
618             return rx_observable->new(sub {
619 5     5   10 my ($subscriber) = @_;
620              
621             my @sources_metadata = map {
622 5         12 +{
623 13         38 buffer => [],
624             completed => 0,
625             };
626             } @sources;
627 5         13 my @own_subscriptions = map RxPerl::Subscription->new, @sources;
628              
629 5         17 $subscriber->subscription->add(\@own_subscriptions);
630              
631 5         16 for my $i (0 .. (@sources - 1)) {
632             my $own_subscriber = {
633             new_subscription => $own_subscriptions[$i],
634             next => sub {
635 48         57 my ($v) = @_;
636              
637             # push to buffer
638 48         47 push @{$sources_metadata[$i]{buffer}}, $v;
  48         69  
639              
640             # if all buffers have elements in them:
641 48 100       113 if (!first {!@{$_->{buffer}}} @sources_metadata) {
  112         107  
  112         183  
642 17         36 my @next = map {shift @$_} map $_->{buffer}, @sources_metadata;
  43         64  
643 17 50       54 $subscriber->{next}->(\@next) if defined $subscriber->{next};
644 17 100       62 if (first {!@{$_->{buffer}} and $_->{completed}} @sources_metadata) {
  37 100       54  
  37         87  
645 4 50       11 $subscriber->{complete}->() if defined $subscriber->{complete};
646             }
647             }
648             },
649             error => sub {
650 0 0       0 $subscriber->{error}->(@_) if defined $subscriber->{error};
651             },
652             complete => sub {
653 6         9 $sources_metadata[$i]{completed} = 1;
654 6 50       10 if (!@{$sources_metadata[$i]{buffer}}) {
  6         33  
655 0 0       0 $subscriber->{complete}->() if defined $subscriber->{complete};
656             }
657             },
658 13         94 };
659              
660 13         32 $sources[$i]->subscribe($own_subscriber);
661             }
662              
663 5         11 return;
664 5         25 });
665             }
666              
667             1;