This file is indexed.

/usr/share/perl5/CSS/Squish.pm is in libcss-squish-perl 0.09-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
use 5.008;
use strict;
use warnings;

package CSS::Squish;

$CSS::Squish::VERSION = '0.09';

# Setting this to true will enable lots of debug logging about what
# CSS::Squish is doing
$CSS::Squish::DEBUG = 0;

use File::Spec;
use Scalar::Util qw(blessed);
use URI;
use URI::file;

=head1 NAME

CSS::Squish - Compact many CSS files into one big file

=head1 SYNOPSIS

  use CSS::Squish;
  my $concatenated = CSS::Squish->concatenate(@files);

  my $squisher = CSS::Squish->new( roots => ['/root1', '/root2'] );
  my $concatenated = $squisher->concatenate(@files);

=head1 DESCRIPTION

This module takes a list of CSS files and concatenates them, making sure
to honor any valid @import statements included in the files.

The benefit of this is that you get to keep your CSS as individual files,
but can serve it to users in one big file, saving the overhead of possibly
dozens of HTTP requests.

Following the CSS 2.1 spec, @import statements must be the first rules in
a CSS file.  Media-specific @import statements will be honored by enclosing
the included file in an @media rule.  This has the side effect of actually
I<improving> compatibility in Internet Explorer, which ignores
media-specific @import rules but understands @media rules.

It is possible that future versions will include methods to compact
whitespace and other parts of the CSS itself, but this functionality
is not supported at the current time.

=cut

#
# This should be a decently close CSS 2.1 compliant parser for @import rules
#
# XXX TODO: This does NOT deal with comments at all at the moment.  Which
# is sort of a problem.
# 

my @ROOTS = qw( );

my @MEDIA_TYPES = qw(all aural braille embossed handheld print
                     projection screen tty tv);
my $MEDIA_TYPES = '(?:' . join('|', @MEDIA_TYPES) . ')';
my $MEDIA_LIST  = qr/$MEDIA_TYPES(?:\s*,\s*$MEDIA_TYPES)*/;

my $AT_IMPORT = qr/^\s*                     # leading whitespace
                    \@import\s+             # @import
                        (?:url\(            #   url(
                        \s*                 #   optional whitespace
                        (?:"|')?            #   optional " or '
                      |                     # or
                        (?:"|'))            #   " or '
                      (.+?)                 # the filename
                        (?:(?:"|')?         #   optional " or '
                        \s*                 #   optional whitespace
                        \)                  #   )
                      |                     # or
                        (?:"|'))            #   " or '
                    (?:\s($MEDIA_LIST))?    # the optional media list
                    \;                      # finishing semi-colon
                   \s*$                     # trailing whitespace
                  /x;

=head1 COMMON METHODS

=head2 new( [roots=>[...]] )

A constructor. For backward compatibility with versions prior to 0.06
you can still call everything as a class method, but should remember
that roots are shared between all callers in this case.

if you're using persistent environment (like mod_perl) then it's very
recomended to use objects.

=cut

sub new {
    my $proto = shift;
    return bless {@_}, ref($proto) || $proto;
}

=head2 concatenate( @files )

Takes a list of files to concatenate and returns the results as one big scalar.

=head2 concatenate_to( $dest, @files )

Takes a filehandle to print to and a list of files to concatenate.
C<concatenate> uses this method with an C<open>ed scalar.

=cut

sub concatenate {
    my $self   = shift;
    my $string = '';
    
    $self->_debug("Opening scalar as file");
    
    open my $fh, '>', \$string or die "Can't open scalar as file! $!";
    $self->concatenate_to($fh, @_);

    $self->_debug("Closing scalar as file");
    close $fh;

    return $string;
}

sub concatenate_to {
    my $self = shift;
    my $dest = shift;

    $self->_debug("Looping over list of files: ", join(", ", @_), "\n");

    my %seen = ();
    while ( my $file = shift @_ ) {

        next if $seen{ $file }{'all'}++;

        my $fh = $self->file_handle( $file );
        unless ( defined $fh ) {
            $self->_debug("Skipping '$file'...");
            print $dest qq[/* WARNING: Unable to find/open file '$file' */\n];
            next;
        }
        $self->_concatenate_to( $dest, $fh, $file, \%seen );
    }
}

sub _concatenate_to {
    my $self = shift;
    my $dest = shift;
    my $fh   = shift;
    my $file = shift;
    my $seen = shift || {};

    while ( my $line = <$fh> ) {
        if ( $line =~ /$AT_IMPORT/o ) {
            my $import = $1;
            my $media  = $2;

            $self->_debug("Processing import '$import'");

            # resolve URI against the current file and get the file path
            # which is always relative to our root(s)
            my $path = $self->resolve_uri( $import, $file );
            unless ( defined $path ) {
                $self->_debug("Skipping import because couldn't resolve URL");
                print $dest $line;
                next;
            }

            if ( $seen->{ $path }{'all'} ) {
                $self->_debug("Skipping import as it was included for all media types");
                print $dest "/** Skipping: \n", $line, "  */\n\n";
                next;
            }

            if ( $media ) {
                my @list = sort map lc, split /\s*,\s*/, ($media||'');
                if ( grep $_ eq 'all', @list ) {
                    @list = ();
                }
                $media = join ', ', @list;
            }
            if ( $seen->{ $path }{ $media || 'all' }++ ) {
                $self->_debug("Skipping import as it's recursion");
                print $dest "/** Skipping: \n", $line, "  */\n\n";
                next;
            }

            # Look up the new file in root(s), so we can leave import
            # if something is wrong
            my $new_fh = $self->file_handle( $path );
            unless ( defined $new_fh ) {
                $self->_debug("Skipping import of '$import'");

                print $dest qq[/* WARNING: Unable to find import '$import' */\n];
                print $dest $line;
                next;
            }

            print $dest "\n/**\n  * From $file: $line  */\n\n";

            if ( defined $media ) {
                print $dest "\@media $media {\n";
                $self->_concatenate_to($dest, $new_fh, $path, $seen);
                print $dest "}\n";
            }
            else {
                $self->_concatenate_to($dest, $new_fh, $path, $seen);
            }

            print $dest "\n/** End of $import */\n\n";
        }
        else {
            print $dest $line;
            last if not $line =~ /^\s*$/;
        }
    }
    $self->_debug("Printing the rest");
    local $_;
    print $dest $_ while <$fh>;
    close $fh;
}

=head1 RESOLVING METHODS

The following methods help map URIs to files and find them on the disk.

In common situation you control CSS and can adopt it to use imports with
relative URIs and most probably only have to set root(s).

However, you can subclass these methods to parse css files before submitting,
implement advanced mapping of URIs to file system and other things.

Mapping works in the following way. When you call concatenate method we get
content of file using file_handle method which as well lookup files in roots.
If roots are not defined then files are treated as absolute paths or relative
to the current directory. Using of absolute paths is not recommended as
unhide server dirrectory layout to clients in css comments and as well don't
allow to handle @import commands with absolute URIs. When files is found we
parse its content for @import commands. On each URI we call resolve_uri method
that convert absolute and relative URIs into file paths.

Here is example of processing:

    roots: /www/overlay/, /www/shared/

    $squisher->concatenate('/css/main.css');
    
    ->file_handle('/css/main.css');
        ->resolve_file('/css/main.css');
        <- '/www/shared/css/main.css';
    <- handle;

    content parsing
    find '@import url(nav.css)'
    -> resolve_uri('nav.css', '/css/main.css');
    <- '/css/nav.css';
        ... recursivly process file
    find '@import url(/css/another.css)'
    -> resolve_uri('/css/another.css', '/css/main.css');
    <- '/css/another.css'
    ...

=head2 roots( @dirs )

A getter/setter for paths to search when looking for files.

The paths specified here are searched for files. This is useful if
your server has multiple document roots or document root doesn't match
the current dir.

See also 'resolve_file' below.

=cut

sub roots {
    my $self = shift;
    my @res;
    unless ( blessed $self ) {
        @ROOTS = @_ if @_;
        @res = @ROOTS;
    } else {
        $self->{'roots'} = [ grep defined, @_ ] if @_;
        @res = @{ $self->{'roots'} };
    }
    $self->_debug("Roots are: ". join ", ", map "'$_'", @res);
    return @res;
}

=head2 file_handle( $file )

Takes a path to a file, resolves (see resolve_file) it and returns a handle.

Returns undef if file couldn't be resolved or it's impossible to open file.

You can subclass it to filter content, process it with templating system or
generate it on the fly:

    package My::CSS::Squish;
    use base qw(CSS::Squish);

    sub file_handle {
        my $self = shift;
        my $file = shift;
        
        my $content = $self->my_prepare_content($file);
        return undef unless defined $content;

        open my $fh, "<", \$content or warn "Couldn't open handle: $!";
        return $fh;
    }

B<Note> that the file is not resolved yet and is relative to the root(s), so
you have to resolve it yourself or call resolve_file method.

=cut

sub file_handle {
    my $self = shift;
    my $file = shift;

    my $path = $self->resolve_file( $file );
    unless ( defined $path ) {
        $self->_debug("Couldn't find '$file' in root(s)");
        return undef;
    }

    my $fh;
    unless ( open $fh, '<', $path ) {
        $self->_debug("Skipping '$file' ($path) due to error: $!");
        return undef;
    }
    return $fh;
}

=head2 resolve_file( $file )

Lookup file in the root(s) and returns first path it found or undef.

When roots are not set just checks if file exists.

=cut

sub resolve_file {
    my $self = shift;
    my $file = shift;

    $self->_debug("Looking for '$file'");
    my @roots = $self->roots;
    unless ( @roots ) {
        return undef unless -e $file;
        return $file;
    }

    foreach my $root ( @roots ) {
        $self->_debug("Searching in '$root'");
        my @spec = File::Spec->splitpath( $root, 1 );
        my $path = File::Spec->catpath( @spec[0,1], $file );

        return $path if -e $path;
    }
    return undef;
}

=head2 _resolve_file( $file, @roots )

DEPRECATED. This private method is deprecated and do nothing useful except
maintaining backwards compatibility. If you were using it then most probably
to find files in roots before submitting them into concatenate method. Now,
it's not required and this method returns back file path without changes.

=cut

sub _resolve_file {
    my ($self, $file, @roots) = @_;
    require Carp;
    Carp::carp("You called ->_resolve_file($file, ...). The method is deprecated!");
    return $file;
}

=head2 resolve_uri( $uri_string, $base_file )

Takes an URI and base file path and transforms it into new
file path.

=cut

sub resolve_uri {
    my $self = shift;
    my $uri_str = shift;
    my $base_file = shift;

    my $uri = URI->new( $uri_str, 'http' );

    if ( defined $uri->scheme || defined $uri->authority ) {
        $self->_debug("Skipping uri because it's external");
        return undef;
    }

    my $strip_leading_slash = 0;
    unless ( $base_file =~ m{^/} ) {
        $base_file = '/'. $base_file;
        $strip_leading_slash = 1;
    }
    my $base_uri = URI::file->new( $base_file );

    my $path = $uri->abs( $base_uri )->path;
    $path =~ s{^/}{} if $strip_leading_slash;
    return $path;
}

sub _debug {
    my $self = shift;
    warn( ( caller(1) )[3], ": ", @_, "\n") if $CSS::Squish::DEBUG;
}

=head1 BUGS AND SHORTCOMINGS

At the current time, comments are not skipped.  This means comments happening
before @import statements at the top of a file will cause the @import rules
to not be parsed.  Make sure the @import rules are the very first thing in
the file (and only one per line).  Processing of @import rules stops as soon
as the first line that doesn't match an @import rule is encountered.

All other bugs should be reported via
L<http://rt.cpan.org/Public/Dist/Display.html?Name=CSS-Squish>
or L<bug-CSS-Squish@rt.cpan.org>.

=head1 AUTHOR

Thomas Sibley <trs@bestpractical.com>, Ruslan Zakirov <ruz@bestpractical.com>

=head1 COPYRIGHT AND LICENSE

Copyright (c) 2006.

This library is free software; you can redistribute it and/or modify
it under the same terms as Perl itself, either Perl version 5.8.3 or,
at your option, any later version of Perl 5 you may have available.

=cut

1;