// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_COMMON_ZIP_READER_H_
#define CHROME_COMMON_ZIP_READER_H_

#include <string>

#include "base/basictypes.h"
#include "base/file_path.h"
#include "base/file_util.h"
#include "base/memory/scoped_ptr.h"
#include "base/time.h"
#include "third_party/zlib/contrib/minizip/unzip.h"

namespace zip {

// This class is used for reading zip files. A typical use case of this
// class is to scan entries in a zip file and extract them. The code will
// look like:
//
//   ZipReader reader;
//   reader.Open(zip_file_path);
//   while (reader.HasMore()) {
//     reader.OpenCurrentEntryInZip();
//     reader.ExtractCurrentEntryToDirectory(output_directory_path);
//     reader.AdvanceToNextEntry();
//   }
//
// For simplicty, error checking is omitted in the example code above. The
// production code should check return values from all of these functions.
//
// This calls can also be used for random access of contents in a zip file
// using LocateAndOpenEntry().
//
class ZipReader {
 public:
  // This class represents information of an entry (file or directory) in
  // a zip file.
  class EntryInfo {
   public:
    EntryInfo(const std::string& filename_in_zip,
              const unz_file_info& raw_file_info);

    // Returns the file path. The path is usually relative like
    // "foo/bar.txt", but if it's absolute, is_unsafe() returns true.
    const FilePath& file_path() const { return file_path_; }

    // Returns the size of the original file (i.e. after uncompressed).
    // Returns 0 if the entry is a directory.
    int64 original_size() const { return original_size_; }

    // Returns the last modified time.
    base::Time last_modified() const { return last_modified_; }

    // Returns true if the entry is a directory.
    bool is_directory() const { return is_directory_; }

    // Returns true if the entry is unsafe, like having ".." or invalid
    // UTF-8 characters in its file name, or the file path is absolute.
    bool is_unsafe() const { return is_unsafe_; }

   private:
    const FilePath file_path_;
    int64 original_size_;
    base::Time last_modified_;
    bool is_directory_;
    bool is_unsafe_;
    DISALLOW_COPY_AND_ASSIGN(EntryInfo);
  };

  ZipReader();
  ~ZipReader();

  // Opens the zip file specified by |zip_file_path|. Returns true on
  // success.
  bool Open(const FilePath& zip_file_path);

#if defined(OS_POSIX)
  // Opens the zip file referred to by the file descriptor |zip_fd|.
  // Returns true on success.
  bool OpenFromFd(int zip_fd);
#endif

  // Closes the currently opened zip file. This function is called in the
  // destructor of the class, so you usually don't need to call this.
  void Close();

  // Returns true if there is at least one entry to read. This function is
  // used to scan entries with AdvanceToNextEntry(), like:
  //
  // while (reader.HasMore()) {
  //   // Do something with the current file here.
  //   reader.AdvanceToNextEntry();
  // }
  bool HasMore();

  // Advances the next entry. Returns true on success.
  bool AdvanceToNextEntry();

  // Opens the current entry in the zip file. On success, returns true and
  // updates the the current entry state (i.e. current_entry_info() is
  // updated). This function should be called before operations over the
  // current entry like ExtractCurrentEntryToFile().
  //
  // Note that there is no CloseCurrentEntryInZip(). The the current entry
  // state is reset automatically as needed.
  bool OpenCurrentEntryInZip();

  // Locates an entry in the zip file and opens it. Returns true on
  // success. This function internally calls OpenCurrentEntryInZip() on
  // success. On failure, current_entry_info() becomes NULL.
  bool LocateAndOpenEntry(const FilePath& path_in_zip);

  // Extracts the current entry to the given output file path. If the
  // current file is a directory, just creates a directory
  // instead. Returns true on success. OpenCurrentEntryInZip() must be
  // called beforehand.
  //
  // This function does not preserve the timestamp of the original entry.
  bool ExtractCurrentEntryToFilePath(const FilePath& output_file_path);

  // Extracts the current entry to the given output directory path using
  // ExtractCurrentEntryToFilePath(). Sub directories are created as needed
  // based on the file path of the current entry. For example, if the file
  // path in zip is "foo/bar.txt", and the output directory is "output",
  // "output/foo/bar.txt" will be created.
  //
  // Returns true on success. OpenCurrentEntryInZip() must be called
  // beforehand.
  bool ExtractCurrentEntryIntoDirectory(const FilePath& output_directory_path);

#if defined(OS_POSIX)
  // Extracts the current entry by writing directly to a file descriptor.
  // Does not close the file descriptor. Returns true on success.
  bool ExtractCurrentEntryToFd(int fd);
#endif

  // Returns the current entry info. Returns NULL if the current entry is
  // not yet opened. OpenCurrentEntryInZip() must be called beforehand.
  EntryInfo* current_entry_info() const {
    return current_entry_info_.get();
  }

  // Returns the number of entries in the zip file.
  // Open() must be called beforehand.
  int num_entries() const { return num_entries_; }

 private:
  // Common code used both in Open and OpenFromFd.
  bool OpenInternal();

  // Resets the internal state.
  void Reset();

  unzFile zip_file_;
  int num_entries_;
  bool reached_end_;
  scoped_ptr<EntryInfo> current_entry_info_;

  DISALLOW_COPY_AND_ASSIGN(ZipReader);
};

}  // namespace zip

#endif  // CHROME_COMMON_ZIP_READER_H_


@@ -385,6 +443,11 @@ bool V8DOMWindowShell::installDOMWindow(v8::Handle<v8::Context> context, DOMWind

+    windowWrapper->SetAccessor(v8::String::New("global"), globalGetter);

keep keep keep keep replace keep keep keep keep

@@ -385,6 +450,11 @@ bool V8DOMWindowShell::installDOMWindow(v8::Handle<v8::Context> context, DOMWind

<?xml version="1.0" encoding="utf-8"?>

<!-- Copyright (c) 2012 The Chromium Authors. All rights reserved.

     Use of this source code is governed by a BSD-style license that can be
     found in the LICENSE file.
 -->

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="org.chromium.content_shell">

    <permission android:name="org.chromium.content_shell.permission.SANDBOX"
            android:protectionLevel="signature" />

    <application android:name="ContentShellApplication"
            android:label="ContentShell"
            android:debuggable="true">
        <activity android:name="ContentShellActivity"
                  android:launchMode="singleTask"
                  android:theme="@android:style/Theme.Holo.Light.NoActionBar"
                  android:configChanges="orientation|keyboardHidden|keyboard|screenSize"
                  android:hardwareAccelerated="true">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>

        <!-- The following service entries exist in order to allow us to
             start more than one sandboxed process. -->

        <!-- NOTE: If you change the values of "android:process" for any of the below services,
             you also need to update kHelperProcessExecutableName in chrome_constants.cc. -->
        <service android:name="org.chromium.content.app.SandboxedProcessService0"
                 android:process=":sandboxed_process0"
                 android:permission="org.chromium.content_shell.permission.SANDBOX"
                 android:exported="false" />
        <service android:name="org.chromium.content.app.SandboxedProcessService1"
                 android:process=":sandboxed_process1"
                 android:permission="org.chromium.content_shell.permission.SANDBOX"
                 android:exported="false" />
        <service android:name="org.chromium.content.app.SandboxedProcessService2"
                 android:process=":sandboxed_process2"
                 android:permission="org.chromium.content_shell.permission.SANDBOX"
                 android:exported="false" />
        <service android:name="org.chromium.content.app.SandboxedProcessService3"
                 android:process=":sandboxed_process3"
                 android:permission="org.chromium.content_shell.permission.SANDBOX"
                 android:exported="false" />
        <service android:name="org.chromium.content.app.SandboxedProcessService4"
                 android:process=":sandboxed_process4"
                 android:permission="org.chromium.content_shell.permission.SANDBOX"
                 android:exported="false" />
    </application>

    <uses-sdk android:minSdkVersion="14" android:targetSdkVersion="14" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.VIBRATE"/>
    <uses-permission android:name="android.permission.WAKE_LOCK"/>
</manifest>


keep keep keep keep keep replace keep keep keep keep

@@ -444,6 +514,8 @@ void V8DOMWindowShell::clearDocumentProperty()

diff --git a/Source/WebCore/WebCore.gyp/WebCore.gyp b/Source/WebCore/WebCore.gyp/WebCore.gyp
index fc0f6dc..a5ac8a8 100644
--- a/Source/WebCore/WebCore.gyp/WebCore.gyp
+++ b/Source/WebCore/WebCore.gyp/WebCore.gyp
@@ -57,6 +57,7 @@
     'webcore_include_dirs': [
       '../',
       '../..',
+      '../../../../..',
       '../Modules/battery',
       '../Modules/filesystem',
       '../Modules/filesystem/chromium',
diff --git a/Source/WebCore/bindings/generic/BindingSecurity.cpp b/Source/WebCore/bindings/generic/BindingSecurity.cpp
index e5144e0..4d57277 100644
--- a/Source/WebCore/bindings/generic/BindingSecurity.cpp
+++ b/Source/WebCore/bindings/generic/BindingSecurity.cpp
@@ -47,6 +47,7 @@ static bool canAccessDocument(BindingState* state, Document* targetDocument, Sec
     if (!targetDocument)
         return false;

+#if 0
     DOMWindow* active = activeDOMWindow(state);
     if (!active)
         return false;
@@ -58,6 +59,9 @@ static bool canAccessDocument(BindingState* state, Document* targetDocument, Sec
         printErrorMessageForFrame(targetDocument->frame(), targetDocument->domWindow()->crossDomainAccessErrorMessage(active));

     return false;
+#endif
+
+    return true;
 }

 bool BindingSecurity::shouldAllowAccessToDOMWindow(BindingState* state, DOMWindow* target, SecurityReportingOption reportingOption)
diff --git a/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm b/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm
index 4ebe654..3905511 100644
--- a/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm
+++ b/Source/WebCore/bindings/scripts/CodeGeneratorV8.pm
@@ -2794,7 +2794,7 @@ END

     my $access_check = "";
     if ($dataNode->extendedAttributes->{"CheckSecurity"} && !($interfaceName eq "DOMWindow")) {
-        $access_check = "instance->SetAccessCheckCallbacks(V8${interfaceName}::namedSecurityCheck, V8${interfaceName}::indexedSecurityCheck, v8::External::Wrap(&V8${interfaceName}::info));";
+        $access_check = "";
     }

     # For the DOMWindow interface, generate the shadow object template
@@ -2806,7 +2806,7 @@ static v8::Persistent<v8::ObjectTemplate> ConfigureShadowObjectTemplate(v8::Pers
     V8DOMConfiguration::batchConfigureAttributes(templ, v8::Handle<v8::ObjectTemplate>(), shadowAttrs, WTF_ARRAY_LENGTH(shadowAttrs));

     // Install a security handler with V8.
-    templ->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info));
+    // templ->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info));
     templ->SetInternalFieldCount(V8DOMWindow::internalFieldCount);
     return templ;
 }
@@ -2945,7 +2945,7 @@ END
     // Set access check callbacks, but turned off initially.
     // When a context is detached from a frame, turn on the access check.
     // Turning on checks also invalidates inline caches of the object.
-    instance->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info), false);
+    // instance->SetAccessCheckCallbacks(V8DOMWindow::namedSecurityCheck, V8DOMWindow::indexedSecurityCheck, v8::External::Wrap(&V8DOMWindow::info), false);
 END
     }
     if ($interfaceName eq "HTMLDocument") {
diff --git a/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp b/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp
index 4dfce70..dcd22d8 100644
--- a/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp
+++ b/Source/WebCore/bindings/v8/V8DOMWindowShell.cpp
@@ -63,6 +63,13 @@
 #include "V8ObjectConstructor.h"
 #include "V8PerContextData.h"
 #include "WorkerContextExecutionProxy.h"
+
+#include "base/command_line.h"
+#include "content/nw/src/shell_switches.h"
+#include "content/nw/src/nw_version.h"
+#include "third_party/node/src/node.h"
+#include "third_party/node/src/req_wrap.h"
+
 #include <algorithm>
 #include <stdio.h>
 #include <utility>
@@ -81,6 +88,11 @@

 namespace WebCore {

+static v8::Handle<v8::Value> globalGetter(v8::Local<v8::String> property, const v8::AccessorInfo& info)
+{
+    return node::g_context->Global()->Get(property);
+}
+
 static void reportFatalError(const char* location, const char* message)
 {
     int memoryUsageMB = MemoryUsageSupport::actualMemoryUsageMB();
@@ -319,6 +331,52 @@ bool V8DOMWindowShell::initializeIfNeeded()

     setSecurityToken();

+    // Do we integrate node?
+    bool use_node = CommandLine::ForCurrentProcess()->HasSwitch(switches::kmNodejs);
+
+    // Test if protocol is file:
+    v8::Local<v8::Script> protocol_script = v8::Script::New(v8::String::New(
+        "(function(){ return window.location.protocol == 'file:' })();"
+    ));
+    bool is_file_protocol = protocol_script->Run()->BooleanValue();
+    use_node = is_file_protocol ? use_node : false;
+
+    // Test if protocol is nw:
+    protocol_script = v8::Script::New(v8::String::New(
+        "(function(){ return window.location.protocol == 'nw:' })();"
+    ));
+    bool is_nw_protocol = protocol_script->Run()->BooleanValue();
+
+    if (use_node) {
+        v8::Local<v8::Script> script = v8::Script::New(v8::String::New(
+            // Make node's relative modules work
+#if defined(OS_WIN)
+            "process.mainModule.filename = window.location.pathname.substr(1);"
+#else
+            "process.mainModule.filename = window.location.pathname;"
+#endif
+            "process.chdir(require('path').dirname(process.mainModule.filename));"
+            "process.mainModule.paths = require('module')._nodeModulePaths(process.cwd());"
+        ));
+        script->Run();
+    }
+
+    if (use_node || is_nw_protocol) {
+        v8::Local<v8::Script> script = v8::Script::New(v8::String::New(
+            // Use WebKit's console globally
+            "global.console = console;"
+
+            // Don't exit on exception
+            "process.on('uncaughtException', function (err) {"
+              "console.log(err.stack);"
+            "});"
+
+            // Save node-webkit version
+            "process.versions['node-webkit'] = '" NW_VERSION_STRING "';"
+        ));
+        script->Run();
+    }
+
     if (m_frame->document())
         context->AllowCodeGenerationFromStrings(m_frame->document()->contentSecurityPolicy()->allowEval(0, ContentSecurityPolicy::SuppressReport));

@@ -385,6 +443,11 @@ bool V8DOMWindowShell::installDOMWindow(v8::Handle<v8::Context> context, DOMWind
     V8DOMWrapper::setDOMWrapper(v8::Handle<v8::Object>::Cast(windowWrapper->GetPrototype()), &V8DOMWindow::info, window);
     V8DOMWrapper::setJSWrapperForDOMObject(PassRefPtr<DOMWindow>(window), windowWrapper);

+    windowWrapper->SetAccessor(v8::String::New("global"), globalGetter);
+    windowWrapper->SetAccessor(v8::String::New("process"), globalGetter);
+    windowWrapper->SetAccessor(v8::String::New("require"), globalGetter);
+    windowWrapper->SetAccessor(v8::String::New("Buffer"), globalGetter);
+
     // Install the windowWrapper as the prototype of the innerGlobalObject.
     // The full structure of the global object is as follows:
     //
@@ -444,6 +507,8 @@ void V8DOMWindowShell::clearDocumentProperty()

 void V8DOMWindowShell::setSecurityToken()
 {
+    m_context->SetSecurityToken(node::g_context->GetSecurityToken());
+#if 0
     Document* document = m_frame->document();

     // Ask the document's SecurityOrigin to generate a security token.
@@ -470,6 +535,7 @@ void V8DOMWindowShell::setSecurityToken()
     // NOTE: V8 does identity comparison in fast path, must use a symbol
     // as the security token.
     m_context->SetSecurityToken(v8::String::NewSymbol(utf8Token.data(), utf8Token.length()));
+#endif
 }

 void V8DOMWindowShell::updateDocument()
diff --git a/Source/WebCore/loader/CrossOriginAccessControl.cpp b/Source/WebCore/loader/CrossOriginAccessControl.cpp
index aba2ba0..ec76d5a 100644
--- a/Source/WebCore/loader/CrossOriginAccessControl.cpp
+++ b/Source/WebCore/loader/CrossOriginAccessControl.cpp
@@ -134,37 +134,6 @@ ResourceRequest createAccessControlPreflightRequest(const ResourceRequest& reque

 bool passesAccessControlCheck(const ResourceResponse& response, StoredCredentials includeCredentials, SecurityOrigin* securityOrigin, String& errorDescription)
 {
-    AtomicallyInitializedStatic(AtomicString&, accessControlAllowOrigin = *new AtomicString("access-control-allow-origin"));
-    AtomicallyInitializedStatic(AtomicString&, accessControlAllowCredentials = *new AtomicString("access-control-allow-credentials"));
-
-    // A wildcard Access-Control-Allow-Origin can not be used if credentials are to be sent,
-    // even with Access-Control-Allow-Credentials set to true.
-    const String& accessControlOriginString = response.httpHeaderField(accessControlAllowOrigin);
-    if (accessControlOriginString == "*" && includeCredentials == DoNotAllowStoredCredentials)
-        return true;
-
-    if (securityOrigin->isUnique()) {
-        errorDescription = "Cannot make any requests from " + securityOrigin->toString() + ".";
-        return false;
-    }
-
-    // FIXME: Access-Control-Allow-Origin can contain a list of origins.
-    if (accessControlOriginString != securityOrigin->toString()) {
-        if (accessControlOriginString == "*")
-            errorDescription = "Cannot use wildcard in Access-Control-Allow-Origin when credentials flag is true.";
-        else
-            errorDescription =  "Origin " + securityOrigin->toString() + " is not allowed by Access-Control-Allow-Origin.";
-        return false;
-    }
-
-    if (includeCredentials == AllowStoredCredentials) {
-        const String& accessControlCredentialsString = response.httpHeaderField(accessControlAllowCredentials);
-        if (accessControlCredentialsString != "true") {
-            errorDescription = "Credentials flag is true, but Access-Control-Allow-Credentials is not \"true\".";
-            return false;
-        }
-    }
-
     return true;
 }

diff --git a/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp b/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp
index 04d5881..65e4734 100644
--- a/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp
+++ b/Source/WebCore/loader/CrossOriginPreflightResultCache.cpp
@@ -123,13 +123,6 @@ bool CrossOriginPreflightResultCacheItem::allowsCrossOriginMethod(const String&

 bool CrossOriginPreflightResultCacheItem::allowsCrossOriginHeaders(const HTTPHeaderMap& requestHeaders, String& errorDescription) const
 {
-    HTTPHeaderMap::const_iterator end = requestHeaders.end();
-    for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {
-        if (!m_headers.contains(it->first) && !isOnAccessControlSimpleRequestHeaderWhitelist(it->first, it->second)) {
-            errorDescription = "Request header field " + it->first.string() + " is not allowed by Access-Control-Allow-Headers.";
-            return false;
-        }
-    }
     return true;
 }

diff --git a/Source/WebCore/page/SecurityOrigin.cpp b/Source/WebCore/page/SecurityOrigin.cpp
index 6934717..fc949c2 100644
--- a/Source/WebCore/page/SecurityOrigin.cpp
+++ b/Source/WebCore/page/SecurityOrigin.cpp
@@ -120,7 +120,7 @@ SecurityOrigin::SecurityOrigin(const KURL& url)
     , m_host(url.host().isNull() ? "" : url.host().lower())
     , m_port(url.port())
     , m_isUnique(false)
-    , m_universalAccess(false)
+    , m_universalAccess(true)
     , m_domainWasSetInDOM(false)
     , m_blockThirdPartyStorage(false)
     , m_enforceFilePathSeparation(false)
@@ -145,7 +145,7 @@ SecurityOrigin::SecurityOrigin()
     , m_domain("")
     , m_port(InvalidPort)
     , m_isUnique(true)
-    , m_universalAccess(false)
+    , m_universalAccess(true)
     , m_domainWasSetInDOM(false)
     , m_canLoadLocalResources(false)
     , m_blockThirdPartyStorage(false)
diff --git a/Source/WebKit/chromium/src/WebKit.cpp b/Source/WebKit/chromium/src/WebKit.cpp
index 9331d05..eca2f5b 100644
--- a/Source/WebKit/chromium/src/WebKit.cpp
+++ b/Source/WebKit/chromium/src/WebKit.cpp
@@ -95,7 +95,8 @@ static bool generateEntropy(unsigned char* buffer, size_t length)
 #ifndef NDEBUG
 static void assertV8RecursionScope()
 {
-    ASSERT(!isMainThread() || WebCore::V8RecursionScope::properlyUsed());
+    // FIXME See why this failed when node::SetupContext
+    // ASSERT(!isMainThread() || WebCore::V8RecursionScope::properlyUsed());
 }
 #endif


// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_COMMON_ZIP_INTERNAL_H_
#define CHROME_COMMON_ZIP_INTERNAL_H_

#include <string>

#include "third_party/zlib/contrib/minizip/unzip.h"
#include "third_party/zlib/contrib/minizip/zip.h"

// Utility functions and constants used internally for the zip file
// library in the directory. Don't use them outside of the library.
namespace zip {
namespace internal {

// Opens the given file name in UTF-8 for unzipping, with some setup for
// Windows.
unzFile OpenForUnzipping(const std::string& file_name_utf8);

#if defined(OS_POSIX)
// Opens the file referred to by |zip_fd| for unzipping.
unzFile OpenFdForUnzipping(int zip_fd);
#endif

// Opens the given file name in UTF-8 for zipping, with some setup for
// Windows. |append_flag| will be passed to zipOpen2().
zipFile OpenForZipping(const std::string& file_name_utf8, int append_flag);

const int kZipMaxPath = 256;
const int kZipBufSize = 8192;

}  // namespace internal
}  // namespace zip

#endif  // CHROME_COMMON_ZIP_INTERNAL_H_


Roger Wang <roger.wang@linux.intel.com>
Zhao Cheng <zcbenz@gmail.com>


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/shell/shell_login_dialog.h"

#include <gtk/gtk.h>

#include "base/logging.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/resource_dispatcher_host.h"
#include "content/public/browser/resource_request_info.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "ui/base/gtk/gtk_hig_constants.h"

namespace content {

void ShellLoginDialog::PlatformCreateDialog(const string16& message) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));

  int render_process_id;
  int render_view_id;
  if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderView(
          &render_process_id,  &render_view_id)) {
    NOTREACHED();
  }

  WebContents* web_contents = NULL;
  RenderViewHost* render_view_host =
      RenderViewHost::FromID(render_process_id, render_view_id);
  if (render_view_host)
    web_contents = WebContents::FromRenderViewHost(render_view_host);
  DCHECK(web_contents);

  gfx::NativeWindow parent_window =
      web_contents->GetView()->GetTopLevelNativeWindow();

  root_ = gtk_message_dialog_new(parent_window,
                                 GTK_DIALOG_MODAL,
                                 GTK_MESSAGE_INFO,
                                 GTK_BUTTONS_OK_CANCEL,
                                 "Please log in.");

  GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(root_));
  GtkWidget* label = gtk_label_new(UTF16ToUTF8(message).c_str());
  gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
  gtk_box_pack_start(GTK_BOX(content_area), label, FALSE, FALSE, 0);

  username_entry_ = gtk_entry_new();
  gtk_entry_set_activates_default(GTK_ENTRY(username_entry_), TRUE);

  password_entry_ = gtk_entry_new();
  gtk_entry_set_activates_default(GTK_ENTRY(password_entry_), TRUE);
  gtk_entry_set_visibility(GTK_ENTRY(password_entry_), FALSE);

  GtkWidget* table = gtk_table_new(2, 2, FALSE);
  gtk_table_set_col_spacing(GTK_TABLE(table), 0, ui::kLabelSpacing);
  gtk_table_set_row_spacings(GTK_TABLE(table), ui::kControlSpacing);

  GtkWidget* username_label = gtk_label_new("Username:");
  gtk_misc_set_alignment(GTK_MISC(username_label), 0, 0.5);

  gtk_table_attach(GTK_TABLE(table), username_label, 0, 1, 0, 1, GTK_FILL,
                   GTK_FILL, 0, 0);
  gtk_table_attach_defaults(GTK_TABLE(table), username_entry_, 1, 2, 0, 1);

  GtkWidget* password_label = gtk_label_new("Password:");
  gtk_misc_set_alignment(GTK_MISC(password_label), 0, 0.5);

  gtk_table_attach(GTK_TABLE(table), password_label, 0, 1, 1, 2, GTK_FILL,
                   GTK_FILL, 0, 0);
  gtk_table_attach_defaults(GTK_TABLE(table), password_entry_, 1, 2, 1, 2);

  gtk_box_pack_start(GTK_BOX(content_area), table, FALSE, FALSE, 0);

  g_signal_connect(root_, "response", G_CALLBACK(OnResponseThunk), this);
  gtk_widget_grab_focus(username_entry_);
  gtk_widget_show_all(GTK_WIDGET(root_));
}

void ShellLoginDialog::PlatformCleanUp() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

void ShellLoginDialog::PlatformRequestCancelled() {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
}

void ShellLoginDialog::OnResponse(GtkWidget* sender, int response_id) {
  switch (response_id) {
    case GTK_RESPONSE_OK:
      UserAcceptedAuth(
          UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(username_entry_))),
          UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(password_entry_))));
      break;
    case GTK_RESPONSE_CANCEL:
    case GTK_RESPONSE_DELETE_EVENT:
      UserCancelledAuth();
      break;
    default:
      NOTREACHED();
  }

  gtk_widget_destroy(root_);
}

}  // namespace content


Document* document = m_frame->document();

// Ask the document's SecurityOrigin to generate a security token.

@@ -470,6 +535,7 @@ void V8DOMWindowShell::setSecurityToken()

// NOTE: V8 does identity comparison in fast path, must use a symbol

keep keep keep keep replace keep keep keep keep keep

@@ -470,6 +542,7 @@ void V8DOMWindowShell::setSecurityToken()


// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "zip_reader.h"

#include "base/file_util.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "net/base/file_stream.h"
#include "third_party/zlib/contrib/minizip/unzip.h"
#if defined(OS_WIN)
#include "third_party/zlib/contrib/minizip/iowin32.h"
#endif
#include "zip_internal.h"

namespace zip {

// TODO(satorux): The implementation assumes that file names in zip files
// are encoded in UTF-8. This is true for zip files created by Zip()
// function in zip.h, but not true for user-supplied random zip files.
ZipReader::EntryInfo::EntryInfo(const std::string& file_name_in_zip,
                                const unz_file_info& raw_file_info)
    : file_path_(FilePath::FromUTF8Unsafe(file_name_in_zip)),
      is_directory_(false) {
  original_size_ = raw_file_info.uncompressed_size;

  // Directory entries in zip files end with "/".
  is_directory_ = EndsWith(file_name_in_zip, "/", false);

  // Check the file name here for directory traversal issues. In the name of
  // simplicity and security, we might reject a valid file name such as "a..b".
  is_unsafe_ = file_name_in_zip.find("..") != std::string::npos;

  // We also consider that the file name is unsafe, if it's invalid UTF-8.
  string16 file_name_utf16;
  if (!UTF8ToUTF16(file_name_in_zip.data(), file_name_in_zip.size(),
                   &file_name_utf16)) {
    is_unsafe_ = true;
  }

  // We also consider that the file name is unsafe, if it's absolute.
  // On Windows, IsAbsolute() returns false for paths starting with "/".
  if (file_path_.IsAbsolute() || StartsWithASCII(file_name_in_zip, "/", false))
    is_unsafe_ = true;

  // Construct the last modified time. The timezone info is not present in
  // zip files, so we construct the time as local time.
  base::Time::Exploded exploded_time = {};  // Zero-clear.
  exploded_time.year = raw_file_info.tmu_date.tm_year;
  // The month in zip file is 0-based, whereas ours is 1-based.
  exploded_time.month = raw_file_info.tmu_date.tm_mon + 1;
  exploded_time.day_of_month = raw_file_info.tmu_date.tm_mday;
  exploded_time.hour = raw_file_info.tmu_date.tm_hour;
  exploded_time.minute = raw_file_info.tmu_date.tm_min;
  exploded_time.second = raw_file_info.tmu_date.tm_sec;
  exploded_time.millisecond = 0;
  if (exploded_time.HasValidValues()) {
    last_modified_ = base::Time::FromLocalExploded(exploded_time);
  } else {
    // Use Unix time epoch if the time stamp data is invalid.
    last_modified_ = base::Time::UnixEpoch();
  }
}

ZipReader::ZipReader() {
  Reset();
}

ZipReader::~ZipReader() {
  Close();
}

bool ZipReader::Open(const FilePath& zip_file_path) {
  DCHECK(!zip_file_);

  // Use of "Unsafe" function does not look good, but there is no way to do
  // this safely on Linux. See file_util.h for details.
  zip_file_ = internal::OpenForUnzipping(zip_file_path.AsUTF8Unsafe());
  if (!zip_file_) {
    return false;
  }

  return OpenInternal();
}

#if defined(OS_POSIX)
bool ZipReader::OpenFromFd(const int zip_fd) {
  DCHECK(!zip_file_);

  zip_file_ = internal::OpenFdForUnzipping(zip_fd);
  if (!zip_file_) {
    return false;
  }

  return OpenInternal();
}
#endif

void ZipReader::Close() {
  if (zip_file_) {
    unzClose(zip_file_);
  }
  Reset();
}

bool ZipReader::HasMore() {
  return !reached_end_;
}

bool ZipReader::AdvanceToNextEntry() {
  DCHECK(zip_file_);

  // Should not go further if we already reached the end.
  if (reached_end_)
    return false;

  unz_file_pos position = {};
  if (unzGetFilePos(zip_file_, &position) != UNZ_OK)
    return false;
  const int current_entry_index = position.num_of_file;
  // If we are currently at the last entry, then the next position is the
  // end of the zip file, so mark that we reached the end.
  if (current_entry_index + 1 == num_entries_) {
    reached_end_ = true;
  } else {
    DCHECK_LT(current_entry_index + 1, num_entries_);
    if (unzGoToNextFile(zip_file_) != UNZ_OK) {
      return false;
    }
  }
  current_entry_info_.reset();
  return true;
}

bool ZipReader::OpenCurrentEntryInZip() {
  DCHECK(zip_file_);

  unz_file_info raw_file_info = {};
  char raw_file_name_in_zip[internal::kZipMaxPath] = {};
  const int result = unzGetCurrentFileInfo(zip_file_,
                                           &raw_file_info,
                                           raw_file_name_in_zip,
                                           sizeof(raw_file_name_in_zip) - 1,
                                           NULL,  // extraField.
                                           0,  // extraFieldBufferSize.
                                           NULL,  // szComment.
                                           0);  // commentBufferSize.
  if (result != UNZ_OK)
    return false;
  if (raw_file_name_in_zip[0] == '\0')
    return false;
  current_entry_info_.reset(
      new EntryInfo(raw_file_name_in_zip, raw_file_info));
  return true;
}

bool ZipReader::LocateAndOpenEntry(const FilePath& path_in_zip) {
  DCHECK(zip_file_);

  current_entry_info_.reset();
  reached_end_ = false;
  const int kDefaultCaseSensivityOfOS = 0;
  const int result = unzLocateFile(zip_file_,
                                   path_in_zip.AsUTF8Unsafe().c_str(),
                                   kDefaultCaseSensivityOfOS);
  if (result != UNZ_OK)
    return false;

  // Then Open the entry.
  return OpenCurrentEntryInZip();
}

bool ZipReader::ExtractCurrentEntryToFilePath(
    const FilePath& output_file_path) {
  DCHECK(zip_file_);

  // If this is a directory, just create it and return.
  if (current_entry_info()->is_directory())
    return file_util::CreateDirectory(output_file_path);

  const int open_result = unzOpenCurrentFile(zip_file_);
  if (open_result != UNZ_OK)
    return false;

  // We can't rely on parent directory entries being specified in the
  // zip, so we make sure they are created.
  FilePath output_dir_path = output_file_path.DirName();
  if (!file_util::CreateDirectory(output_dir_path))
    return false;

  net::FileStream stream(NULL);
  const int flags = (base::PLATFORM_FILE_CREATE_ALWAYS |
                     base::PLATFORM_FILE_WRITE);
  if (stream.OpenSync(output_file_path, flags) != 0)
    return false;

  bool success = true;  // This becomes false when something bad happens.
  while (true) {
    char buf[internal::kZipBufSize];
    const int num_bytes_read = unzReadCurrentFile(zip_file_, buf,
                                                  internal::kZipBufSize);
    if (num_bytes_read == 0) {
      // Reached the end of the file.
      break;
    } else if (num_bytes_read < 0) {
      // If num_bytes_read < 0, then it's a specific UNZ_* error code.
      success = false;
      break;
    } else if (num_bytes_read > 0) {
      // Some data is read. Write it to the output file.
      if (num_bytes_read != stream.WriteSync(buf, num_bytes_read)) {
        success = false;
        break;
      }
    }
  }

  stream.CloseSync();
  unzCloseCurrentFile(zip_file_);
  return success;
}

bool ZipReader::ExtractCurrentEntryIntoDirectory(
    const FilePath& output_directory_path) {
  DCHECK(current_entry_info_.get());

  FilePath output_file_path = output_directory_path.Append(
      current_entry_info()->file_path());
  return ExtractCurrentEntryToFilePath(output_file_path);
}

#if defined(OS_POSIX)
bool ZipReader::ExtractCurrentEntryToFd(const int fd) {
  DCHECK(zip_file_);

  // If this is a directory, there's nothing to extract to the file descriptor,
  // so return false.
  if (current_entry_info()->is_directory())
    return false;

  const int open_result = unzOpenCurrentFile(zip_file_);
  if (open_result != UNZ_OK)
    return false;

  bool success = true;  // This becomes false when something bad happens.
  while (true) {
    char buf[internal::kZipBufSize];
    const int num_bytes_read = unzReadCurrentFile(zip_file_, buf,
                                                  internal::kZipBufSize);
    if (num_bytes_read == 0) {
      // Reached the end of the file.
      break;
    } else if (num_bytes_read < 0) {
      // If num_bytes_read < 0, then it's a specific UNZ_* error code.
      success = false;
      break;
    } else if (num_bytes_read > 0) {
      // Some data is read. Write it to the output file descriptor.
      if (num_bytes_read !=
          file_util::WriteFileDescriptor(fd, buf, num_bytes_read)) {
        success = false;
        break;
      }
    }
  }

  unzCloseCurrentFile(zip_file_);
  return success;
}
#endif  // defined(OS_POSIX)

bool ZipReader::OpenInternal() {
  DCHECK(zip_file_);

  unz_global_info zip_info = {};  // Zero-clear.
  if (unzGetGlobalInfo(zip_file_, &zip_info) != UNZ_OK) {
    return false;
  }
  num_entries_ = zip_info.number_entry;
  if (num_entries_ < 0)
    return false;

  // We are already at the end if the zip file is empty.
  reached_end_ = (num_entries_ == 0);
  return true;
}

void ZipReader::Reset() {
  zip_file_ = NULL;
  num_entries_ = 0;
  reached_end_ = false;
  current_entry_info_.reset();
}

}  // namespace zip


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/nw/src/media/media_internals.h"

#include "base/memory/scoped_ptr.h"
#include "base/string16.h"
#include "base/stringprintf.h"
#include "media/base/media_log.h"
#include "media/base/media_log_event.h"

MediaInternals* MediaInternals::GetInstance() {
  return Singleton<MediaInternals>::get();
}

MediaInternals::~MediaInternals() {}

void MediaInternals::OnDeleteAudioStream(void* host, int stream_id) {
}

void MediaInternals::OnSetAudioStreamPlaying(
    void* host, int stream_id, bool playing) {
}

void MediaInternals::OnSetAudioStreamStatus(
    void* host, int stream_id, const std::string& status) {
}

void MediaInternals::OnSetAudioStreamVolume(
    void* host, int stream_id, double volume) {
}

void MediaInternals::OnMediaEvent(
    int render_process_id, const media::MediaLogEvent& event) {
}

void MediaInternals::OnCaptureDevicesOpened(
    int render_process_id,
    int render_view_id,
    const content::MediaStreamDevices& devices) {
}

void MediaInternals::OnCaptureDevicesClosed(
    int render_process_id,
    int render_view_id,
    const content::MediaStreamDevices& devices) {
}

MediaInternals::MediaInternals() {}


// Copyright (c) 2012 Intel Corp
// Copyright (c) 2012 The Chromium Authors
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
//  in the Software without restriction, including without limitation the rights
//  to use, copy, modify, merge, publish, distribute, sublicense, and/or sell co
// pies of the Software, and to permit persons to whom the Software is furnished
//  to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in al
// l copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IM
// PLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNES
// S FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
//  OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WH
// ETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
//  CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#include "content/shell/shell_javascript_dialog.h"

#include "base/string_util.h"
#include "content/shell/resource.h"
#include "content/shell/shell.h"
#include "content/shell/shell_javascript_dialog_creator.h"

namespace content {

class ShellJavaScriptDialog;

INT_PTR CALLBACK ShellJavaScriptDialog::DialogProc(HWND dialog,
                                                   UINT message,
                                                   WPARAM wparam,
                                                   LPARAM lparam) {
  switch (message) {
    case WM_INITDIALOG: {
      SetWindowLongPtr(dialog, DWL_USER, static_cast<LONG_PTR>(lparam));
      ShellJavaScriptDialog* owner =
          reinterpret_cast<ShellJavaScriptDialog*>(lparam);
      owner->dialog_win_ = dialog;
      SetDlgItemText(dialog, IDC_DIALOGTEXT, owner->message_text_.c_str());
      if (owner->message_type_ == JAVASCRIPT_MESSAGE_TYPE_PROMPT)
        SetDlgItemText(dialog, IDC_PROMPTEDIT,
                       owner->default_prompt_text_.c_str());
      break;
    }
    case WM_DESTROY: {
      ShellJavaScriptDialog* owner = reinterpret_cast<ShellJavaScriptDialog*>(
          GetWindowLongPtr(dialog, DWL_USER));
      if (owner->dialog_win_) {
        owner->dialog_win_ = 0;
        owner->callback_.Run(false, string16());
        owner->creator_->DialogClosed(owner);
      }
      break;
    }
    case WM_COMMAND: {
      ShellJavaScriptDialog* owner = reinterpret_cast<ShellJavaScriptDialog*>(
          GetWindowLongPtr(dialog, DWL_USER));
      string16 user_input;
      bool finish = false;
      bool result;
      switch (LOWORD(wparam)) {
        case IDOK:
          finish = true;
          result = true;
          if (owner->message_type_ == JAVASCRIPT_MESSAGE_TYPE_PROMPT) {
            size_t length =
                GetWindowTextLength(GetDlgItem(dialog, IDC_PROMPTEDIT)) + 1;
            GetDlgItemText(dialog, IDC_PROMPTEDIT,
                           WriteInto(&user_input, length), length);
          }
          break;
        case IDCANCEL:
          finish = true;
          result = false;
          break;
      }
      if (finish) {
        owner->dialog_win_ = 0;
        owner->callback_.Run(result, user_input);
        DestroyWindow(dialog);
        owner->creator_->DialogClosed(owner);
      }
      break;
    }
    default:
      return DefWindowProc(dialog, message, wparam, lparam);
  }
  return 0;
}

ShellJavaScriptDialog::ShellJavaScriptDialog(
    ShellJavaScriptDialogCreator* creator,
    gfx::NativeWindow parent_window,
    JavaScriptMessageType message_type,
    const string16& message_text,
    const string16& default_prompt_text,
    const JavaScriptDialogCreator::DialogClosedCallback& callback)
    : creator_(creator),
      callback_(callback),
      message_text_(message_text),
      default_prompt_text_(default_prompt_text),
      message_type_(message_type) {
  int dialog_type;
  if (message_type == JAVASCRIPT_MESSAGE_TYPE_ALERT)
    dialog_type = IDD_ALERT;
  else if (message_type == JAVASCRIPT_MESSAGE_TYPE_CONFIRM)
    dialog_type = IDD_CONFIRM;
  else // JAVASCRIPT_MESSAGE_TYPE_PROMPT
    dialog_type = IDD_PROMPT;

  dialog_win_ = CreateDialogParam(GetModuleHandle(0),
                                  MAKEINTRESOURCE(dialog_type), 0, DialogProc,
                                  reinterpret_cast<LPARAM>(this));
  ShowWindow(dialog_win_, SW_SHOWNORMAL);
}

ShellJavaScriptDialog::~ShellJavaScriptDialog() {
  Cancel();
}

void ShellJavaScriptDialog::Cancel() {
  if (dialog_win_)
    DestroyWindow(dialog_win_);
}

}  // namespace content


.option('--trace', 'enable transaction tracing with km')

.option('--disable-trace', 'disable transaction tracing with km')

.option('--attach', 'attach logging after your start/restart/stop/reload')

.option('--sort <field_name:sort>', 'sort process according to field\'s name')

keep keep keep add keep keep keep keep keep

.option('--v8', 'enable v8 data collecting')

it should be a NUMBER - byte, "[NUMBER]G"(Gigabyte), "[NUMBER]M"(Megabyte) or "[NUMBER]K"(Kilobyte)

it should be a NUMBER - milliseconds, "[NUMBER]h"(hours), "[NUMBER]m"(minutes) or "[NUMBER]s"(seconds)

it should be "cluster"("cluster_mode") or "fork"("fork_mode") only


// TG!
[{
  // Application 1
  name      : "echo",
  script    : [".", "/", "e", "cho.js"].join('')
},{
  // APplication 2
  name      : "child",
  script    : "./child.js",
  instances : "4",
  error_file : "./child-err.log",
  out_file : "./child-out.log"
},{
  name      : "api-2",
  script    : "./server.js"
}]


/**
 * Copyright 2013 the PM2 project authors. All rights reserved.
 * Use of this source code is governed by a license that
 * can be found in the LICENSE file.
 */
'use strict';

/**
 * @file Fork execution related functions
 * @author Alexandre Strzelewicz <as@unitech.io>
 * @project PM2
 */
var log           = require('debug')('pm2:fork_mode');
var fs            = require('fs');
var cst           = require('../../constants.js');
var moment        = require('moment');
var Utility       = require('../Utility.js');
var path          = require('path');

/**
 * Description
 * @method exports
 * @param {} God
 * @return
 */
module.exports = function ForkMode(God) {
  /**
   * For all apps - FORK MODE
   * fork the app
   * @method forkMode
   * @param {} pm2_env
   * @param {} cb
   * @return
   */
  God.forkMode = function forkMode(pm2_env, cb) {
    var command = '';
    var args    = [];

    console.log('Starting execution sequence in -fork mode- for app name:%s id:%s',
                pm2_env.name,
                pm2_env.pm_id);
    var spawn = require('child_process').spawn;

    var interpreter = pm2_env.exec_interpreter || 'node';
    var pidFile     = pm2_env.pm_pid_path;

    if (interpreter !== 'none') {
      command = interpreter;

      if (pm2_env.node_args && Array.isArray(pm2_env.node_args)) {
        args = args.concat(pm2_env.node_args);
      }

      // Deprecated - to remove at some point
      if (process.env.PM2_NODE_OPTIONS) {
        args = args.concat(process.env.PM2_NODE_OPTIONS.split(' '));
      }

      if (interpreter === 'node' || RegExp('node$').test(interpreter)) {
        args.push(path.resolve(path.dirname(module.filename), '..', 'ProcessContainerFork.js'));
      }
      else
        args.push(pm2_env.pm_exec_path);
    }
    else {
      command = pm2_env.pm_exec_path;
      args = [ ];
    }

    if (pm2_env.args) {
      args = args.concat(pm2_env.args);
    }

    // piping stream o file
    var stds = {
      out: pm2_env.pm_out_log_path,
      err: pm2_env.pm_err_log_path
    };

    // entire log std if necessary.
    if ('pm_log_path' in pm2_env){
      stds.std = pm2_env.pm_log_path;
    }

    log("stds: %j", stds);

    Utility.startLogging(stds, function(err, result) {
      if (err) {
        God.logAndGenerateError(err);
        return cb(err);
      };

      try {
        var cspr = spawn(command, args, {
          env      : pm2_env,
          detached : true,
          windowsHide: true,
          cwd      : pm2_env.pm_cwd || process.cwd(),
          stdio    : ['pipe', 'pipe', 'pipe', 'ipc'] //Same as fork() in node core
        });
      } catch(e) {
        God.logAndGenerateError(e);
        return cb(e);
      }

      cspr.process = {};
      cspr.process.pid = cspr.pid;
      cspr.pm2_env = pm2_env;

      cspr.stderr.on('data', function forkErrData(data) {
        var log_data = null;

        if (pm2_env.disable_logs === true)
          return false;

        if (pm2_env.log_type && pm2_env.log_type === 'json') {
          log_data = JSON.stringify({
            message : data.toString(),
          timestamp : pm2_env.log_date_format ? moment().format(pm2_env.log_date_format) : new Date().toISOString(),
            type : 'err',
            process_id : cspr.pm2_env.pm_id,
            app_name : cspr.pm2_env.name
          }) + '\n';
        }
        else if (pm2_env.log_date_format)
          log_data = moment().format(pm2_env.log_date_format) + ': ' + data.toString();
        else
          log_data = data.toString();

        God.bus.emit('log:err', {
          process : {
            pm_id      : cspr.pm2_env.pm_id,
            name       : cspr.pm2_env.name,
            rev        : (cspr.pm2_env.versioning && cspr.pm2_env.versioning.revision) ? cspr.pm2_env.versioning.revision : null
          },
          at  : Utility.getDate(),
          data : log_data
        });

        if (Utility.checkPathIsNull(pm2_env.pm_err_log_path) &&
          (!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path))) {
          return false;
        }

        stds.std && stds.std.write && stds.std.write(log_data);
        stds.err && stds.err.write && stds.err.write(log_data);
      });

      cspr.stdout.on('data', function forkOutData(data) {
        var log_data = null;

        if (pm2_env.disable_logs === true)
          return false;

        if (pm2_env.log_type && pm2_env.log_type === 'json') {
          log_data = JSON.stringify({
            message : data.toString(),
            timestamp : pm2_env.log_date_format ? moment().format(pm2_env.log_date_format) : new Date().toISOString(),
            type : 'out',
            process_id : cspr.pm2_env.pm_id,
            app_name : cspr.pm2_env.name
          }) + '\n';
        }
        else if (pm2_env.log_date_format)
          log_data = moment().format(pm2_env.log_date_format) + ': ' + data.toString();
        else
          log_data = data.toString();

        God.bus.emit('log:out', {
          process : {
            pm_id      : cspr.pm2_env.pm_id,
            name       : cspr.pm2_env.name,
            rev        : (cspr.pm2_env.versioning && cspr.pm2_env.versioning.revision) ? cspr.pm2_env.versioning.revision : null
          },
          at  : Utility.getDate(),
          data : log_data
        });

        if (Utility.checkPathIsNull(pm2_env.pm_out_log_path) &&
          (!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path)))
          return false;

        stds.std && stds.std.write && stds.std.write(log_data);
        stds.out && stds.out.write && stds.out.write(log_data);
      });

      /**
       * Broadcast message to God
       */
      cspr.on('message', function forkMessage(msg) {
        /*********************************
         * If you edit this function
         * Do the same in ClusterMode.js !
         *********************************/
        if (msg.data && msg.type) {
          process.nextTick(function() {
            return God.bus.emit(msg.type ? msg.type : 'process:msg', {
              at      : Utility.getDate(),
              data    : msg.data,
              process : {
                pm_id      : cspr.pm2_env.pm_id,
                name       : cspr.pm2_env.name,
                versioning : cspr.pm2_env.versioning
              }
            });
          });
        }
        else {

          if (typeof msg == 'object' && 'node_version' in msg) {
            cspr.pm2_env.node_version = msg.node_version;
            return false;
          } else if (typeof msg == 'object' && 'cron_restart' in msg) {
            // cron onTick is invoked in the process
            return God.restartProcessId({
              id : cspr.pm2_env.pm_id
            }, function() {
              console.log('Application %s has been restarted via CRON', cspr.pm2_env.name);
            });
          }

          return God.bus.emit('process:msg', {
            at      : Utility.getDate(),
            raw     : msg,
            process :  {
              pm_id      : cspr.pm2_env.pm_id,
              name       : cspr.pm2_env.name
            }
          });
        }
      });

      try {
        fs.writeFileSync(pidFile, cspr.pid);
      } catch (e) {
        console.error(e.stack || e);
      }

      cspr.once('exit', function forkClose(status) {
        try {
          for(var k in stds){
            if (stds[k].destroy) stds[k].destroy();
            else if (stds[k].end) stds[k].end();
            else if (stds[k].close) stds[k].close();
            stds[k] = stds[k]._file;
          }
        } catch(e) { God.logAndGenerateError(e);}
      });

      cspr._reloadLogs = function(cb) {
        for (var k in stds){
          if (stds[k].destroy) stds[k].destroy();
          else if (stds[k].end) stds[k].end();
          else if (stds[k].close) stds[k].close();
          stds[k] = stds[k]._file;
        }
        //cspr.removeAllListeners();
        Utility.startLogging(stds, cb);
      };

      cspr.unref();

      return cb(null, cspr);
    });

  };
};


"boolean"
]
},
"increment_var": {
"type": "string"
},

#!/usr/bin/env node
'use strict';

var semver = require('semver');

if (semver.satisfies(process.versions.node, '>= 5.7.0'))
  require('v8-compile-cache');

process.env.PM2_USAGE = 'CLI';

var cst       = require('../constants.js');

var commander = require('commander');
var chalk     = require('chalk');
var async     = require('async');

var debug     = require('debug')('pm2:cli');
var PM2       = require('../lib/API.js');
var pkg       = require('../package.json');
var tabtab    = require('../lib/completion.js');

// Early detection of silent to avoid printing motd
if (process.argv.indexOf('--silent') > -1 ||
    process.argv.indexOf('-s') > -1) {
  process.env.PM2_DISCRETE_MODE = true;
}

if (process.argv.indexOf('-v') > -1) {
  console.log(pkg.version);
  process.exit(0);
}

var pm2 = new PM2();

commander.version(pkg.version)
  .option('-v --version', 'get version')
  .option('-s --silent', 'hide all messages', false)
  .option('-m --mini-list', 'display a compacted list without formatting')
  .option('-f --force', 'force actions')
  .option('--disable-logs', 'do not write logs')
  .option('-n --name <name>', 'set a <name> for script')
  .option('-i --instances <number>', 'launch [number] instances (for networked app)(load balanced)')
  .option('--parallel <number>', 'number of parallel actions (for restart/reload)')
  .option('-l --log [path]', 'specify entire log file (error and out are both included)')
  .option('-o --output <path>', 'specify out log file')
  .option('-e --error <path>', 'specify error log file')
  .option('-p --pid <pid>', 'specify pid file')
  .option('-k --kill-timeout <delay>', 'delay before sending final SIGKILL signal to process')
  .option('--listen-timeout <delay>', 'listen timeout on application reload')
  .option('--max-memory-restart <memory>', 'specify max memory amount used to autorestart (in octet or use syntax like 100M)')
  .option('--restart-delay <delay>', 'specify a delay between restarts (in milliseconds)')
  .option('--env <environment_name>', 'specify environment to get specific env variables (for JSON declaration)')
  .option('--log-type <type>', 'specify log output style (raw by default, json optional)')
  .option('-x --execute-command', 'execute a program using fork system')
  .option('--max-restarts [count]', 'only restart the script COUNT times')
  .option('-u --user <username>', 'define user when generating startup script')
  .option('--uid <uid>', 'run target script with <uid> rights')
  .option('--gid <gid>', 'run target script with <gid> rights')
  .option('--cwd <path>', 'run target script as <username>')
  .option('--hp <home path>', 'define home path when generating startup script')
  .option('--wait-ip', 'override systemd script to wait for full internet connectivity to launch pm2')
  .option('--service-name <name>', 'define service name when generating startup script')
  .option('-c --cron <cron_pattern>', 'restart a running process based on a cron pattern')
  .option('-w --write', 'write configuration in local folder')
  .option('--interpreter <interpreter>', 'the interpreter pm2 should use for executing app (bash, python...)')
  .option('--interpreter-args <arguments>', 'interpret options (alias of --node-args)')
  .option('--log-date-format <date format>', 'add custom prefix timestamp to logs')
  .option('--no-daemon', 'run pm2 daemon in the foreground if it doesn\'t exist already')
  .option('-a --update-env', 'update environment on restart/reload (-a <=> apply)')
  .option('--source-map-support', 'force source map support')
  .option('--only <application-name>', 'with json declaration, allow to only act on one application')
  .option('--disable-source-map-support', 'force source map support')
  .option('--wait-ready', 'ask pm2 to wait for ready event from your app')
  .option('--merge-logs', 'merge logs from different instances but keep error and out separated')
  .option('--watch [paths]', 'watch application folder for changes', function(v, m) { m.push(v); return m;}, [])
  .option('--ignore-watch <folders|files>', 'folder/files to be ignored watching, should be a specific name or regex - e.g. --ignore-watch="test node_modules \"some scripts\""')
  .option('--node-args <node_args>', 'space delimited arguments to pass to node in cluster mode - e.g. --node-args="--debug=7001 --trace-deprecation"')
  .option('--no-color', 'skip colors')
  .option('--no-vizion', 'start an app without vizion feature (versioning control)')
  .option('--no-autorestart', 'start an app without automatic restart')
  .option('--no-treekill', 'Only kill the main process, not detached children')
  .option('--no-pmx', 'start an app without pmx')
  .option('--no-automation', 'start an app without pmx')
  .option('--trace', 'enable transaction tracing with km')
  .option('--disable-trace', 'disable transaction tracing with km')
  .option('--attach', 'attach logging after your start/restart/stop/reload')
  .option('--sort <field_name:sort>', 'sort process according to field\'s name')
  .usage('[cmd] app');

commander.on('--help', function() {
  console.log('  Basic Examples:');
  console.log('');
  console.log('    Start an app using all CPUs available + set a name :');
  console.log('    $ pm2 start app.js -i 0 --name "api"');
  console.log('');
  console.log('    Restart the previous app launched, by name :');
  console.log('    $ pm2 restart api');
  console.log('');
  console.log('    Stop the app :');
  console.log('    $ pm2 stop api');
  console.log('');
  console.log('    Restart the app that is stopped :');
  console.log('    $ pm2 restart api');
  console.log('');
  console.log('    Remove the app from the process list :');
  console.log('    $ pm2 delete api');
  console.log('');
  console.log('    Kill daemon pm2 :');
  console.log('    $ pm2 kill');
  console.log('');
  console.log('    Update pm2 :');
  console.log('    $ npm install pm2@latest -g ; pm2 update');
  console.log('');
  console.log('    More examples in https://github.com/Unitech/pm2#usagefeatures');
  console.log('');
  console.log('  Deployment help:');
  console.log('');
  console.log('    $ pm2 deploy help');
  console.log('');
  console.log('');
});

if (process.argv.indexOf('-s') > -1) {
  for(var key in console){
    var code = key.charCodeAt(0);
    if(code >= 97 && code <= 122){
      console[key] = function(){};
    }
  }
}

function beginCommandProcessing() {
  pm2.getVersion(function(err, remote_version) {
    if (!err && (pkg.version != remote_version)) {
      console.log('');
      console.log(chalk.red.bold('>>>> In-memory PM2 is out-of-date, do:\n>>>> $ pm2 update'));
      console.log('In memory PM2 version:', chalk.blue.bold(remote_version));
      console.log('Local PM2 version:', chalk.blue.bold(pkg.version));
      console.log('');
    }
  });
  commander.parse(process.argv);
}

function checkCompletion(){
  return tabtab.complete('pm2', function(err, data) {
    if(err || !data) return;
    if(/^--\w?/.test(data.last)) return tabtab.log(commander.options.map(function (data) {
      return data.long;
    }), data);
    if(/^-\w?/.test(data.last)) return tabtab.log(commander.options.map(function (data) {
      return data.short;
    }), data);
    // array containing commands after which process name should be listed
    var cmdProcess = ['stop', 'restart', 'scale', 'reload', 'gracefulReload', 'delete', 'reset', 'pull', 'forward', 'backward', 'logs', 'describe', 'desc', 'show'];

    if (cmdProcess.indexOf(data.prev) > -1) {
      pm2.list(function(err, list){
        tabtab.log(list.map(function(el){ return el.name }), data);
        pm2.disconnect();
      });
    }
    else if (data.prev == 'pm2') {
      tabtab.log(commander.commands.map(function (data) {
        return data._name;
      }), data);
      pm2.disconnect();
    }
    else
      pm2.disconnect();
  });
};

var _arr = process.argv.indexOf('--') > -1 ? process.argv.slice(0, process.argv.indexOf('--')) : process.argv;

if (_arr.indexOf('log') > -1) {
  process.argv[_arr.indexOf('log')] = 'logs';
}

if (_arr.indexOf('--no-daemon') > -1) {
  //
  // Start daemon if it does not exist
  //
  // Function checks if --no-daemon option is present,
  // and starts daemon in the same process if it does not exists
  //
  console.log('pm2 launched in no-daemon mode (you can add DEBUG="*" env variable to get more messages)');

  var pm2NoDaeamon = new PM2({
    daemon_mode : false
  });

  pm2NoDaeamon.connect(function() {
    pm2 = pm2NoDaeamon;
    beginCommandProcessing();
  });

}
else if (_arr.indexOf('startup') > -1 || _arr.indexOf('unstartup') > -1) {
  setTimeout(function() {
    commander.parse(process.argv);
  }, 100);
}
else {
  // HERE we instanciate the Client object
  pm2.connect(function() {
    debug('Now connected to daemon');
    if (process.argv.slice(2)[0] === 'completion') {
      checkCompletion();
      //Close client if completion related installation
      var third = process.argv.slice(3)[0];
      if ( third == null || third === 'install' || third === 'uninstall')
        pm2.disconnect();
    }
    else {
      beginCommandProcessing();
    }
  });
}

//
// Helper function to fail when unknown command arguments are passed
//
function failOnUnknown(fn) {
  return function(arg) {
    if (arguments.length > 1) {
      console.log(cst.PREFIX_MSG + '\nUnknown command argument: ' + arg);
      commander.outputHelp();
      process.exit(cst.ERROR_EXIT);
    }
    return fn.apply(this, arguments);
  };
}

/**
 * @todo to remove at some point once it's fixed in official commander.js
 * https://github.com/tj/commander.js/issues/475
 *
 * Patch Commander.js Variadic feature
 */
function patchCommanderArg(cmd) {
  var argsIndex;
  if ((argsIndex = commander.rawArgs.indexOf('--')) >= 0) {
    var optargs = commander.rawArgs.slice(argsIndex + 1);
    cmd = cmd.slice(0, cmd.indexOf(optargs[0]));
  }
  return cmd;
}

//
// Start command
//
commander.command('start <file|json|stdin|app_name|pm_id...>')
  .option('--watch', 'Watch folder for changes')
  .option('--fresh', 'Rebuild Dockerfile')
  .option('--daemon', 'Run container in Daemon mode (debug purposes)')
  .option('--container', 'Start application in container mode')
  .option('--dist', 'with --container; change local Dockerfile to containerize all files in current directory')
  .option('--image-name [name]', 'with --dist; set the exported image name')
  .option('--node-version [major]', 'with --container, set a specific major Node.js version')
  .option('--dockerdaemon', 'for debugging purpose')
  .description('start and daemonize an app')
  .action(function(cmd, opts) {
    if (opts.container == true && opts.dist == true)
      return pm2.dockerMode(cmd, opts, 'distribution');
    else if (opts.container == true)
      return pm2.dockerMode(cmd, opts, 'development');

    if (cmd == "-") {
      process.stdin.resume();
      process.stdin.setEncoding('utf8');
      process.stdin.on('data', function (cmd) {
        process.stdin.pause();
        pm2._startJson(cmd, commander, 'restartProcessId', 'pipe');
      });
    }
    else {
      // Commander.js patch
      cmd = patchCommanderArg(cmd);
      async.forEachLimit(cmd, 1, function(script, next) {
        pm2.start(script, commander, next);
      }, function(err) {
        pm2.speedList(err ? 1 : 0);
      });
    }
  });

commander.command('trigger <proc_name> <action_name> [params]')
  .description('deploy your json')
  .action(function(pm_id, action_name, params) {
    pm2.trigger(pm_id, action_name, params);
  });

commander.command('deploy <file|environment>')
  .description('deploy your json')
  .action(function(cmd) {
    pm2.deploy(cmd, commander);
  });

commander.command('startOrRestart <json>')
  .description('start or restart JSON file')
  .action(function(file) {
    pm2._startJson(file, commander, 'restartProcessId');
  });

commander.command('startOrReload <json>')
  .description('start or gracefully reload JSON file')
  .action(function(file) {
    pm2._startJson(file, commander, 'reloadProcessId');
  });

commander.command('startOrGracefulReload <json>')
  .description('start or gracefully reload JSON file')
  .action(function(file) {
    pm2._startJson(file, commander, 'softReloadProcessId');
  });

//
// Stop specific id
//
commander.command('stop <id|name|all|json|stdin...>')
  .option('--watch', 'Stop watching folder for changes')
  .description('stop a process (to start it again, do pm2 restart <app>)')
  .action(function(param) {
    async.forEachLimit(param, 1, function(script, next) {
      pm2.stop(script, next);
    }, function(err) {
      pm2.speedList(err ? 1 : 0);
    });
  });

//
// Stop All processes
//
commander.command('restart <id|name|all|json|stdin...>')
  .option('--watch', 'Toggle watching folder for changes')
  .description('restart a process')
  .action(function(param) {
    // Commander.js patch
    param = patchCommanderArg(param);
    async.forEachLimit(param, 1, function(script, next) {
      pm2.restart(script, commander, next);
    }, function(err) {
      pm2.speedList(err ? 1 : 0);
    });
  });

//
// Scale up/down a process in cluster mode
//
commander.command('scale <app_name> <number>')
  .description('scale up/down a process in cluster mode depending on total_number param')
  .action(function(app_name, number) {
    pm2.scale(app_name, number);
  });

//
// snapshot PM2
//
commander.command('snapshot')
  .description('snapshot PM2 memory')
  .action(function() {
    pm2.snapshotPM2();
  });

//
// snapshot PM2
//
commander.command('profile <command>')
  .description('profile CPU')
  .action(function(command) {
    pm2.profilePM2(command);
  });

//
// Reload process(es)
//
commander.command('reload <name|all>')
  .description('reload processes (note that its for app using HTTP/HTTPS)')
  .action(function(pm2_id) {
    pm2.reload(pm2_id, commander);
  });

//
// Reload process(es)
//
commander.command('gracefulReload <name|all>')
  .description('gracefully reload a process. Send a "shutdown" message to close all connections.')
  .action(function(pm2_id) {
    pm2.gracefulReload(pm2_id, commander);
  });

commander.command('id <name>')
  .description('get process id by name')
  .action(function(name) {
    pm2.getProcessIdByName(name);
  });

//
// Stop and delete a process by name from database
//
commander.command('delete <name|id|script|all|json|stdin...>')
  .description('stop and delete a process from pm2 process list')
  .action(function(name) {
    if (name == "-") {
      process.stdin.resume();
      process.stdin.setEncoding('utf8');
      process.stdin.on('data', function (param) {
        process.stdin.pause();
        pm2.delete(param, 'pipe');
      });
    } else
      async.forEachLimit(name, 1, function(script, next) {
        pm2.delete(script,'', next);
      }, function(err) {
        pm2.speedList(err ? 1 : 0);
      });
  });

//
// Send system signal to process
//
commander.command('sendSignal <signal> <pm2_id|name>')
  .description('send a system signal to the target process')
  .action(function(signal, pm2_id) {
    if (isNaN(parseInt(pm2_id))) {
      console.log(cst.PREFIX_MSG + 'Sending signal to process name ' + pm2_id);
      pm2.sendSignalToProcessName(signal, pm2_id);
    } else {
      console.log(cst.PREFIX_MSG + 'Sending signal to process id ' + pm2_id);
      pm2.sendSignalToProcessId(signal, pm2_id);
    }
  });

//
// Stop and delete a process by name from database
//
commander.command('ping')
  .description('ping pm2 daemon - if not up it will launch it')
  .action(function() {
    pm2.ping();
  });

commander.command('updatePM2')
  .description('update in-memory PM2 with local PM2')
  .action(function() {
    pm2.update();
  });
commander.command('update')
  .description('(alias) update in-memory PM2 with local PM2')
  .action(function() {
    pm2.update();
  });

/**
 * Module specifics
 */
commander.command('install <module|git:// url>')
  .alias('module:install')
  .option('--v1', 'install module in v1 manner (do not use it)')
  .option('--safe [time]', 'keep module backup, if new module fail = restore with previous')
  .description('install or update a module and run it forever')
  .action(function(plugin_name, opts) {
    if (opts.v1)
      commander.v1 = true;
    if (opts.safe)
      commander.safe = opts.safe;
    pm2.install(plugin_name, commander);
  });

commander.command('module:update <module|git:// url>')
  .description('update a module and run it forever')
  .action(function(plugin_name) {
    pm2.install(plugin_name);
  });

commander.command('module:generate [app_name]')
  .description('Generate a sample module in current folder')
  .action(function(app_name) {
    pm2.generateModuleSample(app_name);
  });

commander.command('uninstall <module>')
  .alias('module:uninstall')
  .description('stop and uninstall a module')
  .action(function(plugin_name) {
    pm2.uninstall(plugin_name);
  });

commander.command('publish')
  .alias('module:publish')
  .description('Publish the module you are currently on')
  .action(function() {
    pm2.publish();
  });

commander.command('set [key] [value]')
  .description('sets the specified config <key> <value>')
  .action(function(key, value) {
    pm2.set(key, value);
  });

commander.command('multiset <value>')
  .description('multiset eg "key1 val1 key2 val2')
  .action(function(str) {
    pm2.multiset(str);
  });

commander.command('get [key]')
  .description('get value for <key>')
  .action(function(key) {
    pm2.get(key);
  });

commander.command('conf [key] [value]')
  .description('get / set module config values')
  .action(function(key, value) {
    pm2.conf(key, value);
  });

commander.command('config <key> [value]')
  .description('get / set module config values')
  .action(function(key, value) {
    pm2.conf(key, value);
  });

commander.command('unset <key>')
  .description('clears the specified config <key>')
  .action(function(key) {
    pm2.unset(key);
  });

commander.command('report')
  .description('give a full pm2 report for https://github.com/Unitech/pm2/issues')
  .action(function(key) {
    pm2.report();
  });

//
// Keymetrics CLI integratio
//
commander.command('link [secret] [public] [name]')
  .alias('interact')
  .option('--info-node [url]', 'set url info node')
  .description('linking action to keymetrics.io - command can be stop|info|delete|restart')
  .action(pm2._pre_interact.bind(pm2));

commander.command('unlink')
  .description('linking action to keymetrics.io - command can be stop|info|delete|restart')
  .action(function() {
    pm2.unlink();
  });

commander.command('unmonitor [name]')
  .description('unmonitor target process')
  .action(function(name) {
    pm2.monitorState('unmonitor', name);
  });

commander.command('monitor [name]')
  .description('monitor target process')
  .action(function(name) {
    pm2.monitorState('monitor', name);
  });

commander.command('open')
  .description('open dashboard in browser')
  .action(function(name) {
    pm2.openDashboard();
  });

commander.command('register')
  .description('create an account on keymetrics')
  .action(function(name) {
    pm2.registerToKM();
  });

commander.command('login')
  .description('login to keymetrics and link current PM2')
  .action(function(name) {
    pm2.loginToKM();
  });

//
// Web interface
//
commander.command('web')
  .description('launch a health API on ' + cst.WEB_IPADDR + ':' + cst.WEB_PORT)
  .action(function() {
    console.log('Launching web interface on ' + cst.WEB_IPADDR + ':' + cst.WEB_PORT);
    pm2.web();
  });

//
// Save processes to file
//
commander.command('dump')
  .alias('save')
  .description('dump all processes for resurrecting them later')
  .action(failOnUnknown(function() {
    pm2.dump();
  }));

//
// Save processes to file
//
commander.command('send <pm_id> <line>')
  .description('send stdin to <pm_id>')
  .action(function(pm_id, line) {
    pm2.sendLineToStdin(pm_id, line);
  });

//
// Attach to stdin/stdout
// Not TTY ready
//
commander.command('attach <pm_id> [command separator]')
  .description('attach stdin/stdout to application identified by <pm_id>')
  .action(function(pm_id, separator) {
    pm2.attach(pm_id, separator);
  });

//
// Resurrect
//
commander.command('resurrect')
  .description('resurrect previously dumped processes')
  .action(failOnUnknown(function() {
    console.log(cst.PREFIX_MSG + 'Resurrecting');
    pm2.resurrect();
  }));

//
// Set pm2 to startup
//
commander.command('unstartup [platform]')
  .description('disable and clear auto startup - [platform]=systemd,upstart,launchd,rcd')
  .action(function(platform) {
    pm2.uninstallStartup(platform, commander);
  });

//
// Set pm2 to startup
//
commander.command('startup [platform]')
  .description('setup script for pm2 at boot - [platform]=systemd,upstart,launchd,rcd')
  .action(function(platform) {
    pm2.startup(platform, commander);
  });

//
// Logrotate
//
commander.command('logrotate')
  .description('copy default logrotate configuration')
  .action(function(cmd) {
    pm2.logrotate(commander);
  });

//
// Sample generate
//

commander.command('ecosystem [mode]')
  .alias('generate')
  .description('generate a process conf file. (mode = null or simple)')
  .action(function(mode) {
    pm2.generateSample(mode);
  });

commander.command('reset <name|id|all>')
  .description('reset counters for process')
  .action(function(proc_id) {
    pm2.reset(proc_id);
  });

commander.command('describe <id>')
  .description('describe all parameters of a process id')
  .action(function(proc_id) {
    pm2.describe(proc_id);
  });

commander.command('desc <id>')
  .description('(alias) describe all parameters of a process id')
  .action(function(proc_id) {
    pm2.describe(proc_id);
  });

commander.command('info <id>')
  .description('(alias) describe all parameters of a process id')
  .action(function(proc_id) {
    pm2.describe(proc_id);
  });

commander.command('show <id>')
  .description('(alias) describe all parameters of a process id')
  .action(function(proc_id) {
    pm2.describe(proc_id);
  });

//
// List command
//
commander
  .command('list')
  .alias('ls')
  .description('list all processes')
  .action(function() {
    pm2.list(commander)
  });

commander.command('l')
  .description('(alias) list all processes')
  .action(function() {
    pm2.list()
  });

commander.command('ps')
  .description('(alias) list all processes')
  .action(function() {
    pm2.list()
  });

commander.command('status')
  .description('(alias) list all processes')
  .action(function() {
    pm2.list()
  });

// List in raw json
commander.command('jlist')
  .description('list all processes in JSON format')
  .action(function() {
    pm2.jlist()
  });

// List in prettified Json
commander.command('prettylist')
  .description('print json in a prettified JSON')
  .action(failOnUnknown(function() {
    pm2.jlist(true);
  }));

//
// Dashboard command
//
commander.command('monit')
  .description('launch termcaps monitoring')
  .action(function() {
    pm2.dashboard();
  });

commander.command('imonit')
  .description('launch legacy termcaps monitoring')
  .action(function() {
    pm2.monit();
  });

commander.command('dashboard')
  .alias('dash')
  .description('launch dashboard with monitoring and logs')
  .action(function() {
    pm2.dashboard();
  });

//
// Flushing command
//
commander.command('flush')
  .description('flush logs')
  .action(failOnUnknown(function() {
    pm2.flush();
  }));

//
// Reload all logs
//
commander.command('reloadLogs')
  .description('reload all logs')
  .action(function() {
    pm2.reloadLogs();
  });

//
// Log streaming
//
commander.command('logs [id|name]')
  .option('--json', 'json log output')
  .option('--format', 'formated log output')
  .option('--raw', 'raw output')
  .option('--err', 'only shows error output')
  .option('--out', 'only shows standard output')
  .option('--lines <n>', 'output the last N lines, instead of the last 15 by default')
  .option('--timestamp [format]', 'add timestamps (default format YYYY-MM-DD-HH:mm:ss)')
  .option('--nostream', 'print logs without lauching the log stream')
  .description('stream logs file. Default stream all logs')
  .action(function(id, cmd) {
    var Logs = require('../lib/API/Log.js');

    if (!id) id = 'all';

    var line = 15;
    var raw  = false;
    var exclusive = false;
    var timestamp = false;

    if(!isNaN(parseInt(cmd.lines))) {
      line = parseInt(cmd.lines);
    }

    if (cmd.parent.rawArgs.indexOf('--raw') !== -1)
      raw = true;

    if (cmd.timestamp)
      timestamp = typeof cmd.timestamp === 'string' ? cmd.timestamp : 'YYYY-MM-DD-HH:mm:ss';

    if (cmd.out === true)
      exclusive = 'out';

    if (cmd.err === true)
      exclusive = 'err';

    if (cmd.nostream === true)
      pm2.printLogs(id, line, raw, timestamp, exclusive);
    else if (cmd.json === true)
      Logs.jsonStream(pm2.Client, id);
    else if (cmd.format === true)
      Logs.formatStream(pm2.Client, id, false, 'YYYY-MM-DD-HH:mm:ssZZ');
    else
      pm2.streamLogs(id, line, raw, timestamp, exclusive);
  });

//
// Kill
//
commander.command('kill')
  .description('kill daemon')
  .action(failOnUnknown(function(arg) {
    pm2.killDaemon(function() {
      process.exit(cst.SUCCESS_EXIT);
    });
  }));

//
// Update repository for a given app
//

commander.command('pull <name> [commit_id]')
  .description('updates repository for a given app')
  .action(function(pm2_name, commit_id) {

    if (commit_id !== undefined) {
      pm2._pullCommitId({
        pm2_name: pm2_name,
        commit_id: commit_id
      });
    }
    else
      pm2.pullAndRestart(pm2_name);
  });

//
// Update repository to the next commit for a given app
//
commander.command('forward <name>')
  .description('updates repository to the next commit for a given app')
  .action(function(pm2_name) {
    pm2.forward(pm2_name);
  });

//
// Downgrade repository to the previous commit for a given app
//
commander.command('backward <name>')
  .description('downgrades repository to the previous commit for a given app')
  .action(function(pm2_name) {
    pm2.backward(pm2_name);
  });

//
// Force PM2 to trigger garbage collection
//
commander.command('gc')
  .description('force PM2 to trigger garbage collection')
  .action(function() {
    pm2.forceGc();
  });

//
// Perform a deep update of PM2
//
commander.command('deepUpdate')
  .description('performs a deep update of PM2')
  .action(function() {
    pm2.deepUpdate();
  });

//
// Launch a http server that expose a given path on given port
//
commander.command('serve [path] [port]')
  .alias('expose')
  .description('serve a directory over http via port')
  .action(function (path, port) {
    pm2.serve(path, port, commander);
  });

//
// Catch all
//
commander.command('*')
  .action(function() {
    console.log(cst.PREFIX_MSG + '\nCommand not found');
    commander.outputHelp();
    // Check if it does not forget to close fds from RPC
    process.exit(cst.ERROR_EXIT);
  });

//
// Display help if 0 arguments passed to pm2
//
if (process.argv.length == 2) {
  commander.parse(process.argv);
  commander.outputHelp();
  // Check if it does not forget to close fds from RPC
  process.exit(cst.ERROR_EXIT);
}


gl_retry commander require fs path async debug util chalk fclone IMMUTABLE_MSG bold blue API module exports opts that this daemon_mode pm2_home conf PM2_ROOT_PATH public_key process env KEYMETRICS_SECRET secret_key KEYMETRICS_PUBLIC machine_name INSTANCE_NAME cwd resolve independent Error _extend path_structure IS_WINDOWS random_file randomBytes toString join _conf stdout _handle setBlocking Client gl_interact_infos gl_is_km_linked pid readFileSync INTERACTOR_PID_PATH parseInt trim kill e NODE_ENV KMDaemon getInteractInfo i_err interact prototype connect noDaemon cb start_timer Date start err meta new_pm2_instance Modularizer launchAll err_mod destroy exec killDaemon cmd test_path indexOf accessSync access R_OK exists exist disconnect close data launchModules


process.on('SIGINT', function() {
  // Do othing for tests
});

setInterval(function() {
  console.log('I\'m alive');
}, 2000);


http: process.env.km_link == 'true' || false,

/**
 * Copyright 2013 the PM2 project authors. All rights reserved.
 * Use of this source code is governed by a license that
 * can be found in the LICENSE file.
 *
 * This file wrap target application
 * - redirect stdin, stderr to bus + log files
 * - rename process
 * - pid
 */

var p       = require('path');
var cst     = require('../constants');
var Utility = require('./Utility.js');

// Load all env-vars from master.
var pm2_env = JSON.parse(process.env.pm2_env);
for(var k in pm2_env) {
  process.env[k] = pm2_env[k];
}

// Rename process
process.title = process.env.PROCESS_TITLE || 'node ' + pm2_env.pm_exec_path;

delete process.env.pm2_env;

/**
 * Main entrance to wrap the desired code
 */
(function ProcessContainer() {
  var fs          = require('fs');

  if (process.env.pmx !== 'false')
    require('pmx').init({
      transactions: process.env.km_link == 'true' && process.env.trace == 'true' || false,
      http: process.env.km_link == 'true' || false
    });

  var stdFile     = pm2_env.pm_log_path;
  var outFile     = pm2_env.pm_out_log_path;
  var errFile     = pm2_env.pm_err_log_path;
  var pmId        = pm2_env.pm_id;
  var pidFile     = pm2_env.pm_pid_path;
  var script      = pm2_env.pm_exec_path;
  var cronRestart = pm2_env.cron_restart;

  var original_send = process.send;

  if (typeof(process.env.source_map_support) != 'undefined' &&
      process.env.source_map_support !== 'false') {
    require('source-map-support').install();
  }

  process.send = function() {
    if (process.connected)
      original_send.apply(this, arguments);
  };

  //send node version
  if (process.versions && process.versions.node) {
    process.send({
      'node_version': process.versions.node
    });
  }

  if (cst.MODIFY_REQUIRE)
    require.main.filename = pm2_env.pm_exec_path;

  // Resets global paths for require()
  require('module')._initPaths();

  try {
    fs.writeFileSync(pidFile, process.pid);
  } catch (e) {
    console.error(e.stack || e);
  }

  // Add args to process if args specified on start
  if (process.env.args != null)
    process.argv = process.argv.concat(pm2_env.args);

  // stdio, including: out, err and entire (both out and err if necessary).
  var stds = {
    out: outFile,
    err: errFile
  };
  stdFile && (stds.std = stdFile);

  // uid/gid management
  if (pm2_env.uid || pm2_env.gid) {
    try {
      if (pm2_env.uid)
        process.setuid(pm2_env.uid);
      if (process.env.gid)
        process.setgid(pm2_env.gid);
    } catch(e) {
      setTimeout(function() {
        console.error('%s on call %s', e.message, e.syscall);
        console.error('%s is not accessible', pm2_env.uid);
        return process.exit(1);
      }, 100);
    }
  }

  exec(script, stds);

  if (cronRestart)
    cronize(cronRestart);
})();

/**
 * Cron restart
 */
function cronize(cron_pattern) {
  var cronJob = require('cron').CronJob;
  var job = new cronJob({
    cronTime: cron_pattern,
    onTick  : function() {
      if (process.connected && process.send) {
        process.send({
          'cron_restart': 1
        });
      } else {
        process.emit('disconnect');
        process.nextTick(function() {
          process.exit(0);
        });
      }
    },
    start: false
  });
  job.start();
}

/**
 * Description
 * @method exec
 * @param {} script
 * @param {} stds
 * @return
 */
function exec(script, stds) {
  if (p.extname(script) == '.coffee') {
    try {
      require('coffee-script/register');
    } catch (e) {
      console.error('Failed to load CoffeeScript interpreter:', e.message || e);
    }
  }

  if (p.extname(script) == '.ls') {
    try {
      require('livescript');
    } catch (e) {
      console.error('Failed to load LiveScript interpreter:', e.message || e);
    }
  }

  if (p.extname(script) == '.ts' || p.extname(script) == '.tsx') {
    try {
      require('ts-node/register');
    } catch (e) {
      console.error('Failed to load Typescript interpreter:', e.message || e);
    }
  }

  process.on('message', function (msg) {
    if (msg.type === 'log:reload') {
      for (var k in stds){
        if (typeof stds[k] == 'object' && !isNaN(stds[k].fd)){
          if (stds[k].destroy) stds[k].destroy();
          else if (stds[k].end) stds[k].end();
          else if (stds[k].close) stds[k].close();
          stds[k] = stds[k]._file;
        }
      }
      Utility.startLogging(stds, function (err) {
        if (err)
          return console.error('Failed to reload logs:', err.stack);
        console.log('Reloading log...');
      });
    }
  });

  var moment = null;

  if (pm2_env.log_date_format)
    moment = require('moment');

  Utility.startLogging(stds, function (err) {
    if (err) {
      process.send({
        type    : 'process:exception',
        data    : {
          message: err.message,
          syscall: 'ProcessContainer.startLogging'
        }
      });
      throw err;
      return;
    }

    process.stderr.write = (function(write) {
      return function(string, encoding, cb) {
        var log_data = null;

        // Disable logs if specified
        if (pm2_env.disable_logs === true) {
          return cb ? cb() : false;
        }

        if (pm2_env.log_type && pm2_env.log_type === 'json') {
          log_data = JSON.stringify({
            message : string.toString(),
            timestamp : pm2_env.log_date_format && moment ?
              moment().format(pm2_env.log_date_format) : new Date().toISOString(),
            type : 'err',
            process_id : pm2_env.pm_id,
            app_name : pm2_env.name
          }) + '\n';
        }
        else if (pm2_env.log_date_format && moment)
          log_data = moment().format(pm2_env.log_date_format) + ': ' + string.toString();
        else
          log_data = string.toString();

        process.send({
          type : 'log:err',
          data : log_data
        });

        if (Utility.checkPathIsNull(pm2_env.pm_err_log_path) &&
          (!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path)))
          return cb ? cb() : false;

        stds.std && stds.std.write && stds.std.write(log_data, encoding);
        stds.err && stds.err.write && stds.err.write(log_data, encoding, cb);
      };
    })(process.stderr.write);

    process.stdout.write = (function(write) {
      return function(string, encoding, cb) {
        var log_data = null;

        // Disable logs if specified
        if (pm2_env.disable_logs === true) {
          return cb ? cb() : false;
        }

        if (pm2_env.log_type && pm2_env.log_type === 'json') {
          log_data = JSON.stringify({
            message : string.toString(),
            timestamp : pm2_env.log_date_format && moment ?
              moment().format(pm2_env.log_date_format) : new Date().toISOString(),
            type : 'out',
            process_id : pm2_env.pm_id,
            app_name : pm2_env.name
          }) + '\n';
        }
        else if (pm2_env.log_date_format && moment)
          log_data = moment().format(pm2_env.log_date_format) + ': ' + string.toString();
        else
          log_data = string.toString();

        process.send({
          type : 'log:out',
          data : log_data
        });

        if (Utility.checkPathIsNull(pm2_env.pm_out_log_path) &&
          (!pm2_env.pm_log_path || Utility.checkPathIsNull(pm2_env.pm_log_path)))
          return cb ? cb() : null;

        stds.std && stds.std.write && stds.std.write(log_data, encoding);
        stds.out && stds.out.write && stds.out.write(log_data, encoding, cb);
      };
    })(process.stdout.write);

    function getUncaughtExceptionListener(listener) {
      return function uncaughtListener(err) {
        var error = err && err.stack ? err.stack : err;

        if (listener === 'unhandledRejection') {
          error = 'You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection:\n' + error;
        }

        logError(['std', 'err'], error);

        // Notify master that an uncaughtException has been catched
        try {
          if (err) {
            var errObj = {};

            Object.getOwnPropertyNames(err).forEach(function(key) {
              errObj[key] = err[key];
            });
          }

          process.send({
            type : 'log:err',
            data : '\n' + error + '\n'
          });
          process.send({
            type    : 'process:exception',
            data    : errObj !== undefined ? errObj : {message: 'No error but ' + listener + ' was caught!'}
          });
        } catch(e) {
          logError(['std', 'err'], 'Channel is already closed can\'t broadcast error:\n' + e.stack);
        }

        if (!process.listeners(listener).filter(function (listener) {
            return listener !== uncaughtListener;
        }).length) {
          if (listener == 'uncaughtException') {
            process.emit('disconnect');
            process.exit(cst.CODE_UNCAUGHTEXCEPTION);
          }
        }
      }
    }

    process.on('uncaughtException', getUncaughtExceptionListener('uncaughtException'));
    process.on('unhandledRejection', getUncaughtExceptionListener('unhandledRejection'));

    // Change dir to fix process.cwd
    process.chdir(pm2_env.pm_cwd || process.env.PWD || p.dirname(script));

    require('module')._load(script, null, true);

    function logError(types, error){
      try {
        types.forEach(function(type){
          stds[type] && typeof stds[type].write == 'function' && stds[type].write(error + '\n');
        });
      } catch(e) { }
    }
  });

}


#!/usr/bin/env bash

SRC=$(cd $(dirname "$0"); pwd)
source "${SRC}/include.sh"

cd $file_path/promise/

# Check for 0.10 & 0.12 support
node -e "process.version.indexOf('v0') > -1 ? process.exit(1) : process.exit(0)"
RET=$?
[ $RET -eq 0 ] || exit 0

echo "###### Cluster mode"
> rejection.log
$pm2 start rejection.js -i 1 -l rejection.log --merge-logs
sleep 1
should 'should has not restarted process' 'restart_time: 0' 1
cat rejection.log | grep "You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection"
spec "should have logged promise error"

$pm2 delete all

> empty-rejection.log
$pm2 start empty-rejection.js -i 1 -l empty-rejection.log --merge-logs
sleep 1
should 'should has not restarted process' 'restart_time: 0' 1

cat empty-rejection.log | grep "You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection"
spec "should have logged promise error"

$pm2 delete all

echo "###### Fork mode"

> rejection.log
$pm2 start rejection.js -l rejection.log --merge-logs
sleep 1
should 'should has not restarted process' 'restart_time: 0' 1

cat rejection.log | grep "You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection"
spec "should have logged promise error"

$pm2 delete all

> empty-rejection.log
$pm2 start empty-rejection.js -l empty-rejection.log --merge-logs
sleep 1
should 'should has not restarted process' 'restart_time: 0' 1

cat empty-rejection.log | grep "You have triggered an unhandledRejection, you may have forgotten to catch a Promise rejection"
spec "should have logged promise error"


// Time units, as found in Java:
// see: http://download.oracle.com/javase/6/docs/api/java/util/concurrent/TimeUnit.html
exports.NANOSECONDS  = 1 / (1000 * 1000);
exports.MICROSECONDS = 1 / 1000;
exports.MILLISECONDS = 1;
exports.SECONDS      = 1000 * exports.MILLISECONDS;
exports.MINUTES      = 60 * exports.SECONDS;
exports.HOURS        = 60 * exports.MINUTES;
exports.DAYS         = 24 * exports.HOURS;


process.env.NODE_ENV = 'local_test';
process.env.KM_URL_REFRESH_RATE = 1000;

var axon       = require('pm2-axon');
var PM2        = require('../..');
var should = require('should');
var sub;

function listen(cb) {
  sub = axon.socket('sub');
  sub.bind(8080, cb);
}

function listenRev(cb) {
  var listener_server = require('nssocket').createServer(function(_socket) {
  });

  listener_server.listen(4322, '0.0.0.0', function() {
    console.log('Reverse interact online');
    cb();
  });
}

describe('Programmatically test interactor', function() {
  var pm2;

  before(function(done) {
    listen(function() {
      listenRev(function() {

        pm2 = new PM2.custom({
          public_key : 'xxx',
          secret_key : 'yyy',
          cwd        : __dirname + '/../fixtures/interface'
        });

        pm2.connect(function() {
          pm2.kill(function() {
            done();
          });
        });
      });
    });
  });

  after(function(done) {
    pm2.kill(done);
  });

  describe('application testing', function() {
    it('should start test application', function(done) {
      sub.once('message', function(data) {
        var packet = JSON.parse(data);
        packet.data['process:event'].length.should.eql(2)
        done();
      });

      pm2.start({
        script : 'process_exception_with_logs.js',
        name   : 'API'
      }, function(err, data) {
        if (err) done(err);
        //console.log(arguments);
      });
    });

    it('should get transaction trace via interactor output', function(done) {
      (function callAgain() {
        sub.once('message', function(data) {
          var packet = JSON.parse(data);

          if (packet.data['process:exception']) {
            packet.data['process:exception'][0].data.callsite.should.containEql('process_exception_with_logs.js:7');
            packet.data['process:exception'][0].data.context.should.containEql('console.log');
            should.exist(packet.data['process:exception'][0].data.last_logs);
            //console.log
            done();
          }
          else callAgain();
        });
      })()

      pm2.trigger('API', 'exception');
    });

  });
});


test.isTrue(isModern({
name: "chrome",
major: 60,
}));
test.isFalse(isModern({
name: "firefox",
major: 25,
}));

keep keep keep keep add keep keep keep keep keep

test.isTrue(isModern({
name: "chromeMobile",
major: 60,
}));

const minimumVersions = Object.create(null);
const hasOwn = Object.prototype.hasOwnProperty;

// TODO Should it be possible for callers to setMinimumBrowserVersions to
// forbid any version of a particular browser?

// Given a { name, major, minor, patch } object like the one provided by
// webapp via request.browser, return true if that browser qualifies as
// "modern" according to all requested version constraints.
function isModern(browser) {
  return browser &&
    typeof browser.name === "string" &&
    hasOwn.call(minimumVersions, browser.name) &&
    greaterThanOrEqualTo([
      ~~browser.major,
      ~~browser.minor,
      ~~browser.patch,
    ], minimumVersions[browser.name].version);
}

// Any package that depends on the modern-browsers package can call this
// function to communicate its expectations for the minimum browser
// versions that qualify as "modern." The final decision between
// web.browser.legacy and web.browser will be based on the maximum of all
// requested minimum versions for each browser.
function setMinimumBrowserVersions(versions, source) {
  Object.keys(versions).forEach(browserName => {
    if (hasOwn.call(minimumVersions, browserName) &&
        ! greaterThan(versions[browserName],
                      minimumVersions[browserName].version)) {
      return;
    }

    minimumVersions[browserName] = {
      version: copy(versions[browserName]),
      source: source || getCaller("setMinimumBrowserVersions")
    };
  });
}

function getCaller(calleeName) {
  const error = new Error;
  Error.captureStackTrace(error);
  const lines = error.stack.split("\n");
  let caller;
  lines.some((line, i) => {
    if (line.indexOf(calleeName) >= 0) {
      caller = lines[i + 1].trim();
      return true;
    }
  });
  return caller;
}

Object.assign(exports, {
  isModern,
  setMinimumBrowserVersions,
});

// For making defensive copies of [major, minor, ...] version arrays, so
// they don't change unexpectedly.
function copy(version) {
  if (typeof version === "number") {
    return version;
  }

  if (Array.isArray(version)) {
    return version.map(copy);
  }

  return version;
}

function greaterThanOrEqualTo(a, b) {
  return ! greaterThan(b, a);
}

function greaterThan(a, b) {
  const as = (typeof a === "number") ? [a] : a;
  const bs = (typeof b === "number") ? [b] : b;
  const maxLen = Math.max(as.length, bs.length);

  for (let i = 0; i < maxLen; ++i) {
    a = (i < as.length) ? as[i] : 0;
    b = (i < bs.length) ? bs[i] : 0;

    if (a > b) {
      return true;
    }

    if (a < b) {
      return false;
    }
  }

  return false;
}

function makeSource(feature) {
  return module.id + " (" + feature + ")"
}

setMinimumBrowserVersions({
  chrome: 49,
  edge: 12,
  firefox: 45,
  mobile_safari: [9, 2],
  opera: 36,
  safari: 9,
}, makeSource("classes"));

setMinimumBrowserVersions({
  chrome: 39,
  edge: 13,
  firefox: 26,
  mobile_safari: 10,
  opera: 26,
  safari: 10,
  // Disallow any version of PhantomJS.
  phantomjs: Infinity,
}, makeSource("generator functions"));

setMinimumBrowserVersions({
  chrome: 41,
  edge: 13,
  firefox: 34,
  mobile_safari: [9, 2],
  opera: 29,
  safari: [9, 1],
}, makeSource("template literals"));

setMinimumBrowserVersions({
  chrome: 38,
  edge: 12,
  firefox: 36,
  mobile_safari: 9,
  opera: 25,
  safari: 9,
}, makeSource("symbols"));