diff --git a/.gitignore b/.gitignore --- a/.gitignore +++ b/.gitignore @@ -30,3 +30,6 @@ # User extensions /src/extensions/* + +# NPM local packages +/support/aphlict/server/node_modules/ diff --git a/externals/vegas/LICENSE b/externals/vegas/LICENSE deleted file mode 100644 --- a/externals/vegas/LICENSE +++ /dev/null @@ -1,581 +0,0 @@ -Mozilla Public License 1.1 (MPL 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/externals/vegas/README b/externals/vegas/README deleted file mode 100644 --- a/externals/vegas/README +++ /dev/null @@ -1,29 +0,0 @@ -VEGAS AS3 - version 1.8.5.2228 - -The "vegas.swc" library contains all the AS3 source code of the VEGAS project with all this extensions. - -LICENCE - - Version: MPL 1.1/GPL 2.0/LGPL 2.1 - -PROJECT PAGES - - * http://code.google.com/p/vegas/ - -DOCUMENTATION & CO - - * http://code.google.com/p/vegas/ (tutorials and install) - * http://code.google.com/p/vegas/issues/list (issues) - * http://www.ekameleon.net/vegas/docs - - * http://www.ekameleon.net/blog/ (french blog) - -ABOUT AUTHOR - - * Author : ALCARAZ Marc (eKameleon) - * Link : http://www.ekameleon.net/blog - * Mail : ekameleon@gmail.com - -NOTES - -The vegas.swc file target now the FlashPlayer 10.2 and build with the Flex SDK 4.5.0.19786. \ No newline at end of file diff --git a/externals/vegas/src/system/Serializer.as b/externals/vegas/src/system/Serializer.as deleted file mode 100644 --- a/externals/vegas/src/system/Serializer.as +++ /dev/null @@ -1,86 +0,0 @@ -/* - Version: MPL 1.1/GPL 2.0/LGPL 2.1 - - 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 [maashaack framework]. - - The Initial Developers of the Original Code are - Zwetan Kjukov and Marc Alcaraz . - Portions created by the Initial Developers are Copyright (C) 2006-2011 - the Initial Developers. All Rights Reserved. - - Contributor(s): - - Alternatively, the contents of this file may be used under the terms of - either the GNU General Public License Version 2 or later (the "GPL"), or - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - in which case the provisions of the GPL or the LGPL are applicable instead - of those above. If you wish to allow use of your version of this file only - under the terms of either the GPL or the LGPL, and not to allow others to - use your version of this file under the terms of the MPL, indicate your - decision by deleting the provisions above and replace them with the notice - and other provisions required by the LGPL or the GPL. If you do not delete - the provisions above, a recipient may use your version of this file under - the terms of any one of the MPL, the GPL or the LGPL. -*/ - -package system -{ - - /** - * Defines what a Serializer have to implements to be integrated in the framework. - *

Note : Every serializers (eden, json, wddx, etc.) should implement it.

- */ - public interface Serializer - { - /** - * The prettyIndent value of the serializer. - */ - function get prettyIndent():int; - - /** - * @private - */ - function set prettyIndent( value:int ):void; - - /** - * The prettyPrinting value of the serializer. - */ - function get prettyPrinting():Boolean; - - /** - * @private - */ - function set prettyPrinting( value:Boolean ):void; - - /** - * The identor String value of the serializer. - */ - function get indentor():String; - - /** - * @private - */ - function set indentor( value:String ):void; - - /** - * Deserialize the specified String source representation. - */ - function deserialize( source:String ):*; - - /** - * Serialize the specified object. - */ - function serialize( value:* ):String; - } -} - diff --git a/externals/vegas/src/vegas/strings/JSON.as b/externals/vegas/src/vegas/strings/JSON.as deleted file mode 100644 --- a/externals/vegas/src/vegas/strings/JSON.as +++ /dev/null @@ -1,107 +0,0 @@ -/* - - Version: MPL 1.1/GPL 2.0/LGPL 2.1 - - 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 VEGAS Framework. - - The Initial Developer of the Original Code is - ALCARAZ Marc (aka eKameleon) . - Portions created by the Initial Developer are Copyright (C) 2004-2011 - the Initial Developer. All Rights Reserved. - - Contributor(s) : - - Alternatively, the contents of this file may be used under the terms of - either the GNU General Public License Version 2 or later (the "GPL"), or - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - in which case the provisions of the GPL or the LGPL are applicable instead - of those above. If you wish to allow use of your version of this file only - under the terms of either the GPL or the LGPL, and not to allow others to - use your version of this file under the terms of the MPL, indicate your - decision by deleting the provisions above and replace them with the notice - and other provisions required by the LGPL or the GPL. If you do not delete - the provisions above, a recipient may use your version of this file under - the terms of any one of the MPL, the GPL or the LGPL. - -*/ -package vegas.strings -{ - import vegas.strings.json.JSONSerializer; - - /** - * JSON (JavaScript object Notation) is a lightweight data-interchange format. - *

More information in the official site : http://www.JSON.org

- *

Add Hexa Digits tool in deserialize method - eden inspiration

- * - * @example Example - * - * - * import core.getClassName ; - * - * import vegas.strings.JSON; - * import vegas.strings.errors.JSONError; - * - * // --- Init - * - * var a:Array = [2, true, "hello"] ; - * var o:Object = { prop1 : 1 , prop2 : 2 } ; - * var s:String = "hello world" ; - * var n:Number = 4 ; - * var b:Boolean = true ; - * - * trace("# Serialize \r") ; - * - * trace("- a : " + JSON.serialize( a ) ) ; - * trace("- o : " + JSON.serialize( o ) ) ; - * trace("- s : " + JSON.serialize( s ) ) ; - * trace("- n : " + JSON.serialize( n ) ) ; - * trace("- b : " + JSON.serialize( b ) ) ; - * - * trace ("\r# Deserialize \r") ; - * - * var source:String = '[ { "prop1" : 0xFF0000 , prop2:2, prop3:"hello", prop4:true} , 2, true, 3, [3, 2] ]' ; - * - * o = JSON.deserialize(source) ; - * - * var l:uint = o.length ; - * for (var i:uint = 0 ; i < l ; i++) - * { - * trace("> " + i + " : " + o[i] + " -> typeof :: " + typeof(o[i])) ; - * if (typeof(o[i]) == "object") - * { - * for (var each:String in o[i]) - * { - * trace(" > " + each + " : " + o[i][each] + " :: " + getClassName(o[i][each]) ) ; - * } - * } - * } - * - * trace ("\r# JSONError \r") ; - * - * source = "[3, 2," ; // test1 - * - * // var source:String = '{"prop1":coucou"}' ; // test2 - * - * try - * { - * var errorObj:Object = JSON.deserialize(source) ; - * } - * catch( e:JSONError ) - * { - * trace( e.toString() ) ; - * } - * - * - */ - public var JSON:JSONSerializer = new JSONSerializer() ; -} \ No newline at end of file diff --git a/externals/vegas/src/vegas/strings/json/JSONError.as b/externals/vegas/src/vegas/strings/json/JSONError.as deleted file mode 100644 --- a/externals/vegas/src/vegas/strings/json/JSONError.as +++ /dev/null @@ -1,84 +0,0 @@ -/* - - Version: MPL 1.1/GPL 2.0/LGPL 2.1 - - 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 VEGAS Framework. - - The Initial Developer of the Original Code is - ALCARAZ Marc (aka eKameleon) . - Portions created by the Initial Developer are Copyright (C) 2004-2011 - the Initial Developer. All Rights Reserved. - - Contributor(s) : - - Alternatively, the contents of this file may be used under the terms of - either the GNU General Public License Version 2 or later (the "GPL"), or - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - in which case the provisions of the GPL or the LGPL are applicable instead - of those above. If you wish to allow use of your version of this file only - under the terms of either the GPL or the LGPL, and not to allow others to - use your version of this file under the terms of the MPL, indicate your - decision by deleting the provisions above and replace them with the notice - and other provisions required by the LGPL or the GPL. If you do not delete - the provisions above, a recipient may use your version of this file under - the terms of any one of the MPL, the GPL or the LGPL. - -*/ - -package vegas.strings.json -{ - /** - * This JSONError is throw in the JSON static methods. - */ - public class JSONError extends Error - { - /** - * Creates a new JSONError instance. - */ - public function JSONError( message:String, at:uint, source:String , id:int=0 ) - { - super( message , id ); - name = "JSONError" ; - this.at = at ; - this.source = source ; - } - - /** - * The position of char with an error parsing in the JSON String representation. - */ - public var at:uint ; - - /** - * The source ot the bad parsing. - */ - public var source:String ; - - /** - * Returns a String representation of the object. - * @return a String representation of the object. - */ - public function toString():String - { - var msg:String = "## " + name + " : " + message + " ##" ; - if (!isNaN(at)) - { - msg += ", at:" + at ; - } - if ( source != null ) - { - msg += " in \"" + source + "\""; - } - return msg ; - } - } -} \ No newline at end of file diff --git a/externals/vegas/src/vegas/strings/json/JSONSerializer.as b/externals/vegas/src/vegas/strings/json/JSONSerializer.as deleted file mode 100644 --- a/externals/vegas/src/vegas/strings/json/JSONSerializer.as +++ /dev/null @@ -1,757 +0,0 @@ -/* - - Version: MPL 1.1/GPL 2.0/LGPL 2.1 - - 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 VEGAS Framework. - - The Initial Developer of the Original Code is - ALCARAZ Marc (aka eKameleon) . - Portions created by the Initial Developer are Copyright (C) 2004-2011 - the Initial Developer. All Rights Reserved. - - Contributor(s) : - - Alternatively, the contents of this file may be used under the terms of - either the GNU General Public License Version 2 or later (the "GPL"), or - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - in which case the provisions of the GPL or the LGPL are applicable instead - of those above. If you wish to allow use of your version of this file only - under the terms of either the GPL or the LGPL, and not to allow others to - use your version of this file under the terms of the MPL, indicate your - decision by deleting the provisions above and replace them with the notice - and other provisions required by the LGPL or the GPL. If you do not delete - the provisions above, a recipient may use your version of this file under - the terms of any one of the MPL, the GPL or the LGPL. - -*/ - -package vegas.strings.json -{ - import system.Serializer; - - /** - * This class is the concrete class of the JSON singleton. - * JSON (JavaScript object Notation) is a lightweight data-interchange format. - *

More information in the official site : http://www.JSON.org

- *

Add Hexa Digits tool in deserialize method - eden inspiration

- *

Example :

- *
-     * import core.getClassName ;
-     * 
-     * import vegas.strings.JSON;
-     * import vegas.strings.JSONError;
-     * 
-     * // --- Init
-     * 
-     * var a:Array   = [2, true, "hello"] ;
-     * var o:Object  = { prop1 : 1 , prop2 : 2 } ;
-     * var s:String  = "hello world" ;
-     * var n:Number  = 4 ;
-     * var b:Boolean = true ;
-     * 
-     * trace("Serialize") ;
-     * 
-     * trace("- a : " + JSON.serialize( a ) )  ;
-     * trace("- o : " + JSON.serialize( o ) )  ;
-     * trace("- s : " + JSON.serialize( s ) )  ;
-     * trace("- n : " + JSON.serialize( n ) )  ;
-     * trace("- b : " + JSON.serialize( b ) )  ;
-     * 
-     * trace ("Deserialize") ;
-     * 
-     * var source:String = '[ { "prop1" : 0xFF0000 , prop2:2, prop3:"hello", prop4:true} , 2, true, 3, [3, 2] ]' ;
-     * 
-     * o = JSON.deserialize(source) ;
-     * 
-     * var l:uint = o.length ;
-     * for (var i:uint = 0 ; i < l ; i++)
-     * {
-     *     trace("- " + i + " : " + o[i] + " , typeof :: " + typeof(o[i])) ;
-     *     if (typeof(o[i]) == "object")
-     *     {
-     *         for (var each:String in o[i])
-     *         {
-     *             trace("    + " + each + " : " + o[i][each] + " :: " + getClassName(o[i][each]) ) ;
-     *         }
-     *     }
-     * }
-     * 
-     * trace ("JSONError") ;
-     * 
-     * source = "[3, 2," ; // test1
-     * 
-     * // var source:String = '{"prop1":coucou"}' ; // test2
-     * 
-     * try
-     * {
-     *    var errorObj:Object = JSON.deserialize(source) ;
-     * }
-     * catch( e:JSONError )
-     * {
-     *     trace( e.toString() ) ;
-     * }
-     * 
- */ - public class JSONSerializer implements Serializer - { - /** - * Creates a new JSONSerializer instance. - */ - public function JSONSerializer() - { - // - } - - /** - * The source to evaluate. - */ - public var source:String ; - - /** - * Indicates the indentor string representation. - */ - public function get indentor():String - { - return _indentor; - } - - /** - * @private - */ - public function set indentor(value:String):void - { - _indentor = value; - } - - /** - * Indicates the pretty indent value. - */ - public function get prettyIndent():int - { - return _prettyIndent; - } - - /** - * @private - */ - public function set prettyIndent(value:int):void - { - _prettyIndent = value ; - } - - /** - * Indicates the pretty printing flag value. - */ - public function get prettyPrinting():Boolean - { - return _prettyPrinting ; - } - - /** - * @private - */ - public function set prettyPrinting(value:Boolean):void - { - _prettyPrinting = value; - } - - /** - * Parse a string and interpret the source code to the correct object construct. - *

Example :

- *
-         * "hello world" --> "hello world"
-         * "0xFF"        --> 255
-         * "{a:1,"b":2}" --> {a:1,b:2}
-         * 
- * @return a string representing the data. - */ - public function deserialize( source:String ):* - { - this.source = source ; - at = 0 ; - ch = ' ' ; - return value() ; - } - - /** - * Serialize the specified value object passed-in argument. - */ - public function serialize( value:* ):String - { - var c:String ; // char - var i:int ; - var l:int ; - var s:String = '' ; - var v:* ; - var tof:String = typeof(value) ; - switch (tof) - { - case 'object' : - { - if (value) - { - if (value is Array) - { - l = (value as Array).length ; - for (i = 0 ; i < l ; ++i) - { - v = serialize(value[i]); - if (s) s += ',' ; - s += v ; - } - return '[' + s + ']'; - } - else if ( typeof( value.toString ) != 'undefined') - { - for (var prop:String in value) - { - v = value[prop]; - if ( (typeof(v) != 'undefined') && (typeof(v) != 'function') ) - { - v = serialize(v); - if (s) - { - s += ',' ; - } - s += serialize(prop) + ':' + v ; - } - } - return "{" + s + "}"; - } - } - return 'null'; - } - case 'number': - { - return isFinite(value) ? String(value) : 'null' ; - } - case 'string' : - { - l = (value as String).length ; - s = '"' ; - for (i = 0 ; i < l ; i += 1) - { - c = (value as String).charAt(i) ; - if (c >= ' ') - { - if (c == '\\' || c == '"') - { - s += '\\'; - } - s += c; - } - else - { - switch (c) - { - case '\b': - { - s += '\\b'; - break ; - } - case '\f' : - { - s += '\\f' ; - break ; - } - case '\n' : - { - s += '\\n' ; - break ; - } - case '\r': - { - s += '\\r' ; - break ; - } - case '\t': - { - s += '\\t' ; - break ; - } - default: - { - var code:Number = c.charCodeAt() ; - s += '\\u00' + String(Math.floor(code / 16).toString(16)) + ((code % 16).toString(16)) ; - } - } - } - } - return s + '"' ; - } - case 'boolean' : - { - return String(value); - } - default : - { - return 'null'; - } - } - } - - /** - * The current position of the iterator in the source. - */ - protected var at:Number = 0 ; - - /** - * The current character of the iterator in the source. - */ - protected var ch:String = ' ' ; - - /** - * Check the Array objects in the source expression. - */ - protected function array():Array - { - var a:Array = []; - if ( ch == '[' ) - { - next() ; - white() ; - if (ch == ']') - { - next(); - return a; - } - while (ch) - { - a.push( value() ) ; - white(); - if (ch == ']') - { - next(); - return a; - } - else if (ch != ',') - { - break; - } - next(); - white(); - } - } - error( JSONStrings.badArray ); - return null ; - } - - /** - * Throws a JSONError with the passed-in message. - */ - protected function error( m:String ):void - { - throw new JSONError( m, at - 1 , source) ; - } - - /** - * Indicates if the passed-in character is a digit. - */ - protected function isDigit( c:String ):Boolean - { - return( ("0" <= c) && (c <= "9") ); - } - - /** - * Indicates if the passed-in character is a hexadecimal digit. - */ - protected function isHexDigit( c:String ):Boolean - { - return( isDigit( c ) || (("A" <= c) && (c <= "F")) || (("a" <= c) && (c <= "f")) ); - } - - /** - * Indicates if the current character is a key. - */ - protected function key():* - { - var s:String = ch ; - var semiColon:int = source.indexOf( ':' , at ) ; - var quoteIndex:int = source.indexOf( '"' , at ) ; - var squoteIndex:int = source.indexOf( "'" , at ) ; - if( (quoteIndex <= semiColon && quoteIndex > -1) || (squoteIndex <= semiColon && squoteIndex > -1)) - { - s = string() ; - white() ; - if(ch == ':') - { - return s; - } - else - { - error(JSONStrings.badKey); - } - } - while ( next() ) // Use key handling - { - if (ch == ':') - { - return s; - } - if(ch <= ' ') - { - // - } - else - { - s += ch; - } - } - error( JSONStrings.badKey ) ; - } - - /** - * Returns the next character in the source String representation. - * @return the next character in the source String representation. - */ - protected function next():String - { - ch = source.charAt(at); - at += 1; - return ch; - } - - /** - * Check the Number values in the source expression. - */ - protected function number():* - { - - var n:* = '' ; - var v:* ; - var hex:String = '' ; - var sign:String = '' ; - if (ch == '-') - { - n = '-'; - sign = n ; - next(); - } - if( ch == "0" ) - { - next() ; - if( ( ch == "x") || ( ch == "X") ) - { - next(); - while( isHexDigit( ch ) ) - { - hex += ch ; - next(); - } - if( hex == "" ) - { - error(JSONStrings.malFormedHexadecimal) ; - } - else - { - return Number( sign + "0x" + hex ) ; - } - } - else - { - n += "0" ; - } - } - while ( isDigit(ch) ) - { - n += ch ; - next() ; - } - if (ch == '.') - { - n += '.'; - while (next() && ch >= '0' && ch <= '9') - { - n += ch ; - } - } - v = 1 * n ; - if (!isFinite(v)) - { - error( JSONStrings.badNumber ); - } - else - { - return v ; - } - return NaN ; - } - - /** - * Check the Object values in the source expression. - */ - protected function object():* - { - var k:* = {} ; - var o:* = {} ; - if (ch == '{') - { - next(); - white(); - if (ch == '}') - { - next() ; - return o ; - } - while (ch) - { - k = key() ; - white(); - if (ch != ':') - { - break; - } - next(); - o[k] = value() ; - white(); - if (ch == '}') - { - next(); - return o; - } - else if (ch != ',') - { - break; - } - next(); - white(); - } - } - error( JSONStrings.badObject ) ; - } - - /** - * Check the string objects in the source expression. - */ - protected function string():* - { - var i:* = '' ; - var s:* = '' ; - var t:* ; - var u:* ; - var outer:Boolean ; - if (ch == '"' || ch == "'" ) - { - var outerChar:String = ch ; - while ( next() ) - { - if (ch == outerChar) - { - next() ; - return s ; - } - else if (ch == '\\') - { - switch ( next() ) - { - case 'b': - { - s += '\b' ; - break ; - } - case 'f' : - { - s += '\f'; - break ; - } - case 'n': - { - s += '\n'; - break ; - } - case 'r' : - { - s += '\r'; - break ; - } - case 't' : - { - s += '\t' ; - break ; - } - case 'u' : - { - u = 0; - for (i = 0; i < 4; i += 1) - { - t = parseInt( next() , 16 ) ; - if (!isFinite(t)) - { - outer = true; - break; - } - u = u * 16 + t; - } - if(outer) - { - outer = false; - break; - } - s += String.fromCharCode(u); - break; - } - default : - { - s += ch; - } - } - } - else - { - s += ch; - } - } - } - error( JSONStrings.badString ); - return null ; - } - - /** - * Evaluates the values in the source expression. - */ - protected function value():* - { - white() ; - if (ch == '{' ) - { - return object(); - } - else if ( ch == '[' ) - { - return array(); - } - else if ( ch == '"' || ch == "'" ) - { - return string(); - } - else if ( ch == '-' ) - { - return number(); - } - else - { - return ( ch >= '0' && ch <= '9' ) ? number() : word() ; - } - } - - /** - * Check all white spaces. - */ - protected function white():void - { - while (ch) - { - if (ch <= ' ') - { - next(); - } - else if (ch == '/') - { - switch ( next() ) - { - case '/' : - { - while ( next() && ch != '\n' && ch != '\r') - { - } - break; - } - case '*' : - { - next(); - for (;;) - { - if (ch) - { - if (ch == '*') - { - if ( next() == '/' ) - { - next(); - break; - } - } - else - { - next(); - } - } - else - { - error( JSONStrings.unterminatedComment ); - } - } - break ; - } - default : - { - error( JSONStrings.syntaxError ); - } - } - } - else - { - break ; - } - } - } - - /** - * Check all special words in the source to evaluate. - */ - protected function word():* - { - if (ch == 't') - { - if (next() == 'r' && next() == 'u' && next() == 'e') - { - next() ; - return true ; - } - } - else if ( ch == 'f' ) - { - if (next() == 'a' && next() == 'l' && next() == 's' && next() == 'e') - { - next() ; - return false ; - } - } - else if ( ch == 'n' ) - { - if (next() == 'u' && next() == 'l' && next() == 'l') - { - next() ; - return null ; - } - } - error( JSONStrings.syntaxError ); - return null ; - } - - /** - * @private - */ - private var _prettyIndent:int = 0 ; - - /** - * @private - */ - private var _prettyPrinting:Boolean ; - - /** - * @private - */ - private var _indentor:String = " " ; - } -} diff --git a/externals/vegas/src/vegas/strings/json/JSONStrings.as b/externals/vegas/src/vegas/strings/json/JSONStrings.as deleted file mode 100644 --- a/externals/vegas/src/vegas/strings/json/JSONStrings.as +++ /dev/null @@ -1,85 +0,0 @@ -/* - - Version: MPL 1.1/GPL 2.0/LGPL 2.1 - - 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 VEGAS Framework. - - The Initial Developer of the Original Code is - ALCARAZ Marc (aka eKameleon) . - Portions created by the Initial Developer are Copyright (C) 2004-2011 - the Initial Developer. All Rights Reserved. - - Contributor(s) : - - Alternatively, the contents of this file may be used under the terms of - either the GNU General Public License Version 2 or later (the "GPL"), or - the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), - in which case the provisions of the GPL or the LGPL are applicable instead - of those above. If you wish to allow use of your version of this file only - under the terms of either the GPL or the LGPL, and not to allow others to - use your version of this file under the terms of the MPL, indicate your - decision by deleting the provisions above and replace them with the notice - and other provisions required by the LGPL or the GPL. If you do not delete - the provisions above, a recipient may use your version of this file under - the terms of any one of the MPL, the GPL or the LGPL. - -*/ - -package vegas.strings.json -{ - /** - * The string messages used in the JSON class. - */ - public class JSONStrings - { - /** - * The bad Array error message. - */ - public static var badArray:String = "Bad Array" ; - - /** - * The bad key error message. - */ - public static var badKey:String = "Bad key" ; - - /** - * The bad Number error message. - */ - public static var badNumber:String = "Bad Number" ; - - /** - * The bad Object error message. - */ - public static var badObject:String = "Bad Object" ; - - /** - * The bad String error message. - */ - public static var badString:String = "Bad String" ; - - /** - * The mal formed Hexadecimal error message. - */ - public static var malFormedHexadecimal:String = "Mal formed Hexadecimal" ; - - /** - * The syntax error message. - */ - public static var syntaxError:String = "Syntax Error" ; - - /** - * The unterminated comment error message. - */ - public static var unterminatedComment:String = "Unterminated Comment" ; - } -} \ No newline at end of file diff --git a/resources/celerity/map.php b/resources/celerity/map.php --- a/resources/celerity/map.php +++ b/resources/celerity/map.php @@ -7,8 +7,8 @@ */ return array( 'names' => array( - 'core.pkg.css' => '63e782fb', - 'core.pkg.js' => '44aac665', + 'core.pkg.css' => '8fc8031a', + 'core.pkg.js' => '21041609', 'darkconsole.pkg.js' => '8ab24e01', 'differential.pkg.css' => '8af45893', 'differential.pkg.js' => 'dad3622f', @@ -342,9 +342,9 @@ 'rsrc/image/texture/table_header.png' => '5c433037', 'rsrc/image/texture/table_header_hover.png' => '038ec3b9', 'rsrc/image/texture/table_header_tall.png' => 'd56b434f', - 'rsrc/js/application/aphlict/Aphlict.js' => '4a07e8e3', + 'rsrc/js/application/aphlict/Aphlict.js' => '464d333a', 'rsrc/js/application/aphlict/behavior-aphlict-dropdown.js' => 'f6bc26f0', - 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => 'a826c925', + 'rsrc/js/application/aphlict/behavior-aphlict-listen.js' => '1162a152', 'rsrc/js/application/aphlict/behavior-aphlict-status.js' => '58f7803f', 'rsrc/js/application/auth/behavior-persona-login.js' => '9414ff18', 'rsrc/js/application/config/behavior-reorder-fields.js' => '14a827de', @@ -489,7 +489,6 @@ 'rsrc/js/phuix/PHUIXActionListView.js' => 'b5c256b8', 'rsrc/js/phuix/PHUIXActionView.js' => '6e8cefa4', 'rsrc/js/phuix/PHUIXDropdownMenu.js' => 'bd4c8dca', - 'rsrc/swf/aphlict.swf' => 'f19daffb', ), 'symbols' => array( 'almanac-css' => 'dbb9b3af', @@ -536,10 +535,10 @@ 'herald-rule-editor' => '335fd41f', 'herald-test-css' => '778b008e', 'inline-comment-summary-css' => '8cfd34e8', - 'javelin-aphlict' => '4a07e8e3', + 'javelin-aphlict' => '464d333a', 'javelin-behavior' => '61cbc29a', 'javelin-behavior-aphlict-dropdown' => 'f6bc26f0', - 'javelin-behavior-aphlict-listen' => 'a826c925', + 'javelin-behavior-aphlict-listen' => '1162a152', 'javelin-behavior-aphlict-status' => '58f7803f', 'javelin-behavior-aphront-basic-tokenizer' => 'b3a4b884', 'javelin-behavior-aphront-crop' => 'fa0f4fc2', @@ -909,6 +908,18 @@ 'javelin-uri', 'javelin-install', ), + '1162a152' => array( + 'javelin-behavior', + 'javelin-aphlict', + 'javelin-stratcom', + 'javelin-request', + 'javelin-uri', + 'javelin-dom', + 'javelin-json', + 'javelin-router', + 'javelin-util', + 'phabricator-notification', + ), '13c739ea' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1079,6 +1090,13 @@ 'javelin-behavior', 'javelin-dom', ), + '464d333a' => array( + 'javelin-install', + 'javelin-util', + 'javelin-websocket', + 'javelin-leader', + 'javelin-json', + ), '469c0d9e' => array( 'javelin-behavior', 'javelin-dom', @@ -1100,10 +1118,6 @@ 'javelin-request', 'javelin-util', ), - '4a07e8e3' => array( - 'javelin-install', - 'javelin-util', - ), '4d94d9c3' => array( 'javelin-behavior', 'javelin-stratcom', @@ -1489,18 +1503,6 @@ 'javelin-stratcom', 'javelin-dom', ), - 'a826c925' => array( - 'javelin-behavior', - 'javelin-aphlict', - 'javelin-stratcom', - 'javelin-request', - 'javelin-uri', - 'javelin-dom', - 'javelin-json', - 'javelin-router', - 'javelin-util', - 'phabricator-notification', - ), 'a8d8459d' => array( 'javelin-behavior', 'javelin-dom', @@ -2024,6 +2026,11 @@ 'sprite-tokens-css', 'tokens-css', 'phui-status-list-view-css', + 'phui-feed-story-css', + 'phabricator-feed-css', + 'phabricator-dashboard-css', + 'aphront-multi-column-view-css', + 'phui-action-header-view-css', ), 'core.pkg.js' => array( 'javelin-util', @@ -2093,6 +2100,11 @@ 'javelin-behavior-phabricator-show-older-transactions', 'javelin-behavior-phui-timeline-dropdown-menu', 'javelin-behavior-doorkeeper-tag', + 'phabricator-title', + 'javelin-leader', + 'javelin-websocket', + 'javelin-behavior-dashboard-async-panel', + 'javelin-behavior-dashboard-tab-panel', ), 'darkconsole.pkg.js' => array( 'javelin-behavior-dark-console', diff --git a/resources/celerity/packages.php b/resources/celerity/packages.php --- a/resources/celerity/packages.php +++ b/resources/celerity/packages.php @@ -69,6 +69,11 @@ 'javelin-behavior-phabricator-show-older-transactions', 'javelin-behavior-phui-timeline-dropdown-menu', 'javelin-behavior-doorkeeper-tag', + 'phabricator-title', + 'javelin-leader', + 'javelin-websocket', + 'javelin-behavior-dashboard-async-panel', + 'javelin-behavior-dashboard-tab-panel', ), 'core.pkg.css' => array( 'phabricator-core-css', @@ -126,6 +131,12 @@ 'sprite-tokens-css', 'tokens-css', 'phui-status-list-view-css', + + 'phui-feed-story-css', + 'phabricator-feed-css', + 'phabricator-dashboard-css', + 'aphront-multi-column-view-css', + 'phui-action-header-view-css', ), 'differential.pkg.css' => array( 'differential-core-view-css', diff --git a/src/__phutil_library_map__.php b/src/__phutil_library_map__.php --- a/src/__phutil_library_map__.php +++ b/src/__phutil_library_map__.php @@ -1239,7 +1239,6 @@ 'PhabricatorAlmanacApplication' => 'applications/almanac/application/PhabricatorAlmanacApplication.php', 'PhabricatorAmazonAuthProvider' => 'applications/auth/provider/PhabricatorAmazonAuthProvider.php', 'PhabricatorAnchorView' => 'view/layout/PhabricatorAnchorView.php', - 'PhabricatorAphlictManagementBuildWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementBuildWorkflow.php', 'PhabricatorAphlictManagementDebugWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php', 'PhabricatorAphlictManagementRestartWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementRestartWorkflow.php', 'PhabricatorAphlictManagementStartWorkflow' => 'applications/aphlict/management/PhabricatorAphlictManagementStartWorkflow.php', @@ -4393,7 +4392,6 @@ 'PhabricatorAlmanacApplication' => 'PhabricatorApplication', 'PhabricatorAmazonAuthProvider' => 'PhabricatorOAuth2AuthProvider', 'PhabricatorAnchorView' => 'AphrontView', - 'PhabricatorAphlictManagementBuildWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementDebugWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementRestartWorkflow' => 'PhabricatorAphlictManagementWorkflow', 'PhabricatorAphlictManagementStartWorkflow' => 'PhabricatorAphlictManagementWorkflow', diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementBuildWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementBuildWorkflow.php deleted file mode 100644 --- a/src/applications/aphlict/management/PhabricatorAphlictManagementBuildWorkflow.php +++ /dev/null @@ -1,61 +0,0 @@ -setName('build') - ->setSynopsis(pht('Build the Aphlict client.')) - ->setArguments( - array( - array( - 'name' => 'debug', - 'help' => 'Enable a debug build.', - ), - )); - } - - public function execute(PhutilArgumentParser $args) { - $console = PhutilConsole::getConsole(); - $root = dirname(__FILE__).'/../../../..'; - - if (!Filesystem::binaryExists('mxmlc')) { - throw new PhutilArgumentUsageException( - pht( - "The `mxmlc` binary was not found in PATH. This compiler binary ". - "is required to rebuild the Aphlict client.\n\n". - "Adjust your PATH, or install the Flex SDK from:\n\n". - " http://flex.apache.org\n\n". - "You may also be able to install it with `npm`:\n\n". - " $ npm install flex-sdk\n\n". - "(Note: you should only need to rebuild Aphlict if you are ". - "developing Phabricator.)")); - } - - $argv = array( - "-source-path=$root/externals/vegas/src", - '-static-link-runtime-shared-libraries=true', - '-warnings=true', - '-strict=true', - ); - - if ($args->getArg('debug')) { - $argv[] = '-debug=true'; - } - - list ($err, $stdout, $stderr) = exec_manual('mxmlc %Ls -output=%s %s', - $argv, - $root.'/webroot/rsrc/swf/aphlict.swf', - $root.'/support/aphlict/client/src/AphlictClient.as'); - - if ($err) { - $console->writeErr($stderr); - return 1; - } - - $console->writeOut("Done.\n"); - return 0; - } - -} diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php --- a/src/applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php +++ b/src/applications/aphlict/management/PhabricatorAphlictManagementDebugWorkflow.php @@ -14,7 +14,7 @@ } public function execute(PhutilArgumentParser $args) { - $this->willLaunch(); + $this->willLaunch(true); return $this->launch(true); } diff --git a/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php b/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php --- a/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php +++ b/src/applications/aphlict/management/PhabricatorAphlictManagementWorkflow.php @@ -50,7 +50,7 @@ } } - final protected function willLaunch() { + final protected function willLaunch($debug = false) { $console = PhutilConsole::getConsole(); $pid = $this->getPID(); @@ -61,25 +61,35 @@ 'running. Use `aphlict restart` to restart it.')); } - if (posix_getuid() != 0) { + if (posix_getuid() == 0) { throw new PhutilArgumentUsageException( pht( - 'You must run this script as root; the Aphlict server needs to bind '. - 'to privileged ports.')); + // TODO: Update this message after a while. + 'The notification server should not be run as root. It no '. + 'longer requires access to privileged ports.')); } - // This will throw if we can't find an appropriate `node`. - $this->getNodeBinary(); - } + // Make sure we can write to the PID file. + if (!$debug) { + Filesystem::writeFile($this->getPIDPath(), ''); + } - final protected function launch($debug = false) { - $console = PhutilConsole::getConsole(); + // First, start the server in configuration test mode with --test. This + // will let us error explicitly if there are missing modules, before we + // fork and lose access to the console. + $test_argv = $this->getServerArgv($debug); + $test_argv[] = '--test=true'; - if ($debug) { - $console->writeOut(pht("Starting Aphlict server in foreground...\n")); - } else { - Filesystem::writeFile($this->getPIDPath(), getmypid()); - } + execx( + '%s %s %Ls', + $this->getNodeBinary(), + $this->getAphlictScriptPath(), + $test_argv); + } + + private function getServerArgv($debug) { + $ssl_key = PhabricatorEnv::getEnvConfig('notification.ssl-key'); + $ssl_cert = PhabricatorEnv::getEnvConfig('notification.ssl-cert'); $server_uri = PhabricatorEnv::getEnvConfig('notification.server-uri'); $server_uri = new PhutilURI($server_uri); @@ -87,27 +97,46 @@ $client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri'); $client_uri = new PhutilURI($client_uri); - $user = PhabricatorEnv::getEnvConfig('notification.user'); - $log = PhabricatorEnv::getEnvConfig('notification.log'); + $log = PhabricatorEnv::getEnvConfig('notification.log'); $server_argv = array(); - $server_argv[] = csprintf('--port=%s', $client_uri->getPort()); - $server_argv[] = csprintf('--admin=%s', $server_uri->getPort()); - $server_argv[] = csprintf('--host=%s', $server_uri->getDomain()); + $server_argv[] = '--port='.$client_uri->getPort(); + $server_argv[] = '--admin='.$server_uri->getPort(); + + if ($ssl_key) { + $server_argv[] = '--ssl-key='.$ssl_key; + } - if ($user) { - $server_argv[] = csprintf('--user=%s', $user); + if ($ssl_cert) { + $server_argv[] = '--ssl-cert='.$ssl_cert; } if (!$debug) { - $server_argv[] = csprintf('--log=%s', $log); + $server_argv[] = '--log='.$log; + } + + return $server_argv; + } + + private function getAphlictScriptPath() { + $root = dirname(phutil_get_library_root('phabricator')); + return $root.'/support/aphlict/server/aphlict_server.js'; + } + + final protected function launch($debug = false) { + $console = PhutilConsole::getConsole(); + + if ($debug) { + $console->writeOut(pht("Starting Aphlict server in foreground...\n")); + } else { + Filesystem::writeFile($this->getPIDPath(), getmypid()); } $command = csprintf( - '%s %s %C', + '%s %s %Ls', $this->getNodeBinary(), - dirname(__FILE__).'/../../../../support/aphlict/server/aphlict_server.js', - implode(' ', $server_argv)); + $this->getAphlictScriptPath(), + $this->getServerArgv($debug)); if (!$debug) { declare(ticks = 1); @@ -159,6 +188,7 @@ fclose(STDOUT); fclose(STDERR); + $this->launch(); return 0; } diff --git a/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php b/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php --- a/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php +++ b/src/applications/config/check/PhabricatorExtraConfigSetupCheck.php @@ -194,6 +194,11 @@ 'This option has been renamed to `phabricator.show-prototypes` '. 'to emphasize the unfinished nature of many prototype applications. '. 'Your existing setting has been migrated.'), + 'notification.user' => pht( + 'The notification server no longer requires root permissions. Start '. + 'the server as the user you want it to run under.'), + 'notification.debug' => pht( + 'Notifications no longer have a dedicated debugging mode.'), ); return $ancient_config; diff --git a/src/applications/config/option/PhabricatorNotificationConfigOptions.php b/src/applications/config/option/PhabricatorNotificationConfigOptions.php --- a/src/applications/config/option/PhabricatorNotificationConfigOptions.php +++ b/src/applications/config/option/PhabricatorNotificationConfigOptions.php @@ -36,23 +36,21 @@ 'string', 'http://localhost:22281/') ->setDescription(pht('Location of the notification receiver server.')), - $this->newOption('notification.user', 'string', null) - ->setSummary(pht('Drop permissions to a less-privileged user.')) - ->setDescription( - pht( - 'The notifcation server must be started as root so it can bind '. - 'to privileged ports, but if you specify a system user here it '. - 'will drop permissions to that user after binding to the ports '. - 'it needs.')), $this->newOption('notification.log', 'string', '/var/log/aphlict.log') ->setDescription(pht('Location of the server log file.')), + $this->newOption('notification.ssl-key', 'string', null) + ->setLocked(true) + ->setDescription( + pht('Path to SSL key to use for secure WebSockets.')), + $this->newOption('notification.ssl-cert', 'string', null) + ->setLocked(true) + ->setDescription( + pht('Path to SSL certificate to use for secure WebSockets.')), $this->newOption( 'notification.pidfile', 'string', - '/var/run/aphlict.pid') + '/var/tmp/aphlict/pid/aphlict.pid') ->setDescription(pht('Location of the server PID file.')), - $this->newOption('notification.debug', 'bool', false) - ->setDescription(pht('Enable debug output in the browser.')), ); } diff --git a/src/applications/notification/controller/PhabricatorNotificationTestController.php b/src/applications/notification/controller/PhabricatorNotificationTestController.php --- a/src/applications/notification/controller/PhabricatorNotificationTestController.php +++ b/src/applications/notification/controller/PhabricatorNotificationTestController.php @@ -16,6 +16,11 @@ $viewer_phid = $viewer->getPHID(); + // NOTE: Because we don't currently show you your own notifications, make + // sure this comes from a different PHID. + $application_phid = id(new PhabricatorNotificationsApplication()) + ->getPHID(); + // TODO: When it's easier to get these buttons to render as forms, this // would be slightly nicer as a more standard isFormPost() check. @@ -24,7 +29,7 @@ ->setStoryType($story_type) ->setStoryData($story_data) ->setStoryTime(time()) - ->setStoryAuthorPHID($viewer_phid) + ->setStoryAuthorPHID($application_phid) ->setRelatedPHIDs(array($viewer_phid)) ->setPrimaryObjectPHID($viewer_phid) ->setSubscribedPHIDs(array($viewer_phid)) diff --git a/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php b/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php --- a/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php +++ b/src/applications/notification/setup/PhabricatorAphlictSetupCheck.php @@ -38,7 +38,7 @@ ->addCommand( pht( "(To start the server, run this command.)\n". - "phabricator/ $ sudo ./bin/aphlict start")); + "phabricator/ $ ./bin/aphlict start")); return; } @@ -57,7 +57,7 @@ ->setShortName(pht('Notification Server Version')) ->setName(pht('Notification Server Out of Date')) ->setMessage($message) - ->addCommand('phabricator/ $ sudo ./bin/aphlict restart'); + ->addCommand('phabricator/ $ ./bin/aphlict restart'); } } diff --git a/src/applications/notification/view/PhabricatorNotificationStatusView.php b/src/applications/notification/view/PhabricatorNotificationStatusView.php --- a/src/applications/notification/view/PhabricatorNotificationStatusView.php +++ b/src/applications/notification/view/PhabricatorNotificationStatusView.php @@ -13,18 +13,8 @@ 'nodeID' => $this->getID(), 'pht' => array( 'setup' => pht('Setting Up Client'), - 'start' => pht('Starting Client'), - 'ready' => pht('Ready to Connect'), - 'connecting' => pht('Connecting...'), - 'connected' => pht('Connected'), - 'error' => pht('Connection Error'), - 'client' => pht('Connected Locally'), - - 'error.flash.xdomain' => pht( - 'Unable to connect to Flash Policy Server. Check that the '. - 'notification server is running and port 843 is not firewalled.'), - 'error.flash.disconnected' => pht( - 'Disconnected from notification server.'), + 'open' => pht('Connected'), + 'closed' => pht('Disconnected'), ), )); diff --git a/src/docs/user/configuration/notifications.diviner b/src/docs/user/configuration/notifications.diviner --- a/src/docs/user/configuration/notifications.diviner +++ b/src/docs/user/configuration/notifications.diviner @@ -3,7 +3,8 @@ Guide to setting up notifications. -= Overview = +Overview +======== By default, Phabricator delivers information about events (like users creating tasks or commenting on code reviews) through email and in-application @@ -20,61 +21,95 @@ This document describes the process in detail. -= Running the Aphlict Server = -Phabricator implements realtime notifications using a Node.js server called -"Aphlict". To run it: +Supported Browsers +================== - - Install node.js. - - Run `bin/aphlict start` (this script must be run as root). +Notifications are supported for browsers which support WebSockets. This covers +most modern browsers (like Chrome, Firefox, Safari, and recent versions of +Internet Explorer) and many mobile browsers. -The server must be able to listen on port **843** and port **22280** for Aphlict -to work. You can change the latter port in the `notification.client-uri` config, -but port 843 is used by Flash and can not be changed. In particular, if you're -running in EC2, you need to unblock both of these ports in the server's security -group configuration. +IE8 and IE9 do not support WebSockets, so real-time notifications won't work in +those browsers. -You may want to adjust these settings: + +Installing Node and Modules +=========================== + +The notification server uses Node.js, so you'll need to install it first. + +To install Node.js, follow the instructions on +[[ http://nodejs.org | nodejs.org ]]. + +You will also need to install the `ws` module for Node. After installing +Node, run `npm install -g ws` to install it. + + name="(Option 1, Recommended) Install 'ws' Module Globally" + $ npm install -g ws # Global Install + +If you prefer, you can also install it locally in the `support/aphlict/server/` +directory: + + name="(Option 2) Install 'ws' Module Locally" + phabricator/support/aphlict/server/ $ npm install ws + +Once Node.js and the `ws` module are installed, you're ready to start the +server. + + +Running the Aphlict Server +========================== + +After installing Node.js, you can control the notification server with the +`bin/aphlict` command. To start the server: + + phabricator/ $ bin/aphlict start + +The server must be able to listen on port **22280** for Aphlict to work. In +particular, if you're running in EC2, you need to unblock this port in the +server's security group configuration. You can change this port in the +`notification.client-uri` config. + +You may need to adjust these settings: + + - `notification.ssl-cert` Point this at an SSL certificate for secure + WebSockets. + - `notification.ssl-key` Point this at an SSL keyfile for secure WebSockets. + +In particular, if your server uses HTTPS, you **must** configure these options. +Browsers will not allow you to use non-SSL websockets from an SSL web page. + +You may also want to adjust these settings: - `notification.client-uri` Externally-facing host and port that browsers will connect to in order to listen for notifications. - `notification.server-uri` Internally-facing host and port that Phabricator will connect to in order to publish notifications. - `notification.log` Log file location for the server. - - `notification.user` Non-root user to drop permissions to after binding to - privileged ports. - `notification.pid` Pidfile location used to stop any running server when aphlict is restarted. -In most cases, the defaults are appropriate, except that you should set -`notification.user` to some valid system user so Aphlict isn't running as root. -== Verifying Server Status == +Verifying Server Status +======================= Access `/notification/status/` to verify the server is operational. You should see a table showing stats like "uptime" and connection/message counts if the server is working. If it isn't working, you should see an error. -== Testing the Server == +You can also send a test notification by clicking the button in the upper right +corner of this screen. -The easiest way to test the server is to have two users login and comment on -the same Maniphest Task or Differential Revision. They should receive in-browser -notifications about the other user's activity. -NOTE: This is cumbersome. There will be better testing tools at some point. - -== Debugging Server Problems == +Troubleshooting +=============== You can run `aphlict` in the foreground to get output to your console: - phabricator/ $ sudo ./bin/aphlict debug - -You can run `support/aphlict/client/aphlict_test_client.php` to connect to the -Aphlict server from the command line. Messages the client receives will be -printed to stdout. + phabricator/ $ ./bin/aphlict debug -You can set `notification.debug` in your configuration to get additional -output in your browser. +Because the notification server uses WebSockets, your browser error console +may also have information that is useful in figuring out what's wrong. The server also generates a log, by default in `/var/log/aphlict.log`. You can change this location by changing `notification.log` in your configuration. The diff --git a/src/view/page/PhabricatorStandardPageView.php b/src/view/page/PhabricatorStandardPageView.php --- a/src/view/page/PhabricatorStandardPageView.php +++ b/src/view/page/PhabricatorStandardPageView.php @@ -371,9 +371,6 @@ if (PhabricatorEnv::getEnvConfig('notification.enabled')) { if ($user && $user->isLoggedIn()) { - $aphlict_object_id = celerity_generate_unique_node_id(); - $aphlict_container_id = celerity_generate_unique_node_id(); - $client_uri = PhabricatorEnv::getEnvConfig('notification.client-uri'); $client_uri = new PhutilURI($client_uri); if ($client_uri->getDomain() == 'localhost') { @@ -382,37 +379,24 @@ $client_uri->setDomain($this_host->getDomain()); } - $map = CelerityResourceMap::getNamedInstance('phabricator'); - $swf_uri = $response->getURI($map, 'rsrc/swf/aphlict.swf', true); - - $enable_debug = PhabricatorEnv::getEnvConfig('notification.debug'); - $subscriptions = $this->pageObjects; if ($user) { $subscriptions[] = $user->getPHID(); } + if ($request->isHTTPS()) { + $client_uri->setProtocol('wss'); + } else { + $client_uri->setProtocol('ws'); + } + Javelin::initBehavior( 'aphlict-listen', array( - 'id' => $aphlict_object_id, - 'containerID' => $aphlict_container_id, - 'server' => $client_uri->getDomain(), - 'port' => $client_uri->getPort(), - 'debug' => $enable_debug, - 'swfURI' => $swf_uri, + 'websocketURI' => (string)$client_uri, 'pageObjects' => array_fill_keys($this->pageObjects, true), 'subscriptions' => $subscriptions, )); - - $tail[] = phutil_tag( - 'div', - array( - 'id' => $aphlict_container_id, - 'style' => - 'position: absolute; width: 0; height: 0; overflow: hidden;', - ), - ''); } } diff --git a/support/aphlict/client/aphlict_test_client.php b/support/aphlict/client/aphlict_test_client.php deleted file mode 100755 --- a/support/aphlict/client/aphlict_test_client.php +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env php -setTagline('test client for Aphlict server'); -$args->setSynopsis(<<parseStandardArguments(); -$args->parse( - array( - array( - 'name' => 'server', - 'param' => 'uri', - 'default' => PhabricatorEnv::getEnvConfig('notification.client-uri'), - 'help' => 'Connect to __uri__ instead of the default server.', - ), - )); -$console = PhutilConsole::getConsole(); - -$errno = null; -$errstr = null; - -$uri = $args->getArg('server'); -$uri = new PhutilURI($uri); -$uri->setProtocol('tcp'); - -$console->writeErr("Connecting...\n"); -$socket = stream_socket_client( - $uri, - $errno, - $errstr); - -if (!$socket) { - $console->writeErr( - "Unable to connect to Aphlict (at '$uri'). Error #{$errno}: {$errstr}"); - exit(1); -} else { - $console->writeErr("Connected.\n"); -} - -$io_channel = new PhutilSocketChannel($socket); -$proto_channel = new PhutilJSONProtocolChannel($io_channel); - -$json = new PhutilJSON(); -while (true) { - $message = $proto_channel->waitForMessage(); - $console->writeOut($json->encodeFormatted($message)); -} diff --git a/support/aphlict/client/src/Aphlict.as b/support/aphlict/client/src/Aphlict.as deleted file mode 100644 --- a/support/aphlict/client/src/Aphlict.as +++ /dev/null @@ -1,47 +0,0 @@ -package { - - import flash.display.Sprite; - import flash.external.ExternalInterface; - import flash.net.LocalConnection; - - - public class Aphlict extends Sprite { - - /** - * A transport channel used to receive data. - */ - protected var recv:LocalConnection; - - /** - * A transport channel used to send data. - */ - protected var send:LocalConnection; - - - public function Aphlict() { - super(); - - this.recv = new LocalConnection(); - this.recv.client = this; - - this.send = new LocalConnection(); - } - - final protected function externalInvoke( - type:String, - object:Object = null):void { - - ExternalInterface.call('JX.Aphlict.didReceiveEvent', type, object); - } - - final protected function error(error:Object):void { - this.externalInvoke('error', error.toString()); - } - - final protected function log(message:String):void { - this.externalInvoke('log', message); - } - - } - -} diff --git a/support/aphlict/client/src/AphlictClient.as b/support/aphlict/client/src/AphlictClient.as deleted file mode 100644 --- a/support/aphlict/client/src/AphlictClient.as +++ /dev/null @@ -1,160 +0,0 @@ -package { - - import flash.events.TimerEvent; - import flash.external.ExternalInterface; - import flash.utils.Dictionary; - import flash.utils.Timer; - import flash.events.UncaughtErrorEvent; - - final public class AphlictClient extends Aphlict { - - /** - * The connection name for this client. This will be used for the - * @{class:LocalConnection} object. - */ - private var client:String; - - /** - * The expiry timestamp for the @{class:AphlictMaster}. If this time is - * elapsed then the master will be assumed to be dead and another - * @{class:AphlictClient} will create a master. - */ - private var expiry:Number = 0; - - /** - * The interval at which to ping the @{class:AphlictMaster}. - */ - public static const INTERVAL:Number = 3000; - - private var master:AphlictMaster; - private var timer:Timer; - - private var remoteServer:String; - private var remotePort:Number; - private var subscriptions:Array; - - - public function AphlictClient() { - super(); - - loaderInfo.uncaughtErrorEvents.addEventListener( - UncaughtErrorEvent.UNCAUGHT_ERROR, - this.uncaughtErrorHandler); - - ExternalInterface.marshallExceptions = true; - ExternalInterface.addCallback('connect', this.externalConnect); - - this.setStatus('ready'); - } - - private function uncaughtErrorHandler(event:UncaughtErrorEvent):void { - this.error(event.error.toString()); - } - - public function externalConnect( - server:String, - port:Number, - subscriptions:Array):void { - - this.remoteServer = server; - this.remotePort = port; - this.subscriptions = subscriptions; - - this.client = AphlictClient.generateClientId(); - this.recv.connect(this.client); - - this.timer = new Timer(AphlictClient.INTERVAL); - this.timer.addEventListener(TimerEvent.TIMER, this.keepalive); - - this.connectToMaster(); - } - - /** - * Generate a unique identifier that will be used to communicate with the - * @{class:AphlictMaster}. - */ - private static function generateClientId():String { - return 'aphlict_client_' + Math.round(Math.random() * 100000); - } - - /** - * Create a new connection to the @{class:AphlictMaster}. - * - * If there is no current @{class:AphlictMaster} instance, then a new master - * will be created. - */ - private function connectToMaster():void { - this.timer.stop(); - - // Try to become the master. - try { - this.log('Attempting to become the master...'); - this.master = new AphlictMaster(this.remoteServer, this.remotePort); - this.log('I am the master.'); - } catch (err:ArgumentError) { - this.log('Cannot become the master... probably one already exists'); - } catch (err:Error) { - this.error(err); - } - - this.registerWithMaster(); - this.timer.start(); - } - - /** - * Register our client ID with the @{class:AphlictMaster} and send our - * subscriptions. - */ - private function registerWithMaster():void { - this.send.send('aphlict_master', 'register', this.client); - this.expiry = new Date().getTime() + (5 * AphlictClient.INTERVAL); - this.log('Registered client ' + this.client); - - // Send subscriptions to master. - this.log('Sending subscriptions to master.'); - this.send.send( - 'aphlict_master', - 'subscribe', - this.client, - this.subscriptions); - } - - /** - * Send a keepalive signal to the @{class:AphlictMaster}. - * - * If the connection to the master has expired (because the master has not - * sent a heartbeat signal), then a new connection to master will be - * created. - */ - private function keepalive(event:TimerEvent):void { - if (new Date().getTime() > this.expiry) { - this.connectToMaster(); - } - - this.send.send('aphlict_master', 'ping', this.client); - } - - /** - * This function is used to receive the heartbeat signal from the - * @{class:AphlictMaster}. - */ - public function pong():void { - this.expiry = new Date().getTime() + (2 * AphlictClient.INTERVAL); - } - - /** - * Receive a message from the Aphlict Server, via the - * @{class:AphlictMaster}. - */ - public function receiveMessage(msg:Object):void { - this.log('Received message.'); - this.externalInvoke('receive', msg); - } - - public function setStatus(status:String, code:String = null):void { - this.externalInvoke('status', {type: status, code: code}); - } - - } - -} diff --git a/support/aphlict/client/src/AphlictMaster.as b/support/aphlict/client/src/AphlictMaster.as deleted file mode 100644 --- a/support/aphlict/client/src/AphlictMaster.as +++ /dev/null @@ -1,312 +0,0 @@ -package { - - import flash.events.Event; - import flash.events.IOErrorEvent; - import flash.events.ProgressEvent; - import flash.events.SecurityErrorEvent; - import flash.events.TimerEvent; - import flash.net.Socket; - import flash.utils.ByteArray; - import flash.utils.Dictionary; - import flash.utils.Timer; - import vegas.strings.JSON; - - - final public class AphlictMaster extends Aphlict { - - /** - * The pool of connected clients. - */ - private var clients:Dictionary; - - /** - * A timer used to trigger periodic events. - */ - private var timer:Timer; - - /** - * The interval after which clients will be considered dead and removed - * from the pool. - */ - public static const PURGE_INTERVAL:Number = 3 * AphlictClient.INTERVAL; - - /** - * The hostname for the Aphlict Server. - */ - private var remoteServer:String; - - /** - * The port number for the Aphlict Server. - */ - private var remotePort:Number; - - /** - * A dictionary mapping PHID to subscribed clients. - */ - private var subscriptions:Dictionary; - - private var socket:Socket; - private var readBuffer:ByteArray; - - private var status:String; - private var statusCode:String; - - - public function AphlictMaster(server:String, port:Number) { - super(); - - this.remoteServer = server; - this.remotePort = port; - - this.clients = new Dictionary(); - this.subscriptions = new Dictionary(); - - // Connect to the Aphlict Server. - this.recv.connect('aphlict_master'); - this.connectToServer(); - - // Start a timer and regularly purge dead clients. - this.timer = new Timer(AphlictMaster.PURGE_INTERVAL); - this.timer.addEventListener(TimerEvent.TIMER, this.purgeClients); - this.timer.start(); - } - - /** - * Register a @{class:AphlictClient}. - */ - public function register(client:String):void { - if (!this.clients[client]) { - this.log('Registering client: ' + client); - this.clients[client] = new Date().getTime(); - - this.send.send(client, 'setStatus', this.status, this.statusCode); - } - } - - /** - * Purge stale client connections from the client pool. - */ - private function purgeClients(event:TimerEvent):void { - for (var client:String in this.clients) { - var checkin:Number = this.clients[client]; - - if (new Date().getTime() - checkin > AphlictMaster.PURGE_INTERVAL) { - this.log('Purging client: ' + client); - delete this.clients[client]; - - this.log('Removing client subscriptions: ' + client); - this.unsubscribeAll(client); - } - } - } - - /** - * Clients will regularly "ping" the master to let us know that they are - * still alive. We will "pong" them back to let the client know that the - * master is still alive. - */ - public function ping(client:String):void { - this.clients[client] = new Date().getTime(); - this.send.send(client, 'pong'); - } - - private function connectToServer():void { - this.setStatusOnClients('connecting'); - - var socket:Socket = new Socket(); - - socket.addEventListener(Event.CONNECT, didConnectSocket); - socket.addEventListener(Event.CLOSE, didCloseSocket); - socket.addEventListener(ProgressEvent.SOCKET_DATA, didReceiveSocket); - - socket.addEventListener(IOErrorEvent.IO_ERROR, didIOErrorSocket); - socket.addEventListener( - SecurityErrorEvent.SECURITY_ERROR, - didSecurityErrorSocket); - - socket.connect(this.remoteServer, this.remotePort); - - this.readBuffer = new ByteArray(); - this.socket = socket; - } - - private function didConnectSocket(event:Event):void { - this.setStatusOnClients('connected'); - - // Send subscriptions - var phids = new Array(); - for (var phid:String in this.subscriptions) { - phids.push(phid); - } - - if (phids.length) { - this.sendSubscribeCommand(phids); - } - } - - private function didCloseSocket(event:Event):void { - this.setStatusOnClients('error', 'error.flash.disconnected'); - } - - private function didIOErrorSocket(event:IOErrorEvent):void { - this.externalInvoke('error', event.text); - } - - private function didSecurityErrorSocket(event:SecurityErrorEvent):void { - var text = event.text; - - // This is really gross but there doesn't seem to be anything else - // on the object which gives us an error code. - if (text.match(/^Error #2048/)) { - this.setStatusOnClients('error', 'error.flash.xdomain'); - } - - this.error(text); - } - - public function subscribe(client:String, phids:Array):void { - var newPHIDs = new Array(); - - for (var i:String in phids) { - var phid = phids[i]; - if (!this.subscriptions[phid]) { - this.subscriptions[phid] = new Dictionary(); - newPHIDs.push(phid); - } - this.subscriptions[phid][client] = true; - } - - if (newPHIDs.length) { - this.sendSubscribeCommand(newPHIDs); - } - } - - private function getSubscriptions(client:String):Array { - var subscriptions = new Array(); - - for (var phid:String in this.subscriptions) { - var clients = this.subscriptions[phid]; - if (clients[client]) { - subscriptions.push(phid); - } - } - - return subscriptions; - } - - public function unsubscribeAll(client:String):void { - this.unsubscribe(client, this.getSubscriptions(client)); - } - - public function unsubscribe(client:String, phids:Array):void { - var oldPHIDs = new Array(); - - for (var i:String in phids) { - var phid = phids[i]; - - if (!this.subscriptions[phid]) { - continue; - } - - delete this.subscriptions[phid][client]; - - var empty = true; - for (var key:String in this.subscriptions[phid]) { - empty = false; - } - - if (empty) { - delete this.subscriptions[phid]; - oldPHIDs.push(phid); - } - } - - if (oldPHIDs.length) { - this.sendUnsubscribeCommand(oldPHIDs); - } - } - - private function sendSubscribeCommand(phids:Array):void { - var msg:Dictionary = new Dictionary(); - msg['command'] = 'subscribe'; - msg['data'] = phids; - - this.log('Sending subscribe command to server.'); - this.socket.writeUTF(vegas.strings.JSON.serialize(msg)); - this.socket.flush(); - } - - private function sendUnsubscribeCommand(phids:Array):void { - var msg:Dictionary = new Dictionary(); - msg['command'] = 'unsubscribe'; - msg['data'] = phids; - - this.log('Sending subscribe command to server.'); - this.socket.writeUTF(vegas.strings.JSON.serialize(msg)); - this.socket.flush(); - } - - private function didReceiveSocket(event:Event):void { - try { - var b:ByteArray = this.readBuffer; - this.socket.readBytes(b, b.length); - - do { - b = this.readBuffer; - b.position = 0; - - if (b.length <= 8) { - break; - } - - var msg_len:Number = parseInt(b.readUTFBytes(8), 10); - if (b.length >= msg_len + 8) { - var bytes:String = b.readUTFBytes(msg_len); - var data:Object = vegas.strings.JSON.deserialize(bytes); - var t:ByteArray = new ByteArray(); - t.writeBytes(b, msg_len + 8); - this.readBuffer = t; - - // Send the message to all clients. - for (var client:String in this.clients) { - var subscribed = false; - - for (var i:String in data.subscribers) { - var phid = data.subscribers[i]; - - if (this.subscriptions[phid] && - this.subscriptions[phid][client]) { - subscribed = true; - break; - } - } - - if (subscribed) { - this.log('Sending message to client: ' + client); - this.send.send(client, 'receiveMessage', data); - } - } - } else { - break; - } - } while (true); - } catch (err:Error) { - this.error(err); - } - } - - private function setStatusOnClients( - status:String, - code:String = null):void { - - this.status = status; - this.statusCode = code; - - for (var client:String in this.clients) { - this.send.send(client, 'setStatus', status, code); - } - } - - } - -} diff --git a/support/aphlict/server/aphlict_server.js b/support/aphlict/server/aphlict_server.js --- a/support/aphlict/server/aphlict_server.js +++ b/support/aphlict/server/aphlict_server.js @@ -1,14 +1,9 @@ -/** - * Notification server. Launch with: - * - * sudo node aphlict_server.js --user=aphlict - * - * You can also specify `port`, `admin`, `host` and `log`. - */ - var JX = require('./lib/javelin').JX; +var http = require('http'); +var https = require('https'); +var util = require('util'); +var fs = require('fs'); -JX.require('lib/AphlictFlashPolicyServer', __dirname); JX.require('lib/AphlictListenerList', __dirname); JX.require('lib/AphlictLog', __dirname); @@ -17,8 +12,10 @@ port: 22280, admin: 22281, host: '127.0.0.1', - user: null, - log: '/var/log/aphlict.log' + log: '/var/log/aphlict.log', + 'ssl-key': null, + 'ssl-certificate': null, + test: false }; for (var ii = 2; ii < argv.length; ii++) { @@ -42,124 +39,120 @@ var debug = new JX.AphlictLog() .addConsole(console); -var clients = new JX.AphlictListenerList(); - var config = parse_command_line_arguments(process.argv); +process.on('uncaughtException', function(err) { + debug.log('\n<<< UNCAUGHT EXCEPTION! >>>\n' + err.stack); + process.exit(1); +}); + +var WebSocket; +try { + WebSocket = require('ws'); +} catch (ex) { + throw new Error( + 'You need to install the Node.js "ws" module for websocket support. ' + + 'Usually, you can do this with `npm install -g ws`. ' + ex.toString()); +} + +var ssl_config = { + enabled: (config['ssl-key'] || config['ssl-cert']) +}; + +// Load the SSL certificates (if any were provided) now, so that runs with +// `--test` will see any errors. +if (ssl_config.enabled) { + ssl_config.key = fs.readFileSync(config['ssl-key']); + ssl_config.cert = fs.readFileSync(config['ssl-cert']); +} + +// Add the logfile so we'll fail if we can't write to it. if (config.logfile) { debug.addLogfile(config.logfile); } -if (process.getuid() !== 0) { - console.log( - "ERROR: " + - "This server must be run as root because it needs to bind to privileged " + - "port 843 to start a Flash policy server. It will downgrade to run as a " + - "less-privileged user after binding if you pass a user in the command " + - "line arguments with '--user=alincoln'."); - process.exit(1); +// If we're just doing a configuration test, exit here before starting any +// servers. +if (config.test) { + debug.log('Configuration test OK.'); + process.exit(0); } -var net = require('net'); -var http = require('http'); +var start_time = new Date().getTime(); +var messages_out = 0; +var messages_in = 0; -process.on('uncaughtException', function(err) { - debug.log('\n<<< UNCAUGHT EXCEPTION! >>>\n' + err.stack); +var clients = new JX.AphlictListenerList(); - process.exit(1); -}); +function https_discard_handler(req, res) { + res.writeHead(501); + res.end('HTTP/501 Use Websockets\n'); +} -new JX.AphlictFlashPolicyServer() - .setDebugLog(debug) - .setAccessPort(config.port) - .start(); - - -net.createServer(function(socket) { - var listener = clients.addListener(socket); - - debug.log('<%s> Connected from %s', - listener.getDescription(), - socket.remoteAddress); - - var buffer = new Buffer([]); - var length = 0; - - socket.on('data', function(data) { - buffer = Buffer.concat([buffer, new Buffer(data)]); - - while (buffer.length) { - if (!length) { - length = buffer.readUInt16BE(0); - buffer = buffer.slice(2); - } - - if (buffer.length < length) { - // We need to wait for the rest of the data. - return; - } - - var message; - try { - message = JSON.parse(buffer.toString('utf8', 0, length)); - } catch (err) { - debug.log('<%s> Received invalid data.', listener.getDescription()); - continue; - } finally { - buffer = buffer.slice(length); - length = 0; - } - - debug.log('<%s> Received data: %s', - listener.getDescription(), - JSON.stringify(message)); - - switch (message.command) { - case 'subscribe': - debug.log( - '<%s> Subscribed to: %s', - listener.getDescription(), - JSON.stringify(message.data)); - listener.subscribe(message.data); - break; +var ws; +if (ssl_config.enabled) { + var https_server = https.createServer({ + key: ssl_config.key, + cert: ssl_config.cert + }, https_discard_handler).listen(config.port); - case 'unsubscribe': - debug.log( - '<%s> Unsubscribed from: %s', - listener.getDescription(), - JSON.stringify(message.data)); - listener.unsubscribe(message.data); - break; - - default: - debug.log(' Unrecognized command.', listener.getDescription()); - } - } - }); + ws = new WebSocket.Server({server: https_server}); +} else { + ws = new WebSocket.Server({port: config.port}); +} - socket.on('close', function() { - clients.removeListener(listener); - debug.log('<%s> Disconnected', listener.getDescription()); - }); +ws.on('connection', function(ws) { + var listener = clients.addListener(ws); - socket.on('timeout', function() { - debug.log('<%s> Timed Out', listener.getDescription()); - }); + function log() { + debug.log( + util.format('<%s>', listener.getDescription()) + + ' ' + + util.format.apply(null, arguments)); + } - socket.on('end', function() { - debug.log('<%s> Ended Connection', listener.getDescription()); - }); + log('Connected from %s.', ws._socket.remoteAddress); - socket.on('error', function(e) { - debug.log('<%s> Error: %s', listener.getDescription(), e); - }); + ws.on('message', function(data) { + log('Received message: %s', data); -}).listen(config.port); + var message; + try { + message = JSON.parse(data); + } catch (err) { + log('Message is invalid: %s', err.message); + return; + } + switch (message.command) { + case 'subscribe': + log( + 'Subscribed to: %s', + JSON.stringify(message.data)); + listener.subscribe(message.data); + break; + + case 'unsubscribe': + log( + 'Unsubscribed from: %s', + JSON.stringify(message.data)); + listener.unsubscribe(message.data); + break; + + default: + log('Unrecognized command "%s".', message.command || ''); + } + }); -var messages_out = 0; -var messages_in = 0; -var start_time = new Date().getTime(); + ws.on('close', function() { + clients.removeListener(listener); + log('Disconnected.'); + }); + + ws.on('error', function(err) { + log('Error: %s', err.message); + }); +}); function transmit(msg) { var listeners = clients.getListeners().filter(function(client) { @@ -195,7 +188,7 @@ try { var msg = JSON.parse(body); - debug.log('notification: ' + JSON.stringify(msg)); + debug.log('Received notification: ' + JSON.stringify(msg)); ++messages_in; try { @@ -242,10 +235,4 @@ } }).listen(config.admin, config.host); -// If we're configured to drop permissions, get rid of them now that we've -// bound to the ports we need and opened logfiles. -if (config.user) { - process.setuid(config.user); -} - debug.log('Started Server (PID %d)', process.pid); diff --git a/support/aphlict/server/lib/AphlictFlashPolicyServer.js b/support/aphlict/server/lib/AphlictFlashPolicyServer.js deleted file mode 100644 --- a/support/aphlict/server/lib/AphlictFlashPolicyServer.js +++ /dev/null @@ -1,68 +0,0 @@ -var JX = require('javelin').JX; - -var net = require('net'); - -/** - * Server which handles cross-domain policy requests for Flash. - * - * var server = new AphlictFlashPolicyServer() - * .setAccessPort(9999) - * .start(); - */ -JX.install('AphlictFlashPolicyServer', { - - members: { - _server: null, - _port: 843, - _accessPort: null, - _debug: null, - - setDebugLog: function(log) { - this._debug = log; - return this; - }, - - setAccessPort: function(port) { - this._accessPort = port; - return this; - }, - - start: function() { - this._server = net.createServer(JX.bind(this, this._didConnect)); - this._server.listen(this._port); - return this; - }, - - _didConnect: function(socket) { - this._log(' Policy Request From %s', socket.remoteAddress); - - socket.on('error', JX.bind(this, this._didSocketError, socket)); - - socket.write(this._getFlashPolicyResponse()); - socket.end(); - }, - - _didSocketError: function(socket, error) { - this._log(' Socket Error: %s', error); - }, - - _log: function() { - this._debug && this._debug.log.apply(this._debug, arguments); - }, - - _getFlashPolicyResponse: function() { - var policy = [ - '', - '', - '', - '', - '' - ]; - - return policy.join('\n') + '\0'; - } - - } - -}); diff --git a/support/aphlict/server/lib/AphlictListener.js b/support/aphlict/server/lib/AphlictListener.js --- a/support/aphlict/server/lib/AphlictListener.js +++ b/support/aphlict/server/lib/AphlictListener.js @@ -49,15 +49,7 @@ }, writeMessage: function(message) { - var serial = JSON.stringify(message); - - var length = Buffer.byteLength(serial, 'utf8'); - length = length.toString(); - while (length.length < 8) { - length = '0' + length; - } - - this._socket.write(length + serial); + this._socket.send(JSON.stringify(message)); } } diff --git a/webroot/rsrc/js/application/aphlict/Aphlict.js b/webroot/rsrc/js/application/aphlict/Aphlict.js --- a/webroot/rsrc/js/application/aphlict/Aphlict.js +++ b/webroot/rsrc/js/application/aphlict/Aphlict.js @@ -2,39 +2,31 @@ * @provides javelin-aphlict * @requires javelin-install * javelin-util + * javelin-websocket + * javelin-leader + * javelin-json */ /** - * Simple JS API for the Flash Aphlict client. Example usage: + * Client for the notification server. Example usage: * - * var aphlict = new JX.Aphlict('aphlict_swf', '127.0.0.1', 22280) - * .setHandler(function(type, message) { - * JX.log("Got " + type + " event!") + * var aphlict = new JX.Aphlict('ws://localhost:22280', subscriptions) + * .setHandler(function(message) { + * // ... * }) * .start(); * - * Your handler will receive these events: - * - * - `connect` The client initiated a connection to the server. - * - `connected` The client completed a connection to the server. - * - `close` The client disconnected from the server. - * - `error` There was an error. - * - `receive` Received a message from the server. - * - * You do not have to handle any of them in any specific way. */ JX.install('Aphlict', { - construct: function(id, server, port, subscriptions) { + construct: function(uri, subscriptions) { if (__DEV__) { if (JX.Aphlict._instance) { JX.$E('Aphlict object is a singleton.'); } } - this._id = id; - this._server = server; - this._port = port; + this._uri = uri; this._subscriptions = subscriptions; this._setStatus('setup'); @@ -44,7 +36,6 @@ events: ['didChangeStatus'], members: { - _id: null, _server: null, _port: null, _subscriptions: null, @@ -52,47 +43,92 @@ _statusCode: null, start: function(node, uri) { - this._setStatus('start'); - - // NOTE: This is grotesque, but seems to work everywhere. - node.innerHTML = - '' + - '' + - '' + - '' + - '' + - '' + - ''; + JX.Leader.listen('onBecomeLeader', JX.bind(this, this._lead)); + JX.Leader.listen('onReceiveBroadcast', JX.bind(this, this._receive)); + JX.Leader.start(); + + JX.Leader.call(JX.bind(this, this._begin)); + }, + + getStatus: function() { + return this._status; }, - _didStartFlash: function() { - var id = this._id; + _begin: function() { + JX.Leader.broadcast( + null, + {type: 'aphlict.getstatus'}); + JX.Leader.broadcast( + null, + {type: 'aphlict.subscribe', data: this._subscriptions}); + }, + + _lead: function() { + var socket = new JX.WebSocket(this._uri); + socket.setOpenHandler(JX.bind(this, this._open)); + socket.setMessageHandler(JX.bind(this, this._message)); + socket.setCloseHandler(JX.bind(this, this._close)); - // Flash puts its "objects" into global scope in an inconsistent way, - // because it was written in like 1816 when globals were awesome and IE4 - // didn't support other scopes since global scope is the best anyway. - var container = document[id] || window[id]; + this._socket = socket; - this._flashContainer = container; - this._flashContainer.connect( - this._server, - this._port, - this._subscriptions); + socket.open(); }, - getStatus: function() { - return this._status; + _open: function() { + this._broadcastStatus('open'); + JX.Leader.broadcast(null, {type: 'aphlict.getsubscribers'}); + }, + + _close: function() { + this._broadcastStatus('closed'); + }, + + _broadcastStatus: function(status) { + JX.Leader.broadcast(null, {type: 'aphlict.status', data: status}); + }, + + _message: function(raw) { + var message = JX.JSON.parse(raw); + JX.Leader.broadcast(null, {type: 'aphlict.server', data: message}); }, - getStatusCode: function() { - return this._statusCode; + _receive: function(message, is_leader) { + switch (message.type) { + case 'aphlict.status': + this._setStatus(message.data); + break; + case 'aphlict.getstatus': + if (is_leader) { + this._broadcastStatus(this.getStatus()); + } + break; + case 'aphlict.getsubscribers': + JX.Leader.broadcast( + null, + {type: 'aphlict.subscribe', data: this._subscriptions}); + break; + case 'aphlict.subscribe': + if (is_leader) { + this._write({ + command: 'subscribe', + data: message.data + }); + } + break; + case 'aphlict.server': + var handler = this.getHandler(); + handler && handler(message.data); + break; + } }, - _setStatus: function(status, code) { + _setStatus: function(status) { this._status = status; - this._statusCode = code || null; this.invoke('didChangeStatus'); + }, + + _write: function(message) { + this._socket.send(JX.JSON.stringify(message)); } }, @@ -110,28 +146,8 @@ return null; } return self._instance; - }, - - didReceiveEvent: function(type, message) { - var client = JX.Aphlict.getInstance(); - if (!client) { - return; - } - - if (type == 'status') { - client._setStatus(message.type, message.code); - switch (message.type) { - case 'ready': - client._didStartFlash(); - break; - } - } - - var handler = client.getHandler(); - if (handler) { - handler(type, message); - } } + } }); diff --git a/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js b/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js --- a/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js +++ b/webroot/rsrc/js/application/aphlict/behavior-aphlict-listen.js @@ -41,22 +41,8 @@ // Respond to a notification from the Aphlict notification server. We send // a request to Phabricator to get notification details. - function onaphlictmessage(type, message) { - switch (type) { - case 'receive': - JX.Stratcom.invoke('aphlict-receive-message', null, message); - break; - - default: - case 'error': - case 'log': - case 'status': - if (config.debug) { - var details = message ? JX.JSON.stringify(message) : ''; - JX.log('(Aphlict) [' + type + '] ' + details); - } - break; - } + function onaphlictmessage(message) { + JX.Stratcom.invoke('aphlict-receive-message', null, message); } @@ -89,13 +75,11 @@ } var client = new JX.Aphlict( - config.id, - config.server, - config.port, + config.websocketURI, config.subscriptions); client .setHandler(onaphlictmessage) - .start(JX.$(config.containerID), config.swfURI); + .start(); }); diff --git a/webroot/rsrc/swf/aphlict.swf b/webroot/rsrc/swf/aphlict.swf deleted file mode 100644 index 0000000000000000000000000000000000000000..0000000000000000000000000000000000000000 GIT binary patch literal 0 Hc$@