[Pkg-mozext-commits] [colorediffs-extension] 01/02: Imported Upstream version 0.6.2012.01.27.14.07.45

Michael Fladischer fladi-guest at moszumanska.debian.org
Wed May 14 09:45:57 UTC 2014


This is an automated email from the git hooks/post-receive script.

fladi-guest pushed a commit to branch master
in repository colorediffs-extension.

commit 716c2474f614a9dfcedca799c32afb26babcab20
Author: Michael Fladischer <FladischerMichael at fladi.at>
Date:   Mon May 20 21:18:50 2013 +0200

    Imported Upstream version 0.6.2012.01.27.14.07.45
---
 LICENSE                                            | 470 ++++++++++++++++++
 chrome.manifest                                    |   5 +
 .../content/colorediffs/bindings/bindings.css      |   7 +
 .../content/colorediffs/bindings/colorpicker.css   |   9 +
 .../content/colorediffs/bindings/main-bindings.xbl |  97 ++++
 .../content/colorediffs/callbacks.js               |  38 ++
 .../content/colorediffs/colorediffs.js             | 150 ++++++
 .../content/colorediffs/contents.rdf               |  31 ++
 chrome/colorediffs.jar!/content/colorediffs/dom.js |  44 ++
 .../content/colorediffs/globals.js                 | 151 ++++++
 .../colorediffs.jar!/content/colorediffs/icon.png  | Bin 0 -> 1396 bytes
 .../content/colorediffs/ilUtils.js                 |  28 ++
 .../content/colorediffs/main-overlay.xul           | 102 ++++
 .../content/colorediffs/msgwindowoverlay.xul       |   6 +
 .../colorediffs/options/context-view-options.xul   |  63 +++
 .../colorediffs/options/options-pref-callback.js   |  32 ++
 .../content/colorediffs/options/options-pref.js    |  63 +++
 .../content/colorediffs/options/options.css        |  17 +
 .../content/colorediffs/options/options.js         | 207 ++++++++
 .../content/colorediffs/options/options.xul        | 122 +++++
 .../options/side-by-side-view-options.xul          | 112 +++++
 .../colorediffs/options/unified-view-options.xul   |  63 +++
 .../content/colorediffs/overlay.js                 |  79 +++
 .../content/colorediffs/overlay.xul                |   6 +
 .../content/colorediffs/parsers/context-parser.js  | 160 ++++++
 .../content/colorediffs/parsers/main-parser.js     |   8 +
 .../content/colorediffs/parsers/unified-parser.js  | 551 +++++++++++++++++++++
 .../colorediffs.jar!/content/colorediffs/prefs.js  | 100 ++++
 .../content/colorediffs/toolbar.js                 | 111 +++++
 .../colorediffs/transformations/add-title.js       |  14 +
 .../colorediffs/transformations/calc-chunk-size.js |  19 +
 .../transformations/collect-tab-sizes.js           |  40 ++
 .../colorediffs/transformations/composite-init.js  | 134 +++++
 .../colorediffs/transformations/composite-run.js   |  89 ++++
 .../transformations/composite-transformation.js    |  15 +
 .../transformations/detect-old-new-files.js        |  23 +
 .../transformations/find-common-name.js            | 253 ++++++++++
 .../transformations/main-transformation.js         |   6 +
 .../transformations/make-lines-equal-length.js     |  73 +++
 .../replace-file-names-transformation.js           |  20 +
 .../colorediffs/transformations/replace-tabs.js    |  23 +
 .../transformations/select-old-new-files.js        |  27 +
 .../transformations/show-line-numbers.js           |  87 ++++
 .../show-whitespaces-transformation.js             |  23 +
 .../transformations/truncate-file-names.js         |  87 ++++
 .../content/colorediffs/views/context-view.js      | 243 +++++++++
 .../content/colorediffs/views/main-view.js         |   3 +
 .../content/colorediffs/views/side-by-side-view.js | 335 +++++++++++++
 .../content/colorediffs/views/unified-view.js      | 219 ++++++++
 chrome/colorediffs.jar!/skin/colorediffs.css       |  17 +
 chrome/colorediffs.jar!/skin/line-numbers.png      | Bin 0 -> 342 bytes
 chrome/colorediffs.jar!/skin/options.png           | Bin 0 -> 325 bytes
 chrome/colorediffs.jar!/skin/white-space.png       | Bin 0 -> 289 bytes
 defaults/preferences/colorediffs.js                |  66 +++
 install.rdf                                        |  32 ++
 55 files changed, 4680 insertions(+)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7714141
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,470 @@
+                          MOZILLA PUBLIC LICENSE
+                                Version 1.1
+
+                              ---------------
+
+1. Definitions.
+
+     1.0.1. "Commercial Use" means distribution or otherwise making the
+     Covered Code available to a third party.
+
+     1.1. "Contributor" means each entity that creates or contributes to
+     the creation of Modifications.
+
+     1.2. "Contributor Version" means the combination of the Original
+     Code, prior Modifications used by a Contributor, and the Modifications
+     made by that particular Contributor.
+
+     1.3. "Covered Code" means the Original Code or Modifications or the
+     combination of the Original Code and Modifications, in each case
+     including portions thereof.
+
+     1.4. "Electronic Distribution Mechanism" means a mechanism generally
+     accepted in the software development community for the electronic
+     transfer of data.
+
+     1.5. "Executable" means Covered Code in any form other than Source
+     Code.
+
+     1.6. "Initial Developer" means the individual or entity identified
+     as the Initial Developer in the Source Code notice required by Exhibit
+     A.
+
+     1.7. "Larger Work" means a work which combines Covered Code or
+     portions thereof with code not governed by the terms of this License.
+
+     1.8. "License" means this document.
+
+     1.8.1. "Licensable" means having the right to grant, to the maximum
+     extent possible, whether at the time of the initial grant or
+     subsequently acquired, any and all of the rights conveyed herein.
+
+     1.9. "Modifications" means any addition to or deletion from the
+     substance or structure of either the Original Code or any previous
+     Modifications. When Covered Code is released as a series of files, a
+     Modification is:
+          A. Any addition to or deletion from the contents of a file
+          containing Original Code or previous Modifications.
+
+          B. Any new file that contains any part of the Original Code or
+          previous Modifications.
+
+     1.10. "Original Code" means Source Code of computer software code
+     which is described in the Source Code notice required by Exhibit A as
+     Original Code, and which, at the time of its release under this
+     License is not already Covered Code governed by this License.
+
+     1.10.1. "Patent Claims" means any patent claim(s), now owned or
+     hereafter acquired, including without limitation,  method, process,
+     and apparatus claims, in any patent Licensable by grantor.
+
+     1.11. "Source Code" means the preferred form of the Covered Code for
+     making modifications to it, including all modules it contains, plus
+     any associated interface definition files, scripts used to control
+     compilation and installation of an Executable, or source code
+     differential comparisons against either the Original Code or another
+     well known, available Covered Code of the Contributor's choice. The
+     Source Code can be in a compressed or archival form, provided the
+     appropriate decompression or de-archiving software is widely available
+     for no charge.
+
+     1.12. "You" (or "Your")  means an individual or a legal entity
+     exercising rights under, and complying with all of the terms of, this
+     License or a future version of this License issued under Section 6.1.
+     For legal entities, "You" includes any entity which controls, is
+     controlled by, or is under common control with You. For purposes of
+     this definition, "control" means (a) the power, direct or indirect,
+     to cause the direction or management of such entity, whether by
+     contract or otherwise, or (b) ownership of more than fifty percent
+     (50%) of the outstanding shares or beneficial ownership of such
+     entity.
+
+2. Source Code License.
+
+     2.1. The Initial Developer Grant.
+     The Initial Developer hereby grants You a world-wide, royalty-free,
+     non-exclusive license, subject to third party intellectual property
+     claims:
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Initial Developer to use, reproduce,
+          modify, display, perform, sublicense and distribute the Original
+          Code (or portions thereof) with or without Modifications, and/or
+          as part of a Larger Work; and
+
+          (b) under Patents Claims infringed by the making, using or
+          selling of Original Code, to make, have made, use, practice,
+          sell, and offer for sale, and/or otherwise dispose of the
+          Original Code (or portions thereof).
+
+          (c) the licenses granted in this Section 2.1(a) and (b) are
+          effective on the date Initial Developer first distributes
+          Original Code under the terms of this License.
+
+          (d) Notwithstanding Section 2.1(b) above, no patent license is
+          granted: 1) for code that You delete from the Original Code; 2)
+          separate from the Original Code;  or 3) for infringements caused
+          by: i) the modification of the Original Code or ii) the
+          combination of the Original Code with other software or devices.
+
+     2.2. Contributor Grant.
+     Subject to third party intellectual property claims, each Contributor
+     hereby grants You a world-wide, royalty-free, non-exclusive license
+
+          (a)  under intellectual property rights (other than patent or
+          trademark) Licensable by Contributor, to use, reproduce, modify,
+          display, perform, sublicense and distribute the Modifications
+          created by such Contributor (or portions thereof) either on an
+          unmodified basis, with other Modifications, as Covered Code
+          and/or as part of a Larger Work; and
+
+          (b) under Patent Claims infringed by the making, using, or
+          selling of  Modifications made by that Contributor either alone
+          and/or in combination with its Contributor Version (or portions
+          of such combination), to make, use, sell, offer for sale, have
+          made, and/or otherwise dispose of: 1) Modifications made by that
+          Contributor (or portions thereof); and 2) the combination of
+          Modifications made by that Contributor with its Contributor
+          Version (or portions of such combination).
+
+          (c) the licenses granted in Sections 2.2(a) and 2.2(b) are
+          effective on the date Contributor first makes Commercial Use of
+          the Covered Code.
+
+          (d)    Notwithstanding Section 2.2(b) above, no patent license is
+          granted: 1) for any code that Contributor has deleted from the
+          Contributor Version; 2)  separate from the Contributor Version;
+          3)  for infringements caused by: i) third party modifications of
+          Contributor Version or ii)  the combination of Modifications made
+          by that Contributor with other software  (except as part of the
+          Contributor Version) or other devices; or 4) under Patent Claims
+          infringed by Covered Code in the absence of Modifications made by
+          that Contributor.
+
+3. Distribution Obligations.
+
+     3.1. Application of License.
+     The Modifications which You create or to which You contribute are
+     governed by the terms of this License, including without limitation
+     Section 2.2. The Source Code version of Covered Code may be
+     distributed only under the terms of this License or a future version
+     of this License released under Section 6.1, and You must include a
+     copy of this License with every copy of the Source Code You
+     distribute. You may not offer or impose any terms on any Source Code
+     version that alters or restricts the applicable version of this
+     License or the recipients' rights hereunder. However, You may include
+     an additional document offering the additional rights described in
+     Section 3.5.
+
+     3.2. Availability of Source Code.
+     Any Modification which You create or to which You contribute must be
+     made available in Source Code form under the terms of this License
+     either on the same media as an Executable version or via an accepted
+     Electronic Distribution Mechanism to anyone to whom you made an
+     Executable version available; and if made available via Electronic
+     Distribution Mechanism, must remain available for at least twelve (12)
+     months after the date it initially became available, or at least six
+     (6) months after a subsequent version of that particular Modification
+     has been made available to such recipients. You are responsible for
+     ensuring that the Source Code version remains available even if the
+     Electronic Distribution Mechanism is maintained by a third party.
+
+     3.3. Description of Modifications.
+     You must cause all Covered Code to which You contribute to contain a
+     file documenting the changes You made to create that Covered Code and
+     the date of any change. You must include a prominent statement that
+     the Modification is derived, directly or indirectly, from Original
+     Code provided by the Initial Developer and including the name of the
+     Initial Developer in (a) the Source Code, and (b) in any notice in an
+     Executable version or related documentation in which You describe the
+     origin or ownership of the Covered Code.
+
+     3.4. Intellectual Property Matters
+          (a) Third Party Claims.
+          If Contributor has knowledge that a license under a third party's
+          intellectual property rights is required to exercise the rights
+          granted by such Contributor under Sections 2.1 or 2.2,
+          Contributor must include a text file with the Source Code
+          distribution titled "LEGAL" which describes the claim and the
+          party making the claim in sufficient detail that a recipient will
+          know whom to contact. If Contributor obtains such knowledge after
+          the Modification is made available as described in Section 3.2,
+          Contributor shall promptly modify the LEGAL file in all copies
+          Contributor makes available thereafter and shall take other steps
+          (such as notifying appropriate mailing lists or newsgroups)
+          reasonably calculated to inform those who received the Covered
+          Code that new knowledge has been obtained.
+
+          (b) Contributor APIs.
+          If Contributor's Modifications include an application programming
+          interface and Contributor has knowledge of patent licenses which
+          are reasonably necessary to implement that API, Contributor must
+          also include this information in the LEGAL file.
+
+               (c)    Representations.
+          Contributor represents that, except as disclosed pursuant to
+          Section 3.4(a) above, Contributor believes that Contributor's
+          Modifications are Contributor's original creation(s) and/or
+          Contributor has sufficient rights to grant the rights conveyed by
+          this License.
+
+     3.5. Required Notices.
+     You must duplicate the notice in Exhibit A in each file of the Source
+     Code.  If it is not possible to put such notice in a particular Source
+     Code file due to its structure, then You must include such notice in a
+     location (such as a relevant directory) where a user would be likely
+     to look for such a notice.  If You created one or more Modification(s)
+     You may add your name as a Contributor to the notice described in
+     Exhibit A.  You must also duplicate this License in any documentation
+     for the Source Code where You describe recipients' rights or ownership
+     rights relating to Covered Code.  You may choose to offer, and to
+     charge a fee for, warranty, support, indemnity or liability
+     obligations to one or more recipients of Covered Code. However, You
+     may do so only on Your own behalf, and not on behalf of the Initial
+     Developer or any Contributor. You must make it absolutely clear than
+     any such warranty, support, indemnity or liability obligation is
+     offered by You alone, and You hereby agree to indemnify the Initial
+     Developer and every Contributor for any liability incurred by the
+     Initial Developer or such Contributor as a result of warranty,
+     support, indemnity or liability terms You offer.
+
+     3.6. Distribution of Executable Versions.
+     You may distribute Covered Code in Executable form only if the
+     requirements of Section 3.1-3.5 have been met for that Covered Code,
+     and if You include a notice stating that the Source Code version of
+     the Covered Code is available under the terms of this License,
+     including a description of how and where You have fulfilled the
+     obligations of Section 3.2. The notice must be conspicuously included
+     in any notice in an Executable version, related documentation or
+     collateral in which You describe recipients' rights relating to the
+     Covered Code. You may distribute the Executable version of Covered
+     Code or ownership rights under a license of Your choice, which may
+     contain terms different from this License, provided that You are in
+     compliance with the terms of this License and that the license for the
+     Executable version does not attempt to limit or alter the recipient's
+     rights in the Source Code version from the rights set forth in this
+     License. If You distribute the Executable version under a different
+     license You must make it absolutely clear that any terms which differ
+     from this License are offered by You alone, not by the Initial
+     Developer or any Contributor. You hereby agree to indemnify the
+     Initial Developer and every Contributor for any liability incurred by
+     the Initial Developer or such Contributor as a result of any such
+     terms You offer.
+
+     3.7. Larger Works.
+     You may create a Larger Work by combining Covered Code with other code
+     not governed by the terms of this License and distribute the Larger
+     Work as a single product. In such a case, You must make sure the
+     requirements of this License are fulfilled for the Covered Code.
+
+4. Inability to Comply Due to Statute or Regulation.
+
+     If it is impossible for You to comply with any of the terms of this
+     License with respect to some or all of the Covered Code due to
+     statute, judicial order, or regulation then You must: (a) comply with
+     the terms of this License to the maximum extent possible; and (b)
+     describe the limitations and the code they affect. Such description
+     must be included in the LEGAL file described in Section 3.4 and must
+     be included with all distributions of the Source Code. Except to the
+     extent prohibited by statute or regulation, such description must be
+     sufficiently detailed for a recipient of ordinary skill to be able to
+     understand it.
+
+5. Application of this License.
+
+     This License applies to code to which the Initial Developer has
+     attached the notice in Exhibit A and to related Covered Code.
+
+6. Versions of the License.
+
+     6.1. New Versions.
+     Netscape Communications Corporation ("Netscape") may publish revised
+     and/or new versions of the License from time to time. Each version
+     will be given a distinguishing version number.
+
+     6.2. Effect of New Versions.
+     Once Covered Code has been published under a particular version of the
+     License, You may always continue to use it under the terms of that
+     version. You may also choose to use such Covered Code under the terms
+     of any subsequent version of the License published by Netscape. No one
+     other than Netscape has the right to modify the terms applicable to
+     Covered Code created under this License.
+
+     6.3. Derivative Works.
+     If You create or use a modified version of this License (which you may
+     only do in order to apply it to code which is not already Covered Code
+     governed by this License), You must (a) rename Your license so that
+     the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",
+     "MPL", "NPL" or any confusingly similar phrase do not appear in your
+     license (except to note that your license differs from this License)
+     and (b) otherwise make it clear that Your version of the license
+     contains terms which differ from the Mozilla Public License and
+     Netscape Public License. (Filling in the name of the Initial
+     Developer, Original Code or Contributor in the notice described in
+     Exhibit A shall not of themselves be deemed to be modifications of
+     this License.)
+
+7. DISCLAIMER OF WARRANTY.
+
+     COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,
+     WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
+     WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF
+     DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.
+     THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE
+     IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,
+     YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE
+     COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER
+     OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF
+     ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
+
+8. TERMINATION.
+
+     8.1.  This License and the rights granted hereunder will terminate
+     automatically if You fail to comply with terms herein and fail to cure
+     such breach within 30 days of becoming aware of the breach. All
+     sublicenses to the Covered Code which are properly granted shall
+     survive any termination of this License. Provisions which, by their
+     nature, must remain in effect beyond the termination of this License
+     shall survive.
+
+     8.2.  If You initiate litigation by asserting a patent infringement
+     claim (excluding declatory judgment actions) against Initial Developer
+     or a Contributor (the Initial Developer or Contributor against whom
+     You file such action is referred to as "Participant")  alleging that:
+
+     (a)  such Participant's Contributor Version directly or indirectly
+     infringes any patent, then any and all rights granted by such
+     Participant to You under Sections 2.1 and/or 2.2 of this License
+     shall, upon 60 days notice from Participant terminate prospectively,
+     unless if within 60 days after receipt of notice You either: (i)
+     agree in writing to pay Participant a mutually agreeable reasonable
+     royalty for Your past and future use of Modifications made by such
+     Participant, or (ii) withdraw Your litigation claim with respect to
+     the Contributor Version against such Participant.  If within 60 days
+     of notice, a reasonable royalty and payment arrangement are not
+     mutually agreed upon in writing by the parties or the litigation claim
+     is not withdrawn, the rights granted by Participant to You under
+     Sections 2.1 and/or 2.2 automatically terminate at the expiration of
+     the 60 day notice period specified above.
+
+     (b)  any software, hardware, or device, other than such Participant's
+     Contributor Version, directly or indirectly infringes any patent, then
+     any rights granted to You by such Participant under Sections 2.1(b)
+     and 2.2(b) are revoked effective as of the date You first made, used,
+     sold, distributed, or had made, Modifications made by that
+     Participant.
+
+     8.3.  If You assert a patent infringement claim against Participant
+     alleging that such Participant's Contributor Version directly or
+     indirectly infringes any patent where such claim is resolved (such as
+     by license or settlement) prior to the initiation of patent
+     infringement litigation, then the reasonable value of the licenses
+     granted by such Participant under Sections 2.1 or 2.2 shall be taken
+     into account in determining the amount or value of any payment or
+     license.
+
+     8.4.  In the event of termination under Sections 8.1 or 8.2 above,
+     all end user license agreements (excluding distributors and resellers)
+     which have been validly granted by You or any distributor hereunder
+     prior to termination shall survive termination.
+
+9. LIMITATION OF LIABILITY.
+
+     UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT
+     (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL
+     DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,
+     OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR
+     ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY
+     CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,
+     WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER
+     COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN
+     INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF
+     LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY
+     RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW
+     PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE
+     EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO
+     THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.
+
+10. U.S. GOVERNMENT END USERS.
+
+     The Covered Code is a "commercial item," as that term is defined in
+     48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer
+     software" and "commercial computer software documentation," as such
+     terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48
+     C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),
+     all U.S. Government End Users acquire Covered Code with only those
+     rights set forth herein.
+
+11. MISCELLANEOUS.
+
+     This License represents the complete agreement concerning subject
+     matter hereof. If any provision of this License is held to be
+     unenforceable, such provision shall be reformed only to the extent
+     necessary to make it enforceable. This License shall be governed by
+     California law provisions (except to the extent applicable law, if
+     any, provides otherwise), excluding its conflict-of-law provisions.
+     With respect to disputes in which at least one party is a citizen of,
+     or an entity chartered or registered to do business in the United
+     States of America, any litigation relating to this License shall be
+     subject to the jurisdiction of the Federal Courts of the Northern
+     District of California, with venue lying in Santa Clara County,
+     California, with the losing party responsible for costs, including
+     without limitation, court costs and reasonable attorneys' fees and
+     expenses. The application of the United Nations Convention on
+     Contracts for the International Sale of Goods is expressly excluded.
+     Any law or regulation which provides that the language of a contract
+     shall be construed against the drafter shall not apply to this
+     License.
+
+12. RESPONSIBILITY FOR CLAIMS.
+
+     As between Initial Developer and the Contributors, each party is
+     responsible for claims and damages arising, directly or indirectly,
+     out of its utilization of rights under this License and You agree to
+     work with Initial Developer and Contributors to distribute such
+     responsibility on an equitable basis. Nothing herein is intended or
+     shall be deemed to constitute any admission of liability.
+
+13. MULTIPLE-LICENSED CODE.
+
+     Initial Developer may designate portions of the Covered Code as
+     "Multiple-Licensed".  "Multiple-Licensed" means that the Initial
+     Developer permits you to utilize portions of the Covered Code under
+     Your choice of the NPL or the alternative licenses, if any, specified
+     by the Initial Developer in the file described in Exhibit A.
+
+EXHIBIT A -Mozilla Public License.
+
+     ``The contents of this file are subject to the Mozilla Public License
+     Version 1.1 (the "License"); you may not use this file except in
+     compliance with the License. You may obtain a copy of the License at
+     http://www.mozilla.org/MPL/
+
+     Software distributed under the License is distributed on an "AS IS"
+     basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the
+     License for the specific language governing rights and limitations
+     under the License.
+
+     The Original Code is ______________________________________.
+
+     The Initial Developer of the Original Code is ________________________.
+     Portions created by ______________________ are Copyright (C) ______
+     _______________________. All Rights Reserved.
+
+     Contributor(s): ______________________________________.
+
+     Alternatively, the contents of this file may be used under the terms
+     of the _____ license (the  "[___] License"), in which case the
+     provisions of [______] License are applicable instead of those
+     above.  If you wish to allow use of your version of this file only
+     under the terms of the [____] License and not to allow others to use
+     your version of this file under the MPL, indicate your decision by
+     deleting  the provisions above and replace  them with the notice and
+     other provisions required by the [___] License.  If you do not delete
+     the provisions above, a recipient may use your version of this file
+     under either the MPL or the [___] License."
+
+     [NOTE: The text of this Exhibit A may differ slightly from the text of
+     the notices in the Source Code files of the Original Code. You should
+     use the text of this Exhibit A rather than the text found in the
+     Original Code Source Code for Your Modifications.]
+
diff --git a/chrome.manifest b/chrome.manifest
new file mode 100644
index 0000000..69da7da
--- /dev/null
+++ b/chrome.manifest
@@ -0,0 +1,5 @@
+content	colorediffs	jar:chrome/colorediffs.jar!/content/colorediffs/
+skin colorediffs classic/1.0 jar:chrome/colorediffs.jar!/skin/
+
+overlay	chrome://messenger/content/messenger.xul	chrome://colorediffs/content/overlay.xul
+overlay	chrome://messenger/content/messageWindow.xul	chrome://colorediffs/content/msgwindowoverlay.xul
diff --git a/chrome/colorediffs.jar!/content/colorediffs/bindings/bindings.css b/chrome/colorediffs.jar!/content/colorediffs/bindings/bindings.css
new file mode 100644
index 0000000..f7a97d9
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/bindings/bindings.css
@@ -0,0 +1,7 @@
+viewsmenu {
+	-moz-binding: url('chrome://colorediffs/content/bindings/main-bindings.xbl#views');
+}
+
+colorpicker {
+	-moz-binding: url('chrome://colorediffs/content/bindings/main-bindings.xbl#color-picker');
+}
diff --git a/chrome/colorediffs.jar!/content/colorediffs/bindings/colorpicker.css b/chrome/colorediffs.jar!/content/colorediffs/bindings/colorpicker.css
new file mode 100644
index 0000000..386b760
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/bindings/colorpicker.css
@@ -0,0 +1,9 @@
+.colorpickerspacer {
+	height: 12px;
+	border: 1px inset #CCCCCC;
+}
+
+.colorpickerbutton {
+	min-width: 60px;
+	margin: 1px;
+}
diff --git a/chrome/colorediffs.jar!/content/colorediffs/bindings/main-bindings.xbl b/chrome/colorediffs.jar!/content/colorediffs/bindings/main-bindings.xbl
new file mode 100644
index 0000000..5266687
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/bindings/main-bindings.xbl
@@ -0,0 +1,97 @@
+<?xml version="1.0"?>
+<bindings
+   xmlns="http://www.mozilla.org/xbl"
+   xmlns:xul="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+   xmlns:xbl="http://www.mozilla.org/xbl">
+	<binding id="views">
+		<content>
+			<xul:menulist xbl:inherits="command,preference">
+				<xul:menupopup>
+					<xul:menuitem label="plain" value="none"/>
+				</xul:menupopup>
+			</xul:menulist>
+		</content>
+		<implementation>
+			<constructor><![CDATA[
+				var menulist = document.getAnonymousNodes(this)[0];
+				var menupopup = menulist.firstChild;
+
+				for(var view in colorediffsGlobal.views) {
+					var item = document.createElement("menuitem");
+					item.setAttribute("label", view);
+					item.setAttribute("value", view);
+					menupopup.appendChild(item);
+				}
+
+				if (menulist.hasAttribute('preference')) {
+					var pref = document.getElementById(menulist.getAttribute('preference'));
+					this.selectedItem = pref.valueFromPreferences;
+				}
+			]]></constructor>
+			<property name="selectedItem">
+				<getter><![CDATA[
+					return document.getAnonymousNodes(this)[0].selectedItem.value;
+				]]></getter>
+				<setter><![CDATA[
+					var menulist = document.getAnonymousNodes(this)[0];
+					var items = menulist.firstChild.childNodes;
+					for( var i=0; i < items.length; i++ ) {
+						if ( items[i].getAttribute("value") == val ) {
+							menulist.selectedItem = items[i];
+							break;
+						}
+					}
+				]]></setter>
+			</property>
+			<property name="value">
+				<getter><![CDATA[
+					return this.selectedItem;
+				]]></getter>
+				<setter><![CDATA[
+					this.selectedItem = val;
+				]]></setter>
+			</property>
+		</implementation>
+	</binding>
+
+	<binding id="color-picker">
+		<resources>
+			<stylesheet src="chrome://colorediffs/content/bindings/colorpicker.css"/>
+		</resources>
+		<content>
+			<xul:button class="colorpickerbutton" xbl:inherits="preference">
+				<xul:spacer class="colorpickerspacer" flex="1"/>
+			</xul:button>
+		</content>
+		<implementation>
+			<constructor><![CDATA[
+			]]></constructor>
+			<property name="color">
+				<getter><![CDATA[
+					return document.getAnonymousNodes(this)[0].firstChild.style.backgroundColor;
+				]]></getter>
+				<setter><![CDATA[
+					document.getAnonymousNodes(this)[0].firstChild.style.backgroundColor = val;
+				]]></setter>
+			</property>
+			<property name="value">
+				<getter><![CDATA[
+					return this.color;
+				]]></getter>
+			</property>
+		</implementation>
+		<handlers>
+			<handler event="click" button="0"><![CDATA[
+				var colorObj = { NoDefault:false, Type:"Page", TextColor:0, PageColor:0, Cancel:false };
+
+				window.openDialog("chrome://editor/content/EdColorPicker.xul", "_blank", "chrome,close,titlebar,modal", "", colorObj);
+
+				if (colorObj.Cancel) {
+					return;
+				}
+
+				this.color = colorObj.BackgroundColor;
+			]]></handler>
+		</handlers>
+	</binding>
+</bindings>
diff --git a/chrome/colorediffs.jar!/content/colorediffs/callbacks.js b/chrome/colorediffs.jar!/content/colorediffs/callbacks.js
new file mode 100644
index 0000000..dfc164a
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/callbacks.js
@@ -0,0 +1,38 @@
+if (!colorediffsGlobal) {
+    var colorediffsGlobal = {};
+}
+
+colorediffsGlobal.tooltipCallback = function(element) {
+    var me = colorediffsGlobal;
+
+    function getTooltip() {
+	var elem = element;
+
+	while( elem && elem.nodeName.toLowerCase() != "body" && elem.nodeName.toLowerCase() != "browser" && elem.nodeName.toLowerCase() != "html" && (elem.getAttribute('title') == null || elem.getAttribute('title') == "")) {
+	    elem = elem.parentNode;
+	}
+	return (elem != null)?elem.getAttribute('title'):null;
+    };
+
+    if ( me.isActive() ) {
+	var title = getTooltip();
+	if (title == "") {
+	    title = null;
+	}
+
+	me.$("colorediff-tooltip").value = title;
+	return title != null;
+    } else {
+	return false;
+    }
+
+};
+
+colorediffsGlobal.scrollCallback = function(evt) {
+    var ourclass = evt.target.getAttribute('class');
+    var opositeClass = (ourclass == "left")?"right":"left";
+
+    var otherSide = evt.target.parentNode.parentNode.getElementsByClassName(opositeClass)[0];
+    otherSide.scrollLeft = evt.target.scrollLeft;
+};
+
diff --git a/chrome/colorediffs.jar!/content/colorediffs/colorediffs.js b/chrome/colorediffs.jar!/content/colorediffs/colorediffs.js
new file mode 100644
index 0000000..963be22
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/colorediffs.js
@@ -0,0 +1,150 @@
+if (!colorediffsGlobal) {
+	var colorediffsGlobal = {};
+}
+
+colorediffsGlobal.isMessageDiff = function() {
+	var content = this.getMessagePane();
+	if (!content) {
+		return false;
+	}
+
+	var messagePrefix = /^mailbox-message:|^imap-message:|^news-message:/i;
+	if ( ! messagePrefix.test(gMessageDisplay.folderDisplay.selectedMessageUris[0]) ) {
+		return false;
+	}
+
+	var message = content.contentDocument;
+	var body = message.body;
+
+	if ( !body ) {
+		return false;
+	}
+
+	var text = colorediffsGlobal.htmlToPlainText(body.innerHTML);
+
+	for each (var parser in colorediffsGlobal.parsers) {
+		if (parser.couldParse(text)) {
+			return true;
+		}
+	}
+	return false;
+};
+
+colorediffsGlobal.writeDebugFile = function(filename, html, pref) {
+	if (pref.debugDir.has()) {
+		var debugDir = pref.debugDir.get();
+		if ( debugDir != "" ) {
+			var file = Components.classes["@mozilla.org/file/local;1"]
+				.createInstance(Components.interfaces.nsILocalFile);
+			file.initWithPath(debugDir);
+			file.append(filename);
+
+			var foStream = Components.classes["@mozilla.org/network/file-output-stream;1"]
+				.createInstance(Components.interfaces.nsIFileOutputStream);
+
+			foStream.init(file, 0x02 | 0x08 | 0x20, 0664, 0); // write, create, truncate
+			foStream.write(html, html.length);
+			foStream.close();
+		}
+	}
+};
+
+colorediffsGlobal.onLoadMessage = function() {
+	var me = colorediffsGlobal;
+
+	var message = me.getMessagePane().contentDocument;
+	var pref = new colorediffsGlobal.Pref(colorediffsGlobal.getPrefs());
+	me.writeDebugFile("before1.html", message.documentElement.innerHTML, pref);
+
+	if (!me.isMessageDiff()) {
+	me.setActive(false);
+	me.colorediffsToolbar.initToolbar();
+	return;
+	}
+
+	me.setActive(true);
+	me.colorediffsToolbar.initToolbar();
+
+	//don't do anything if user wants plain
+	if (pref.mode.get() == 'none') {
+	return;
+	}
+
+	var body = message.body;
+
+	me.writeDebugFile("before.html", message.documentElement.innerHTML, pref);
+
+	var divs = body.getElementsByTagName("div");
+	if ( !divs ) {
+		return;
+	}
+
+	var reloadPlanned = false;
+
+	var text = me.fold(divs, function(div, text) {
+		switch(div.getAttribute("class")) {
+			case "moz-text-plain":
+			case "moz-text-flowed":
+				return text + colorediffsGlobal.stripHtml(div) + "\n\n\n";
+			case "moz-text-html":
+				//that means we're looking at HTML part of multipart mail
+				//Check if we're after reload
+				if (colorediffsGlobal.restorePreferHtmlTo === undefined) {
+					//Will try to make Thunderird reload it with text part in use.
+					colorediffsGlobal.restorePreferHtmlTo = pref.preferHtml.get();
+					pref.preferHtml.set(true);
+					ReloadMessage();
+					reloadPlanned = true;
+				} else { //ok, reloading was bad idea, but maybe html part is only log and diff is actually in attached file
+					// so let's give it a try
+					return text + colorediffsGlobal.stripHtml(div) + "\n\n\n";
+				}
+			default:
+				return text;
+		}
+	}, "");
+
+	if (reloadPlanned) {
+		return; //got to reload
+	}
+
+	//Should do it here so we can check whether we planned reload or not in the code that actually plan it.
+	if (colorediffsGlobal.restorePreferHtmlTo !== undefined) {
+		pref.preferHtml.set(colorediffsGlobal.restorePreferHtmlTo);
+		delete colorediffsGlobal.restorePreferHtmlTo;
+	}
+
+	//no luck finding a moz styled divs,
+	//	let's try just stripping all html out
+	if (text == "") {
+		text = colorediffsGlobal.stripHtml(body);
+	}
+
+	me.writeDebugFile("text.html", text, pref);
+	//Choose parser
+	var il = colorediffsGlobal.parse(text, pref);
+
+	//Apply filters
+	il = colorediffsGlobal.transform(il, pref);
+
+	var dom = new colorediffsGlobal.domHelper(message);
+
+	//Generate view
+	var renderedStyleBody = colorediffsGlobal.render(il, pref, dom);
+
+	var head = message.getElementsByTagName("head")[0];
+	head.appendChild(renderedStyleBody[0]);
+
+	body.innerHTML = "";
+	body.appendChild(renderedStyleBody[1]);
+
+	me.writeDebugFile("after.html", message.documentElement.innerHTML, pref);
+
+
+	//inner functions
+	//Strip <pre wrap=""><br><hr size="4" width="90%"><br> tags from every div
+	function stripThunderbirdGeneratedHtml(html) {
+		return html.replace(/^<pre .*?>(?:<br>(?:<hr .*?>|<fieldset .*?>.*?<\/fieldset>)<br>)?((?:.|\n)*)<\/pre>$/i, "$1");
+	}
+};
+
diff --git a/chrome/colorediffs.jar!/content/colorediffs/contents.rdf b/chrome/colorediffs.jar!/content/colorediffs/contents.rdf
new file mode 100644
index 0000000..70b9125
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/contents.rdf
@@ -0,0 +1,31 @@
+<?xml version="1.0"?>
+
+<RDF:RDF xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+		 xmlns:chrome="http://www.mozilla.org/rdf/chrome#">
+
+	<RDF:Seq about="urn:mozilla:package:root">
+		<RDF:li resource="urn:mozilla:package:colorediffs"/>
+	</RDF:Seq>
+
+	<RDF:Description about="urn:mozilla:package:colorediffs"
+			 chrome:displayName="Colored Diffs"
+			 chrome:name="colorediffs">
+	</RDF:Description>
+
+
+	<!-- overlay information -->
+	<RDF:Seq about="urn:mozilla:overlays">
+		<RDF:li resource="chrome://messenger/content/messenger.xul"/>
+		<RDF:li resource="chrome://messenger/content/messageWindow.xul"/>
+	</RDF:Seq>
+
+
+	<RDF:Seq about="chrome://messenger/content/messenger.xul">
+		<RDF:li>chrome://colorediffs/content/overlay.xul</RDF:li>
+	</RDF:Seq>
+
+	<RDF:Seq about="chrome://messenger/content/messageWindow.xul">
+		<RDF:li>chrome://colorediffs/content/msgwindowoverlay.xul</RDF:li>
+	</RDF:Seq>
+
+</RDF:RDF>
diff --git a/chrome/colorediffs.jar!/content/colorediffs/dom.js b/chrome/colorediffs.jar!/content/colorediffs/dom.js
new file mode 100644
index 0000000..e80e419
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/dom.js
@@ -0,0 +1,44 @@
+colorediffsGlobal.domHelper = function(doc) {
+
+	function addElements(element, start_index, array) {
+		var length = array.length;
+		for(var i = start_index; i < length; ++i) {
+			var arg = array[i];
+			switch(typeof arg) {
+				case "string":
+					element.innerHTML += arg;
+					break;
+				case "object":
+					if (arg instanceof Element) {
+						element.appendChild(arg);
+					} else if (arg instanceof Array) {
+						arguments.callee(element, 0, arg);
+					}
+					break;
+				case "function":
+					var res = arg();
+					if ( res != null ) {
+						element.appendChild(res);
+					}
+					break;
+			}
+		}
+	}
+
+	this.createElement = function(tag, attributes) {
+		var element = doc.createElement(tag);
+		for (var attribute in attributes) {
+			element.setAttribute(attribute, attributes[attribute]);
+		}
+
+		addElements(element, 2, arguments);
+
+		return element;
+	};
+
+	this.createDocumentFragment = function() {
+		var element = doc.createDocumentFragment();
+		addElements(element, 0, arguments);
+		return element;
+	};
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/globals.js b/chrome/colorediffs.jar!/content/colorediffs/globals.js
new file mode 100644
index 0000000..f24693f
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/globals.js
@@ -0,0 +1,151 @@
+if (!colorediffsGlobal) {
+	var colorediffsGlobal = {
+		parsers:{},
+		transformations:{},
+		views:{}
+	};
+}
+
+colorediffsGlobal.$ = function(id) {
+	return document.getElementById(id);
+};
+
+colorediffsGlobal.$R = function(f) {
+	return f();
+};
+
+colorediffsGlobal.getMessagePane = function() {
+	if (!this.gmessagePane) {
+		this.gmessagePane = this.$("messagepane");
+	}
+
+	return this.gmessagePane;
+};
+
+colorediffsGlobal.isActive = function(m) {
+	var node = colorediffsGlobal.$("colorediff-mode");
+	if ( node ) {
+		return node.value;
+	} else {
+		return false;
+	}
+};
+
+colorediffsGlobal.setActive = function(m) {
+	colorediffsGlobal.$("colorediff-mode").value = m;
+};
+
+colorediffsGlobal.pad = function(string, l, s) {
+	if (!s) s = " ";
+
+	if ( string.length < l ) {
+		var padding = new Array(Math.ceil((l - string.length)/s.length) + 1);
+
+		return string.concat(padding.join(s));
+	} else {
+		return string;
+	}
+};
+
+colorediffsGlobal.isUpperCaseLetter = function(c) {
+	return /^[A-Z]$/.test(c);
+};
+
+colorediffsGlobal.getPrefs = function() {
+	return Components.classes["@mozilla.org/preferences-service;1"].getService(Components.interfaces.nsIPrefBranch);
+};
+
+colorediffsGlobal.htmlToPlainText = function(html) {
+	var texts = html.split(/(<\/?[^>]+>)/);
+	var text = texts.map(function(string) {
+			if (string.length > 0 && string[0] == '<') {
+				//replace smileys
+				var regExpRes = string.match(/^<img.*?alt\s*=\s*['"](.*)["']/i);
+				if (regExpRes) {
+					return regExpRes[1];
+				} else {
+					return "";
+				}
+			} else {
+				//return string;
+				return string.replace(/&([^;]+);/g, function(str, p1) {
+						switch (p1) {
+							case "nbsp": return " ";
+							case "amp": return "&";
+							case "lt": return "<";
+							case "gt": return ">";
+							case "quot": return '"';
+						}
+						return " ";
+					});
+			}
+	}).join("");
+
+	return text;
+};
+
+colorediffsGlobal.outerHtml = function(dom_node, innerHtml) {
+	var html = "<" + dom_node.tagName;
+	if (dom_node.hasAttributes()) {
+		var attributes = dom_node.attributes;
+		var attributes_length = attributes.length;
+		for (let i = 0; i < attributes_length; i++) {
+			var attribute = attributes[i];
+			html += ' ' + attribute.name + '="' + attribute.value.replace('"', '\\"') + '"';
+		}
+	}
+	html += '>' + innerHtml + '</' + dom_node.tagName + '>';
+	return html;
+};
+
+colorediffsGlobal.stripHtml = function(dom_node) {
+	if (dom_node.nodeName == "#text") {
+		return colorediffsGlobal.escapeHTML(dom_node.textContent);
+	} else if (dom_node.nodeType == 1) {
+		var klass = dom_node.getAttribute("class");
+		var text = colorediffsGlobal.stripHtmlList(dom_node.childNodes);
+		if (klass != null && (klass.indexOf('moz-txt-link') == 0 || klass.indexOf('moz-smiley') == 0)) {
+			text = colorediffsGlobal.outerHtml(dom_node, text);
+		}
+		return text;
+	} else {
+		//it's not a real dom node, comment of something similar.
+		// better to ignore it
+		return "";
+	}
+};
+
+colorediffsGlobal.stripHtmlList = function(dom_node_list) {
+	var text = "";
+	var nodes_length = dom_node_list.length;
+	for (let i = 0; i < nodes_length; i++) {
+		text += colorediffsGlobal.stripHtml(dom_node_list[i]);
+	}
+	return text;
+};
+
+colorediffsGlobal.escapeHTML = function(text) {
+	text = text.replace("&", "&", "g");
+	text = text.replace("<", "<", "g");
+	text = text.replace(">", ">", "g");
+	text = text.replace('"', """, "g");
+	return text;
+};
+
+colorediffsGlobal.unescapeHTML = function(text) {
+	text = text.replace("&", "&", "g");
+	text = text.replace("<", "<", "g");
+	text = text.replace(">", ">", "g");
+	text = text.replace(""", '"', "g");
+	text = text.replace(" ", ' ', "g");
+	return text;
+};
+
+colorediffsGlobal.fold = function(a, fun, o) {
+	var l = a.length;
+	for (var i=0; i < l; ++i) {
+		o = fun(a[i], o);
+	}
+	return o;
+};
+
diff --git a/chrome/colorediffs.jar!/content/colorediffs/icon.png b/chrome/colorediffs.jar!/content/colorediffs/icon.png
new file mode 100644
index 0000000..b494d79
Binary files /dev/null and b/chrome/colorediffs.jar!/content/colorediffs/icon.png differ
diff --git a/chrome/colorediffs.jar!/content/colorediffs/ilUtils.js b/chrome/colorediffs.jar!/content/colorediffs/ilUtils.js
new file mode 100644
index 0000000..3de8de5
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/ilUtils.js
@@ -0,0 +1,28 @@
+colorediffsGlobal.ilUtils = {
+	chunksMap: function (file, func) {
+		var result = [];
+		var l = 0;
+		if ( file['new'] && file['new'].chunks ) {
+			l = Math.max(l, file['new'].chunks.length);
+		} else if ( file['old'] && file['old'].chunks ) {
+			l = Math.max(l, file['old'].chunks.length);
+		}
+
+		for (var i = 0; i < l; i++) {
+			var old_chunk = null;
+			if ( file['old'] && file['old'].chunks	&& file['old'].chunks[i] ) {
+				old_chunk = file['old'].chunks[i];
+			}
+
+			var new_chunk = null;
+			if ( file['new'] && file['new'].chunks	&& file['new'].chunks[i] ) {
+				new_chunk = file['new'].chunks[i];
+			}
+
+
+			result.push(func(old_chunk, new_chunk));
+		}
+
+		return result;
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/main-overlay.xul b/chrome/colorediffs.jar!/content/colorediffs/main-overlay.xul
new file mode 100644
index 0000000..b1937ae
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/main-overlay.xul
@@ -0,0 +1,102 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://colorediffs/content/bindings/bindings.css" type="text/css"?>
+
+<overlay id="main-colorediffs" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+
+	<script type="application/x-javascript" src="chrome://colorediffs/content/globals.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/prefs.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/overlay.js"/>
+
+	<script type="application/x-javascript" src="chrome://colorediffs/content/dom.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/ilUtils.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/callbacks.js"/>
+
+	<script type="application/x-javascript" src="chrome://colorediffs/content/parsers/unified-parser.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/parsers/context-parser.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/parsers/main-parser.js"/>
+
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/composite-transformation.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/composite-init.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/composite-run.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/add-title.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/strip-html.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/find-common-name.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/detect-old-new-files.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/select-old-new-files.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/truncate-file-names.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/make-lines-equal-length.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/replace-file-names-transformation.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/replace-tabs.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/show-whitespaces-transformation.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/show-line-numbers.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/collect-tab-sizes.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/calc-chunk-size.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/main-transformation.js"/>
+
+	<script type="application/x-javascript" src="chrome://colorediffs/content/views/side-by-side-view.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/views/unified-view.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/views/context-view.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/views/main-view.js"/>
+
+	<script type="application/x-javascript" src="chrome://colorediffs/content/colorediffs.js"/>
+	<script type="application/x-javascript" src="chrome://colorediffs/content/toolbar.js"/>
+
+	<vbox id="messagepanebox">
+		<toolbar id="colorediffs-toolbar" toolbarname="Colorediffs Toolbar"
+				 class="chromeclass-toolbar" customizable="true" insertafter="msgHeaderView" hidden="true">
+			<toolbaritem>
+				<viewsmenu id="colorediffs-view-mode" command="cmd_change_mode"/>
+			</toolbaritem>
+			<toolbarbutton id="colorediffs-show-line-numbers" tooltiptext="Show/hide line numbers"
+						   command="cmd_change_line_numbers_mode" checked="false"/>
+			<toolbarbutton id="colorediffs-show-whitespaces" tooltiptext="Show/hide whitespace chars"
+						   command="cmd_change_white_spaces_mode" checked="false"/>
+			<toolbaritem>
+				<menulist tooltiptext="Tune what should be shown" id="colorediffs-diff-mode" command="cmd_change_diff_mode">
+					<menupopup>
+						<menuitem label="both" value="both"/>
+						<menuitem label="new" value="new"/>
+						<menuitem label="old" value="old"/>
+					</menupopup>
+				</menulist>
+			</toolbaritem>
+			<toolbarbutton id="colorediffs-options" tooltiptext="Show options dialog"
+						   command="cmd_show_options"/>
+			<toolbaritem>
+				<menulist tooltiptext="Tab size" id="colorediffs-tab-size" command="cmd_change_tab_size">
+					<menupopup>
+						<menuitem label="2" value="2"/>
+						<menuitem label="4" value="4"/>
+						<menuitem label="8" value="8"/>
+					</menupopup>
+				</menulist>
+			</toolbaritem>
+			<toolbarbutton id="colorediffs-close-toolbar" tooltiptext="Hide toolbar"
+						   command="cmd_change_toolbar"/>
+		</toolbar>
+	</vbox>
+
+	<window id="messengerWindow">
+		<commands>
+			<command id="cmd_change_mode" oncommand="colorediffsGlobal.colorediffsToolbar.selectMode();"/>
+			<command id="cmd_change_white_spaces_mode" oncommand="colorediffsGlobal.colorediffsToolbar.toggleWhiteSpaces();"/>
+			<command id="cmd_change_line_numbers_mode" oncommand="colorediffsGlobal.colorediffsToolbar.toggleLineNumbers();"/>
+			<command id="cmd_show_options" oncommand="colorediffsGlobal.colorediffsToolbar.showOptions();"/>
+			<command id="cmd_change_diff_mode" oncommand="colorediffsGlobal.colorediffsToolbar.selectDiffMode();"/>
+			<command id="cmd_change_tab_size" oncommand="colorediffsGlobal.colorediffsToolbar.selectTabSize();"/>
+			<command id="cmd_change_toolbar" oncommand="colorediffsGlobal.colorediffsToolbar.closeToolbar();"/>
+		</commands>
+
+		<broadcasterset>
+			<broadcaster id="colorediff-mode" value="true"/>
+		</broadcasterset>
+
+		<popupset>
+			<tooltip id="colorediffs-mytooltip-wrapper" orient="vertical" style="background-color: #33DD00;" onpopupshowing="return colorediffsGlobal.tooltipCallback(document.tooltipNode);">
+				<label id="colorediff-tooltip"/>
+			</tooltip>
+		</popupset>
+	</window>
+
+	<browser id="messagepane" tooltip="colorediffs-mytooltip-wrapper"/>
+</overlay>
diff --git a/chrome/colorediffs.jar!/content/colorediffs/msgwindowoverlay.xul b/chrome/colorediffs.jar!/content/colorediffs/msgwindowoverlay.xul
new file mode 100644
index 0000000..354b3f9
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/msgwindowoverlay.xul
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://colorediffs/skin/colorediffs.css" type="text/css"?>
+<?xul-overlay href="chrome://colorediffs/content/main-overlay.xul"?>
+
+<overlay id="msgwindowoverlay" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+</overlay>
diff --git a/chrome/colorediffs.jar!/content/colorediffs/options/context-view-options.xul b/chrome/colorediffs.jar!/content/colorediffs/options/context-view-options.xul
new file mode 100644
index 0000000..93cb84a
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/options/context-view-options.xul
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://colorediffs/content/bindings.css" type="text/css"?>
+<?xul-overlay href="chrome://colorediffs/content/main-overlay.xul"?>
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+	<deck id="view-properties">
+		<preferences>
+			<preference id="c_title-fg-pref" name="diffColorer.c_title_fg" type="string"/>
+			<preference id="c_title-bg-pref" name="diffColorer.c_title_bg" type="string"/>
+			<preference id="c_deletedLine-fg-pref" name="diffColorer.c_deletedLine_fg" type="string"/>
+			<preference id="c_deletedLine-bg-pref" name="diffColorer.c_deletedLine_bg" type="string"/>
+			<preference id="c_addedLine-fg-pref" name="diffColorer.c_addedLine_fg" type="string"/>
+			<preference id="c_addedLine-bg-pref" name="diffColorer.c_addedLine_bg" type="string"/>
+			<preference id="c_steadyLine-fg-pref" name="diffColorer.c_steadyLine_fg" type="string"/>
+			<preference id="c_steadyLine-bg-pref" name="diffColorer.c_steadyLine_bg" type="string"/>
+			<preference id="c_anchor-fg-pref" name="diffColorer.c_anchor_fg" type="string"/>
+			<preference id="c_anchor-bg-pref" name="diffColorer.c_anchor_bg" type="string"/>
+			<preference id="c_precode-fg-pref" name="diffColorer.c_precode_fg" type="string"/>
+			<preference id="c_precode-bg-pref" name="diffColorer.c_precode_bg" type="string"/>
+		</preferences>
+
+		<grid id="context-view-options" flex="1">
+			<columns>
+				<column/>
+				<column class="pickercolumn"/>
+				<column class="pickercolumn"/>
+			</columns>
+			<rows>
+				<row class="center"><spacer/></row>
+				<row align="center">
+					<label value="Title:"/>
+					<colorpicker id="title_fg" preference="c_title-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="title_bg" preference="c_title-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Deleted Lines:"/>
+					<colorpicker id="deletedLine_fg" preference="c_deletedLine-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="deletedLine_bg" preference="c_deletedLine-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Added Lines:"/>
+					<colorpicker id="addedLine_fg" preference="c_addedLine-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="addedLine_bg" preference="c_addedLine-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Steady Lines:"/>
+					<colorpicker id="steadyLine_fg" preference="c_steadyLine-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="steadyLine_bg" preference="c_steadyLine-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Anchors:"/>
+					<colorpicker id="anchor_fg" preference="c_anchor-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="anchor_bg" preference="c_anchor-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Precode:"/>
+					<colorpicker id="precode_fg" preference="c_precode-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="precode_bg" preference="c_precode-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+			</rows>
+		</grid>
+	</deck>
+</overlay>
diff --git a/chrome/colorediffs.jar!/content/colorediffs/options/options-pref-callback.js b/chrome/colorediffs.jar!/content/colorediffs/options/options-pref-callback.js
new file mode 100644
index 0000000..d1fa162
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/options/options-pref-callback.js
@@ -0,0 +1,32 @@
+colorediffsGlobal.OptionsPrefCallbackModel = function(prefModel, callback) {
+	this.getBoolPref = function(prop) {
+		return prefModel.getBoolPref(prop);
+	};
+
+	this.setBoolPref = function(prop, value) {
+		prefModel.setBoolPref(prop, value);
+		callback();
+	};
+
+	this.getIntPref = function(prop) {
+		return prefModel.getIntPref(prop);
+	};
+
+	this.setIntPref = function(prop, value) {
+		prefModel.setIntPref(prop, value);
+		callback();
+	};
+
+	this.getCharPref = function(prop) {
+		return prefModel.getCharPref(prop);
+	};
+
+	this.setCharPref = function(prop, value) {
+		prefModel.setCharPref(prop, value);
+		callback();
+	};
+
+	this.prefHasUserValue = function(prop) {
+		return prefModel.prefHasUserValue(prop);
+	};
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/options/options-pref.js b/chrome/colorediffs.jar!/content/colorediffs/options/options-pref.js
new file mode 100644
index 0000000..491eae0
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/options/options-pref.js
@@ -0,0 +1,63 @@
+if (!colorediffsGlobal) {
+    colorediffsGlobal = {};
+}
+
+colorediffsGlobal.OptionsPrefModel = function(prefModel) {
+	var boolPrefs = {};
+	var charPrefs = {};
+	var intPrefs = {};
+
+	var getPref = function(hash, prop, defFunc) {
+		return (hash[prop] != undefined) ? hash[prop] : defFunc(prop);
+	};
+
+	var setPref = function(hash, prop, value) {
+		hash[prop] = value;
+	};
+
+	var hasPref = function(prop) {
+		return boolPrefs[prop] != undefined || charPrefs[prop] != undefined || intPrefs[prop] != undefined;;
+	};
+
+	this.getBoolPref = function(prop) {
+		return getPref(boolPrefs, prop, prefModel.getBoolPref);
+	};
+
+	this.setBoolPref = function(prop, value) {
+		setPref(boolPrefs, prop, value);
+	};
+
+	this.getIntPref = function(prop) {
+		return getPref(intPrefs, prop, prefModel.getIntPref);
+	};
+
+	this.setIntPref = function(prop, value) {
+		setPref(intPrefs, prop, value);
+	};
+
+	this.getCharPref = function(prop) {
+		return getPref(charPrefs, prop, prefModel.getCharPref);
+	};
+
+	this.setCharPref = function(prop, value) {
+		setPref(charPrefs, prop, value);
+	};
+
+	this.prefHasUserValue = function(prop) {
+		return hasPref(prop) || prefModel.prefHasUserValue(prop);
+	};
+
+	this.saveToModel = function() {
+		for (var b in boolPrefs) {
+			prefModel.setBoolPref(b, boolPrefs[b]);
+		}
+
+		for (var c in charPrefs) {
+			prefModel.setCharPref(c, charPrefs[c]);
+		}
+
+		for (var i in intPrefs) {
+			prefModel.setIntPref(c, intPrefs[i]);
+		}
+	};
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/options/options.css b/chrome/colorediffs.jar!/content/colorediffs/options/options.css
new file mode 100644
index 0000000..4023d68
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/options/options.css
@@ -0,0 +1,17 @@
+#previewbox {
+	background-color:white;
+	border: 1px inset ThreedShadow;
+	padding: 5px;
+	height:8em;
+	width:30em;
+}
+
+.center {
+	text-align:center;
+}
+
+.pickercolumn {
+	width:5em;
+}
+
+
diff --git a/chrome/colorediffs.jar!/content/colorediffs/options/options.js b/chrome/colorediffs.jar!/content/colorediffs/options/options.js
new file mode 100644
index 0000000..b601810
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/options/options.js
@@ -0,0 +1,207 @@
+if (!colorediffsGlobal) {
+	var colorediffsGlobal = {}
+}
+
+colorediffsGlobal.initOptions = function() {
+	var me = colorediffsGlobal;
+
+	var globalPrefs = new colorediffsGlobal.Pref(colorediffsGlobal.getPrefs());
+
+	if ( globalPrefs.instantApply.get() ) {
+		//repaint all the instances at every change.
+		var internalPrefs = new colorediffsGlobal.OptionsPrefCallbackModel(
+			colorediffsGlobal.getPrefs(),
+			function() {
+				updatePreview();
+				//repaint actual mail message
+				var observerService =
+					Components.classes["@mozilla.org/observer-service;1"]
+					.getService(Components.interfaces.nsIObserverService);
+				observerService.notifyObservers(null, "colored-diff-update", null);
+			});
+	} else {
+		//Store changes and commit them only by OK button.
+		//Repaint only preview
+		var cachedPrefs = new colorediffsGlobal.OptionsPrefModel(colorediffsGlobal.getPrefs());
+
+		var internalPrefs = new colorediffsGlobal.OptionsPrefCallbackModel(
+			cachedPrefs,
+			function() {
+				updatePreview();
+			});
+	}
+
+	var prefs = new colorediffsGlobal.Pref(internalPrefs);
+
+	var getNodeGetter = function (name) {
+		return function() {return me.$(name);}
+	}
+
+	var getViewModeNode = getNodeGetter('view_mode');
+	var getViewNode = getNodeGetter('view');
+	var getPreviewNode = getNodeGetter('previewbox');
+
+	var savePrefs = function() {
+		if (cachedPrefs) {
+			cachedPrefs.saveToModel();
+
+			//repaint actual mail message
+			var observerService =
+				Components.classes["@mozilla.org/observer-service;1"]
+				.getService(Components.interfaces.nsIObserverService);
+			observerService.notifyObservers(null, "colored-diff-update", null);
+		} //else everything is saved and updated already
+	}
+
+	var updatePreview = function() {
+		if (prefs.mode.get() == "none") {
+			var code = "" + <r><![CDATA[
+<pre>
+Log message
+
+File title
+===============================
+--- filename
++++ filename
+@@ -10,4 +10,5 @@
+ line1
+ line2
+ line3
++line4
+ line5
+</pre>
+]]></r>;
+
+
+			var doc = getPreviewNode().contentDocument;
+			var head = doc.getElementsByTagName("head")[0];
+			head.innerHTML = "";
+
+			var body = doc.getElementsByTagName("body")[0];
+			body.innerHTML = code;
+
+		} else {
+			var status = ["S", "S", "S", "A", "S"];
+
+			var il = {
+				log:"Log message",
+				files:[
+					{title: "File title",
+					 additional_info:null,
+					 'old': {
+						name: "filename",
+						chunks: [
+							{line:10,
+							 code:[
+								 " line1",
+								 "	line2",
+								 " line3",
+								 null,
+								 "	line5"],
+							 status: status,
+							 doesnt_have_new_line:false}]
+					 },
+					 'new': {
+						name: "filename",
+						chunks: [
+							{line:10,
+							 code:[
+								 " line1",
+								 "	line2",
+								 " line3",
+								 " line4",
+								 "	line5"],
+							 status: status,
+							 doesnt_have_new_line:false}]
+					 }}]};
+
+			var doc = getPreviewNode().contentDocument;
+			var dom = new colorediffsGlobal.domHelper(doc);
+
+			//Apply filters
+			var il = colorediffsGlobal.transform(il, prefs);
+
+			//Generate view
+			var renderedStyleBody = colorediffsGlobal.render(il, prefs, dom);
+
+			var head = doc.getElementsByTagName("head")[0];
+			head.innerHTML = "";
+			head.appendChild(renderedStyleBody[0]);
+
+			var body = doc.getElementsByTagName("body")[0];
+			body.innerHTML = "";
+			body.appendChild(renderedStyleBody[1]);
+		}
+	}
+
+	colorediffsGlobal.options =	{
+		checkOptions : function() {
+			savePrefs();
+			return true;
+		},
+
+		onChangeMode : function() {
+			var deck = me.$("view-properties");
+
+			if (getViewNode().selectedItem == "none") {
+				deck.selectedIndex = 0;
+			} else {
+				var view = me.views[getViewNode().selectedItem];
+
+				//change options page
+				var children = deck.childNodes;
+				var l = children.length;
+
+				for (var i=1; i <l; i++) {
+					if (children[i].id == view.getPropertyPageId()) {
+						deck.selectedIndex = i;
+						break;
+					}
+				}
+			}
+
+			window.sizeToContent();
+		},
+
+		//new code
+		changePref: function(control) {
+			var pref = document.getElementById(control.getAttribute('preference'));
+
+			if (control.value != undefined) {
+				var value = control.value;
+			} else if (control.checked != undefined) {
+				var value = control.checked;
+			} else if (control.color != undefined) {
+				var value = control.color;
+			} else if (control.selectedItem != undefined) {
+				var value = control.selectedItem;
+			}
+
+			switch (pref.type) {
+				case "bool":
+					internalPrefs.setBoolPref(pref.name, value);
+					break;
+				case "string":
+					internalPrefs.setCharPref(pref.name, value);
+					break;
+			}
+		}
+
+	}
+
+	getPreviewNode().contentWindow.setTimeout(function() {
+		if (getPreviewNode().contentDocument.getElementsByTagName("body")[0].innerHTML == "") {
+			updatePreview();
+		}
+		getPreviewNode().contentWindow.setTimeout(arguments.callee, 1000);
+	}, 1000);
+	
+        //init code
+	updatePreview();
+	colorediffsGlobal.options.onChangeMode();
+}
+
+colorediffsGlobal.deleteOptions = function() {
+	colorediffsGlobal.options = null;
+}
+
diff --git a/chrome/colorediffs.jar!/content/colorediffs/options/options.xul b/chrome/colorediffs.jar!/content/colorediffs/options/options.xul
new file mode 100644
index 0000000..eb1b9fd
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/options/options.xul
@@ -0,0 +1,122 @@
+<?xml version="1.0"?>
+
+<?xml-stylesheet href="chrome://global/skin/" type="text/css"?>
+<?xml-stylesheet href="chrome://colorediffs/content/options/options.css" type="text/css"?>
+<?xml-stylesheet href="chrome://colorediffs/content/bindings/bindings.css" type="text/css"?>
+
+<?xul-overlay href="chrome://colorediffs/content/options/unified-view-options.xul"?>
+<?xul-overlay href="chrome://colorediffs/content/options/context-view-options.xul"?>
+<?xul-overlay href="chrome://colorediffs/content/options/side-by-side-view-options.xul"?>
+
+<prefwindow xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"
+		xmlns:html="http://www.w3.org/1999/xhtml"
+		id="settings"
+		onload="colorediffsGlobal.initOptions();"
+		persist="width height screenX screenY sizemode"
+		ondialogaccept="colorediffsGlobal.options.checkOptions();colorediffsGlobal.deleteOptions();"
+		ondialogcancel="colorediffsGlobal.deleteOptions();"
+		title="Colored Diffs"
+		width = "1000">
+
+	<prefpane id="colorediffsSettingsPane" style = "width:200em">
+		<preferences>
+			<preference id="show-whitespace" name="diffColorer.show-whitespace" type="bool" instantApply="false"/>
+			<preference id="show-line-numbers" name="diffColorer.show-line-numbers" type="bool" instantApply="false"/>
+			<preference id="show-toolbar" name="diffColorer.show-toolbar" type="bool"/>
+			<preference id="view-mode-pref" name="diffColorer.view-mode" type="string"/>
+		</preferences>
+
+		<script type="application/x-javascript" src="chrome://colorediffs/content/globals.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/prefs.js"/>
+
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/composite-transformation.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/composite-init.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/composite-run.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/find-common-name.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/strip-html.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/detect-old-new-files.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/select-old-new-files.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/truncate-file-names.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/make-lines-equal-length.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/add-title.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/replace-file-names-transformation.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/replace-tabs.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/show-whitespaces-transformation.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/show-line-numbers.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/collect-tab-sizes.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/calc-chunk-size.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/transformations/main-transformation.js"/>
+
+		<script type="application/x-javascript" src="chrome://colorediffs/content/views/side-by-side-view.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/views/unified-view.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/views/context-view.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/views/main-view.js"/>
+
+		<script type="application/x-javascript" src="chrome://colorediffs/content/options/options-pref.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/options/options-pref-callback.js"/>
+		<script type="application/x-javascript" src="chrome://colorediffs/content/options/options.js"/>
+
+	<commands>
+		<command id="cmd_change_mode" oncommand="colorediffsGlobal.options.changePref(event.explicitOriginalTarget);colorediffsGlobal.options.onChangeMode();"/>
+		<command id="cmd_change_color" oncommand="updatePreview();"/>
+		<command id="cmd_change_pref" oncommand="colorediffsGlobal.options.changePref(event.explicitOriginalTarget);"/>
+	</commands>
+
+	<broadcasterset>
+		<broadcaster id="view_mode" value="unified"/>
+	</broadcasterset>
+
+	<!--this is the nice way to set style to multiple controls-->
+	<!--all the controls should work this way but I don't have time to do this now-->
+	<broadcasterset>
+		<broadcaster id="sbs_steadyLine" style=""/>
+		<broadcaster id="sbs_addedLine" style=""/>
+	</broadcasterset>
+
+	<hbox style = "width:200em">
+		<tabbox>
+			<tabs>
+				<tab label="Views"/>
+				<tab label="General options"/>
+			</tabs>
+			<tabpanels>
+				<tabpanel>
+					<groupbox>
+						<caption>
+							<label value="Choose view:"/>
+							<viewsmenu id="view" command="cmd_change_mode" preference="view-mode-pref"/>
+						</caption>
+						<hbox align="center">
+							<spacer flex="1"/>
+							<deck id="view-properties">
+								<box id="plan-view-options"/>
+							</deck>
+						</hbox>
+						<spacer style="margin-top:10px"/>
+					</groupbox>
+				</tabpanel>
+				<tabpanel>
+					<hbox align="baseline">
+						<vbox>
+							<checkbox id="show-whitespaces" label="Show whitespaces" checked="false" command="cmd_change_pref" preference="show-whitespace"/>
+							<checkbox id="show-line-numbers" label="Show line numbers" checked="false" command="cmd_change_pref" preference="show-line-numbers"/>
+						</vbox>
+						<checkbox id="show-toolbar" label="Show toolbar" checked="false" command="cmd_change_pref" preference="show-toolbar"/>
+					</hbox>
+				</tabpanel>
+			</tabpanels>
+		</tabbox>
+		<spacer/>
+		<vbox style="width:50em">
+			<deck>
+				<box/>
+				<tab/>
+			</deck>
+			<browser
+				onload="colorediffsGlobal.options.onChangeMode();"
+				id="previewbox" flex="1"/>
+		</vbox>
+	</hbox>
+	<spacer flex="1" style="height:5px;"/>
+	</prefpane>
+</prefwindow>
diff --git a/chrome/colorediffs.jar!/content/colorediffs/options/side-by-side-view-options.xul b/chrome/colorediffs.jar!/content/colorediffs/options/side-by-side-view-options.xul
new file mode 100644
index 0000000..cc37200
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/options/side-by-side-view-options.xul
@@ -0,0 +1,112 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://colorediffs/content/bindings.css" type="text/css"?>
+<?xul-overlay href="chrome://colorediffs/content/main-overlay.xul"?>
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+	<deck id="view-properties">
+		<preferences>
+			<preference id="sbs_log-fg-pref" name="diffColorer.sbs_log_fg" type="string"/>
+			<preference id="sbs_log-bg-pref" name="diffColorer.sbs_log_bg" type="string"/>
+			<preference id="sbs_precode-fg-pref" name="diffColorer.sbs_precode_fg" type="string"/>
+			<preference id="sbs_precode-bg-pref" name="diffColorer.sbs_precode_bg" type="string"/>
+			<preference id="sbs_left-title-fg-pref" name="diffColorer.sbs_left-title_fg" type="string"/>
+			<preference id="sbs_left-title-bg-pref" name="diffColorer.sbs_left-title_bg" type="string"/>
+			<preference id="sbs_right-title-fg-pref" name="diffColorer.sbs_right-title_fg" type="string"/>
+			<preference id="sbs_right-title-bg-pref" name="diffColorer.sbs_right-title_bg" type="string"/>
+			<preference id="sbs_file-diff-fg-pref" name="diffColorer.sbs_file-diff_fg" type="string"/>
+			<preference id="sbs_file-diff-bg-pref" name="diffColorer.sbs_file-diff_bg" type="string"/>
+			<preference id="sbs_left-fg-pref" name="diffColorer.sbs_left_fg" type="string"/>
+			<preference id="sbs_left-bg-pref" name="diffColorer.sbs_left_bg" type="string"/>
+			<preference id="sbs_right-fg-pref" name="diffColorer.sbs_right_fg" type="string"/>
+			<preference id="sbs_right-bg-pref" name="diffColorer.sbs_right_bg" type="string"/>
+			<preference id="sbs_emptyLine-fg-pref" name="diffColorer.sbs_emptyLine_fg" type="string"/>
+			<preference id="sbs_emptyLine-bg-pref" name="diffColorer.sbs_emptyLine_bg" type="string"/>
+			<preference id="sbs_title-fg-pref" name="diffColorer.sbs_title_fg" type="string"/>
+			<preference id="sbs_title-bg-pref" name="diffColorer.sbs_title_bg" type="string"/>
+			<preference id="sbs_deletedLine-fg-pref" name="diffColorer.sbs_deletedLine_fg" type="string"/>
+			<preference id="sbs_deletedLine-bg-pref" name="diffColorer.sbs_deletedLine_bg" type="string"/>
+			<preference id="sbs_addedLine-fg-pref" name="diffColorer.sbs_addedLine_fg" type="string"/>
+			<preference id="sbs_addedLine-bg-pref" name="diffColorer.sbs_addedLine_bg" type="string"/>
+			<preference id="sbs_steadyLine-fg-pref" name="diffColorer.sbs_steadyLine_fg" type="string"/>
+			<preference id="sbs_steadyLine-bg-pref" name="diffColorer.sbs_steadyLine_bg" type="string"/>
+			<preference id="sbs_anchor-fg-pref" name="diffColorer.sbs_anchor_fg" type="string"/>
+			<preference id="sbs_anchor-bg-pref" name="diffColorer.sbs_anchor_bg" type="string"/>
+		</preferences>
+
+		<grid id="side-by-side-view-options" flex="1">
+			<columns>
+				<column/>
+				<column class="pickercolumn"/>
+				<column class="pickercolumn"/>
+			</columns>
+			<rows>
+				<row class="center"><spacer/></row>
+				<row align="center">
+					<label value="Log:"/>
+					<colorpicker id="sbs_log_fg" preference="sbs_log-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_log_bg" preference="sbs_log-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Whole diff:"/>
+					<colorpicker id="sbs_file-diff_fg" preference="sbs_file-diff-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_file-diff_bg" preference="sbs_file-diff-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Title:"/>
+					<colorpicker id="sbs_title_fg" preference="sbs_title-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_title_bg" preference="sbs_title-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Additional info:"/>
+					<colorpicker id="sbs_precode_fg" preference="sbs_precode-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_precode_bg" preference="sbs_precode-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Left diff header:"/>
+					<colorpicker id="sbs_left-title_fg" preference="sbs_left-title-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_left-title_bg" preference="sbs_left-title-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Right diff header:"/>
+					<colorpicker id="sbs_right-title_fg" preference="sbs_right-title-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_right-title_bg" preference="sbs_right-title-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Anchors:"/>
+					<colorpicker id="sbs_anchor_fg" preference="sbs_anchor-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_anchor_bg" preference="sbs_anchor-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Left diff:"/>
+					<colorpicker id="sbs_left_fg" preference="sbs_left-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_left_bg" preference="sbs_left-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Right diff:"/>
+					<colorpicker id="sbs_right_fg" preference="sbs_right-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_right_bg" preference="sbs_right-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Deleted Lines:"/>
+					<colorpicker id="sbs_deletedLine_fg" preference="sbs_deletedLine-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_deletedLine_bg" preference="sbs_deletedLine-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Added Lines:"/>
+					<colorpicker id="sbs_addedLine_fg" preference="sbs_addedLine-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_addedLine_bg" preference="sbs_addedLine-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Steady Lines:"/>
+					<colorpicker id="sbs_steadyLine_fg" preference="sbs_steadyLine-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_steadyLine_bg" preference="sbs_steadyLine-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Non existing line:"/>
+					<colorpicker id="sbs_emptyLine_fg" preference="sbs_emptyLine-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="sbs_emptyLine_bg" preference="sbs_emptyLine-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+			</rows>
+		</grid>
+	</deck>
+</overlay>
diff --git a/chrome/colorediffs.jar!/content/colorediffs/options/unified-view-options.xul b/chrome/colorediffs.jar!/content/colorediffs/options/unified-view-options.xul
new file mode 100644
index 0000000..f11a156
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/options/unified-view-options.xul
@@ -0,0 +1,63 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://colorediffs/content/bindings.css" type="text/css"?>
+<?xul-overlay href="chrome://colorediffs/content/main-overlay.xul"?>
+
+<overlay xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+	<deck id="view-properties">
+		<preferences>
+			<preference id="title-fg-pref" name="diffColorer.title_fg" type="string"/>
+			<preference id="title-bg-pref" name="diffColorer.title_bg" type="string"/>
+			<preference id="deletedLine-fg-pref" name="diffColorer.deletedLine_fg" type="string"/>
+			<preference id="deletedLine-bg-pref" name="diffColorer.deletedLine_bg" type="string"/>
+			<preference id="addedLine-fg-pref" name="diffColorer.addedLine_fg" type="string"/>
+			<preference id="addedLine-bg-pref" name="diffColorer.addedLine_bg" type="string"/>
+			<preference id="steadyLine-fg-pref" name="diffColorer.steadyLine_fg" type="string"/>
+			<preference id="steadyLine-bg-pref" name="diffColorer.steadyLine_bg" type="string"/>
+			<preference id="anchor-fg-pref" name="diffColorer.anchor_fg" type="string"/>
+			<preference id="anchor-bg-pref" name="diffColorer.anchor_bg" type="string"/>
+			<preference id="precode-fg-pref" name="diffColorer.precode_fg" type="string"/>
+			<preference id="precode-bg-pref" name="diffColorer.precode_bg" type="string"/>
+		</preferences>
+
+		<grid id="unified-view-options" flex="1">
+			<columns>
+				<column/>
+				<column class="pickercolumn"/>
+				<column class="pickercolumn"/>
+			</columns>
+			<rows>
+				<row class="center"><spacer/></row>
+				<row align="center">
+					<label value="Title:"/>
+					<colorpicker id="title_fg" preference="title-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="title_bg" preference="title-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Deleted Lines:"/>
+					<colorpicker id="deletedLine_fg" preference="deletedLine-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="deletedLine_bg" preference="deletedLine-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Added Lines:"/>
+					<colorpicker id="addedLine_fg" preference="addedLine-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="addedLine_bg" preference="addedLine-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Steady Lines:"/>
+					<colorpicker id="steadyLine_fg" preference="steadyLine-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="steadyLine_bg" preference="steadyLine-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Anchors:"/>
+					<colorpicker id="anchor_fg" preference="anchor-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="anchor_bg" preference="anchor-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+				<row align="center">
+					<label value="Precode:"/>
+					<colorpicker id="precode_fg" preference="precode-fg-pref" command="cmd_change_pref" type="button" flex="1"/>
+					<colorpicker id="precode_bg" preference="precode-bg-pref" command="cmd_change_pref" type="button" flex="1"/>
+				</row>
+			</rows>
+		</grid>
+	</deck>
+</overlay>
diff --git a/chrome/colorediffs.jar!/content/colorediffs/overlay.js b/chrome/colorediffs.jar!/content/colorediffs/overlay.js
new file mode 100644
index 0000000..985c41b
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/overlay.js
@@ -0,0 +1,79 @@
+if (!colorediffsGlobal) {
+	var colorediffsGlobal = {};
+}
+
+//This observer make sure message get redrew if user change layout
+colorediffsGlobal.MailPaneConfigObserver = {
+	observe: function(subject, topic, prefName) {
+		// verify that we're changing the mail pane config pref
+		if (topic == "nsPref:changed") {
+			colorediffsGlobal.load();
+		}
+	}
+};
+
+colorediffsGlobal.load = function() {
+	var me = colorediffsGlobal;
+
+	var gmessagepane = me.getMessagePane();
+	if (gmessagepane) {
+	gmessagepane.addEventListener("load", function() {me.onLoadMessage();}, true);
+	}
+
+	var updateObserver = {
+	observe: function(subject, topic, data) {
+		if(topic=="colored-diff-update" && me.isActive()) {
+		ReloadMessage();
+		}
+	}
+	};
+
+	var observerService = Components.classes["@mozilla.org/observer-service;1"].getService(Components.interfaces.nsIObserverService);
+	observerService.addObserver(updateObserver, "colored-diff-update", false);
+
+	var unload = function() {
+	var pref = me.getPrefs();
+	pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
+	pref.removeObserver("mail.pane_config.dynamic", me.MailPaneConfigObserver);
+
+	observerService.removeObserver(updateObserver, "colored-diff-update");
+	};
+
+	window.addEventListener("unload", unload, false);
+
+//	   Components.utils.import("resource://test-framework/main.js");
+//	   run_tests("{282C3C7A-15A8-4037-A30D-BBEB17FFC76B}", "content/colorediffs/tests", document);
+
+	// var pref = new colorediffsGlobal.Pref(colorediffsGlobal.getPrefs());
+	// if (pref.debugDir.has()) {
+	// //run tests
+
+	// var MY_ID = "{282C3C7A-15A8-4037-A30D-BBEB17FFC76B}";
+	// var em = Components.classes["@mozilla.org/extensions/manager;1"].getService(Components.interfaces.nsIExtensionManager);
+	// var file = em.getInstallLocation(MY_ID).getItemFile(MY_ID, "test-framework/main.js");
+	// var fstream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
+	// var sstream = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
+	// fstream.init(file, -1, 0, 0);
+	// sstream.init(fstream);
+
+	// var data = "";
+	// var str = sstream.read(4096);
+	// while (str.length > 0) {data += str; str = sstream.read(4096);}
+
+	// sstream.close();
+	// fstream.close();
+
+	// eval(data);
+	// run_tests(MY_ID, "content/colorediffs/tests/", document);
+	// }
+};
+
+colorediffsGlobal.temp = function() {
+	var me = colorediffsGlobal;
+	var pref = me.getPrefs();
+
+	pref.QueryInterface(Components.interfaces.nsIPrefBranchInternal);
+	pref.addObserver("mail.pane_config.dynamic", me.MailPaneConfigObserver, false);
+
+	window.addEventListener("load", function() {me.load();}, false);
+}();
diff --git a/chrome/colorediffs.jar!/content/colorediffs/overlay.xul b/chrome/colorediffs.jar!/content/colorediffs/overlay.xul
new file mode 100644
index 0000000..c6e3080
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/overlay.xul
@@ -0,0 +1,6 @@
+<?xml version="1.0"?>
+<?xml-stylesheet href="chrome://colorediffs/skin/colorediffs.css" type="text/css"?>
+<?xul-overlay href="chrome://colorediffs/content/main-overlay.xul"?>
+
+<overlay id="colorediffs" xmlns="http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul">
+</overlay>
diff --git a/chrome/colorediffs.jar!/content/colorediffs/parsers/context-parser.js b/chrome/colorediffs.jar!/content/colorediffs/parsers/context-parser.js
new file mode 100644
index 0000000..7242dce
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/parsers/context-parser.js
@@ -0,0 +1,160 @@
+colorediffsGlobal.parsers["context"] = {
+	parse:function(text) {
+		var parseFile = function(title, code) {
+			var parseChunk = function(code) {
+				var chunks = {};
+				chunks['old'] = {};
+				chunks['new'] = {};
+
+				var parts = code.split(/^(?:\*|\-){3}\s+(\d+)\,\d+\s+(?:\*|\-){4}$/m);
+
+				//parts[0] is "\n"
+				// parts[1] is line number of old code
+				// parts[2] is either old code or "\n"
+				// parts[3] is line number of new code
+				// parts[4] is new code
+
+				chunks['new'].line = Number(parts[3]);
+				chunks['old'].line = Number(parts[1]);
+
+				//split code
+				chunks['old'].code = [];
+				chunks['new'].code = [];
+
+				var line_status = [];
+
+				var processSteadyParts = function(oldCodeString, newCodeString) {
+					var i=0, j=0;
+
+					var oldCode = [];
+					var newCode = [];
+
+					var oldLines = oldCodeString.trim("\n").split("\n");
+					var newLines = newCodeString.trim("\n").split("\n");
+
+					var line_status = [];
+
+					while ( i < oldLines.length || j < newLines.length ) {
+						if (/^\-(.*)$/.test(oldLines[i])) {
+							oldCode.push(oldLines[i].substring(2));
+							newCode.push(null);
+							line_status.push("D"); //Deleted
+							i++;
+						} else if (/^\+(.*)$/.test(newLines[j])) {
+							newCode.push(newLines[j].substring(2));
+							oldCode.push(null);
+							line_status.push("A"); //Added
+							j++;
+						} else {
+							if ( /^ (.*)$/.test(oldLines[i] ) ) {
+								oldCode.push(oldLines[i].substring(2));
+								newCode.push(oldLines[i].substring(2));
+								line_status.push("S"); //the Same
+							} else if ( /^ (.*)$/.test(newLines[j] ) ) {
+								newCode.push(newLines[j].substring(2));
+								oldCode.push(newLines[j].substring(2));
+								line_status.push("S"); //the Same
+							}
+							i++; j++;
+						}
+					}
+					return [oldCode, newCode, line_status];
+				}
+
+				//Separate modified parts from non-modified
+				var modifiedPartsOld = parts[2].split(/(\n(?:!.*\n)+)/);
+				var modifiedPartsNew = parts[4].split(/(\n(?:!.*\n)+)/);
+
+				//There are always the same number of modified/non-modified parts in old and new code
+				for (var i = 0; i < modifiedPartsOld.length; i++) {
+					if ( /^!/m.test(modifiedPartsOld[i]) ) {
+						//modified parts
+						chunks['old'].code = chunks['old'].code.concat(modifiedPartsOld[i].trim("\n").replace(/^! /mg, "").split("\n"));
+						chunks['new'].code = chunks['new'].code.concat(modifiedPartsNew[i].trim("\n").replace(/^! /mg, "").split("\n"));
+						var minCodeLength = Math.min(chunks['old'].code.length, chunks['new'].code.length);
+
+						while ( line_status.length < minCodeLength ) {
+							line_status.push("C"); //Changed
+						}
+
+						while ( chunks['old'].code.length < chunks['new'].code.length ) {
+							chunks['old'].code.push(null);
+							line_status.push("A"); //Added
+						}
+						while ( chunks['old'].code.length > chunks['new'].code.length ) {
+							chunks['new'].code.push(null);
+							line_status.push("D"); //Deleted
+						}
+					} else {
+						//steady parts
+						var splittedCode = processSteadyParts(modifiedPartsOld[i], modifiedPartsNew[i]);
+						chunks['old'].code = chunks['old'].code.concat(splittedCode[0]);
+						chunks['new'].code = chunks['new'].code.concat(splittedCode[1]);
+						line_status = line_status.concat(splittedCode[2]);
+					}
+				}
+
+				var oldLines = parts[2].trim("\n").split("\n");
+				var newLines = parts[4].trim("\n").split("\n");
+				var oldLastLine = oldLines[oldLines.length-1];
+				var newLastLine = newLines[newLines.length-1];;
+
+				chunks['old'].doesnt_have_new_line = /^\\ No newline at end of file$/.test(oldLastLine);
+				chunks['new'].doesnt_have_new_line = /^\\ No newline at end of file$/.test(newLastLine);
+
+				chunks['old'].status = chunks['new'].status = line_status;
+
+				return chunks;
+			}
+
+			var res_file = {'old':{}, 'new':{}};
+
+			res_file.title = title;
+
+			var parts = code.split(/^\*{4,}$/m);
+			//parts[0] is some text before code
+
+			//get filename from it
+			var filename = "";
+			var regExpRes = parts[0].match(/---\s+(.*?)(?:\s|\n)+/);
+			if (regExpRes) {
+				res_file['new'].name = res_file['old'].name = regExpRes[1];
+			}
+
+			res_file.additional_file_info = parts[0];
+			res_file['old'].chunks = [];
+			res_file['new'].chunks = [];
+
+			for ( var i = 1; i < parts.length; i++ ) {
+				var chunks = parseChunk(parts[i]);
+
+				res_file['old'].chunks.push(chunks['old']);
+				res_file['new'].chunks.push(chunks['new']);
+			}
+
+			return res_file;
+		}
+
+
+		//main function body
+		var res = {}
+
+		var diffs = text.split(/(?:\n\n((?:.*\n){1,3}[-=]+\n))|(?:\n\n(diff.*)\n)/);
+		//Ok, diffs[0] is log, put it away.
+		//diffs[odd] are titles
+		//diffs[even] are diffs themselves
+		res.log = diffs[0];
+		res.files = [];
+
+		for ( var i = 1; i < diffs.length; i += 3 ) {
+			res.files.push(parseFile(diffs[i]+diffs[i+1], diffs[i+2]));
+		}
+
+		return res;
+	},
+	couldParse: function(text) {
+		var line_tag = /^(?:\*|\-){3}\s+(\d+)\,\d+\s+(?:\*|\-){4}$/m;
+		return line_tag.test(text);
+	}
+};
+
diff --git a/chrome/colorediffs.jar!/content/colorediffs/parsers/main-parser.js b/chrome/colorediffs.jar!/content/colorediffs/parsers/main-parser.js
new file mode 100644
index 0000000..65c09c0
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/parsers/main-parser.js
@@ -0,0 +1,8 @@
+colorediffsGlobal.parse = function(code, pref) {
+	for each (var parser in colorediffsGlobal.parsers) {
+		if (parser.couldParse(code)) {
+			return parser.parse(code, pref);
+		}
+	}
+	return null;
+}
diff --git a/chrome/colorediffs.jar!/content/colorediffs/parsers/unified-parser.js b/chrome/colorediffs.jar!/content/colorediffs/parsers/unified-parser.js
new file mode 100644
index 0000000..6257125
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/parsers/unified-parser.js
@@ -0,0 +1,551 @@
+//diff grammar
+// normal_line = \d+\n
+// postfix = normal_line | normal_line postfix
+// new_file = additional_file_info blank_line new_code
+// new_code = normal_line | normal_line new_code
+
+colorediffsGlobal.parsers["unified"] = {
+ parse: function(text, pref) {
+
+		var lines = text.split("\n");
+		var curr_line = 0;
+
+		function _try(f) {
+			var saved_line = curr_line;
+
+			var res = false;
+			try {
+				res = f();
+			} catch (e) {
+			}
+
+			if ( res ) {
+				return true;
+			} else {
+				curr_line = saved_line;
+				return false;
+			}
+		}
+
+		function _should(f) {
+			if (!f) {
+				throw "ASSERT FAILED";
+			}
+		}
+
+		function _try_many() {
+			for (var i = 0; i < arguments.length; i++) {
+				if (_try(arguments[i])) {
+					return true;
+				}
+			}
+			return false;
+		}
+
+		function _next() {
+			curr_line++;
+			if (curr_line >= lines.length) {
+				throw "EOF";
+			}
+		}
+
+		function _get() {
+			return lines[curr_line];
+		}
+
+		function _accept(r) {
+			var res = r.test(lines[curr_line]);
+			if (res) _next();
+			return res;
+
+		}
+
+		function _test(r) {
+			return r.test(lines[curr_line]);
+		}
+
+		// blank_line = \n
+		function blank_line() {
+			return /^$/;
+		}
+
+		function custom_log_terminator() {
+		    return /^# Begin patch$/; //for bazaar merger
+		}
+
+		// diff = log blank_line code postfix
+		function diff() {
+			var result = {postfix:""};
+
+			log_and_code(result);
+			code_and_postfix(result);
+
+			return result;
+		}
+
+		function code_and_postfix(result) {
+			function _(func) { return function() { return func(result); }; };
+
+			try {
+				while(true) {
+					_try(_(code(result)));
+					if (_try(_(postfix))) {
+						break;
+					} else {
+					        result.postfix += _get() + "\n";
+						_next();
+					}
+				}
+			} catch (e) {
+			}
+
+			return true;
+		}
+
+		function postfix(result) {
+			var postfix = "";
+			var max_postfix_size = pref.parserMaxPostfixSize.get();
+
+			var i = 0;
+
+			while(_get() || _test(blank_line())) {
+				postfix += _get() + "\n";
+				i++;
+				if ( i > max_postfix_size ) {
+					return false;
+				}
+				try {
+					_next();
+				} catch (e) {
+					break;
+				}
+			}
+
+			result.postfix += postfix;
+			return true;
+		}
+
+		// log = normal_line | normal_line log
+		function log_and_code(result) {
+			var log1 = "";
+		    all:
+			do {
+				while(!_test(blank_line()) && !_test(custom_log_terminator())) {
+					log1 += _get() + "\n";
+				    try {
+					_next();
+				    } catch (e) {
+					break all;
+				    }
+				}
+				log1 += _get() + "\n";
+				_next();
+			} while( !_try(function() {return code(result);}) );
+
+			result.log = log1.trim("\n");
+		}
+
+		// code = file blank_line | file blank_line code
+		function code(result) {
+			if ( !result.files ) {
+				result.files = [];
+			}
+
+			try {
+				do {
+					//skip blank lines
+					while( _test(blank_line()) ) { _next(); }
+				} while( _try(function() {return file(result);}) );
+			} catch (e) {
+			}
+
+			return result.files.length != 0;
+		}
+
+		// file = title file_info chunks | file_info chunks | "--- NEW FILE:" \s file_name " ---" new_file
+		function file(result) {
+			var file = {'old':{}, 'new':{}};
+
+			function _(func) { return function() { return func(file, result); } };
+
+			if (_try_many(
+					_(patch_binary_file),
+					_(normal_file),
+					_(cvs_new_file),
+					_(cvs_deleted_file),
+					_(cvs_binary_file),
+					_(svn_binary_file)
+				)) {
+				result.files.push(file);
+				return true;
+			} else {
+				return false;
+			}
+		}
+
+		function normal_file(file) {
+			function _(func) { return function() { return func(file); }; };
+
+			_try(_(title));
+			_try(_(additional_file_info));
+			_should(file_info(file));
+			_should(chunks(file));
+			return true;
+		}
+
+		function cvs_new_file_title() {
+			return _test(/^--- NEW FILE:\s.* ---$/);
+		}
+
+		function cvs_new_file(file, result) {
+			_should(cvs_new_file_title());
+			var name = _get().match(/^--- NEW FILE:\s(.*) ---$/)[1];
+			_next();
+			_should(new_file(file, result, name));
+			return true;
+		}
+
+		function cvs_binary_file_title() {
+			return _test(/^---\s(?:new\s)?BINARY FILE:\s.*\s---$/);
+		}
+
+		function extract_binary_file_name(file, data) {
+			var r = data.match(/\b(\w[ \w-\/\.]+\.[\w]+\w)\b/);
+			if ( r && r[1] ) {
+				file['new'].name = file['old'].name = r[1];
+			} else {
+				file['new'].name = file['old'].name = "";
+			}
+		}
+
+		function cvs_binary_file(file) {
+			_should(cvs_binary_file_title());
+			extract_binary_file_name(file, _get());
+			_next();
+			_should(additional_file_info(file));
+			return true;
+		}
+
+		function patch_binary_file(file) {
+			_should(_test(/^Binary files .* and .* differ$/));
+			var r = _get().match(/^Binary files (.*) and (.*) differ$/);
+			if (r) {
+				file['old'].name = r[1];
+				file['new'].name = r[2];
+			}
+			_next();
+			return true;
+		}
+
+		function cvs_deleted_file_title() {
+			return _test(/^--- .* DELETED ---$/);
+		}
+
+		function cvs_deleted_file(file) {
+			_should(cvs_deleted_file_title());
+			file['old'].name = _get().match(/^--- (.*) DELETED ---$/)[1];
+			_next();
+			return true;
+		}
+
+		function svn_binary_file(file) {
+			_should(title(file));
+			_should(additional_file_info(file));
+
+			extract_file_name_from_raw_data(file, file.title);
+
+			return true;
+		}
+
+		function extract_file_name_from_raw_data(file, data) {
+			var r = data.match(/\b(\w[\w-\/\.]+\.[\w]+\w)\b/);
+			if ( r && r[1] ) {
+				file['new'].name = file['old'].name = r[1];
+			} else {
+				file['new'].name = file['old'].name = "";
+			}
+		}
+
+		// title = normal_line "==========================" | normal_line "---------------------------" | normal_line title
+		function title(file) {
+			var max_title_size = pref.parserMaxTitleSize.get();
+			var min_title_delimiter_chars_count = pref.parserMinTitleDelimiterCharsCount.get();
+			var delimiterRegexp = new RegExp("^[-=]{" + min_title_delimiter_chars_count + ",}$");
+			var title = "";
+			var num = 0;
+			do {
+				title += _get() + "\n";
+				_next();
+				num++;
+
+				if ( num >= max_title_size || _test(blank_line()) ) {
+					return false;
+				}
+			} while (!_test(delimiterRegexp));
+
+			_next();
+			file.title = title.trim("\n");
+			return true;
+		}
+
+		// file_info = additional_file_info old_file_info new_file_info | old_file_info new_file_info
+		function file_info(file) {
+			if (_test(/^---/)) {
+				var oldFileInfo = getFileInfo(_get());
+				_next();
+				var newFileInfo = getFileInfo(_get());
+				_next();
+
+				file['old'].name = oldFileInfo[0];
+				file['old'].version = oldFileInfo[1];
+
+				file['new'].name = newFileInfo[0];
+				file['new'].version = newFileInfo[1];
+				return true;
+			} else {
+				return false;
+			}
+		}
+
+		// old_file_info = "---" old_file_name "\t" date "\t" version
+		// new_file_info = "+++" new_file_name "\t" date "\t" version
+		// old_file_name = file_name
+		// new_file_name = file_name
+		// file_name = [^\t]+
+		// date = [^\t]+
+		// version = [^\t]+
+		function getFileInfo(s) {
+		        var fiReg = /^[+-]{3}\s(.*?)(?:\t(.*))?$/;
+			var r = fiReg.exec(s);
+
+			if (r) {
+			    if (/(empty file)/.test(r[1])) { //Filename should match that
+				return ["", r[1] + " " + r[2]];
+			    } else {
+				return [r[1], r[2]];
+			    }
+			} else {
+			    return [s, ""];
+			}
+		}
+
+		// additional_file_info = normal_line | normal_line additional_file_info
+		function additional_file_info(file) {
+			var max_additional_info_size = pref.parserMaxAdditionalInfoSize.get();
+			var additional_file_info = "";
+			var num = 0;
+			while ( !_test(/^---/) && !_test(blank_line())) {
+				if (num >= max_additional_info_size) {
+					return false;
+				}
+
+				additional_file_info += _get() + "\n";
+				_next();
+				num++;
+			}
+
+			file.additional_info = additional_file_info;
+			return true;
+		}
+
+		// chunks = chunk | chunk chunks
+		function chunks(file) {
+			file['old'].chunks = [];
+			file['new'].chunks = [];
+			while( _try(function() {return chunk(file);}) ) {
+			}
+
+			return file['old'].chunks.length == file['new'].chunks.length && file['new'].chunks.length > 0;
+		}
+
+		// chunk = anchor diff_code
+		function chunk(file) {
+			var old_chunk = {code:[]};
+			var new_chunk = {code:[]};
+			anchor(old_chunk, new_chunk);
+			diff_code(old_chunk, new_chunk);
+			file['old'].chunks.push(old_chunk);
+			file['new'].chunks.push(new_chunk);
+			return true;
+		}
+
+		// anchor = @@ \-\d+(,\d+)? \+\d+(,\d+)? @@
+		function anchor(old_chunk, new_chunk) {
+			var regExpRes = _get().match(/^@@\s+\-(\d+)(?:\,\d+)?\s+\+(\d+)(?:\,\d+)?\s+@@/);
+			old_chunk.line = Number(regExpRes[1]);
+			new_chunk.line = Number(regExpRes[2]);
+			if (_test(/@@$/)) {
+				_next();
+			} else {
+				//git adds the first line of code to the anchor line for some reason
+				//TODO: do you think it is better to split the string instead of rewriting it?
+				lines[curr_line] = _get().slice(regExpRes[0].length);
+			}
+		}
+
+		function check_next_paragraph_for_code() {
+		    return !_try(function() {
+			return !_try(function() {
+			    //skip initial blanks
+			    while( _test(blank_line()) ) { _next(); }
+			    while(true) {
+				if (_test(/^\-(.*)$/)) {
+				} else if (_test(/^\+(.*)$/)) {
+				} else if (_test(/^\\ No newline at end of file$/)) {
+				} else if (_test(/^ (.*)$/)) {
+				} else if (_test(blank_line()))	{
+				    return true;
+				} else {
+				    return false;
+				}
+				try { _next(); } catch (e) {return true;}
+			    }
+			});
+		    });
+		}
+
+		// diff_code = diff_code_line | diff_code_line diff_code
+		// diff_code_line = " " .* | "+" .* | "-" .*
+		function diff_code(old_chunk, new_chunk) {
+			function makeEqualLength() {
+				while ( old_chunk.code.length < new_chunk.code.length ) {
+					line_status[old_chunk.code.length] = "A"; //Added
+					old_chunk.code.push(null);
+				}
+				while ( old_chunk.code.length > new_chunk.code.length ) {
+					line_status[new_chunk.code.length] = "D"; //Deleted
+					new_chunk.code.push(null);
+				}
+			}
+
+			var line_status = [];
+			var temp_result = {files: []};
+
+			old_chunk.doesnt_have_new_line = false;
+			new_chunk.doesnt_have_new_line = false;
+
+			var prev_line = null;
+
+			while(true) {
+				if (_test(/^---\s/)) { //might be the beginning of other file
+					//here is the trick. Inside _try_many stores the current_line position and checks a bunch of titles.
+					//	If any of the titles match it saves the new position otherwise it restore the old one.
+					//	The outer _try checks if the nested one return true which means title was matched and new position is saved
+					//	   and convert that to false so actually position would be restored.
+					//	If however _try_many returns false that means position didn't move and we can return true and save it once again.
+					//	So _try returns false means there was a match and true means there wasn't
+					//	Position would not be affected anyway.
+					if (!_try(function() {
+							return !_try_many(
+								function() { return file_info({'old':{}, 'new':{}}); },
+								cvs_new_file_title,
+								cvs_deleted_file_title,
+								cvs_binary_file_title
+							);
+						}
+						)) {
+						break;
+					}
+				} else if (_test(/^\-(.*)$/)) {
+					line_status[old_chunk.code.length] = "C"; //Changed
+					old_chunk.code.push(_get().substring(1));
+				} else if (_test(/^\+(.*)$/)) {
+					line_status[new_chunk.code.length] = "C"; //Changed
+					new_chunk.code.push(_get().substring(1));
+				} else if (_test(/^\\ No newline at end of file$/)) {
+					//check what sign previous line has if there was any
+					if ( prev_line != null ) {
+						if (/^\-/.test(prev_line)) {
+							old_chunk.doesnt_have_new_line = true;
+						} else if (/^\+/.test(prev_line)) {
+							new_chunk.doesnt_have_new_line = true;
+						} else if (/^ /.test(prev_line)) {
+							old_chunk.doesnt_have_new_line = true;
+							new_chunk.doesnt_have_new_line = true;
+						}
+					}
+				} else if (_test(/^ (.*)$/)) {
+					makeEqualLength();
+					old_chunk.code.push(_get().substring(1));
+					new_chunk.code.push(_get().substring(1));
+					line_status.push("S"); //the Same
+				} else if (_test(blank_line())) {
+				    if (check_next_paragraph_for_code()) {
+					makeEqualLength();
+					old_chunk.code.push("");
+					new_chunk.code.push("");
+					line_status.push("S"); //the Same
+				    } else {
+					break;
+				    }
+				} else {
+					break;
+				}
+				prev_line = _get();
+				try { _next(); } catch (e) {break;}
+			}
+			makeEqualLength();
+
+			new_chunk.status = old_chunk.status = line_status;
+		}
+
+		function new_file(f, result, name) {
+			var code = [];
+			var status = [];
+			var temp_result = {files: []};
+
+			try {
+				while(true) {
+					while(!_test(/^--- .* ---$/) && !_test(/^Index: /)) {
+						code.push(_get());
+						status.push("A");
+						_next();
+					}
+
+					if (_try(function() { return file(temp_result); })) {
+						break;
+					}
+				}
+			} catch (e) {
+			}
+
+			code.pop();
+			status.pop();
+
+			var new_file = {
+				'new': {
+					name: name,
+					chunks: [{
+						line:1,
+						code: code,
+						status: status
+					}]
+				},
+				'old': {}
+			};
+
+			result.files.push(new_file);
+			result.files = result.files.concat(temp_result.files);
+
+			var file_to_copy = result.files[result.files.length - 1];
+			result.files.pop();
+
+			//copy next file to first argument
+			for (var a in file_to_copy) {
+				f[a] = file_to_copy[a];
+			}
+
+			return true;
+
+		}
+
+		return diff();
+
+	},
+	couldParse: function(text) {
+		var line_tag = /^@@\s+\-\d+(?:\,\d+)?\s\+\d+(?:\,\d+)?\s+@@/m;
+		var new_tag = /^--- NEW FILE:\s.* ---$/m;
+		var binary_tag = /^---\s(?:new\s)?BINARY FILE:\s.*\s---$/m;
+		return line_tag.test(text) || new_tag.test(text) || binary_tag.test(text);
+	}
+}
diff --git a/chrome/colorediffs.jar!/content/colorediffs/prefs.js b/chrome/colorediffs.jar!/content/colorediffs/prefs.js
new file mode 100644
index 0000000..0103673
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/prefs.js
@@ -0,0 +1,100 @@
+if (!colorediffsGlobal) {
+    var colorediffsGlobal = {};
+}
+
+colorediffsGlobal.Pref = function (prefModel) {
+	var me = this;
+	var pref = prefModel;
+
+	var createGetSet = function(name, prop_name, getter, setter) {
+		me[name] = {
+			get: function() { return getter(prop_name); },
+			set: function(value) { setter(prop_name, value); },
+			has: function () {return pref.prefHasUserValue(prop_name);}
+		};
+	};
+
+	var createBoolGetSet = function(name, prop_name) {
+		var getBoolPref = function(p) {
+			return pref.getBoolPref(p);
+		};
+
+		var setBoolPref = function(p, v) {
+			return pref.setBoolPref(p, v);
+		};
+
+		createGetSet(name, prop_name, getBoolPref, setBoolPref);
+	};
+
+	var createIntGetSet = function(name, prop_name) {
+		var getIntPref = function(p) {
+			return pref.getIntPref(p);
+		};
+
+		var setIntPref = function(p, v) {
+			return pref.setIntPref(p, v);
+		};
+
+		createGetSet(name, prop_name, getIntPref, setIntPref);
+	};
+
+	var getCharPref = function(p) {
+		return pref.getCharPref(p);
+	};
+
+	var setCharPref = function(p, v) {
+		pref.setCharPref(p, v);
+	};
+
+	var createCharGetSet = function(name, prop_name) {
+		createGetSet(name, prop_name, getCharPref, setCharPref);
+	};
+
+	var getProperty = function(prop, color) {
+		var v = getCharPref(color);
+		if (v) {
+			return prop + ": " + v + ";";
+		} else {
+			return "";
+		}
+	};
+
+	me.getColorProps = function(baseName) {
+		return getProperty("color", baseName + "_fg") + getProperty("background-color", baseName + "_bg");
+	};
+
+	me.getColorBG = function(baseName) {
+		return getCharPref(baseName + "_bg");
+	};
+
+	me.getColorFG = function(baseName) {
+		return getCharPref(baseName + "_fg");
+	};
+
+	me.setColorBG = function(baseName, value) {
+		setCharPref(baseName + "_bg", value);
+	};
+
+	me.setColorFG = function(baseName, value) {
+		setCharPref(baseName + "_fg", value);
+	};
+
+
+	createCharGetSet("mode", "diffColorer.view-mode");
+	createCharGetSet("debugDir", "diffColorer.debug-dir");
+	createBoolGetSet("showWhiteSpace", "diffColorer.show-whitespace");
+	createBoolGetSet("showToolbar", "diffColorer.show-toolbar");
+	createBoolGetSet("instantApply", "browser.preferences.instantApply");
+
+	createIntGetSet("parserMaxTitleSize", "diffColorer.parser.max-title-size");
+	createIntGetSet("parserMinTitleDelimiterCharsCount", "diffColorer.parser.min-title-delimiter-chars-count");
+	createIntGetSet("parserMaxAdditionalInfoSize", "diffColorer.parser.max-additional-info-size");
+	createIntGetSet("parserMaxPostfixSize", "diffColorer.parser.max-postfix-size");
+
+	createCharGetSet("diffMode", "diffColorer.diff-mode");
+	createBoolGetSet("showLineNumbers", "diffColorer.show-line-numbers");
+
+	createBoolGetSet("preferHtml", "mailnews.display.prefer_plaintext");
+
+	createIntGetSet("tabSize", "diffColorer.tab-size");
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/toolbar.js b/chrome/colorediffs.jar!/content/colorediffs/toolbar.js
new file mode 100644
index 0000000..279dfe7
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/toolbar.js
@@ -0,0 +1,111 @@
+if (!colorediffsGlobal) {
+	var colorediffsGlobal = {};
+}
+
+colorediffsGlobal.colorediffsToolbar = new function() {
+	var me = colorediffsGlobal;
+	var pref = new me.Pref(me.getPrefs());
+
+	var getNode = function (name) {
+		return function() {return me.$(name);};
+	};
+
+	var getViewModeNode = getNode('colorediffs-view-mode');
+	var getDiffModeNode = getNode('colorediffs-diff-mode');
+	var getTabSizeNode = getNode('colorediffs-tab-size');
+	var getShowWhiteSpacesNode = getNode('colorediffs-show-whitespaces');
+	var getShowLineNumbersNode = getNode('colorediffs-show-line-numbers');
+	var getToolbarNode = getNode('colorediffs-toolbar');
+
+	var reloadWithScrollPreserved = function() {
+		var mp = me.getMessagePane();
+		var oldScroll = mp.contentWindow.scrollY;
+		mp.addEventListener(
+			"load",
+			function() {
+				mp.contentWindow.scrollTo(0, oldScroll);
+				mp.removeEventListener("load", arguments.callee, true);
+			},
+			true);
+		ReloadMessage();
+	};
+
+	var updatePrefs = function() {
+		pref.showWhiteSpace.set(getShowWhiteSpacesNode().checked);
+		pref.showLineNumbers.set(getShowLineNumbersNode().checked);
+		pref.mode.set(getViewModeNode().selectedItem);
+		pref.diffMode.set(getDiffModeNode().selectedItem.value);
+		pref.tabSize.set(getTabSizeNode().selectedItem.value);
+		pref.showToolbar.set(!getToolbarNode().hidden);
+	};
+
+	this.selectMode = function () {
+		updatePrefs();
+		ReloadMessage();
+	};
+
+	this.toggleWhiteSpaces = function () {
+		getShowWhiteSpacesNode().checked = !getShowWhiteSpacesNode().checked;
+		updatePrefs();
+
+		reloadWithScrollPreserved();
+	};
+
+	this.toggleLineNumbers = function () {
+		getShowLineNumbersNode().checked = !getShowLineNumbersNode().checked;
+		updatePrefs();
+
+		reloadWithScrollPreserved();
+	};
+
+	this.showOptions = function() {
+		var features = "chrome,titlebar,toolbar,centerscreen";
+		window.openDialog("chrome://colorediffs/content/options/options.xul", "Preferences", features);
+	};
+
+	this.selectDiffMode = function() {
+		updatePrefs();
+		reloadWithScrollPreserved();
+	};
+
+	this.selectTabSize = function() {
+		updatePrefs();
+		reloadWithScrollPreserved();
+	};
+
+	this.closeToolbar = function() {
+		getToolbarNode().hidden=true;
+		updatePrefs();
+	};
+
+	function selectComboByValue(menulist, value) {
+	    var items = menulist.firstChild.childNodes;
+	    for( var i=0; i < items.length; i++ ) {
+		if ( items[i].getAttribute("value") == value ) {
+		    menulist.selectedItem = items[i];
+		    break;
+		}
+	    }
+	}
+
+	this.initToolbar = function () {
+		if (pref.showToolbar.get()) {
+			//check if should be shown
+			if (!me.isActive()) {
+				getToolbarNode().hidden=true;
+			} else {
+				getToolbarNode().hidden=false;
+				getShowWhiteSpacesNode().checked = pref.showWhiteSpace.get();
+
+				//update combobox
+				getViewModeNode().selectedItem = pref.mode.get();
+				getShowLineNumbersNode().checked = pref.showLineNumbers.get();
+
+				selectComboByValue(getDiffModeNode(), pref.diffMode.get());
+				selectComboByValue(getTabSizeNode(), pref.tabSize.get());
+			}
+		} else {
+			getToolbarNode().hidden=true;
+		}
+	};
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/add-title.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/add-title.js
new file mode 100644
index 0000000..24e3e93
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/add-title.js
@@ -0,0 +1,14 @@
+colorediffsGlobal.transformations.composite.members["add-title"] = {
+	init: function(registrator, pref) {
+
+		registrator.addListener("add-title", "file", addTitle, "find-common-name");
+
+		function addTitle(file) {
+			if (!file.title) {
+				file.title = file.common_name;
+			}
+
+			return file;
+		}
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/calc-chunk-size.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/calc-chunk-size.js
new file mode 100644
index 0000000..8dc7afa
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/calc-chunk-size.js
@@ -0,0 +1,19 @@
+colorediffsGlobal.transformations.composite.members["calc-chunk-size"] = {
+	init: function(registrator, pref) {
+
+		registrator.addListener("calc-chunk-size-init-chunk", "chunk", initChunk);
+		registrator.addListener("calc-chunk-size", "line", sumLine, ["calc-chunk-size-init-chunk", "select-old-new-files"]);
+
+		function initChunk(chunk) {
+			chunk.code_size = 0;
+			return chunk;
+		}
+
+		function sumLine(line, i, chunk) {
+			if (line != null) {
+				chunk.code_size++;
+			}
+			return line;
+		}
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/collect-tab-sizes.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/collect-tab-sizes.js
new file mode 100644
index 0000000..4c15607
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/collect-tab-sizes.js
@@ -0,0 +1,40 @@
+colorediffsGlobal.transformations.composite.members["collect-tab-sizes"] = {
+	init: function(registrator, pref) {
+		if (pref.mode.get() == "side-by-side" || pref.tabSize.get() != 8 || pref.showWhiteSpace.get() || pref.showLineNumbers.get()) {
+			registrator.addListener("collect-tab-sizes-init-chunk", "chunk", initChunk);
+			registrator.addListener("collect-tab-sizes", "line", collectTabSizes, "collect-tab-sizes-init-chunk");
+		}
+
+		function initChunk(chunk) {
+			chunk.tab_sizes = new Array(chunk.code.length);
+			return chunk;
+		}
+
+		function collectTabSizes(line, i, chunk) {
+			chunk.tab_sizes[i] = calcTabSizes(line);
+
+			return line;
+		}
+
+		function calcTabSizes(s) {
+			if (s) {
+				var offsetCorrector = 0;
+				var tab_sizes = [];
+				var i = -1;
+				while ((i = s.indexOf("\t", i + 1)) != -1) {
+					var l = pref.tabSize.get() - (i + offsetCorrector) % pref.tabSize.get();
+					tab_sizes.push(l);
+					offsetCorrector += l - 1;
+				}
+
+				if (tab_sizes.length == 0) {
+					return null;
+				} else {
+					return tab_sizes;
+				}
+			} else {
+				return null;
+			}
+		}
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/composite-init.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/composite-init.js
new file mode 100644
index 0000000..8477212
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/composite-init.js
@@ -0,0 +1,134 @@
+colorediffsGlobal.transformations["composite"].methods.initOthers =
+	function (pref) {
+		var callbacks = {};
+		var dependants = {};
+
+		for each (var member in colorediffsGlobal.transformations.composite.members) {
+			member.init({
+				addListener: function(name, type, callback, depends) {
+					var node = {
+						type:type,
+						callback:callback,
+						ancessorCount:0
+					};
+
+					callbacks[name] = node;
+
+					if (depends) {
+						if (depends instanceof Array) {
+							for (var i = 0; i < depends.length; i++) {
+								addDependant(depends[i], node);
+							}
+						} else {
+							addDependant(depends, node);
+						}
+					} else {
+						addDependant("root", node);
+					}
+
+					function addDependant(dependsOn, node) {
+						if (dependants[dependsOn]) {
+							dependants[dependsOn].push(node);
+						} else {
+							dependants[dependsOn] = [node];
+						}
+					}
+				}
+			}, pref);
+		}
+
+
+		var roots = buildDependenciesGraph();
+		dependants = null;
+		callbacks = null;
+
+		var nodes = buildTree(["file", "chunk-pair", "chunk", "line"]);
+		roots = null;
+
+		function buildDependenciesGraph() {
+			callbacks["root"] = {};
+
+			for (var name in dependants) {
+				if (callbacks[name]) {
+					callbacks[name].children = dependants[name];
+					if (name != "root") {
+						dependants[name].forEach(function(node) {
+								node.ancessorCount++;
+							});
+					}
+				} else {//The callback we depends on isn't enabled, should go to the root
+					for (var i = 0; i < dependants[name].length; i++) {
+						var dependant = dependants[name][i];
+						if (dependant.ancessorCount == 0) { // push only if we aren't depends on something enabled
+							dependant.ancessorCount = 1;
+							callbacks["root"].children.push(dependant);
+						}
+					}
+				}
+			}
+
+			return callbacks["root"].children;
+		}
+
+		function buildTree(types) {
+			var nodes = [];
+
+			while(true) {
+				var node = {
+					callbacks:[]
+				};
+
+				var i = 0;
+				while( i < roots.length ) {
+					if ( roots[i].type == types[0] ) {
+						node.callbacks.push(roots[i].callback);
+
+						var iWasReplaced = false;
+						var children = roots[i].children;
+						if (children) {
+							for (var j = 0; j < children.length; j++) {
+								if ( --children[j].ancessorCount == 0 ) {
+									if ( !iWasReplaced ) {
+										roots[i] = children[j];
+										iWasReplaced = true;
+									} else {
+										roots.push(children[j]);
+									}
+								}
+							}
+						}
+						if ( !iWasReplaced ) {
+							roots.splice(i, 1);
+						}
+					} else {
+						i++;
+					}
+				}
+
+				if (types.length > 1) {//recursion stop condition
+					node.next = buildTree(types.slice(1));
+				} else {
+					node.next = null;
+				}
+
+				if (node.callbacks.length == 0 && node.next == null) {//if nothing got changed
+					break;
+				} else {
+					nodes.push(node);
+				}
+
+				if (types.length == 1) { //There are no chance we could find something with our type now
+					break;
+				}
+			}
+
+			if (nodes.length == 0) {
+				return null;
+			} else {
+				return nodes;
+			}
+		}
+
+		return nodes;
+	}
+
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/composite-run.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/composite-run.js
new file mode 100644
index 0000000..43e00ed
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/composite-run.js
@@ -0,0 +1,89 @@
+colorediffsGlobal.transformations["composite"].methods.proceedIL =
+	function (il, nodes) {
+		il.files.forEach(function(file) {proceedFile(file, nodes);});
+
+		function proceedFile(file, nodes) {
+			for (var i = 0; i < nodes.length; i++) {
+				nodes[i].callbacks.forEach(
+					function(callback) {
+						callback(file, il);
+					}
+				);
+
+				if (nodes[i].next) {
+					var l = 0;
+
+					if ( file['old'] && file['old'].chunks ) {
+						l = file['old'].chunks.length;
+					} else if ( file['new'] && file['new'].chunks ) {
+						l = file['new'].chunks.length;
+					}
+
+					for (var j = 0; j < l; j++) {
+						var old_chunk = null;
+						var new_chunk = null;
+
+						if ( file['old'] && file['old'].chunks ) {
+							old_chunk = file['old'].chunks[j];
+						}
+
+						if ( file['new'] && file['new'].chunks ) {
+							new_chunk = file['new'].chunks[j];
+						}
+
+						proceedChunkPair(file, old_chunk, new_chunk, nodes[i].next);
+					}
+				}
+			}
+		}
+
+		function proceedChunkPair(file, old_chunk, new_chunk, nodes) {
+			for (var i = 0; i < nodes.length; i++) {
+				nodes[i].callbacks.forEach(
+					function(callback) {
+						callback(old_chunk, new_chunk, file);
+					}
+				);
+
+				if (nodes[i].next) {
+					if (old_chunk) {
+						proceedChunk(file, old_chunk, nodes[i].next);
+					}
+
+					if (new_chunk) {
+						proceedChunk(file, new_chunk, nodes[i].next);
+					}
+				}
+			}
+		}
+
+		function proceedChunk(file, chunk, nodes) {
+			for (var i = 0; i < nodes.length; i++) {
+				nodes[i].callbacks.forEach(
+					function(callback) {
+						callback(chunk, file);
+					}
+				);
+
+				if (nodes[i].next) {
+					chunk.code = chunk.code.map(
+						function(line, j) {
+							return proceedLine(file, chunk, line, j, nodes[i].next);
+						}
+					);
+				}
+			}
+		}
+
+		function proceedLine(file, chunk, line, index, nodes) {
+			for (var i = 0; i < nodes.length; i++) {
+				nodes[i].callbacks.forEach(
+					function(callback) {
+						line = callback(line, index, chunk, file);
+					}
+				);
+			}
+			return line;
+		}
+	}
+
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/composite-transformation.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/composite-transformation.js
new file mode 100644
index 0000000..0ee1fe9
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/composite-transformation.js
@@ -0,0 +1,15 @@
+colorediffsGlobal.transformations["composite"] = {
+	run: function (il, pref) {
+
+		//add transformations
+		var nodes = colorediffsGlobal.transformations.composite.methods.initOthers(pref);
+
+		//proceed
+		colorediffsGlobal.transformations.composite.methods.proceedIL(il, nodes);
+
+		return il;
+	}
+};
+
+colorediffsGlobal.transformations.composite.members = {};
+colorediffsGlobal.transformations.composite.methods = {};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/detect-old-new-files.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/detect-old-new-files.js
new file mode 100644
index 0000000..a50a418
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/detect-old-new-files.js
@@ -0,0 +1,23 @@
+colorediffsGlobal.transformations.composite.members["detect-old-new-files"] = {
+	init: function(registrator, pref) {
+
+		registrator.addListener("detect-old-new-files", "file", detectOldNewFiles);
+
+		function detectOldNewFiles(file) {
+			if (file['new'] && file['new'].chunks && file['old'] && file['old'].chunks) {
+				deleteSide('new');
+				deleteSide('old');
+			}
+
+			function deleteSide(side_to_delete) {
+				if ( !file[side_to_delete].chunks[0] || file[side_to_delete].chunks[0].line == 0 ) {
+					file[side_to_delete].chunks = null;
+				}
+			}
+
+
+			return file;
+		}
+
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/find-common-name.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/find-common-name.js
new file mode 100644
index 0000000..02fdcc9
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/find-common-name.js
@@ -0,0 +1,253 @@
+colorediffsGlobal.transformations.composite.members["find-common-name"] = {
+	init: function(registrator, pref) {
+
+		registrator.addListener("find-common-name", "file", findCommonName);
+
+		function findCommonName(file, il) {
+			if ( file['new'].name || file['old'].name ) {
+				//get common part of the names
+				var commonPart = returnCommonPart(file['new'].name || "", file['old'].name || "");
+
+				//try all the combinations of it on the log until found something
+				//common_name = found_part
+				file.common_name = checkCombinations(il.log, commonPart) || commonPart;
+
+				file.id = file.common_name;
+			}
+
+			return file;
+		}
+
+		function returnCommonPart(s1, s2) {
+			if (s1 && !s2) {
+				return s1;
+			} else if (s2 && !s1) {
+				return s2;
+			}
+			var d = findDiff(s1, s2);
+			var max = "";
+			for (var o = d; o; o = o.next[0]) {
+				if (o.prev.length == 0 || o.prev.length == 2) {//funny way to find out if this is a common part
+					if (o.text.length > max.length) {
+						max = o.text;
+					}
+				}
+			}
+			return max.trim();
+		}
+
+		function skipNextComponent(s) {
+			var i1 = s.indexOf("/");
+			var i2 = s.indexOf("\\");
+
+			var i = Math.max(i1, i2) + 1;
+
+			if ( i > 0 ) {
+				return s.substring(i);
+			} else {
+				return "";
+			}
+		}
+
+		function checkPathCombinations(log, name) {
+			do {
+				if ( log.indexOf(name) >= 0 ) {
+					return name;
+				}
+
+				name = skipNextComponent(name);
+			} while( name != "" );
+			return null;
+		}
+
+		function chopToLastSpace(s) {
+			if (s.indexOf(" ") == -1) {
+			return "";
+			} else {
+			return s.replace(/ +.*?$/, "");
+			}
+		}
+
+		function checkCombinations(log, name) {
+			do {
+			var tempN = checkPathCombinations(log, name);
+			if ( tempN != null ) {
+				return tempN;
+			}
+
+			name = chopToLastSpace(name);
+			} while( name != "" );
+			return null;
+		}
+
+		function findDiff(a, b) {
+			//replace element in array
+			function replace(arr, el, new_el) {
+				if (el == new_el) return;
+				for (var i=0; arr[i]; i++) {
+					if (arr[i] == el) {
+						arr[i] = new_el;
+						break;
+					}
+				}
+			}
+
+			function zip(arr) {
+				var res = [];
+				var prev = null;
+				for (var i=0; arr[i]; i++) {
+					if (arr[i] != prev) {
+						res.push(arr[i]);
+					}
+					prev = arr[i];
+				}
+				return res;
+			}
+
+			function join(old_o, new_o) {
+				var common = {
+					text: old_o.text,
+					prev: zip(old_o.prev, new_o.prev),
+					next: zip(old_o.next, new_o.next)
+				};
+
+				for (let i = 0; i < common.prev.length; i++) {
+					replace(common.prev[i].next, old_o, common);
+					replace(common.prev[i].next, new_o, common);
+				}
+
+				for (let i = 0; i < common.next.length; i++) {
+					replace(common.prev[i].prev, old_o, common);
+					replace(common.prev[i].prev, new_o, common);
+				}
+			}
+
+			function break_to_tokens(s) {
+				var ts = s.split(/([^A-Za-z0-9])/);
+				var res = {text:"", next:[], prev: []};
+				var next = res;
+				for (var i = 0; typeof(ts[i]) != "undefined"; i++) {
+					var new_o = {text:ts[i], next:[], prev: []};
+					next.next.push(new_o);
+					new_o.prev.push(next);
+					next = new_o;
+				}
+				res.next[0].prev = [];
+				return {first: res.next[0], last: next};
+			}
+
+			//vtokens are used as keys in hash to look for anchors
+			// should also have a link to what tokens it's from
+			// should contain one or more tokens
+//			function break_to_vtokens(s) {
+//			var res = [];
+//			for (var i = 0; s[i]; i++) {
+//				res.push(s.substr(i, 3));
+//			}
+//			return res;
+//			}
+			function break_to_vtokens(tokens) {
+				var res = [];
+				for (var o = tokens.first; o; o = o.next[0]) {
+					res.push({anchor:o.text, tokens:[o]});
+				}
+				return res;
+			}
+
+			var hash = {};
+
+			var new_tokens = break_to_tokens(b);
+			var new_vtokens = break_to_vtokens(new_tokens);
+			for (var i = 0; new_vtokens[i]; i++) {
+				var temp = hash[new_vtokens[i].anchor];
+				if (!temp) {
+					//we are interested in new/old tokens only if nc==oc==1
+					hash[new_vtokens[i].anchor] = temp = {nc: 0, oc: 0, new_tokens: new_vtokens[i].tokens, old_tokens:[]};
+				}
+				temp.nc++;
+			}
+
+			var old_tokens = break_to_tokens(a);
+			var old_vtokens = break_to_vtokens(old_tokens);
+			for (i = 0; old_vtokens[i]; i++) {
+				var temp = hash[old_vtokens[i].anchor];
+				if (!temp) {
+					hash[old_vtokens[i].anchor] = temp = {nc: 0, oc: 0, new_tokens: [], old_tokens:[]};
+				}
+				temp.oc++;
+				temp.old_tokens = old_vtokens[i].tokens; //we are interested in new/old tokens only if nc==oc==1
+			}
+
+			var common_first = {text:"", prev:[], next:[old_tokens.first, new_tokens.first]};
+			var common_last = {text:"", next:[], prev:[old_tokens.last, new_tokens.last]};
+			old_tokens.first.prev.push(common_first); new_tokens.first.prev.push(common_first);
+			old_tokens.last.next.push(common_last); new_tokens.last.next.push(common_last);
+			var res = {first:common_first, last:common_last};
+
+			for (el in hash) {
+				var e = hash[el];
+				if (e.nc == 1 && e.oc == 1) {
+					for (i = 0; e.old_tokens[i] && e.new_tokens[i]; i++) {
+						join(e.old_tokens[i], e.new_tokens[i]);
+					}
+				}
+			}
+
+			for (var o = res.first; o; o = o.next[0]) {
+				if (o.next.length == 2) {
+					//we're on common element, see if we can join next one
+					if (o.next[0].text == o.next[1].text) {
+						join(o.next[0], o.next[1]);
+					}
+				}
+			}
+
+			for (o = res.last; o; o = o.prev[0]) {
+				if (o.prev.length == 2) {
+					//we're on common element, see if we can join previous one
+					if (o.prev[0].text == o.prev[1].text) {
+						join(o.prev[0], o.prev[1]);
+					}
+				}
+			}
+
+			//simplify result by joining tokens from the same group (common, old) together
+			for (o = res.first; o;) {
+				//if a <-> b exclusively
+				if (o.next.length == 1 && o.next[0].prev.length == 1) {
+					var onext = o.next[0];
+					//join a and b
+					o.text = o.text + onext.text;
+					o.next = onext.next;
+					for (i = 0; o.next[i]; i++) {
+						replace(o.next[i].prev, onext, o);
+					}
+				} else {
+					o = o.next[0];
+				}
+			}
+
+			//simplify result by joining tokens from the same group (common, new) together
+			for (o = res.first; o;) {
+				//if a <-> b exclusively
+				if (o.next.length == 1 && o.next[0].prev.length == 1) {
+					var onext = o.next[0];
+						//join a and b
+					o.text = o.text + onext.text;
+					o.next = onext.next;
+					for (i = 0; o.next[i]; i++) {
+						replace(o.next[i].prev, onext, o);
+					}
+				} else {
+					o = o.next[o.next.length-1];
+				}
+			}
+
+			return res.first;
+		}
+
+
+		//test
+		//findDiff("This is a diff line", "This is a new line");
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/main-transformation.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/main-transformation.js
new file mode 100644
index 0000000..27b0735
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/main-transformation.js
@@ -0,0 +1,6 @@
+colorediffsGlobal.transform = function(il, pref) {
+	for each (var tr in colorediffsGlobal.transformations) {
+		il = tr.run(il, pref);
+	}
+	return il;
+}
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/make-lines-equal-length.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/make-lines-equal-length.js
new file mode 100644
index 0000000..fd79647
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/make-lines-equal-length.js
@@ -0,0 +1,73 @@
+colorediffsGlobal.transformations.composite.members["make-lines-equal-length"] = {
+	init: function(registrator, pref) {
+		if (pref.mode.get() == "side-by-side") {
+			registrator.addListener("make-lines-equal-length-init-chunk", "chunk", initChunk);
+			registrator.addListener("make-lines-equal-length-calc-pad-length", "line", calcPadLength, ["collect-tab-sizes", "make-lines-equal-length-init-chunk"]);
+			registrator.addListener("make-lines-equal-length-sync-pad-length", "chunk-pair", syncPadLength, "make-lines-equal-length-calc-pad-length");
+			registrator.addListener("make-lines-equal-length", "line", padLines, "make-lines-equal-length-sync-pad-length");
+			registrator.addListener("make-lines-equal-length-close-chunk", "chunk", closeChunk, "make-lines-equal-length");
+		}
+
+		function syncPadLength(old_chunk, new_chunk) {
+			var maxLength = 0;
+
+			if (old_chunk) {
+				maxLength = Math.max(old_chunk.maxLineLength, maxLength);
+			}
+
+			if (new_chunk) {
+				maxLength = Math.max(new_chunk.maxLineLength, maxLength);
+			}
+			if (old_chunk) {
+				old_chunk.maxLineLength = maxLength;
+			}
+
+			if (new_chunk) {
+				new_chunk.maxLineLength = maxLength;
+			}
+		}
+
+		function calcPadLength(line, i, chunk) {
+			chunk.maxLineLength = Math.max(countLength(line, chunk.tab_sizes[i]), chunk.maxLineLength);
+			return line;
+		}
+
+		function initChunk(chunk) {
+			chunk.padding = new Array(chunk.code.length + 1);
+			chunk.maxLineLength = 0;
+			return chunk;
+		}
+
+		function padLines(line, i, chunk) {
+			var lineLength = countLength(line, chunk.tab_sizes[i]);
+
+			var p = colorediffsGlobal.pad("", chunk.maxLineLength - lineLength);
+
+			if (lineLength + p.length == 0) p = " ";
+			chunk.padding[i] = p;
+			return line;
+		}
+
+		function closeChunk(chunk) {
+			chunk.padding[chunk.padding.length - 1] = (colorediffsGlobal.pad("", chunk.maxLineLength)); //used if \No new line at end of file in old and new parts differs
+			delete chunk.maxLineLength;
+			return chunk;
+		}
+
+		function countLength(s, tab_sizes) {
+			if (s) {
+				var l = s.length;
+
+				if (tab_sizes) {
+					for (var i = 0; i < tab_sizes.length; i++) {
+						l += tab_sizes[i] - 1;
+					}
+				}
+
+				return l;
+			} else {
+				return 0;
+			}
+		}
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/replace-file-names-transformation.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/replace-file-names-transformation.js
new file mode 100644
index 0000000..8e27cfa
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/replace-file-names-transformation.js
@@ -0,0 +1,20 @@
+colorediffsGlobal.transformations.composite.members["replace-file-names"] = {
+	init: function(registrator, pref) {
+
+		registrator.addListener("replace-file-names", "file", replaceFilesInLog, "find-common-name");
+
+		function replaceFilesInLog(file, il) {
+			replace(file.common_name, file.id, il);
+
+			return file;
+		}
+
+
+		function replace(name, id, il) {
+		    if (name) {
+			il.log = il.log.replace(new RegExp("([\\/\\.a-zA-Z0-9-]*\\b" + name.replace(".", "\\.", "g") + "\\b)"), "<a href='#" + id + "'>$1</a>");
+		    }
+		}
+	}
+};
+
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/replace-tabs.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/replace-tabs.js
new file mode 100644
index 0000000..3da095b
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/replace-tabs.js
@@ -0,0 +1,23 @@
+colorediffsGlobal.transformations.composite.members["replace-tabs"] = {
+	init: function(registrator, pref) {
+		if ( (pref.showLineNumbers.get() || pref.tabSize.get() != 8) && !pref.showWhiteSpace.get()) {
+			registrator.addListener("replace-tabs", "line", replaceTabs, ["show-line-numbers", "show-whitespaces", "calc-tab-sizes"]);
+		}
+
+		function replaceTabs(line, index, chunk) {
+			var tab_sizes = chunk.tab_sizes[index];
+			if ( line ) {
+				var i = 0;
+				line = line.replace(
+					"\t",
+					function() {
+						return colorediffsGlobal.pad("", tab_sizes[i++]);
+					},
+					"g"
+				);
+
+			}
+			return line;
+		}
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/select-old-new-files.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/select-old-new-files.js
new file mode 100644
index 0000000..6b88aa9
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/select-old-new-files.js
@@ -0,0 +1,27 @@
+colorediffsGlobal.transformations.composite.members["select-old-new-files"] = {
+	init: function(registrator, pref) {
+
+		function register(func) {
+			registrator.addListener("select-old-new-files", "file", func, "find-common-name");
+		}
+
+
+		switch( pref.diffMode.get() ) {
+			case "new":
+				register(function(file) {return selectSide('old', file);});
+				break;
+			case "old":
+				register(function(file) {return selectSide('new', file);});
+				break;
+		}
+
+		function selectSide(side, file) {
+
+			if (file[side] && file[side].chunks) {
+				file[side].chunks = null;
+			}
+
+			return file;
+		}
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/show-line-numbers.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/show-line-numbers.js
new file mode 100644
index 0000000..da910f1
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/show-line-numbers.js
@@ -0,0 +1,87 @@
+colorediffsGlobal.transformations.composite.members["show-line-numbers"] = {
+	init: function(registrator, pref) {
+		if ( pref.showLineNumbers.get() ) {
+			registrator.addListener("show-line-numbers-calc-max-line-number", "chunk-pair", calcMaxLineNumber, "calc-chunk-size");
+			registrator.addListener("show-line-numbers-calc-init-chunk", "chunk", initChunk, "show-line-numbers-calc-max-line-number");
+			registrator.addListener("show-line-numbers", "line", addLineNumber, ["show-line-numbers-calc-init-chunk"]);
+			registrator.addListener("show-line-numbers-close-chunk", "chunk", closeChunk, "show-line-numbers");
+		}
+
+		function calcMaxLineNumber(old_chunk, new_chunk) {
+			var maxLineNumber = 0;
+
+			if ( old_chunk ) {
+				maxLineNumber = old_chunk.line + old_chunk.code_size - 1;
+			}
+
+			if ( new_chunk ) {
+				maxLineNumber = Math.max(new_chunk.line + new_chunk.code_size - 1, maxLineNumber);
+			}
+
+			var charsLength = countCharsLength(maxLineNumber);
+
+			if ( old_chunk ) {
+				old_chunk.charsLength = charsLength;
+			}
+
+			if ( new_chunk ) {
+				new_chunk.charsLength = charsLength;
+			}
+		}
+
+		function closeChunk(chunk) {
+			delete chunk.charsLength;
+			delete chunk.local_pad;
+			delete chunk.lineNumber;
+		}
+
+		function initChunk(chunk) {
+			if ( countCharsLength(chunk.line) != chunk.charsLength ) {
+				chunk.local_pad = pad;
+			} else {
+				chunk.local_pad = function(n) { return "" + n; };
+			}
+
+			chunk.lineNumber = chunk.line;
+			return chunk;
+		}
+
+		function addLineNumber(line, i, chunk) {
+			if ( line != null ) {
+				line = decorate(chunk.local_pad(chunk.lineNumber, chunk.charsLength)) + line;
+
+				chunk.lineNumber++;
+			} else if (chunk.padding && chunk.padding[i]) {
+				chunk.padding[i] = decoratePadding(colorediffsGlobal.pad("", chunk.charsLength)) + chunk.padding[i];
+			}
+
+			return line;
+		}
+
+		function decorate(s) {
+			return "<span style='border-right:solid 1px;border-left:solid 1px;margin-right:2px;padding-left:1px;padding-right:1px'>" + s + "</span>";
+		}
+
+		function decoratePadding(s) {
+			return "<span style='margin-right:4px;padding-left:1px;padding-right:1px'>" + s + "</span>";
+		}
+
+		//works for numbers > 0 only
+		function countCharsLength(n) {
+			var c = 1;
+			while( (n = Math.floor(n / 10)) > 0 ) { c++; }
+			return c;
+		}
+
+		function pad(n, length) {
+			var s = "" + n;
+			var nLength = countCharsLength(n);
+			while ( nLength < length ) {
+				s = " " + s;
+				nLength++;
+			}
+
+			return s;
+		}
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/show-whitespaces-transformation.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/show-whitespaces-transformation.js
new file mode 100644
index 0000000..9403ef8
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/show-whitespaces-transformation.js
@@ -0,0 +1,23 @@
+colorediffsGlobal.transformations.composite.members["show-whitespaces"] = {
+	init: function(registrator, pref) {
+		if (pref.showWhiteSpace.get()) {
+			registrator.addListener("show-whitespaces", "line", replaceWhitespaces, ["collect-tab-sizes"]);
+		}
+
+		function replaceWhitespaces(line, index, chunk) {
+			var tab_sizes = chunk.tab_sizes[index];
+			if ( line ) {
+				line = line.replace(" ", "·", "g");
+				var i = 0;
+				line = line.replace(
+					"\t",
+					function() {
+						return "»" + colorediffsGlobal.pad("", tab_sizes[i++] - 1);
+					},
+					"g"
+				);
+			}
+			return line;
+		}
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/transformations/truncate-file-names.js b/chrome/colorediffs.jar!/content/colorediffs/transformations/truncate-file-names.js
new file mode 100644
index 0000000..f65f4f8
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/transformations/truncate-file-names.js
@@ -0,0 +1,87 @@
+colorediffsGlobal.transformations.composite.members["truncate-file-names"] = {
+	init: function(registrator, pref) {
+
+		registrator.addListener("truncate-file-names", "file", truncateFileNames, ["find-common-name", "select-old-new-files"]);
+
+		function truncateFileNames(file, il) {
+			if (file.common_name) {
+				file.commonNameTruncated = truncateFileName(file.common_name, 80);
+			}
+
+			if (file['new'] && file['new'].name) {
+				file['new'].name15Truncated = truncateFileName(file['new'].name, 80);
+				if (pref.mode.get() == "unified" && file['old'] && file['old'].name) {
+					file['new'].name7Truncated = truncateFileName(file['new'].name, 30);
+				}
+			}
+
+			if (file['old'] && file['old'].name) {
+				file['old'].name15Truncated = truncateFileName(file['old'].name, 80);
+				if (pref.mode.get() == "unified" && file['new'] && file['new'].name) {
+					file['old'].name7Truncated = truncateFileName(file['old'].name, 30);
+				}
+			}
+
+			return file;
+		}
+
+		function truncateFileName(name, length) {
+			var nameLength = name.length;
+
+			length -= 3;
+
+			if ( nameLength <= length ) {
+				return name;
+			} else {
+				var nextIndex = -1;
+				var lastIndex = nameLength;
+				do {
+					var a = skipLastComponent();
+					var b = skipNextComponent();
+				} while(a || b);
+
+				if ( nextIndex == lastIndex ) {
+					return name;
+				} else {
+					return name.substring(0, nextIndex + 1) + "..." + name.substring(lastIndex);
+				}
+			}
+
+
+			function skipNextComponent() {
+				var i1 = name.indexOf("/", nextIndex + 1);
+				var i2 = name.indexOf("\\", nextIndex + 1);
+
+				var i = Math.max(i1, i2);
+
+				if ( i > 0 && nextIndex <= lastIndex && calcLenght(i, lastIndex) <= length ) {
+					nextIndex = i;
+					return true;
+				} else {
+					return false;
+				}
+			}
+
+			function skipLastComponent() {
+				var i1 = name.lastIndexOf("/", lastIndex - 1);
+				var i2 = name.lastIndexOf("\\", lastIndex - 1);
+
+				var i = Math.max(i1, i2);
+
+				if ( i > 0 && nextIndex <= lastIndex && calcLenght(nextIndex, i) <= length ) {
+					lastIndex = i;
+					return true;
+				} else {
+					return false;
+				}
+			}
+
+			function calcLenght(nextIndex, lastIndex) {
+				return nameLength - lastIndex + nextIndex + 1;
+			}
+
+			return name;
+		}
+
+	}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/views/context-view.js b/chrome/colorediffs.jar!/content/colorediffs/views/context-view.js
new file mode 100644
index 0000000..b32c3ba
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/views/context-view.js
@@ -0,0 +1,243 @@
+
+colorediffsGlobal.views["context"] = {
+ render: function(il, pref, dom) {
+		var me = colorediffsGlobal;
+
+		return [
+			function() {
+				var colorStyle = function(style, prop) {
+					return "." + style + " {" + pref.getColorProps(prop) + "}\n";
+				}
+
+				var stylecontent = "";
+
+				stylecontent += colorStyle("linetag", "diffColorer.c_anchor");
+				stylecontent += colorStyle("addline", "diffColorer.c_addedLine");
+				stylecontent += colorStyle("delline", "diffColorer.c_deletedLine");
+				stylecontent += colorStyle("steadyline", "diffColorer.c_steadyLine");
+				stylecontent += colorStyle("title", "diffColorer.c_title");
+				stylecontent += colorStyle("precode", "diffColorer.c_precode");
+				//stylecontent += ".addline {color: red;}\n";
+				stylecontent += "pre {font-family:monospace;}\n";
+				stylecontent += ".title, .linetag, .diffs, .addline, .delline, .precode {margin:0;}\n";
+				return dom.createElement("style", null, stylecontent);
+			}(),
+			dom.createDocumentFragment(
+				dom.createElement("pre", {id:'log', 'class':'log', wrap: ""}, il.log),
+				il.files.map(function(file) {
+						return dom.createElement(
+							"div", {'class':'file-diff', title:file.commonNameTruncated, id:file.id, width:"100%"},
+							dom.createElement(
+								"pre", {'class':'title', wrap: ""},
+								file.title + "\n======================================="
+							),
+							dom.createElement(
+								"pre", {'class':'precode', wrap: ""},
+								file.additional_info
+							),
+							function () {
+								if (file['old'].chunks || file['new'].chunks) {
+									var old_name;
+									var new_name;
+									var old_version;
+									var new_version;
+
+									if ( file['old'] && file['old'].name ) {
+										old_name = file['old'].name;
+										old_version = (file['old'].version) ? "\t" + file['old'].version : "";
+									} else {
+										old_name = file['new'].name;
+										old_version = "";
+									}
+
+									if ( file['new'] && file['new'].name ) {
+										new_name = file['new'].name;
+										new_version = (file['new'].version) ? "\t" + file['new'].version : "";
+									} else {
+										new_name = file['old'].name;
+										new_version = "";
+									}
+
+
+									return [dom.createElement(
+											"pre", {'class':'delline'},
+											"*** " + old_name + old_version
+										),
+										dom.createElement(
+											"pre", {'class':'addline'},
+											"--- " + new_name + new_version
+										)];
+								} else {
+									return null;
+								}
+							}(),
+							me.ilUtils.chunksMap(file, function(old_chunk, new_chunk) {
+									if (old_chunk == null) {
+										old_chunk = gen_empty_chunk(new_chunk);
+									}
+
+									if (new_chunk == null) {
+										new_chunk = gen_empty_chunk(old_chunk);
+									}
+
+									var oldCodeDecorated = [];
+									var newCodeDecorated = [];
+
+									var oldCodeDecoratedDelayed = [];
+									var newCodeDecoratedDelayed = [];
+
+									var oldLine = old_chunk.line;
+									var newLine = new_chunk.line;
+
+									var oldCode = old_chunk.code.concat([]); //copy array
+									var newCode = new_chunk.code.concat([]); //copy array
+
+									if (old_chunk.doesnt_have_new_line != new_chunk.doesnt_have_new_line) {
+										oldCode.pop();newCode.pop();
+									}
+
+									oldCode.push("");newCode.push("");
+
+									var onlyNew = true;
+									var onlyOld = true;
+									var l = oldCode.length;
+
+									for (var i=0; i < l; ++i) {
+										if ( oldCode[i] == newCode[i] ) {
+											if (oldCodeDecoratedDelayed.length == 0 && newCodeDecoratedDelayed.length != 0) {
+												newCodeDecorated = newCodeDecorated.concat(newCodeDecoratedDelayed);
+												onlyOld = false;
+											} else if (newCodeDecoratedDelayed.length == 0 && oldCodeDecoratedDelayed.length != 0) {
+												oldCodeDecorated = oldCodeDecorated.concat(oldCodeDecoratedDelayed);
+												onlyNew = false;
+											} else if (newCodeDecoratedDelayed.length != 0 && oldCodeDecoratedDelayed.length != 0) {
+												newCodeDecorated = newCodeDecorated.concat(
+													newCodeDecoratedDelayed.map(
+														function(line) {
+															return line.replace(">+ ", ">! ");
+														}
+													));
+												oldCodeDecorated = oldCodeDecorated.concat(
+													oldCodeDecoratedDelayed.map(
+														function(line) {
+															return line.replace(">- ", ">! ");
+														}
+													));
+
+												onlyNew = false;
+												onlyOld = false;
+											}
+
+											newCodeDecoratedDelayed = [];
+											oldCodeDecoratedDelayed = [];
+
+											var line = oldCode[i];
+
+											oldCodeDecorated.push("<div class='steadyline' title='" + file['old'].name15Truncated + ":" + oldLine + "'>  " + line +" </div>");
+											newCodeDecorated.push("<div class='steadyline' title='" + file['new'].name15Truncated + ":" + newLine + "'>  " + line +" </div>");
+
+											newLine++;
+											oldLine++;
+										} else {
+											if ( newCode[i] != null ) {
+												var line = newCode[i];
+												newCodeDecoratedDelayed.push("<div class='addline' title='" + file['new'].name15Truncated + ":" + newLine + "'>+ " + line +" </div>");
+												newLine++;
+											}
+											if ( oldCode[i] != null ) {
+												var line = oldCode[i];
+												oldCodeDecoratedDelayed.push("<div class='delline' title='" + file['old'].name15Truncated + ":" + oldLine + "'>- " + line +" </div>");
+												oldLine++;
+											}
+										}
+									}
+
+									oldCodeDecorated.pop(); newCodeDecorated.pop();
+
+									if (old_chunk.doesnt_have_new_line) {
+										oldCodeDecorated.push("<div class='steadyline' title='" + file['old'].name15Truncated + "'>\\ No newline at end of file</div>");
+									}
+
+									if (new_chunk.doesnt_have_new_line) {
+										newCodeDecorated.push("<div class='steadyline' title='" + file['new'].name15Truncated + "'>\\ No newline at end of file</div>");
+									}
+
+
+									if ( onlyOld ) {
+										newCodeDecorated = [];
+									}
+
+									if ( onlyNew ) {
+										oldCodeDecorated = [];
+									}
+
+									return [
+										dom.createElement(
+											"pre", {'class':'linetag'},
+											"***************"
+										),
+										dom.createElement(
+											"pre", {'class':'linetag'},
+											"*** " +
+											old_chunk.line +
+											"," + old_chunk.code_size +
+											" ****"
+										),
+										function() {
+											if (onlyNew) {
+												return null;
+											} else {
+												return dom.createElement(
+													"pre", {'class':'diffs'},
+													oldCodeDecorated.join("")
+												);
+											}
+										},
+										dom.createElement(
+											"pre", {'class':'linetag'},
+											"--- " +
+											new_chunk.line +
+											"," + new_chunk.code_size +
+											" ----"
+										),
+										function() {
+											if (onlyOld) {
+												return null;
+											} else {
+												return dom.createElement(
+													"pre", {'class':'diffs'},
+													newCodeDecorated.join("")
+												);
+											}
+										}
+									];
+								}
+							),
+							dom.createElement(
+								"pre", {},
+								""
+							)
+						);
+					}
+				),
+				dom.createElement(
+					"pre", {wrap: ""},
+					il.postfix || ""
+				)
+			)
+		];
+
+
+		function gen_empty_chunk(oposite_chunk) {
+			var chunk = {line:0, code:[], code_size:0};
+			for (var i = 0; i < oposite_chunk.code.length; i++ ) {
+				chunk.code.push(null);
+			}
+			return chunk;
+		}
+
+		//Seriously, that bug is annoying.
+		return null;
+	},
+	getPropertyPageId: function() {return "context-view-options";}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/views/main-view.js b/chrome/colorediffs.jar!/content/colorediffs/views/main-view.js
new file mode 100644
index 0000000..c5cd7b0
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/views/main-view.js
@@ -0,0 +1,3 @@
+colorediffsGlobal.render = function(il, pref, dom) {
+	return colorediffsGlobal.views[pref.mode.get()].render(il, pref, dom);
+}
diff --git a/chrome/colorediffs.jar!/content/colorediffs/views/side-by-side-view.js b/chrome/colorediffs.jar!/content/colorediffs/views/side-by-side-view.js
new file mode 100644
index 0000000..70cdbfc
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/views/side-by-side-view.js
@@ -0,0 +1,335 @@
+
+colorediffsGlobal.views["side-by-side"] = {
+ render: function(il, pref, dom) {
+		var me = colorediffsGlobal;
+
+		function createCodeElement (side, code) {
+			var e = dom.createElement("pre", {'class':side}, code);
+			e.addEventListener("scroll", function(evt) {colorediffsGlobal.scrollCallback(evt);}, false);
+			return e;
+		}
+
+		function pcp(str) {
+			return str.replace(/\$cp{(.*?)}/g, function(str, prop) {
+					return pref.getColorProps(prop.trim());
+				});
+		}
+
+		function createCodeLine(klass, title, code) {
+			var t = (title)?"title='" + title + "'" : "";
+			return "<span class='" + klass + "' " + t + ">" + code + "</span>\n";
+		}
+
+		return [
+			function() {
+				var stylecontent = "";
+				stylecontent += "	.log			{$cp{diffColorer.sbs_log		}; padding: 5px; border: 1px solid black;overflow:auto;}\n";
+				stylecontent += "	.file-diff		{$cp{diffColorer.sbs_file-diff	}; padding: 3px;margin:5px;border: 1px solid black; table-layout: fixed;}\n";
+				stylecontent += "	.title			{$cp{diffColorer.sbs_title		};padding: 5px; margin:0; overflow:auto; border: 1px solid black;}\n";
+				stylecontent += "	.pre-code		{$cp{diffColorer.sbs_precode	}; margin:0;overflow:auto;}\n";
+				stylecontent += "	.addline		{$cp{diffColorer.sbs_addedLine	}; margin-left:5px;margin-right:5px;}\n";
+				stylecontent += "	.delline		{$cp{diffColorer.sbs_deletedLine}; margin-left:5px;margin-right:5px;}\n";
+				stylecontent += "	.steadyline		{$cp{diffColorer.sbs_steadyLine }; margin-left:5px;margin-right:5px;}\n";
+				stylecontent += "	.linetag		{$cp{diffColorer.sbs_anchor		}; text-align:center;clear:left;margin:0;}\n";
+				stylecontent += "	.left			{$cp{diffColorer.sbs_left		};margin:0; overflow:auto; border: 1px solid black;padding-top:5px;padding-bottom:5px;}\n";
+				stylecontent += "	.right			{$cp{diffColorer.sbs_right		};margin:0; overflow:auto; border: 1px solid black;padding-top:5px;padding-bottom:5px;}\n";
+				stylecontent += "	.left-title		{$cp{diffColorer.sbs_left-title };padding: 0; margin:0; overflow:auto; border: 1px solid black;}\n";
+				stylecontent += "	.right-title	{$cp{diffColorer.sbs_right-title};padding: 0; margin:0; overflow:auto; border: 1px solid black;}\n";
+				stylecontent += "	.left .addline	{$cp{diffColorer.sbs_emptyLine	};color: green;}\n";
+				stylecontent += "	.right .delline	{$cp{diffColorer.sbs_emptyLine	};color: green;}\n";
+
+				return dom.createElement("style", null, pcp(stylecontent));
+			}(),
+			dom.createDocumentFragment(
+				dom.createElement("pre", {id:'log', 'class':'log', wrap: ""}, il.log),
+				il.files.map(function(file) {
+
+						return dom.createElement(
+							"table", {'class':'file-diff', title:file.commonNameTruncated, id:file.id, width:"99%", align:"center"},
+							dom.createElement(
+								"tr", {},
+								dom.createElement(
+									"td", {colspan:2},
+									dom.createElement(
+										"pre", {'class':'title', wrap: ""},
+										file.title
+									)
+								)
+							),
+							dom.createElement(
+								"tr", {'class':'pre-code'},
+								dom.createElement(
+									"td", {colspan:2},
+									dom.createElement(
+										"pre", {'class':'pre-code', wrap: ""},
+										file.additional_info
+									)
+								)
+							),
+							function() {
+								if ( file['old'] && file['old'].chunks && file['new'] && file['new'].chunks ) {
+									return side_by_side_file(file);
+								} else if ( file['old'] && file['old'].chunks ) {
+									return standalone_file(file, 'old');
+								} else if ( file['new'] && file['new'].chunks ) {
+									return standalone_file(file, 'new');
+								} else {
+									return null;
+								}
+							} ()
+						);
+					}
+				),
+				dom.createElement(
+					"pre", {wrap: "", style: "overflow:auto;"},
+					il.postfix || ""
+				)
+			)
+		];
+
+		function side_by_side_file(file) {
+			var old_version = (file['old'].version) ? "\t" + file['old'].version : "";
+			var new_version = (file['new'].version) ? "\t" + file['new'].version : "";
+
+			var old_title = (file['old'].name + old_version).replace(" ", " ", "g");
+			var new_title = (file['new'].name + new_version).replace(" ", " ", "g");
+
+			return [
+				dom.createElement(
+					"tr", {},
+					dom.createElement(
+						"td", {valign:'top', width:'50%'},
+						dom.createElement(
+							'pre', {'class':'left-title', wrap: ""},
+							dom.createElement('div', {style: 'padding:5px'}, old_title))
+					),
+					dom.createElement(
+						"td", {valign:'top', width:'50%'},
+						dom.createElement(
+							'pre', {'class':'right-title', wrap: ""},
+							dom.createElement('div', {style: 'padding:5px'}, new_title))
+					)
+				),
+				me.ilUtils.chunksMap(file, function(old_chunk, new_chunk) {
+						var prev_old_class = null;
+						var prev_new_class = null;
+
+
+						function startCodeBlockIfNeeded(old_class, new_class) {
+							if (old_class != prev_old_class) {
+								if (prev_old_class) {
+									oldCodeDecorated += "</div>";
+								}
+								oldCodeDecorated += "<div class='" + old_class + "'>";
+								prev_old_class = old_class;
+							}
+							if (new_class != prev_new_class) {
+								if (prev_new_class) {
+									newCodeDecorated += "</div>";
+								}
+								newCodeDecorated += "<div class='" + new_class + "'>";
+								prev_new_class = new_class;
+							}
+						}
+
+						var oldCodeDecorated = "";
+						var newCodeDecorated = "";
+						var oldLine = old_chunk.line;
+						var newLine = new_chunk.line;
+
+						var oldCode = old_chunk.code;
+						var newCode = new_chunk.code;
+
+						var oldPadding = old_chunk.padding;
+						var newPadding = new_chunk.padding;
+
+						var l = old_chunk.code.length;
+
+						for (var i=0; i < l; ++i) {
+							var oldCodeLine = oldCode[i] + oldPadding[i];
+							var newCodeLine = newCode[i] + newPadding[i];
+
+							switch( old_chunk.status[i] ) {
+								case "A": //Added
+									startCodeBlockIfNeeded('addline', 'addline');
+									oldCodeDecorated += createCodeLine('addline', null, oldPadding[i]);
+									newCodeDecorated += createCodeLine('addline', file['new'].name15Truncated + ":" + newLine, newCodeLine);
+									newLine++;
+									break;
+								case "D": //Deleted
+									startCodeBlockIfNeeded('delline', 'delline');
+									newCodeDecorated += createCodeLine('delline', null, newPadding[i]);
+									oldCodeDecorated += createCodeLine('delline', file['old'].name15Truncated + ":" + oldLine, oldCodeLine);
+									oldLine++;
+									break;
+								case "C": //Changed
+									startCodeBlockIfNeeded('delline', 'addline');
+									oldCodeDecorated += createCodeLine('delline', file['old'].name15Truncated + ":" + oldLine, oldCodeLine);
+									newCodeDecorated += createCodeLine('addline', file['new'].name15Truncated + ":" + newLine, newCodeLine);
+									newLine++;
+									oldLine++;
+									break;
+								case "S": //the Same
+									startCodeBlockIfNeeded('steadyline', 'steadyline');
+									oldCodeDecorated += createCodeLine('steadyline', file['old'].name15Truncated + ":" + oldLine, oldCodeLine);
+									newCodeDecorated += createCodeLine('steadyline', file['new'].name15Truncated + ":" + newLine, newCodeLine);
+									newLine++;
+									oldLine++;
+									break;
+							}
+						}
+
+						if (old_chunk.doesnt_have_new_line && !new_chunk.doesnt_have_new_line) {
+							startCodeBlockIfNeeded('addline', 'addline');
+							newCodeDecorated += createCodeLine('addline', file['new'].name15Truncated + ":" + newLine, newPadding[i]);
+							oldCodeDecorated += createCodeLine('addline', file['old'].name15Truncated, oldPadding[i]);
+						}
+
+						if (!old_chunk.doesnt_have_new_line && new_chunk.doesnt_have_new_line) {
+							startCodeBlockIfNeeded('delline', 'delline');
+							newCodeDecorated += createCodeLine('delline', file['new'].name15Truncated, newPadding[i]);
+							oldCodeDecorated += createCodeLine('delline', file['old'].name15Truncated + ":" + oldLine, oldPadding[i]);
+						}
+
+						oldCodeDecorated += "</div>";
+						newCodeDecorated += "</div>";
+
+						return [
+							dom.createElement(
+								"tr", {'class':'linetag'},
+								dom.createElement("td", {colspan:2},
+												  "@@ -" + old_chunk.line +
+												  "," + old_chunk.code_size +
+												  " +" +new_chunk.line +
+												  "," + new_chunk.code_size +
+												  " @@")
+							),
+							dom.createElement(
+								"tr", {'class':'diffs'},
+								dom.createElement(
+									"td", {valign:'top', width:'50%'},
+									createCodeElement('left', oldCodeDecorated)
+								),
+								dom.createElement(
+									"td", {valign:'top', width:'50%'},
+									createCodeElement('right', newCodeDecorated)
+								)
+							)
+						];
+					}
+				)
+			];
+		}
+
+		function standalone_file(file, side) {
+			var version = (file[side].version) ? "\t" + file[side].version : "";
+
+			switch(side) {
+				case "new":
+					var changedClass = "addline";
+					var ignoredTag = "D";
+					var anchorSign = "+";
+					var sideClass = "right";
+					break;
+				case "old":
+					var changedClass = "delline";
+					var ignoredTag = "A";
+					var anchorSign = "-";
+					var sideClass = "left";
+					break;
+			}
+
+			return [
+				dom.createElement(
+					"tr", {},
+					dom.createElement(
+						"td", {valign:'top', colspan:'2'},
+						dom.createElement(
+							'pre', {'class':sideClass+"-title", wrap: ""},
+							dom.createElement('div', {style: 'padding:5px'}, file[side].name + version)
+						)
+					)
+				),
+				file[side].chunks.map(function(chunk) {
+						function getDecoratedLine(decoratedClass, code, line) {
+							return createCodeLine(decoratedClass, file[side].name15Truncated + ":" + line, code);
+						}
+
+						var prev_class = null;
+
+						function startCodeBlockIfNeeded(klass) {
+							if (klass != prev_class) {
+								if (prev_class) {
+									codeDecorated += "</div>";
+								}
+								codeDecorated += "<div class='" + klass + "'>";
+								prev_class = klass;
+							}
+						}
+
+						var codeDecorated = "";
+						var line = chunk.line;
+
+						var code = chunk.code;
+						var padding = chunk.padding;
+
+						var l = chunk.code.length;
+
+						for (var i=0; i < l; ++i) {
+							var codeLine = code[i] + padding[i];
+
+							if ( codeLine == "" ) {
+								codeLine = " ";
+							}
+
+							switch( chunk.status[i] ) {
+								case "A": //Added
+								case "D": //Deleted
+								case "C": //Changed
+									startCodeBlockIfNeeded(changedClass);
+									if (ignoredTag != chunk.status[i]) {
+										codeDecorated += getDecoratedLine(changedClass, codeLine, line);
+										line++;
+									}
+									break;
+								case "S": //the Same
+									startCodeBlockIfNeeded('steadyline');
+									codeDecorated += getDecoratedLine('steadyline', codeLine, line);
+									line++;
+									break;
+							}
+
+						}
+
+						if (chunk.doesnt_have_new_line) {
+							startCodeBlockIfNeeded('steadyline');
+							codeDecorated += createCodeLine('steadyline', file.name15Truncated, "\\ No newline at end of file");
+						}
+
+						codeDecorated += "</div>";
+
+						return [
+							dom.createElement(
+								"tr", {'class':'linetag'},
+								dom.createElement("td", {colspan:'2'},
+												  "@@ " + anchorSign + chunk.line +
+												  "," + chunk.code_size +
+												  " @@")
+							),
+							dom.createElement(
+								"tr", {'class':'diffs'},
+								dom.createElement(
+									"td", {valign:'top', colspan:'2'},
+									dom.createElement("pre", {'class':sideClass}, codeDecorated)
+								)
+							)
+						];
+					}
+				)
+			];
+		}
+
+		return null;
+	},
+	getPropertyPageId: function() {return "side-by-side-view-options";}
+};
diff --git a/chrome/colorediffs.jar!/content/colorediffs/views/unified-view.js b/chrome/colorediffs.jar!/content/colorediffs/views/unified-view.js
new file mode 100644
index 0000000..1d5f1cd
--- /dev/null
+++ b/chrome/colorediffs.jar!/content/colorediffs/views/unified-view.js
@@ -0,0 +1,219 @@
+
+colorediffsGlobal.views["unified"] = {
+ render: function(il, pref, dom) {
+		var me = colorediffsGlobal;
+
+		return [
+			function() {
+				var colorStyle = function(style, prop) {
+					return "." + style + " {" + pref.getColorProps(prop) + "}\n";
+				}
+
+				var stylecontent = "";
+
+				stylecontent += colorStyle("linetag", "diffColorer.anchor");
+				stylecontent += colorStyle("addline", "diffColorer.addedLine");
+				stylecontent += colorStyle("delline", "diffColorer.deletedLine");
+				stylecontent += colorStyle("steadyline", "diffColorer.steadyLine");
+				stylecontent += colorStyle("title", "diffColorer.title");
+				stylecontent += colorStyle("precode", "diffColorer.precode");
+				//stylecontent += ".addline {color: red;}\n";
+				stylecontent += "pre {font-family:monospace;}\n";
+				stylecontent += ".title, .linetag, .diffs, .addline, .delline, .precode {margin:0;}\n";
+				return dom.createElement("style", null, stylecontent);
+			}(),
+			dom.createDocumentFragment(
+				dom.createElement("pre", {id:'log', 'class':'log', wrap: ""}, il.log),
+				il.files.map(function(file) {
+						return dom.createElement(
+							"div", {'class':'file-diff', title:file.commonNameTruncated, id:file.id, width:"100%"},
+							dom.createElement(
+								"pre", {'class':'title', wrap: ""},
+								file.title + "\n======================================="
+							),
+							dom.createElement(
+								"pre", {'class':'precode', wrap: ""},
+								file.additional_info
+							),
+							function () {
+								if (file['old'].chunks || file['new'].chunks) {
+									var old_name;
+									var new_name;
+									var old_version;
+									var new_version;
+
+									if ( file['old'] && file['old'].name ) {
+										old_name = file['old'].name;
+										old_version = (file['old'].version) ? "\t" + file['old'].version : "";
+									} else {
+										old_name = file['new'].name;
+										old_version = "";
+									}
+
+									if ( file['new'] && file['new'].name ) {
+										new_name = file['new'].name;
+										new_version = (file['new'].version) ? "\t" + file['new'].version : "";
+									} else {
+										new_name = file['old'].name;
+										new_version = "";
+									}
+
+
+									return [dom.createElement(
+											"pre", {'class':'delline'},
+											"--- " + old_name + old_version
+										),
+										dom.createElement(
+											"pre", {'class':'addline'},
+											"+++ " + new_name + new_version
+										)];
+								} else {
+									return null;
+								}
+							}(),
+							me.ilUtils.chunksMap(file, function(old_chunk, new_chunk) {
+									var only_new = false;
+									var only_old = false;
+
+
+									if (old_chunk == null) {
+										only_new = true;
+										old_chunk = gen_empty_chunk(new_chunk);
+									}
+
+									if (new_chunk == null) {
+										only_old = true;
+										new_chunk = gen_empty_chunk(old_chunk);
+									}
+
+									var codeDecorated = [];
+									var oldCodeDecorated = [];
+									var newCodeDecorated = [];
+
+									var oldLine = old_chunk.line;
+									var newLine = new_chunk.line;
+
+									var oldCode = old_chunk.code; //.concat([]); //do not copy array;
+									var newCode = new_chunk.code; //.concat([]); //do not copy array
+
+									var l = new_chunk.code.length;
+
+									for (var i=0; i < l; ++i) {
+										switch( new_chunk.status[i] ) {
+											case "A": //Added
+												var line = newCode[i];
+
+												newCodeDecorated.push("<div class='addline' title='" + file['new'].name15Truncated + ":" + newLine + "'>+" + line +" </div>");
+												newLine++;
+												break;
+											case "D": //Deleted
+												var line = oldCode[i];
+
+												oldCodeDecorated.push("<div class='delline' title='" + file['old'].name15Truncated + ":" + oldLine + "'>-" + line +" </div>");
+												oldLine++;
+												break;
+											case "C": //Changed
+												newCodeDecorated.push("<div class='addline' title='" + file['new'].name15Truncated + ":" + newLine + "'>+" + newCode[i] +" </div>");
+												oldCodeDecorated.push("<div class='delline' title='" + file['old'].name15Truncated + ":" + oldLine + "'>-" + oldCode[i] +" </div>");
+												newLine++;
+												oldLine++;
+												break;
+											case "S": //the Same
+												if ( !only_new ) {
+													codeDecorated = codeDecorated.concat(oldCodeDecorated);
+												}
+
+												if ( !only_old ) {
+													codeDecorated = codeDecorated.concat(newCodeDecorated);
+												}
+
+												oldCodeDecorated = [];
+												newCodeDecorated = [];
+
+												if ( only_old ) {
+													var line = oldCode[i];
+													var tooltip = file['old'].name15Truncated + ':' + oldLine;
+												} else if (only_new) {
+													var line = newCode[i];
+													var tooltip = file['new'].name15Truncated + ':' + newLine;
+												} else {
+													var line = newCode[i];
+													var tooltip = "old: " + file['old'].name7Truncated + ':' + oldLine + ", " +
+																  "new: " + file['new'].name7Truncated + ':' + newLine;
+												}
+
+												codeDecorated.push("<div class='steadyline' title='" + tooltip + "'> " + line +" </div>");
+
+												newLine++;
+												oldLine++;
+												break;
+										}
+									}
+
+									if (old_chunk.doesnt_have_new_line && !new_chunk.doesnt_have_new_line) {
+										oldCodeDecorated.push("<div class='steadyline' title='" + file['old'].name15Truncated + "'>\\ No newline at end of file</div>");
+									}
+
+									if (!old_chunk.doesnt_have_new_line && new_chunk.doesnt_have_new_line) {
+										newCodeDecorated.push("<div class='steadyline' title='" + file['new'].name15Truncated + "'>\\ No newline at end of file</div>");
+									}
+
+									if ( !only_new ) {
+										codeDecorated = codeDecorated.concat(oldCodeDecorated);
+									}
+
+									if ( !only_old ) {
+										codeDecorated = codeDecorated.concat(newCodeDecorated);
+									}
+
+									if (old_chunk.doesnt_have_new_line && new_chunk.doesnt_have_new_line) {
+										codeDecorated.push("<div class='steadyline' title='" + file.commonNameTruncated + "'>\\ No newline at end of file</div>");
+									}
+
+									return [
+										dom.createElement(
+											"pre", {'class':'linetag'},
+											"@@ -" + old_chunk.line +
+											"," + old_chunk.code_size +
+											" +" +new_chunk.line +
+											"," + new_chunk.code_size +
+											" @@"
+										),
+										dom.createElement(
+											"pre", {'class':'diffs'},
+											codeDecorated.join("")
+										)
+									];
+								}
+							),
+							dom.createElement(
+								"pre", {},
+								""
+							)
+						);
+					}
+				),
+				dom.createElement(
+					"pre", {wrap: ""},
+					il.postfix || ""
+				)
+			)
+		];
+
+
+		function gen_empty_chunk(oposite_chunk) {
+			var chunk = {line:0, code:[], code_size:0};
+			for (var i = 0; i < oposite_chunk.code.length; i++ ) {
+				chunk.code.push(null);
+			}
+
+			chunk.status = oposite_chunk.status;
+
+			return chunk;
+		}
+
+		//Seriously, that bug is annoying.
+		return null;
+	},
+	getPropertyPageId: function() {return "unified-view-options";}
+};
diff --git a/chrome/colorediffs.jar!/skin/colorediffs.css b/chrome/colorediffs.jar!/skin/colorediffs.css
new file mode 100644
index 0000000..f233721
--- /dev/null
+++ b/chrome/colorediffs.jar!/skin/colorediffs.css
@@ -0,0 +1,17 @@
+#colorediffs-show-whitespaces {
+	list-style-image: url("chrome://colorediffs/skin/white-space.png");
+}
+
+#colorediffs-options {
+	list-style-image: url("chrome://colorediffs/skin/options.png");
+}
+
+#colorediffs-show-line-numbers {
+	list-style-image: url("chrome://colorediffs/skin/line-numbers.png");
+}
+
+#colorediffs-close-toolbar {
+	/*-moz-image-region: rect(0px, 48px, 16px, 32px);*/
+	height: 24px;
+	list-style-image: url("chrome://global/skin/icons/Close.gif");
+}
\ No newline at end of file
diff --git a/chrome/colorediffs.jar!/skin/line-numbers.png b/chrome/colorediffs.jar!/skin/line-numbers.png
new file mode 100644
index 0000000..7946357
Binary files /dev/null and b/chrome/colorediffs.jar!/skin/line-numbers.png differ
diff --git a/chrome/colorediffs.jar!/skin/options.png b/chrome/colorediffs.jar!/skin/options.png
new file mode 100644
index 0000000..a6d18d8
Binary files /dev/null and b/chrome/colorediffs.jar!/skin/options.png differ
diff --git a/chrome/colorediffs.jar!/skin/white-space.png b/chrome/colorediffs.jar!/skin/white-space.png
new file mode 100644
index 0000000..8b66ca0
Binary files /dev/null and b/chrome/colorediffs.jar!/skin/white-space.png differ
diff --git a/defaults/preferences/colorediffs.js b/defaults/preferences/colorediffs.js
new file mode 100644
index 0000000..79f3a5a
--- /dev/null
+++ b/defaults/preferences/colorediffs.js
@@ -0,0 +1,66 @@
+pref("diffColorer.anchor_fg", "blue");
+pref("diffColorer.anchor_bg", "white");
+pref("diffColorer.steadyLine_fg", "grey");
+pref("diffColorer.steadyLine_bg", "white");
+pref("diffColorer.deletedLine_fg", "red");
+pref("diffColorer.deletedLine_bg", "white");
+pref("diffColorer.addedLine_fg", "green");
+pref("diffColorer.addedLine_bg", "white");
+pref("diffColorer.title_fg", "#840084");
+pref("diffColorer.title_bg", "white");
+pref("diffColorer.precode_fg", "lightgrey");
+pref("diffColorer.precode_bg", "white");
+
+pref("diffColorer.c_anchor_fg", "blue");
+pref("diffColorer.c_anchor_bg", "white");
+pref("diffColorer.c_steadyLine_fg", "grey");
+pref("diffColorer.c_steadyLine_bg", "white");
+pref("diffColorer.c_deletedLine_fg", "red");
+pref("diffColorer.c_deletedLine_bg", "white");
+pref("diffColorer.c_addedLine_fg", "green");
+pref("diffColorer.c_addedLine_bg", "white");
+pref("diffColorer.c_title_fg", "#840084");
+pref("diffColorer.c_title_bg", "white");
+pref("diffColorer.c_precode_fg", "lightgrey");
+pref("diffColorer.c_precode_bg", "white");
+
+pref("diffColorer.sbs_anchor_fg", "blue");
+pref("diffColorer.sbs_anchor_bg", "#DDFF88");
+pref("diffColorer.sbs_steadyLine_fg", "#484848");
+pref("diffColorer.sbs_steadyLine_bg", "#EFEFEF");
+pref("diffColorer.sbs_deletedLine_fg", "#4F0000");
+pref("diffColorer.sbs_deletedLine_bg", "#EFAAAA");
+pref("diffColorer.sbs_addedLine_fg", "#004F00");
+pref("diffColorer.sbs_addedLine_bg", "#AAEFAA");
+pref("diffColorer.sbs_title_fg", "#000025");
+pref("diffColorer.sbs_title_bg", "#9988FF");
+pref("diffColorer.sbs_log_fg", "black");
+pref("diffColorer.sbs_log_bg", "lightgray");
+pref("diffColorer.sbs_file-diff_fg", "white");
+pref("diffColorer.sbs_file-diff_bg", "#DDFF88");
+pref("diffColorer.sbs_precode_fg", "gray");
+pref("diffColorer.sbs_precode_bg", "#DDFF88");
+pref("diffColorer.sbs_left-title_fg", "#4F0000");
+pref("diffColorer.sbs_left-title_bg", "#EFAAAA");
+pref("diffColorer.sbs_right-title_fg", "#004F00");
+pref("diffColorer.sbs_right-title_bg", "#AAEFAA");
+pref("diffColorer.sbs_right_fg", "white");
+pref("diffColorer.sbs_right_bg", "#EFEFEF");
+pref("diffColorer.sbs_left_fg", "white");
+pref("diffColorer.sbs_left_bg", "#EFEFEF");
+pref("diffColorer.sbs_emptyLine_fg", "white");
+pref("diffColorer.sbs_emptyLine_bg", "#997777");
+
+pref("diffColorer.view-mode", "unified");
+pref("diffColorer.debug-mode", false);
+pref("diffColorer.show-whitespace", true);
+pref("diffColorer.show-toolbar", true);
+
+pref("diffColorer.parser.max-title-size", 5);
+pref("diffColorer.parser.min-title-delimiter-chars-count", 15);
+pref("diffColorer.parser.max-additional-info-size", 7);
+pref("diffColorer.parser.max-postfix-size", 15);
+
+pref("diffColorer.diff-mode", "both");
+pref("diffColorer.show-line-numbers", false);
+pref("diffColorer.tab-size", 8);
diff --git a/install.rdf b/install.rdf
new file mode 100644
index 0000000..70ff770
--- /dev/null
+++ b/install.rdf
@@ -0,0 +1,32 @@
+<?xml version="1.0"?>
+<RDF:RDF xmlns:em="http://www.mozilla.org/2004/em-rdf#"
+		 xmlns:NC="http://home.netscape.com/NC-rdf#"
+		 xmlns:RDF="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
+  <RDF:Description RDF:about="urn:mozilla:install-manifest"
+				   em:id="{282C3C7A-15A8-4037-A30D-BBEB17FFC76B}"
+				   em:name="Colored Diffs"
+				   em:version="0.6.2012.01.27.14.07.45"
+				   em:creator="Vadim Atlygin"
+				   em:description="Color diffs sent by SVN/CVS notifications."
+				   em:homepageURL="http://code.google.com/p/colorediffs/"
+				   em:iconURL="chrome://colorediffs/content/icon.png"
+				   em:optionsURL="chrome://colorediffs/content/options/options.xul"
+				   >
+    <em:targetApplication>
+      <RDF:Description>
+        <em:id>{3550f703-e582-4d05-9a08-453d09bdfdc6}</em:id>
+        <em:maxVersion>10.*</em:maxVersion>
+        <em:minVersion>3.0a1pre</em:minVersion>
+
+      </RDF:Description>
+    </em:targetApplication>
+    <em:targetApplication>
+      <RDF:Description>
+        <em:id>{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}</em:id>
+        <em:maxVersion>2.0.*</em:maxVersion>
+        <em:minVersion>2.0a2</em:minVersion>
+
+      </RDF:Description>
+    </em:targetApplication>
+  </RDF:Description>
+</RDF:RDF>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-mozext/colorediffs-extension.git



More information about the Pkg-mozext-commits mailing list