1b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang#!/usr/bin/env python
2b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
3b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# This code is original from jsmin by Douglas Crockford, it was translated to
4b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# Python by Baruch Even. The original code had the following copyright and
5b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# license.
6b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang#
7b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# /* jsmin.c
8b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang#    2007-05-22
9b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang#
10b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# Copyright (c) 2002 Douglas Crockford  (www.crockford.com)
11b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang#
12b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# Permission is hereby granted, free of charge, to any person obtaining a copy of
13b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# this software and associated documentation files (the "Software"), to deal in
14b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# the Software without restriction, including without limitation the rights to
15b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
16b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# of the Software, and to permit persons to whom the Software is furnished to do
17b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# so, subject to the following conditions:
18b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang#
19b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# The above copyright notice and this permission notice shall be included in all
20b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# copies or substantial portions of the Software.
21b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang#
22b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# The Software shall be used for Good, not Evil.
23b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang#
24b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
29b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
30b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# SOFTWARE.
31b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# */
32b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
33b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang# imports adjusted for speed (cStringIO) and python 3 (io) -- nd
34b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangtry:
35b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    from cStringIO import StringIO
36b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangexcept ImportError:
37b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    try:
38b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        from StringIO import StringIO
39b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    except ImportError:
40b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        from io import StringIO
41b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
42b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
43b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangdef jsmin(js):
44b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    ins = StringIO(js)
45b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    outs = StringIO()
46b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    JavascriptMinify().minify(ins, outs)
47b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    str = outs.getvalue()
48b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    if len(str) > 0 and str[0] == '\n':
49b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        str = str[1:]
50b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    return str
51b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
52b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangdef isAlphanum(c):
53b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    """return true if the character is a letter, digit, underscore,
54b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           dollar sign, or non-ASCII character.
55b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    """
56b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    return ((c >= 'a' and c <= 'z') or (c >= '0' and c <= '9') or
57b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            (c >= 'A' and c <= 'Z') or c == '_' or c == '$' or c == '\\' or (c is not None and ord(c) > 126));
58b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
59b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangclass UnterminatedComment(Exception):
60b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    pass
61b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
62b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangclass UnterminatedStringLiteral(Exception):
63b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    pass
64b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
65b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangclass UnterminatedRegularExpression(Exception):
66b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    pass
67b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
68b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangclass JavascriptMinify(object):
69b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
70b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    def _outA(self):
71b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self.outstream.write(self.theA)
72b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    def _outB(self):
73b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self.outstream.write(self.theB)
74b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
75b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    def _get(self):
76b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        """return the next character from stdin. Watch out for lookahead. If
77b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           the character is a control character, translate it to a space or
78b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           linefeed.
79b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        """
80b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        c = self.theLookahead
81b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self.theLookahead = None
82b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        if c == None:
83b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            c = self.instream.read(1)
84b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        if c >= ' ' or c == '\n':
85b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            return c
86b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        if c == '': # EOF
87b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            return '\000'
88b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        if c == '\r':
89b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            return '\n'
90b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        return ' '
91b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
92b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    def _peek(self):
93b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self.theLookahead = self._get()
94b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        return self.theLookahead
95b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
96b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    def _next(self):
97b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        """get the next character, excluding comments. peek() is used to see
98b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           if an unescaped '/' is followed by a '/' or '*'.
99b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        """
100b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        c = self._get()
101b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        if c == '/' and self.theA != '\\':
102b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            p = self._peek()
103b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            if p == '/':
104b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                c = self._get()
105b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                while c > '\n':
106b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    c = self._get()
107b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                return c
108b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            if p == '*':
109b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                c = self._get()
110b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                while 1:
111b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    c = self._get()
112b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    if c == '*':
113b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        if self._peek() == '/':
114b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                            self._get()
115b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                            return ' '
116b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    if c == '\000':
117b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        raise UnterminatedComment()
118b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
119b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        return c
120b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
121b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    def _action(self, action):
122b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        """do something! What you do is determined by the argument:
123b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           1   Output A. Copy B to A. Get the next B.
124b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           2   Copy B to A. Get the next B. (Delete A).
125b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           3   Get the next B. (Delete B).
126b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           action treats a string as a single character. Wow!
127b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           action recognizes a regular expression if it is preceded by ( or , or =.
128b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        """
129b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        if action <= 1:
130b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            self._outA()
131b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
132b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        if action <= 2:
133b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            self.theA = self.theB
134b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            if self.theA == "'" or self.theA == '"':
135b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                while 1:
136b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    self._outA()
137b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    self.theA = self._get()
138b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    if self.theA == self.theB:
139b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        break
140b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    if self.theA <= '\n':
141b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        raise UnterminatedStringLiteral()
142b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    if self.theA == '\\':
143b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        self._outA()
144b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        self.theA = self._get()
145b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
146b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
147b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        if action <= 3:
148b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            self.theB = self._next()
149b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            if self.theB == '/' and (self.theA == '(' or self.theA == ',' or
150b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                                     self.theA == '=' or self.theA == ':' or
151b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                                     self.theA == '[' or self.theA == '?' or
152b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                                     self.theA == '!' or self.theA == '&' or
153b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                                     self.theA == '|' or self.theA == ';' or
154b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                                     self.theA == '{' or self.theA == '}' or
155b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                                     self.theA == '\n'):
156b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                self._outA()
157b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                self._outB()
158b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                while 1:
159b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    self.theA = self._get()
160b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    if self.theA == '/':
161b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        break
162b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    elif self.theA == '\\':
163b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        self._outA()
164b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        self.theA = self._get()
165b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    elif self.theA <= '\n':
166b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        raise UnterminatedRegularExpression()
167b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    self._outA()
168b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                self.theB = self._next()
169b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
170b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
171b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    def _jsmin(self):
172b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        """Copy the input to the output, deleting the characters which are
173b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           insignificant to JavaScript. Comments will be removed. Tabs will be
174b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           replaced with spaces. Carriage returns will be replaced with linefeeds.
175b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang           Most spaces and linefeeds will be removed.
176b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        """
177b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self.theA = '\n'
178b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self._action(3)
179b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
180b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        while self.theA != '\000':
181b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            if self.theA == ' ':
182b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                if isAlphanum(self.theB):
183b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    self._action(1)
184b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                else:
185b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    self._action(2)
186b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            elif self.theA == '\n':
187b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                if self.theB in ['{', '[', '(', '+', '-']:
188b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    self._action(1)
189b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                elif self.theB == ' ':
190b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    self._action(3)
191b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                else:
192b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    if isAlphanum(self.theB):
193b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        self._action(1)
194b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    else:
195b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        self._action(2)
196b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang            else:
197b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                if self.theB == ' ':
198b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    if isAlphanum(self.theA):
199b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        self._action(1)
200b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    else:
201b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        self._action(3)
202b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                elif self.theB == '\n':
203b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    if self.theA in ['}', ']', ')', '+', '-', '"', '\'']:
204b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        self._action(1)
205b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    else:
206b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        if isAlphanum(self.theA):
207b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                            self._action(1)
208b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                        else:
209b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                            self._action(3)
210b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                else:
211b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang                    self._action(1)
212b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
213b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    def minify(self, instream, outstream):
214b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self.instream = instream
215b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self.outstream = outstream
216b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self.theA = '\n'
217b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self.theB = None
218b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self.theLookahead = None
219b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
220b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self._jsmin()
221b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang        self.instream.close()
222b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang
223b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wangif __name__ == '__main__':
224b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    import sys
225b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    jsm = JavascriptMinify()
226b2cf025c7d5cebd43084f38c6c7ff9cc17da428aWei Wang    jsm.minify(sys.stdin, sys.stdout)
227