line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package POE::XUL::Controler; |
2
|
|
|
|
|
|
|
# $Id: Controler.pm 1566 2010-11-03 03:13:32Z fil $ |
3
|
|
|
|
|
|
|
# |
4
|
|
|
|
|
|
|
# Copyright Philip Gwyn / Awalé 2007-2010. All rights reserved. |
5
|
|
|
|
|
|
|
# |
6
|
|
|
|
|
|
|
|
7
|
14
|
|
|
14
|
|
53
|
use strict; |
|
14
|
|
|
|
|
20
|
|
|
14
|
|
|
|
|
343
|
|
8
|
14
|
|
|
14
|
|
49
|
use warnings; |
|
14
|
|
|
|
|
18
|
|
|
14
|
|
|
|
|
350
|
|
9
|
|
|
|
|
|
|
|
10
|
14
|
|
|
14
|
|
47
|
use Carp; |
|
14
|
|
|
|
|
17
|
|
|
14
|
|
|
|
|
688
|
|
11
|
14
|
|
|
14
|
|
52
|
use Digest::MD5 qw(md5_hex); |
|
14
|
|
|
|
|
19
|
|
|
14
|
|
|
|
|
548
|
|
12
|
14
|
|
|
14
|
|
51
|
use POE::Kernel; |
|
14
|
|
|
|
|
23
|
|
|
14
|
|
|
|
|
85
|
|
13
|
14
|
|
|
14
|
|
6642
|
use POE::XUL::ChangeManager; |
|
14
|
|
|
|
|
29
|
|
|
14
|
|
|
|
|
400
|
|
14
|
14
|
|
|
14
|
|
5868
|
use POE::XUL::Event; |
|
14
|
|
|
|
|
25
|
|
|
14
|
|
|
|
|
343
|
|
15
|
14
|
|
|
14
|
|
64
|
use POE::XUL::Logging; |
|
14
|
|
|
|
|
17
|
|
|
14
|
|
|
|
|
771
|
|
16
|
14
|
|
|
14
|
|
55
|
use Scalar::Util qw( weaken ); |
|
14
|
|
|
|
|
13
|
|
|
14
|
|
|
|
|
474
|
|
17
|
|
|
|
|
|
|
|
18
|
14
|
|
|
14
|
|
47
|
use constant DEBUG => 0; |
|
14
|
|
|
|
|
15
|
|
|
14
|
|
|
|
|
17031
|
|
19
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
our $VERSION = '0.0601'; |
21
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
############################################################## |
23
|
|
|
|
|
|
|
sub new |
24
|
|
|
|
|
|
|
{ |
25
|
6
|
|
|
6
|
0
|
8
|
my( $package, $timeout, $apps ) = @_; |
26
|
6
|
|
|
|
|
23
|
my $self = bless { |
27
|
|
|
|
|
|
|
sessions => {}, |
28
|
|
|
|
|
|
|
timeout => $timeout, |
29
|
|
|
|
|
|
|
apps => $apps, |
30
|
|
|
|
|
|
|
events => {} |
31
|
|
|
|
|
|
|
}, $package; |
32
|
6
|
|
|
|
|
20
|
return $self; |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
############################################################## |
36
|
|
|
|
|
|
|
sub build_event |
37
|
|
|
|
|
|
|
{ |
38
|
0
|
|
|
0
|
0
|
|
my( $self, $event_name, $CM, $resp, $req ) = @_; |
39
|
0
|
|
|
|
|
|
my $event = POE::XUL::Event->new( $event_name, $CM, $resp ); |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
# Keep a weak reference so we can cancel the event if needs be |
42
|
0
|
|
|
|
|
|
my $r = 0+$req; |
43
|
0
|
|
|
|
|
|
$self->{events}{$r} = $event; |
44
|
0
|
|
|
|
|
|
weaken( $self->{events}{$r} ); |
45
|
0
|
|
|
|
|
|
DEBUG and xwarn "BUILD r=$r event=$event"; |
46
|
|
|
|
|
|
|
|
47
|
0
|
|
|
|
|
|
return $event; |
48
|
|
|
|
|
|
|
} |
49
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
############################################################## |
51
|
|
|
|
|
|
|
sub build_change_manager |
52
|
|
|
|
|
|
|
{ |
53
|
0
|
|
|
0
|
0
|
|
my( $self ) = @_; |
54
|
|
|
|
|
|
|
|
55
|
0
|
|
|
|
|
|
return POE::XUL::ChangeManager->new(); |
56
|
|
|
|
|
|
|
} |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
|
61
|
|
|
|
|
|
|
############################################################## |
62
|
|
|
|
|
|
|
# Does a given session ID exist? |
63
|
|
|
|
|
|
|
sub exists |
64
|
|
|
|
|
|
|
{ |
65
|
0
|
|
|
0
|
0
|
|
my( $self, $SID ) = @_; |
66
|
0
|
|
|
|
|
|
return exists $self->{sessions}{ $SID }; |
67
|
|
|
|
|
|
|
} |
68
|
|
|
|
|
|
|
|
69
|
|
|
|
|
|
|
############################################################## |
70
|
|
|
|
|
|
|
# How many sessions currently exist |
71
|
|
|
|
|
|
|
sub count |
72
|
|
|
|
|
|
|
{ |
73
|
0
|
|
|
0
|
0
|
|
my( $self ) = @_; |
74
|
0
|
|
|
|
|
|
return 0 + keys %{ $self->{sessions} }; |
|
0
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
} |
76
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
|
78
|
|
|
|
|
|
|
############################################################## |
79
|
|
|
|
|
|
|
# A new session has been created |
80
|
|
|
|
|
|
|
sub register |
81
|
|
|
|
|
|
|
{ |
82
|
0
|
|
|
0
|
0
|
|
my( $self, $SID, $session, $CM ) = @_; |
83
|
|
|
|
|
|
|
|
84
|
0
|
|
|
|
|
|
DEBUG and xdebug "register SID=$SID"; |
85
|
|
|
|
|
|
|
# TODO make sure the session has the SID as an alias? |
86
|
0
|
|
|
|
|
|
$self->{sessions}{ $SID } = { |
87
|
|
|
|
|
|
|
session => $session->ID, |
88
|
|
|
|
|
|
|
CM => $CM |
89
|
|
|
|
|
|
|
}; |
90
|
0
|
|
|
|
|
|
$self->keepalive( $SID ); |
91
|
|
|
|
|
|
|
} |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
############################################################## |
94
|
|
|
|
|
|
|
# A session has been shutdown |
95
|
|
|
|
|
|
|
sub unregister |
96
|
|
|
|
|
|
|
{ |
97
|
0
|
|
|
0
|
0
|
|
my( $self, $SID ) = @_; |
98
|
0
|
0
|
|
|
|
|
return unless $self->{sessions}{ $SID }; |
99
|
0
|
|
|
|
|
|
DEBUG and xdebug "Unregister SID=$SID"; |
100
|
0
|
|
|
|
|
|
my $details = delete $self->{sessions}{ $SID }; |
101
|
|
|
|
|
|
|
|
102
|
0
|
|
|
|
|
|
my $tid = $details->{timeout_id}; |
103
|
0
|
|
|
|
|
|
my $session = $details->{session}; |
104
|
0
|
|
|
|
|
|
my $CM = $details->{CM}; |
105
|
0
|
0
|
|
|
|
|
if( $tid ) { |
106
|
0
|
|
|
|
|
|
$poe_kernel->alarm_remove( $tid ); |
107
|
|
|
|
|
|
|
} |
108
|
0
|
|
|
|
|
|
$CM->dispose; |
109
|
0
|
|
|
|
|
|
$poe_kernel->post( $session, 'shutdown', $SID ); # TODO use alias $SID |
110
|
|
|
|
|
|
|
} |
111
|
|
|
|
|
|
|
|
112
|
|
|
|
|
|
|
############################################################## |
113
|
|
|
|
|
|
|
sub keepalive |
114
|
|
|
|
|
|
|
{ |
115
|
0
|
|
|
0
|
0
|
|
my( $self, $SID ) = @_; |
116
|
0
|
0
|
|
|
|
|
return unless $self->{sessions}{ $SID }; |
117
|
0
|
|
|
|
|
|
my $tid = $self->{sessions}{$SID}{timeout_id}; |
118
|
0
|
0
|
|
|
|
|
if( $tid ) { |
119
|
|
|
|
|
|
|
|
120
|
0
|
|
|
|
|
|
$poe_kernel->delay_adjust( $tid, $self->{timeout} ); |
121
|
0
|
|
|
|
|
|
DEBUG and |
122
|
|
|
|
|
|
|
xdebug "timeout for $SID: tid=$self->{sessions}{$SID}{timeout_id} timeout=$self->{timeout}"; |
123
|
|
|
|
|
|
|
} |
124
|
|
|
|
|
|
|
else { |
125
|
|
|
|
|
|
|
# session_timeout is defined in POE::Component::XUL |
126
|
|
|
|
|
|
|
$self->{sessions}{ $SID }{timeout_id} = |
127
|
|
|
|
|
|
|
$poe_kernel->delay_set( 'session_timeout', |
128
|
|
|
|
|
|
|
$self->{timeout}, |
129
|
0
|
|
|
|
|
|
$SID ); |
130
|
0
|
|
|
|
|
|
DEBUG and |
131
|
|
|
|
|
|
|
xdebug "timeout for $SID: tid=$self->{sessions}{$SID}{timeout_id} timeout=$self->{timeout}"; |
132
|
|
|
|
|
|
|
} |
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
|
136
|
|
|
|
|
|
|
############################################################## |
137
|
|
|
|
|
|
|
# Find the constructor for a package |
138
|
|
|
|
|
|
|
sub package_ctor |
139
|
|
|
|
|
|
|
{ |
140
|
0
|
|
|
0
|
0
|
|
my( $self, $package ) = @_; |
141
|
|
|
|
|
|
|
|
142
|
0
|
0
|
|
|
|
|
confess "No package" unless $package; |
143
|
0
|
|
|
|
|
|
return $package->can( 'spawn' ); |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
############################################################## |
147
|
|
|
|
|
|
|
# Spawn a component from a package |
148
|
|
|
|
|
|
|
sub package_build |
149
|
|
|
|
|
|
|
{ |
150
|
0
|
|
|
0
|
0
|
|
my( $self, $package ) = @_; |
151
|
0
|
|
|
|
|
|
my $ctor = $self->package_ctor( $package ); |
152
|
0
|
0
|
|
|
|
|
unless( $ctor ) { |
153
|
|
|
|
|
|
|
return sub { |
154
|
0
|
|
|
0
|
|
|
my( $event ) = @_; |
155
|
0
|
|
|
|
|
|
$event->response->content( "Can't build an application from $package" ); |
156
|
0
|
|
|
|
|
|
$event->response->code( 500 ); |
157
|
0
|
|
|
|
|
|
}; |
158
|
|
|
|
|
|
|
} |
159
|
0
|
|
|
0
|
|
|
return sub { $ctor->( $package, @_ ) }; |
|
0
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
} |
161
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
|
163
|
|
|
|
|
|
|
############################################################## |
164
|
|
|
|
|
|
|
sub boot |
165
|
|
|
|
|
|
|
{ |
166
|
0
|
|
|
0
|
0
|
|
my( $self, $req, $resp ) = @_; |
167
|
0
|
|
|
|
|
|
my $app = $req->param( 'app' ); |
168
|
0
|
0
|
|
|
|
|
unless( $app ) { |
169
|
0
|
|
|
|
|
|
xlog "Controler: Request must have application name"; |
170
|
0
|
|
|
|
|
|
return "Controler: Request must have application name"; |
171
|
|
|
|
|
|
|
} |
172
|
0
|
|
|
|
|
|
my $A = $self->{apps}{$app}; |
173
|
|
|
|
|
|
|
|
174
|
0
|
0
|
|
|
|
|
unless( $A ) { |
175
|
0
|
|
|
|
|
|
xlog "Unknown application: $app"; |
176
|
0
|
|
|
|
|
|
return "Application inconnue : $app"; |
177
|
|
|
|
|
|
|
} |
178
|
|
|
|
|
|
|
|
179
|
0
|
0
|
|
|
|
|
unless( ref $A ) { |
180
|
0
|
|
|
|
|
|
$A = $self->package_build( $A ); |
181
|
|
|
|
|
|
|
} |
182
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
# use Data::Dumper; |
184
|
|
|
|
|
|
|
# xlog "A=", Dumper $A; |
185
|
0
|
|
|
|
|
|
my $CM = $self->build_change_manager(); |
186
|
|
|
|
|
|
|
|
187
|
0
|
|
|
|
|
|
my $event = $self->build_event( 'boot', $CM, $resp, $req ); |
188
|
0
|
|
|
|
|
|
$event->__init( $req ); |
189
|
|
|
|
|
|
|
$event->coderef( |
190
|
|
|
|
|
|
|
sub { |
191
|
0
|
|
|
0
|
|
|
my( $event ) = @_; |
192
|
0
|
|
|
|
|
|
my $SID = $self->make_session_id; |
193
|
0
|
|
|
|
|
|
$event->SID( $SID ); |
194
|
0
|
|
|
|
|
|
$event->CM->SID( $SID ); |
195
|
0
|
|
|
|
|
|
my $session = $A->( $event, $app ); |
196
|
0
|
|
|
|
|
|
$self->register( $SID, $session, $event->CM ); |
197
|
0
|
|
|
|
|
|
$event->defer; |
198
|
0
|
|
|
|
|
|
$poe_kernel->post( $SID, 'boot', $event, $app ); |
199
|
|
|
|
|
|
|
} |
200
|
0
|
|
|
|
|
|
); |
201
|
|
|
|
|
|
|
|
202
|
0
|
|
|
|
|
|
$self->xul_request( $event ); |
203
|
0
|
|
|
|
|
|
return; |
204
|
|
|
|
|
|
|
} |
205
|
|
|
|
|
|
|
|
206
|
|
|
|
|
|
|
############################################################## |
207
|
|
|
|
|
|
|
sub close |
208
|
|
|
|
|
|
|
{ |
209
|
0
|
|
|
0
|
0
|
|
my( $self, $SID, $req, $resp ) = @_; |
210
|
|
|
|
|
|
|
|
211
|
0
|
|
|
|
|
|
my $S = $self->{sessions}{ $SID }; |
212
|
0
|
0
|
|
|
|
|
die "Can't find session $SID" unless $SID; |
213
|
|
|
|
|
|
|
|
214
|
0
|
|
|
|
|
|
my $event = $self->build_event( 'close', $S->{CM}, $resp, $req ); |
215
|
|
|
|
|
|
|
$event->coderef( |
216
|
|
|
|
|
|
|
sub { |
217
|
0
|
|
|
0
|
|
|
xlog "Close $SID"; |
218
|
|
|
|
|
|
|
# TODO : use alias $SID |
219
|
0
|
|
|
|
|
|
my $session = $poe_kernel->ID_id_to_session( $S->{session} ); |
220
|
0
|
|
|
|
|
|
$poe_kernel->signal( $session, 'UIDESTROY' ); |
221
|
0
|
|
|
|
|
|
$self->unregister( $SID ); |
222
|
|
|
|
|
|
|
} |
223
|
0
|
|
|
|
|
|
); |
224
|
|
|
|
|
|
|
|
225
|
0
|
|
|
|
|
|
$self->xul_request( $event ); |
226
|
0
|
|
|
|
|
|
return; |
227
|
|
|
|
|
|
|
} |
228
|
|
|
|
|
|
|
|
229
|
|
|
|
|
|
|
############################################################## |
230
|
|
|
|
|
|
|
sub connect |
231
|
|
|
|
|
|
|
{ |
232
|
0
|
|
|
0
|
0
|
|
my( $self, $SID, $req, $resp ) = @_; |
233
|
|
|
|
|
|
|
|
234
|
0
|
|
|
|
|
|
my $S = $self->{sessions}{ $SID }; |
235
|
0
|
0
|
|
|
|
|
die "Can't find session $SID" unless $SID; |
236
|
|
|
|
|
|
|
|
237
|
0
|
|
|
|
|
|
my $event = $self->build_event( 'connect', $S->{CM}, $resp, $req ); |
238
|
0
|
|
|
|
|
|
$event->__init( $req ); |
239
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
$event->coderef( sub { |
241
|
0
|
|
|
0
|
|
|
$event->defer; |
242
|
0
|
|
|
|
|
|
$poe_kernel->post( $SID, 'connect', $event ); |
243
|
0
|
|
|
|
|
|
} ); |
244
|
0
|
|
|
|
|
|
$self->xul_request( $event ); |
245
|
0
|
|
|
|
|
|
return; |
246
|
|
|
|
|
|
|
} |
247
|
|
|
|
|
|
|
|
248
|
|
|
|
|
|
|
############################################################## |
249
|
|
|
|
|
|
|
sub disconnect |
250
|
|
|
|
|
|
|
{ |
251
|
0
|
|
|
0
|
0
|
|
my( $self, $SID, $req, $resp ) = @_; |
252
|
|
|
|
|
|
|
|
253
|
0
|
|
|
|
|
|
my $S = $self->{sessions}{ $SID }; |
254
|
0
|
0
|
|
|
|
|
die "Can't find session $SID" unless $SID; |
255
|
|
|
|
|
|
|
|
256
|
0
|
|
|
|
|
|
my $event = $self->build_event( 'disconnect', $S->{CM}, $resp, $req ); |
257
|
0
|
|
|
|
|
|
$event->__init( $req ); |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
$event->coderef( sub { |
260
|
0
|
|
|
0
|
|
|
$event->defer; |
261
|
0
|
|
|
|
|
|
$poe_kernel->post( $SID, 'disconnect', $event ); |
262
|
0
|
|
|
|
|
|
} ); |
263
|
0
|
|
|
|
|
|
$self->xul_request( $event ); |
264
|
0
|
|
|
|
|
|
return; |
265
|
|
|
|
|
|
|
} |
266
|
|
|
|
|
|
|
|
267
|
|
|
|
|
|
|
############################################################## |
268
|
|
|
|
|
|
|
sub request |
269
|
|
|
|
|
|
|
{ |
270
|
0
|
|
|
0
|
0
|
|
my ( $self, $SID, $event_type, $req, $resp ) = @_; |
271
|
|
|
|
|
|
|
|
272
|
0
|
|
|
|
|
|
my $S = $self->{sessions}{ $SID }; |
273
|
0
|
0
|
|
|
|
|
die "Can't find session $SID" unless $SID; |
274
|
|
|
|
|
|
|
|
275
|
0
|
|
|
|
|
|
my $event = $self->build_event( $event_type, $S->{CM}, $resp, $req ); |
276
|
0
|
|
|
|
|
|
$event->__init( $req ); |
277
|
|
|
|
|
|
|
|
278
|
0
|
|
|
|
|
|
$self->xul_request( $event ); |
279
|
|
|
|
|
|
|
} |
280
|
|
|
|
|
|
|
|
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
############################################################## |
283
|
|
|
|
|
|
|
# Standard XUL request (Click / Change / etc ) |
284
|
|
|
|
|
|
|
sub xul_request |
285
|
|
|
|
|
|
|
{ |
286
|
0
|
|
|
0
|
0
|
|
my( $self, $event ) = @_; |
287
|
|
|
|
|
|
|
|
288
|
0
|
|
|
|
|
|
$event->done( 1 ); |
289
|
0
|
|
|
|
|
|
$event->run(); |
290
|
|
|
|
|
|
|
|
291
|
0
|
|
|
|
|
|
DEBUG and xdebug "Request done"; |
292
|
0
|
0
|
|
|
|
|
if( $event->is_flushed ) { |
|
|
0
|
|
|
|
|
|
293
|
|
|
|
|
|
|
# User code might have already flushed everything |
294
|
0
|
|
|
|
|
|
DEBUG and xdebug "Request already flushed"; |
295
|
|
|
|
|
|
|
} |
296
|
|
|
|
|
|
|
elsif( $event->done ) { |
297
|
0
|
|
|
|
|
|
DEBUG and xdebug "Response now"; |
298
|
0
|
|
|
|
|
|
$event->flush; |
299
|
|
|
|
|
|
|
} |
300
|
|
|
|
|
|
|
else { |
301
|
|
|
|
|
|
|
# User code wants us to wait |
302
|
0
|
|
|
|
|
|
DEBUG and xdebug "Defered response"; |
303
|
|
|
|
|
|
|
# User code will then call $event->finish when the time is right |
304
|
|
|
|
|
|
|
} |
305
|
0
|
|
|
|
|
|
return 1; |
306
|
|
|
|
|
|
|
} |
307
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
############################################################## |
309
|
|
|
|
|
|
|
## Cancel a request. This happens on browser disconnect |
310
|
|
|
|
|
|
|
sub cancel |
311
|
|
|
|
|
|
|
{ |
312
|
0
|
|
|
0
|
0
|
|
my( $self, $request ) = @_; |
313
|
|
|
|
|
|
|
|
314
|
0
|
|
|
|
|
|
my $r = 0+$request; |
315
|
0
|
|
|
|
|
|
my $event = $self->{events}{ $r }; |
316
|
0
|
0
|
|
|
|
|
unless( $event ) { |
317
|
0
|
0
|
|
|
|
|
if( $request->method ne 'DISCONNECT' ) { |
318
|
0
|
|
|
|
|
|
xlog "FAILURE! I no longer have an event for $request ", 0+$request; |
319
|
|
|
|
|
|
|
} |
320
|
0
|
|
|
|
|
|
return; |
321
|
|
|
|
|
|
|
} |
322
|
|
|
|
|
|
|
|
323
|
0
|
|
|
|
|
|
my $SID = $event->SID; |
324
|
0
|
|
|
|
|
|
my $S = $self->{sessions}{ $SID }; |
325
|
0
|
0
|
|
|
|
|
unless( $SID ) { |
326
|
0
|
|
|
|
|
|
xwarn "Can't find session $SID"; |
327
|
0
|
|
|
|
|
|
return; |
328
|
|
|
|
|
|
|
} |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
DEBUG and |
331
|
0
|
|
|
|
|
|
xwarn "CANCEL r=$r event=$event SID=$SID"; |
332
|
|
|
|
|
|
|
|
333
|
0
|
|
|
|
|
|
$event->cancel; |
334
|
|
|
|
|
|
|
# TODO : do I need to set a flag on the CM? |
335
|
|
|
|
|
|
|
} |
336
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
############################################################## |
338
|
|
|
|
|
|
|
## Generate an unguessable session ID. |
339
|
|
|
|
|
|
|
## Though unguessable isn't all that useful : it can be sniffed off the air |
340
|
|
|
|
|
|
|
sub make_session_id { |
341
|
0
|
|
|
0
|
0
|
|
my $self = shift; |
342
|
0
|
|
|
|
|
|
my $id = md5_hex($$, time, rand(9999)); |
343
|
|
|
|
|
|
|
# Format it like a UUID: B6ED3B3F-72C8-3EEF-8173-EC86AA01EA29 |
344
|
0
|
|
|
|
|
|
substr( $id, 20, 0, '-' ); |
345
|
0
|
|
|
|
|
|
substr( $id, 16, 0, '-' ); |
346
|
0
|
|
|
|
|
|
substr( $id, 12, 0, '-' ); |
347
|
0
|
|
|
|
|
|
substr( $id, 8, 0, '-' ); |
348
|
0
|
|
|
|
|
|
return $id; |
349
|
|
|
|
|
|
|
} |
350
|
|
|
|
|
|
|
|
351
|
|
|
|
|
|
|
1; |
352
|
|
|
|
|
|
|
|