kopia lustrzana https://github.com/c9/core
Merge remote-tracking branch 'origin/master' into ide-preview-sessions
commit
c4eea5501b
|
@ -0,0 +1,564 @@
|
|||
CLOUD9 ONPREM LICENSE AGREEMENT
|
||||
|
||||
|
||||
For parties who have entered a separate commercial agreement with Cloud9 to use
|
||||
the Cloud9 SDK for commercial purposes, the following license shall apply.
|
||||
|
||||
|
||||
Congratulations! You’re on your way to a better coding experience.
|
||||
Cloud9 IDE, Inc.'s ("Cloud9", "we", or "us") Cloud9 OnPrem software helps you
|
||||
build software faster and more efficiently by enabling distributed collaborative
|
||||
development for teams. Before you download and/or use our Cloud9 OnPrem software,
|
||||
we need you to agree to a special set of terms. Welcome to the Software License
|
||||
Agreement (the "Agreement").
|
||||
|
||||
PLEASE READ THIS AGREEMENT CAREFULLY BEFORE INSTALLING OR USING THE SOFTWARE.
|
||||
THESE TERMS AND CONDITIONS GOVERN YOUR USE OF THE SOFTWARE (AS DEFINED BELOW),
|
||||
UNLESS WE HAVE EXECUTED A SEPARATE WRITTEN AGREEMENT WITH YOU FOR THAT PURPOSE.
|
||||
WE'RE ONLY WILLING TO LICENSE THE SOFTWARE TO YOU IF YOU ACCEPT ALL THE TERMS
|
||||
AND CONDITIONS OF THIS AGREEMENT. BY INSTALLING OR USING THE SOFTWARE OR BY
|
||||
CLICKING "I ACCEPT" BELOW, YOU ARE CONFIRMING THAT YOU UNDERSTAND THIS
|
||||
AGREEMENT, AND THAT YOU ACCEPT ALL OF ITS TERMS AND CONDITIONS. IF YOU ARE
|
||||
ENTERING INTO THIS AGREEMENT ON BEHALF OF A COMPANY OR OTHER LEGAL ENTITY, YOU
|
||||
REPRESENT THAT YOU HAVE THE LEGAL AUTHORITY TO BIND THE ENTITY TO THIS
|
||||
AGREEMENT, IN WHICH CASE "YOU" WILL MEAN THE ENTITY YOU REPRESENT. IF YOU DON'T
|
||||
HAVE SUCH AUTHORITY, OR IF YOU DON'T ACCEPT ALL THE TERMS AND CONDITIONS OF THIS
|
||||
AGREEMENT, THEN WE ARE UNWILLING TO LICENSE THE SOFTWARE TO YOU, AND YOU MAY NOT
|
||||
DOWNLOAD, INSTALL, OR USE IT.
|
||||
|
||||
1.Definitions.
|
||||
Here are some definitions we use in this Agreement. If you see a capitalized
|
||||
word that isn't listed here, it will be defined somewhere in the Agreement.
|
||||
|
||||
The "Agreement Effective Date" is the earlier of the date that you either click
|
||||
"I Accept" to the terms and conditions of this Agreement, or that you first
|
||||
place an order for Software or Services.
|
||||
|
||||
“Cloud9 SDK” is an Application Programming Interface defined to give users the
|
||||
ability to extend the Cloud9 OnPrem software or integrate it with other systems.
|
||||
|
||||
“Derivative Works” refer to any software created using any of the Cloud9 OnPrem
|
||||
source code.
|
||||
|
||||
"Documentation" means any manuals, documentation and other supporting materials
|
||||
related to the Software that we generally provide to our customers.
|
||||
Documentation is considered part of the Software.
|
||||
|
||||
"Fees" means both: (i) the fees you're required to pay us to use the Software
|
||||
during the applicable License Term, as such fees are reflected on each
|
||||
applicable Order Form; and (ii) the fees you're required to pay us for any
|
||||
Services you engage us to perform, as such fees are reflected on each applicable
|
||||
SOW.
|
||||
|
||||
"License Key" means a data file utilized by the Software's access control
|
||||
mechanism that allows you to use the Software during the License Term.
|
||||
|
||||
"License Term" means one (1) year from the applicable Order Effective Date.
|
||||
The "Order Form" is a written or electronic form that we'll give you to order
|
||||
Software (or that we'll use to order Software on your behalf, once we've gotten
|
||||
your authorization). Upon execution by the parties (or, in the case of an
|
||||
electronic orders, confirmation and placement of the order), each Order Form
|
||||
will be subject to the terms and conditions of this Agreement.
|
||||
The "Order Effective Date" is the effective date of each Order Form.
|
||||
|
||||
“Plugins” refer to any software created to interact with the Cloud9 OnPrem
|
||||
software using the Cloud9 SDK.
|
||||
|
||||
"Seats" mean the number of User accounts for the Software that you're authorized
|
||||
to create. The number of Seats is specified in the applicable Order Form. Only
|
||||
one User can use a Seat at a time. Multiple Users aren't allowed to use the same
|
||||
Seat.
|
||||
|
||||
"Services" means training, consulting, or implementation services that we
|
||||
provide to you pursuant to a mutually executed Statement of Work. Services do
|
||||
not include support.
|
||||
|
||||
"Software" means the object-code/obfuscated source code, actual source code or
|
||||
Derivative Works version of our proprietary Cloud9 OnPrem software application.
|
||||
Software includes any applicable Documentation, as well as any Updates to the
|
||||
Software that we provide you or that you can access under this Agreement.
|
||||
"Statement of Work" or "SOW" means a mutually executed statement of work
|
||||
detailing the Services we'll perform for you, their price, and your related
|
||||
obligations (if any).
|
||||
|
||||
An "Update" is a Software release that we make generally available to our
|
||||
customers, along with any corresponding changes to Documentation. An Update may
|
||||
be an error correction or bug fix, generally indicated by a change in the digit
|
||||
to the right of the second decimal point (e.g., a change from version x.x.x to
|
||||
x.x.y); or it may be an enhancement, new feature, or new functionality,
|
||||
generally indicated by a change in the digit to the right of the first decimal
|
||||
point (e.g., x.x.x to x.y.x) or to the left of the first decimal point
|
||||
(e.g., x.x.x to y.x.x).
|
||||
|
||||
A "User" is a single person or machine account that initiates the execution of
|
||||
the Software and/or interacts with or directs the Software in the performance of
|
||||
its functions. The number of Users shouldn't exceed the number of Seats you've
|
||||
licensed from us.
|
||||
|
||||
2.License Grant.
|
||||
|
||||
Subject to your compliance with the terms of this Agreement (including, among
|
||||
other things, paying the Fees you owe us), we hereby grant you a non-exclusive,
|
||||
non-transferable, worldwide, royalty-free, limited-term license to install,
|
||||
execute, and use the Software for your internal business purposes during the
|
||||
applicable License Term, in accordance with the Documentation, and only for the
|
||||
number of Seats that you've paid for. You can make copies of the Software for
|
||||
non-production purposes only, provided that you reproduce all copyright and
|
||||
other proprietary notices that are on the original copy of the Software.
|
||||
|
||||
Your agents and contractors can use the Software too, so long as they're using
|
||||
it on your behalf, and provided that you agree to be fully responsible for their
|
||||
behavior under this Agreement.
|
||||
|
||||
3.Restrictions.
|
||||
We license the Software to you – we don't sell it. As between us, we own all
|
||||
right, title and interest in and to the Software, and any intellectual property
|
||||
rights associated with it and with our company. We reserve all rights in and to
|
||||
the Software that we don't expressly grant you in this Agreement. You agree not
|
||||
to, nor permit nor authorize any third party to: (i) sublicense, sell, rent,
|
||||
lease, transfer, assign, or distribute the Software to third parties; (ii) host
|
||||
the Software for the benefit of third parties; (iii) disclose or permit any
|
||||
third party to access the Software, except as expressly permitted in Section 2,
|
||||
above; (iv) hack or modify the License Key, or try to avoid or change any
|
||||
license registration process we may implement; (v) modify or create derivative
|
||||
works of the Software, or merge the Software with other software; (vi)
|
||||
disassemble, decompile, bypass any code obfuscation, or otherwise reverse
|
||||
engineer the Software or attempt to derive any of its source code, in whole or
|
||||
in part, except to the extent such activities are expressly permitted by law or
|
||||
applicable license notwithstanding this prohibition; (vii) modify, obscure, or
|
||||
delete any proprietary rights notices included in or on the Software or
|
||||
Documentation; (viii) otherwise use or copy the Software in a manner not
|
||||
expressly permitted by this Agreement; or (ix) use any Software that we license
|
||||
to you beyond its applicable License Term.
|
||||
|
||||
4.Seats.
|
||||
Remember, only one User can use a Seat at a time. Multiple Users aren't allowed
|
||||
to use the same Seat, and only one human being can be associated with a
|
||||
particular User account. If you want to swap out, delete, or suspend a User, you
|
||||
can do that, and then assign a new User to the open Seat. If you find that you
|
||||
need more Seats, that's great – we're here to help! Just submit a new request
|
||||
through our website or via our sales team, and pay for the additional Seats
|
||||
(a new Order Form will be generated). If and when you add additional Seats to
|
||||
your subscription, you'll pay Fees for those seats at the then-current price,
|
||||
prorated for the balance of the applicable License Term. When the time comes to
|
||||
renew your Seats for another year-long License Term, we'll invoice you for all
|
||||
of your Seats at once, at the then-current price (we reserve the right to change
|
||||
our prices at any time, but the new prices won't affect you until it's time to
|
||||
renew your license for another year). You agree that any orders that you make
|
||||
(or that you authorize us to make on your behalf) for additional Seats during
|
||||
the term of this Agreement will be governed by this Agreement.
|
||||
|
||||
5.Verification.
|
||||
From time to time, we may have reason to make sure that you're not using extra
|
||||
Seats without paying for them. You agree to cooperate with us to achieve that
|
||||
goal. To help us verify the number of Seats you're actually using, you agree to
|
||||
promptly give us any usage files and reports that your instance of the Software
|
||||
generates, if and when we ask for them. We might also (or instead) ask one of
|
||||
your officers to certify the number of Seats that you're actually using. You
|
||||
agree to provide such a certification if we ask for it. If we determine that
|
||||
you're using more Seats than you've paid for, in addition to any other remedies
|
||||
we might have at law or in equity, you agree to pay us the then-current Fees for
|
||||
the additional Seats you're using, starting from the date you began using each
|
||||
Seat.
|
||||
|
||||
6.Government Users.
|
||||
No technical data or computer software is developed under this Agreement. The
|
||||
Software and Documentation have been developed solely with private funds, and
|
||||
are considered "Commercial Computer Software" and "Commercial Computer Software
|
||||
Documentation" as described in FAR 12.212, FAR 27.405-3, and DFARS 227.7202-3,
|
||||
and are licensed to the to the U.S. Government end user as restricted computer
|
||||
software and limited rights data. Any use, disclosure, modification,
|
||||
distribution, or reproduction of the Software or Documentation by the U.S.
|
||||
Government or its contractors is subject to the restrictions set forth in this
|
||||
Agreement.
|
||||
|
||||
7.Delivery.
|
||||
Promptly after the applicable Order Effective Date, we'll make the Software and
|
||||
the License Key available for you to download on a secure, password-protected
|
||||
website. As Updates become available, we'll make those available for you to
|
||||
download on the same website. You're responsible for maintaining the
|
||||
confidentiality of all of your usernames and passwords, including the ones you
|
||||
use to download the Software. Take good care of them, because you agree that
|
||||
you'll be responsible for any activity that takes place using your usernames and
|
||||
passwords (whether you knew about it or not).
|
||||
|
||||
8.Services.
|
||||
Our Services can help you get the most out of the Software. If you want
|
||||
Services, let us know, and we'll work with you to prepare a SOW that describes
|
||||
the date, time, location, and objectives of the Services, as well as the price.
|
||||
|
||||
Each SOW will be binding once we both sign it, and you agree that any Services
|
||||
we provide to you (whether pursuant to a SOW or not) will be governed
|
||||
exclusively by the terms of this Agreement. In the event of any conflict
|
||||
between the terms of this Agreement and any SOW, the terms of this Agreement
|
||||
will control. Provided you comply with the terms of this Agreement (including,
|
||||
among other things, paying us the Fees you owe us), we'll perform the Services
|
||||
described in each SOW, according to the timeframes set forth in that SOW.
|
||||
|
||||
We'll control the manner and means by which the Services are performed, and we
|
||||
reserve the right to determine which personnel we assign to perform Services for
|
||||
you.
|
||||
|
||||
Provided we remain responsible for all of their acts and omissions, we can use
|
||||
third parties to help us perform the Services. You acknowledge that we will
|
||||
retain all right, title and interest in and to anything we use or develop in
|
||||
connection with performing Services for you, including, among other things,
|
||||
software programs, tools, specifications, ideas, concepts, inventions,
|
||||
processes, techniques, and know-how. To the extent we deliver anything to you
|
||||
during the course of performing Services, we grant you a non-exclusive,
|
||||
non-transferable, worldwide, royalty-free, limited-term license to use those
|
||||
deliverables during the term of this Agreement, solely in conjunction with your
|
||||
use of the Software.
|
||||
|
||||
9.Term and Termination.
|
||||
|
||||
9.1 Term.
|
||||
This Agreement starts on the Agreement Effective Date and will continue in
|
||||
effect for one (1) year (the "Initial Term"), at which time, so long as you
|
||||
choose to renew your Software license for additional License Terms (which, to be
|
||||
clear, you're under no obligation to do), this Agreement will automatically
|
||||
continue in effect for additional one (1) year terms (each, a "Renewal Term")
|
||||
until this Agreement is either terminated by a party or expires in accordance
|
||||
with this Section 8. We'll notify you at least sixty (60) days before the end of
|
||||
the Initial Term and each Renewal Term that it's time for you to renew your
|
||||
Software license. If you want to renew, let us know. We'll generate a new Order
|
||||
Form for you, and make a new License Key available for you to download that will
|
||||
let you use the Software for another License Term.
|
||||
|
||||
9.2 Termination for Convenience;
|
||||
Automatic Expiration. Either of us can terminate this Agreement for our
|
||||
convenience at the end of the Initial Term or any Renewal Term by providing
|
||||
written notice to the other at least thirty (30) days before the end of the
|
||||
Initial Term or any Renewal Term. This Agreement will automatically expire
|
||||
without the requirement of notice if, at the end of the Initial Term or any
|
||||
Renewal Term, you decide not to pay the Fees required to renew your Seats for an
|
||||
additional License Term.
|
||||
|
||||
9.3 Termination for Breach.
|
||||
We can terminate this Agreement immediately upon notice to you if you breach
|
||||
any part of it, and you fail to cure the breach within thirty (30) days of us
|
||||
notifying you of it. That said, there are certain kinds of breaches that we take
|
||||
much more seriously, and that can really damage us. We therefore reserve the
|
||||
right to terminate this Agreement immediately upon written notice to you, but
|
||||
without giving you a cure period, if you breach any of the terms of this
|
||||
Agreement relating to our intellectual property (including your compliance with
|
||||
the license grant and any license restrictions) or our Confidential Information
|
||||
(defined below).
|
||||
|
||||
9.4 Effect of Termination.
|
||||
When this Agreement terminates or expires: (i) the License Term for any Software
|
||||
in your possession will immediately end, and any outstanding SOWs will
|
||||
immediately terminate; (ii) you'll no longer have the right to use the Software,
|
||||
and any licenses we grant you in this Agreement will automatically cease to
|
||||
exist as of the date of termination/expiration; (iii) if you owed us any money
|
||||
prior to termination/expiration, you'll need to pay us all that money
|
||||
immediately; (iv) you'll destroy all copies of the Software in your possession
|
||||
or control, and certify in writing to us that you've done so; and (v) each of
|
||||
us will promptly return to the other (or, if the other party requests it,
|
||||
destroy) all Confidential Information belonging to the other. You'll still be
|
||||
able to access the Software to migrate your data for ninety (90) days after
|
||||
termination or expiration of this Agreement, but you won't be allowed to use the
|
||||
Software on a production basis during that time. We encourage you to keep
|
||||
copies of your data outside of the Software itself, because if the Software gets
|
||||
disabled, you won't have access to the data you've stored there (and we won't be
|
||||
liable to you if that happens). Sections 1, 3, 5, 6, 8, 9.2, 9.3, 9.4, 11, 12.2,
|
||||
and 13-17 will survive the termination or expiration of this Agreement for any
|
||||
reason.
|
||||
|
||||
10.Support.
|
||||
|
||||
10.1 Support Times.
|
||||
Provided that you've paid us the Fees you owe us, we'll provide you with
|
||||
technical support for the Software twenty-four (24) hours per day, five (5) days
|
||||
per week, excluding weekends and national U.S. holidays. We currently only offer
|
||||
support via email (write to us at mailto:support@c9.io) or web-based ticketing
|
||||
(through https://c9.io/support). You can contact our amazing support team to
|
||||
help answer your questions on installing and using the Software, identifying and
|
||||
verifying the causes of suspected errors in the Software, and helping you find
|
||||
workarounds for Software malfunctions. Though we'll do our best to respond to
|
||||
automated support requests, we typically need more information than an automated
|
||||
ticketing system can give us to solve your issue. Whenever possible, please
|
||||
initiate any support requests from a person or machine that our support team can
|
||||
interact with. We like the personal touch.
|
||||
|
||||
10.2 Updates.
|
||||
We'll make Updates available to you on the same secure website where you
|
||||
downloaded the Software and the License Key.
|
||||
|
||||
10.3 Exclusions.
|
||||
We might not be able to correct every problem we find, but we'll use our
|
||||
reasonable efforts to correct any material, reproducible errors in the Software
|
||||
that you make us aware of. We might ask for your help in reproducing the error
|
||||
for us. Please - don't do things with our Software that would make it harder for
|
||||
us to help you. We won't be responsible for supporting you in those
|
||||
circumstances, which include, among other things: (i) someone (other than us)
|
||||
modifying the Software; (ii) changing your operating system or environment in a
|
||||
way that adversely affects the Software or its performance; (iii) using the
|
||||
Software in a manner for which it was not designed, or other than as authorized
|
||||
under this Agreement; or (iv) accident, negligence, or misuse of the Software.
|
||||
We're only required to support a given version of the Software for a year from
|
||||
the date of its commercial release, or six months from the commercial release
|
||||
of the next Update, whichever is longer. If you want support for earlier
|
||||
versions of the Software, we'll try to help you if we can, but you'll need to
|
||||
pay us for that help at our then-current rates.
|
||||
|
||||
11.Payment.
|
||||
You agree to pay the Fees to us in full, without deduction or setoff of any
|
||||
kind, in U.S. Dollars (unless the Order Form says otherwise), within 30 days of
|
||||
the date of the invoice we send you related to the applicable SOW or Order Form.
|
||||
Amounts payable under this Agreement are nonrefundable, except as provided in
|
||||
Section 12.1. If you don't pay us on time, we reserve the right, in addition to
|
||||
taking any other action that we see fit, to charge you interest on past due
|
||||
amounts at 1.0% per month or the highest interest rate allowed by law, whichever
|
||||
is less, and to additionally charge all expenses of recovery. You are solely
|
||||
responsible for all taxes, fees, duties and governmental assessments (except for
|
||||
taxes based on Cloud9's net income) that are imposed or become due in connection
|
||||
with the subject matter of this Agreement.
|
||||
|
||||
12.Limited Warranties
|
||||
|
||||
12.1 Limited Warranties.
|
||||
We offer you (and only you) the following limited warranties: (i) that the
|
||||
unmodified Software, at the time we make it available to you for download, will
|
||||
not contain or transmit any malware, viruses, or worms (otherwise known as
|
||||
computer code or other technology specifically designed to disrupt, disable, or
|
||||
harm your software, hardware, computer system, or network); (ii) that any
|
||||
Services we perform for you under this Agreement will be performed in a good and
|
||||
workmanlike manner, by appropriately qualified personnel (you just need to let
|
||||
us know about a problem within thirty (30) days of the date the Services were
|
||||
performed); and (iii) that, for ninety (90) days from the date the Software is
|
||||
made available for download, the unmodified Software will substantially conform
|
||||
to its Documentation. We don't warrant that your use of the Software will be
|
||||
uninterrupted, or that the operation of the Software will be error-free.
|
||||
|
||||
These warranties won't apply if you modify the Software, or if you use the
|
||||
Software in any way that isn't expressly permitted by this Agreement and the
|
||||
Documentation.
|
||||
|
||||
Our only obligation, and your only remedy, for any breach of these limited
|
||||
warranties will be, at our option and expense, to either (i) repair the
|
||||
Software; (ii) replace the Software; or (iii) terminate this Agreement with
|
||||
respect to the defective Software, and refund the Fees you've paid for the
|
||||
defective Software during the then-current License Term once you've returned it
|
||||
to us (or destroyed it).
|
||||
|
||||
12.2 Disclaimer.
|
||||
THE LIMITED WARRANTIES DESCRIBED ABOVE ARE THE ONLY WARRANTIES WE MAKE WITH
|
||||
RESPECT TO THE SOFTWARE, SERVICES AND OUR TECHNICAL SUPPORT. WE DON'T MAKE ANY
|
||||
OTHER WARRANTIES, AND WE HEREBY SPECIFICALLY DISCLAIM ANY OTHER WARRANTIES,
|
||||
WHETHER EXPRESS, IMPLIED, OR STATUTORY, INCLUDING BUT NOT LIMITED TO WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, NON-INFRINGEMENT,
|
||||
OR ANY WARRANTIES OR CONDITIONS ARISING OUT OF COURSE OF DEALING OR USAGE OF
|
||||
TRADE. NO ADVICE OR INFORMATION, WHETHER ORAL OR WRITTEN, THAT YOU GET FROM US
|
||||
OR ANYWHERE ELSE WILL CREATE ANY WARRANTY OR CONDITION NOT EXPRESSLY STATED IN
|
||||
THIS AGREEMENT.
|
||||
|
||||
13.LIMITATION OF LIABILITY.
|
||||
|
||||
13.1 Waiver of Consequential Damages.
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO EVENT WILL WE BE LIABLE
|
||||
TO YOU OR TO ANY THIRD PARTY FOR ANY INDIRECT, SPECIAL, INCIDENTAL, PUNITIVE, OR
|
||||
CONSEQUENTIAL DAMAGES (INCLUDING FOR LOSS OF PROFITS, REVENUE, OR DATA) OR FOR
|
||||
THE COST OF OBTAINING SUBSTITUTE PRODUCTS ARISING OUT OF OR IN CONNECTION WITH
|
||||
THIS AGREEMENT, HOWEVER CAUSED, WHETHER SUCH LIABILITY ARISES FROM ANY CLAIM
|
||||
BASED UPON CONTRACT, WARRANTY, TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR
|
||||
OTHERWISE, AND WHETHER OR NOT WE'VE BEEN ADVISED OF THE POSSIBILITY OF SUCH
|
||||
DAMAGES.
|
||||
|
||||
13.2 Limitation of Total Liability.
|
||||
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, OUR TOTAL CUMULATIVE
|
||||
LIABILITY TO YOU OR ANY THIRD PARTY UNDER THIS AGREEMENT, FROM ALL CAUSES OF
|
||||
ACTION AND ALL THEORIES OF LIABILITY, WILL BE LIMITED TO AND WILL NOT EXCEED THE
|
||||
FEES YOU'VE ACTUALLY PAID US DURING THE 12 MONTHS PRECEDING THE CLAIM GIVING
|
||||
RISE TO SUCH LIABILITY.
|
||||
|
||||
13.3 Basis of Bargain.
|
||||
You understand and agree that we've set our prices and entered into this
|
||||
Agreement with you in reliance upon the limitations of liability set forth in
|
||||
this Agreement, which allocate risk between us and form the basis of a bargain
|
||||
between the parties.
|
||||
|
||||
14.Indemnification.
|
||||
|
||||
14.1 Our Indemnification Obligation.
|
||||
We'll defend or settle, at our option and expense, any third-party claim brought
|
||||
against you to the extent that it's based on an allegation that your use or
|
||||
possession of the Software as permitted under this Agreement infringes a
|
||||
copyright or misappropriates a trade secret of any third party (each, a "Claim"),
|
||||
and, subject to Section 13, we'll pay all damages and costs (including
|
||||
reasonable legal fees) finally awarded by a court of final appeal attributable
|
||||
to such a Claim, provided that you notify us in writing of any such Claim as
|
||||
soon as reasonably practicable and allow us to control, and reasonably cooperate
|
||||
with us in the defense of, any such Claim and related settlement negotiations.
|
||||
|
||||
14.2 Exclusions.
|
||||
You understand that we'll have no obligation to indemnify you for any Claim
|
||||
that's based on (i) the modification of the Software, unless we were the ones
|
||||
who made the modifications; (ii) your use of the Software other than as
|
||||
authorized by this Agreement and the Documentation; (iii) your failure to use
|
||||
updated or modified Software that we make available to you that would have
|
||||
helped avoid or mitigate the Claim; (iv) your failure to stop using the Software
|
||||
after receiving written notice to do so from us in order to avoid further
|
||||
infringement or misappropriation; or (v) the combination, operation or use of
|
||||
the Software with equipment, devices, software, systems, or data that we didn't
|
||||
supply (subparts (i)-(v) may be referred to collectively as "Indemnity
|
||||
Exclusions").
|
||||
|
||||
14.3 Right to Ameliorate Damages.
|
||||
If your use of the Software is, or in our reasonable opinion is likely to be,
|
||||
subject to a Claim under Section 14.1, we may, at our sole option and at no
|
||||
charge to you (and in addition to our indemnity obligation to you in Section
|
||||
14.1): (i) procure for you the right to continue using the Software; (ii)
|
||||
replace or modify the Software so that it is non-infringing and substantially
|
||||
equivalent in function to the original Software; or (iii) if options (i) and (ii)
|
||||
above are not commercially practicable in our reasonable estimation, we can
|
||||
terminate this Agreement and all licenses granted hereunder (in which event,
|
||||
you will immediately stop using the Software) and refund the Fees that you paid
|
||||
us for the then-current License Term.
|
||||
|
||||
14.4 Sole Remedy.
|
||||
THIS SECTION 14 SETS FORTH OUR SOLE AND EXCLUSIVE OBLIGATIONS, AND YOUR SOLE AND
|
||||
EXCLUSIVE REMEDIES, WITH RESPECT TO CLAIMS OF INFRINGEMENT OR MISAPPROPRIATION
|
||||
OF THIRD PARTY INTELLECTUAL PROPERTY RIGHTS.
|
||||
|
||||
14.5 Your Indemnification Obligation.
|
||||
Because we can't know what you're doing with the Software behind your firewall,
|
||||
except to the extent that we're obliged to indemnify you in Section 14.1 above,
|
||||
you will defend, indemnify, and hold us harmless from and against any claims
|
||||
that may arise out of or that are based upon (i) your breach of this Agreement;
|
||||
(ii) content that you upload to the Software; or (iii) an Indemnity Exclusion.
|
||||
|
||||
15.Confidentiality.
|
||||
|
||||
15.1 Definition of Confidential Information.
|
||||
For the purposes of this Agreement, "Confidential Information" means any
|
||||
business or technical information that either one of us discloses to the other,
|
||||
in writing, orally, or by any other means, and including things like computer
|
||||
programs, code, algorithms, data, know-how, formulas, processes, ideas,
|
||||
inventions (whether patentable or not), schematics and other technical,
|
||||
business, financial, and product development plans, names and expertise of
|
||||
employees and consultants, and customer lists. For the purposes of this
|
||||
Agreement, except as expressly set forth in Section 17.2 below, the source code
|
||||
of our Software will be deemed to be Cloud9's Confidential Information,
|
||||
regardless of whether it is marked as such.
|
||||
|
||||
15.2 Restrictions on Use and Disclosure.
|
||||
Neither of us will use the other party's Confidential Information, except as
|
||||
permitted under this Agreement. Each of us agrees to maintain in confidence and
|
||||
protect the other party's Confidential Information using at least the same
|
||||
degree of care as we use for its own information of a similar nature, but in all
|
||||
events at least a reasonable degree of care. Each of us agrees to take all
|
||||
reasonable precautions to prevent any unauthorized disclosure of the other's
|
||||
Confidential Information, including, without limitation, disclosing Confidential
|
||||
Information only to its employees, independent contractors, consultants, and
|
||||
legal and financial advisors (collectively, "Representatives") (i) with a need
|
||||
to know such information, (ii) who are parties to appropriate agreements
|
||||
sufficient to comply with this Section 15, and (iii) who are informed of the
|
||||
nondisclosure obligations imposed by this Section 15. Each of us will be
|
||||
responsible for all acts and omissions of our Representatives. The foregoing
|
||||
obligations won't restrict either of us from disclosing Confidential Information
|
||||
of the other party pursuant to the order or requirement of a court,
|
||||
administrative agency, or other governmental body, provided that the party
|
||||
required to make such a disclosure gives reasonable notice to the other party to
|
||||
enable them to contest such order or requirement. The restrictions set forth in
|
||||
this Section 15 will survive the termination or expiration of this Agreement.
|
||||
|
||||
15.3 Exclusions.
|
||||
The restrictions set forth in Section 15.2 will not apply with respect to any
|
||||
Confidential Information that: (i) was or becomes publicly known through no
|
||||
fault of the receiving party; (ii) was rightfully known or becomes rightfully
|
||||
known to the receiving party without confidential or proprietary restriction
|
||||
from a source other than the disclosing party who has a right to disclose it;
|
||||
(iii) is approved by the disclosing party for disclosure without restriction in
|
||||
a written document which is signed by a duly authorized officer of such
|
||||
disclosing party; or (iv) the receiving party independently develops without
|
||||
access to or use of the other party's Confidential Information.
|
||||
|
||||
16.Governing Law and Jurisdiction.
|
||||
This Agreement will be governed by and interpreted in accordance with the laws
|
||||
of the State of California, without giving effect to any principles of conflict
|
||||
of laws. The parties expressly agree that the United Nations Convention on
|
||||
Contracts for the International Sale of Goods and the Uniform Computer
|
||||
Information Transactions Act will not apply to this Agreement. Any legal action
|
||||
or proceeding arising under, related to or connected with this Agreement will
|
||||
be brought exclusively in the federal (if they have jurisdiction) or state
|
||||
courts located in San Francisco, California and the parties irrevocably consent
|
||||
to the personal jurisdiction and venue there.
|
||||
|
||||
17.Miscellaneous.
|
||||
|
||||
17.1 Assignment.
|
||||
You aren't allowed to assign or transfer any of your rights or obligations in
|
||||
this Agreement, in whole or in part, by operation of law or otherwise, without
|
||||
our prior written consent, and any attempt by you to do so without our consent
|
||||
will be null and void. We can assign this Agreement in its entirety, upon
|
||||
notice to you but without the requirement to obtain consent, in connection with
|
||||
a merger, acquisition, corporate reorganization, or sale of all or substantially
|
||||
all of our business or assets.
|
||||
|
||||
17.3 Severability.
|
||||
In the event that any provision of this Agreement is deemed by a court of
|
||||
competent jurisdiction to be illegal, invalid, or unenforceable, the court will
|
||||
modify or reform this Agreement to give as much effect as possible to that
|
||||
provision. Any provision that can't be modified or reformed in this way will be
|
||||
deemed deleted, and the remaining provisions of this Agreement will continue in
|
||||
full force and effect.
|
||||
|
||||
17.4 Notices.
|
||||
Any notice, request, demand or other communication required or permitted under
|
||||
this Agreement should be in writing (e-mail counts), should reference this
|
||||
Agreement, and will be deemed to be properly given: (i) upon receipt, if
|
||||
delivered personally; (ii) upon confirmation of receipt by the intended
|
||||
recipient, if by e-mail; (iii) five (5) business days after it is sent by
|
||||
registered or certified mail, with written confirmation of receipt; or (iv)
|
||||
three (3) business days after deposit with an internationally recognized express
|
||||
courier, with written confirmation of receipt. Notices should be sent to the
|
||||
address(es) set forth on the Invoice, unless we notify each other that those
|
||||
addresses have changed.
|
||||
|
||||
17.5 Waiver.
|
||||
A party's obligations under this Agreement can only be waived in a writing
|
||||
signed by an authorized representative of the other party, which waiver will be
|
||||
effective only with respect to the specific obligation described. Any waiver or
|
||||
failure to enforce any provision of this Agreement on one occasion will not be
|
||||
deemed a waiver of any other provision or of such provision on any other
|
||||
occasion.
|
||||
|
||||
17.6 Force Majeure.
|
||||
We will be excused from performing under this Agreement to the extent that we're
|
||||
unable to perform due extraordinary causes beyond our reasonable control. That
|
||||
might include things like acts of God, strikes, lockouts, riots, acts of war,
|
||||
epidemics, communication line failure, and power failures.
|
||||
|
||||
17.7 Independent Contractors.
|
||||
We're each independent contractors with respect to the subject matter of this
|
||||
Agreement. Nothing contained in this Agreement will be deemed or construed in
|
||||
any manner whatsoever to create a partnership, joint venture, employment, agency,
|
||||
fiduciary, or other similar relationship between us, and neither of us can bind
|
||||
the other contractually.
|
||||
|
||||
17.8 Amendments;
|
||||
Entire Agreement. No modification, change, or amendment of this Agreement will
|
||||
be binding upon the parties, unless we both agree to the change in a writing
|
||||
signed by each of our authorized representatives. This Agreement, including each
|
||||
Order Form and SOW, constitutes the entire agreement and understanding of the
|
||||
parties with respect to its subject matter, and supersedes any and all prior or
|
||||
contemporaneous understandings and agreements, whether oral or written, between
|
||||
the parties with respect to its subject matter.
|
||||
|
||||
17.9 No Other Terms.
|
||||
Sometimes your accounting folks will send us purchase orders with lots of itty
|
||||
bitty language attached that requires a microscope for us to read. Everybody
|
||||
does it – we understand. But this Agreement is the only agreement between us,
|
||||
and the terms of any purchase order, written terms or conditions, or other
|
||||
document that you submit to us that contain terms that are different from, in
|
||||
conflict with, or in addition to the terms of this Agreement, SOW or any Order
|
||||
Form are hereby rejected by Cloud9, and will be void and of no effect.
|
||||
|
||||
17.10 No Publicity Without Your Permission.
|
||||
We may identify you as a customer to current and prospective clients.
|
||||
|
||||
We won't use your name or logo in any advertising or marketing materials without
|
||||
your permission, though; and if we ask for your permission, you always have the
|
||||
right to say no.
|
||||
|
|
@ -9,7 +9,10 @@
|
|||
"https://cloud9beta.com/", "https://ide.cloud9beta.com/",
|
||||
"http://localhost:8181/", "http://localhost:5252/",
|
||||
"https://c9.vm:8181/", "https://c9.vm:5252/",
|
||||
"https://c9.dev/", "https://ide.c9.dev/"
|
||||
"https://c9.dev/", "https://ide.c9.dev/",
|
||||
"https://ide.dev.smartface.io",
|
||||
"https://ide.cs50.io",
|
||||
"https://ide.mbed.com"
|
||||
]
|
||||
},
|
||||
"description": "Cloud9 is an online platform for development that makes developing applications more convenient than ever",
|
||||
|
|
|
@ -35,8 +35,6 @@ module.exports = function(options) {
|
|||
var devel = options.standalone && !options.local || options.mode === "devel" || options.mode == "onlinedev" || options.dev;
|
||||
|
||||
var localExtendFiles = options.localExtend || options.standalone;
|
||||
// allow extend code access only to C9-deveoped plugins
|
||||
var extendToken = options.extendToken || "token";
|
||||
|
||||
var plugins = [
|
||||
// C9
|
||||
|
@ -412,7 +410,6 @@ module.exports = function(options) {
|
|||
"plugins/c9.ide.language.go/go",
|
||||
{
|
||||
packagePath: "plugins/c9.ide.language.jsonalyzer/jsonalyzer",
|
||||
extendToken: extendToken,
|
||||
workspaceDir: workspaceDir,
|
||||
homeDir: options.home,
|
||||
bashBin: options.bashBin,
|
||||
|
@ -692,11 +689,7 @@ module.exports = function(options) {
|
|||
pubkey: options.user.pubkey,
|
||||
date_add: options.user.date_add,
|
||||
active: options.user.active,
|
||||
alpha: options.user.alpha,
|
||||
beta: options.user.beta,
|
||||
c9version: options.user.c9version,
|
||||
no_newsletter: options.user.no_newsletter,
|
||||
subscription_on_signup: options.user.subscription_on_signup,
|
||||
premium: options.user.premium,
|
||||
region: options.user.region,
|
||||
},
|
||||
|
@ -787,7 +780,6 @@ module.exports = function(options) {
|
|||
},
|
||||
{
|
||||
packagePath: "plugins/c9.ide.pubsub/pubsub-client",
|
||||
extendToken: extendToken
|
||||
},
|
||||
{
|
||||
packagePath: "plugins/c9.ide.collab/notifications/bubble",
|
||||
|
@ -868,7 +860,6 @@ module.exports = function(options) {
|
|||
plugins.push(
|
||||
{
|
||||
packagePath: "plugins/c9.ide.collab/connect",
|
||||
extendToken: extendToken,
|
||||
enable: collab,
|
||||
debug: debug,
|
||||
localServerFile: localExtendFiles,
|
||||
|
@ -924,6 +915,9 @@ module.exports = function(options) {
|
|||
plugins.push({
|
||||
packagePath: "plugins/c9.ide.language.codeintel/codeintel",
|
||||
preinstalled: hosted && !options.ssh,
|
||||
paths: {
|
||||
php: ".:./vendor",
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -105,7 +105,7 @@ module.exports = function(config, optimist) {
|
|||
console.log("Run using --listen localhost instead to only expose Cloud9 to localhost,");
|
||||
console.log("or use -a username:password to setup HTTP authentication\n");
|
||||
}
|
||||
var auth = (argv.auth || ":").split(":");
|
||||
var auth = (argv.auth + "").split(":");
|
||||
|
||||
var plugins = [
|
||||
{
|
||||
|
@ -158,7 +158,6 @@ module.exports = function(config, optimist) {
|
|||
"c9.vfs.client": true,
|
||||
"c9.cli.bridge": true,
|
||||
"c9.nodeapi": true,
|
||||
"c9.ide.experiment": true,
|
||||
"saucelabs.preview": true,
|
||||
"salesforce.sync": true,
|
||||
"salesforce.language": true
|
||||
|
@ -194,7 +193,6 @@ module.exports = function(config, optimist) {
|
|||
"./c9.vfs.server/statics",
|
||||
"./c9.analytics/mock_analytics",
|
||||
"./c9.metrics/mock_metrics",
|
||||
"./c9.ide.experiment/mock_experiment",
|
||||
{
|
||||
packagePath: "./c9.vfs.server/vfs.connect.standalone",
|
||||
workspaceDir: baseProc,
|
||||
|
|
|
@ -148,7 +148,7 @@ var EditSession = function(text, mode) {
|
|||
this.$undoSelect = true;
|
||||
|
||||
this.$foldData = [];
|
||||
this.id = "session" + EditSession.$uid;
|
||||
this.id = "session" + (++EditSession.$uid);
|
||||
this.$foldData.toString = function() {
|
||||
return this.join("\n");
|
||||
};
|
||||
|
|
|
@ -364,10 +364,11 @@ var TextInput = function(parentNode, host) {
|
|||
return;
|
||||
// console.log("onCompositionStart", inComposition)
|
||||
inComposition = {};
|
||||
inComposition.canUndo = host.session.$undoManager;
|
||||
host.onCompositionStart();
|
||||
setTimeout(onCompositionUpdate, 0);
|
||||
host.on("mousedown", onCompositionEnd);
|
||||
if (!host.selection.isEmpty()) {
|
||||
if (inComposition.canUndo && !host.selection.isEmpty()) {
|
||||
host.insert("");
|
||||
host.session.markUndoGroup();
|
||||
host.selection.clearSelection();
|
||||
|
@ -385,7 +386,8 @@ var TextInput = function(parentNode, host) {
|
|||
host.onCompositionUpdate(val);
|
||||
if (inComposition.lastValue)
|
||||
host.undo();
|
||||
inComposition.lastValue = val;
|
||||
if (inComposition.canUndo)
|
||||
inComposition.lastValue = val;
|
||||
if (inComposition.lastValue) {
|
||||
var r = host.selection.getRange();
|
||||
host.insert(inComposition.lastValue);
|
||||
|
|
|
@ -154,17 +154,15 @@ define(function(require, exports, module) {
|
|||
return this.ace.inVirtualSelectionMode && this.ace.selection.index;
|
||||
};
|
||||
this.onChange = function(delta) {
|
||||
if (delta.action[0] == 'i') {
|
||||
var change = { text: delta.lines };
|
||||
var curOp = this.curOp = this.curOp || {};
|
||||
if (!curOp.changeHandlers)
|
||||
curOp.changeHandlers = this._eventRegistry["change"] && this._eventRegistry["change"].slice();
|
||||
if (this.virtualSelectionMode()) return;
|
||||
if (!curOp.lastChange) {
|
||||
curOp.lastChange = curOp.change = change;
|
||||
} else {
|
||||
curOp.lastChange.next = curOp.lastChange = change;
|
||||
}
|
||||
var change = { text: delta.action[0] == 'i' ? delta.lines : [] };
|
||||
var curOp = this.curOp = this.curOp || {};
|
||||
if (!curOp.changeHandlers)
|
||||
curOp.changeHandlers = this._eventRegistry["change"] && this._eventRegistry["change"].slice();
|
||||
if (this.virtualSelectionMode()) return;
|
||||
if (!curOp.lastChange) {
|
||||
curOp.lastChange = curOp.change = change;
|
||||
} else {
|
||||
curOp.lastChange.next = curOp.lastChange = change;
|
||||
}
|
||||
this.$updateMarkers(delta);
|
||||
};
|
||||
|
@ -5693,6 +5691,10 @@ dom.importCssString(".normal-mode .ace_cursor{\
|
|||
if (changeObj.origin == '+input' || changeObj.origin == 'paste'
|
||||
|| changeObj.origin === undefined /* only in testing */) {
|
||||
var text = changeObj.text.join('\n');
|
||||
if (lastChange.maybeReset) {
|
||||
lastChange.changes = [];
|
||||
lastChange.maybeReset = false;
|
||||
}
|
||||
lastChange.changes.push(text);
|
||||
}
|
||||
// Change objects may be chained with next.
|
||||
|
@ -5715,7 +5717,7 @@ dom.importCssString(".normal-mode .ace_cursor{\
|
|||
lastChange.expectCursorActivityForChange = false;
|
||||
} else {
|
||||
// Cursor moved outside the context of an edit. Reset the change.
|
||||
lastChange.changes = [];
|
||||
lastChange.maybeReset = true;
|
||||
}
|
||||
} else if (!cm.curOp.isVimOp) {
|
||||
handleExternalSelection(cm, vim);
|
||||
|
@ -5779,6 +5781,10 @@ dom.importCssString(".normal-mode .ace_cursor{\
|
|||
var keyName = CodeMirror.keyName(e);
|
||||
if (!keyName) { return; }
|
||||
function onKeyFound() {
|
||||
if (lastChange.maybeReset) {
|
||||
lastChange.changes = [];
|
||||
lastChange.maybeReset = false;
|
||||
}
|
||||
lastChange.changes.push(new InsertModeKey(keyName));
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -77,7 +77,7 @@ function build(config, opts, callback){
|
|||
if (added[pkg.id])
|
||||
return;
|
||||
added[pkg.id] = true;
|
||||
if (!pkg.source)
|
||||
if (pkg.source == null)
|
||||
return;
|
||||
if (pkg.deps)
|
||||
pkg.deps.forEach(addModule);
|
||||
|
|
|
@ -113,6 +113,7 @@ module.exports = function(mains, opts) {
|
|||
}
|
||||
|
||||
function setModuleSource(mod, src, cb) {
|
||||
src = src.replace(/\r\n/g, "\n"); // normalize windows newlines
|
||||
if (cache)
|
||||
cache.files[mod.file] = src;
|
||||
mod.source = src;
|
||||
|
@ -345,13 +346,14 @@ function removeUseStrict(module) {
|
|||
module.source = module.source.replace(/['"]use strict['"];/g, "");
|
||||
}
|
||||
|
||||
var commentRe = /^(;)?(?:\s*(?:\/\/.+\n|\/\*(?:[^*]|\*(?!\/))*\*\/))+(?: *\n)?/gm;
|
||||
function removeLicenceComments(module) {
|
||||
if (/\.(js|jsx|css|less)/.test(module.path))
|
||||
module.source = module.source.replace(/(?:(;)|\n|^)\s*\/\*[\d\D]*?\*\/|(\n|^)\s*\/\/.*/g, "$1");
|
||||
module.source = module.source.replace(commentRe, "$1");
|
||||
}
|
||||
function removeLicenceCommentsKeepLines(module) {
|
||||
if (/\.(js|jsx|css|less)/.test(module.path)) {
|
||||
module.source = module.source.replace(/(?:(;)|\n|^)\s*\/\*[\d\D]*?\*\/|\n\s*\/\/.*/g, function(cm, start) {
|
||||
module.source = module.source.replace(commentRe, function(cm, start) {
|
||||
return (start||"") + cm.replace(/.+/g, "");
|
||||
});
|
||||
}
|
||||
|
@ -391,8 +393,8 @@ function wrapUMD(module) {
|
|||
+ ' $build_deps$.module.define(name, [], function() { return $build_deps$.module.exports });\n'
|
||||
+ ' }\n'
|
||||
+ '}\n'
|
||||
+ 'define.amd = true;'
|
||||
+ module.source
|
||||
+ 'define.amd = true;\n'
|
||||
+ module.source + '\n'
|
||||
+ '});';
|
||||
}
|
||||
|
||||
|
@ -410,4 +412,7 @@ function quote(str) {
|
|||
}
|
||||
|
||||
|
||||
module.exports.resolveModulePath = resolveModulePath;
|
||||
module.exports.getSubmodules = getSubmodules;
|
||||
module.exports.resolveModulePath = resolveModulePath;
|
||||
module.exports.removeLicenceComments = removeLicenceComments;
|
||||
module.exports.removeLicenceCommentsKeepLines = removeLicenceCommentsKeepLines;
|
|
@ -24,12 +24,15 @@ function runCommand(pattern, command, options, callback) {
|
|||
return runCommand(pattern, command, {}, options);
|
||||
}
|
||||
|
||||
var parallel = ""
|
||||
var optionsArray = [];
|
||||
if (options.parallel) {
|
||||
parallel = " -P"
|
||||
optionsArray.push("-P");
|
||||
}
|
||||
if (options.cacheOnly) {
|
||||
optionsArray.push("--cache-only");
|
||||
}
|
||||
|
||||
var gsshCommand = GSSH + " " + parallel + " " + pattern + " '" + command + "'";
|
||||
var gsshCommand = GSSH + " " + optionsArray.join(" ") + " " + pattern + " '" + command + "'";
|
||||
childProcess.exec(gsshCommand, function (err, stdout) {
|
||||
return callback(err, stdout);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
"use strict";
|
||||
|
||||
module.exports = function isZuoraId(value){
|
||||
if (/^\d+$/.test(value))
|
||||
return false;
|
||||
|
||||
return /^[a-z0-9]{32}$/.test(value);
|
||||
};
|
|
@ -0,0 +1,42 @@
|
|||
"use strict";
|
||||
"use mocha";
|
||||
|
||||
require("c9/inline-mocha")(module);
|
||||
var assert = require("assert");
|
||||
var isZuoraId= require("c9/is-zuora-id");
|
||||
|
||||
describe("iz-zuora-id-test", function() {
|
||||
|
||||
it("returns false when account id undefined", function() {
|
||||
assert.equal(false, isZuoraId(undefined), "should return false when account id undefined");
|
||||
});
|
||||
|
||||
it("returns false when account id null", function() {
|
||||
assert.equal(false, isZuoraId(null), "should return false when account id null");
|
||||
});
|
||||
|
||||
it("returns false when account id is an empty string", function() {
|
||||
assert.equal(false, isZuoraId(""), "should return false when account id is an empty string");
|
||||
});
|
||||
|
||||
it("returns false when account id contains only digits", function() {
|
||||
var accountId = "12345700674455";
|
||||
assert.equal(false, isZuoraId(accountId), "should return false when account id contains only digits");
|
||||
});
|
||||
|
||||
it("returns false when account id contains only digits and has the correct length", function() {
|
||||
var accountId = "123456789101112131415161718192021";
|
||||
assert.equal(false, isZuoraId(accountId), "should return false when account id contains only digits and has the correct length");
|
||||
});
|
||||
|
||||
it("returns false when account id contains both digits and letters but does not have the correct length", function() {
|
||||
var accountId = "78654hjfgf764674h87634876g7h89h";
|
||||
assert.equal(false, isZuoraId(accountId), "should return false");
|
||||
});
|
||||
|
||||
it("returns true when account id has both letters and digits and correct length", function() {
|
||||
var accountId = "2c92a0f850a7a1b50150c672fa3a6ddd";
|
||||
|
||||
assert.equal(true, isZuoraId(accountId), "should return true when account id has both letters and digits and correct length");
|
||||
});
|
||||
});
|
|
@ -1,32 +1,46 @@
|
|||
var error = require("http-error");
|
||||
|
||||
var MAX_EXPIRE_INTERVAL = 5000;
|
||||
|
||||
/**
|
||||
* In memory rate limiter as connect middleware
|
||||
*/
|
||||
module.exports = ratelimit;
|
||||
|
||||
function ratelimit(key, duration, max) {
|
||||
var limit = {};
|
||||
var requests = Object.create(null); // in case there handles like 'constructor'
|
||||
setInterval(function() {
|
||||
Object.keys(requests).forEach(expireRequests);
|
||||
}, Math.min(duration * 0.75, MAX_EXPIRE_INTERVAL));
|
||||
|
||||
function expireRequests(handle) {
|
||||
var requestsForHandle = requests[handle];
|
||||
var totalToSplice = 0;
|
||||
var expireTime = Date.now() - duration;
|
||||
/* Requests are already sorted by date as they are appended, so we just loop
|
||||
until we find one that shouldn't have expired and splice them from the list */
|
||||
for (totalToSplice = 0; totalToSplice < requestsForHandle.length; totalToSplice++) {
|
||||
if (requestsForHandle[totalToSplice] >= expireTime) break;
|
||||
}
|
||||
requests[handle].splice(0, totalToSplice);
|
||||
if (requests[handle].length == 0) {
|
||||
delete requests[handle];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return function(req, res, next) {
|
||||
var handle = req.params[key];
|
||||
|
||||
var lim = limit[handle] || (limit[handle] = []);
|
||||
var now = Date.now();
|
||||
for (var i = 0; i < lim.length; i++) {
|
||||
if (now - lim[i] > duration) {
|
||||
lim.splice(i, 1);
|
||||
i--;
|
||||
}
|
||||
else break;
|
||||
}
|
||||
if (lim.length > max) {
|
||||
requests[handle] = requests[handle] || [];
|
||||
if (requests[handle].length >= max) {
|
||||
var err = new error.TooManyRequests("Rate limit exceeded");
|
||||
err.retryIn = duration - (Date.now() - lim[0]);
|
||||
next(err);
|
||||
return;
|
||||
err.retryIn = Math.min(duration, 5000);
|
||||
return next(err);
|
||||
}
|
||||
lim.push(Date.now());
|
||||
|
||||
requests[handle].push(Date.now());
|
||||
return next();
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,104 @@
|
|||
"use server";
|
||||
|
||||
require("c9/inline-mocha")(module);
|
||||
|
||||
var ratelimit = require("./ratelimit");
|
||||
var assert = require("assert");
|
||||
var async = require("async");
|
||||
|
||||
describe("ratelimit", function() {
|
||||
|
||||
it("Should limit based on key", function (done) {
|
||||
var limiter = ratelimit("username", 10, 1);
|
||||
limiter({params: {username: "super"}}, null, function (err) {
|
||||
assert(!err, err);
|
||||
limiter({params: {username: "super"}}, null, function (err) {
|
||||
assert(err);
|
||||
assert.equal(err.code, 429);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("Should work with different keys", function (done) {
|
||||
var limiter = ratelimit("username", 10, 1);
|
||||
limiter({params: {username: "super"}}, null, function (err) {
|
||||
assert(!err, err);
|
||||
limiter({params: {username: "aloha"}}, null, function (err) {
|
||||
assert(!err, err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
|
||||
it("Should work again after a delay", function (done) {
|
||||
var limiter = ratelimit("username", 10, 1);
|
||||
limiter({params: {username: "super"}}, null, function (err) {
|
||||
assert(!err, err);
|
||||
setTimeout(function() {
|
||||
limiter({params: {username: "super"}}, null, function (err) {
|
||||
assert(!err, err);
|
||||
done();
|
||||
});
|
||||
}, 25);
|
||||
});
|
||||
});
|
||||
|
||||
it("Should work with many requests", function (done) {
|
||||
var MAX_REQUESTS = 5;
|
||||
var limiter = ratelimit("username", 10, MAX_REQUESTS);
|
||||
var successfulRequests = 0;
|
||||
async.times(10, function(n, next) {
|
||||
limiter({params: {username: "super"}}, null, function (err) {
|
||||
if (err) return next(err);
|
||||
successfulRequests++;
|
||||
next();
|
||||
});
|
||||
}, function (err) {
|
||||
assert.equal(successfulRequests, MAX_REQUESTS);
|
||||
setTimeout(function() {
|
||||
limiter({params: {username: "super"}}, null, function (err) {
|
||||
assert(!err, err);
|
||||
done();
|
||||
});
|
||||
}, 25);
|
||||
});
|
||||
});
|
||||
|
||||
it("Should expire keys at the correct times", function (done) {
|
||||
var limiter = ratelimit("username", 50, 2);
|
||||
async.series([
|
||||
function(next) {
|
||||
limiter({params: {username: "mario"}}, null, function(err) {
|
||||
assert(!err, err);
|
||||
setTimeout(next, 25);
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
limiter({params: {username: "mario"}}, null, function(err) {
|
||||
assert(!err, err);
|
||||
setTimeout(next, 40);
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
limiter({params: {username: "mario"}}, null, function(err) {
|
||||
assert(!err, err);
|
||||
limiter({params: {username: "mario"}}, null, function(err) {
|
||||
assert(err);
|
||||
assert.equal(err.code, 429);
|
||||
setTimeout(next, 20);
|
||||
});
|
||||
});
|
||||
},
|
||||
function (next) {
|
||||
limiter({params: {username: "mario"}}, null, function(err) {
|
||||
assert(!err, err);
|
||||
next();
|
||||
});
|
||||
}
|
||||
], done);
|
||||
});
|
||||
|
||||
});
|
|
@ -13,6 +13,7 @@ define(function(require, exports, module) {
|
|||
"bitbucket.org": "bitbucket",
|
||||
"github.com": "github",
|
||||
"source.developers.google.com": "google",
|
||||
"gitlab.com": "gitlab",
|
||||
};
|
||||
var defaultProvider = "unknown";
|
||||
|
||||
|
@ -75,6 +76,9 @@ define(function(require, exports, module) {
|
|||
case "bitbucket":
|
||||
scm = parsed.pathname.match(/\.git$/) ? "git": "hg";
|
||||
break;
|
||||
case "gitlab":
|
||||
scm = "git";
|
||||
break;
|
||||
default:
|
||||
scm = parsed.pathname.match(/\.git$/) ? "git": "hg";
|
||||
}
|
||||
|
|
|
@ -16,57 +16,60 @@ describe(__filename, function() {
|
|||
|
||||
describe("#parse", function() {
|
||||
it("should parse ssh url", function(done) {
|
||||
var url = parse("git@github.com:fjakobs/lispjs.git");
|
||||
assert.equal(url.scm, "git");
|
||||
assert.equal(url.protocol, "ssh:");
|
||||
assert.equal(url.auth, "git");
|
||||
assert.equal(url.hostname, "github.com");
|
||||
assert.equal(url.pathname, "fjakobs/lispjs.git");
|
||||
done();
|
||||
var url = parse("git@github.com:fjakobs/lispjs.git");
|
||||
assert.equal(url.scm, "git");
|
||||
assert.equal(url.protocol, "ssh:");
|
||||
assert.equal(url.provider, "github");
|
||||
assert.equal(url.auth, "git");
|
||||
assert.equal(url.hostname, "github.com");
|
||||
assert.equal(url.pathname, "fjakobs/lispjs.git");
|
||||
done();
|
||||
}),
|
||||
|
||||
}),
|
||||
it("should parse git url", function(done) {
|
||||
var url = parse("git://github.com/fjakobs/lispjs.git");
|
||||
assert.equal(url.scm, "git");
|
||||
assert.equal(url.protocol, "git:");
|
||||
assert.equal(url.provider, "github");
|
||||
assert.equal(url.hostname, "github.com");
|
||||
assert.equal(url.pathname, "fjakobs/lispjs.git");
|
||||
done();
|
||||
}),
|
||||
|
||||
it("should parse git url", function(done) {
|
||||
var url = parse("git://github.com/fjakobs/lispjs.git");
|
||||
assert.equal(url.scm, "git");
|
||||
assert.equal(url.protocol, "git:");
|
||||
assert.equal(url.hostname, "github.com");
|
||||
assert.equal(url.pathname, "fjakobs/lispjs.git");
|
||||
done();
|
||||
it("should parse https url", function(done) {
|
||||
var url = parse("https://fjakobs@github.com/fjakobs/lispjs.git");
|
||||
assert.equal(url.protocol, "https:");
|
||||
assert.equal(url.scm, "git");
|
||||
assert.equal(url.auth, "fjakobs");
|
||||
assert.equal(url.provider, "github");
|
||||
assert.equal(url.hostname, "github.com");
|
||||
assert.equal(url.pathname, "fjakobs/lispjs.git");
|
||||
done();
|
||||
|
||||
}),
|
||||
}),
|
||||
|
||||
it("should parse https url", function(done) {
|
||||
var url = parse("https://fjakobs@github.com/fjakobs/lispjs.git");
|
||||
assert.equal(url.protocol, "https:");
|
||||
assert.equal(url.scm, "git");
|
||||
assert.equal(url.auth, "fjakobs");
|
||||
assert.equal(url.hostname, "github.com");
|
||||
assert.equal(url.pathname, "fjakobs/lispjs.git");
|
||||
done();
|
||||
|
||||
}),
|
||||
|
||||
it("should parse Bitbucket url", function(done) {
|
||||
var url = parse("git@bitbucket.org/Richard/expressling.git");
|
||||
assert.equal(url.protocol, "ssh:");
|
||||
assert.equal(url.scm, "git");
|
||||
assert.equal(url.auth, "git");
|
||||
assert.equal(url.hostname, "bitbucket.org");
|
||||
assert.equal(url.pathname, "Richard/expressling.git");
|
||||
done();
|
||||
});
|
||||
it("should parse Bitbucket url", function(done) {
|
||||
var url = parse("git@bitbucket.org/Richard/expressling.git");
|
||||
assert.equal(url.protocol, "ssh:");
|
||||
assert.equal(url.scm, "git");
|
||||
assert.equal(url.auth, "git");
|
||||
assert.equal(url.provider, "bitbucket");
|
||||
assert.equal(url.hostname, "bitbucket.org");
|
||||
assert.equal(url.pathname, "Richard/expressling.git");
|
||||
done();
|
||||
});
|
||||
|
||||
it("should parse Bitbucket hg ssh url", function(done) {
|
||||
var url = parse("ssh://hg@bitbucket.org/fjakobs/juhu");
|
||||
assert.equal(url.protocol, "ssh:");
|
||||
assert.equal(url.scm, "hg");
|
||||
assert.equal(url.provider, "bitbucket");
|
||||
assert.equal(url.hostname, "bitbucket.org");
|
||||
assert.equal(url.pathname, "fjakobs/juhu");
|
||||
done();
|
||||
});
|
||||
|
||||
it("should parse github URL without .git", function(done) {
|
||||
it("should parse Github url without .git", function(done) {
|
||||
var url = parse("https://github.com/arunoda/meteor-streams");
|
||||
assert.equal(url.protocol, "https:");
|
||||
assert.equal(url.scm, "git");
|
||||
|
@ -76,7 +79,27 @@ describe(__filename, function() {
|
|||
done();
|
||||
});
|
||||
|
||||
it("Should refuse a git url with dangerous shell chars in it", function() {
|
||||
it("should parse Gitlab url", function(done) {
|
||||
var url = parse("git@gitlab.com:bdewachter/testfiles.git");
|
||||
assert.equal(url.scm, "git");
|
||||
assert.equal(url.protocol, "ssh:");
|
||||
assert.equal(url.provider, "gitlab");
|
||||
assert.equal(url.hostname, "gitlab.com");
|
||||
assert.equal(url.pathname, "bdewachter/testfiles.git");
|
||||
done();
|
||||
}),
|
||||
|
||||
it("should parse Gitlab url without .git", function(done) {
|
||||
var url = parse("https://gitlab.com/bdewachter/testfiles.git");
|
||||
assert.equal(url.protocol, "https:");
|
||||
assert.equal(url.scm, "git");
|
||||
assert.equal(url.provider, "gitlab");
|
||||
assert.equal(url.hostname, "gitlab.com");
|
||||
assert.equal(url.pathname, "bdewachter/testfiles.git");
|
||||
done();
|
||||
});
|
||||
|
||||
it("should refuse a git url with dangerous shell chars in it", function() {
|
||||
var validUrls = [
|
||||
"https://github.com/arunoda/meteor-streams",
|
||||
"https://fjakobs@github.com/fjakobs/lispjs.git",
|
||||
|
|
|
@ -11,7 +11,13 @@ module.exports = function startup(options, imports, register) {
|
|||
set: sessionStore.set.bind(sessionStore),
|
||||
destroy: sessionStore.destroy.bind(sessionStore),
|
||||
regenerate: sessionStore.regenerate.bind(sessionStore),
|
||||
createSession: sessionStore.createSession.bind(sessionStore)
|
||||
createSession: sessionStore.createSession.bind(sessionStore),
|
||||
set generate(fn) {
|
||||
sessionStore.generate = fn;
|
||||
},
|
||||
get generate() {
|
||||
return sessionStore.generate;
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
|
|
@ -39,7 +39,7 @@ module.exports = function setup(mount, vfs, mountOptions) {
|
|||
if (path) {
|
||||
entry.href = path + entry.name;
|
||||
var mime = entry.linkStat ? entry.linkStat.mime : entry.mime;
|
||||
if (mime && mime.match(/(directory|folder)$/)) {
|
||||
if (/(directory|folder)$/.test(mime)) {
|
||||
entry.href += "/";
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,15 @@ var pathBasename = require("path").basename;
|
|||
var dirname = require("path").dirname;
|
||||
var basename = require("path").basename;
|
||||
var Stream = require("stream").Stream;
|
||||
var getMime = require("simple-mime")("application/octet-stream");
|
||||
var getMime = (function(simpleMime) {
|
||||
// workaround for a bug in simple-mime
|
||||
return function(path) {
|
||||
var mime = simpleMime(path);
|
||||
if (typeof mime != "string")
|
||||
return "application/octet-stream"
|
||||
return mime;
|
||||
}
|
||||
})(require("simple-mime")());
|
||||
var vm = require("vm");
|
||||
var exists = fs.exists || require("path").exists;
|
||||
var crypto = require("crypto");
|
||||
|
@ -2094,7 +2102,7 @@ module.exports = function setup(fsOptions) {
|
|||
// Kill the session with the same name before starting a new one
|
||||
if (options.kill) {
|
||||
session = sessions[options.session];
|
||||
if (session)
|
||||
if (session && session.pty)
|
||||
session.pty.kill();
|
||||
|
||||
if (!options.command)
|
||||
|
|
35
package.json
35
package.json
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "c9",
|
||||
"description": "New Cloud9 Client",
|
||||
"version": "3.1.2288",
|
||||
"version": "3.1.2576",
|
||||
"author": "Ajax.org B.V. <info@ajax.org>",
|
||||
"private": true,
|
||||
"main": "bin/c9",
|
||||
|
@ -44,6 +44,9 @@
|
|||
"chai": "~1.5.0",
|
||||
"mocha": "1.8.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "node server.js"
|
||||
},
|
||||
"devDependencies": {},
|
||||
"licenses": [],
|
||||
"bundledDependencies": [
|
||||
|
@ -55,7 +58,7 @@
|
|||
"c9"
|
||||
],
|
||||
"c9plugins": {
|
||||
"c9.ide.language": "#ebc064ef16",
|
||||
"c9.ide.language": "#79bcb2fe06",
|
||||
"c9.ide.language.core": "#undefined",
|
||||
"c9.ide.language.css": "#be07d72209",
|
||||
"c9.ide.language.generic": "#3949510863",
|
||||
|
@ -64,16 +67,16 @@
|
|||
"c9.ide.language.javascript": "#e626169643",
|
||||
"c9.ide.language.javascript.immediate": "#c8b1e5767a",
|
||||
"c9.ide.language.javascript.eslint": "#4de5457db1",
|
||||
"c9.ide.language.javascript.tern": "#b55d0069bb",
|
||||
"c9.ide.language.javascript.tern": "#64ab01f271",
|
||||
"c9.ide.language.javascript.infer": "#18acb93a3a",
|
||||
"c9.ide.language.jsonalyzer": "#4b329741b1",
|
||||
"c9.ide.language.codeintel": "#253ae15f5e",
|
||||
"c9.ide.collab": "#cd36cae90c",
|
||||
"c9.ide.language.jsonalyzer": "#d8183d84b4",
|
||||
"c9.ide.language.codeintel": "#fc867feec4",
|
||||
"c9.ide.collab": "#cfbf987438",
|
||||
"c9.ide.local": "#10eb45842a",
|
||||
"c9.ide.find": "#e33fbaed2f",
|
||||
"c9.ide.find.infiles": "#c0a13737ef",
|
||||
"c9.ide.find.infiles": "#bd34c29373",
|
||||
"c9.ide.find.replace": "#810ebf8bfb",
|
||||
"c9.ide.run.debug": "#ef40edcc3f",
|
||||
"c9.ide.run.debug": "#94a48978bf",
|
||||
"c9.automate": "#47e2c429c9",
|
||||
"c9.ide.ace.emmet": "#6dc4585e02",
|
||||
"c9.ide.ace.gotoline": "#a8ff07c8f4",
|
||||
|
@ -90,23 +93,23 @@
|
|||
"c9.ide.format": "#5ec97fb083",
|
||||
"c9.ide.help.support": "#932fbb3743",
|
||||
"c9.ide.imgeditor": "#612e75ef4f",
|
||||
"c9.ide.immediate": "#19758abe08",
|
||||
"c9.ide.installer": "#1232d4e179",
|
||||
"c9.ide.language.python": "#330b80e3b2",
|
||||
"c9.ide.immediate": "#0e0c18066c",
|
||||
"c9.ide.installer": "#b2e4ba0a92",
|
||||
"c9.ide.language.python": "#aff0772c78",
|
||||
"c9.ide.language.go": "#6ce1c7a7ef",
|
||||
"c9.ide.mount": "#4c39359b87",
|
||||
"c9.ide.navigate": "#0b7ec7936c",
|
||||
"c9.ide.mount": "#6ddfd05db3",
|
||||
"c9.ide.navigate": "#5d5707058c",
|
||||
"c9.ide.newresource": "#981a408a7b",
|
||||
"c9.ide.openfiles": "#2ae85a9e33",
|
||||
"c9.ide.preview": "#5f5fff0185",
|
||||
"c9.ide.preview.browser": "#897177be7f",
|
||||
"c9.ide.preview.markdown": "#c3174d86e0",
|
||||
"c9.ide.pubsub": "#a85fb27eca",
|
||||
"c9.ide.readonly": "#719881e192",
|
||||
"c9.ide.pubsub": "#99b7289040",
|
||||
"c9.ide.readonly": "#cfd951ec16",
|
||||
"c9.ide.recentfiles": "#7c099abf40",
|
||||
"c9.ide.remote": "#301d2ab519",
|
||||
"c9.ide.processlist": "#2b12cd1bdd",
|
||||
"c9.ide.run": "#6bd4996a4e",
|
||||
"c9.ide.run": "#d661a7b847",
|
||||
"c9.ide.run.build": "#0598fff697",
|
||||
"c9.ide.run.debug.xdebug": "#9956689819",
|
||||
"c9.ide.save": "#25a63f31e2",
|
||||
|
|
|
@ -0,0 +1,86 @@
|
|||
/**
|
||||
* Server-side support for A/B testing experiments.
|
||||
*
|
||||
* Note that this plugin demands users and user IDs for most of its API,
|
||||
* where this is optional in the client-side implementation.
|
||||
*/
|
||||
main.consumes = ["analytics"];
|
||||
main.provides = ["abtesting"];
|
||||
module.exports = main;
|
||||
|
||||
function main(options, imports, register) {
|
||||
var analytics = imports["analytics"];
|
||||
var outplan = require("outplan");
|
||||
|
||||
var MS_PER_DAY = 1000 * 60 * 60 * 24;
|
||||
|
||||
outplan.configure({
|
||||
logFunction: function(e) {
|
||||
var label = e.name + " - " + e.event;
|
||||
analytics.track(label, { variation: e.params.name });
|
||||
}
|
||||
});
|
||||
|
||||
function create(name, choices, options) {
|
||||
return outplan.create(name, choices, options);
|
||||
}
|
||||
|
||||
function expose(experimentName, userId, options) {
|
||||
return outplan.expose(experimentName, userId, options);
|
||||
}
|
||||
|
||||
function isUserCreatedAfter(experimentDate, user) {
|
||||
if (!user || !user.date_add)
|
||||
throw new Error("Expected: user");
|
||||
var diffDays = (experimentDate - Date.now()) / MS_PER_DAY;
|
||||
if (diffDays > 20) {
|
||||
// Sanity check: new Date() takes zero-based month argument, one-based day argument
|
||||
throw new Error("Passed a date far in the future to isUserCreatedAfter()");
|
||||
}
|
||||
return user.date_add > experimentDate;
|
||||
}
|
||||
|
||||
register(null, {
|
||||
"abtesting": {
|
||||
/**
|
||||
* Create a new experiment. Alias for require("outplan").create()
|
||||
*
|
||||
* @param {String} name
|
||||
* The name of the experiment.
|
||||
* @param {String[]|Object[]} choices
|
||||
* A list of variations, e.g. ["A", "B"],
|
||||
* or variation objects, e.g. [{ name: "A", color: "#AAA" }, { name: "B", color: "#BBB" }]
|
||||
* @param {Object} [option]
|
||||
* Options for the experiment. This may also include
|
||||
* arguments for the distribution operator, e.g. weight.
|
||||
* @param {Function} [options.operator]
|
||||
* The distribution operator, e.g. outplan.WeightedChoice.
|
||||
*/
|
||||
create: create,
|
||||
|
||||
/**
|
||||
* Get the selected variation of an experiment, and call the log function with
|
||||
* an "expose" event to track its exposure.
|
||||
*
|
||||
* @param {String} name The experiment name.
|
||||
* @param {Number} userId A unique identifier for the current user.
|
||||
* @param {Object} [options] Options
|
||||
* @param {Boolean} [options.log=true] Whether to log an "exposure event"
|
||||
*/
|
||||
expose: expose,
|
||||
|
||||
/**
|
||||
* Helper to determine if the current user was created after the start of an experiment.
|
||||
*
|
||||
* @throws {Error} when a date in the future (~20 days from now) is passed.
|
||||
* This error is thrown as a sanity check to make sure `new Date()`
|
||||
* is called with a zero-based month argument (and a one-based day).
|
||||
*
|
||||
* @param {Date} experimentDate
|
||||
* @param {Object} user A user object
|
||||
* @param {Number} user.date_add
|
||||
*/
|
||||
isUserCreatedAfter: isUserCreatedAfter,
|
||||
}
|
||||
});
|
||||
}
|
|
@ -30,85 +30,43 @@ define(function(require, exports, module) {
|
|||
return '"' + name + '"';
|
||||
};
|
||||
|
||||
var SupportedIcons = {
|
||||
"c9search": "page_white_magnify",
|
||||
"js": "page_white_code",
|
||||
"jsx": "page_white_code_red",
|
||||
"ts": "page_white_code",
|
||||
"tsx": "page_white_code_red",
|
||||
"json": "page_white_code",
|
||||
"css": "css",
|
||||
"scss": "css",
|
||||
"sass": "css",
|
||||
"less": "css",
|
||||
"xml": "page_white_code_red",
|
||||
"svg": "page_white_picture",
|
||||
"php": "page_white_php",
|
||||
"phtml": "page_white_php",
|
||||
"html": "html",
|
||||
"xhtml": "html",
|
||||
"coffee": "page_white_cup",
|
||||
"py": "page_white_code",
|
||||
"go": "page_white_code",
|
||||
"java": "page_white_cup",
|
||||
"logic": "logiql",
|
||||
"ru": "page_white_ruby",
|
||||
"gemspec": "page_white_ruby",
|
||||
"rake": "page_white_ruby",
|
||||
"rb": "page_white_ruby",
|
||||
"c": "page_white_c",
|
||||
"cc": "page_white_c",
|
||||
"cpp": "page_white_cplusplus",
|
||||
"cxx": "page_white_c",
|
||||
"h": "page_white_h",
|
||||
"hh": "page_white_h",
|
||||
"hpp": "page_white_h",
|
||||
"bmp": "image",
|
||||
"djv": "image",
|
||||
"djvu": "image",
|
||||
"gif": "image",
|
||||
"ico": "image",
|
||||
"jpeg": "image",
|
||||
"jpg": "image",
|
||||
"pbm": "image",
|
||||
"pgm": "image",
|
||||
"png": "image",
|
||||
"pnm": "image",
|
||||
"ppm": "image",
|
||||
"psd": "image",
|
||||
"svgz": "image",
|
||||
"tif": "image",
|
||||
"tiff": "image",
|
||||
"xbm": "image",
|
||||
"xpm": "image",
|
||||
"pdf": "page_white_acrobat",
|
||||
"clj": "page_white_code",
|
||||
"ml": "page_white_code",
|
||||
"mli": "page_white_code",
|
||||
"cfm": "page_white_coldfusion",
|
||||
"sql": "page_white_database",
|
||||
"db": "page_white_database",
|
||||
"sh": "page_white_wrench",
|
||||
"bash": "page_white_wrench",
|
||||
"xq": "page_white_code",
|
||||
"xz": "page_white_zip",
|
||||
"gz": "page_white_zip",
|
||||
"bz": "page_white_zip",
|
||||
"zip": "page_white_zip",
|
||||
"tar": "page_white_zip",
|
||||
"rar": "page_white_compressed",
|
||||
"exe": "page_white_swoosh",
|
||||
"o": "page_white_swoosh",
|
||||
"lnk": "page_white_swoosh",
|
||||
"txt": "page_white_text",
|
||||
"settings": "page_white_gear",
|
||||
"run": "page_white_gear",
|
||||
"build": "page_white_gear",
|
||||
"gitignore": "page_white_gear",
|
||||
"profile": "page_white_gear",
|
||||
"bashrc": "page_white_gear",
|
||||
};
|
||||
|
||||
var SupportedIcons = (function() {
|
||||
var extToClass = Object.create(null);
|
||||
var classToExt = {
|
||||
"page_white_magnify": "c9search",
|
||||
"page_white_code": ["clj", "go", "js", "json", "ml", "mli", "py", "ts", "xq"],
|
||||
"page_white_code_red": ["jsx", "tsx", "xml"],
|
||||
"css": ["css", "less", "sass", "scss"],
|
||||
"page_white_picture": "svg",
|
||||
"page_white_php": ["php", "phtml"],
|
||||
"html": ["html", "xhtml"],
|
||||
"page_white_cup": ["coffee", "java"],
|
||||
"logiql": "logic",
|
||||
"page_white_ruby": ["gemspec", "rake", "rb", "ru"],
|
||||
"page_white_c": ["c", "cc", "cxx"],
|
||||
"page_white_cplusplus": "cpp",
|
||||
"page_white_h": ["h", "hh", "hpp"],
|
||||
"image": ["bmp", "djv", "djvu", "gif", "ico", "jpeg", "jpg", "pbm", "pgm", "png", "pnm", "ppm", "psd", "svgz", "tif", "tiff", "xbm", "xpm"],
|
||||
"page_white_acrobat": "pdf",
|
||||
"page_white_coldfusion": "cfm",
|
||||
"page_white_database": ["db", "sql"],
|
||||
"page_white_wrench": ["bash", "sh"],
|
||||
"page_white_zip": ["bz", "gz", "tar", "xz", "zip"],
|
||||
"page_white_compressed": "rar",
|
||||
"page_white_swoosh": ["exe", "lnk", "o", "bin", "class"],
|
||||
"page_white_text": "txt",
|
||||
"page_white_gear": ["bashrc", "build", "gitignore", "profile", "run", "settings"]
|
||||
};
|
||||
Object.keys(classToExt).forEach(function(k) {
|
||||
var exts = classToExt[k];
|
||||
if (typeof exts == "string")
|
||||
exts = [exts];
|
||||
exts.forEach(function(ext) {
|
||||
extToClass[ext] = k;
|
||||
});
|
||||
});
|
||||
return extToClass;
|
||||
})();
|
||||
plugin.getFileIcon = function(name) {
|
||||
var icon = "page_white_text";
|
||||
var ext;
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
</p>
|
||||
|
||||
<a href="http://status.c9.io">Status Page</a> |
|
||||
<a href="mailto:support@c9.io">Support</a> |
|
||||
<a href="https://c9.io/support">Support</a> |
|
||||
<a href="https://c9.io/dashboard.html">Dashboard</a> |
|
||||
<a href="https://c9.io">Home</a>
|
||||
</div>
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
</p>
|
||||
|
||||
<a href="http://status.c9.io">Status Page</a> |
|
||||
<a href="mailto:support@c9.io">Support</a> |
|
||||
<a href="https://c9.io/support">Support</a> |
|
||||
<a href="https://c9.io/dashboard.html">Dashboard</a> |
|
||||
<a href="https://c9.io/">Home</a>
|
||||
</div>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
<% } %>
|
||||
|
||||
<a href="http://status.c9.io">Status Page</a> |
|
||||
<a href="mailto:support@c9.io">Support</a> |
|
||||
<a href="https://c9.io/support">Support</a> |
|
||||
<a href="https://c9.io/dashboard.html">Dashboard</a> |
|
||||
<a href="https://c9.io/">Home</a>
|
||||
</div>
|
||||
|
|
|
@ -29,7 +29,7 @@
|
|||
<% } %>
|
||||
|
||||
<a href="http://status.c9.io">Status Page</a> |
|
||||
<a href="mailto:support@c9.io">Support</a> |
|
||||
<a href="https://c9.io/support">Support</a> |
|
||||
<a href="https://c9.io/dashboard.html">Dashboard</a> |
|
||||
<a href="https://c9.io/">Home</a>
|
||||
</div>
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<% } %>
|
||||
|
||||
<a href="http://status.c9.io">Status Page</a> |
|
||||
<a href="mailto:support@c9.io">Support</a> |
|
||||
<a href="https://c9.io/support">Support</a> |
|
||||
<a href="https://c9.io/dashboard.html">Dashboard</a> |
|
||||
<a href="https://c9.io">Home</a>
|
||||
</div>
|
||||
|
|
|
@ -369,10 +369,10 @@ define(function(require, exports, module) {
|
|||
createNode(dir, {mime: "folder"});
|
||||
});
|
||||
|
||||
if (!dirsToMake[0])
|
||||
var node = dirsToMake[0] && findNode(dirsToMake[0]);
|
||||
if (!node)
|
||||
return;
|
||||
|
||||
var node = findNode(dirsToMake[0]);
|
||||
e.undo = function(){
|
||||
dirsToMake.forEach(function(dir) {
|
||||
var node = findNode(dir);
|
||||
|
@ -570,7 +570,7 @@ define(function(require, exports, module) {
|
|||
node = {label: p, path: subPath, status: "pending", isFolder: true};
|
||||
// TODO filter hidden files in getChildren instead.
|
||||
if (!showHidden && isFileHidden(p)) {
|
||||
orphans[node.path] = path;
|
||||
orphans[node.path] = node;
|
||||
return;
|
||||
}
|
||||
} else if (updateNode) {
|
||||
|
@ -707,7 +707,7 @@ define(function(require, exports, module) {
|
|||
status: "pending",
|
||||
className: "projectRoot",
|
||||
isEditable: false,
|
||||
map: {}
|
||||
map: Object.create(null)
|
||||
};
|
||||
var root = {};
|
||||
root.map = Object.create(null);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
e
|
|
@ -0,0 +1 @@
|
|||
v
|
|
@ -0,0 +1 @@
|
|||
i
|
|
@ -0,0 +1 @@
|
|||
l
|
|
@ -0,0 +1,105 @@
|
|||
/**
|
||||
* Client-side support for A/B testing experiments.
|
||||
*/
|
||||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
main.consumes = ["Plugin", "info", "c9.analytics"];
|
||||
main.provides = ["abtesting"];
|
||||
return main;
|
||||
|
||||
function main(options, imports, register) {
|
||||
var Plugin = imports.Plugin;
|
||||
var plugin = new Plugin("Ajax.org", main.consumes);
|
||||
var info = imports.info;
|
||||
var analytics = imports["c9.analytics"];
|
||||
var outplan = require("outplan");
|
||||
|
||||
var MS_PER_DAY = 1000 * 60 * 60 * 24;
|
||||
|
||||
var userId;
|
||||
|
||||
plugin.on("load", function() {
|
||||
userId = info.getUser().id;
|
||||
outplan.configure({
|
||||
logFunction: function(e) {
|
||||
var label = e.name + " - " + e.event;
|
||||
analytics.track(label, { variation: e.params.name });
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
plugin.on("unload", function() {
|
||||
userId = undefined;
|
||||
});
|
||||
|
||||
function create(name, choices, options) {
|
||||
var experiment = outplan.create(name, choices, options);
|
||||
experiment.expose = expose.bind(null, name);
|
||||
return experiment;
|
||||
}
|
||||
|
||||
function expose(experimentName, overrideUserId, options) {
|
||||
if (overrideUserId && typeof overrideUserId === "object")
|
||||
return expose(experimentName, null, options);
|
||||
|
||||
return outplan.expose(experimentName, overrideUserId == null ? userId : overrideUserId, options);
|
||||
}
|
||||
|
||||
function isUserCreatedAfter(experimentDate) {
|
||||
var diffDays = (experimentDate - Date.now()) / MS_PER_DAY;
|
||||
if (diffDays > 20) {
|
||||
// Sanity check: new Date() takes zero-based month argument, one-based day argument
|
||||
throw new Error("Passed a date far in the future to isUserCreatedAfter()");
|
||||
}
|
||||
return info.getUser().date_add > experimentDate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Support for A/B testing experiments.
|
||||
*/
|
||||
plugin.freezePublicAPI({
|
||||
/**
|
||||
* Create a new experiment. Alias for require("outplan").create()
|
||||
*
|
||||
* @param {String} name
|
||||
* The name of the experiment.
|
||||
* @param {String[]|Object[]} choices
|
||||
* A list of variations, e.g. ["A", "B"],
|
||||
* or variation objects, e.g. [{ name: "A", color: "#AAA" }, { name: "B", color: "#BBB" }]
|
||||
* @param {Object} [option]
|
||||
* Options for the experiment. This may also include
|
||||
* arguments for the distribution operator, e.g. weight.
|
||||
* @param {Function} [options.operator]
|
||||
* The distribution operator, e.g. outplan.WeightedChoice.
|
||||
*/
|
||||
create: create,
|
||||
|
||||
/**
|
||||
* Get the selected variation of an experiment, and call the log function with
|
||||
* an "expose" event to track its exposure.
|
||||
*
|
||||
* @param {String} name The experiment name.
|
||||
* @param {Number} [userId] A unique identifier for the current user.
|
||||
* @param {Object} [options] Options
|
||||
* @param {Boolean} [options.log=true] Whether to log an "exposure event"
|
||||
*/
|
||||
expose: expose,
|
||||
|
||||
/**
|
||||
* Helper to determine if the current user was created after the start of an experiment.
|
||||
*
|
||||
* @throws {Error} when a date in the future (~20 days from now) is passed.
|
||||
* This error is thrown as a sanity check to make sure `new Date()`
|
||||
* is called with a zero-based month argument (and a one-based day).
|
||||
*
|
||||
* @param {Date} experimentDate
|
||||
*/
|
||||
isUserCreatedAfter: isUserCreatedAfter,
|
||||
});
|
||||
|
||||
register(null, {
|
||||
"abtesting": plugin
|
||||
});
|
||||
}
|
||||
});
|
|
@ -976,11 +976,12 @@ define(function(require, exports, module) {
|
|||
|
||||
c = 0;
|
||||
|
||||
addEditorMenu("Edit/Code Folding/Fold", "fold"),
|
||||
addEditorMenu("Edit/Code Folding/Toggle Fold", "toggleFoldWidget"),
|
||||
addEditorMenu("Edit/Code Folding/Unfold", "unfold"),
|
||||
|
||||
menus.addItemByPath("Edit/Code Folding/~", new ui.divider(), c += 100, handle);
|
||||
addEditorMenu("Edit/Code Folding/Fold All", "foldall"),
|
||||
addEditorMenu("Edit/Code Folding/Fold Other", "foldOther");
|
||||
addEditorMenu("Edit/Code Folding/Fold All", "foldall");
|
||||
addEditorMenu("Edit/Code Folding/Unfold All", "unfoldall");
|
||||
|
||||
c = 0;
|
||||
|
|
|
@ -51,21 +51,19 @@ define(function(require, exports, module) {
|
|||
function set(type, data, list) {
|
||||
if (notSupported(type))
|
||||
return;
|
||||
|
||||
type = convertType(type);
|
||||
|
||||
if (nativeObject) {
|
||||
nativeObject.setData(type, data);
|
||||
handleClipboardData(nativeObject, type, data);
|
||||
return true;
|
||||
}
|
||||
|
||||
var setData = function(e) {
|
||||
if (list) {
|
||||
list.forEach(function(type) {
|
||||
e.clipboardData.setData(type, data);
|
||||
handleClipboardData(e.clipboardData, type, data);
|
||||
});
|
||||
}
|
||||
e.clipboardData.setData(type, data);
|
||||
handleClipboardData(e.clipboardData, type, data);
|
||||
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
|
@ -82,17 +80,15 @@ define(function(require, exports, module) {
|
|||
function get(type, full) {
|
||||
if (notSupported(type))
|
||||
return;
|
||||
|
||||
type = convertType(type);
|
||||
|
||||
if (!full && nativeObject)
|
||||
return nativeObject.getData(type);
|
||||
return handleClipboardData(nativeObject, type);
|
||||
|
||||
var data;
|
||||
var getData = function(e) {
|
||||
data = full
|
||||
? e.clipboardData
|
||||
: e.clipboardData.getData(type);
|
||||
: handleClipboardData(e.clipboardData, type);
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
@ -120,8 +116,22 @@ define(function(require, exports, module) {
|
|||
return !/text($|\/)/.test(type);
|
||||
}
|
||||
|
||||
function convertType(type) {
|
||||
return document.all ? "Text" : type;
|
||||
function handleClipboardData(clipboardData, type, data, forceIEMime) {
|
||||
if (!clipboardData)
|
||||
return;
|
||||
// using "Text" doesn't work on old webkit but ie needs it
|
||||
var mime = forceIEMime ? "Text" : type;
|
||||
try {
|
||||
if (data) {
|
||||
// Safari 5 has clipboardData object, but does not handle setData()
|
||||
return clipboardData.setData(mime, data) !== false;
|
||||
} else {
|
||||
return clipboardData.getData(mime);
|
||||
}
|
||||
} catch(e) {
|
||||
if (!forceIEMime)
|
||||
return handleClipboardData(clipboardData, type, data, true);
|
||||
}
|
||||
}
|
||||
|
||||
function wrap(obj) {
|
||||
|
|
|
@ -2,7 +2,7 @@ define(function(require, exports, module) {
|
|||
"use strict";
|
||||
|
||||
main.consumes = [
|
||||
"Plugin", "c9", "ui", "menus", "tree", "info", "vfs"
|
||||
"Plugin", "c9", "ui", "menus", "tree", "info", "vfs", "preferences", "settings"
|
||||
];
|
||||
main.provides = ["download"];
|
||||
return main;
|
||||
|
@ -15,7 +15,12 @@ define(function(require, exports, module) {
|
|||
var tree = imports.tree;
|
||||
var vfs = imports.vfs;
|
||||
var info = imports.info;
|
||||
|
||||
var prefs = imports.preferences;
|
||||
var settings = imports.settings;
|
||||
|
||||
var SETTING_NAME = "downloadFilesAs";
|
||||
var SETTING_PATH = "user/general/@" + SETTING_NAME;
|
||||
|
||||
/***** Initialization *****/
|
||||
|
||||
var plugin = new Plugin("Ajax.org", main.consumes);
|
||||
|
@ -40,6 +45,28 @@ define(function(require, exports, module) {
|
|||
onclick: download
|
||||
}), 140, plugin);
|
||||
});
|
||||
|
||||
// Preferences
|
||||
prefs.add({
|
||||
"General" : {
|
||||
"Tree & Navigate" : {
|
||||
"Download Files As" : {
|
||||
type: "dropdown",
|
||||
path: SETTING_PATH,
|
||||
items: [
|
||||
{ caption : "auto", value : "auto" },
|
||||
{ caption : "tar.gz", value : "tar.gz" },
|
||||
{ caption : "zip", value : "zip" }
|
||||
],
|
||||
position: 5000
|
||||
}
|
||||
}
|
||||
}
|
||||
}, plugin);
|
||||
|
||||
settings.on("read", function() {
|
||||
settings.setDefaults("user/general", [[SETTING_NAME, "auto"]]);
|
||||
}, plugin);
|
||||
}
|
||||
|
||||
function download() {
|
||||
|
@ -55,25 +82,40 @@ define(function(require, exports, module) {
|
|||
if (node.isFolder && node.path == "/")
|
||||
downloadProject();
|
||||
else if (paths.length > 1)
|
||||
vfs.download(paths);
|
||||
downloadPaths(paths);
|
||||
else if (node.isFolder)
|
||||
downloadFolder(node.path);
|
||||
else
|
||||
downloadFile(node.path);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
function downloadProject() {
|
||||
vfs.download("/", info.getWorkspace().name + ".tar.gz");
|
||||
vfs.download("/", info.getWorkspace().name + getArchiveFileExtension());
|
||||
}
|
||||
|
||||
function downloadPaths(paths) {
|
||||
vfs.download(paths, info.getWorkspace().name + getArchiveFileExtension());
|
||||
}
|
||||
|
||||
function downloadFolder(path) {
|
||||
vfs.download(path.replace(/\/*$/, "/"));
|
||||
var withTrailingSlash = path.replace(/\/*$/, "/");
|
||||
var parts = withTrailingSlash.split("/");
|
||||
var lastPart = parts[parts.length - 2];
|
||||
vfs.download(withTrailingSlash, lastPart + getArchiveFileExtension());
|
||||
}
|
||||
|
||||
|
||||
function downloadFile(path) {
|
||||
vfs.download(path.replace(/\/*$/, ""), null, true);
|
||||
}
|
||||
|
||||
function getArchiveFileExtension() {
|
||||
var downloadFilesAs = settings.get(SETTING_PATH);
|
||||
if (downloadFilesAs === 'auto' || !downloadFilesAs) {
|
||||
downloadFilesAs = /Win/.test(navigator.platform) ? 'zip' : 'tar.gz';
|
||||
}
|
||||
return '.' + downloadFilesAs;
|
||||
}
|
||||
|
||||
/***** Lifecycle *****/
|
||||
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
/**
|
||||
* Dummy implementation of experiments.
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
plugin.consumes = [];
|
||||
plugin.provides = ["experiment"];
|
||||
|
||||
module.exports = plugin;
|
||||
|
||||
function plugin(options, imports, register) {
|
||||
|
||||
register(null, {
|
||||
"experiment": {
|
||||
configure: function() {},
|
||||
onStart: function() {
|
||||
var chain = {
|
||||
variation: function() {
|
||||
return chain;
|
||||
}
|
||||
};
|
||||
return chain;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
|
@ -33,6 +33,10 @@
|
|||
padding-left: 33px !important;
|
||||
}
|
||||
|
||||
.c9-menu-btnEmpty {
|
||||
padding-left: 9px;
|
||||
}
|
||||
|
||||
.c9-menu-btnDown:not(.c9-menu-btnmenuDown){
|
||||
box-shadow: none;
|
||||
border: 0;
|
||||
|
@ -512,4 +516,4 @@ body .runner-form-header{
|
|||
.runtestbtn .icon{
|
||||
height: 21px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,9 +92,9 @@ define(function(require, exports, module) {
|
|||
delete extraPackages[config.packagePath];
|
||||
}
|
||||
});
|
||||
Object.keys(extraPackages).forEach(function(extraConfig) {
|
||||
Object.keys(extraPackages).forEach(function(packagePath) {
|
||||
console.warn("[c9.ide.loader] Package "
|
||||
+ extraConfig.packagePath + " should be installed, according "
|
||||
+ packagePath + " should be installed, according "
|
||||
+ "to the database, but was not found on the filesystem. "
|
||||
+ "Try reinstalling it.");
|
||||
});
|
||||
|
|
|
@ -41,6 +41,7 @@ define(function(require, exports, module) {
|
|||
ui: "lib/ui",
|
||||
c9: "lib/c9",
|
||||
frontdoor: "lib/frontdoor",
|
||||
outplan: "lib/outplan/dist/outplan",
|
||||
};
|
||||
|
||||
if (whitelist === "*") {
|
||||
|
@ -70,6 +71,7 @@ define(function(require, exports, module) {
|
|||
"ui",
|
||||
"emmet",
|
||||
"frontdoor",
|
||||
"outplan",
|
||||
"mocha", // TESTING
|
||||
"chai", // TESTING
|
||||
].forEach(function(name) {
|
||||
|
@ -86,9 +88,11 @@ define(function(require, exports, module) {
|
|||
}]);
|
||||
|
||||
statics.addStatics(externalPlugins.map(function(plugin) {
|
||||
if (typeof plugin == "string")
|
||||
plugin = { path: plugin, mount: plugin};
|
||||
return {
|
||||
path: __dirname + "/../../node_modules/" + plugin,
|
||||
mount: "/plugins/" + plugin
|
||||
path: __dirname + "/../../node_modules/" + plugin.path,
|
||||
mount: "/plugins/" + plugin.mount
|
||||
};
|
||||
}));
|
||||
|
||||
|
|
|
@ -155,6 +155,11 @@ define(function(require, exports, module) {
|
|||
str += this.getLine(end, newLineChar).substring(0, range.end.column);
|
||||
return str;
|
||||
};
|
||||
|
||||
session.doc.getValue = function() {
|
||||
return this.getTextRange(new Range(0, 0, this.getLength(), Number.MAX_VALUE));
|
||||
};
|
||||
|
||||
session.$computeWidth =
|
||||
session.getScreenWidth = function () {
|
||||
return this.term.cols;
|
||||
|
|
|
@ -537,7 +537,7 @@ define(function(require, exports, module) {
|
|||
if (err) {
|
||||
var message = err.message;
|
||||
if (err.code == "EEXIST")
|
||||
message = "File " + path + " already exists.";
|
||||
message = "File " + newpath + " already exists.";
|
||||
return showError(message);
|
||||
}
|
||||
if (dirname(newpath) != dirname(path))
|
||||
|
|
|
@ -91,11 +91,13 @@ apf.codebox = function(struct, tagName) {
|
|||
var checkInitial = function() {
|
||||
var value = ace.getValue();
|
||||
if (value && ace.renderer.initialMessageNode) {
|
||||
ace.renderer.off("afterRender", checkInitial);
|
||||
dom.removeCssClass(ace.container, "ace_initialMsg");
|
||||
ace.renderer.scroller.removeChild(ace.renderer.initialMessageNode);
|
||||
ace.renderer.initialMessageNode = null;
|
||||
}
|
||||
else if (!value && !ace.renderer.initialMessageNode) {
|
||||
ace.renderer.on("afterRender", checkInitial);
|
||||
dom.addCssClass(ace.container, "ace_initialMsg");
|
||||
var el = document.createElement("div");
|
||||
el.className = "tb_textboxInitialMsg";
|
||||
|
@ -103,7 +105,6 @@ apf.codebox = function(struct, tagName) {
|
|||
ace.renderer.initialMessageNode = el;
|
||||
ace.renderer.scroller.appendChild(ace.renderer.initialMessageNode);
|
||||
}
|
||||
|
||||
};
|
||||
ace.on("input", checkInitial);
|
||||
|
||||
|
|
|
@ -0,0 +1,18 @@
|
|||
"use strict";
|
||||
|
||||
var HttpError = require("http-error");
|
||||
|
||||
function isDotFile(path){
|
||||
return /^[.]/.test(path) ;
|
||||
}
|
||||
|
||||
module.exports = function blockDotFiles(req, res, next){
|
||||
if (!req.params.path) return next();
|
||||
|
||||
var pathParts = req.params.path.split("/");
|
||||
|
||||
if (pathParts.some(isDotFile))
|
||||
return next(new HttpError.NotFound("File does not exist"));
|
||||
|
||||
next();
|
||||
};
|
|
@ -0,0 +1,67 @@
|
|||
"use struct";
|
||||
"use server";
|
||||
|
||||
require("c9/inline-mocha")(module);
|
||||
|
||||
var blockDotFiles = require("./block-dot-files");
|
||||
var async = require("async");
|
||||
var format = require("util").format;
|
||||
var assert = require("assert-diff");
|
||||
|
||||
var HttpError = require("http-error");
|
||||
|
||||
describe(__filename, function() {
|
||||
it("should block acess to files starting with a dot", function(done) {
|
||||
|
||||
var err404 = new HttpError.NotFound("File does not exist");
|
||||
|
||||
var cases = [
|
||||
{
|
||||
label: "Block ../",
|
||||
path: "../../../../etc/password",
|
||||
err: err404
|
||||
},
|
||||
{
|
||||
label: "Block anything starting with a .",
|
||||
path: ".ssh/id_rsa",
|
||||
err: err404
|
||||
},
|
||||
{
|
||||
label: "Block anything starting with a .",
|
||||
path: ".git/config",
|
||||
err: err404
|
||||
},
|
||||
{
|
||||
label: "Block anything with a . in the start of a pathpart",
|
||||
path: "deep/.git/config",
|
||||
err: err404
|
||||
},
|
||||
{
|
||||
label: "Don't block normal paths",
|
||||
path: "one/two/three.txt",
|
||||
},
|
||||
{
|
||||
label: "Don't block empty paths",
|
||||
path: "",
|
||||
},
|
||||
{
|
||||
label: "Don't choke on undefineds",
|
||||
},
|
||||
|
||||
];
|
||||
|
||||
|
||||
async.each(cases, function(testCase, next) {
|
||||
var mockReq = {
|
||||
params: {
|
||||
path: testCase.path
|
||||
}
|
||||
};
|
||||
|
||||
blockDotFiles(mockReq, null, function(err) {
|
||||
assert.deepEqual(err, testCase.err, testCase.label);
|
||||
next();
|
||||
});
|
||||
}, done);
|
||||
});
|
||||
});
|
|
@ -52,7 +52,7 @@ define(function(require, exports, module) {
|
|||
}, [
|
||||
requestTimeout(15*60*1000),
|
||||
require("./lib/middleware/sanitize-path-param"),
|
||||
ratelimit("username", 20 * 1000, 1000),
|
||||
require("./lib/middleware/block-dot-files"),
|
||||
handler.getProjectSession(),
|
||||
handler.getRole(db),
|
||||
handler.getProxyUrl(function() {
|
||||
|
@ -85,4 +85,4 @@ define(function(require, exports, module) {
|
|||
|
||||
register();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
</p>
|
||||
|
||||
<a href="http://status.c9.io">Status Page</a> |
|
||||
<a href="mailto:support@c9.io">Support</a> |
|
||||
<a href="https://c9.io/support">Support</a> |
|
||||
<a href="https://c9.io/dashboard.html">Dashboard</a> |
|
||||
<a href="https://c9.io">Home</a>
|
||||
</div>
|
||||
|
|
|
@ -17,7 +17,7 @@ require("amd-loader");
|
|||
|
||||
var build, options, pathConfig;
|
||||
|
||||
describe("The Module", function(){
|
||||
describe("The build module", function(){
|
||||
this.timeout(60000);
|
||||
|
||||
beforeEach(function(next) {
|
||||
|
@ -63,7 +63,7 @@ describe("The Module", function(){
|
|||
});
|
||||
});
|
||||
|
||||
it("test compile less", function(done) {
|
||||
it("should compile less", function(done) {
|
||||
build.buildSkin("ssh", "dark", pathConfig, function(err, result) {
|
||||
if (err) return done(err);
|
||||
|
||||
|
@ -71,6 +71,28 @@ describe("The Module", function(){
|
|||
assert(code);
|
||||
done(err);
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("should remove comments", function(done) {
|
||||
var removeLicenceComments = require("architect-build/module-deps").removeLicenceComments;
|
||||
function remove(src) {
|
||||
var module = { source: "" + src, path: ".js" };
|
||||
removeLicenceComments(module);
|
||||
return module.source;
|
||||
}
|
||||
assert.equal(remove("" + function() {
|
||||
// 1
|
||||
var a;
|
||||
/***/ // hello
|
||||
var x; // not removed
|
||||
/* asd
|
||||
*/
|
||||
x += "he/*ll*/o" + a;
|
||||
}) , function() {
|
||||
var a;
|
||||
var x; // not removed
|
||||
x += "he/*ll*/o" + a;
|
||||
});
|
||||
done();
|
||||
});
|
||||
});
|
|
@ -20,6 +20,8 @@ define(function (require, exports, module) {
|
|||
if (loaded) return false;
|
||||
loaded = true;
|
||||
|
||||
if (c9.readonly) return false;
|
||||
|
||||
ext.loadRemotePlugin("log", {
|
||||
code: require("text!./log-service.js"),
|
||||
redefine: true
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
define(function(require, exports, module) {
|
||||
"use strict";
|
||||
|
||||
main.consumes = ["Plugin", "ext", "c9", "vfs", "metrics"];
|
||||
main.consumes = ["Plugin", "ext", "c9", "vfs"];
|
||||
main.provides = ["vfs.ping"];
|
||||
return main;
|
||||
|
||||
|
@ -9,7 +9,6 @@ define(function(require, exports, module) {
|
|||
var Plugin = imports.Plugin;
|
||||
var c9 = imports.c9;
|
||||
var ext = imports.ext;
|
||||
var metrics = imports.metrics;
|
||||
|
||||
/***** Initialization *****/
|
||||
|
||||
|
@ -17,15 +16,18 @@ define(function(require, exports, module) {
|
|||
var api;
|
||||
|
||||
var loaded = false;
|
||||
function load(){
|
||||
if (loaded) return;
|
||||
function load(oldVfs) {
|
||||
if (loaded && !oldVfs) return;
|
||||
loaded = true;
|
||||
|
||||
|
||||
ext.loadRemotePlugin("ping", {
|
||||
code: require("text!./ping-service.js"),
|
||||
redefine: true
|
||||
file: oldVfs ? undefined : "c9.vfs.client/ping-service.js",
|
||||
code: oldVfs ? require("text!./ping-service.js") : undefined
|
||||
}, function(err, remote) {
|
||||
if (err)
|
||||
if (!remote && !oldVfs)
|
||||
return load(true);
|
||||
|
||||
if (!remote)
|
||||
return console.error(err);
|
||||
|
||||
api = remote;
|
||||
|
|
|
@ -204,11 +204,12 @@ define(function(require, exports, module) {
|
|||
|
||||
function reconnectNow() {
|
||||
reconnect(function(_err) {
|
||||
connection.connect();
|
||||
connection && connection.connect();
|
||||
});
|
||||
}
|
||||
|
||||
function reconnect(callback) {
|
||||
if (!connection) return;
|
||||
connection.socket.setSocket(null);
|
||||
|
||||
vfsEndpoint.get(protocolVersion, function(err, urls) {
|
||||
|
@ -336,6 +337,11 @@ define(function(require, exports, module) {
|
|||
plugin.on("unload", function(){
|
||||
loaded = false;
|
||||
|
||||
if (consumer)
|
||||
consumer.disconnect();
|
||||
if (connection)
|
||||
connection.disconnect();
|
||||
|
||||
id = null;
|
||||
buffer = [];
|
||||
region = null;
|
||||
|
@ -346,6 +352,7 @@ define(function(require, exports, module) {
|
|||
serviceUrl = null;
|
||||
eioOptions = null;
|
||||
consumer = null;
|
||||
connection = null;
|
||||
vfs = null;
|
||||
showErrorTimer = null;
|
||||
showErrorTimerMessage = null;
|
||||
|
|
|
@ -80,41 +80,62 @@ define(function(require, exports, module) {
|
|||
});
|
||||
}
|
||||
else {
|
||||
// TODO add support for downloding as zip on windows
|
||||
// var cwd;
|
||||
// var args = ["-r", "-"];
|
||||
// paths.forEach(function(path) {
|
||||
// if (!path) return;
|
||||
// var dir = Path.dirname(path);
|
||||
// if (!cwd) cwd = dir;
|
||||
// var name = Path.relative(cwd, path);
|
||||
// if (name[0] == "-") name = "./" + name;
|
||||
// args.push(name);
|
||||
// });
|
||||
// vfs.spawn("zip", { args: args, cwd: cwd }
|
||||
|
||||
var args = ["-zcf", "-"];
|
||||
paths.forEach(function(path) {
|
||||
var executable, args, contentType;
|
||||
|
||||
if (/\.zip$/.test(filename)) {
|
||||
executable = "zip";
|
||||
args = ["-r", "-", "--"];
|
||||
contentType = "application/zip"
|
||||
}
|
||||
else {
|
||||
executable = "tar";
|
||||
args = ["-zcf", "-", "--"];
|
||||
contentType = "application/x-gzip"
|
||||
}
|
||||
|
||||
// Find the longest common parent directory of all the paths.
|
||||
var cwd = null;
|
||||
paths.forEach(function (path) {
|
||||
if (!path) return;
|
||||
var dir = Path.dirname(path);
|
||||
var name = Path.basename(path);
|
||||
if (name[0] == "-")
|
||||
name = "--add-file=" + name;
|
||||
args.push("-C" + dir, name);
|
||||
if (!cwd) {
|
||||
cwd = dir;
|
||||
}
|
||||
else {
|
||||
var relative = Path.relative(cwd, dir).split(Path.sep);
|
||||
var i = 0;
|
||||
while (relative[i] === '..') {
|
||||
cwd = Path.resolve(cwd, '..');
|
||||
i++;
|
||||
}
|
||||
}
|
||||
});
|
||||
vfs.spawn("tar", { args: args }, function (err, meta) {
|
||||
paths.forEach(function(path) {
|
||||
if (!path) return;
|
||||
path = Path.relative(cwd, path);
|
||||
// tar misinterprets the Windows path separator as an escape sequence, so use forward slash.
|
||||
if (Path.sep === '\\') {
|
||||
path = path.replace(/\\/g, '/');
|
||||
}
|
||||
args.push(path);
|
||||
});
|
||||
|
||||
vfs.spawn(executable, {
|
||||
args: args,
|
||||
cwd: cwd
|
||||
}, function (err, meta) {
|
||||
if (err)
|
||||
return next(err);
|
||||
|
||||
|
||||
process = meta.process;
|
||||
|
||||
// once we receive data on stdout pipe it to the response
|
||||
|
||||
// once we receive data on stdout pipe it to the response
|
||||
process.stdout.once("data", function (data) {
|
||||
if (res.headerSent)
|
||||
return;
|
||||
|
||||
res.writeHead(200, {
|
||||
"Content-Type": "application/x-gzip",
|
||||
"Content-Type": contentType,
|
||||
"Content-Disposition": filenameHeader
|
||||
});
|
||||
res.write(data);
|
||||
|
@ -125,7 +146,7 @@ define(function(require, exports, module) {
|
|||
process.stderr.on("data", function (data) {
|
||||
stderr += data;
|
||||
});
|
||||
|
||||
|
||||
process.on("exit", function(code, signal) {
|
||||
if (res.headerSent)
|
||||
return;
|
||||
|
@ -133,16 +154,16 @@ define(function(require, exports, module) {
|
|||
var err;
|
||||
if (code == 127) {
|
||||
err = new error.PreconditionFailed(
|
||||
"Your instance seems to be missing the 'tar' utility\n" +
|
||||
"Your instance seems to be missing the '" + executable + "' utility\n" +
|
||||
"If you are using an SSH workspace, please do:\n" +
|
||||
" 'sudo apt-get install tar'");
|
||||
" 'sudo apt-get install " + executable + "'");
|
||||
} else if (code) {
|
||||
err = new error.InternalServerError(
|
||||
"'tar' utility failed with exit code " + code +
|
||||
"'" + executable + "' utility failed with exit code " + code +
|
||||
" and stderr:/n'" + stderr + "'");
|
||||
} else if (signal) {
|
||||
err = new error.InternalServerError(
|
||||
"'tar' utility was terminated by signal " + signal
|
||||
"'" + executable + "' utility was terminated by signal " + signal
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -53,8 +53,9 @@ describe(__filename, function(){
|
|||
|
||||
describe("download", function() {
|
||||
|
||||
it("should download", function(next) {
|
||||
it("should download as tar", function(next) {
|
||||
tmp.dir({unsafeCleanup: true}, function(err, path) {
|
||||
path = path.replace(/\w:/, '');
|
||||
var filename = path + "/download.tar.gz";
|
||||
var file = fs.createWriteStream(filename);
|
||||
http.get("http://localhost:8787/?download=download.tar.gz", function(res) {
|
||||
|
@ -77,21 +78,22 @@ describe(__filename, function(){
|
|||
});
|
||||
});
|
||||
|
||||
it("should download sub directory", function(next) {
|
||||
it("should download sub directory as tar", function(next) {
|
||||
tmp.dir({unsafeCleanup: true}, function(err, path) {
|
||||
path = path.replace(/\w:/, '');
|
||||
assert.equal(err, null);
|
||||
|
||||
var filename = path + "/download.tar.gz";
|
||||
var file = fs.createWriteStream(filename);
|
||||
http.get("http://localhost:8787/views?download=download.tar.gz", function(res) {
|
||||
http.get("http://localhost:8787/test?download=download.tar.gz", function(res) {
|
||||
res.pipe(file);
|
||||
|
||||
res.on("end", function() {
|
||||
execFile("tar", ["-zxvf", filename, "views/status.html.ejs"], {cwd: path}, function(err) {
|
||||
execFile("tar", ["-zxvf", filename, "test/dir1/testdata1.txt"], {cwd: path}, function(err) {
|
||||
assert.equal(err, null);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/views/status.html.ejs", "utf8"),
|
||||
fs.readFileSync(path + "/views/status.html.ejs", "utf8")
|
||||
fs.readFileSync(__dirname + "/test/dir1/testdata1.txt", "utf8"),
|
||||
fs.readFileSync(path + "/test/dir1/testdata1.txt", "utf8")
|
||||
);
|
||||
next();
|
||||
});
|
||||
|
@ -102,22 +104,180 @@ describe(__filename, function(){
|
|||
|
||||
it("should download without specifying a name", function(next) {
|
||||
tmp.dir({unsafeCleanup: true}, function(err, path) {
|
||||
path = path.replace(/\w:/, '');
|
||||
assert.equal(err, null);
|
||||
|
||||
var filename = path + "/download.tar.gz";
|
||||
var file = fs.createWriteStream(filename);
|
||||
http.get("http://localhost:8787/views?download", function(res) {
|
||||
http.get("http://localhost:8787/test?download", function(res) {
|
||||
assert.equal(res.headers["content-type"], "application/x-gzip");
|
||||
assert.equal(res.headers["content-disposition"], "attachment; filename*=utf-8''views.tar.gz");
|
||||
assert.equal(res.headers["content-disposition"], "attachment; filename*=utf-8''test.tar.gz");
|
||||
|
||||
res.pipe(file);
|
||||
|
||||
res.on("end", function() {
|
||||
execFile("tar", ["-zxvf", filename, "views/status.html.ejs"], {cwd: path}, function(err) {
|
||||
execFile("tar", ["-zxvf", filename, "test/dir1/testdata1.txt"], {cwd: path}, function(err) {
|
||||
assert.equal(err, null);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/views/status.html.ejs", "utf8"),
|
||||
fs.readFileSync(path + "/views/status.html.ejs", "utf8")
|
||||
fs.readFileSync(__dirname + "/test/dir1/testdata1.txt", "utf8"),
|
||||
fs.readFileSync(path + "/test/dir1/testdata1.txt", "utf8")
|
||||
);
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should download several files in same directory as tar", function(next) {
|
||||
tmp.dir({unsafeCleanup: true}, function(err, path) {
|
||||
path = path.replace(/\w:/, '');
|
||||
assert.equal(err, null);
|
||||
|
||||
var filename = path + "/download.tar.gz";
|
||||
var file = fs.createWriteStream(filename);
|
||||
http.get("http://localhost:8787/test/dir2/testdata2a.txt,/test/dir2/testdata2b.txt?download=download.tar.gz", function(res) {
|
||||
res.pipe(file);
|
||||
res.on("end", function() {
|
||||
execFile("tar", ["-zxvf", filename], {cwd: path}, function(err) {
|
||||
assert.equal(err, null);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/test/dir2/testdata2a.txt", "utf8"),
|
||||
fs.readFileSync(path + "/testdata2a.txt", "utf8")
|
||||
);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/test/dir2/testdata2b.txt", "utf8"),
|
||||
fs.readFileSync(path + "/testdata2b.txt", "utf8")
|
||||
);
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should download several files in different directories as tar", function(next) {
|
||||
tmp.dir({unsafeCleanup: true}, function(err, path) {
|
||||
path = path.replace(/\w:/, '');
|
||||
assert.equal(err, null);
|
||||
|
||||
var filename = path + "/download.tar.gz";
|
||||
var file = fs.createWriteStream(filename);
|
||||
http.get("http://localhost:8787/test/dir1/testdata1.txt,/test/dir2/testdata2a.txt?download=download.tar.gz", function(res) {
|
||||
res.pipe(file);
|
||||
res.on("end", function() {
|
||||
execFile("tar", ["-zxvf", filename], {cwd: path}, function(err) {
|
||||
assert.equal(err, null);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/test/dir1/testdata1.txt", "utf8"),
|
||||
fs.readFileSync(path + "/dir1/testdata1.txt", "utf8")
|
||||
);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/test/dir2/testdata2a.txt", "utf8"),
|
||||
fs.readFileSync(path + "/dir2/testdata2a.txt", "utf8")
|
||||
);
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should download as zip", function(next) {
|
||||
tmp.dir({unsafeCleanup: true}, function(err, path) {
|
||||
path = path.replace(/\w:/, '');
|
||||
var filename = path + "/download.zip";
|
||||
var file = fs.createWriteStream(filename);
|
||||
http.get("http://localhost:8787/?download=download.zip", function(res) {
|
||||
assert.equal(res.headers["content-type"], "application/zip");
|
||||
assert.equal(res.headers["content-disposition"], "attachment; filename*=utf-8''download.zip");
|
||||
|
||||
res.pipe(file);
|
||||
|
||||
res.on("end", function() {
|
||||
execFile("unzip", [filename, "c9.vfs.server/download.js"], {cwd: path}, function(err, stdout, stderr) {
|
||||
assert.equal(err, null);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/download.js", "utf8"),
|
||||
fs.readFileSync(path + "/c9.vfs.server/download.js", "utf8")
|
||||
);
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should download sub directory as zip", function(next) {
|
||||
tmp.dir({unsafeCleanup: true}, function(err, path) {
|
||||
path = path.replace(/\w:/, '');
|
||||
assert.equal(err, null);
|
||||
|
||||
var filename = path + "/download.zip";
|
||||
var file = fs.createWriteStream(filename);
|
||||
http.get("http://localhost:8787/test?download=download.zip", function(res) {
|
||||
res.pipe(file);
|
||||
|
||||
res.on("end", function() {
|
||||
execFile("unzip", [filename, "test/dir1/testdata1.txt"], {cwd: path}, function(err) {
|
||||
assert.equal(err, null);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/test/dir1/testdata1.txt", "utf8"),
|
||||
fs.readFileSync(path + "/test/dir1/testdata1.txt", "utf8")
|
||||
);
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should download several files in same directory as zip", function(next) {
|
||||
tmp.dir({unsafeCleanup: true}, function(err, path) {
|
||||
path = path.replace(/\w:/, '');
|
||||
assert.equal(err, null);
|
||||
|
||||
var filename = path + "/download.zip";
|
||||
var file = fs.createWriteStream(filename);
|
||||
http.get("http://localhost:8787/test/dir2/testdata2a.txt,/test/dir2/testdata2b.txt?download=download.zip", function(res) {
|
||||
res.pipe(file);
|
||||
res.on("end", function() {
|
||||
execFile("unzip", [filename], {cwd: path}, function(err) {
|
||||
assert.equal(err, null);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/test/dir2/testdata2a.txt", "utf8"),
|
||||
fs.readFileSync(path + "/testdata2a.txt", "utf8")
|
||||
);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/test/dir2/testdata2b.txt", "utf8"),
|
||||
fs.readFileSync(path + "/testdata2b.txt", "utf8")
|
||||
);
|
||||
next();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("should download several files in different directories as zip", function(next) {
|
||||
tmp.dir({unsafeCleanup: true}, function(err, path) {
|
||||
path = path.replace(/\w:/, '');
|
||||
assert.equal(err, null);
|
||||
|
||||
var filename = path + "/download.zip";
|
||||
var file = fs.createWriteStream(filename);
|
||||
http.get("http://localhost:8787/test/dir1/testdata1.txt,/test/dir2/testdata2a.txt?download=download.zip", function(res) {
|
||||
res.pipe(file);
|
||||
res.on("end", function() {
|
||||
execFile("unzip", [filename], {cwd: path}, function(err) {
|
||||
assert.equal(err, null);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/test/dir1/testdata1.txt", "utf8"),
|
||||
fs.readFileSync(path + "/dir1/testdata1.txt", "utf8")
|
||||
);
|
||||
assert.equal(
|
||||
fs.readFileSync(__dirname + "/test/dir2/testdata2a.txt", "utf8"),
|
||||
fs.readFileSync(path + "/dir2/testdata2a.txt", "utf8")
|
||||
);
|
||||
next();
|
||||
});
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
test data 1
|
|
@ -0,0 +1 @@
|
|||
test data 2a
|
|
@ -0,0 +1 @@
|
|||
test data 2b
|
|
@ -56,7 +56,6 @@ define(function(require, exports, module) {
|
|||
projectDir: vfsOptions.projectDir,
|
||||
extendDirectory: options.extendDirectory,
|
||||
extendOptions: projectOptions.extendOptions,
|
||||
extendToken: "not_needed",
|
||||
collab: options.collab,
|
||||
vfsOptions: vfsOptions,
|
||||
public: true
|
||||
|
|
|
@ -24,7 +24,6 @@ function Vfs(vfs, master, options) {
|
|||
this.public = options.public || false;
|
||||
this.vfsOptions = options.vfsOptions || {};
|
||||
this.pid = this.vfsOptions.pid;
|
||||
var extendToken = options.extendToken;
|
||||
|
||||
this.homeDir = options.homeDir;
|
||||
this.workspaceDir = options.projectDir;
|
||||
|
@ -36,14 +35,12 @@ function Vfs(vfs, master, options) {
|
|||
blocked: this.readonly,
|
||||
extendDirectory: options.extendDirectory,
|
||||
extendOptions: options.extendOptions,
|
||||
extendToken: extendToken
|
||||
});
|
||||
this.vfsWorkspace = wrapVfs(vfs, {
|
||||
root: this.workspaceDir,
|
||||
readonly: this.readonly,
|
||||
extendDirectory: options.extendDirectory,
|
||||
extendOptions: options.extendOptions,
|
||||
extendToken: extendToken
|
||||
});
|
||||
|
||||
var vfsProxy = proxyVfs(Object.keys(this.vfsHome), this.vfsHome, this.vfsWorkspace);
|
||||
|
|
|
@ -8,7 +8,6 @@ module.exports = function(vfs, options) {
|
|||
var methods = options.methods || Object.keys(vfs);
|
||||
var readonly = "readonly" in options ? options.readonly : false;
|
||||
var blocked = !!options.blocked;
|
||||
var extendToken = options.extendToken;
|
||||
|
||||
var roMethods = {
|
||||
resolve: 1,
|
||||
|
@ -74,18 +73,26 @@ module.exports = function(vfs, options) {
|
|||
options[key] = extendOptions[key];
|
||||
}
|
||||
|
||||
if (options.code || options.stream) {
|
||||
if (readonly && (!extendToken || extendToken !== options.extendToken))
|
||||
return callback(new error.Forbidden("VFS extend: " + name + " with options 'stream' or 'code' not authorized in read only mode"));
|
||||
else
|
||||
return vfs.extend(name, options, callback);
|
||||
if (readonly) {
|
||||
var whitelist = {
|
||||
"c9.ide.collab/server/collab-server.js": true,
|
||||
"c9.ide.pubsub/pubsub-service.js": true,
|
||||
"c9.vfs.client/ping-service.js": true,
|
||||
};
|
||||
if (!options.file || !whitelist[options.file])
|
||||
return callback(new error.Forbidden("VFS extend: " + name + " is not authorized in read only mode"));
|
||||
}
|
||||
|
||||
if (!options.file)
|
||||
return callback(new error.Forbidden("Option 'file' is missing"));
|
||||
|
||||
if (typeof options.file != "string")
|
||||
return callback(new error.Forbidden("Invalid option 'file'"));
|
||||
|
||||
// localfs extend checks for file, then code, then stream
|
||||
if (!options.file) {
|
||||
if (options.code || options.stream)
|
||||
return vfs.extend(name, options, callback);
|
||||
|
||||
return callback(new error.Forbidden("Option 'file' is missing"));
|
||||
}
|
||||
|
||||
if (typeof options.file != "string")
|
||||
return callback(new error.Forbidden("Invalid option 'file'"));
|
||||
|
||||
if (extendDirectory) {
|
||||
var file = options.file = path.normalize(path.join(extendDirectory, options.file));
|
||||
|
|
|
@ -221,8 +221,6 @@ function plugin(options, imports, register) {
|
|||
});
|
||||
});
|
||||
|
||||
api.get("/api.json", {name: "api"}, frontdoor.middleware.describeApi(api));
|
||||
|
||||
// fake authentication
|
||||
api.authenticate = api.authenticate || function() {
|
||||
return function(req, res, next) {
|
||||
|
@ -255,7 +253,7 @@ function plugin(options, imports, register) {
|
|||
};
|
||||
api.updatConfig = api.updatConfig || function(opts, params) {
|
||||
var id = params.token;
|
||||
opts.accessToken = opts.extendToken = id || "token";
|
||||
opts.accessToken = id || "token";
|
||||
var user = opts.extendOptions.user;
|
||||
user.id = id || -1;
|
||||
user.name = id ? "user" + id : "johndoe";
|
||||
|
|
|
@ -271,6 +271,7 @@
|
|||
return cb();
|
||||
setTimeout.paused = true;
|
||||
window.app.services.vfs.connection.disconnect();
|
||||
window.app.services["vfs.endpoint"].clearCache();
|
||||
setTimeout.force(function() {
|
||||
setTimeout.paused = false;
|
||||
setTimeout.clear();
|
||||
|
|
|
@ -160,7 +160,8 @@ if [ "$os" == "windows" ]; then
|
|||
cscript //NoLogo //B //E:jscript ./shortcut.wscript.js
|
||||
rm -f ./shortcut.wscript.js
|
||||
|
||||
bash ./makelocal.sh
|
||||
current_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
bash "$current_dir/makelocal.sh"
|
||||
fi
|
||||
|
||||
|
||||
|
|
Ładowanie…
Reference in New Issue