// 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/browser/native_window_toolbar_win.h"

#include "base/logging.h"
#include "base/string16.h"
#include "base/utf_string_conversions.h"
#include "content/nw/src/nw_shell.h"
#include "grit/nw_resources.h"
#include "grit/ui_resources.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/views/background.h"
#include "ui/views/controls/button/image_button.h"
#include "ui/views/controls/textfield/textfield.h"
#include "ui/views/layout/box_layout.h"

namespace nw {

const int kButtonMargin = 2;

NativeWindowToolbarWin::NativeWindowToolbarWin(content::Shell* shell)
    : shell_(shell) {
}

NativeWindowToolbarWin::~NativeWindowToolbarWin() {
}

views::View* NativeWindowToolbarWin::GetContentsView() {
  return this;
}

void NativeWindowToolbarWin::Layout() {
  int panel_width = width();
  int x = kButtonMargin;

  // Place three left buttons.
  gfx::Size sz = back_button_->GetPreferredSize();
  back_button_->SetBounds(x, (height() - sz.height()) / 2,
                          sz.width(), sz.height());
  x += sz.width() + kButtonMargin;

  sz = forward_button_->GetPreferredSize();
  forward_button_->SetBounds(x, back_button_->y(),
                             sz.width(), sz.height());
  x += sz.width() + kButtonMargin;

  sz = stop_or_refresh_button_->GetPreferredSize();
  stop_or_refresh_button_->SetBounds(x, back_button_->y(),
                                     sz.width(), sz.height());
  x += sz.width() + kButtonMargin;

  // And place dev reload button as far as possible.
  sz = dev_reload_button_->GetPreferredSize();
  dev_reload_button_->SetBounds(panel_width - sz.width() - kButtonMargin,
                                back_button_->y(),
                                sz.width(),
                                sz.height());

  sz = devtools_button_->GetPreferredSize();
  devtools_button_->SetBounds(dev_reload_button_->x() - sz.width() - kButtonMargin,
                              back_button_->y(),
                              sz.width(),
                              sz.height());

  // Stretch url entry.
  url_entry_->SetBounds(x,
                        (height() - 24) / 2,
                        devtools_button_->x() - kButtonMargin - x,
                        24);
}

void NativeWindowToolbarWin::ViewHierarchyChanged(bool is_add,
                                                  views::View* parent,
                                                  views::View* child) {
  if (is_add && child == this)
    InitToolbar();
}

void NativeWindowToolbarWin::ContentsChanged(
    views::Textfield* sender,
    const string16& new_contents) {
}

bool NativeWindowToolbarWin::HandleKeyEvent(views::Textfield* sender,
                                            const ui::KeyEvent& key_event) {
  if (key_event.key_code() == ui::VKEY_RETURN) {
    string16 url_string = url_entry_->text();
    if (!url_string.empty()) {
      GURL url(url_string);
      if (!url.has_scheme())
        url = GURL(L"http://" + url_string);
      shell_->LoadURL(url);
    }
  }

  return false;
}

void NativeWindowToolbarWin::ButtonPressed(views::Button* sender,
                                           const ui::Event& event) {
  if (sender == back_button_)
    shell_->GoBackOrForward(-1);
  else if (sender == forward_button_)
    shell_->GoBackOrForward(1);
  else if (sender == stop_or_refresh_button_)
    shell_->ReloadOrStop();
  else if (sender == devtools_button_)
    shell_->ShowDevTools();
  else if (sender == dev_reload_button_)
    shell_->Reload(content::Shell::RELOAD_DEV);

  NOTREACHED() << "Click on unkown toolbar button.";
}

void NativeWindowToolbarWin::InitToolbar() {
  set_background(views::Background::CreateStandardPanelBackground());

  views::BoxLayout* layout = new views::BoxLayout(
      views::BoxLayout::kHorizontal, 5, 5, 10);
  SetLayoutManager(layout);

  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
  back_button_ = new views::ImageButton(this);
  back_button_->SetImage(views::CustomButton::STATE_NORMAL,
      rb.GetNativeImageNamed(IDR_NW_BACK).ToImageSkia());
  back_button_->SetImage(views::CustomButton::STATE_HOVERED,
      rb.GetNativeImageNamed(IDR_NW_BACK_H).ToImageSkia());
  back_button_->SetImage(views::CustomButton::STATE_PRESSED,
      rb.GetNativeImageNamed(IDR_NW_BACK_P).ToImageSkia());
  back_button_->SetImage(views::CustomButton::STATE_DISABLED,
      rb.GetNativeImageNamed(IDR_NW_BACK_D).ToImageSkia());
  back_button_->SetAccessibleName(L"Back");
  AddChildView(back_button_);

  forward_button_ = new views::ImageButton(this);
  forward_button_->SetImage(views::CustomButton::STATE_NORMAL,
      rb.GetNativeImageNamed(IDR_NW_FORWARD).ToImageSkia());
  forward_button_->SetImage(views::CustomButton::STATE_HOVERED,
      rb.GetNativeImageNamed(IDR_NW_FORWARD_H).ToImageSkia());
  forward_button_->SetImage(views::CustomButton::STATE_PRESSED,
      rb.GetNativeImageNamed(IDR_NW_FORWARD_P).ToImageSkia());
  forward_button_->SetImage(views::CustomButton::STATE_DISABLED,
      rb.GetNativeImageNamed(IDR_NW_FORWARD_D).ToImageSkia());
  forward_button_->SetAccessibleName(L"Forward");
  AddChildView(forward_button_);

  stop_or_refresh_button_ = new views::ImageButton(this);
  SetIsLoading(true);
  AddChildView(stop_or_refresh_button_);

  url_entry_ = new views::Textfield(views::Textfield::STYLE_DEFAULT);
  url_entry_->SetController(this);
  AddChildView(url_entry_);

  devtools_button_ = new views::ImageButton(this);
  devtools_button_->SetImage(views::CustomButton::STATE_NORMAL,
      rb.GetNativeImageNamed(IDR_NW_TOOLS).ToImageSkia());
  devtools_button_->SetImage(views::CustomButton::STATE_HOVERED,
      rb.GetNativeImageNamed(IDR_NW_TOOLS_H).ToImageSkia());
  devtools_button_->SetImage(views::CustomButton::STATE_PRESSED,
      rb.GetNativeImageNamed(IDR_NW_TOOLS_P).ToImageSkia());
  devtools_button_->SetAccessibleName(L"Devtools");
  AddChildView(devtools_button_);

  dev_reload_button_ = new views::ImageButton(this);
  dev_reload_button_->SetImage(views::CustomButton::STATE_NORMAL,
      rb.GetNativeImageNamed(IDR_NW_RELOAD).ToImageSkia());
  dev_reload_button_->SetImage(views::CustomButton::STATE_HOVERED,
      rb.GetNativeImageNamed(IDR_NW_RELOAD_H).ToImageSkia());
  dev_reload_button_->SetImage(views::CustomButton::STATE_PRESSED,
      rb.GetNativeImageNamed(IDR_NW_RELOAD_P).ToImageSkia());
  dev_reload_button_->SetImage(views::CustomButton::STATE_DISABLED,
      rb.GetNativeImageNamed(IDR_NW_RELOAD_D).ToImageSkia());
  dev_reload_button_->SetAccessibleName(L"Reload render process");
  AddChildView(dev_reload_button_);
}

void NativeWindowToolbarWin::SetButtonEnabled(
    NativeWindow::TOOLBAR_BUTTON button,
    bool enabled) {
  switch (button) {
    case nw::NativeWindow::BUTTON_BACK:
      back_button_->SetEnabled(enabled);
      break;
    case nw::NativeWindow::BUTTON_FORWARD:
      forward_button_->SetEnabled(enabled);
      break;
    case nw::NativeWindow::BUTTON_REFRESH_OR_STOP:
      stop_or_refresh_button_->SetEnabled(enabled);
      break;
    case nw::NativeWindow::BUTTON_DEVTOOLS:
      devtools_button_->SetEnabled(enabled);
      break;
    case nw::NativeWindow::BUTTON_REFRESH_DEV:
      dev_reload_button_->SetEnabled(enabled);
      break;
  }
}

void NativeWindowToolbarWin::SetUrlEntry(const std::string& url) {
  url_entry_->SetText(UTF8ToUTF16(url));
}

void NativeWindowToolbarWin::SetIsLoading(bool loading) {
  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();

  if (loading) {
    stop_or_refresh_button_->SetImage(views::CustomButton::STATE_NORMAL,
        rb.GetNativeImageNamed(IDR_NW_STOP).ToImageSkia());
    stop_or_refresh_button_->SetImage(views::CustomButton::STATE_HOVERED,
        rb.GetNativeImageNamed(IDR_NW_STOP_H).ToImageSkia());
    stop_or_refresh_button_->SetImage(views::CustomButton::STATE_PRESSED,
        rb.GetNativeImageNamed(IDR_NW_STOP_P).ToImageSkia());
    stop_or_refresh_button_->SetImage(views::CustomButton::STATE_DISABLED,
        rb.GetNativeImageNamed(IDR_NW_STOP_D).ToImageSkia());
    stop_or_refresh_button_->SetAccessibleName(L"Stop");
  } else {
    stop_or_refresh_button_->SetImage(views::CustomButton::STATE_NORMAL,
        rb.GetNativeImageNamed(IDR_NW_RELOAD).ToImageSkia());
    stop_or_refresh_button_->SetImage(views::CustomButton::STATE_HOVERED,
        rb.GetNativeImageNamed(IDR_NW_RELOAD_H).ToImageSkia());
    stop_or_refresh_button_->SetImage(views::CustomButton::STATE_PRESSED,
        rb.GetNativeImageNamed(IDR_NW_RELOAD_P).ToImageSkia());
    stop_or_refresh_button_->SetImage(views::CustomButton::STATE_DISABLED,
        rb.GetNativeImageNamed(IDR_NW_RELOAD_D).ToImageSkia());
    stop_or_refresh_button_->SetAccessibleName(L"Reload");
  }

  // Force refresh
  stop_or_refresh_button_->SchedulePaint();
}

}  // namespace nw


CommandLine* command_line = CommandLine::ForCurrentProcess();

for (unsigned i = 0; i < chromium_args.size(); ++i) {

if (!IsSwitch(chromium_args[i], &key, &value))

// Note:: On Windows, the |CommandLine::StringType| will be |std::wstring|,

// so the chromium_args[i] is not compatible. We convert the wstring to

// string here is safe beacuse we use ASCII only.

if (!IsSwitch(ASCIIToWide(chromium_args[i]), &key, &value))

// 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/api/bindings_common.h"

#include "base/logging.h"
#include "base/values.h"
#include "content/nw/src/api/api_messages.h"
#include "content/public/renderer/render_view.h"
#include "content/public/renderer/render_thread.h"
#include "content/public/renderer/v8_value_converter.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebView.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebFrame.h"
#include "ui/base/resource/resource_bundle.h"

using content::RenderView;
using content::RenderThread;
using content::V8ValueConverter;
using WebKit::WebFrame;
using WebKit::WebView;

RenderView* GetCurrentRenderView() {
  WebFrame* frame = WebFrame::frameForCurrentContext();
  if (!frame)
    return NULL;

  WebView* view = frame->view();
  if (!view)
    return NULL;  // can happen during closing.

  RenderView* render_view = RenderView::FromWebView(view);
  return render_view;
}

base::StringPiece GetStringResource(int resource_id) {
  return ResourceBundle::GetSharedInstance().GetRawDataResource(resource_id);
}

namespace remote {

v8::Handle<v8::Value> AllocateObject(int routing_id,
                                     int object_id,
                                     const std::string& type,
                                     v8::Handle<v8::Value> options) {
  v8::HandleScope handle_scope;

  scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());
  converter->SetStripNullFromObjects(true);

  scoped_ptr<base::Value> value_option(
      converter->FromV8Value(options, v8::Context::GetCurrent()));
  if (!value_option.get() ||
      !value_option->IsType(base::Value::TYPE_DICTIONARY))
    return v8::ThrowException(v8::Exception::Error(v8::String::New(
        "Unable to convert 'option' passed to AllocateObject")));

  RenderThread::Get()->Send(new ShellViewHostMsg_Allocate_Object(
      routing_id,
      object_id,
      type,
      *static_cast<base::DictionaryValue*>(value_option.get())));
  return v8::Undefined();
}

v8::Handle<v8::Value> DeallocateObject(int routing_id,
                                       int object_id) {
  RenderThread::Get()->Send(new ShellViewHostMsg_Deallocate_Object(
      routing_id, object_id));
  return v8::Undefined();
}

v8::Handle<v8::Value> CallObjectMethod(int routing_id,
                                       int object_id,
                                       const std::string& type,
                                       const std::string& method,
                                       v8::Handle<v8::Value> args) {
  scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());

  scoped_ptr<base::Value> value_args(
      converter->FromV8Value(args, v8::Context::GetCurrent()));
  if (!value_args.get() ||
      !value_args->IsType(base::Value::TYPE_LIST))
    return v8::ThrowException(v8::Exception::Error(v8::String::New(
        "Unable to convert 'args' passed to CallObjectMethod")));

  RenderThread::Get()->Send(new ShellViewHostMsg_Call_Object_Method(
      routing_id,
      object_id,
      type,
      method,
      *static_cast<base::ListValue*>(value_args.get())));
  return v8::Undefined();
}

v8::Handle<v8::Value> CallObjectMethodSync(int routing_id,
                                           int object_id,
                                           const std::string& type,
                                           const std::string& method,
                                           v8::Handle<v8::Value> args) {
  scoped_ptr<V8ValueConverter> converter(V8ValueConverter::create());

  scoped_ptr<base::Value> value_args(
      converter->FromV8Value(args, v8::Context::GetCurrent()));
  if (!value_args.get() ||
      !value_args->IsType(base::Value::TYPE_LIST))
    return v8::ThrowException(v8::Exception::Error(v8::String::New(
        "Unable to convert 'args' passed to CallObjectMethodSync")));

  base::ListValue result;
  RenderThread::Get()->Send(new ShellViewHostMsg_Call_Object_Method_Sync(
      routing_id,
      object_id,
      type,
      method,
      *static_cast<base::ListValue*>(value_args.get()),
      &result));
  return converter->ToV8Value(&result, v8::Context::GetCurrent());
}

}  // namespace remote


// 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/net/shell_network_delegate.h"

#include "net/base/net_errors.h"

namespace content {

ShellNetworkDelegate::ShellNetworkDelegate() {
}

ShellNetworkDelegate::~ShellNetworkDelegate() {
}

int ShellNetworkDelegate::OnBeforeURLRequest(
    net::URLRequest* request,
    const net::CompletionCallback& callback,
    GURL* new_url) {
  return net::OK;
}

int ShellNetworkDelegate::OnBeforeSendHeaders(
    net::URLRequest* request,
    const net::CompletionCallback& callback,
    net::HttpRequestHeaders* headers) {
  return net::OK;
}

void ShellNetworkDelegate::OnSendHeaders(
    net::URLRequest* request,
    const net::HttpRequestHeaders& headers) {
}

int ShellNetworkDelegate::OnHeadersReceived(
    net::URLRequest* request,
    const net::CompletionCallback& callback,
    const net::HttpResponseHeaders* original_response_headers,
    scoped_refptr<net::HttpResponseHeaders>* override_response_headers) {
  return net::OK;
}

void ShellNetworkDelegate::OnBeforeRedirect(net::URLRequest* request,
                                            const GURL& new_location) {
}

void ShellNetworkDelegate::OnResponseStarted(net::URLRequest* request) {
}

void ShellNetworkDelegate::OnRawBytesRead(const net::URLRequest& request,
                                          int bytes_read) {
}

void ShellNetworkDelegate::OnCompleted(net::URLRequest* request, bool started) {
}

void ShellNetworkDelegate::OnURLRequestDestroyed(net::URLRequest* request) {
}

void ShellNetworkDelegate::OnPACScriptError(int line_number,
                                            const string16& error) {
}

ShellNetworkDelegate::AuthRequiredResponse ShellNetworkDelegate::OnAuthRequired(
    net::URLRequest* request,
    const net::AuthChallengeInfo& auth_info,
    const AuthCallback& callback,
    net::AuthCredentials* credentials) {
  return AUTH_REQUIRED_RESPONSE_NO_ACTION;
}

bool ShellNetworkDelegate::OnCanGetCookies(const net::URLRequest& request,
                                           const net::CookieList& cookie_list) {
  return true;
}

bool ShellNetworkDelegate::OnCanSetCookie(const net::URLRequest& request,
                                          const std::string& cookie_line,
                                          net::CookieOptions* options) {
  return true;
}

bool ShellNetworkDelegate::OnCanAccessFile(const net::URLRequest& request,
                                           const FilePath& path) const {
  return true;
}

bool ShellNetworkDelegate::OnCanThrottleRequest(
    const net::URLRequest& request) const {
  return false;
}

int ShellNetworkDelegate::OnBeforeSocketStreamConnect(
    net::SocketStream* socket,
    const net::CompletionCallback& callback) {
  return net::OK;
}

void ShellNetworkDelegate::OnRequestWaitStateChange(
    const net::URLRequest& request,
    RequestWaitState waiting) {
}

}  // namespace content


// 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/nw_package.h"

#include <vector>

#include "base/command_line.h"
#include "base/file_util.h"
#include "base/files/scoped_temp_dir.h"
#include "base/json/json_file_value_serializer.h"
#include "base/string_split.h"
#include "base/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/values.h"
#include "chrome/common/zip.h"
#include "content/nw/src/common/shell_switches.h"
#include "googleurl/src/gurl.h"
#include "grit/nw_resources.h"
#include "net/base/escape.h"
#include "third_party/node/deps/uv/include/uv.h"
#include "ui/base/resource/resource_bundle.h"
#include "ui/gfx/image/image.h"
#include "ui/gfx/image/image_skia_rep.h"
#include "webkit/glue/image_decoder.h"

namespace nw {

namespace {

#ifndef PATH_MAX
#define PATH_MAX MAX_PATH
#endif

bool MakePathAbsolute(FilePath* file_path) {
  DCHECK(file_path);

  FilePath current_directory;
  if (!file_util::GetCurrentDirectory(&current_directory))
    return false;

  if (file_path->IsAbsolute())
    return true;

  if (current_directory.empty())
    return file_util::AbsolutePath(file_path);

  if (!current_directory.IsAbsolute())
    return false;

  *file_path = current_directory.Append(*file_path);
  return true;
}

FilePath GetSelfPath() {
  CommandLine* command_line = CommandLine::ForCurrentProcess();

  FilePath path;

  size_t size = 2*PATH_MAX;
  char* execPath = new char[size];
  if (uv_exepath(execPath, &size) == 0) {
    path = FilePath::FromUTF8Unsafe(std::string(execPath, size));
  } else {
    path = FilePath(command_line->GetProgram());
  }

#if defined(OS_MACOSX)
  // Find if we have node-webkit.app/Resources/app.nw.
  path = path.DirName().DirName().Append("Resources").Append("app.nw");
#endif

  return path;
}

void RelativePathToURI(FilePath root, base::DictionaryValue* manifest) {
  std::string old;
  if (!manifest->GetString(switches::kmMain, &old))
    return;

  // Don't append path if there is already a prefix
  if (MatchPattern(old, "*://*"))
    return;

  FilePath main_path = root.Append(FilePath::FromUTF8Unsafe(old));
  manifest->SetString(switches::kmMain,
                      std::string("file://") + main_path.AsUTF8Unsafe());
}

}  // namespace

Package::Package()
    : path_(GetSelfPath()),
      self_extract_(true) {
  // First try to extract self.
  if (InitFromPath())
    return;

  // Then see if we have arguments and extract it.
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  const CommandLine::StringVector& args = command_line->GetArgs();
  if (args.size() > 0) {
    self_extract_ = false;
    path_ = FilePath(args[0]);
  } else {
    // Try to load from the folder where the exe resides.
    // Note: self_extract_ is true here, otherwise a 'Invalid Package' error
    // would be triggered.
    path_ = GetSelfPath().DirName();
#if defined(OS_MACOSX)
    path_ = path_.DirName().DirName().DirName();
#endif
  }
  if (InitFromPath())
    return;

  // Finally we init with default settings.
  self_extract_ = false;
  InitWithDefault();
}

Package::Package(FilePath path)
    : path_(path),
      self_extract_(false) {
  if (!InitFromPath())
    InitWithDefault();
}

Package::~Package() {
}

FilePath Package::ConvertToAbsoutePath(const FilePath& path) {
  if (path.IsAbsolute())
    return path;

  return this->path().Append(path);
}

bool Package::GetImage(const FilePath& icon_path, gfx::Image* image) {
  FilePath path = ConvertToAbsoutePath(icon_path);

  // Read the file from disk.
  std::string file_contents;
  if (path.empty() || !file_util::ReadFileToString(path, &file_contents))
    return false;

  // Decode the bitmap using WebKit's image decoder.
  const unsigned char* data =
      reinterpret_cast<const unsigned char*>(file_contents.data());
  webkit_glue::ImageDecoder decoder;
  scoped_ptr<SkBitmap> decoded(new SkBitmap());
  // Note: This class only decodes bitmaps from extension resources. Chrome
  // doesn't (for security reasons) directly load extension resources provided
  // by the extension author, but instead decodes them in a separate
  // locked-down utility process. Only if the decoding succeeds is the image
  // saved from memory to disk and subsequently used in the Chrome UI.
  // Chrome is therefore decoding bitmaps here that were generated by Chrome.
  *decoded = decoder.Decode(data, file_contents.length());
  if (decoded->empty())
    return false;  // Unable to decode.

  *image = gfx::Image(*decoded.release());
  return true;
}

GURL Package::GetStartupURL() {
  std::string url;
  // Specify URL in --url
  CommandLine* command_line = CommandLine::ForCurrentProcess();
  if (command_line->HasSwitch(switches::kUrl)) {
    url = command_line->GetSwitchValueASCII(switches::kUrl);
    GURL gurl(url);
    if (!gurl.has_scheme())
      return GURL(std::string("http://") + url);

    return gurl;
  }

  // Report if encountered errors.
  if (!error_page_url_.empty())
    return GURL(error_page_url_);

  // Read from manifest.
  if (root()->GetString(switches::kmMain, &url))
    return GURL(url);
  else
    return GURL("nw:blank");
}

std::string Package::GetName() {
  std::string name("node-webkit");
  root()->GetString(switches::kmName, &name);
  return name;
}

bool Package::GetUseNode() {
  bool use_node = true;
  root()->GetBoolean(switches::kmNodejs, &use_node);
  return use_node;
}

base::DictionaryValue* Package::window() {
  base::DictionaryValue* window;
  root()->GetDictionaryWithoutPathExpansion(switches::kmWindow, &window);
  return window;
}

bool Package::InitFromPath() {
  base::ThreadRestrictions::SetIOAllowed(true);

  if (!ExtractPath())
    return false;

  // path_/package.json
  FilePath manifest_path = path_.AppendASCII("package.json");
  if (!file_util::PathExists(manifest_path)) {
    if (!self_extract())
      ReportError("Invalid package",
                  "There is no 'package.json' in the package, please make "
                  "sure the 'package.json' is in the root of the package.");
    return false;
  }

  // Parse file.
  std::string error;
  JSONFileValueSerializer serializer(manifest_path);
  scoped_ptr<Value> root(serializer.Deserialize(NULL, &error));
  if (!root.get()) {
    ReportError("Unable to parse package.json",
                error.empty() ?
                    "Failed to read the manifest file: " +
                        manifest_path.AsUTF8Unsafe() :
                    error);
    return false;
  } else if (!root->IsType(Value::TYPE_DICTIONARY)) {
    ReportError("Invalid package.json",
                "package.json's content should be a object type.");
    return false;
  }

  // Save result in global
  root_.reset(static_cast<DictionaryValue*>(root.release()));

  // Check fields
  const char* required_fields[] = {
    switches::kmMain,
    switches::kmName
  };
  for (unsigned i = 0; i < arraysize(required_fields); i++)
    if (!root_->HasKey(required_fields[i])) {
      ReportError("Invalid package.json",
                  std::string("Field '") + required_fields[i] + "'"
                      " is required.");
      return false;
    }

  // Force window field no empty.
  if (!root_->HasKey(switches::kmWindow)) {
    base::DictionaryValue* window = new base::DictionaryValue();
    window->SetString(switches::kmPosition, "center");
    root_->Set(switches::kmWindow, window);
  }

  // Read chromium command line args.
  ReadChromiumArgs();

  RelativePathToURI(path_, this->root());
  return true;
}

void Package::InitWithDefault() {
  root_.reset(new base::DictionaryValue());
  root()->SetString(switches::kmName, "node-webkit");
  root()->SetString(switches::kmMain, "nw:blank");
  base::DictionaryValue* window = new base::DictionaryValue();
  root()->Set(switches::kmWindow, window);

  // Hide toolbar if specifed in the command line.
  if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kNoToolbar))
    window->SetBoolean(switches::kmToolbar, false);

  // Window should show in center by default.
  window->SetString(switches::kmPosition, "center");
}

bool Package::ExtractPath() {
  // Convert to absoulute path.
  if (!MakePathAbsolute(&path_)) {
    ReportError("Cannot extract package",
                "Path is invalid: " + path_.AsUTF8Unsafe());
    return false;
  }

  // Read symbolic link.
#if defined(OS_POSIX)
  FilePath target;
  if (file_util::ReadSymbolicLink(path_, &target))
    path_ = target;
#endif

  // If it's a file then try to extract from it.
  if (!file_util::DirectoryExists(path_)) {
    FilePath extracted_path;
    if (ExtractPackage(path_, &extracted_path)) {
      path_ = extracted_path;
    } else if (!self_extract()) {
      ReportError("Cannot extract package",
                  "Failed to unzip the package file: " + path_.AsUTF8Unsafe());
      return false;
    }
  }

  return true;
}

bool Package::ExtractPackage(const FilePath& zip_file, FilePath* where) {
  // Auto clean our temporary directory
  static scoped_ptr<base::ScopedTempDir> scoped_temp_dir;

#if defined(OS_WIN)
  if (!file_util::CreateNewTempDirectory(L"nw", where)) {
#else
  if (!file_util::CreateNewTempDirectory("nw", where)) {
#endif
    ReportError("Cannot extract package",
                "Unable to create temporary directory.");
    return false;
  }

  scoped_temp_dir.reset(new base::ScopedTempDir());
  if (!scoped_temp_dir->Set(*where)) {
    ReportError("Cannot extract package",
                "Unable to set temporary directory.");
    return false;
  }

  return zip::Unzip(zip_file, *where);
}

void Package::ReadChromiumArgs() {
  if (!root()->HasKey(switches::kmChromiumArgs))
    return;

  std::string args;
  if (!root()->GetStringASCII(switches::kmChromiumArgs, &args))
    return;

  std::vector<std::string> chromium_args;
  base::SplitString(args, ' ', &chromium_args);

  CommandLine* command_line = CommandLine::ForCurrentProcess();

  for (unsigned i = 0; i < chromium_args.size(); ++i) {
    std::string key, value;
    if (!IsSwitch(chromium_args[i], &key, &value))
      continue;
    command_line->AppendSwitchASCII(key, value);
  }
}

void Package::ReportError(const std::string& title,
                          const std::string& content) {
  if (!error_page_url_.empty())
    return;

  const base::StringPiece template_html(
      ResourceBundle::GetSharedInstance().GetRawDataResource(
          IDR_NW_PACKAGE_ERROR));

  if (template_html.empty()) {
    // Print hand written error info if nw.pak doesn't exist.
    NOTREACHED() << "Unable to load error template.";
    error_page_url_ = "data:text/html;base64,VW5hYmxlIHRvIGZpbmQgbncucGFrLgo=";
    return;
  }

  std::vector<std::string> subst;
  subst.push_back(title);
  subst.push_back(content);
  error_page_url_ = "data:text/html;charset=utf-8," +
      net::EscapeQueryParamValue(
          ReplaceStringPlaceholders(template_html, subst, NULL), false);
}

}  // namespace nw


// 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.

#ifndef CONTENT_NW_SRC_SHELL_H_
#define CONTENT_NW_SRC_SHELL_H_

#include <vector>

#include "base/basictypes.h"
#include "base/memory/weak_ptr.h"
#include "base/memory/scoped_ptr.h"
#include "content/public/browser/notification_registrar.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/web_contents_delegate.h"
#include "content/public/browser/web_contents_observer.h"
#include "ipc/ipc_channel.h"

namespace base {
class DictionaryValue;
}

namespace extensions {
struct DraggableRegion;
}

class GURL;

namespace nw {
class NativeWindow;
class Package;
}

namespace content {

class BrowserContext;
class ShellJavaScriptDialogCreator;
class SiteInstance;
class WebContents;

// This represents one window of the Content Shell, i.e. all the UI including
// buttons and url bar, as well as the web content area.
class Shell : public WebContentsDelegate,
              public content::WebContentsObserver,
              public NotificationObserver {
 public:
  enum ReloadType {
    RELOAD,                      // Normal (cache-validating) reload.
    RELOAD_IGNORING_CACHE,       // Reload bypassing the cache (shift-reload).
    RELOAD_ORIGINAL_REQUEST_URL, // Reload using the original request
                                 // URL.
    RELOAD_DEV                   // Refresh code from disk, should start a new renderer
                                 // process
  };

  explicit Shell(WebContents* web_contents, base::DictionaryValue* manifest);
  virtual ~Shell();

  // Create a new shell.
  static Shell* Create(BrowserContext* browser_context,
                       const GURL& url,
                       SiteInstance* site_instance,
                       int routing_id,
                       WebContents* base_web_contents);

  // Returns the Shell object corresponding to the given RenderViewHost.
  static Shell* FromRenderViewHost(RenderViewHost* rvh);

  void LoadURL(const GURL& url);
  void GoBackOrForward(int offset);
  void Reload(ReloadType type = RELOAD);
  void Stop();
  void ReloadOrStop();
  void ShowDevTools();

  // Send an event to renderer.
  void SendEvent(const std::string& event, const std::string& arg1 = "");

  // Decide whether we should close the window.
  bool ShouldCloseWindow();

  // Print critical error.
  void PrintCriticalError(const std::string& title,
                          const std::string& content);

  // Returns the currently open windows.
  static std::vector<Shell*>& windows() { return windows_; }

  static nw::Package* GetPackage();

  static void set_exit_code(int code) { exit_code_ = code; }

  static int exit_code() { return exit_code_; }

  WebContents* web_contents() const { return web_contents_.get(); }
  nw::NativeWindow* window() { return window_.get(); }

  void set_force_close(bool force) { force_close_ = force; }
  bool is_devtools() const { return is_devtools_; }
  bool force_close() const { return force_close_; }
  void set_id(int id) { id_ = id; }
  int id() const { return id_; }

 protected:
  // content::WebContentsObserver implementation.
  virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE;

  // content::WebContentsDelegate implementation.
  virtual WebContents* OpenURLFromTab(WebContents* source,
                                      const OpenURLParams& params) OVERRIDE;
  virtual void LoadingStateChanged(WebContents* source) OVERRIDE;
  virtual void ActivateContents(content::WebContents* contents) OVERRIDE;
  virtual void DeactivateContents(content::WebContents* contents) OVERRIDE;
  virtual void CloseContents(WebContents* source) OVERRIDE;
  virtual void MoveContents(WebContents* source, const gfx::Rect& pos) OVERRIDE;
  virtual bool IsPopupOrPanel(const WebContents* source) const OVERRIDE;
  virtual void WebContentsCreated(WebContents* source_contents,
                                  int64 source_frame_id,
                                  const GURL& target_url,
                                  WebContents* new_contents) OVERRIDE;
  virtual void RunFileChooser(
      content::WebContents* web_contents,
      const content::FileChooserParams& params) OVERRIDE;
  virtual void EnumerateDirectory(content::WebContents* web_contents,
                                  int request_id,
                                  const FilePath& path) OVERRIDE;
  virtual void DidNavigateMainFramePostCommit(
      WebContents* web_contents) OVERRIDE;
  virtual JavaScriptDialogCreator* GetJavaScriptDialogCreator() OVERRIDE;
  virtual void RequestToLockMouse(WebContents* web_contents,
                                  bool user_gesture,
                                  bool last_unlocked_by_target) OVERRIDE;
  virtual void HandleKeyboardEvent(
      WebContents* source,
      const NativeWebKeyboardEvent& event) OVERRIDE;
  virtual bool AddMessageToConsole(WebContents* source,
                                   int32 level,
                                   const string16& message,
                                   int32 line_no,
                                   const string16& source_id) OVERRIDE;
  virtual void RequestMediaAccessPermission(
      WebContents* web_contents,
      const MediaStreamRequest& request,
      const MediaResponseCallback& callback) OVERRIDE;

 private:
  void UpdateDraggableRegions(
      const std::vector<extensions::DraggableRegion>& regions);

  // NotificationObserver
  virtual void Observe(int type,
                       const NotificationSource& source,
                       const NotificationDetails& details) OVERRIDE;

  scoped_ptr<ShellJavaScriptDialogCreator> dialog_creator_;
  scoped_ptr<WebContents> web_contents_;
  scoped_ptr<nw::NativeWindow> window_;

  // Notification manager.
  NotificationRegistrar registrar_;

  // Weak potiner to devtools window.
  base::WeakPtr<Shell> devtools_window_;

  // Factory to generate weak pointer, used by devtools.
  base::WeakPtrFactory<Shell> weak_ptr_factory_;

  // Whether this shell is devtools window.
  bool is_devtools_;

  // Flag to indicate we will force closing.
  bool force_close_;

  // ID of corresponding js object.
  int id_;

  // A container of all the open windows. We use a vector so we can keep track
  // of ordering.
  static std::vector<Shell*> windows_;

  // True if the destructur of Shell should post a quit closure on the current
  // message loop if the destructed Shell object was the last one.
  static bool quit_message_loop_;

  static int exit_code_;
};

}  // namespace content

#endif  // CONTENT_NW_SRC_SHELL_H_


// 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.

#ifndef CONTENT_NW_SRC_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_
#define CONTENT_NW_SRC_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_

#include "base/compiler_specific.h"
#include "base/memory/ref_counted.h"
#include "content/public/browser/download_manager_delegate.h"

namespace content {

class DownloadManager;

class ShellDownloadManagerDelegate
    : public DownloadManagerDelegate,
      public base::RefCountedThreadSafe<ShellDownloadManagerDelegate> {
 public:
  ShellDownloadManagerDelegate();

  void SetDownloadManager(DownloadManager* manager);

  virtual void Shutdown() OVERRIDE;
  virtual bool DetermineDownloadTarget(
      DownloadItem* download,
      const DownloadTargetCallback& callback) OVERRIDE;

  // Inhibits prompting and sets the default download path.
  void SetDownloadBehaviorForTesting(
      const FilePath& default_download_path);

 protected:
  // To allow subclasses for testing.
  virtual ~ShellDownloadManagerDelegate();

 private:
  friend class base::RefCountedThreadSafe<ShellDownloadManagerDelegate>;

  void GenerateFilename(int32 download_id,
                        const DownloadTargetCallback& callback,
                        const FilePath& generated_name,
                        const FilePath& suggested_directory);
  void OnDownloadPathGenerated(int32 download_id,
                               const DownloadTargetCallback& callback,
                               const FilePath& suggested_path);
  void ChooseDownloadPath(int32 download_id,
                          const DownloadTargetCallback& callback,
                          const FilePath& suggested_path);

  DownloadManager* download_manager_;
  FilePath default_download_path_;
  bool suppress_prompting_;

  DISALLOW_COPY_AND_ASSIGN(ShellDownloadManagerDelegate);
};

}  // namespace content

#endif  // CONTENT_NW_SRC_BROWSER_SHELL_DOWNLOAD_MANAGER_DELEGATE_H_


// 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/browser/shell_download_manager_delegate.h"

#if defined(TOOLKIT_GTK)
#include <gtk/gtk.h>
#endif

#if defined(OS_WIN)
#include <windows.h>
#include <commdlg.h>
#endif

#include "base/bind.h"
#include "base/file_util.h"
#include "base/logging.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/download_manager.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_view.h"
#include "net/base/net_util.h"

namespace content {

ShellDownloadManagerDelegate::ShellDownloadManagerDelegate()
    : download_manager_(NULL),
      suppress_prompting_(false) {
  // Balanced in Shutdown();
  AddRef();
}

ShellDownloadManagerDelegate::~ShellDownloadManagerDelegate(){
}

void ShellDownloadManagerDelegate::SetDownloadManager(
    DownloadManager* download_manager) {
  download_manager_ = download_manager;
}

void ShellDownloadManagerDelegate::Shutdown() {
  Release();
}

bool ShellDownloadManagerDelegate::DetermineDownloadTarget(
    DownloadItem* download,
    const DownloadTargetCallback& callback) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  // This assignment needs to be here because even at the call to
  // SetDownloadManager, the system is not fully initialized.
  if (default_download_path_.empty()) {
    default_download_path_ = download_manager_->GetBrowserContext()->GetPath().
        Append(FILE_PATH_LITERAL("Downloads"));
  }

  if (!download->GetForcedFilePath().empty()) {
    callback.Run(download->GetForcedFilePath(),
                 DownloadItem::TARGET_DISPOSITION_OVERWRITE,
                 DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
                 download->GetForcedFilePath());
    return true;
  }

  FilePath generated_name = net::GenerateFileName(
      download->GetURL(),
      download->GetContentDisposition(),
      EmptyString(),
      download->GetSuggestedFilename(),
      download->GetMimeType(),
      "download");

  BrowserThread::PostTask(
      BrowserThread::FILE,
      FROM_HERE,
      base::Bind(
          &ShellDownloadManagerDelegate::GenerateFilename,
          this, download->GetId(), callback, generated_name,
          default_download_path_));
  return true;
}

void ShellDownloadManagerDelegate::GenerateFilename(
    int32 download_id,
    const DownloadTargetCallback& callback,
    const FilePath& generated_name,
    const FilePath& suggested_directory) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE));
  if (!file_util::PathExists(suggested_directory))
    file_util::CreateDirectory(suggested_directory);

  FilePath suggested_path(suggested_directory.Append(generated_name));
  BrowserThread::PostTask(
      BrowserThread::UI,
      FROM_HERE,
      base::Bind(
          &ShellDownloadManagerDelegate::OnDownloadPathGenerated,
          this, download_id, callback, suggested_path));
}

void ShellDownloadManagerDelegate::OnDownloadPathGenerated(
    int32 download_id,
    const DownloadTargetCallback& callback,
    const FilePath& suggested_path) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  if (suppress_prompting_) {
    // Testing exit.
    callback.Run(suggested_path, DownloadItem::TARGET_DISPOSITION_OVERWRITE,
                 DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS,
                 suggested_path.AddExtension(FILE_PATH_LITERAL(".crdownload")));
    return;
  }

  ChooseDownloadPath(download_id, callback, suggested_path);
}

void ShellDownloadManagerDelegate::ChooseDownloadPath(
    int32 download_id,
    const DownloadTargetCallback& callback,
    const FilePath& suggested_path) {
  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
  DownloadItem* item = download_manager_->GetDownload(download_id);
  if (!item || (item->GetState() != DownloadItem::IN_PROGRESS))
    return;

  FilePath result;
#if defined(OS_WIN)
  std::wstring file_part = FilePath(suggested_path).BaseName().value();
  wchar_t file_name[MAX_PATH];
  base::wcslcpy(file_name, file_part.c_str(), arraysize(file_name));
  OPENFILENAME save_as;
  ZeroMemory(&save_as, sizeof(save_as));
  save_as.lStructSize = sizeof(OPENFILENAME);
  save_as.hwndOwner = item->GetWebContents()->GetNativeView();
  save_as.lpstrFile = file_name;
  save_as.nMaxFile = arraysize(file_name);

  std::wstring directory;
  if (!suggested_path.empty())
    directory = suggested_path.DirName().value();

  save_as.lpstrInitialDir = directory.c_str();
  save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING |
                  OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST;

  if (GetSaveFileName(&save_as))
    result = FilePath(std::wstring(save_as.lpstrFile));
#elif defined(TOOLKIT_GTK)
  GtkWidget *dialog;
  gfx::NativeWindow parent_window;
  std::string base_name = FilePath(suggested_path).BaseName().value();

  parent_window = item->GetWebContents()->GetView()->GetTopLevelNativeWindow();
  dialog = gtk_file_chooser_dialog_new("Save File",
                                       parent_window,
                                       GTK_FILE_CHOOSER_ACTION_SAVE,
                                       GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
                                       GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
                                       NULL);
  gtk_file_chooser_set_do_overwrite_confirmation(GTK_FILE_CHOOSER(dialog),
                                                 TRUE);
  gtk_file_chooser_set_current_name(GTK_FILE_CHOOSER(dialog),
                                    base_name.c_str());

  if (gtk_dialog_run(GTK_DIALOG(dialog)) == GTK_RESPONSE_ACCEPT) {
    char *filename;
    filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dialog));
    result = FilePath(filename);
  }
  gtk_widget_destroy(dialog);
#else
  NOTIMPLEMENTED();
#endif

  callback.Run(result, DownloadItem::TARGET_DISPOSITION_PROMPT,
               DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, result);
}

void ShellDownloadManagerDelegate::SetDownloadBehaviorForTesting(
    const FilePath& default_download_path) {
  default_download_path_ = default_download_path;
  suppress_prompting_ = true;
}

}  // namespace content


    <title>Test</title>

Can this remote page call node:


# 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.

{
  'variables': {
    'nw_product_name': 'node-webkit',
  },
  'targets': [
    {
      'target_name': 'nw_lib',
      'type': 'static_library',
      'defines!': ['CONTENT_IMPLEMENTATION'],
      'variables': {
        'chromium_code': 1,
      },
      'dependencies': [
        '<(DEPTH)/base/base.gyp:base',
        '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations',
        '<(DEPTH)/build/temp_gyp/googleurl.gyp:googleurl',
        '<(DEPTH)/content/content.gyp:content_app',
        '<(DEPTH)/content/content.gyp:content_browser',
        '<(DEPTH)/content/content.gyp:content_common',
        '<(DEPTH)/content/content.gyp:content_gpu',
        '<(DEPTH)/content/content.gyp:content_plugin',
        '<(DEPTH)/content/content.gyp:content_ppapi_plugin',
        '<(DEPTH)/content/content.gyp:content_renderer',
        '<(DEPTH)/content/content.gyp:content_utility',
        '<(DEPTH)/content/content.gyp:content_worker',
        '<(DEPTH)/content/content_resources.gyp:content_resources',
        '<(DEPTH)/ipc/ipc.gyp:ipc',
        '<(DEPTH)/media/media.gyp:media',
        '<(DEPTH)/net/net.gyp:net_with_v8',
        '<(DEPTH)/net/net.gyp:net_resources',
        '<(DEPTH)/skia/skia.gyp:skia',
        '<(DEPTH)/third_party/node/node.gyp:node',
        '<(DEPTH)/ui/ui.gyp:ui',
        '<(DEPTH)/ui/ui.gyp:ui_resources',
        '<(DEPTH)/v8/tools/gyp/v8.gyp:v8',
        '<(DEPTH)/webkit/support/webkit_support.gyp:webkit_support',
        '<(DEPTH)/third_party/zlib/zlib.gyp:minizip',
        '<(webkit_src_dir)/Source/WebKit/chromium/WebKit.gyp:webkit',
        'nw_resources',
      ],
      'include_dirs': [
        '<(DEPTH)',
      ],
      'sources': [
        '<(DEPTH)/chrome/browser/platform_util_common_linux.cc',
        '<(DEPTH)/chrome/browser/platform_util_linux.cc',
        '<(DEPTH)/chrome/browser/platform_util_mac.mm',
        '<(DEPTH)/chrome/browser/platform_util_win.cc',
        '<(DEPTH)/chrome/browser/platform_util.h',
        '<(DEPTH)/chrome/browser/process_singleton_linux.cc',
        '<(DEPTH)/chrome/browser/process_singleton_mac.cc',
        '<(DEPTH)/chrome/browser/process_singleton_win.cc',
        '<(DEPTH)/chrome/browser/process_singleton.h',
        '<(DEPTH)/chrome/browser/status_icons/status_icon.cc',
        '<(DEPTH)/chrome/browser/status_icons/status_icon.h',
        '<(DEPTH)/chrome/browser/status_icons/status_icon_observer.h',
        '<(DEPTH)/chrome/browser/status_icons/status_tray.cc',
        '<(DEPTH)/chrome/browser/status_icons/status_tray.h',
        '<(DEPTH)/chrome/browser/ui/cocoa/custom_frame_view.h',
        '<(DEPTH)/chrome/browser/ui/cocoa/custom_frame_view.mm',
        '<(DEPTH)/chrome/browser/ui/base_window.h',
        '<(DEPTH)/chrome/browser/ui/gtk/gtk_window_util.cc',
        '<(DEPTH)/chrome/browser/ui/gtk/gtk_window_util.h',
        '<(DEPTH)/chrome/browser/ui/views/status_icons/status_icon_win.cc',
        '<(DEPTH)/chrome/browser/ui/views/status_icons/status_icon_win.h',
        '<(DEPTH)/chrome/browser/ui/views/status_icons/status_tray_win.cc',
        '<(DEPTH)/chrome/browser/ui/views/status_icons/status_tray_win.h',
        '<(DEPTH)/chrome/common/chrome_constants.cc',
        '<(DEPTH)/chrome/common/chrome_constants.h',
        '<(DEPTH)/chrome/common/chrome_switches.cc',
        '<(DEPTH)/chrome/common/chrome_switches.h',
        '<(DEPTH)/chrome/common/extensions/draggable_region.cc',
        '<(DEPTH)/chrome/common/extensions/draggable_region.h',
        '<(DEPTH)/chrome/common/zip.cc',
        '<(DEPTH)/chrome/common/zip.h',
        '<(DEPTH)/chrome/common/zip_reader.cc',
        '<(DEPTH)/chrome/common/zip_reader.h',
        '<(DEPTH)/chrome/common/zip_internal.cc',
        '<(DEPTH)/chrome/common/zip_internal.h',
        '<(DEPTH)/chrome/renderer/page_click_listener.h',
        '<(DEPTH)/chrome/renderer/page_click_tracker.cc',
        '<(DEPTH)/chrome/renderer/page_click_tracker.h',
        '<(DEPTH)/chrome/renderer/static_v8_external_string_resource.cc',
        '<(DEPTH)/chrome/renderer/static_v8_external_string_resource.h',
        'src/api/api_messages.cc',
        'src/api/api_messages.h',
        'src/api/app/app.cc',
        'src/api/app/app.h',
        'src/api/bindings_common.cc',
        'src/api/bindings_common.h',
        'src/api/base/base.cc',
        'src/api/base/base.h',
        'src/api/clipboard/clipboard.cc',
        'src/api/clipboard/clipboard.h',
        'src/api/dispatcher.cc',
        'src/api/dispatcher.h',
        'src/api/dispatcher_bindings.cc',
        'src/api/dispatcher_bindings.h',
        'src/api/dispatcher_host.cc',
        'src/api/dispatcher_host.h',
        'src/api/window_bindings.cc',
        'src/api/window_bindings.h',
        'src/api/menu/menu.cc',
        'src/api/menu/menu.h',
        'src/api/menu/menu_delegate_win.cc',
        'src/api/menu/menu_delegate_win.h',
        'src/api/menu/menu_gtk.cc',
        'src/api/menu/menu_mac.mm',
        'src/api/menu/menu_win.cc',
        'src/api/menuitem/menuitem.cc',
        'src/api/menuitem/menuitem.h',
        'src/api/menuitem/menuitem_gtk.cc',
        'src/api/menuitem/menuitem_mac.mm',
        'src/api/menuitem/menuitem_win.cc',
        'src/api/menuitem/menuitem_delegate_mac.h',
        'src/api/menuitem/menuitem_delegate_mac.mm',
        'src/api/shell/shell.cc',
        'src/api/shell/shell.h',
        'src/api/tray/tray.cc',
        'src/api/tray/tray.h',
        'src/api/tray/tray_gtk.cc',
        'src/api/tray/tray_mac.mm',
        'src/api/tray/tray_win.cc',
        'src/api/window/window.cc',
        'src/api/window/window.h',
        'src/browser/app_controller_mac.h',
        'src/browser/app_controller_mac.mm',
        'src/browser/file_select_helper.cc',
        'src/browser/file_select_helper.h',
        'src/browser/native_window.cc',
        'src/browser/native_window.h',
        'src/browser/native_window_gtk.cc',
        'src/browser/native_window_gtk.h',
        'src/browser/native_window_helper_mac.h',
        'src/browser/native_window_mac.h',
        'src/browser/native_window_mac.mm',
        'src/browser/native_window_toolbar_win.cc',
        'src/browser/native_window_toolbar_win.h',
        'src/browser/native_window_win.cc',
        'src/browser/native_window_win.h',
        'src/browser/shell_application_mac.h',
        'src/browser/shell_application_mac.mm',
        'src/browser/shell_devtools_delegate.cc',
        'src/browser/shell_devtools_delegate.h',
        'src/browser/shell_download_manager_delegate.cc',
        'src/browser/shell_download_manager_delegate.h',
        'src/browser/shell_javascript_dialog_creator.cc',
        'src/browser/shell_javascript_dialog_creator.h',
        'src/browser/shell_javascript_dialog_gtk.cc',
        'src/browser/shell_javascript_dialog_mac.mm',
        'src/browser/shell_javascript_dialog_win.cc',
        'src/browser/shell_javascript_dialog.h',
        'src/browser/shell_login_dialog_gtk.cc',
        'src/browser/shell_login_dialog_mac.mm',
        'src/browser/shell_login_dialog_win.cc',
        'src/browser/shell_login_dialog.cc',
        'src/browser/shell_login_dialog.h',
        'src/browser/shell_resource_context.cc',
        'src/browser/shell_resource_context.h',
        'src/browser/shell_resource_dispatcher_host_delegate.cc',
        'src/browser/shell_resource_dispatcher_host_delegate.h',
        'src/browser/shell_toolbar_delegate_mac.h',
        'src/browser/shell_toolbar_delegate_mac.mm',
        'src/browser/standard_menus_mac.h',
        'src/browser/standard_menus_mac.mm',
        'src/common/gpu_internals.cc',
        'src/common/gpu_internals.h',
        'src/common/shell_switches.cc',
        'src/common/shell_switches.h',
        'src/geolocation/shell_access_token_store.cc',
        'src/geolocation/shell_access_token_store.h',
        'src/media/media_internals.cc',
        'src/media/media_internals.h',
        'src/media/media_capture_devices_dispatcher.cc',
        'src/media/media_capture_devices_dispatcher.h',
        'src/media/media_stream_devices_controller.cc',
        'src/media/media_stream_devices_controller.h',
        'src/net/clear_on_exit_policy.h',
        'src/net/clear_on_exit_policy.cc',
        'src/net/resource_request_job.cc',
        'src/net/resource_request_job.h',
        'src/net/shell_network_delegate.cc',
        'src/net/shell_network_delegate.h',
        'src/net/shell_url_request_context_getter.cc',
        'src/net/shell_url_request_context_getter.h',
        'src/net/sqlite_persistent_cookie_store.h',
        'src/net/sqlite_persistent_cookie_store.cc',
        'src/nw_protocol_handler.cc',
        'src/nw_protocol_handler.h',
        'src/nw_package.cc',
        'src/nw_package.h',
        'src/nw_version.h',
        'src/paths_mac.h',
        'src/paths_mac.mm',
        'src/renderer/autofill_agent.h',
        'src/renderer/autofill_agent.cc',
        'src/renderer/prerenderer/prerenderer_client.cc',
        'src/renderer/prerenderer/prerenderer_client.h',
        'src/renderer/shell_content_renderer_client.cc',
        'src/renderer/shell_content_renderer_client.h',
        'src/renderer/shell_render_process_observer.cc',
        'src/renderer/shell_render_process_observer.h',
        'src/nw_shell.cc',
        'src/nw_shell.h',
        'src/shell_browser_context.cc',
        'src/shell_browser_context.h',
        'src/shell_browser_main.cc',
        'src/shell_browser_main.h',
        'src/shell_browser_main_parts.cc',
        'src/shell_browser_main_parts.h',
        'src/shell_browser_main_parts_mac.mm',
        'src/shell_content_browser_client.cc',
        'src/shell_content_browser_client.h',
        'src/shell_content_client.cc',
        'src/shell_content_client.h',
        'src/shell_main_delegate.cc',
        'src/shell_main_delegate.h',
      ],
      'msvs_settings': {
        'VCLinkerTool': {
          'SubSystem': '2',  # Set /SUBSYSTEM:WINDOWS
        },
      },
      'conditions': [
        ['OS=="win" and win_use_allocator_shim==1', {
          'dependencies': [
            '<(DEPTH)/base/allocator/allocator.gyp:allocator',
          ],
        }],
        ['OS=="win"', {
          'resource_include_dirs': [
            '<(SHARED_INTERMEDIATE_DIR)/webkit',
          ],
          'dependencies': [
            '<(DEPTH)/ui/ui.gyp:ui_resources',
            '<(DEPTH)/ui/views/controls/webview/webview.gyp:webview',
            '<(DEPTH)/ui/views/views.gyp:views',
            '<(DEPTH)/webkit/support/webkit_support.gyp:webkit_resources',
            '<(DEPTH)/webkit/support/webkit_support.gyp:webkit_strings',
          ],
          'configurations': {
            'Debug_Base': {
              'msvs_settings': {
                'VCLinkerTool': {
                  'LinkIncremental': '<(msvs_large_module_debug_link_mode)',
                },
              },
            },
          },
        }],  # OS=="win"
      ],
    },
    {
      'target_name': 'nw_resources',
      'type': 'none',
      'dependencies': [
        'generate_nw_resources',
      ],
      'variables': {
        'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/content',
      },
      'includes': [ '../../build/grit_target.gypi' ],
      'copies': [
        {
          'destination': '<(PRODUCT_DIR)',
          'files': [
            '<(SHARED_INTERMEDIATE_DIR)/content/nw_resources.pak'
          ],
        },
      ],
    },
    {
      'target_name': 'generate_nw_resources',
      'type': 'none',
      'variables': {
        'grit_out_dir': '<(SHARED_INTERMEDIATE_DIR)/content',
      },
      'actions': [
        {
          'action_name': 'nw_resources',
          'variables': {
            'grit_grd_file': 'src/resources/nw_resources.grd',
          },
          'includes': [ '../../build/grit_action.gypi' ],
        },
      ],
    },
    {
      # We build a minimal set of resources so WebKit in nw has
      # access to necessary resources.
      'target_name': 'nw_pak',
      'type': 'none',
      'dependencies': [
        '<(DEPTH)/content/browser/devtools/devtools_resources.gyp:devtools_resources',
        '<(DEPTH)/ui/ui.gyp:ui_resources',
        'nw_resources',
      ],
      'variables': {
        'repack_path': '<(DEPTH)/tools/grit/grit/format/repack.py',
      },
      'actions': [
        {
          'action_name': 'repack_nw_pack',
          'variables': {
            'pak_inputs': [
              '<(SHARED_INTERMEDIATE_DIR)/content/content_resources.pak',
              '<(SHARED_INTERMEDIATE_DIR)/content/nw_resources.pak',
              '<(SHARED_INTERMEDIATE_DIR)/net/net_resources.pak',
              '<(SHARED_INTERMEDIATE_DIR)/ui/app_locale_settings/app_locale_settings_en-US.pak',
              '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/ui_resources_100_percent.pak',
              '<(SHARED_INTERMEDIATE_DIR)/ui/ui_strings/ui_strings_en-US.pak',
              '<(SHARED_INTERMEDIATE_DIR)/webkit/devtools_resources.pak',
              '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_chromium_resources.pak',
              '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_resources_100_percent.pak',
              '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_strings_en-US.pak',
            ],
          },
          'inputs': [
            '<(repack_path)',
            '<@(pak_inputs)',
          ],
          'outputs': [
            '<(PRODUCT_DIR)/nw.pak',
          ],
          'action': ['python', '<(repack_path)', '<@(_outputs)',
                     '<@(pak_inputs)'],
        },
      ],
    },
    {
      'target_name': 'nw_package_bin',
      'type': 'none',
      'actions': [
        {
          'action_name': 'package_nw_binaries',
          'variables':{
            'package_script': '<(DEPTH)/content/nw/tools/package_binaries.py',
          },
          'inputs': [
            '<(package_script)',
          ],
          'outputs':[
            '<(PRODUCT_DIR)/new_package.re',
          ],
          'action': ['python', '<(package_script)'],
        },
      ],
    },
    {
      'target_name': 'nw',
      'type': 'executable',
      'mac_bundle': 1,
      'defines!': ['CONTENT_IMPLEMENTATION'],
      'variables': {
        'chromium_code': 1,
      },
      'dependencies': [
        'nw_lib',
        'nw_pak',
      ],
      'include_dirs': [
        '<(DEPTH)',
      ],
      'sources': [
        '../app/startup_helper_win.cc',
        'src/shell_main.cc',
      ],
      'mac_bundle_resources': [
        'src/mac/nw.icns',
        'src/mac/app-Info.plist',
      ],
      # TODO(mark): Come up with a fancier way to do this.  It should only
      # be necessary to list app-Info.plist once, not the three times it is
      # listed here.
      'mac_bundle_resources!': [
        'src/mac/app-Info.plist',
      ],
      'xcode_settings': {
        'INFOPLIST_FILE': 'nw/src/mac/app-Info.plist',
      },
      'msvs_settings': {
        'VCLinkerTool': {
          'SubSystem': '2',  # Set /SUBSYSTEM:WINDOWS
        },
      },
      'conditions': [
        ['OS=="win" and win_use_allocator_shim==1', {
          'dependencies': [
            '<(DEPTH)/base/allocator/allocator.gyp:allocator',
          ],
        }],
        ['OS=="win"', {
          'sources': [
            'src/shell.rc',
					  '../../webkit/glue/resources/pan_east.cur',
						'../../webkit/glue/resources/pan_middle.cur',
						'../../webkit/glue/resources/pan_north.cur',
						'../../webkit/glue/resources/pan_north_east.cur',
					  '../../webkit/glue/resources/pan_north_west.cur',
						'../../webkit/glue/resources/pan_south.cur',
						'../../webkit/glue/resources/pan_south_east.cur',
						'../../webkit/glue/resources/pan_south_west.cur',
						'../../webkit/glue/resources/pan_west.cur',

            '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_resources.rc',
          ],
          'configurations': {
            'Debug_Base': {
              'msvs_settings': {
                'VCLinkerTool': {
                  'LinkIncremental': '<(msvs_large_module_debug_link_mode)',
                },
              },
            },
          },
        }],  # OS=="win"
        ['OS == "win" or (toolkit_uses_gtk == 1 and selinux == 0)', {
          'dependencies': [
            '<(DEPTH)/sandbox/sandbox.gyp:sandbox',
          ],
        }],  # OS=="win" or (toolkit_uses_gtk == 1 and selinux == 0)
        ['toolkit_uses_gtk == 1', {
          'dependencies': [
            '<(DEPTH)/build/linux/system.gyp:gtk',
          ],
        }],  # toolkit_uses_gtk
        ['OS=="mac"', {
          'product_name': '<(nw_product_name)',
          'dependencies!': [
            'nw_lib',
          ],
          'dependencies': [
            'nw_framework',
            'nw_helper_app',
          ],
          'copies': [
            {
              'destination': '<(PRODUCT_DIR)/<(nw_product_name).app/Contents/Frameworks',
              'files': [
                '<(PRODUCT_DIR)/<(nw_product_name) Helper.app',
              ],
            },
          ],
          'postbuilds': [
            {
              'postbuild_name': 'Copy <(nw_product_name) Framework.framework',
              'action': [
                '<(DEPTH)/build/mac/copy_framework_unversioned.sh',
                '${BUILT_PRODUCTS_DIR}/<(nw_product_name) Framework.framework',
                '${BUILT_PRODUCTS_DIR}/${CONTENTS_FOLDER_PATH}/Frameworks',
              ],
            },
            {
              'postbuild_name': 'Fix Framework Link',
              'action': [
                'install_name_tool',
                '-change',
                '/Library/Frameworks/<(nw_product_name) Framework.framework/Versions/A/<(nw_product_name) Framework',
                '@executable_path/../Frameworks/<(nw_product_name) Framework.framework/<(nw_product_name) Framework',
                '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}'
              ],
            },
            {
              # Modify the Info.plist as needed.
              'postbuild_name': 'Tweak Info.plist',
              'action': ['<(DEPTH)/build/mac/tweak_info_plist.py',
                         '--breakpad=0',
                         '--keystone=0'],
            },
            {
              # This postbuid step is responsible for creating the following
              # helpers:
              #
              # Content Shell Helper EH.app and Content Shell Helper NP.app are
              # created from Content Shell Helper.app.
              #
              # The EH helper is marked for an executable heap. The NP helper
              # is marked for no PIE (ASLR).
              'postbuild_name': 'Make More Helpers',
              'action': [
                '<(DEPTH)/build/mac/make_more_helpers.sh',
                'Frameworks',
                '<(nw_product_name)',
              ],
            },
            {
              # Make sure there isn't any Objective-C in the shell's
              # executable.
              'postbuild_name': 'Verify No Objective-C',
              'action': [
                '<(DEPTH)/build/mac/verify_no_objc.sh',
              ],
            },
          ],
        }],  # OS=="mac"
      ],
    },
  ],
  'conditions': [
    ['OS=="mac"', {
      'targets': [
        {
          'target_name': 'nw_framework',
          'type': 'shared_library',
          'product_name': '<(nw_product_name) Framework',
          'mac_bundle': 1,
          'mac_bundle_resources': [
            'src/mac/English.lproj/HttpAuth.xib',
            '<(PRODUCT_DIR)/nw.pak'
          ],
          'dependencies': [
            'nw_lib',
          ],
          'include_dirs': [
            '../..',
          ],
          'sources': [
            'src/shell_content_main.cc',
            'src/shell_content_main.h',
          ],
          'copies': [
            {
              # Copy FFmpeg binaries for audio/video support.
              'destination': '<(PRODUCT_DIR)/$(CONTENTS_FOLDER_PATH)/Libraries',
              'files': [
                '<(PRODUCT_DIR)/ffmpegsumo.so',
              ],
            },
          ],
        },  # target nw_framework
        {
          'target_name': 'nw_helper_app',
          'type': 'executable',
          'variables': { 'enable_wexit_time_destructors': 1, },
          'product_name': '<(nw_product_name) Helper',
          'mac_bundle': 1,
          'dependencies': [
            'nw_framework',
          ],
          'sources': [
            'src/shell_main.cc',
            'src/mac/helper-Info.plist',
          ],
          # TODO(mark): Come up with a fancier way to do this.  It should only
          # be necessary to list helper-Info.plist once, not the three times it
          # is listed here.
          'mac_bundle_resources!': [
            'src/mac/helper-Info.plist',
          ],
          # TODO(mark): For now, don't put any resources into this app.  Its
          # resources directory will be a symbolic link to the browser app's
          # resources directory.
          'mac_bundle_resources/': [
            ['exclude', '.*'],
          ],
          'xcode_settings': {
            'INFOPLIST_FILE': 'nw/src/mac/helper-Info.plist',
          },
          'postbuilds': [
            {
              # The framework defines its load-time path
              # (DYLIB_INSTALL_NAME_BASE) relative to the main executable
              # (chrome).  A different relative path needs to be used in
              # nw_helper_app.
              'postbuild_name': 'Fix Framework Link',
              'action': [
                'install_name_tool',
                '-change',
                '/Library/Frameworks/<(nw_product_name) Framework.framework/Versions/A/<(nw_product_name) Framework',
                '@executable_path/../../../../Frameworks/<(nw_product_name) Framework.framework/<(nw_product_name) Framework',
                '${BUILT_PRODUCTS_DIR}/${EXECUTABLE_PATH}'
              ],
            },
            {
              # Modify the Info.plist as needed.  The script explains why this
              # is needed.  This is also done in the chrome and chrome_dll
              # targets.  In this case, --breakpad=0, --keystone=0, and --svn=0
              # are used because Breakpad, Keystone, and Subversion keys are
              # never placed into the helper.
              'postbuild_name': 'Tweak Info.plist',
              'action': ['<(DEPTH)/build/mac/tweak_info_plist.py',
                         '--breakpad=0',
                         '--keystone=0'],
            },
            {
              # Make sure there isn't any Objective-C in the helper app's
              # executable.
              'postbuild_name': 'Verify No Objective-C',
              'action': [
                '<(DEPTH)/build/mac/verify_no_objc.sh',
              ],
            },
          ],
          'conditions': [
            ['component=="shared_library"', {
              'xcode_settings': {
                'LD_RUNPATH_SEARCH_PATHS': [
                  # Get back from Content Shell.app/Contents/Frameworks/
                  #                                 Helper.app/Contents/MacOS
                  '@loader_path/../../../../../..',
                ],
              },
            }],
          ],
        },  # target nw_helper_app
      ],
    }],  # OS=="mac"
  ]
}


// 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/browser/standard_menus_mac.h"

#include "base/sys_string_conversions.h"
#import <Cocoa/Cocoa.h>

// For some reaon, Apple removed setAppleMenu from the headers in 10.4,
// but the method still is there and works. To avoid warnings, we declare
// it ourselves here.
@interface NSApplication(SDL_Missing_Methods)
- (void)setAppleMenu:(NSMenu *)menu;
@end

namespace nw {

StandardMenusMac::StandardMenusMac(const std::string& app_name)
    : app_name_(app_name) {
}

StandardMenusMac::~StandardMenusMac() {
}

void StandardMenusMac::BuildAppleMenu() {
  NSMenu* appleMenu = [[NSMenu alloc] initWithTitle:@""];

  NSString* name = base::SysUTF8ToNSString(app_name_);
  [appleMenu addItemWithTitle:[@"About " stringByAppendingString:name]
                       action:@selector(orderFrontStandardAboutPanel:)
                keyEquivalent:@""];

  [appleMenu addItem:[NSMenuItem separatorItem]];

  [appleMenu addItemWithTitle:[@"Hide " stringByAppendingString:name]
                       action:@selector(hide:)
                keyEquivalent:@"h"];

  NSMenuItem* menuItem = (NSMenuItem *)[appleMenu
      addItemWithTitle:@"Hide Others"
                action:@selector(hideOtherApplications:)
         keyEquivalent:@"h"];
  [menuItem setKeyEquivalentModifierMask:(NSAlternateKeyMask|NSCommandKeyMask)];

  [appleMenu addItemWithTitle:@"Show All"
                       action:@selector(unhideAllApplications:)
                keyEquivalent:@""];

  [appleMenu addItem:[NSMenuItem separatorItem]];

  [appleMenu addItemWithTitle:[@"Quit " stringByAppendingString:name]
                       action:@selector(closeAllWindows:)
                keyEquivalent:@"q"];

  // Add to menubar.
  [[[NSApp mainMenu] itemAtIndex:0] setSubmenu:appleMenu];

  // Finally give up our references to the objects.
  [appleMenu release];
}

void StandardMenusMac::BuildEditMenu() {
  NSMenu* editMenu = [[NSMenu alloc] initWithTitle:@"Edit"];

  [editMenu addItemWithTitle:@"Undo"
                      action:@selector(undo:)
               keyEquivalent:@"z"];
  NSMenuItem* menuItem = (NSMenuItem *)[editMenu
      addItemWithTitle:@"Redo"
                action:@selector(redo:)
         keyEquivalent:@"z"];
  [menuItem setKeyEquivalentModifierMask:(NSShiftKeyMask|NSCommandKeyMask)];

  [editMenu addItem:[NSMenuItem separatorItem]];

  [editMenu addItemWithTitle:@"Cut"
                      action:@selector(cut:)
               keyEquivalent:@"x"];
  [editMenu addItemWithTitle:@"Copy"
                      action:@selector(copy:)
               keyEquivalent:@"c"];
  [editMenu addItemWithTitle:@"Paste"
                      action:@selector(paste:)
               keyEquivalent:@"v"];
  [editMenu addItemWithTitle:@"Delete"
                      action:@selector(delete:)
               keyEquivalent:@""];
  [editMenu addItemWithTitle:@"Select All"
                      action:@selector(selectAll:)
               keyEquivalent:@"a"];

  menuItem = [[NSMenuItem alloc] initWithTitle:@"Edit"
                                        action:nil
                                 keyEquivalent:@""];
  [menuItem setSubmenu:editMenu];
  [[NSApp mainMenu] insertItem:menuItem atIndex:1];

  [editMenu release];
  [menuItem release];
}

void StandardMenusMac::BuildWindowMenu() {
  NSMenu* windowMenu = [[NSMenu alloc] initWithTitle:@"Window"];

  [windowMenu addItemWithTitle:@"Minimize"
                        action:@selector(performMiniaturize:)
                 keyEquivalent:@"m"];
  [windowMenu addItemWithTitle:@"Close"
                        action:@selector(performClose:)
                 keyEquivalent:@"w"];

  [windowMenu addItem:[NSMenuItem separatorItem]];

  [windowMenu addItemWithTitle:@"Bring All to Front"
                        action:@selector(arrangeInFront:)
                 keyEquivalent:@""];

  NSMenuItem* windowMenuItem = [[NSMenuItem alloc]
      initWithTitle:@"Window"
             action:nil
      keyEquivalent:@""];
  [windowMenuItem setSubmenu:windowMenu];
  [[NSApp mainMenu] addItem:windowMenuItem];

  [NSApp setWindowsMenu:windowMenu];

  [windowMenu release];
  [windowMenuItem release];
}

}  // namespace nw


#if defined(OS_WIN) || defined(OS_LINUX)

ui::NwMenuModel* model() { return menu_model_.get(); }

keep keep keep replace keep keep keep keep

// 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/api/menu/menu.h"

#include "base/values.h"
#include "base/strings/utf_string_conversions.h"
#include "content/nw/src/api/object_manager.h"
#include "content/nw/src/api/menuitem/menuitem.h"
#include "content/public/browser/render_frame_host.h"
#include "content/public/browser/render_view_host.h"
#include "content/public/browser/render_widget_host_view.h"
#include "content/public/browser/web_contents.h"
#include "extensions/browser/app_window/app_window.h"
#include "skia/ext/image_operations.h"
#include "ui/aura/client/screen_position_client.h"
#include "ui/aura/window.h"
#include "ui/aura/window_tree_host.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/widget/widget.h"
#include "ui/views/focus/focus_manager.h"
#include "vector"

namespace ui {

NwMenuModel::NwMenuModel(Delegate* delegate) : SimpleMenuModel(delegate) {
}

bool NwMenuModel::HasIcons() const {
  // Always return false, see the comment about |NwMenuModel|.
  return false;
}

} // namespace ui

namespace nw {

void Menu::Create(const base::DictionaryValue& option) {
  is_menu_modified_ = true;
  menu_delegate_.reset(new MenuDelegate(object_manager()));
  menu_model_.reset(new ui::NwMenuModel(menu_delegate_.get()));

  focus_manager_ = NULL;
  window_ = NULL;

  std::string type;

  menu_items_.empty();
}

void Menu::Destroy() {
}

void Menu::Append(MenuItem* menu_item) {
  if (menu_item->submenu_)
    menu_model_->AddSubMenu(menu_item->id(), menu_item->label_,
                            menu_item->submenu_->menu_model_.get());
  else if (menu_item->type_ == "normal")
    menu_model_->AddItem(menu_item->id(), menu_item->label_);
  else if (menu_item->type_ == "checkbox")
    menu_model_->AddCheckItem(menu_item->id(), menu_item->label_);
  else if (menu_item->type_ == "separator")
    menu_model_->AddSeparator(ui::NORMAL_SEPARATOR);

  is_menu_modified_ = true;
  menu_items_.push_back(menu_item);
  menu_item->menu_ = this;
}

void Menu::Insert(MenuItem* menu_item, int pos) {
  if (pos < 0 || pos > menu_items_.size()) return;

  if (menu_item->submenu_)
    menu_model_->InsertSubMenuAt(pos, menu_item->id(), menu_item->label_,
                                 menu_item->submenu_->menu_model_.get());
  else if (menu_item->type_ == "normal")
    menu_model_->InsertItemAt(pos, menu_item->id(), menu_item->label_);
  else if (menu_item->type_ == "checkbox")
    menu_model_->InsertCheckItemAt(pos, menu_item->id(), menu_item->label_);
  else if (menu_item->type_ == "separator")
    menu_model_->InsertSeparatorAt(pos, ui::NORMAL_SEPARATOR);

  is_menu_modified_ = true;
  menu_item->menu_ = this;
  menu_items_.insert(menu_items_.begin() + pos, menu_item);
}

void Menu::Remove(MenuItem* menu_item, int pos) {
  if (pos < 0 || pos >= menu_items_.size()) return;

  menu_model_->RemoveItemAt(pos);
  menu_items_.erase(menu_items_.begin() + pos);
  is_menu_modified_ = true;
  menu_item->menu_ = NULL;
  menu_item->RemoveKeys();
}

void Menu::Popup(int x, int y, content::RenderFrameHost* rfh) {
  // Rebuild();

  // Map point from document to screen.
  gfx::Point screen_point(x, y);

  // Convert from content coordinates to window coordinates.
  // This code copied from chrome_web_contents_view_delegate_views.cc
  aura::Window* target_window = GetActiveNativeView(rfh);
  aura::Window* root_window = target_window->GetRootWindow();
  views::Widget* top_level_widget =
    views::Widget::GetTopLevelWidgetForNativeView(target_window);
  aura::client::ScreenPositionClient* screen_position_client =
        aura::client::GetScreenPositionClient(root_window);
  if (screen_position_client) {
    screen_position_client->ConvertPointToScreen(target_window,
             &screen_point);
  }
  set_delay_destruction(true);
  views::MenuRunner runner(menu_model_.get(), views::MenuRunner::CONTEXT_MENU);
  ignore_result(
      runner.RunMenuAt(top_level_widget,
                       NULL,
                       gfx::Rect(screen_point, gfx::Size()),
                       views::MENU_ANCHOR_TOPRIGHT,
                       ui::MENU_SOURCE_NONE));
  set_delay_destruction(false);
  if (pending_destruction())
    object_manager_->OnDeallocateObject(id_);
}

void Menu::UpdateKeys(views::FocusManager *focus_manager){
  if (focus_manager == NULL){
    return ;
  } else {
    focus_manager_ = focus_manager;
    for(auto item : menu_items_) {
      item->UpdateKeys(focus_manager);
    }
  }
}

void Menu::RemoveKeys() {
  if (!focus_manager_) return;

  for(auto item: menu_items_) {
    item->RemoveKeys();
  }

  focus_manager_ = NULL;
}

void Menu::UpdateStates() {
}

aura::Window* Menu::GetActiveNativeView(content::RenderFrameHost* rfh) {
  content::WebContents* web_contents =
    content::WebContents::FromRenderFrameHost(rfh);
  if (!web_contents) {
    LOG(ERROR) << "Menu: couldn't find WebContents";
    return NULL;
  }
  return web_contents->GetFullscreenRenderWidgetHostView()
             ? web_contents->GetFullscreenRenderWidgetHostView()
                   ->GetNativeView()
             : web_contents->GetNativeView();
}

}  // namespace nw


# once

Only call a function once.

## usage

```javascript
var once = require('once')

function load (file, cb) {
  cb = once(cb)
  loader.load('file')
  loader.once('load', cb)
  loader.once('error', cb)
}
```

Or add to the Function.prototype in a responsible way:

```javascript
// only has to be done once
require('once').proto()

function load (file, cb) {
  cb = cb.once()
  loader.load('file')
  loader.once('load', cb)
  loader.once('error', cb)
}
```

Ironically, the prototype feature makes this module twice as
complicated as necessary.

To check whether you function has been called, use `fn.called`. Once the
function is called for the first time the return value of the original
function is saved in `fn.value` and subsequent calls will continue to
return this value.

```javascript
var once = require('once')

function load (cb) {
  cb = once(cb)
  var stream = createStream()
  stream.once('data', cb)
  stream.once('end', function () {
    if (!cb.called) cb(new Error('not found'))
  })
}
```


void Menu::Insert(MenuItem* menu_item, int pos) {

if (pos < 0 || pos > menu_items_.size()) return;

keep keep keep replace replace keep keep keep keep


#include <stdio.h>

#include "base/at_exit.h"
#include "base/files/file_path.h"
#include "base/files/file_util.h"
#include "base/files/file_enumerator.h"
#include "base/i18n/icu_util.h"
#include "base/logging.h"
#include "base/memory/ptr_util.h"
#include "base/process/memory.h"
#include "base/strings/string_util.h"
#include "base/stl_util.h"
#include "crypto/secure_hash.h"
#include "crypto/sha2.h"
//#include "extensions/browser/content_hash_tree.h"
//#include "extensions/browser/computed_hashes.h"

#include "base/base64.h"
#include "base/json/json_reader.h"
#include "base/json/json_writer.h"
#include "base/values.h"

using crypto::kSHA256Length;
using crypto::SecureHash;

namespace {
const char kBlockHashesKey[] = "root_hash";
//const char kBlockSizeKey[] = "block_size";
const char kFileHashesKey[] = "files";
const char kPathKey[] = "path";
//const char kVersionKey[] = "version";
//const int kVersion = 2;

typedef std::set<base::FilePath> SortedFilePathSet;

bool MakePathAbsolute(base::FilePath* file_path) {
  DCHECK(file_path);

  base::FilePath current_directory;
  if (!base::GetCurrentDirectory(&current_directory))
    return false;

  if (file_path->IsAbsolute())
    return true;

  if (current_directory.empty()) {
    *file_path = base::MakeAbsoluteFilePath(*file_path);
    return true;
  }

  if (!current_directory.IsAbsolute())
    return false;

#ifdef OS_LINUX
  //linux might gives "/" as current_directory, return false
  if (current_directory.value().length() <= 1)
	return false;
#endif

  *file_path = current_directory.Append(*file_path);
  return true;
}

}  // namespace

class MyComputedHashes {
 public:
  class Writer {
   public:
    Writer();
    ~Writer();

    // Adds hashes for |relative_path|. Should not be called more than once
    // for a given |relative_path|.
    void AddHash(const base::FilePath& relative_path,
                 int block_size,
                 const std::string& hashes);

    bool WriteToFile(const base::FilePath& path);

   private:
    // Each element of this list contains the path and block hashes for one
    // file.
    std::unique_ptr<base::ListValue> file_list_;
  };

  // Computes the SHA256 hash of each |block_size| chunk in |contents|, placing
  // the results into |hashes|.
  static void ComputeHashesForContent(const std::string& contents,
                                      size_t block_size,
                                      std::vector<std::string>* hashes);
};

MyComputedHashes::Writer::Writer() : file_list_(new base::ListValue) {
}

MyComputedHashes::Writer::~Writer() {
}

void MyComputedHashes::Writer::AddHash(const base::FilePath& relative_path,
                                       int block_size,
                                       const std::string& root) {
  base::DictionaryValue* dict = new base::DictionaryValue();
  file_list_->Append(base::WrapUnique(dict));
  dict->SetString(kPathKey,
                  relative_path.NormalizePathSeparatorsTo('/').AsUTF8Unsafe());
  //dict->SetInteger(kBlockSizeKey, block_size);
  std::string encoded;
  base::Base64Encode(root, &encoded);
  base::ReplaceChars(encoded, "=", "", &encoded);
  base::ReplaceChars(encoded, "/", "_", &encoded);
  base::ReplaceChars(encoded, "+", "-", &encoded);
  dict->SetString(kBlockHashesKey, encoded);
}

bool MyComputedHashes::Writer::WriteToFile(const base::FilePath& path) {
  std::string json;
  base::DictionaryValue top_dictionary;
  top_dictionary.SetInteger("block_size", 4096);
  top_dictionary.SetInteger("hash_block_size", 4096);
  top_dictionary.SetString("format", "treehash");
  top_dictionary.Set(kFileHashesKey, file_list_.release());

  if (!base::JSONWriter::Write(top_dictionary, &json))
    return false;
  int written = base::WriteFile(path, json.data(), (int)json.size());
  if (static_cast<unsigned>(written) != json.size()) {
    LOG(ERROR) << "Error writing " << path.AsUTF8Unsafe()
               << " ; write result:" << written << " expected:" << json.size();
    return false;
  }
  return true;
}

void MyComputedHashes::ComputeHashesForContent(const std::string& contents,
                                             size_t block_size,
                                             std::vector<std::string>* hashes) {
  size_t offset = 0;
  // Even when the contents is empty, we want to output at least one hash
  // block (the hash of the empty string).
  do {
    const char* block_start = contents.data() + offset;
    DCHECK(offset <= contents.size());
    size_t bytes_to_read = std::min(contents.size() - offset, block_size);
    std::unique_ptr<crypto::SecureHash> hash(
        crypto::SecureHash::Create(crypto::SecureHash::SHA256));
    hash->Update(block_start, bytes_to_read);

    hashes->push_back(std::string());
    std::string* buffer = &(hashes->back());
    buffer->resize(crypto::kSHA256Length);
    hash->Finish(base::string_as_array(buffer), buffer->size());

    // If |contents| is empty, then we want to just exit here.
    if (bytes_to_read == 0)
      break;

    offset += bytes_to_read;
  } while (offset < contents.size());
}

std::string ComputeTreeHashRoot(const std::vector<std::string>& leaf_hashes,
                                int branch_factor) {
  if (leaf_hashes.empty() || branch_factor < 2)
    return std::string();

  // The nodes of the tree we're currently operating on.
  std::vector<std::string> current_nodes;

  // We avoid having to copy all of the input leaf nodes into |current_nodes|
  // by using a pointer. So the first iteration of the loop this points at
  // |leaf_hashes|, but thereafter it points at |current_nodes|.
  const std::vector<std::string>* current = &leaf_hashes;

  // Where we're inserting new hashes computed from the current level.
  std::vector<std::string> parent_nodes;

  while (current->size() > 1) {
    // Iterate over the current level of hashes, computing the hash of up to
    // |branch_factor| elements to form the hash of each parent node.
    std::vector<std::string>::const_iterator i = current->begin();
    while (i != current->end()) {
      std::unique_ptr<crypto::SecureHash> hash(
          crypto::SecureHash::Create(crypto::SecureHash::SHA256));
      for (int j = 0; j < branch_factor && i != current->end(); j++) {
        DCHECK_EQ(i->size(), crypto::kSHA256Length);
        hash->Update(i->data(), i->size());
        ++i;
      }
      parent_nodes.push_back(std::string(crypto::kSHA256Length, 0));
      std::string* output = &(parent_nodes.back());
      hash->Finish(base::string_as_array(output), output->size());
    }
    current_nodes.swap(parent_nodes);
    parent_nodes.clear();
    current = &current_nodes;
  }
  DCHECK_EQ(1u, current->size());
  return (*current)[0];
}

bool CreateHashes(const base::FilePath& hashes_file, const base::FilePath& work_path) {
  // Make sure the directory exists.
  if (!base::CreateDirectoryAndGetError(hashes_file.DirName(), NULL))
    return false;

  base::FilePath root_path(work_path);
  MakePathAbsolute(&root_path);
  base::FileEnumerator enumerator(root_path,
                                  true, /* recursive */
                                  base::FileEnumerator::FILES);
  // First discover all the file paths and put them in a sorted set.
  SortedFilePathSet paths;
  for (;;) {
    base::FilePath full_path = enumerator.Next();
    if (full_path.empty())
      break;
    paths.insert(full_path);
  }

  // Now iterate over all the paths in sorted order and compute the block hashes
  // for each one.
  MyComputedHashes::Writer writer;
  for (SortedFilePathSet::iterator i = paths.begin(); i != paths.end(); ++i) {
    const base::FilePath& full_path = *i;
    base::FilePath relative_path;
    root_path.AppendRelativePath(full_path, &relative_path);
    relative_path = relative_path.NormalizePathSeparatorsTo('/');

    std::string contents;
    if (!base::ReadFileToString(full_path, &contents)) {
      LOG(ERROR) << "Could not read " << full_path.MaybeAsASCII();
      continue;
    }

    // Iterate through taking the hash of each block of size (block_size_) of
    // the file.
    std::vector<std::string> hashes;
    MyComputedHashes::ComputeHashesForContent(contents, 4096, &hashes);
    std::string root =
      ComputeTreeHashRoot(hashes, 4096 / crypto::kSHA256Length);
    writer.AddHash(relative_path, 4096, root);
  }
  bool result = writer.WriteToFile(hashes_file);
  return result;
}

#if defined(OS_WIN)
int wmain(int argc, wchar_t* argv[]) {
#else
int main(int argc, char* argv[]) {
#endif
  base::AtExitManager exit_manager;
  //base::i18n::InitializeICU();

  return CreateHashes(base::FilePath(FILE_PATH_LITERAL("payload.json")),
                      base::FilePath(FILE_PATH_LITERAL("."))) ? 1 : 0;
}


var mkdirp = require('../');
var path = require('path');
var fs = require('fs');
var exists = fs.exists || path.exists;
var test = require('tap').test;
var _0777 = parseInt('0777', 8);
var _0755 = parseInt('0755', 8);

test('rel', function (t) {
    t.plan(5);
    var x = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
    var y = Math.floor(Math.random() * Math.pow(16,4)).toString(16);
    var z = Math.floor(Math.random() * Math.pow(16,4)).toString(16);

    var cwd = process.cwd();
    process.chdir('/tmp');

    var file = [x,y,z].join('/');

    mkdirp(file, _0755, function (err) {
        t.ifError(err);
        exists(file, function (ex) {
            t.ok(ex, 'file created');
            fs.stat(file, function (err, stat) {
                t.ifError(err);
                process.chdir(cwd);
                t.equal(stat.mode & _0777, _0755);
                t.ok(stat.isDirectory(), 'target not a directory');
            })
        })
    });
});


<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>worker-stream-event</title>
</head>
<body>
  <script>
  require('fs').createReadStream('package.json').on('open', () => {
    var h1 = document.createElement('h1');
    h1.setAttribute('id', 'result');
    h1.innerHTML = 'success';
    document.body.appendChild(h1);
  });
  </script>
</body>
</html>