From a4de9e4fdfb003fb94d0c21f338a6990d4303092 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 15 Apr 2014 21:28:41 +0800 Subject: [PATCH 001/492] don't force close remote instance with Node support Still use the 'close' event; Bind Window object on opening Remote window with normal frame is still force closed Fix #1778 --- src/api/api_messages.h | 2 ++ src/api/dispatcher_host.cc | 15 ++++++++++----- src/api/dispatcher_host.h | 2 ++ src/renderer/shell_content_renderer_client.cc | 10 ++++++++++ 4 files changed, 24 insertions(+), 5 deletions(-) diff --git a/src/api/api_messages.h b/src/api/api_messages.h index b4155c721f..88db56ae0b 100644 --- a/src/api/api_messages.h +++ b/src/api/api_messages.h @@ -100,3 +100,5 @@ IPC_MESSAGE_CONTROL0(ShellViewMsg_ClearCache) IPC_SYNC_MESSAGE_ROUTED0_1(ShellViewHostMsg_AllocateId, int) +IPC_SYNC_MESSAGE_ROUTED1_1(ShellViewHostMsg_SetForceClose, bool, int) + diff --git a/src/api/dispatcher_host.cc b/src/api/dispatcher_host.cc index d9fa56b49f..9bd3d33a3b 100644 --- a/src/api/dispatcher_host.cc +++ b/src/api/dispatcher_host.cc @@ -115,6 +115,7 @@ bool DispatcherHost::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(ShellViewHostMsg_GetShellId, OnGetShellId); IPC_MESSAGE_HANDLER(ShellViewHostMsg_CreateShell, OnCreateShell); IPC_MESSAGE_HANDLER(ShellViewHostMsg_AllocateId, OnAllocateId); + IPC_MESSAGE_HANDLER(ShellViewHostMsg_SetForceClose, OnSetForceClose); IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() @@ -281,17 +282,14 @@ void DispatcherHost::OnCreateShell(const std::string& url, WebContents* web_contents = content::WebContentsImpl::CreateWithOpener( create_params, static_cast(base_web_contents)); - content::Shell* new_shell = - content::Shell::Create(base_web_contents, + + content::Shell::Create(base_web_contents, GURL(url), new_manifest.get(), web_contents); if (new_renderer) { browser_context->set_pinning_renderer(true); - // since the new-instance shell is always bound - // there would be 'Close' event cannot reach dest - new_shell->set_force_close(true); } *routing_id = web_contents->GetRoutingID(); @@ -307,4 +305,11 @@ void DispatcherHost::OnAllocateId(int * ret) { *ret = AllocateId(); } +void DispatcherHost::OnSetForceClose(bool force, int* ret) { + content::Shell* shell = + content::Shell::FromRenderViewHost(render_view_host()); + shell->set_force_close(force); + *ret = 0; +} + } // namespace nwapi diff --git a/src/api/dispatcher_host.h b/src/api/dispatcher_host.h index f15115e1f1..2c904de25f 100644 --- a/src/api/dispatcher_host.h +++ b/src/api/dispatcher_host.h @@ -117,6 +117,8 @@ class DispatcherHost : public content::WebContentsObserver { const base::DictionaryValue& manifest, int* routing_id); void OnAllocateId(int* ret); + void OnSetForceClose(bool force, int* ret); + DISALLOW_COPY_AND_ASSIGN(DispatcherHost); }; diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index 5e2af8c561..b368fe1c79 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -347,6 +347,16 @@ void ShellContentRendererClient::InstallNodeSymbols( "process.versions['chromium'] = '" CHROME_VERSION "';" )); script->Run(); + v8::Local script2 = v8::Script::New(v8::String::New( + " nwDispatcher.requireNwGui().Window.get();" + )); + script2->Run(); + } else { + int ret; + RenderViewImpl* render_view = RenderViewImpl::FromWebView(frame->view()); + + render_view->Send(new ShellViewHostMsg_SetForceClose( + render_view->GetRoutingID(), true, &ret)); } } From dfc3ea1f47f52b3ae1e893250f695f7ea9f595c9 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Fri, 18 Apr 2014 16:06:07 +0100 Subject: [PATCH 002/492] [README] Update for 0.8.6 --- README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 1bef16f610..ec456e7b58 100644 --- a/README.md +++ b/README.md @@ -29,13 +29,13 @@ Prebuilt binaries (v0.9.2 - Feb 20, 2014): * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-osx-ia32.zip) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** -[v0.8.5 release notes](https://groups.google.com/d/msg/node-webkit/Izwu5icHFOQ/0A-3uEKfldkJ) +[v0.8.6 release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) -Prebuilt binaries (v0.8.5 - Feb 26, 2014): +Prebuilt binaries (v0.8.6 - Apr 18, 2014): -* Linux: [32bit](http://dl.node-webkit.org/v0.8.5/node-webkit-v0.8.5-linux-ia32.tar.gz) / [64bit] (http://dl.node-webkit.org/v0.8.5/node-webkit-v0.8.5-linux-x64.tar.gz) -* Windows: [win32](http://dl.node-webkit.org/v0.8.5/node-webkit-v0.8.5-win-ia32.zip) -* Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.8.5/node-webkit-v0.8.5-osx-ia32.zip) +* Linux: [32bit](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-linux-ia32.tar.gz) / [64bit] (http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-linux-x64.tar.gz) +* Windows: [win32](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-win-ia32.zip) +* Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-osx-ia32.zip) [Looking for older versions?](https://github.com/rogerwang/node-webkit/wiki/Downloads-of-old-versions) From a76a1a0c4cc68697d722e37e56805c9dbfa4b8d1 Mon Sep 17 00:00:00 2001 From: tinyproxy Date: Thu, 24 Apr 2014 15:30:32 +0800 Subject: [PATCH 003/492] Append nw-quit test case --- tests/manual_tests/quit/app/close-handler.js | 13 ++ tests/manual_tests/quit/app/index-server.html | 23 +++ tests/manual_tests/quit/app/index.html | 125 +++++++++++++ tests/manual_tests/quit/app/package.json | 4 + tests/manual_tests/quit/app/splash.html | 5 + tests/manual_tests/quit/index.html | 173 ++++++++++++++++++ tests/manual_tests/quit/package.json | 5 + 7 files changed, 348 insertions(+) create mode 100644 tests/manual_tests/quit/app/close-handler.js create mode 100644 tests/manual_tests/quit/app/index-server.html create mode 100644 tests/manual_tests/quit/app/index.html create mode 100644 tests/manual_tests/quit/app/package.json create mode 100644 tests/manual_tests/quit/app/splash.html create mode 100644 tests/manual_tests/quit/index.html create mode 100644 tests/manual_tests/quit/package.json diff --git a/tests/manual_tests/quit/app/close-handler.js b/tests/manual_tests/quit/app/close-handler.js new file mode 100644 index 0000000000..45be750277 --- /dev/null +++ b/tests/manual_tests/quit/app/close-handler.js @@ -0,0 +1,13 @@ +exports.init = function(win, nwGui) { + console.log('Setting up close handler'); + win.on('close', function(how) { + console.log('Got CLOSE event in close-handler.js with "' + how + '"'); + win.hide(); + var http = require('http'); + http.get("http://localhost:9000/close"); + setTimeout(function() { + console.log('Quitting from close handler'); + nwGui.App.quit(); + }, 5000); + }); +}; diff --git a/tests/manual_tests/quit/app/index-server.html b/tests/manual_tests/quit/app/index-server.html new file mode 100644 index 0000000000..a99f5bae1d --- /dev/null +++ b/tests/manual_tests/quit/app/index-server.html @@ -0,0 +1,23 @@ + + + NW Quit Test Server + + +

This is a hidden window

+ + + diff --git a/tests/manual_tests/quit/app/index.html b/tests/manual_tests/quit/app/index.html new file mode 100644 index 0000000000..52f5e8fc52 --- /dev/null +++ b/tests/manual_tests/quit/app/index.html @@ -0,0 +1,125 @@ + + + NW Quit Test + + +

+ + + + diff --git a/tests/manual_tests/quit/app/package.json b/tests/manual_tests/quit/app/package.json new file mode 100644 index 0000000000..2247ae95c3 --- /dev/null +++ b/tests/manual_tests/quit/app/package.json @@ -0,0 +1,4 @@ +{ + "name": "nw-quit", + "main": "index.html" +} diff --git a/tests/manual_tests/quit/app/splash.html b/tests/manual_tests/quit/app/splash.html new file mode 100644 index 0000000000..e70567e578 --- /dev/null +++ b/tests/manual_tests/quit/app/splash.html @@ -0,0 +1,5 @@ + + +

Splash screen

+ + diff --git a/tests/manual_tests/quit/index.html b/tests/manual_tests/quit/index.html new file mode 100644 index 0000000000..bf68312caa --- /dev/null +++ b/tests/manual_tests/quit/index.html @@ -0,0 +1,173 @@ + + + + + test + + + +
+
    +
  1. Click Quit Button(Automatical)
  2. +
  3. Click native window red dot.(left top or right top)
  4. +
  5. Press COMMAND-Q(MAC ONLY)
  6. +
  7. Press left top system menu node-webkit and click nw-quit.(MAC ONLY)
  8. +
+
+ +
+ + + + + + + + + + + + +
MethodcloseHandlerInNodeshowSplashScreenstartServerResult
+
+ + + + \ No newline at end of file diff --git a/tests/manual_tests/quit/package.json b/tests/manual_tests/quit/package.json new file mode 100644 index 0000000000..113d160a54 --- /dev/null +++ b/tests/manual_tests/quit/package.json @@ -0,0 +1,5 @@ +{ + "name":"test", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file From 144ac4601725f4f2a459f80fd17e34f309f2148f Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 25 Apr 2014 15:13:11 +0800 Subject: [PATCH 004/492] Fix headless devtools in iframe Adding back websocket interface in devtools --- src/nw_shell.cc | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 09b614c538..ffb76671eb 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -26,6 +26,7 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "content/browser/child_process_security_policy_impl.h" +#include "content/browser/devtools/devtools_http_handler_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/devtools_agent_host.h" @@ -74,6 +75,7 @@ using nw::NativeWindowWin; using base::MessageLoop; +using content::DevToolsHttpHandlerImpl; namespace content { std::vector Shell::windows_; @@ -412,12 +414,17 @@ void Shell::ShowDevTools(const char* jail_id, bool headless) { browser_client->shell_browser_main_parts()->devtools_delegate(); GURL url = delegate->devtools_http_handler()->GetFrontendURL(); - SendEvent("devtools-opened", url.spec()); if (headless) { - // FIXME: DevToolsFrontendHost + DevToolsAgentHost* agent_host = DevToolsAgentHost::GetOrCreateFor(inspected_rvh).get(); + + url = delegate->devtools_http_handler()->GetFrontendURL(agent_host); + DevToolsHttpHandlerImpl* http_handler = static_cast(delegate->devtools_http_handler()); + http_handler->EnumerateTargets(); + SendEvent("devtools-opened", url.spec()); return; } + SendEvent("devtools-opened", url.spec()); // Use our minimum set manifest base::DictionaryValue manifest; manifest.SetBoolean(switches::kmToolbar, false); From d4cc1ea77d2dbf07a59a43a09d2866d7119438e0 Mon Sep 17 00:00:00 2001 From: Mithgol Date: Fri, 25 Apr 2014 07:09:08 -0700 Subject: [PATCH 005/492] =?UTF-8?q?capital=20=E2=80=9CS=E2=80=9D=20in?= =?UTF-8?q?=C2=A0=E2=80=9CJavaScript=E2=80=9D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ec456e7b58..ab7e6356e6 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ ## Introduction node-webkit is an app runtime based on `Chromium` and `node.js`. You can -write native apps in HTML and Javascript with node-webkit. It also lets you +write native apps in HTML and JavaScript with node-webkit. It also lets you call Node.js modules directly from the DOM and enables a new way of writing native applications with all Web technologies. From feff3f923070bb001d40844a7ba8412992775fd6 Mon Sep 17 00:00:00 2001 From: libm Date: Tue, 29 Apr 2014 22:43:15 +0800 Subject: [PATCH 006/492] Return non-zero when error to inform ninja of the failure. --- tools/package_binaries.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 6122aac774..0ffdda01db 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -26,11 +26,11 @@ tmp = sys.argv[sys.argv.index('-p') + 1] if not os.path.isabs(tmp): print 'the path is not an absolute path.\n' - exit() + exit(-1) if not os.path.exists(tmp): print 'the directory does not exist.\n' - exit() + exit(-1) project_root = tmp @@ -50,27 +50,27 @@ if platform_name == 'linux' and not os.path.exists( os.path.join(project_root, 'nw')): print 'nw file does not exist.\n' - exit() + exit(-1) if platform_name == 'win' and not os.path.exists( os.path.join(project_root, 'nw.exe')): print 'nw file does not exist.\n' - exit() + exit(-1) if platform_name == 'osx' and not os.path.exists( os.path.join(project_root, 'node-webkit.app')): print 'nw file does not exist.\n' - exit() + exit(-1) if platform_name != 'win' and not os.path.exists( os.path.join(project_root, 'chromedriver2_server')): print 'chromedriver2_server file does not exist.\n' - exit() + exit(-1) if platform_name == 'win' and not os.path.exists( os.path.join(project_root, 'chromedriver2_server.exe')): print 'chromedriver2_server file does not exist.\n' - exit() + exit(-1) required_file_linux = ( From 22e3610734976be030074b48d2ce79ec1efa4d79 Mon Sep 17 00:00:00 2001 From: libm Date: Wed, 30 Apr 2014 13:01:43 +0800 Subject: [PATCH 007/492] Make linux_dump_symbols default to be 1 The linux_dump_sybols is set to 0 in common.gypi:1033, so the default value in nw.gypi will be ignored anyways. Removing the % could make this option valid. --- nw.gypi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nw.gypi b/nw.gypi index 11af9d460d..5cedde1553 100644 --- a/nw.gypi +++ b/nw.gypi @@ -7,7 +7,7 @@ 'nw_product_name': 'node-webkit', 'conditions': [ ['OS=="linux"', { - 'linux_dump_symbols%': 1, + 'linux_dump_symbols': 1, }], ], }, From 33f393e5d931ff3d995dfa29799c77106dc3db05 Mon Sep 17 00:00:00 2001 From: tinyproxy Date: Thu, 17 Apr 2014 16:02:02 +0800 Subject: [PATCH 008/492] Append uncaughtException listener to process to avoid crash. Fix bugs in the test cases' code,to help generate a stable result. Update Mocha version to avoid stoping while test case failed. --- tests/automatic_tests/app/index.html | 3 +- tests/automatic_tests/app/mocha_test.js | 13 +- .../calls_across_window/mocha_test.js | 1 - .../chromedriver2_server_test.py | 41 +- .../chromedriver2_server/mocha_test.js | 4 +- .../chromium-args/mocha_test.js | 54 +- tests/automatic_tests/cookies_api/index.html | 258 +- .../automatic_tests/cookies_api/mocha_test.js | 166 +- .../document_cookies/mocha_test.js | 110 +- .../loaded_event/mocha_test.js | 6 +- tests/automatic_tests/node-main/mocha_test.js | 19 +- .../automatic_tests/node-remote/mocha_test.js | 2 +- tests/automatic_tests/process/exit/index.html | 4 +- tests/automatic_tests/process/mocha_test.js | 36 +- .../reload_application/mocha_test.js | 2 - tests/automatic_tests/snapshot/mocha_test.js | 192 +- tests/automatic_tests/start_app/mocha_test.js | 13 +- tests/automatic_tests/start_app/script.js | 7 +- .../user-agent-app/mocha_test.js | 37 +- tests/automatic_tests/website/mocha_test.js | 25 +- tests/automatic_tests/window/index.html | 9 + tests/index.html | 46 +- tests/mocha/Readme.md | 172 + tests/mocha/bin/_mocha | 467 ++ tests/mocha/bin/mocha | 51 + tests/mocha/images/error.png | Bin 0 -> 412 bytes tests/mocha/images/ok.png | Bin 0 -> 388 bytes tests/mocha/index.js | 4 + tests/mocha/lib/browser/debug.js | 5 + tests/mocha/lib/browser/diff.js | 354 + tests/mocha/lib/browser/events.js | 178 + tests/mocha/lib/browser/fs.js | 0 tests/mocha/lib/browser/path.js | 0 tests/mocha/lib/browser/progress.js | 125 + tests/mocha/lib/browser/tty.js | 13 + tests/mocha/lib/context.js | 69 + tests/mocha/lib/hook.js | 49 + tests/mocha/lib/interfaces/bdd.js | 137 + tests/mocha/lib/interfaces/exports.js | 60 + tests/mocha/lib/interfaces/index.js | 5 + tests/mocha/lib/interfaces/qunit.js | 122 + tests/mocha/lib/interfaces/tdd.js | 138 + tests/mocha/lib/mocha.js | 370 ++ tests/mocha/lib/ms.js | 109 + tests/mocha/lib/reporters/base.js | 507 ++ tests/mocha/lib/reporters/doc.js | 56 + tests/mocha/lib/reporters/dot.js | 62 + tests/mocha/lib/reporters/html-cov.js | 51 + tests/mocha/lib/reporters/html.js | 273 + tests/mocha/lib/reporters/index.js | 18 + tests/mocha/lib/reporters/json-cov.js | 153 + tests/mocha/lib/reporters/json-stream.js | 61 + tests/mocha/lib/reporters/json.js | 70 + tests/mocha/lib/reporters/landing.js | 97 + tests/mocha/lib/reporters/list.js | 64 + tests/mocha/lib/reporters/markdown.js | 91 + tests/mocha/lib/reporters/min.js | 38 + tests/mocha/lib/reporters/nyan.js | 260 + tests/mocha/lib/reporters/progress.js | 86 + tests/mocha/lib/reporters/spec.js | 83 + tests/mocha/lib/reporters/tap.js | 73 + .../lib/reporters/templates/coverage.jade | 50 + tests/mocha/lib/reporters/templates/menu.jade | 13 + .../mocha/lib/reporters/templates/script.html | 34 + .../mocha/lib/reporters/templates/style.html | 320 + tests/mocha/lib/reporters/xunit.js | 119 + tests/mocha/lib/runnable.js | 231 + tests/mocha/lib/runner.js | 661 ++ tests/mocha/lib/suite.js | 320 + tests/mocha/lib/template.html | 18 + tests/mocha/lib/test.js | 32 + tests/mocha/lib/utils.js | 299 + tests/mocha/mocha.css | 270 + tests/mocha/mocha.js | 5848 +++++++++++++++++ tests/mocha/node_modules/commander/History.md | 179 + tests/mocha/node_modules/commander/Readme.md | 195 + tests/mocha/node_modules/commander/index.js | 847 +++ .../mocha/node_modules/commander/package.json | 38 + tests/mocha/node_modules/diff/README.md | 101 + tests/mocha/node_modules/diff/diff.js | 354 + tests/mocha/node_modules/diff/package.json | 51 + tests/mocha/node_modules/glob/.npmignore | 2 + tests/mocha/node_modules/glob/.travis.yml | 3 + tests/mocha/node_modules/glob/LICENSE | 27 + tests/mocha/node_modules/glob/README.md | 250 + tests/mocha/node_modules/glob/examples/g.js | 9 + .../node_modules/glob/examples/usr-local.js | 9 + tests/mocha/node_modules/glob/glob.js | 675 ++ .../glob/node_modules/graceful-fs/.npmignore | 1 + .../glob/node_modules/graceful-fs/LICENSE | 27 + .../glob/node_modules/graceful-fs/README.md | 26 + .../node_modules/graceful-fs/graceful-fs.js | 160 + .../node_modules/graceful-fs/package.json | 49 + .../node_modules/graceful-fs/polyfills.js | 228 + .../node_modules/graceful-fs/test/open.js | 39 + .../graceful-fs/test/readdir-sort.js | 21 + .../glob/node_modules/inherits/LICENSE | 16 + .../glob/node_modules/inherits/README.md | 42 + .../glob/node_modules/inherits/inherits.js | 1 + .../node_modules/inherits/inherits_browser.js | 23 + .../glob/node_modules/inherits/package.json | 33 + .../glob/node_modules/inherits/test.js | 25 + .../glob/node_modules/minimatch/.npmignore | 1 + .../glob/node_modules/minimatch/LICENSE | 23 + .../glob/node_modules/minimatch/README.md | 218 + .../glob/node_modules/minimatch/minimatch.js | 1055 +++ .../node_modules/lru-cache/.npmignore | 1 + .../node_modules/lru-cache/CONTRIBUTORS | 14 + .../minimatch/node_modules/lru-cache/LICENSE | 23 + .../node_modules/lru-cache/README.md | 97 + .../node_modules/lru-cache/lib/lru-cache.js | 252 + .../node_modules/lru-cache/package.json | 33 + .../node_modules/lru-cache/test/basic.js | 369 ++ .../node_modules/lru-cache/test/foreach.js | 52 + .../lru-cache/test/memory-leak.js | 50 + .../minimatch/node_modules/sigmund/LICENSE | 27 + .../minimatch/node_modules/sigmund/README.md | 53 + .../minimatch/node_modules/sigmund/bench.js | 283 + .../node_modules/sigmund/package.json | 42 + .../minimatch/node_modules/sigmund/sigmund.js | 39 + .../node_modules/sigmund/test/basic.js | 24 + .../glob/node_modules/minimatch/package.json | 40 + .../glob/node_modules/minimatch/test/basic.js | 399 ++ .../minimatch/test/brace-expand.js | 33 + .../node_modules/minimatch/test/caching.js | 14 + .../node_modules/minimatch/test/defaults.js | 274 + .../test/extglob-ending-with-state-char.js | 8 + tests/mocha/node_modules/glob/package.json | 40 + .../mocha/node_modules/glob/test/00-setup.js | 176 + .../node_modules/glob/test/bash-comparison.js | 63 + .../node_modules/glob/test/bash-results.json | 350 + .../mocha/node_modules/glob/test/cwd-test.js | 55 + .../node_modules/glob/test/globstar-match.js | 19 + tests/mocha/node_modules/glob/test/mark.js | 74 + .../node_modules/glob/test/nocase-nomagic.js | 113 + .../node_modules/glob/test/pause-resume.js | 73 + .../node_modules/glob/test/root-nomount.js | 39 + tests/mocha/node_modules/glob/test/root.js | 46 + tests/mocha/node_modules/glob/test/stat.js | 32 + .../node_modules/glob/test/zz-cleanup.js | 11 + tests/mocha/node_modules/growl/History.md | 63 + tests/mocha/node_modules/growl/Readme.md | 99 + tests/mocha/node_modules/growl/lib/growl.js | 234 + tests/mocha/node_modules/growl/package.json | 14 + tests/mocha/node_modules/growl/test.js | 20 + tests/mocha/node_modules/mkdirp/.npmignore | 2 + tests/mocha/node_modules/mkdirp/.travis.yml | 5 + tests/mocha/node_modules/mkdirp/LICENSE | 21 + .../mocha/node_modules/mkdirp/examples/pow.js | 6 + tests/mocha/node_modules/mkdirp/index.js | 82 + tests/mocha/node_modules/mkdirp/package.json | 34 + .../mocha/node_modules/mkdirp/readme.markdown | 63 + tests/mocha/node_modules/mkdirp/test/chmod.js | 38 + .../mocha/node_modules/mkdirp/test/clobber.js | 37 + .../mocha/node_modules/mkdirp/test/mkdirp.js | 28 + tests/mocha/node_modules/mkdirp/test/perm.js | 32 + .../node_modules/mkdirp/test/perm_sync.js | 39 + tests/mocha/node_modules/mkdirp/test/race.js | 41 + tests/mocha/node_modules/mkdirp/test/rel.js | 32 + .../mocha/node_modules/mkdirp/test/return.js | 25 + .../node_modules/mkdirp/test/return_sync.js | 24 + tests/mocha/node_modules/mkdirp/test/root.js | 18 + tests/mocha/node_modules/mkdirp/test/sync.js | 32 + tests/mocha/node_modules/mkdirp/test/umask.js | 28 + .../node_modules/mkdirp/test/umask_sync.js | 32 + tests/mocha/package.json | 60 + tests/package.json | 1 - tests/server/cookie_server.js | 71 + tests/server/server.js | 3 + 169 files changed, 22400 insertions(+), 464 deletions(-) create mode 100644 tests/mocha/Readme.md create mode 100755 tests/mocha/bin/_mocha create mode 100755 tests/mocha/bin/mocha create mode 100644 tests/mocha/images/error.png create mode 100644 tests/mocha/images/ok.png create mode 100644 tests/mocha/index.js create mode 100644 tests/mocha/lib/browser/debug.js create mode 100644 tests/mocha/lib/browser/diff.js create mode 100644 tests/mocha/lib/browser/events.js create mode 100644 tests/mocha/lib/browser/fs.js create mode 100644 tests/mocha/lib/browser/path.js create mode 100644 tests/mocha/lib/browser/progress.js create mode 100644 tests/mocha/lib/browser/tty.js create mode 100644 tests/mocha/lib/context.js create mode 100644 tests/mocha/lib/hook.js create mode 100644 tests/mocha/lib/interfaces/bdd.js create mode 100644 tests/mocha/lib/interfaces/exports.js create mode 100644 tests/mocha/lib/interfaces/index.js create mode 100644 tests/mocha/lib/interfaces/qunit.js create mode 100644 tests/mocha/lib/interfaces/tdd.js create mode 100644 tests/mocha/lib/mocha.js create mode 100644 tests/mocha/lib/ms.js create mode 100644 tests/mocha/lib/reporters/base.js create mode 100644 tests/mocha/lib/reporters/doc.js create mode 100644 tests/mocha/lib/reporters/dot.js create mode 100644 tests/mocha/lib/reporters/html-cov.js create mode 100644 tests/mocha/lib/reporters/html.js create mode 100644 tests/mocha/lib/reporters/index.js create mode 100644 tests/mocha/lib/reporters/json-cov.js create mode 100644 tests/mocha/lib/reporters/json-stream.js create mode 100644 tests/mocha/lib/reporters/json.js create mode 100644 tests/mocha/lib/reporters/landing.js create mode 100644 tests/mocha/lib/reporters/list.js create mode 100644 tests/mocha/lib/reporters/markdown.js create mode 100644 tests/mocha/lib/reporters/min.js create mode 100644 tests/mocha/lib/reporters/nyan.js create mode 100644 tests/mocha/lib/reporters/progress.js create mode 100644 tests/mocha/lib/reporters/spec.js create mode 100644 tests/mocha/lib/reporters/tap.js create mode 100644 tests/mocha/lib/reporters/templates/coverage.jade create mode 100644 tests/mocha/lib/reporters/templates/menu.jade create mode 100644 tests/mocha/lib/reporters/templates/script.html create mode 100644 tests/mocha/lib/reporters/templates/style.html create mode 100644 tests/mocha/lib/reporters/xunit.js create mode 100644 tests/mocha/lib/runnable.js create mode 100644 tests/mocha/lib/runner.js create mode 100644 tests/mocha/lib/suite.js create mode 100644 tests/mocha/lib/template.html create mode 100644 tests/mocha/lib/test.js create mode 100644 tests/mocha/lib/utils.js create mode 100644 tests/mocha/mocha.css create mode 100644 tests/mocha/mocha.js create mode 100644 tests/mocha/node_modules/commander/History.md create mode 100644 tests/mocha/node_modules/commander/Readme.md create mode 100644 tests/mocha/node_modules/commander/index.js create mode 100644 tests/mocha/node_modules/commander/package.json create mode 100644 tests/mocha/node_modules/diff/README.md create mode 100644 tests/mocha/node_modules/diff/diff.js create mode 100644 tests/mocha/node_modules/diff/package.json create mode 100644 tests/mocha/node_modules/glob/.npmignore create mode 100644 tests/mocha/node_modules/glob/.travis.yml create mode 100644 tests/mocha/node_modules/glob/LICENSE create mode 100644 tests/mocha/node_modules/glob/README.md create mode 100644 tests/mocha/node_modules/glob/examples/g.js create mode 100644 tests/mocha/node_modules/glob/examples/usr-local.js create mode 100644 tests/mocha/node_modules/glob/glob.js create mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/.npmignore create mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/LICENSE create mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/README.md create mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/graceful-fs.js create mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/package.json create mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/polyfills.js create mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/test/open.js create mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/test/readdir-sort.js create mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/LICENSE create mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/README.md create mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/inherits.js create mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/inherits_browser.js create mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/package.json create mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/test.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/.npmignore create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/LICENSE create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/README.md create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/minimatch.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/.npmignore create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/CONTRIBUTORS create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/LICENSE create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/README.md create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/package.json create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/basic.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/foreach.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/LICENSE create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/README.md create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/bench.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/package.json create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/sigmund.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/test/basic.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/package.json create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/test/basic.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/test/brace-expand.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/test/caching.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/test/defaults.js create mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/test/extglob-ending-with-state-char.js create mode 100644 tests/mocha/node_modules/glob/package.json create mode 100644 tests/mocha/node_modules/glob/test/00-setup.js create mode 100644 tests/mocha/node_modules/glob/test/bash-comparison.js create mode 100644 tests/mocha/node_modules/glob/test/bash-results.json create mode 100644 tests/mocha/node_modules/glob/test/cwd-test.js create mode 100644 tests/mocha/node_modules/glob/test/globstar-match.js create mode 100644 tests/mocha/node_modules/glob/test/mark.js create mode 100644 tests/mocha/node_modules/glob/test/nocase-nomagic.js create mode 100644 tests/mocha/node_modules/glob/test/pause-resume.js create mode 100644 tests/mocha/node_modules/glob/test/root-nomount.js create mode 100644 tests/mocha/node_modules/glob/test/root.js create mode 100644 tests/mocha/node_modules/glob/test/stat.js create mode 100644 tests/mocha/node_modules/glob/test/zz-cleanup.js create mode 100644 tests/mocha/node_modules/growl/History.md create mode 100644 tests/mocha/node_modules/growl/Readme.md create mode 100644 tests/mocha/node_modules/growl/lib/growl.js create mode 100644 tests/mocha/node_modules/growl/package.json create mode 100644 tests/mocha/node_modules/growl/test.js create mode 100644 tests/mocha/node_modules/mkdirp/.npmignore create mode 100644 tests/mocha/node_modules/mkdirp/.travis.yml create mode 100644 tests/mocha/node_modules/mkdirp/LICENSE create mode 100644 tests/mocha/node_modules/mkdirp/examples/pow.js create mode 100644 tests/mocha/node_modules/mkdirp/index.js create mode 100644 tests/mocha/node_modules/mkdirp/package.json create mode 100644 tests/mocha/node_modules/mkdirp/readme.markdown create mode 100644 tests/mocha/node_modules/mkdirp/test/chmod.js create mode 100644 tests/mocha/node_modules/mkdirp/test/clobber.js create mode 100644 tests/mocha/node_modules/mkdirp/test/mkdirp.js create mode 100644 tests/mocha/node_modules/mkdirp/test/perm.js create mode 100644 tests/mocha/node_modules/mkdirp/test/perm_sync.js create mode 100644 tests/mocha/node_modules/mkdirp/test/race.js create mode 100644 tests/mocha/node_modules/mkdirp/test/rel.js create mode 100644 tests/mocha/node_modules/mkdirp/test/return.js create mode 100644 tests/mocha/node_modules/mkdirp/test/return_sync.js create mode 100644 tests/mocha/node_modules/mkdirp/test/root.js create mode 100644 tests/mocha/node_modules/mkdirp/test/sync.js create mode 100644 tests/mocha/node_modules/mkdirp/test/umask.js create mode 100644 tests/mocha/node_modules/mkdirp/test/umask_sync.js create mode 100644 tests/mocha/package.json create mode 100644 tests/server/cookie_server.js diff --git a/tests/automatic_tests/app/index.html b/tests/automatic_tests/app/index.html index f12e02f867..65a091fbbf 100644 --- a/tests/automatic_tests/app/index.html +++ b/tests/automatic_tests/app/index.html @@ -21,10 +21,11 @@ if (self.name == 2) gui.App.clearCache(); else if (self.name == 3) { + gui.App.clearCache(); var client = require('../../nw_test_app').createClient({ argv: gui.App.argv, data: {} - }); + }); } location.reload(); } diff --git a/tests/automatic_tests/app/mocha_test.js b/tests/automatic_tests/app/mocha_test.js index 6ae0862b28..3f32b62f9f 100644 --- a/tests/automatic_tests/app/mocha_test.js +++ b/tests/automatic_tests/app/mocha_test.js @@ -37,11 +37,20 @@ describe('gui.App', function() { describe('clearCache()', function(done) { it('should clear the HTTP cache in memory and the one on disk', function() { var res_save = global.local_server.res_save; - + //request 4 time + //1. 200 request image from remote server + //2. 304 load image from cache + //3. 304 load image from cache, but we call clearCache API this time + //4. 200 clear cache, request image from remote server + assert.equal(res_save.length,4); + assert.equal(res_save[0].status, 200); + assert.equal(res_save[0].pathname, 'img.jpg'); assert.equal(res_save[1].status, 304); assert.equal(res_save[1].pathname, 'img.jpg'); - assert.equal(res_save[2].status, 200); + assert.equal(res_save[2].status, 304); assert.equal(res_save[2].pathname, 'img.jpg'); + assert.equal(res_save[3].status, 200); + assert.equal(res_save[3].pathname, 'img.jpg'); }); }); }) diff --git a/tests/automatic_tests/calls_across_window/mocha_test.js b/tests/automatic_tests/calls_across_window/mocha_test.js index 3ecb13696d..ceaa1d3864 100644 --- a/tests/automatic_tests/calls_across_window/mocha_test.js +++ b/tests/automatic_tests/calls_across_window/mocha_test.js @@ -7,7 +7,6 @@ var cb; describe('AppTest', function(){ describe('call across window', function(){ - var app; var exec_argv; var socket; diff --git a/tests/automatic_tests/chromedriver2_server/chromedriver2_server_test.py b/tests/automatic_tests/chromedriver2_server/chromedriver2_server_test.py index 52eeb0be29..1d1fac779e 100644 --- a/tests/automatic_tests/chromedriver2_server/chromedriver2_server_test.py +++ b/tests/automatic_tests/chromedriver2_server/chromedriver2_server_test.py @@ -2,11 +2,35 @@ import time import os from selenium import webdriver +from platform import platform #path = os.getcwd(); #path = os.path.join(path, 'tmp-nw', 'chromedriver2_server'); -path = '/home/owen-cloud/Desktop/kevin/node-webkit/tests/tmp-nw/chromedriver2_server'; +path = os.path.join(os.path.abspath(__file__),"../../../tmp-nw/chromedriver2_server") +path = os.path.abspath(path) +def kill_process_tree(pid): + machine_type = platform() + if "Linux" in machine_type or "Darwin" in machine_type: + import psutil + parent = psutil.Process(spid) + for child in parent.get_children(recursive=True): + child.kill() + parent.kill() + return + elif 'Windows' in machine_type: + import subprocess + dev_null = open(os.devnull,"wb") + subprocess.Popen(['taskkill', '/F', '/T', '/PID', str(pid)],stdout=dev_null,stderr=dev_null) + return + else: + # print "Unknow OS type" + return + + + + +driver = None try: driver = webdriver.Chrome(path); driver.get('http://www.google.com'); @@ -16,11 +40,18 @@ search_box = driver.find_element_by_name('q') search_box.send_keys('ChromeDriver') search_box.submit() - time.sleep(5) # Let the user actually see something! - assert driver.title[0:12] == 'ChromeDriver' - driver.quit() + time.sleep(5); + title = str(driver.title[0:12]) + assert title == 'ChromeDriver' except: - driver.quit(); traceback.print_exc() else: print 'pass' + + +# Now driver.quit() will not quit normal, it is selenium's bug +# we kill process recursive, if the API works, uncomment next line and delete last 2 lines +# driver.quit() +spid = driver.service.process.pid +kill_process_tree(spid) +exit(0) diff --git a/tests/automatic_tests/chromedriver2_server/mocha_test.js b/tests/automatic_tests/chromedriver2_server/mocha_test.js index f1a22bcfde..ed666c6cfe 100644 --- a/tests/automatic_tests/chromedriver2_server/mocha_test.js +++ b/tests/automatic_tests/chromedriver2_server/mocha_test.js @@ -47,7 +47,9 @@ describe('chromedriver2_server', function() { done("chromedrier2_server does not exist"); else { assert.equal(result[0], null); - assert.equal(result[1], 'pass\n'); + if (result[1] != 'pass\n' && result[1] != 'pass\r\n'){ + done(result[1]); + } assert.equal(result[2], ''); done(); } diff --git a/tests/automatic_tests/chromium-args/mocha_test.js b/tests/automatic_tests/chromium-args/mocha_test.js index c0bc77a0a0..8a6481ca1e 100644 --- a/tests/automatic_tests/chromium-args/mocha_test.js +++ b/tests/automatic_tests/chromium-args/mocha_test.js @@ -31,34 +31,34 @@ describe('chromium-args', function() { }); }); - describe('--app=url', function() { - var result2 = false; - before(function(done) { - this.timeout(0); - fs_extra.copy(path.join(app_path, 'package2.json'), path.join(app_path, 'package.json'), function (err) { - if (err) { - throw err; - } - var child = app_test.createChildProcess({ - execPath: exec_path, - appPath: app_path, - end: function(data, app) { - result2 = data; - app.kill(); - done() - } - }); - }); - }); + // describe('--app=url', function() { + // var result2 = false; + // before(function(done) { + // this.timeout(0); + // fs_extra.copy(path.join(app_path, 'package2.json'), path.join(app_path, 'package.json'), function (err) { + // if (err) { + // throw err; + // } + // var child = app_test.createChildProcess({ + // execPath: exec_path, + // appPath: app_path, + // end: function(data, app) { + // result2 = data; + // app.kill(); + // done() + // } + // }); + // }); + // }); - it('website should be the url', function() { - assert.equal(result2, true); - }); + // it('website should be the url', function() { + // assert.equal(result2, true); + // }); - after(function() { - fs.unlink(path.join(app_path, 'package.json'), function(err) {if(err && err.code !== 'ENOENT') throw err}); - fs.unlink(path.join(app_path, 'hi'), function(err) {if(err && err.code !== 'ENOENT') throw err}); - }); - }); + // after(function() { + // fs.unlink(path.join(app_path, 'package.json'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + // fs.unlink(path.join(app_path, 'hi'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + // }); + // }); }); diff --git a/tests/automatic_tests/cookies_api/index.html b/tests/automatic_tests/cookies_api/index.html index 10f426bfc4..08a3dd72ae 100644 --- a/tests/automatic_tests/cookies_api/index.html +++ b/tests/automatic_tests/cookies_api/index.html @@ -1,129 +1,145 @@ - - TEST CASE FOR COOKIES API - - -

Hello World!

- We are using node.js - + + - - - diff --git a/tests/automatic_tests/cookies_api/mocha_test.js b/tests/automatic_tests/cookies_api/mocha_test.js index 4f662d15e3..c0f75be3ee 100644 --- a/tests/automatic_tests/cookies_api/mocha_test.js +++ b/tests/automatic_tests/cookies_api/mocha_test.js @@ -4,99 +4,99 @@ var assert = require('assert'); var results; var changed; describe('Window.cookies', function() { - describe("get, getAll", function() { - before(function(done) { - this.timeout(0); - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'cookies_api'), - args: [1], - end: function(data, app) { - results = data; - app.kill(); - console.log("1"); - done(); - } - }); - }); - it('should get cookies', function() { - assert.equal(results[0], true); - assert.equal(results[1], true); - }) + before(function(done) { + this.timeout(0); + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'cookies_api'), + args: [1], + end: function(data, app) { + results = data; + app.kill(); + done(); + } + }); + }); + it('should get cookies', function(done) { + assert.equal(results[0], true); + assert.equal(results[1], true); + done(); + }) }) describe("set", function() { - describe("set lang en", function() { - before(function(done) { - this.timeout(0); - var first = false; - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'cookies_api'), - args: [2], - end: function(data, app) { - results = data; - changed = results[1]; - app.kill(); - console.log("2"); - done(); - } - }); - }); - it('should get cookies', function() { - assert.equal(results[0], true); - }) - }); + describe("set lang en", function() { + before(function(done) { + this.timeout(0); + var first = false; + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'cookies_api'), + args: [2], + end: function(data, app) { + results = data; + changed = results[1]; + app.kill(); + done(); + } + }); + }); + it('should get cookies', function(done) { + assert.equal(results[0], true); + done(); + }) + }); - describe("set lang zh", function() { - before(function(done) { - this.timeout(0); - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'cookies_api'), - args: [3], - end: function(data, app) { - console.log("3"); - results = data; - done(); - app.kill(); - } - }); - }); + describe("set lang zh", function() { + before(function(done) { + this.timeout(0); + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'cookies_api'), + args: [3], + end: function(data, app) { + results = data; + done(); + app.kill(); + } + }); + }); - it('should get cookies', function() { - assert.equal(results[0], true); - }) - }); + it('should get cookies', function(done) { + assert.equal(results[0], true); + done(); + }) + }); }); - + describe('remove', function() { - before(function(done) { - this.timeout(0); - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'cookies_api'), - args: [4], - end: function(data, app) { - console.log("4"); - results = data; - app.kill(); - done(); - } - }); - }); + before(function(done) { + this.timeout(0); + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'cookies_api'), + args: [4], + end: function(data, app) { + results = data; + changed = results[0]; + app.kill(); + done(); + } + }); + }); - it('should remove lang', function() { - assert.equal(results[1], false); - }); + it('should remove lang', function(done) { + assert.equal(results[1], false); + done(); + }); }); - + describe('onChanged', function() { - it('should be called when changed', function() { - assert.equal(changed, true); - }) + it('should be called when changed', function(done) { + assert.equal(changed, true); + done(); + }) }); -}); - +}); \ No newline at end of file diff --git a/tests/automatic_tests/document_cookies/mocha_test.js b/tests/automatic_tests/document_cookies/mocha_test.js index c06b748823..bed1986203 100644 --- a/tests/automatic_tests/document_cookies/mocha_test.js +++ b/tests/automatic_tests/document_cookies/mocha_test.js @@ -4,60 +4,70 @@ var assert = require('assert'); var gui = require('nw.gui'); var results = new Array(); describe('document.cookies', function() { +//this case could be very slow on OS X +//leave child process enough time to finish its job + this.timeout(10000); + describe('http', function() { + before(function(done) { + this.timeout(0); + var url = "http://127.0.0.1:8123/document_cookies.html"; + var win = gui.Window.open(url); - describe('http', function() { - before(function(done) { - this.timeout(0); - var url = "http://127.0.0.1:8123/document_cookies.html"; - var win = gui.Window.open(url); - - setTimeout(function() { - results.push(win.window.msg.textContent); - done(); - win.window.close(); - }, 1000); - }); - it('should be set', function() { - assert.equal(results[0], '123'); + win.on("loaded", function() { + results.push(win.window.msg.textContent); + done(); + win.window.close(); + }); + }); + it('should be set', function() { + assert.equal(results[0], '123'); + }); }); - }); - describe('file', function() { - before(function(done) { - this.timeout(0); - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'document_cookies', 'file'), - end: function(data, app) { - results.push(data); - app.kill(); - done(); - } - }); - setTimeout(done, 3000); + describe('file', function() { + before(function(done) { + this.timeout(0); + var crontab = undefined; + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'document_cookies', 'file'), + end: function(data, app) { + if (crontab !== undefined){ + clearTimeout(crontab); + } + results.push(data); + app.kill(); + done(); + } + }); + crontab = setTimeout(done, 10000); + }); + it('should be set', function() { + assert.equal(results[1], '123'); + }); }); - it ('should be set', function() { - assert.equal(results[1], '123'); - }); - }); - describe('app', function() { - before(function(done) { - this.timeout(0); - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'document_cookies', 'app'), - end: function(data, app) { - results.push(data); - app.kill(); - done(); - } - }); - setTimeout(done, 3000); - }); - it ('should be set', function() { - assert.equal(results[2], '123'); + describe('app', function() { + before(function(done) { + this.timeout(0); + var crontab = undefined; + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'document_cookies', 'app'), + end: function(data, app) { + if (crontab !== undefined){ + clearTimeout(crontab); + } + results.push(data); + app.kill(); + done(); + } + }); + crontab = setTimeout(done, 10000); + }); + it('should be set', function() { + assert.equal(results[2], '123'); + }); }); - }); -}); +}); \ No newline at end of file diff --git a/tests/automatic_tests/loaded_event/mocha_test.js b/tests/automatic_tests/loaded_event/mocha_test.js index ec416b4b38..b4a9d6f52a 100644 --- a/tests/automatic_tests/loaded_event/mocha_test.js +++ b/tests/automatic_tests/loaded_event/mocha_test.js @@ -8,11 +8,15 @@ describe('loaded event', function() { function(done) { this.timeout(0); var result = false; + var crontab = undefined; var child = app_test.createChildProcess({ execPath: process.execPath, appPath: path.join(global.tests_dir, 'loaded_event'), end: function(data, app) { + if (crontab !== undefined){ + clearTimeout(crontab); + } result = true; done(); app.kill(); @@ -20,7 +24,7 @@ describe('loaded event', function() { }); - setTimeout(function(){ + crontab = setTimeout(function(){ if (!result) { child.close(); //child.app.kill(); diff --git a/tests/automatic_tests/node-main/mocha_test.js b/tests/automatic_tests/node-main/mocha_test.js index 6ca189d9d7..4205726b60 100644 --- a/tests/automatic_tests/node-main/mocha_test.js +++ b/tests/automatic_tests/node-main/mocha_test.js @@ -4,37 +4,40 @@ var app_test = require('./nw_test_app'); describe('node-main', function() { describe('create http server in node-main', function() { it('nw should not close by itself after show devtool', - function(done) { + function(done) { this.timeout(0); var result = false; + var crontab = undefined; + var child = app_test.createChildProcess({ execPath: process.execPath, appPath: path.join(global.tests_dir, - 'show_devtool_after_http_server_created_in_node_main'), + 'show_devtool_after_http_server_created_in_node_main'), end: function(data, app) { + clearTimeout(crontab); app.kill(); if (data.success) { done(); } else { done('erro'); - } + } result = true; } }); - setTimeout(function(){ + crontab = setTimeout(function() { if (!result) { done('nw close by itself') } }, 3000); //child.app.stderr.on('data', function(d){ console.log ('app' + d);}); - }) + }) }) describe('call require() in app', function() { - it('nw should can require modules', function(done){ + it('nw should can require modules', function(done) { this.timeout(0); var child = app_test.createChildProcess({ @@ -46,10 +49,10 @@ describe('node-main', function() { done(); } else { done(data.error); - } + } } }); }) }) -}) +}) \ No newline at end of file diff --git a/tests/automatic_tests/node-remote/mocha_test.js b/tests/automatic_tests/node-remote/mocha_test.js index 737c129899..56672bfccc 100644 --- a/tests/automatic_tests/node-remote/mocha_test.js +++ b/tests/automatic_tests/node-remote/mocha_test.js @@ -62,7 +62,7 @@ describe('node-remote', function() { } else { done(); } - + socket.end(); }); socket.write('8124'); }) diff --git a/tests/automatic_tests/process/exit/index.html b/tests/automatic_tests/process/exit/index.html index 15aed33954..b33afd4e6d 100644 --- a/tests/automatic_tests/process/exit/index.html +++ b/tests/automatic_tests/process/exit/index.html @@ -11,8 +11,10 @@ fs.openSync('a.txt', 'w'); }); + + process.exit(); - gui.Window.get().close(true); + // gui.Window.get().close(true); sdew diff --git a/tests/automatic_tests/process/mocha_test.js b/tests/automatic_tests/process/mocha_test.js index cc0b6b8c4c..3fb3d72140 100644 --- a/tests/automatic_tests/process/mocha_test.js +++ b/tests/automatic_tests/process/mocha_test.js @@ -4,29 +4,33 @@ var fs = require('fs-extra'); describe('process', function() { - describe('exit', function(){ + describe('exit', function() { it('event process.exit should be fired after calling win.close(true)', function(done) { - - + var crontab = undefined; var child = app_test.createChildProcess({ execPath: process.execPath, appPath: path.join(global.tests_dir, 'process', 'exit'), - no_connect: true + no_connect: true, }); - setTimeout(function() { - fs.exists(path.join(global.tests_dir, 'process', 'exit', 'a.txt'), function (exists) { - if (exists) { - fs.unlink(path.join(global.tests_dir, 'process', 'exit', 'a.txt'), done); - } else { - done('the event `exit` does not been called.'); - } - }); - - }, 1500); - + child.app.on('exit',function(){ + fs.exists(path.join(global.tests_dir, 'process', 'exit', 'a.txt'), function(exists) { + if (crontab){ + clearTimeout(crontab); + } + if (exists) { + fs.unlink(path.join(global.tests_dir, 'process', 'exit', 'a.txt'), done); + } else { + done('the event `exit` does not been called.'); + } + }); + }); + crontab = setTimeout(function() { + console.log("CHILD PROCESS FAIL TO EXIT"); + done('the event `exit` does not been called.'); + }, 5000); }) }) -}) +}) \ No newline at end of file diff --git a/tests/automatic_tests/reload_application/mocha_test.js b/tests/automatic_tests/reload_application/mocha_test.js index f41181b8ab..80c945498d 100644 --- a/tests/automatic_tests/reload_application/mocha_test.js +++ b/tests/automatic_tests/reload_application/mocha_test.js @@ -8,8 +8,6 @@ var cb; describe('AppTest', function(){ describe('reload app (long-to-run)', function(){ - - var exec_argv = [path.join(global.tests_dir, 'reload_application'), '--port', global.port, diff --git a/tests/automatic_tests/snapshot/mocha_test.js b/tests/automatic_tests/snapshot/mocha_test.js index 5a9e5eac6c..f60084d184 100644 --- a/tests/automatic_tests/snapshot/mocha_test.js +++ b/tests/automatic_tests/snapshot/mocha_test.js @@ -7,98 +7,116 @@ var snapshotPath; describe('snapshot', function() { - describe('demo should work fine', function() { - before(function(done) { - var snapshotExec; - if (os.platform() == 'darwin') { - snapshotExec = '../../../../../../nwsnapshot'; - } - if (os.platform() == 'linux') { - snapshotExec = 'nwsnapshot'; - } - if (os.platform() == 'win32') { - snapshotExec = 'nwsnapshot.exe'; - } - - snapshotPath = path.join(process.execPath, '..', snapshotExec); - console.log("snapshotPath: " + snapshotPath); - - cp.execFile(snapshotPath, - ['--extra_code', 'mytest.js', 'mytest.bin'], - {cwd:'./' + global.tests_dir + '/snapshot/'}, - function (error, stdout, stderr) { - done(); + describe('demo should work fine', function() { + before(function(done) { + var snapshotExec; + if (os.platform() == 'darwin') { + snapshotExec = '../../../../../../nwsnapshot'; + } + if (os.platform() == 'linux') { + snapshotExec = 'nwsnapshot'; + } + if (os.platform() == 'win32') { + snapshotExec = 'nwsnapshot.exe'; } - ); - }) + snapshotPath = path.join(process.execPath, '..', snapshotExec); + console.log("snapshotPath: " + snapshotPath); + + cp.execFile(snapshotPath, ['--extra_code', 'mytest.js', 'mytest.bin'], { + cwd: './' + global.tests_dir + '/snapshot/' + }, + function(error, stdout, stderr) { + done(); + } + + ); + }) + + after(function() { + fs.unlink(path.join(global.tests_dir, 'snapshot', 'mytest.bin'), function(err) { + if (err && err.code !== 'ENOENT') throw err + }); + fs.unlink(path.join(global.tests_dir, 'snapshot', 'v8.log'), function(err) { + if (err && err.code !== 'ENOENT') throw err + }); + }) - after(function() { - fs.unlink(path.join(global.tests_dir, 'snapshot', 'mytest.bin'), function(err) {if(err && err.code !== 'ENOENT') throw err}); - fs.unlink(path.join(global.tests_dir, 'snapshot', 'v8.log'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + it('the native code could be exectuted', + function(done) { + this.timeout(0); + var result = false; + + var checkBinExists = function() { + var binPath = path.join(global.tests_dir, 'snapshot', 'mytest.bin'); + console.log(binPath); + if (fs.existsSync(binPath) == false) { + setTimeout(checkBinExists, 500); + } else { + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'snapshot'), + end: function(data, app) { + done(); + app.kill(); + result = true; + } + }); + + setTimeout(function() { + if (!result) { + done('the native code does not been executed'); + child.close(); + //child.removeConnection(); + //child.app.kill(); + } + }, 10000); + //child.app.stderr.on('data', function(d){ console.log ('app' + d);}); + } + }; + + checkBinExists(); + }) }) - it('the native code could be exectuted', - function(done) { - this.timeout(0); - var result = false; - - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'snapshot'), - end: function(data, app) { - done(); - app.kill(); - result = true; - } - }); - - setTimeout(function(){ - if (!result) { - done('the native code does not been executed'); - child.close(); - //child.removeConnection(); - //child.app.kill(); - } - }, 3000); - //child.app.stderr.on('data', function(d){ console.log ('app' + d);}); - - }) - }) - - describe('1266-snapshot-crash-start', function() { - before(function(done) { - cp.execFile(snapshotPath, - ['--extra_code', 'file_to_snapshot_to_app.bin.js', 'app.bin'], - {cwd:'./' + global.tests_dir + '/snapshot/1266-snapshot-crash-start/'}, - function (error, stdout, stderr) { - done(); - } - - ); - }) - - after(function() { - fs.unlink(path.join(global.tests_dir, 'snapshot','1266-snapshot-crash-start', 'app.bin'), function(err) {if(err && err.code !== 'ENOENT') throw err}); - fs.unlink(path.join(global.tests_dir, 'snapshot','1266-snapshot-crash-start', 'v8.log'), function(err) {if(err && err.code !== 'ENOENT') throw err}); - fs.unlink(path.join(global.tests_dir, 'snapshot','1266-snapshot-crash-start','tmp'), function(err) {if(err && err.code !== 'ENOENT') throw err}); - }) - - it('another demo should close nomally', function(done) { - this.timeout(0); - var ppath = process.execPath + " " + path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start'); - cp.exec(ppath, function(err, stdout, stderr) { - }); - setTimeout(function(){ - fs.exists(path.join(global.tests_dir, 'snapshot','1266-snapshot-crash-start', 'tmp'), function(exists) { - if (exists) - done(); - else - done('another demo fails'); + describe('1266-snapshot-crash-start', function() { + before(function(done) { + cp.execFile(snapshotPath, ['--extra_code', 'file_to_snapshot_to_app.bin.js', 'app.bin'], { + cwd: './' + global.tests_dir + '/snapshot/1266-snapshot-crash-start/' + }, + function(error, stdout, stderr) { + done(); + } + + ); + }) + + after(function() { + fs.unlink(path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start', 'app.bin'), function(err) { + if (err && err.code !== 'ENOENT') throw err + }); + fs.unlink(path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start', 'v8.log'), function(err) { + if (err && err.code !== 'ENOENT') throw err + }); + fs.unlink(path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start', 'tmp'), function(err) { + if (err && err.code !== 'ENOENT') throw err + }); + }) + + it('another demo should close nomally', function(done) { + this.timeout(0); + var ppath = process.execPath + " " + path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start'); + cp.exec(ppath, function(err, stdout, stderr) {}); + setTimeout(function() { + fs.exists(path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start', 'tmp'), function(exists) { + if (exists) + done(); + else + done('another demo fails'); + }); + }, 3000); }); - }, 3000); - }); - }); + }); -}) +}) \ No newline at end of file diff --git a/tests/automatic_tests/start_app/mocha_test.js b/tests/automatic_tests/start_app/mocha_test.js index 6afa1b2fc7..2735c5b4c3 100644 --- a/tests/automatic_tests/start_app/mocha_test.js +++ b/tests/automatic_tests/start_app/mocha_test.js @@ -12,9 +12,7 @@ var execPath = func.getExecPath(); describe('Startup', function() { describe('different method of starting app (long-to-run)', function() { var temp_root = 'tmp-nw'; - before(function(done){ - this.timeout(10000); func.copyExecFiles(function() { func.copySourceFiles(); func.zipSourceFiles(function() { @@ -22,15 +20,16 @@ describe('different method of starting app (long-to-run)', function() { done(); }); }); + setTimeout(function(){ + done("ERROR") + },10000); }) after(function() { - setTimeout(function() { - fs.remove('tmp-nw', function (er) { - if (er) throw er; - }) - }, 1000); + fs.removeSync('tmp-nw', function (er) { + if (er) throw er; + }) }) it('start from nw that package.json in the same folder', function(done) { diff --git a/tests/automatic_tests/start_app/script.js b/tests/automatic_tests/start_app/script.js index 64d9a6a3fa..497bb9b9ef 100644 --- a/tests/automatic_tests/start_app/script.js +++ b/tests/automatic_tests/start_app/script.js @@ -84,8 +84,11 @@ exports.copySourceFiles = function(folder) { } exports.zipSourceFiles = function(callback) { - exec('python automatic_tests/start_app/zip.py'); - setTimeout(callback, 2000); + exec('python automatic_tests/start_app/zip.py',function(){ + if (typeof callback === 'function'){ + callback(); + } + }); } exports.makeExecuableFile = function() { diff --git a/tests/automatic_tests/user-agent-app/mocha_test.js b/tests/automatic_tests/user-agent-app/mocha_test.js index 418475a433..a03849f7ac 100644 --- a/tests/automatic_tests/user-agent-app/mocha_test.js +++ b/tests/automatic_tests/user-agent-app/mocha_test.js @@ -7,27 +7,30 @@ describe('user-agent-app', function() { function(done) { this.timeout(0); var result = false; + var crontab = undefined; var child = app_test.createChildProcess({ execPath: process.execPath, appPath: path.join(global.tests_dir, 'user-agent-app'), end: function(data, app) { - result = true; - var package_info = JSON.parse(fs.readFileSync('automatic_tests/user-agent-app/package.json', 'utf8')); - app.kill(); - if (data == package_info.name) { - done(); - } - else{ - done('the user agent has changed'); - } + if (crontab != undefined){ + clearTimeout(crontab); + } + result = true; + var package_info = JSON.parse(fs.readFileSync('automatic_tests/user-agent-app/package.json', 'utf8')); + app.kill(); + if (data == package_info.name) { + done(); + } else { + done('the user agent has changed'); + } } }); - setTimeout(function(){ - if (!result) { - child.close(); - done('loaded event does not been fired'); - } - }, 10000); - }) -}) + crontab = setTimeout(function() { + if (!result) { + child.close(); + done('loaded event does not been fired'); + } + }, 10000); + }) +}) \ No newline at end of file diff --git a/tests/automatic_tests/website/mocha_test.js b/tests/automatic_tests/website/mocha_test.js index 7547c91eca..9caeec32ba 100644 --- a/tests/automatic_tests/website/mocha_test.js +++ b/tests/automatic_tests/website/mocha_test.js @@ -6,31 +6,32 @@ describe('website', function() { it('html5test.com should score high (long-to-run)', function(done) { this.timeout(0); - var win = gui.Window.open('http://html5test.com', { show: false }); + var win = gui.Window.open('http://html5test.com', { show: true }); win.on('loaded', function() { - var results = win.window.document.getElementById('results'); - if (results == null){ - done('Can not connect to the web'); - win.close(); - return; - } - try { - var score = results.childNodes[0].childNodes[1].innerHTML;; + //do not read data immediately, it is a RESTful site. + //wait 4 seconds + setTimeout(function(){ + var results = win.window.document.querySelectorAll('div.pointsPanel strong'); + if (results.length === 0){ + done('Can not connect to the web'); + return; + } + + var score = parseInt(results[0].innerHTML); if (score >= 445) { done(); } else { done('have a low score'); } win.close(); - } catch (e) { - } + },4000); }); }); it('should support WebGL at get.webgl.org', function(done) { this.timeout(0); - var win = gui.Window.open('http://get.webgl.org', { show: false }); + var win = gui.Window.open('http://get.webgl.org', { show: true }); win.on('loaded', function() { var results = win.window.document.getElementById('webgl-yes'); if (results.classList.contains('webgl-hidden')) { diff --git a/tests/automatic_tests/window/index.html b/tests/automatic_tests/window/index.html index 3ebd01f650..4afe3dd08a 100644 --- a/tests/automatic_tests/window/index.html +++ b/tests/automatic_tests/window/index.html @@ -4,11 +4,18 @@ Test Case for 'Window.focus' + -
diff --git a/tests/mocha/lib/reporters/templates/style.html b/tests/mocha/lib/reporters/templates/style.html new file mode 100644 index 0000000000..643c0ab7b8 --- /dev/null +++ b/tests/mocha/lib/reporters/templates/style.html @@ -0,0 +1,320 @@ + \ No newline at end of file diff --git a/tests/mocha/lib/reporters/xunit.js b/tests/mocha/lib/reporters/xunit.js new file mode 100644 index 0000000000..e956380d8e --- /dev/null +++ b/tests/mocha/lib/reporters/xunit.js @@ -0,0 +1,119 @@ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `XUnit`. + */ + +exports = module.exports = XUnit; + +/** + * Initialize a new `XUnit` reporter. + * + * @param {Runner} runner + * @api public + */ + +function XUnit(runner) { + Base.call(this, runner); + var stats = this.stats + , tests = [] + , self = this; + + runner.on('pending', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + tests.push(test); + }); + + runner.on('fail', function(test){ + tests.push(test); + }); + + runner.on('end', function(){ + console.log(tag('testsuite', { + name: 'Mocha Tests' + , tests: stats.tests + , failures: stats.failures + , errors: stats.failures + , skipped: stats.tests - stats.failures - stats.passes + , timestamp: (new Date).toUTCString() + , time: (stats.duration / 1000) || 0 + }, false)); + + tests.forEach(test); + console.log(''); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +XUnit.prototype.__proto__ = Base.prototype; + +/** + * Output tag for the given `test.` + */ + +function test(test) { + var attrs = { + classname: test.parent.fullTitle() + , name: test.title + , time: (test.duration / 1000) || 0 + }; + + if ('failed' == test.state) { + var err = test.err; + attrs.message = escape(err.message); + console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); + } else if (test.pending) { + console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); + } else { + console.log(tag('testcase', attrs, true) ); + } +} + +/** + * HTML tag helper. + */ + +function tag(name, attrs, close, content) { + var end = close ? '/>' : '>' + , pairs = [] + , tag; + + for (var key in attrs) { + pairs.push(key + '="' + escape(attrs[key]) + '"'); + } + + tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; + if (content) tag += content + ''; +} diff --git a/tests/mocha/lib/runnable.js b/tests/mocha/lib/runnable.js new file mode 100644 index 0000000000..6940bb77d3 --- /dev/null +++ b/tests/mocha/lib/runnable.js @@ -0,0 +1,231 @@ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , debug = require('debug')('mocha:runnable') + , milliseconds = require('./ms'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Object#toString(). + */ + +var toString = Object.prototype.toString; + +/** + * Expose `Runnable`. + */ + +module.exports = Runnable; + +/** + * Initialize a new `Runnable` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Runnable(title, fn) { + this.title = title; + this.fn = fn; + this.async = fn && fn.length; + this.sync = ! this.async; + this._timeout = 2000; + this._slow = 75; + this.timedOut = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Runnable.prototype.__proto__ = EventEmitter.prototype; + +/** + * Set & get timeout `ms`. + * + * @param {Number|String} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._timeout = ms; + if (this.timer) this.resetTimeout(); + return this; +}; + +/** + * Set & get slow `ms`. + * + * @param {Number|String} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.slow = function(ms){ + if (0 === arguments.length) return this._slow; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._slow = ms; + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Runnable.prototype.fullTitle = function(){ + return this.parent.fullTitle() + ' ' + this.title; +}; + +/** + * Clear the timeout. + * + * @api private + */ + +Runnable.prototype.clearTimeout = function(){ + clearTimeout(this.timer); +}; + +/** + * Inspect the runnable void of private properties. + * + * @return {String} + * @api private + */ + +Runnable.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + if ('_' == key[0]) return; + if ('parent' == key) return '#'; + if ('ctx' == key) return '#'; + return val; + }, 2); +}; + +/** + * Reset the timeout. + * + * @api private + */ + +Runnable.prototype.resetTimeout = function(){ + var self = this; + var ms = this.timeout() || 1e9; + + this.clearTimeout(); + this.timer = setTimeout(function(){ + self.callback(new Error('timeout of ' + ms + 'ms exceeded')); + self.timedOut = true; + }, ms); +}; + +/** + * Whitelist these globals for this test run + * + * @api private + */ +Runnable.prototype.globals = function(arr){ + var self = this; + this._allowedGlobals = arr; +}; + +/** + * Run the test and invoke `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runnable.prototype.run = function(fn){ + var self = this + , ms = this.timeout() + , start = new Date + , ctx = this.ctx + , finished + , emitted; + + if (ctx) ctx.runnable(this); + + // called multiple times + function multiple(err) { + if (emitted) return; + emitted = true; + self.emit('error', err || new Error('done() called multiple times')); + } + + // finished + function done(err) { + if (self.timedOut) return; + if (finished) return multiple(err); + self.clearTimeout(); + self.duration = new Date - start; + finished = true; + fn(err); + } + + // for .resetTimeout() + this.callback = done; + + // explicit async with `done` argument + if (this.async) { + this.resetTimeout(); + + try { + this.fn.call(ctx, function(err){ + if (err instanceof Error || toString.call(err) === "[object Error]") return done(err); + if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); + done(); + }); + } catch (err) { + done(err); + } + return; + } + + if (this.asyncOnly) { + return done(new Error('--async-only option in use without declaring `done()`')); + } + + // sync or promise-returning + try { + if (this.pending) { + done(); + } else { + callFn(this.fn); + } + } catch (err) { + done(err); + } + + function callFn(fn) { + var result = fn.call(ctx); + if (result && typeof result.then === 'function') { + self.resetTimeout(); + result.then(function(){ done() }, done); + } else { + done(); + } + } +}; diff --git a/tests/mocha/lib/runner.js b/tests/mocha/lib/runner.js new file mode 100644 index 0000000000..deb442e145 --- /dev/null +++ b/tests/mocha/lib/runner.js @@ -0,0 +1,661 @@ +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , debug = require('debug')('mocha:runner') + , Test = require('./test') + , utils = require('./utils') + , filter = utils.filter + , keys = utils.keys; + +/** + * Non-enumerable globals. + */ + +var globals = [ + 'setTimeout', + 'clearTimeout', + 'setInterval', + 'clearInterval', + 'XMLHttpRequest', + 'Date' +]; + +/** + * Expose `Runner`. + */ + +module.exports = Runner; + +/** + * Initialize a `Runner` for the given `suite`. + * + * Events: + * + * - `start` execution started + * - `end` execution complete + * - `suite` (suite) test suite execution started + * - `suite end` (suite) all tests (and sub-suites) have finished + * - `test` (test) test execution started + * - `test end` (test) test completed + * - `hook` (hook) hook execution started + * - `hook end` (hook) hook complete + * - `pass` (test) test passed + * - `fail` (test, err) test failed + * - `pending` (test) test pending + * + * @api public + */ + +function Runner(suite) { + var self = this; + this._globals = []; + this._abort = false; + this.suite = suite; + this.total = suite.total(); + this.failures = 0; + this.on('test end', function(test){ self.checkGlobals(test); }); + this.on('hook end', function(hook){ self.checkGlobals(hook); }); + this.grep(/.*/); + this.globals(this.globalProps().concat(extraGlobals())); +} + +/** + * Wrapper for setImmediate, process.nextTick, or browser polyfill. + * + * @param {Function} fn + * @api private + */ + +Runner.immediately = global.setImmediate || process.nextTick; + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Runner.prototype.__proto__ = EventEmitter.prototype; + +/** + * Run tests with full titles matching `re`. Updates runner.total + * with number of tests matched. + * + * @param {RegExp} re + * @param {Boolean} invert + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.grep = function(re, invert){ + debug('grep %s', re); + this._grep = re; + this._invert = invert; + this.total = this.grepTotal(this.suite); + return this; +}; + +/** + * Returns the number of tests matching the grep search for the + * given suite. + * + * @param {Suite} suite + * @return {Number} + * @api public + */ + +Runner.prototype.grepTotal = function(suite) { + var self = this; + var total = 0; + + suite.eachTest(function(test){ + var match = self._grep.test(test.fullTitle()); + if (self._invert) match = !match; + if (match) total++; + }); + + return total; +}; + +/** + * Return a list of global properties. + * + * @return {Array} + * @api private + */ + +Runner.prototype.globalProps = function() { + var props = utils.keys(global); + + // non-enumerables + for (var i = 0; i < globals.length; ++i) { + if (~utils.indexOf(props, globals[i])) continue; + props.push(globals[i]); + } + + return props; +}; + +/** + * Allow the given `arr` of globals. + * + * @param {Array} arr + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.globals = function(arr){ + if (0 == arguments.length) return this._globals; + debug('globals %j', arr); + this._globals = this._globals.concat(arr); + return this; +}; + +/** + * Check for global variable leaks. + * + * @api private + */ + +Runner.prototype.checkGlobals = function(test){ + if (this.ignoreLeaks) return; + var ok = this._globals; + + var globals = this.globalProps(); + var isNode = process.kill; + var leaks; + + if (test) { + ok = ok.concat(test._allowedGlobals || []); + } + + if(this.prevGlobalsLength == globals.length) return; + this.prevGlobalsLength = globals.length; + + leaks = filterLeaks(ok, globals); + this._globals = this._globals.concat(leaks); + + if (leaks.length > 1) { + this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); + } else if (leaks.length) { + this.fail(test, new Error('global leak detected: ' + leaks[0])); + } +}; + +/** + * Fail the given `test`. + * + * @param {Test} test + * @param {Error} err + * @api private + */ + +Runner.prototype.fail = function(test, err){ + ++this.failures; + test.state = 'failed'; + + if ('string' == typeof err) { + err = new Error('the string "' + err + '" was thrown, throw an Error :)'); + } + + this.emit('fail', test, err); +}; + +/** + * Fail the given `hook` with `err`. + * + * Hook failures work in the following pattern: + * - If bail, then exit + * - Failed `before` hook skips all tests in a suite and subsuites, + * but jumps to corresponding `after` hook + * - Failed `before each` hook skips remaining tests in a + * suite and jumps to corresponding `after each` hook, + * which is run only once + * - Failed `after` hook does not alter + * execution order + * - Failed `after each` hook skips remaining tests in a + * suite and subsuites, but executes other `after each` + * hooks + * + * @param {Hook} hook + * @param {Error} err + * @api private + */ + +Runner.prototype.failHook = function(hook, err){ + this.fail(hook, err); + if (this.suite.bail()) { + this.emit('end'); + } +}; + +/** + * Run hook `name` callbacks and then invoke `fn()`. + * + * @param {String} name + * @param {Function} function + * @api private + */ + +Runner.prototype.hook = function(name, fn){ + var suite = this.suite + , hooks = suite['_' + name] + , self = this + , timer; + + function next(i) { + var hook = hooks[i]; + if (!hook) return fn(); + if (self.failures && suite.bail()) return fn(); + self.currentRunnable = hook; + + hook.ctx.currentTest = self.test; + + self.emit('hook', hook); + + hook.on('error', function(err){ + self.failHook(hook, err); + }); + + hook.run(function(err){ + hook.removeAllListeners('error'); + var testError = hook.error(); + if (testError) self.fail(self.test, testError); + if (err) { + self.failHook(hook, err); + + // stop executing hooks, notify callee of hook err + return fn(err); + } + self.emit('hook end', hook); + delete hook.ctx.currentTest; + next(++i); + }); + } + + Runner.immediately(function(){ + next(0); + }); +}; + +/** + * Run hook `name` for the given array of `suites` + * in order, and callback `fn(err, errSuite)`. + * + * @param {String} name + * @param {Array} suites + * @param {Function} fn + * @api private + */ + +Runner.prototype.hooks = function(name, suites, fn){ + var self = this + , orig = this.suite; + + function next(suite) { + self.suite = suite; + + if (!suite) { + self.suite = orig; + return fn(); + } + + self.hook(name, function(err){ + if (err) { + var errSuite = self.suite; + self.suite = orig; + return fn(err, errSuite); + } + + next(suites.pop()); + }); + } + + next(suites.pop()); +}; + +/** + * Run hooks from the top level down. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookUp = function(name, fn){ + var suites = [this.suite].concat(this.parents()).reverse(); + this.hooks(name, suites, fn); +}; + +/** + * Run hooks from the bottom up. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookDown = function(name, fn){ + var suites = [this.suite].concat(this.parents()); + this.hooks(name, suites, fn); +}; + +/** + * Return an array of parent Suites from + * closest to furthest. + * + * @return {Array} + * @api private + */ + +Runner.prototype.parents = function(){ + var suite = this.suite + , suites = []; + while (suite = suite.parent) suites.push(suite); + return suites; +}; + +/** + * Run the current test and callback `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTest = function(fn){ + var test = this.test + , self = this; + + if (this.asyncOnly) test.asyncOnly = true; + + try { + test.on('error', function(err){ + self.fail(test, err); + }); + test.run(fn); + } catch (err) { + fn(err); + } +}; + +/** + * Run tests in the given `suite` and invoke + * the callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTests = function(suite, fn){ + var self = this + , tests = suite.tests.slice() + , test; + + + function hookErr(err, errSuite, after) { + // before/after Each hook for errSuite failed: + var orig = self.suite; + + // for failed 'after each' hook start from errSuite parent, + // otherwise start from errSuite itself + self.suite = after ? errSuite.parent : errSuite; + + if (self.suite) { + // call hookUp afterEach + self.hookUp('afterEach', function(err2, errSuite2) { + self.suite = orig; + // some hooks may fail even now + if (err2) return hookErr(err2, errSuite2, true); + // report error suite + fn(errSuite); + }); + } else { + // there is no need calling other 'after each' hooks + self.suite = orig; + fn(errSuite); + } + } + + function next(err, errSuite) { + // if we bail after first err + if (self.failures && suite._bail) return fn(); + + if (self._abort) return fn(); + + if (err) return hookErr(err, errSuite, true); + + // next test + test = tests.shift(); + + // all done + if (!test) return fn(); + + // grep + var match = self._grep.test(test.fullTitle()); + if (self._invert) match = !match; + if (!match) return next(); + + // pending + if (test.pending) { + self.emit('pending', test); + self.emit('test end', test); + return next(); + } + + // execute test and hook(s) + self.emit('test', self.test = test); + self.hookDown('beforeEach', function(err, errSuite){ + + if (err) return hookErr(err, errSuite, false); + + self.currentRunnable = self.test; + self.runTest(function(err){ + test = self.test; + + if (err) { + self.fail(test, err); + self.emit('test end', test); + return self.hookUp('afterEach', next); + } + + test.state = 'passed'; + self.emit('pass', test); + self.emit('test end', test); + self.hookUp('afterEach', next); + }); + }); + } + + this.next = next; + next(); +}; + +/** + * Run the given `suite` and invoke the + * callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runSuite = function(suite, fn){ + var total = this.grepTotal(suite) + , self = this + , i = 0; + + debug('run suite %s', suite.fullTitle()); + + if (!total) return fn(); + + this.emit('suite', this.suite = suite); + + function next(errSuite) { + if (errSuite) { + // current suite failed on a hook from errSuite + if (errSuite == suite) { + // if errSuite is current suite + // continue to the next sibling suite + return done(); + } else { + // errSuite is among the parents of current suite + // stop execution of errSuite and all sub-suites + return done(errSuite); + } + } + + if (self._abort) return done(); + + var curr = suite.suites[i++]; + if (!curr) return done(); + self.runSuite(curr, next); + } + + function done(errSuite) { + self.suite = suite; + self.hook('afterAll', function(){ + self.emit('suite end', suite); + fn(errSuite); + }); + } + + this.hook('beforeAll', function(err){ + if (err) return done(); + self.runTests(suite, next); + }); +}; + +/** + * Handle uncaught exceptions. + * + * @param {Error} err + * @api private + */ + +Runner.prototype.uncaught = function(err){ + debug('uncaught exception %s', err.message); + var runnable = this.currentRunnable; + if (!runnable || 'failed' == runnable.state) return; + runnable.clearTimeout(); + err.uncaught = true; + this.fail(runnable, err); + + // recover from test + if ('test' == runnable.type) { + this.emit('test end', runnable); + this.hookUp('afterEach', this.next); + return; + } + + // bail on hooks + this.emit('end'); +}; + +/** + * Run the root suite and invoke `fn(failures)` + * on completion. + * + * @param {Function} fn + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.run = function(fn){ + var self = this + , fn = fn || function(){}; + + function uncaught(err){ + self.uncaught(err); + } + + debug('start'); + + // callback + this.on('end', function(){ + debug('end'); + process.removeListener('uncaughtException', uncaught); + fn(self.failures); + }); + + // run suites + this.emit('start'); + this.runSuite(this.suite, function(){ + debug('finished running'); + self.emit('end'); + }); + + // uncaught exception + process.on('uncaughtException', uncaught); + + return this; +}; + +/** + * Cleanly abort execution + * + * @return {Runner} for chaining + * @api public + */ +Runner.prototype.abort = function(){ + debug('aborting'); + this._abort = true; +} + +/** + * Filter leaks with the given globals flagged as `ok`. + * + * @param {Array} ok + * @param {Array} globals + * @return {Array} + * @api private + */ + +function filterLeaks(ok, globals) { + return filter(globals, function(key){ + // Firefox and Chrome exposes iframes as index inside the window object + if (/^d+/.test(key)) return false; + + // in firefox + // if runner runs in an iframe, this iframe's window.getInterface method not init at first + // it is assigned in some seconds + if (global.navigator && /^getInterface/.test(key)) return false; + + // an iframe could be approached by window[iframeIndex] + // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak + if (global.navigator && /^\d+/.test(key)) return false; + + // Opera and IE expose global variables for HTML element IDs (issue #243) + if (/^mocha-/.test(key)) return false; + + var matched = filter(ok, function(ok){ + if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); + return key == ok; + }); + return matched.length == 0 && (!global.navigator || 'onerror' !== key); + }); +} + +/** + * Array of globals dependent on the environment. + * + * @return {Array} + * @api private + */ + + function extraGlobals() { + if (typeof(process) === 'object' && + typeof(process.version) === 'string') { + + var nodeVersion = process.version.split('.').reduce(function(a, v) { + return a << 8 | v; + }); + + // 'errno' was renamed to process._errno in v0.9.11. + + if (nodeVersion < 0x00090B) { + return ['errno']; + } + } + + return []; + } diff --git a/tests/mocha/lib/suite.js b/tests/mocha/lib/suite.js new file mode 100644 index 0000000000..d403a83f38 --- /dev/null +++ b/tests/mocha/lib/suite.js @@ -0,0 +1,320 @@ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter + , debug = require('debug')('mocha:suite') + , milliseconds = require('./ms') + , utils = require('./utils') + , Hook = require('./hook'); + +/** + * Expose `Suite`. + */ + +exports = module.exports = Suite; + +/** + * Create a new `Suite` with the given `title` + * and parent `Suite`. When a suite with the + * same title is already present, that suite + * is returned to provide nicer reporter + * and more flexible meta-testing. + * + * @param {Suite} parent + * @param {String} title + * @return {Suite} + * @api public + */ + +exports.create = function(parent, title){ + var suite = new Suite(title, parent.ctx); + suite.parent = parent; + if (parent.pending) suite.pending = true; + title = suite.fullTitle(); + parent.addSuite(suite); + return suite; +}; + +/** + * Initialize a new `Suite` with the given + * `title` and `ctx`. + * + * @param {String} title + * @param {Context} ctx + * @api private + */ + +function Suite(title, ctx) { + this.title = title; + this.ctx = ctx; + this.suites = []; + this.tests = []; + this.pending = false; + this._beforeEach = []; + this._beforeAll = []; + this._afterEach = []; + this._afterAll = []; + this.root = !title; + this._timeout = 2000; + this._slow = 75; + this._bail = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Suite.prototype.__proto__ = EventEmitter.prototype; + +/** + * Return a clone of this `Suite`. + * + * @return {Suite} + * @api private + */ + +Suite.prototype.clone = function(){ + var suite = new Suite(this.title); + debug('clone'); + suite.ctx = this.ctx; + suite.timeout(this.timeout()); + suite.slow(this.slow()); + suite.bail(this.bail()); + return suite; +}; + +/** + * Set timeout `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._timeout = parseInt(ms, 10); + return this; +}; + +/** + * Set slow `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.slow = function(ms){ + if (0 === arguments.length) return this._slow; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('slow %d', ms); + this._slow = ms; + return this; +}; + +/** + * Sets whether to bail after first error. + * + * @parma {Boolean} bail + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.bail = function(bail){ + if (0 == arguments.length) return this._bail; + debug('bail %s', bail); + this._bail = bail; + return this; +}; + +/** + * Run `fn(test[, done])` before running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeAll = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"before all" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._beforeAll.push(hook); + this.emit('beforeAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterAll = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"after all" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._afterAll.push(hook); + this.emit('afterAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` before each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeEach = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"before each" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._beforeEach.push(hook); + this.emit('beforeEach', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterEach = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"after each" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._afterEach.push(hook); + this.emit('afterEach', hook); + return this; +}; + +/** + * Add a test `suite`. + * + * @param {Suite} suite + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addSuite = function(suite){ + suite.parent = this; + suite.timeout(this.timeout()); + suite.slow(this.slow()); + suite.bail(this.bail()); + this.suites.push(suite); + this.emit('suite', suite); + return this; +}; + +/** + * Add a `test` to this suite. + * + * @param {Test} test + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addTest = function(test){ + test.parent = this; + test.timeout(this.timeout()); + test.slow(this.slow()); + test.ctx = this.ctx; + this.tests.push(test); + this.emit('test', test); + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Suite.prototype.fullTitle = function(){ + if (this.parent) { + var full = this.parent.fullTitle(); + if (full) return full + ' ' + this.title; + } + return this.title; +}; + +/** + * Return the total number of tests. + * + * @return {Number} + * @api public + */ + +Suite.prototype.total = function(){ + return utils.reduce(this.suites, function(sum, suite){ + return sum + suite.total(); + }, 0) + this.tests.length; +}; + +/** + * Iterates through each suite recursively to find + * all tests. Applies a function in the format + * `fn(test)`. + * + * @param {Function} fn + * @return {Suite} + * @api private + */ + +Suite.prototype.eachTest = function(fn){ + utils.forEach(this.tests, fn); + utils.forEach(this.suites, function(suite){ + suite.eachTest(fn); + }); + return this; +}; diff --git a/tests/mocha/lib/template.html b/tests/mocha/lib/template.html new file mode 100644 index 0000000000..0590d4aac2 --- /dev/null +++ b/tests/mocha/lib/template.html @@ -0,0 +1,18 @@ + + + + Mocha + + + + + +
+ + + + + + diff --git a/tests/mocha/lib/test.js b/tests/mocha/lib/test.js new file mode 100644 index 0000000000..11773e0cc9 --- /dev/null +++ b/tests/mocha/lib/test.js @@ -0,0 +1,32 @@ + +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Test`. + */ + +module.exports = Test; + +/** + * Initialize a new `Test` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Test(title, fn) { + Runnable.call(this, title, fn); + this.pending = !fn; + this.type = 'test'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +Test.prototype.__proto__ = Runnable.prototype; diff --git a/tests/mocha/lib/utils.js b/tests/mocha/lib/utils.js new file mode 100644 index 0000000000..37fd5d7e1b --- /dev/null +++ b/tests/mocha/lib/utils.js @@ -0,0 +1,299 @@ +/** + * Module dependencies. + */ + +var fs = require('fs') + , path = require('path') + , join = path.join + , debug = require('debug')('mocha:watch'); + +/** + * Ignored directories. + */ + +var ignore = ['node_modules', '.git']; + +/** + * Escape special characters in the given string of html. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html){ + return String(html) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>'); +}; + +/** + * Array#forEach (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.forEach = function(arr, fn, scope){ + for (var i = 0, l = arr.length; i < l; i++) + fn.call(scope, arr[i], i); +}; + +/** + * Array#map (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.map = function(arr, fn, scope){ + var result = []; + for (var i = 0, l = arr.length; i < l; i++) + result.push(fn.call(scope, arr[i], i)); + return result; +}; + +/** + * Array#indexOf (<=IE8) + * + * @parma {Array} arr + * @param {Object} obj to find index of + * @param {Number} start + * @api private + */ + +exports.indexOf = function(arr, obj, start){ + for (var i = start || 0, l = arr.length; i < l; i++) { + if (arr[i] === obj) + return i; + } + return -1; +}; + +/** + * Array#reduce (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} initial value + * @api private + */ + +exports.reduce = function(arr, fn, val){ + var rval = val; + + for (var i = 0, l = arr.length; i < l; i++) { + rval = fn(rval, arr[i], i, arr); + } + + return rval; +}; + +/** + * Array#filter (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @api private + */ + +exports.filter = function(arr, fn){ + var ret = []; + + for (var i = 0, l = arr.length; i < l; i++) { + var val = arr[i]; + if (fn(val, i, arr)) ret.push(val); + } + + return ret; +}; + +/** + * Object.keys (<=IE8) + * + * @param {Object} obj + * @return {Array} keys + * @api private + */ + +exports.keys = Object.keys || function(obj) { + var keys = [] + , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 + + for (var key in obj) { + if (has.call(obj, key)) { + keys.push(key); + } + } + + return keys; +}; + +/** + * Watch the given `files` for changes + * and invoke `fn(file)` on modification. + * + * @param {Array} files + * @param {Function} fn + * @api private + */ + +exports.watch = function(files, fn){ + var options = { interval: 100 }; + files.forEach(function(file){ + debug('file %s', file); + fs.watchFile(file, options, function(curr, prev){ + if (prev.mtime < curr.mtime) fn(file); + }); + }); +}; + +/** + * Ignored files. + */ + +function ignored(path){ + return !~ignore.indexOf(path); +} + +/** + * Lookup files in the given `dir`. + * + * @return {Array} + * @api private + */ + +exports.files = function(dir, ret){ + ret = ret || []; + + fs.readdirSync(dir) + .filter(ignored) + .forEach(function(path){ + path = join(dir, path); + if (fs.statSync(path).isDirectory()) { + exports.files(path, ret); + } else if (path.match(/\.(js|coffee|litcoffee|coffee.md)$/)) { + ret.push(path); + } + }); + + return ret; +}; + +/** + * Compute a slug from the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.slug = function(str){ + return str + .toLowerCase() + .replace(/ +/g, '-') + .replace(/[^-\w]/g, ''); +}; + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +exports.clean = function(str) { + str = str + .replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '') + .replace(/^function *\(.*\) *{/, '') + .replace(/\s+\}$/, ''); + + var spaces = str.match(/^\n?( *)/)[1].length + , tabs = str.match(/^\n?(\t*)/)[1].length + , re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm'); + + str = str.replace(re, ''); + + return exports.trim(str); +}; + +/** + * Escape regular expression characters in `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.escapeRegexp = function(str){ + return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); +}; + +/** + * Trim the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.trim = function(str){ + return str.replace(/^\s+|\s+$/g, ''); +}; + +/** + * Parse the given `qs`. + * + * @param {String} qs + * @return {Object} + * @api private + */ + +exports.parseQuery = function(qs){ + return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){ + var i = pair.indexOf('=') + , key = pair.slice(0, i) + , val = pair.slice(++i); + + obj[key] = decodeURIComponent(val); + return obj; + }, {}); +}; + +/** + * Highlight the given string of `js`. + * + * @param {String} js + * @return {String} + * @api private + */ + +function highlight(js) { + return js + .replace(//g, '>') + .replace(/\/\/(.*)/gm, '//$1') + .replace(/('.*?')/gm, '$1') + .replace(/(\d+\.\d+)/gm, '$1') + .replace(/(\d+)/gm, '$1') + .replace(/\bnew *(\w+)/gm, 'new $1') + .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') +} + +/** + * Highlight the contents of tag `name`. + * + * @param {String} name + * @api private + */ + +exports.highlightTags = function(name) { + var code = document.getElementsByTagName(name); + for (var i = 0, len = code.length; i < len; ++i) { + code[i].innerHTML = highlight(code[i].innerHTML); + } +}; diff --git a/tests/mocha/mocha.css b/tests/mocha/mocha.css new file mode 100644 index 0000000000..42b9798fa4 --- /dev/null +++ b/tests/mocha/mocha.css @@ -0,0 +1,270 @@ +@charset "utf-8"; + +body { + margin:0; +} + +#mocha { + font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; + margin: 60px 50px; +} + +#mocha ul, +#mocha li { + margin: 0; + padding: 0; +} + +#mocha ul { + list-style: none; +} + +#mocha h1, +#mocha h2 { + margin: 0; +} + +#mocha h1 { + margin-top: 15px; + font-size: 1em; + font-weight: 200; +} + +#mocha h1 a { + text-decoration: none; + color: inherit; +} + +#mocha h1 a:hover { + text-decoration: underline; +} + +#mocha .suite .suite h1 { + margin-top: 0; + font-size: .8em; +} + +#mocha .hidden { + display: none; +} + +#mocha h2 { + font-size: 12px; + font-weight: normal; + cursor: pointer; +} + +#mocha .suite { + margin-left: 15px; +} + +#mocha .test { + margin-left: 15px; + overflow: hidden; +} + +#mocha .test.pending:hover h2::after { + content: '(pending)'; + font-family: arial, sans-serif; +} + +#mocha .test.pass.medium .duration { + background: #c09853; +} + +#mocha .test.pass.slow .duration { + background: #b94a48; +} + +#mocha .test.pass::before { + content: '✓'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; + color: #00d6b2; +} + +#mocha .test.pass .duration { + font-size: 9px; + margin-left: 5px; + padding: 2px 5px; + color: #fff; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -ms-border-radius: 5px; + -o-border-radius: 5px; + border-radius: 5px; +} + +#mocha .test.pass.fast .duration { + display: none; +} + +#mocha .test.pending { + color: #0b97c4; +} + +#mocha .test.pending::before { + content: '◦'; + color: #0b97c4; +} + +#mocha .test.fail { + color: #c00; +} + +#mocha .test.fail pre { + color: black; +} + +#mocha .test.fail::before { + content: '✖'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; + color: #c00; +} + +#mocha .test pre.error { + color: #c00; + max-height: 300px; + overflow: auto; +} + +/** + * (1): approximate for browsers not supporting calc + * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) + * ^^ seriously + */ +#mocha .test pre { + display: block; + float: left; + clear: left; + font: 12px/1.5 monaco, monospace; + margin: 5px; + padding: 15px; + border: 1px solid #eee; + max-width: 85%; /*(1)*/ + max-width: calc(100% - 42px); /*(2)*/ + word-wrap: break-word; + border-bottom-color: #ddd; + -webkit-border-radius: 3px; + -webkit-box-shadow: 0 1px 3px #eee; + -moz-border-radius: 3px; + -moz-box-shadow: 0 1px 3px #eee; + border-radius: 3px; +} + +#mocha .test h2 { + position: relative; +} + +#mocha .test a.replay { + position: absolute; + top: 3px; + right: 0; + text-decoration: none; + vertical-align: middle; + display: block; + width: 15px; + height: 15px; + line-height: 15px; + text-align: center; + background: #eee; + font-size: 15px; + -moz-border-radius: 15px; + border-radius: 15px; + -webkit-transition: opacity 200ms; + -moz-transition: opacity 200ms; + transition: opacity 200ms; + opacity: 0.3; + color: #888; +} + +#mocha .test:hover a.replay { + opacity: 1; +} + +#mocha-report.pass .test.fail { + display: none; +} + +#mocha-report.fail .test.pass { + display: none; +} + +#mocha-report.pending .test.pass, +#mocha-report.pending .test.fail { + display: none; +} +#mocha-report.pending .test.pass.pending { + display: block; +} + +#mocha-error { + color: #c00; + font-size: 1.5em; + font-weight: 100; + letter-spacing: 1px; +} + +#mocha-stats { + position: fixed; + top: 15px; + right: 10px; + font-size: 12px; + margin: 0; + color: #888; + z-index: 1; +} + +#mocha-stats .progress { + float: right; + padding-top: 0; +} + +#mocha-stats em { + color: black; +} + +#mocha-stats a { + text-decoration: none; + color: inherit; +} + +#mocha-stats a:hover { + border-bottom: 1px solid #eee; +} + +#mocha-stats li { + display: inline-block; + margin: 0 5px; + list-style: none; + padding-top: 11px; +} + +#mocha-stats canvas { + width: 40px; + height: 40px; +} + +#mocha code .comment { color: #ddd; } +#mocha code .init { color: #2f6fad; } +#mocha code .string { color: #5890ad; } +#mocha code .keyword { color: #8a6343; } +#mocha code .number { color: #2f6fad; } + +@media screen and (max-device-width: 480px) { + #mocha { + margin: 60px 0px; + } + + #mocha #stats { + position: absolute; + } +} diff --git a/tests/mocha/mocha.js b/tests/mocha/mocha.js new file mode 100644 index 0000000000..6eb96ae6ff --- /dev/null +++ b/tests/mocha/mocha.js @@ -0,0 +1,5848 @@ +;(function(global){;(function(){ + +// CommonJS require() + +function require(p){ + var path = require.resolve(p) + , mod = require.modules[path]; + if (!mod) throw new Error('failed to require "' + p + '"'); + if (!mod.exports) { + mod.exports = {}; + mod.call(mod.exports, mod, mod.exports, require.relative(path)); + } + return mod.exports; + } + +require.modules = {}; + +require.resolve = function (path){ + var orig = path + , reg = path + '.js' + , index = path + '/index.js'; + return require.modules[reg] && reg + || require.modules[index] && index + || orig; + }; + +require.register = function (path, fn){ + require.modules[path] = fn; + }; + +require.relative = function (parent) { + return function(p){ + if ('.' != p.charAt(0)) return require(p); + + var path = parent.split('/') + , segs = p.split('/'); + path.pop(); + + for (var i = 0; i < segs.length; i++) { + var seg = segs[i]; + if ('..' == seg) path.pop(); + else if ('.' != seg) path.push(seg); + } + + return require(path.join('/')); + }; + }; + + +require.register("browser/debug.js", function(module, exports, require){ + +module.exports = function(type){ + return function(){ + } +}; + +}); // module: browser/debug.js + +require.register("browser/diff.js", function(module, exports, require){ +/* See LICENSE file for terms of use */ + +/* + * Text diff implementation. + * + * This library supports the following APIS: + * JsDiff.diffChars: Character by character diff + * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace + * JsDiff.diffLines: Line based diff + * + * JsDiff.diffCss: Diff targeted at CSS content + * + * These methods are based on the implementation proposed in + * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 + */ +var JsDiff = (function() { + /*jshint maxparams: 5*/ + function clonePath(path) { + return { newPos: path.newPos, components: path.components.slice(0) }; + } + function removeEmpty(array) { + var ret = []; + for (var i = 0; i < array.length; i++) { + if (array[i]) { + ret.push(array[i]); + } + } + return ret; + } + function escapeHTML(s) { + var n = s; + n = n.replace(/&/g, '&'); + n = n.replace(//g, '>'); + n = n.replace(/"/g, '"'); + + return n; + } + + var Diff = function(ignoreWhitespace) { + this.ignoreWhitespace = ignoreWhitespace; + }; + Diff.prototype = { + diff: function(oldString, newString) { + // Handle the identity case (this is due to unrolling editLength == 0 + if (newString === oldString) { + return [{ value: newString }]; + } + if (!newString) { + return [{ value: oldString, removed: true }]; + } + if (!oldString) { + return [{ value: newString, added: true }]; + } + + newString = this.tokenize(newString); + oldString = this.tokenize(oldString); + + var newLen = newString.length, oldLen = oldString.length; + var maxEditLength = newLen + oldLen; + var bestPath = [{ newPos: -1, components: [] }]; + + // Seed editLength = 0 + var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); + if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) { + return bestPath[0].components; + } + + for (var editLength = 1; editLength <= maxEditLength; editLength++) { + for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) { + var basePath; + var addPath = bestPath[diagonalPath-1], + removePath = bestPath[diagonalPath+1]; + oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; + if (addPath) { + // No one else is going to attempt to use this value, clear it + bestPath[diagonalPath-1] = undefined; + } + + var canAdd = addPath && addPath.newPos+1 < newLen; + var canRemove = removePath && 0 <= oldPos && oldPos < oldLen; + if (!canAdd && !canRemove) { + bestPath[diagonalPath] = undefined; + continue; + } + + // Select the diagonal that we want to branch from. We select the prior + // path whose position in the new string is the farthest from the origin + // and does not pass the bounds of the diff graph + if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { + basePath = clonePath(removePath); + this.pushComponent(basePath.components, oldString[oldPos], undefined, true); + } else { + basePath = clonePath(addPath); + basePath.newPos++; + this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined); + } + + var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath); + + if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) { + return basePath.components; + } else { + bestPath[diagonalPath] = basePath; + } + } + } + }, + + pushComponent: function(components, value, added, removed) { + var last = components[components.length-1]; + if (last && last.added === added && last.removed === removed) { + // We need to clone here as the component clone operation is just + // as shallow array clone + components[components.length-1] = + {value: this.join(last.value, value), added: added, removed: removed }; + } else { + components.push({value: value, added: added, removed: removed }); + } + }, + extractCommon: function(basePath, newString, oldString, diagonalPath) { + var newLen = newString.length, + oldLen = oldString.length, + newPos = basePath.newPos, + oldPos = newPos - diagonalPath; + while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) { + newPos++; + oldPos++; + + this.pushComponent(basePath.components, newString[newPos], undefined, undefined); + } + basePath.newPos = newPos; + return oldPos; + }, + + equals: function(left, right) { + var reWhitespace = /\S/; + if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) { + return true; + } else { + return left === right; + } + }, + join: function(left, right) { + return left + right; + }, + tokenize: function(value) { + return value; + } + }; + + var CharDiff = new Diff(); + + var WordDiff = new Diff(true); + var WordWithSpaceDiff = new Diff(); + WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { + return removeEmpty(value.split(/(\s+|\b)/)); + }; + + var CssDiff = new Diff(true); + CssDiff.tokenize = function(value) { + return removeEmpty(value.split(/([{}:;,]|\s+)/)); + }; + + var LineDiff = new Diff(); + LineDiff.tokenize = function(value) { + return value.split(/^/m); + }; + + return { + Diff: Diff, + + diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); }, + diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); }, + diffWordsWithSpace: function(oldStr, newStr) { return WordWithSpaceDiff.diff(oldStr, newStr); }, + diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); }, + + diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); }, + + createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { + var ret = []; + + ret.push('Index: ' + fileName); + ret.push('==================================================================='); + ret.push('--- ' + fileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); + ret.push('+++ ' + fileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); + + var diff = LineDiff.diff(oldStr, newStr); + if (!diff[diff.length-1].value) { + diff.pop(); // Remove trailing newline add + } + diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier + + function contextLines(lines) { + return lines.map(function(entry) { return ' ' + entry; }); + } + function eofNL(curRange, i, current) { + var last = diff[diff.length-2], + isLast = i === diff.length-2, + isLastOfType = i === diff.length-3 && (current.added !== last.added || current.removed !== last.removed); + + // Figure out if this is the last line for the given file and missing NL + if (!/\n$/.test(current.value) && (isLast || isLastOfType)) { + curRange.push('\\ No newline at end of file'); + } + } + + var oldRangeStart = 0, newRangeStart = 0, curRange = [], + oldLine = 1, newLine = 1; + for (var i = 0; i < diff.length; i++) { + var current = diff[i], + lines = current.lines || current.value.replace(/\n$/, '').split('\n'); + current.lines = lines; + + if (current.added || current.removed) { + if (!oldRangeStart) { + var prev = diff[i-1]; + oldRangeStart = oldLine; + newRangeStart = newLine; + + if (prev) { + curRange = contextLines(prev.lines.slice(-4)); + oldRangeStart -= curRange.length; + newRangeStart -= curRange.length; + } + } + curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?'+':'-') + entry; })); + eofNL(curRange, i, current); + + if (current.added) { + newLine += lines.length; + } else { + oldLine += lines.length; + } + } else { + if (oldRangeStart) { + // Close out any changes that have been output (or join overlapping) + if (lines.length <= 8 && i < diff.length-2) { + // Overlapping + curRange.push.apply(curRange, contextLines(lines)); + } else { + // end the range and output + var contextSize = Math.min(lines.length, 4); + ret.push( + '@@ -' + oldRangeStart + ',' + (oldLine-oldRangeStart+contextSize) + + ' +' + newRangeStart + ',' + (newLine-newRangeStart+contextSize) + + ' @@'); + ret.push.apply(ret, curRange); + ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); + if (lines.length <= 4) { + eofNL(ret, i, current); + } + + oldRangeStart = 0; newRangeStart = 0; curRange = []; + } + } + oldLine += lines.length; + newLine += lines.length; + } + } + + return ret.join('\n') + '\n'; + }, + + applyPatch: function(oldStr, uniDiff) { + var diffstr = uniDiff.split('\n'); + var diff = []; + var remEOFNL = false, + addEOFNL = false; + + for (var i = (diffstr[0][0]==='I'?4:0); i < diffstr.length; i++) { + if(diffstr[i][0] === '@') { + var meh = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); + diff.unshift({ + start:meh[3], + oldlength:meh[2], + oldlines:[], + newlength:meh[4], + newlines:[] + }); + } else if(diffstr[i][0] === '+') { + diff[0].newlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === '-') { + diff[0].oldlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === ' ') { + diff[0].newlines.push(diffstr[i].substr(1)); + diff[0].oldlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === '\\') { + if (diffstr[i-1][0] === '+') { + remEOFNL = true; + } else if(diffstr[i-1][0] === '-') { + addEOFNL = true; + } + } + } + + var str = oldStr.split('\n'); + for (var i = diff.length - 1; i >= 0; i--) { + var d = diff[i]; + for (var j = 0; j < d.oldlength; j++) { + if(str[d.start-1+j] !== d.oldlines[j]) { + return false; + } + } + Array.prototype.splice.apply(str,[d.start-1,+d.oldlength].concat(d.newlines)); + } + + if (remEOFNL) { + while (!str[str.length-1]) { + str.pop(); + } + } else if (addEOFNL) { + str.push(''); + } + return str.join('\n'); + }, + + convertChangesToXML: function(changes){ + var ret = []; + for ( var i = 0; i < changes.length; i++) { + var change = changes[i]; + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + + ret.push(escapeHTML(change.value)); + + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + } + return ret.join(''); + }, + + // See: http://code.google.com/p/google-diff-match-patch/wiki/API + convertChangesToDMP: function(changes){ + var ret = [], change; + for ( var i = 0; i < changes.length; i++) { + change = changes[i]; + ret.push([(change.added ? 1 : change.removed ? -1 : 0), change.value]); + } + return ret; + } + }; +})(); + +if (typeof module !== 'undefined') { + module.exports = JsDiff; +} + +}); // module: browser/diff.js + +require.register("browser/events.js", function(module, exports, require){ + +/** + * Module exports. + */ + +exports.EventEmitter = EventEmitter; + +/** + * Check if `obj` is an array. + */ + +function isArray(obj) { + return '[object Array]' == {}.toString.call(obj); +} + +/** + * Event emitter constructor. + * + * @api public + */ + +function EventEmitter(){}; + +/** + * Adds a listener. + * + * @api public + */ + +EventEmitter.prototype.on = function (name, fn) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = fn; + } else if (isArray(this.$events[name])) { + this.$events[name].push(fn); + } else { + this.$events[name] = [this.$events[name], fn]; + } + + return this; +}; + +EventEmitter.prototype.addListener = EventEmitter.prototype.on; + +/** + * Adds a volatile listener. + * + * @api public + */ + +EventEmitter.prototype.once = function (name, fn) { + var self = this; + + function on () { + self.removeListener(name, on); + fn.apply(this, arguments); + }; + + on.listener = fn; + this.on(name, on); + + return this; +}; + +/** + * Removes a listener. + * + * @api public + */ + +EventEmitter.prototype.removeListener = function (name, fn) { + if (this.$events && this.$events[name]) { + var list = this.$events[name]; + + if (isArray(list)) { + var pos = -1; + + for (var i = 0, l = list.length; i < l; i++) { + if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { + pos = i; + break; + } + } + + if (pos < 0) { + return this; + } + + list.splice(pos, 1); + + if (!list.length) { + delete this.$events[name]; + } + } else if (list === fn || (list.listener && list.listener === fn)) { + delete this.$events[name]; + } + } + + return this; +}; + +/** + * Removes all listeners for an event. + * + * @api public + */ + +EventEmitter.prototype.removeAllListeners = function (name) { + if (name === undefined) { + this.$events = {}; + return this; + } + + if (this.$events && this.$events[name]) { + this.$events[name] = null; + } + + return this; +}; + +/** + * Gets all listeners for a certain event. + * + * @api public + */ + +EventEmitter.prototype.listeners = function (name) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = []; + } + + if (!isArray(this.$events[name])) { + this.$events[name] = [this.$events[name]]; + } + + return this.$events[name]; +}; + +/** + * Emits an event. + * + * @api public + */ + +EventEmitter.prototype.emit = function (name) { + if (!this.$events) { + return false; + } + + var handler = this.$events[name]; + + if (!handler) { + return false; + } + + var args = [].slice.call(arguments, 1); + + if ('function' == typeof handler) { + handler.apply(this, args); + } else if (isArray(handler)) { + var listeners = handler.slice(); + + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + } else { + return false; + } + + return true; +}; +}); // module: browser/events.js + +require.register("browser/fs.js", function(module, exports, require){ + +}); // module: browser/fs.js + +require.register("browser/path.js", function(module, exports, require){ + +}); // module: browser/path.js + +require.register("browser/progress.js", function(module, exports, require){ +/** + * Expose `Progress`. + */ + +module.exports = Progress; + +/** + * Initialize a new `Progress` indicator. + */ + +function Progress() { + this.percent = 0; + this.size(0); + this.fontSize(11); + this.font('helvetica, arial, sans-serif'); +} + +/** + * Set progress size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.size = function(n){ + this._size = n; + return this; +}; + +/** + * Set text to `str`. + * + * @param {String} str + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.text = function(str){ + this._text = str; + return this; +}; + +/** + * Set font size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.fontSize = function(n){ + this._fontSize = n; + return this; +}; + +/** + * Set font `family`. + * + * @param {String} family + * @return {Progress} for chaining + */ + +Progress.prototype.font = function(family){ + this._font = family; + return this; +}; + +/** + * Update percentage to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + */ + +Progress.prototype.update = function(n){ + this.percent = n; + return this; +}; + +/** + * Draw on `ctx`. + * + * @param {CanvasRenderingContext2d} ctx + * @return {Progress} for chaining + */ + +Progress.prototype.draw = function(ctx){ + try { + var percent = Math.min(this.percent, 100) + , size = this._size + , half = size / 2 + , x = half + , y = half + , rad = half - 1 + , fontSize = this._fontSize; + + ctx.font = fontSize + 'px ' + this._font; + + var angle = Math.PI * 2 * (percent / 100); + ctx.clearRect(0, 0, size, size); + + // outer circle + ctx.strokeStyle = '#9f9f9f'; + ctx.beginPath(); + ctx.arc(x, y, rad, 0, angle, false); + ctx.stroke(); + + // inner circle + ctx.strokeStyle = '#eee'; + ctx.beginPath(); + ctx.arc(x, y, rad - 1, 0, angle, true); + ctx.stroke(); + + // text + var text = this._text || (percent | 0) + '%' + , w = ctx.measureText(text).width; + + ctx.fillText( + text + , x - w / 2 + 1 + , y + fontSize / 2 - 1); + } catch (ex) {} //don't fail if we can't render progress + return this; +}; + +}); // module: browser/progress.js + +require.register("browser/tty.js", function(module, exports, require){ + +exports.isatty = function(){ + return true; +}; + +exports.getWindowSize = function(){ + if ('innerHeight' in global) { + return [global.innerHeight, global.innerWidth]; + } else { + // In a Web Worker, the DOM Window is not available. + return [640, 480]; + } +}; + +}); // module: browser/tty.js + +require.register("context.js", function(module, exports, require){ + +/** + * Expose `Context`. + */ + +module.exports = Context; + +/** + * Initialize a new `Context`. + * + * @api private + */ + +function Context(){} + +/** + * Set or get the context `Runnable` to `runnable`. + * + * @param {Runnable} runnable + * @return {Context} + * @api private + */ + +Context.prototype.runnable = function(runnable){ + if (0 == arguments.length) return this._runnable; + this.test = this._runnable = runnable; + return this; +}; + +/** + * Set test timeout `ms`. + * + * @param {Number} ms + * @return {Context} self + * @api private + */ + +Context.prototype.timeout = function(ms){ + this.runnable().timeout(ms); + return this; +}; + +/** + * Set test slowness threshold `ms`. + * + * @param {Number} ms + * @return {Context} self + * @api private + */ + +Context.prototype.slow = function(ms){ + this.runnable().slow(ms); + return this; +}; + +/** + * Inspect the context void of `._runnable`. + * + * @return {String} + * @api private + */ + +Context.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + if ('_runnable' == key) return; + if ('test' == key) return; + return val; + }, 2); +}; + +}); // module: context.js + +require.register("hook.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Hook`. + */ + +module.exports = Hook; + +/** + * Initialize a new `Hook` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Hook(title, fn) { + Runnable.call(this, title, fn); + this.type = 'hook'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +function F(){}; +F.prototype = Runnable.prototype; +Hook.prototype = new F; +Hook.prototype.constructor = Hook; + + +/** + * Get or set the test `err`. + * + * @param {Error} err + * @return {Error} + * @api public + */ + +Hook.prototype.error = function(err){ + if (0 == arguments.length) { + var err = this._error; + this._error = null; + return err; + } + + this._error = err; +}; + +}); // module: hook.js + +require.register("interfaces/bdd.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test') + , utils = require('../utils'); + +/** + * BDD-style interface: + * + * describe('Array', function(){ + * describe('#indexOf()', function(){ + * it('should return -1 when not present', function(){ + * + * }); + * + * it('should return the index when present', function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context, file, mocha){ + + /** + * Execute before running tests. + */ + + context.before = function(name, fn){ + suites[0].beforeAll(name, fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(name, fn){ + suites[0].afterAll(name, fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(name, fn){ + suites[0].beforeEach(name, fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(name, fn){ + suites[0].afterEach(name, fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.describe = context.context = function(title, fn){ + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + fn.call(suite); + suites.shift(); + return suite; + }; + + /** + * Pending describe. + */ + + context.xdescribe = + context.xcontext = + context.describe.skip = function(title, fn){ + var suite = Suite.create(suites[0], title); + suite.pending = true; + suites.unshift(suite); + fn.call(suite); + suites.shift(); + }; + + /** + * Exclusive suite. + */ + + context.describe.only = function(title, fn){ + var suite = context.describe(title, fn); + mocha.grep(suite.fullTitle()); + return suite; + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.it = context.specify = function(title, fn){ + var suite = suites[0]; + if (suite.pending) var fn = null; + var test = new Test(title, fn); + suite.addTest(test); + return test; + }; + + /** + * Exclusive test-case. + */ + + context.it.only = function(title, fn){ + var test = context.it(title, fn); + var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; + mocha.grep(new RegExp(reString)); + return test; + }; + + /** + * Pending test case. + */ + + context.xit = + context.xspecify = + context.it.skip = function(title){ + context.it(title); + }; + }); +}; + +}); // module: interfaces/bdd.js + +require.register("interfaces/exports.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * TDD-style interface: + * + * exports.Array = { + * '#indexOf()': { + * 'should return -1 when the value is not present': function(){ + * + * }, + * + * 'should return the correct index when the value is present': function(){ + * + * } + * } + * }; + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('require', visit); + + function visit(obj) { + var suite; + for (var key in obj) { + if ('function' == typeof obj[key]) { + var fn = obj[key]; + switch (key) { + case 'before': + suites[0].beforeAll(fn); + break; + case 'after': + suites[0].afterAll(fn); + break; + case 'beforeEach': + suites[0].beforeEach(fn); + break; + case 'afterEach': + suites[0].afterEach(fn); + break; + default: + suites[0].addTest(new Test(key, fn)); + } + } else { + var suite = Suite.create(suites[0], key); + suites.unshift(suite); + visit(obj[key]); + suites.shift(); + } + } + } +}; + +}); // module: interfaces/exports.js + +require.register("interfaces/index.js", function(module, exports, require){ + +exports.bdd = require('./bdd'); +exports.tdd = require('./tdd'); +exports.qunit = require('./qunit'); +exports.exports = require('./exports'); + +}); // module: interfaces/index.js + +require.register("interfaces/qunit.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test') + , utils = require('../utils'); + +/** + * QUnit-style interface: + * + * suite('Array'); + * + * test('#length', function(){ + * var arr = [1,2,3]; + * ok(arr.length == 3); + * }); + * + * test('#indexOf()', function(){ + * var arr = [1,2,3]; + * ok(arr.indexOf(1) == 0); + * ok(arr.indexOf(2) == 1); + * ok(arr.indexOf(3) == 2); + * }); + * + * suite('String'); + * + * test('#length', function(){ + * ok('foo'.length == 3); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context, file, mocha){ + + /** + * Execute before running tests. + */ + + context.before = function(name, fn){ + suites[0].beforeAll(name, fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(name, fn){ + suites[0].afterAll(name, fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(name, fn){ + suites[0].beforeEach(name, fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(name, fn){ + suites[0].afterEach(name, fn); + }; + + /** + * Describe a "suite" with the given `title`. + */ + + context.suite = function(title){ + if (suites.length > 1) suites.shift(); + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + return suite; + }; + + /** + * Exclusive test-case. + */ + + context.suite.only = function(title, fn){ + var suite = context.suite(title, fn); + mocha.grep(suite.fullTitle()); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + var test = new Test(title, fn); + suites[0].addTest(test); + return test; + }; + + /** + * Exclusive test-case. + */ + + context.test.only = function(title, fn){ + var test = context.test(title, fn); + var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; + mocha.grep(new RegExp(reString)); + }; + + /** + * Pending test case. + */ + + context.test.skip = function(title){ + context.test(title); + }; + }); +}; + +}); // module: interfaces/qunit.js + +require.register("interfaces/tdd.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test') + , utils = require('../utils');; + +/** + * TDD-style interface: + * + * suite('Array', function(){ + * suite('#indexOf()', function(){ + * suiteSetup(function(){ + * + * }); + * + * test('should return -1 when not present', function(){ + * + * }); + * + * test('should return the index when present', function(){ + * + * }); + * + * suiteTeardown(function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context, file, mocha){ + + /** + * Execute before each test case. + */ + + context.setup = function(name, fn){ + suites[0].beforeEach(name, fn); + }; + + /** + * Execute after each test case. + */ + + context.teardown = function(name, fn){ + suites[0].afterEach(name, fn); + }; + + /** + * Execute before the suite. + */ + + context.suiteSetup = function(name, fn){ + suites[0].beforeAll(name, fn); + }; + + /** + * Execute after the suite. + */ + + context.suiteTeardown = function(name, fn){ + suites[0].afterAll(name, fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.suite = function(title, fn){ + var suite = Suite.create(suites[0], title); + suites.unshift(suite); + fn.call(suite); + suites.shift(); + return suite; + }; + + /** + * Pending suite. + */ + context.suite.skip = function(title, fn) { + var suite = Suite.create(suites[0], title); + suite.pending = true; + suites.unshift(suite); + fn.call(suite); + suites.shift(); + }; + + /** + * Exclusive test-case. + */ + + context.suite.only = function(title, fn){ + var suite = context.suite(title, fn); + mocha.grep(suite.fullTitle()); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + var suite = suites[0]; + if (suite.pending) var fn = null; + var test = new Test(title, fn); + suite.addTest(test); + return test; + }; + + /** + * Exclusive test-case. + */ + + context.test.only = function(title, fn){ + var test = context.test(title, fn); + var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; + mocha.grep(new RegExp(reString)); + }; + + /** + * Pending test case. + */ + + context.test.skip = function(title){ + context.test(title); + }; + }); +}; + +}); // module: interfaces/tdd.js + +require.register("mocha.js", function(module, exports, require){ +/*! + * mocha + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var path = require('browser/path') + , utils = require('./utils'); + +/** + * Expose `Mocha`. + */ + +exports = module.exports = Mocha; + +/** + * Expose internals. + */ + +exports.utils = utils; +exports.interfaces = require('./interfaces'); +exports.reporters = require('./reporters'); +exports.Runnable = require('./runnable'); +exports.Context = require('./context'); +exports.Runner = require('./runner'); +exports.Suite = require('./suite'); +exports.Hook = require('./hook'); +exports.Test = require('./test'); + +/** + * Return image `name` path. + * + * @param {String} name + * @return {String} + * @api private + */ + +function image(name) { + return __dirname + '/../images/' + name + '.png'; +} + +/** + * Setup mocha with `options`. + * + * Options: + * + * - `ui` name "bdd", "tdd", "exports" etc + * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` + * - `globals` array of accepted globals + * - `timeout` timeout in milliseconds + * - `bail` bail on the first test failure + * - `slow` milliseconds to wait before considering a test slow + * - `ignoreLeaks` ignore global leaks + * - `grep` string or regexp to filter tests with + * + * @param {Object} options + * @api public + */ + +function Mocha(options) { + options = options || {}; + this.files = []; + this.options = options; + this.grep(options.grep); + this.suite = new exports.Suite('', new exports.Context); + this.ui(options.ui); + this.bail(options.bail); + this.reporter(options.reporter); + if (null != options.timeout) this.timeout(options.timeout); + this.useColors(options.useColors) + if (options.slow) this.slow(options.slow); + + this.suite.on('pre-require', function (context) { + exports.afterEach = context.afterEach || context.teardown; + exports.after = context.after || context.suiteTeardown; + exports.beforeEach = context.beforeEach || context.setup; + exports.before = context.before || context.suiteSetup; + exports.describe = context.describe || context.suite; + exports.it = context.it || context.test; + exports.setup = context.setup || context.beforeEach; + exports.suiteSetup = context.suiteSetup || context.before; + exports.suiteTeardown = context.suiteTeardown || context.after; + exports.suite = context.suite || context.describe; + exports.teardown = context.teardown || context.afterEach; + exports.test = context.test || context.it; + }); +} + +/** + * Enable or disable bailing on the first failure. + * + * @param {Boolean} [bail] + * @api public + */ + +Mocha.prototype.bail = function(bail){ + if (0 == arguments.length) bail = true; + this.suite.bail(bail); + return this; +}; + +/** + * Add test `file`. + * + * @param {String} file + * @api public + */ + +Mocha.prototype.addFile = function(file){ + this.files.push(file); + return this; +}; + +/** + * Set reporter to `reporter`, defaults to "dot". + * + * @param {String|Function} reporter name or constructor + * @api public + */ + +Mocha.prototype.reporter = function(reporter){ + if ('function' == typeof reporter) { + this._reporter = reporter; + } else { + reporter = reporter || 'dot'; + var _reporter; + try { _reporter = require('./reporters/' + reporter); } catch (err) {}; + if (!_reporter) try { _reporter = require(reporter); } catch (err) {}; + if (!_reporter && reporter === 'teamcity') + console.warn('The Teamcity reporter was moved to a package named ' + + 'mocha-teamcity-reporter ' + + '(https://npmjs.org/package/mocha-teamcity-reporter).'); + if (!_reporter) throw new Error('invalid reporter "' + reporter + '"'); + this._reporter = _reporter; + } + return this; +}; + +/** + * Set test UI `name`, defaults to "bdd". + * + * @param {String} bdd + * @api public + */ + +Mocha.prototype.ui = function(name){ + name = name || 'bdd'; + this._ui = exports.interfaces[name]; + if (!this._ui) try { this._ui = require(name); } catch (err) {}; + if (!this._ui) throw new Error('invalid interface "' + name + '"'); + this._ui = this._ui(this.suite); + return this; +}; + +/** + * Load registered files. + * + * @api private + */ + +Mocha.prototype.loadFiles = function(fn){ + var self = this; + var suite = this.suite; + var pending = this.files.length; + this.files.forEach(function(file){ + file = path.resolve(file); + suite.emit('pre-require', global, file, self); + suite.emit('require', require(file), file, self); + suite.emit('post-require', global, file, self); + --pending || (fn && fn()); + }); +}; + +/** + * Enable growl support. + * + * @api private + */ + +Mocha.prototype._growl = function(runner, reporter) { + var notify = require('growl'); + + runner.on('end', function(){ + var stats = reporter.stats; + if (stats.failures) { + var msg = stats.failures + ' of ' + runner.total + ' tests failed'; + notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); + } else { + notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { + name: 'mocha' + , title: 'Passed' + , image: image('ok') + }); + } + }); +}; + +/** + * Add regexp to grep, if `re` is a string it is escaped. + * + * @param {RegExp|String} re + * @return {Mocha} + * @api public + */ + +Mocha.prototype.grep = function(re){ + this.options.grep = 'string' == typeof re + ? new RegExp(utils.escapeRegexp(re)) + : re; + return this; +}; + +/** + * Invert `.grep()` matches. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.invert = function(){ + this.options.invert = true; + return this; +}; + +/** + * Ignore global leaks. + * + * @param {Boolean} ignore + * @return {Mocha} + * @api public + */ + +Mocha.prototype.ignoreLeaks = function(ignore){ + this.options.ignoreLeaks = !!ignore; + return this; +}; + +/** + * Enable global leak checking. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.checkLeaks = function(){ + this.options.ignoreLeaks = false; + return this; +}; + +/** + * Enable growl support. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.growl = function(){ + this.options.growl = true; + return this; +}; + +/** + * Ignore `globals` array or string. + * + * @param {Array|String} globals + * @return {Mocha} + * @api public + */ + +Mocha.prototype.globals = function(globals){ + this.options.globals = (this.options.globals || []).concat(globals); + return this; +}; + +/** + * Emit color output. + * + * @param {Boolean} colors + * @return {Mocha} + * @api public + */ + +Mocha.prototype.useColors = function(colors){ + this.options.useColors = arguments.length && colors != undefined + ? colors + : true; + return this; +}; + +/** + * Use inline diffs rather than +/-. + * + * @param {Boolean} inlineDiffs + * @return {Mocha} + * @api public + */ + +Mocha.prototype.useInlineDiffs = function(inlineDiffs) { + this.options.useInlineDiffs = arguments.length && inlineDiffs != undefined + ? inlineDiffs + : false; + return this; +}; + +/** + * Set the timeout in milliseconds. + * + * @param {Number} timeout + * @return {Mocha} + * @api public + */ + +Mocha.prototype.timeout = function(timeout){ + this.suite.timeout(timeout); + return this; +}; + +/** + * Set slowness threshold in milliseconds. + * + * @param {Number} slow + * @return {Mocha} + * @api public + */ + +Mocha.prototype.slow = function(slow){ + this.suite.slow(slow); + return this; +}; + +/** + * Makes all tests async (accepting a callback) + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.asyncOnly = function(){ + this.options.asyncOnly = true; + return this; +}; + +/** + * Run tests and invoke `fn()` when complete. + * + * @param {Function} fn + * @return {Runner} + * @api public + */ + +Mocha.prototype.run = function(fn){ + if (this.files.length) this.loadFiles(); + var suite = this.suite; + var options = this.options; + options.files = this.files; + var runner = new exports.Runner(suite); + var reporter = new this._reporter(runner, options); + runner.ignoreLeaks = false !== options.ignoreLeaks; + runner.asyncOnly = options.asyncOnly; + if (options.grep) runner.grep(options.grep, options.invert); + if (options.globals) runner.globals(options.globals); + if (options.growl) this._growl(runner, reporter); + exports.reporters.Base.useColors = options.useColors; + exports.reporters.Base.inlineDiffs = options.useInlineDiffs; + return runner.run(fn); +}; + +}); // module: mocha.js + +require.register("ms.js", function(module, exports, require){ +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} options + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options){ + options = options || {}; + if ('string' == typeof val) return parse(val); + return options.long ? longFormat(val) : shortFormat(val); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str); + if (!match) return; + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 's': + return n * s; + case 'ms': + return n; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function shortFormat(ms) { + if (ms >= d) return Math.round(ms / d) + 'd'; + if (ms >= h) return Math.round(ms / h) + 'h'; + if (ms >= m) return Math.round(ms / m) + 'm'; + if (ms >= s) return Math.round(ms / s) + 's'; + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function longFormat(ms) { + return plural(ms, d, 'day') + || plural(ms, h, 'hour') + || plural(ms, m, 'minute') + || plural(ms, s, 'second') + || ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, n, name) { + if (ms < n) return; + if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name; + return Math.ceil(ms / n) + ' ' + name + 's'; +} + +}); // module: ms.js + +require.register("reporters/base.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var tty = require('browser/tty') + , diff = require('browser/diff') + , ms = require('../ms') + , utils = require('../utils'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Check if both stdio streams are associated with a tty. + */ + +var isatty = tty.isatty(1) && tty.isatty(2); + +/** + * Expose `Base`. + */ + +exports = module.exports = Base; + +/** + * Enable coloring by default. + */ + +exports.useColors = isatty || (process.env.MOCHA_COLORS !== undefined); + +/** + * Inline diffs instead of +/- + */ + +exports.inlineDiffs = false; + +/** + * Default color map. + */ + +exports.colors = { + 'pass': 90 + , 'fail': 31 + , 'bright pass': 92 + , 'bright fail': 91 + , 'bright yellow': 93 + , 'pending': 36 + , 'suite': 0 + , 'error title': 0 + , 'error message': 31 + , 'error stack': 90 + , 'checkmark': 32 + , 'fast': 90 + , 'medium': 33 + , 'slow': 31 + , 'green': 32 + , 'light': 90 + , 'diff gutter': 90 + , 'diff added': 42 + , 'diff removed': 41 +}; + +/** + * Default symbol map. + */ + +exports.symbols = { + ok: '✓', + err: '✖', + dot: '․' +}; + +// With node.js on Windows: use symbols available in terminal default fonts +if ('win32' == process.platform) { + exports.symbols.ok = '\u221A'; + exports.symbols.err = '\u00D7'; + exports.symbols.dot = '.'; +} + +/** + * Color `str` with the given `type`, + * allowing colors to be disabled, + * as well as user-defined color + * schemes. + * + * @param {String} type + * @param {String} str + * @return {String} + * @api private + */ + +var color = exports.color = function(type, str) { + if (!exports.useColors) return str; + return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; +}; + +/** + * Expose term window size, with some + * defaults for when stderr is not a tty. + */ + +exports.window = { + width: isatty + ? process.stdout.getWindowSize + ? process.stdout.getWindowSize(1)[0] + : tty.getWindowSize()[1] + : 75 +}; + +/** + * Expose some basic cursor interactions + * that are common among reporters. + */ + +exports.cursor = { + hide: function(){ + isatty && process.stdout.write('\u001b[?25l'); + }, + + show: function(){ + isatty && process.stdout.write('\u001b[?25h'); + }, + + deleteLine: function(){ + isatty && process.stdout.write('\u001b[2K'); + }, + + beginningOfLine: function(){ + isatty && process.stdout.write('\u001b[0G'); + }, + + CR: function(){ + if (isatty) { + exports.cursor.deleteLine(); + exports.cursor.beginningOfLine(); + } else { + process.stdout.write('\r'); + } + } +}; + +/** + * Outut the given `failures` as a list. + * + * @param {Array} failures + * @api public + */ + +exports.list = function(failures){ + console.error(); + failures.forEach(function(test, i){ + // format + var fmt = color('error title', ' %s) %s:\n') + + color('error message', ' %s') + + color('error stack', '\n%s\n'); + + // msg + var err = test.err + , message = err.message || '' + , stack = err.stack || message + , index = stack.indexOf(message) + message.length + , msg = stack.slice(0, index) + , actual = err.actual + , expected = err.expected + , escape = true; + + // uncaught + if (err.uncaught) { + msg = 'Uncaught ' + msg; + } + + // explicitly show diff + if (err.showDiff && sameType(actual, expected)) { + escape = false; + err.actual = actual = stringify(canonicalize(actual)); + err.expected = expected = stringify(canonicalize(expected)); + } + + // actual / expected diff + if ('string' == typeof actual && 'string' == typeof expected) { + fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); + var match = message.match(/^([^:]+): expected/); + msg = '\n ' + color('error message', match ? match[1] : msg); + + if (exports.inlineDiffs) { + msg += inlineDiff(err, escape); + } else { + msg += unifiedDiff(err, escape); + } + } + + // indent stack trace without msg + stack = stack.slice(index ? index + 1 : index) + .replace(/^/gm, ' '); + + console.error(fmt, (i + 1), test.fullTitle(), msg, stack); + }); +}; + +/** + * Initialize a new `Base` reporter. + * + * All other reporters generally + * inherit from this reporter, providing + * stats such as test duration, number + * of tests passed / failed etc. + * + * @param {Runner} runner + * @api public + */ + +function Base(runner) { + var self = this + , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } + , failures = this.failures = []; + + if (!runner) return; + this.runner = runner; + + runner.stats = stats; + + runner.on('start', function(){ + stats.start = new Date; + }); + + runner.on('suite', function(suite){ + stats.suites = stats.suites || 0; + suite.root || stats.suites++; + }); + + runner.on('test end', function(test){ + stats.tests = stats.tests || 0; + stats.tests++; + }); + + runner.on('pass', function(test){ + stats.passes = stats.passes || 0; + + var medium = test.slow() / 2; + test.speed = test.duration > test.slow() + ? 'slow' + : test.duration > medium + ? 'medium' + : 'fast'; + + stats.passes++; + }); + + runner.on('fail', function(test, err){ + stats.failures = stats.failures || 0; + stats.failures++; + test.err = err; + failures.push(test); + }); + + runner.on('end', function(){ + stats.end = new Date; + stats.duration = new Date - stats.start; + }); + + runner.on('pending', function(){ + stats.pending++; + }); +} + +/** + * Output common epilogue used by many of + * the bundled reporters. + * + * @api public + */ + +Base.prototype.epilogue = function(){ + var stats = this.stats; + var tests; + var fmt; + + console.log(); + + // passes + fmt = color('bright pass', ' ') + + color('green', ' %d passing') + + color('light', ' (%s)'); + + console.log(fmt, + stats.passes || 0, + ms(stats.duration)); + + // pending + if (stats.pending) { + fmt = color('pending', ' ') + + color('pending', ' %d pending'); + + console.log(fmt, stats.pending); + } + + // failures + if (stats.failures) { + fmt = color('fail', ' %d failing'); + + console.error(fmt, + stats.failures); + + Base.list(this.failures); + console.error(); + } + + console.log(); +}; + +/** + * Pad the given `str` to `len`. + * + * @param {String} str + * @param {String} len + * @return {String} + * @api private + */ + +function pad(str, len) { + str = String(str); + return Array(len - str.length + 1).join(' ') + str; +} + + +/** + * Returns an inline diff between 2 strings with coloured ANSI output + * + * @param {Error} Error with actual/expected + * @return {String} Diff + * @api private + */ + +function inlineDiff(err, escape) { + var msg = errorDiff(err, 'WordsWithSpace', escape); + + // linenos + var lines = msg.split('\n'); + if (lines.length > 4) { + var width = String(lines.length).length; + msg = lines.map(function(str, i){ + return pad(++i, width) + ' |' + ' ' + str; + }).join('\n'); + } + + // legend + msg = '\n' + + color('diff removed', 'actual') + + ' ' + + color('diff added', 'expected') + + '\n\n' + + msg + + '\n'; + + // indent + msg = msg.replace(/^/gm, ' '); + return msg; +} + +/** + * Returns a unified diff between 2 strings + * + * @param {Error} Error with actual/expected + * @return {String} Diff + * @api private + */ + +function unifiedDiff(err, escape) { + var indent = ' '; + function cleanUp(line) { + if (escape) { + line = escapeInvisibles(line); + } + if (line[0] === '+') return indent + colorLines('diff added', line); + if (line[0] === '-') return indent + colorLines('diff removed', line); + if (line.match(/\@\@/)) return null; + if (line.match(/\\ No newline/)) return null; + else return indent + line; + } + function notBlank(line) { + return line != null; + } + msg = diff.createPatch('string', err.actual, err.expected); + var lines = msg.split('\n').splice(4); + return '\n ' + + colorLines('diff added', '+ expected') + ' ' + + colorLines('diff removed', '- actual') + + '\n\n' + + lines.map(cleanUp).filter(notBlank).join('\n'); +} + +/** + * Return a character diff for `err`. + * + * @param {Error} err + * @return {String} + * @api private + */ + +function errorDiff(err, type, escape) { + var actual = escape ? escapeInvisibles(err.actual) : err.actual; + var expected = escape ? escapeInvisibles(err.expected) : err.expected; + return diff['diff' + type](actual, expected).map(function(str){ + if (str.added) return colorLines('diff added', str.value); + if (str.removed) return colorLines('diff removed', str.value); + return str.value; + }).join(''); +} + +/** + * Returns a string with all invisible characters in plain text + * + * @param {String} line + * @return {String} + * @api private + */ +function escapeInvisibles(line) { + return line.replace(/\t/g, '') + .replace(/\r/g, '') + .replace(/\n/g, '\n'); +} + +/** + * Color lines for `str`, using the color `name`. + * + * @param {String} name + * @param {String} str + * @return {String} + * @api private + */ + +function colorLines(name, str) { + return str.split('\n').map(function(str){ + return color(name, str); + }).join('\n'); +} + +/** + * Stringify `obj`. + * + * @param {Object} obj + * @return {String} + * @api private + */ + +function stringify(obj) { + if (obj instanceof RegExp) return obj.toString(); + return JSON.stringify(obj, null, 2); +} + +/** + * Return a new object that has the keys in sorted order. + * @param {Object} obj + * @return {Object} + * @api private + */ + + function canonicalize(obj, stack) { + stack = stack || []; + + if (utils.indexOf(stack, obj) !== -1) return obj; + + var canonicalizedObj; + + if ('[object Array]' == {}.toString.call(obj)) { + stack.push(obj); + canonicalizedObj = utils.map(obj, function(item) { + return canonicalize(item, stack); + }); + stack.pop(); + } else if (typeof obj === 'object' && obj !== null) { + stack.push(obj); + canonicalizedObj = {}; + utils.forEach(utils.keys(obj).sort(), function(key) { + canonicalizedObj[key] = canonicalize(obj[key], stack); + }); + stack.pop(); + } else { + canonicalizedObj = obj; + } + + return canonicalizedObj; + } + +/** + * Check that a / b have the same type. + * + * @param {Object} a + * @param {Object} b + * @return {Boolean} + * @api private + */ + +function sameType(a, b) { + a = Object.prototype.toString.call(a); + b = Object.prototype.toString.call(b); + return a == b; +} + + +}); // module: reporters/base.js + +require.register("reporters/doc.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Doc`. + */ + +exports = module.exports = Doc; + +/** + * Initialize a new `Doc` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Doc(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , indents = 2; + + function indent() { + return Array(indents).join(' '); + } + + runner.on('suite', function(suite){ + if (suite.root) return; + ++indents; + console.log('%s
', indent()); + ++indents; + console.log('%s

%s

', indent(), utils.escape(suite.title)); + console.log('%s
', indent()); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + console.log('%s
', indent()); + --indents; + console.log('%s
', indent()); + --indents; + }); + + runner.on('pass', function(test){ + console.log('%s
%s
', indent(), utils.escape(test.title)); + var code = utils.escape(utils.clean(test.fn.toString())); + console.log('%s
%s
', indent(), code); + }); +} + +}); // module: reporters/doc.js + +require.register("reporters/dot.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `Dot`. + */ + +exports = module.exports = Dot; + +/** + * Initialize a new `Dot` matrix test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Dot(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , n = 0; + + runner.on('start', function(){ + process.stdout.write('\n '); + }); + + runner.on('pending', function(test){ + process.stdout.write(color('pending', Base.symbols.dot)); + }); + + runner.on('pass', function(test){ + if (++n % width == 0) process.stdout.write('\n '); + if ('slow' == test.speed) { + process.stdout.write(color('bright yellow', Base.symbols.dot)); + } else { + process.stdout.write(color(test.speed, Base.symbols.dot)); + } + }); + + runner.on('fail', function(test, err){ + if (++n % width == 0) process.stdout.write('\n '); + process.stdout.write(color('fail', Base.symbols.dot)); + }); + + runner.on('end', function(){ + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Dot.prototype = new F; +Dot.prototype.constructor = Dot; + +}); // module: reporters/dot.js + +require.register("reporters/html-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var JSONCov = require('./json-cov') + , fs = require('browser/fs'); + +/** + * Expose `HTMLCov`. + */ + +exports = module.exports = HTMLCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTMLCov(runner) { + var jade = require('jade') + , file = __dirname + '/templates/coverage.jade' + , str = fs.readFileSync(file, 'utf8') + , fn = jade.compile(str, { filename: file }) + , self = this; + + JSONCov.call(this, runner, false); + + runner.on('end', function(){ + process.stdout.write(fn({ + cov: self.cov + , coverageClass: coverageClass + })); + }); +} + +/** + * Return coverage class for `n`. + * + * @return {String} + * @api private + */ + +function coverageClass(n) { + if (n >= 75) return 'high'; + if (n >= 50) return 'medium'; + if (n >= 25) return 'low'; + return 'terrible'; +} +}); // module: reporters/html-cov.js + +require.register("reporters/html.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , Progress = require('../browser/progress') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `HTML`. + */ + +exports = module.exports = HTML; + +/** + * Stats template. + */ + +var statsTemplate = ''; + +/** + * Initialize a new `HTML` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTML(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , stat = fragment(statsTemplate) + , items = stat.getElementsByTagName('li') + , passes = items[1].getElementsByTagName('em')[0] + , passesLink = items[1].getElementsByTagName('a')[0] + , failures = items[2].getElementsByTagName('em')[0] + , failuresLink = items[2].getElementsByTagName('a')[0] + , duration = items[3].getElementsByTagName('em')[0] + , canvas = stat.getElementsByTagName('canvas')[0] + , report = fragment('
    ') + , stack = [report] + , progress + , ctx + , root = document.getElementById('mocha'); + + if (canvas.getContext) { + var ratio = window.devicePixelRatio || 1; + canvas.style.width = canvas.width; + canvas.style.height = canvas.height; + canvas.width *= ratio; + canvas.height *= ratio; + ctx = canvas.getContext('2d'); + ctx.scale(ratio, ratio); + progress = new Progress; + } + + if (!root) return error('#mocha div missing, add it to your document'); + + // pass toggle + on(passesLink, 'click', function(){ + unhide(); + var name = /pass/.test(report.className) ? '' : ' pass'; + report.className = report.className.replace(/fail|pass/g, '') + name; + if (report.className.trim()) hideSuitesWithout('test pass'); + }); + + // failure toggle + on(failuresLink, 'click', function(){ + unhide(); + var name = /fail/.test(report.className) ? '' : ' fail'; + report.className = report.className.replace(/fail|pass/g, '') + name; + if (report.className.trim()) hideSuitesWithout('test fail'); + }); + + root.appendChild(stat); + root.appendChild(report); + + if (progress) progress.size(40); + + runner.on('suite', function(suite){ + if (suite.root) return; + + // suite + var url = self.suiteURL(suite); + var el = fragment('
  • %s

  • ', url, escape(suite.title)); + + // container + stack[0].appendChild(el); + stack.unshift(document.createElement('ul')); + el.appendChild(stack[0]); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + stack.shift(); + }); + + runner.on('fail', function(test, err){ + if ('hook' == test.type) runner.emit('test end', test); + }); + + runner.on('test end', function(test){ + // TODO: add to stats + var percent = stats.tests / this.total * 100 | 0; + if (progress) progress.update(percent).draw(ctx); + + // update stats + var ms = new Date - stats.start; + text(passes, stats.passes); + text(failures, stats.failures); + text(duration, (ms / 1000).toFixed(2)); + + // test + if ('passed' == test.state) { + var url = self.testURL(test); + var el = fragment('
  • %e%ems

  • ', test.speed, test.title, test.duration, url); + } else if (test.pending) { + var el = fragment('
  • %e

  • ', test.title); + } else { + var el = fragment('
  • %e

  • ', test.title, encodeURIComponent(test.fullTitle())); + var str = test.err.stack || test.err.toString(); + + // FF / Opera do not add the message + if (!~str.indexOf(test.err.message)) { + str = test.err.message + '\n' + str; + } + + // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we + // check for the result of the stringifying. + if ('[object Error]' == str) str = test.err.message; + + // Safari doesn't give you a stack. Let's at least provide a source line. + if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { + str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; + } + + el.appendChild(fragment('
    %e
    ', str)); + } + + // toggle code + // TODO: defer + if (!test.pending) { + var h2 = el.getElementsByTagName('h2')[0]; + + on(h2, 'click', function(){ + pre.style.display = 'none' == pre.style.display + ? 'block' + : 'none'; + }); + + var pre = fragment('
    %e
    ', utils.clean(test.fn.toString())); + el.appendChild(pre); + pre.style.display = 'none'; + } + + // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. + if (stack[0]) stack[0].appendChild(el); + }); +} + +/** + * Provide suite URL + * + * @param {Object} [suite] + */ + +HTML.prototype.suiteURL = function(suite){ + return '?grep=' + encodeURIComponent(suite.fullTitle()); +}; + +/** + * Provide test URL + * + * @param {Object} [test] + */ + +HTML.prototype.testURL = function(test){ + return '?grep=' + encodeURIComponent(test.fullTitle()); +}; + +/** + * Display error `msg`. + */ + +function error(msg) { + document.body.appendChild(fragment('
    %s
    ', msg)); +} + +/** + * Return a DOM fragment from `html`. + */ + +function fragment(html) { + var args = arguments + , div = document.createElement('div') + , i = 1; + + div.innerHTML = html.replace(/%([se])/g, function(_, type){ + switch (type) { + case 's': return String(args[i++]); + case 'e': return escape(args[i++]); + } + }); + + return div.firstChild; +} + +/** + * Check for suites that do not have elements + * with `classname`, and hide them. + */ + +function hideSuitesWithout(classname) { + var suites = document.getElementsByClassName('suite'); + for (var i = 0; i < suites.length; i++) { + var els = suites[i].getElementsByClassName(classname); + if (0 == els.length) suites[i].className += ' hidden'; + } +} + +/** + * Unhide .hidden suites. + */ + +function unhide() { + var els = document.getElementsByClassName('suite hidden'); + for (var i = 0; i < els.length; ++i) { + els[i].className = els[i].className.replace('suite hidden', 'suite'); + } +} + +/** + * Set `el` text to `str`. + */ + +function text(el, str) { + if (el.textContent) { + el.textContent = str; + } else { + el.innerText = str; + } +} + +/** + * Listen on `event` with callback `fn`. + */ + +function on(el, event, fn) { + if (el.addEventListener) { + el.addEventListener(event, fn, false); + } else { + el.attachEvent('on' + event, fn); + } +} + +}); // module: reporters/html.js + +require.register("reporters/index.js", function(module, exports, require){ + +exports.Base = require('./base'); +exports.Dot = require('./dot'); +exports.Doc = require('./doc'); +exports.TAP = require('./tap'); +exports.JSON = require('./json'); +exports.HTML = require('./html'); +exports.List = require('./list'); +exports.Min = require('./min'); +exports.Spec = require('./spec'); +exports.Nyan = require('./nyan'); +exports.XUnit = require('./xunit'); +exports.Markdown = require('./markdown'); +exports.Progress = require('./progress'); +exports.Landing = require('./landing'); +exports.JSONCov = require('./json-cov'); +exports.HTMLCov = require('./html-cov'); +exports.JSONStream = require('./json-stream'); + +}); // module: reporters/index.js + +require.register("reporters/json-cov.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `JSONCov`. + */ + +exports = module.exports = JSONCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @param {Boolean} output + * @api public + */ + +function JSONCov(runner, output) { + var self = this + , output = 1 == arguments.length ? true : output; + + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var cov = global._$jscoverage || {}; + var result = self.cov = map(cov); + result.stats = self.stats; + result.tests = tests.map(clean); + result.failures = failures.map(clean); + result.passes = passes.map(clean); + if (!output) return; + process.stdout.write(JSON.stringify(result, null, 2 )); + }); +} + +/** + * Map jscoverage data to a JSON structure + * suitable for reporting. + * + * @param {Object} cov + * @return {Object} + * @api private + */ + +function map(cov) { + var ret = { + instrumentation: 'node-jscoverage' + , sloc: 0 + , hits: 0 + , misses: 0 + , coverage: 0 + , files: [] + }; + + for (var filename in cov) { + var data = coverage(filename, cov[filename]); + ret.files.push(data); + ret.hits += data.hits; + ret.misses += data.misses; + ret.sloc += data.sloc; + } + + ret.files.sort(function(a, b) { + return a.filename.localeCompare(b.filename); + }); + + if (ret.sloc > 0) { + ret.coverage = (ret.hits / ret.sloc) * 100; + } + + return ret; +}; + +/** + * Map jscoverage data for a single source file + * to a JSON structure suitable for reporting. + * + * @param {String} filename name of the source file + * @param {Object} data jscoverage coverage data + * @return {Object} + * @api private + */ + +function coverage(filename, data) { + var ret = { + filename: filename, + coverage: 0, + hits: 0, + misses: 0, + sloc: 0, + source: {} + }; + + data.source.forEach(function(line, num){ + num++; + + if (data[num] === 0) { + ret.misses++; + ret.sloc++; + } else if (data[num] !== undefined) { + ret.hits++; + ret.sloc++; + } + + ret.source[num] = { + source: line + , coverage: data[num] === undefined + ? '' + : data[num] + }; + }); + + ret.coverage = ret.hits / ret.sloc * 100; + + return ret; +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} + +}); // module: reporters/json-cov.js + +require.register("reporters/json-stream.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total; + + runner.on('start', function(){ + console.log(JSON.stringify(['start', { total: total }])); + }); + + runner.on('pass', function(test){ + console.log(JSON.stringify(['pass', clean(test)])); + }); + + runner.on('fail', function(test, err){ + console.log(JSON.stringify(['fail', clean(test)])); + }); + + runner.on('end', function(){ + process.stdout.write(JSON.stringify(['end', self.stats])); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} +}); // module: reporters/json-stream.js + +require.register("reporters/json.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `JSON`. + */ + +exports = module.exports = JSONReporter; + +/** + * Initialize a new `JSON` reporter. + * + * @param {Runner} runner + * @api public + */ + +function JSONReporter(runner) { + var self = this; + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var obj = { + stats: self.stats + , tests: tests.map(clean) + , failures: failures.map(clean) + , passes: passes.map(clean) + }; + + process.stdout.write(JSON.stringify(obj, null, 2)); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} +}); // module: reporters/json.js + +require.register("reporters/landing.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Landing`. + */ + +exports = module.exports = Landing; + +/** + * Airplane color. + */ + +Base.colors.plane = 0; + +/** + * Airplane crash color. + */ + +Base.colors['plane crash'] = 31; + +/** + * Runway color. + */ + +Base.colors.runway = 90; + +/** + * Initialize a new `Landing` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Landing(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , total = runner.total + , stream = process.stdout + , plane = color('plane', '✈') + , crashed = -1 + , n = 0; + + function runway() { + var buf = Array(width).join('-'); + return ' ' + color('runway', buf); + } + + runner.on('start', function(){ + stream.write('\n '); + cursor.hide(); + }); + + runner.on('test end', function(test){ + // check if the plane crashed + var col = -1 == crashed + ? width * ++n / total | 0 + : crashed; + + // show the crash + if ('failed' == test.state) { + plane = color('plane crash', '✈'); + crashed = col; + } + + // render landing strip + stream.write('\u001b[4F\n\n'); + stream.write(runway()); + stream.write('\n '); + stream.write(color('runway', Array(col).join('⋅'))); + stream.write(plane) + stream.write(color('runway', Array(width - col).join('⋅') + '\n')); + stream.write(runway()); + stream.write('\u001b[0m'); + }); + + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Landing.prototype = new F; +Landing.prototype.constructor = Landing; + +}); // module: reporters/landing.js + +require.register("reporters/list.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , n = 0; + + runner.on('start', function(){ + console.log(); + }); + + runner.on('test', function(test){ + process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); + }); + + runner.on('pending', function(test){ + var fmt = color('checkmark', ' -') + + color('pending', ' %s'); + console.log(fmt, test.fullTitle()); + }); + + runner.on('pass', function(test){ + var fmt = color('checkmark', ' '+Base.symbols.dot) + + color('pass', ' %s: ') + + color(test.speed, '%dms'); + cursor.CR(); + console.log(fmt, test.fullTitle(), test.duration); + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +List.prototype = new F; +List.prototype.constructor = List; + + +}); // module: reporters/list.js + +require.register("reporters/markdown.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Markdown`. + */ + +exports = module.exports = Markdown; + +/** + * Initialize a new `Markdown` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Markdown(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , level = 0 + , buf = ''; + + function title(str) { + return Array(level).join('#') + ' ' + str; + } + + function indent() { + return Array(level).join(' '); + } + + function mapTOC(suite, obj) { + var ret = obj; + obj = obj[suite.title] = obj[suite.title] || { suite: suite }; + suite.suites.forEach(function(suite){ + mapTOC(suite, obj); + }); + return ret; + } + + function stringifyTOC(obj, level) { + ++level; + var buf = ''; + var link; + for (var key in obj) { + if ('suite' == key) continue; + if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; + if (key) buf += Array(level).join(' ') + link; + buf += stringifyTOC(obj[key], level); + } + --level; + return buf; + } + + function generateTOC(suite) { + var obj = mapTOC(suite, {}); + return stringifyTOC(obj, 0); + } + + generateTOC(runner.suite); + + runner.on('suite', function(suite){ + ++level; + var slug = utils.slug(suite.fullTitle()); + buf += '' + '\n'; + buf += title(suite.title) + '\n'; + }); + + runner.on('suite end', function(suite){ + --level; + }); + + runner.on('pass', function(test){ + var code = utils.clean(test.fn.toString()); + buf += test.title + '.\n'; + buf += '\n```js\n'; + buf += code + '\n'; + buf += '```\n\n'; + }); + + runner.on('end', function(){ + process.stdout.write('# TOC\n'); + process.stdout.write(generateTOC(runner.suite)); + process.stdout.write(buf); + }); +} +}); // module: reporters/markdown.js + +require.register("reporters/min.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `Min`. + */ + +exports = module.exports = Min; + +/** + * Initialize a new `Min` minimal test reporter (best used with --watch). + * + * @param {Runner} runner + * @api public + */ + +function Min(runner) { + Base.call(this, runner); + + runner.on('start', function(){ + // clear screen + process.stdout.write('\u001b[2J'); + // set cursor position + process.stdout.write('\u001b[1;3H'); + }); + + runner.on('end', this.epilogue.bind(this)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Min.prototype = new F; +Min.prototype.constructor = Min; + + +}); // module: reporters/min.js + +require.register("reporters/nyan.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `Dot`. + */ + +exports = module.exports = NyanCat; + +/** + * Initialize a new `Dot` matrix test reporter. + * + * @param {Runner} runner + * @api public + */ + +function NyanCat(runner) { + Base.call(this, runner); + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , rainbowColors = this.rainbowColors = self.generateColors() + , colorIndex = this.colorIndex = 0 + , numerOfLines = this.numberOfLines = 4 + , trajectories = this.trajectories = [[], [], [], []] + , nyanCatWidth = this.nyanCatWidth = 11 + , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth) + , scoreboardWidth = this.scoreboardWidth = 5 + , tick = this.tick = 0 + , n = 0; + + runner.on('start', function(){ + Base.cursor.hide(); + self.draw(); + }); + + runner.on('pending', function(test){ + self.draw(); + }); + + runner.on('pass', function(test){ + self.draw(); + }); + + runner.on('fail', function(test, err){ + self.draw(); + }); + + runner.on('end', function(){ + Base.cursor.show(); + for (var i = 0; i < self.numberOfLines; i++) write('\n'); + self.epilogue(); + }); +} + +/** + * Draw the nyan cat + * + * @api private + */ + +NyanCat.prototype.draw = function(){ + this.appendRainbow(); + this.drawScoreboard(); + this.drawRainbow(); + this.drawNyanCat(); + this.tick = !this.tick; +}; + +/** + * Draw the "scoreboard" showing the number + * of passes, failures and pending tests. + * + * @api private + */ + +NyanCat.prototype.drawScoreboard = function(){ + var stats = this.stats; + var colors = Base.colors; + + function draw(color, n) { + write(' '); + write('\u001b[' + color + 'm' + n + '\u001b[0m'); + write('\n'); + } + + draw(colors.green, stats.passes); + draw(colors.fail, stats.failures); + draw(colors.pending, stats.pending); + write('\n'); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Append the rainbow. + * + * @api private + */ + +NyanCat.prototype.appendRainbow = function(){ + var segment = this.tick ? '_' : '-'; + var rainbowified = this.rainbowify(segment); + + for (var index = 0; index < this.numberOfLines; index++) { + var trajectory = this.trajectories[index]; + if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift(); + trajectory.push(rainbowified); + } +}; + +/** + * Draw the rainbow. + * + * @api private + */ + +NyanCat.prototype.drawRainbow = function(){ + var self = this; + + this.trajectories.forEach(function(line, index) { + write('\u001b[' + self.scoreboardWidth + 'C'); + write(line.join('')); + write('\n'); + }); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Draw the nyan cat + * + * @api private + */ + +NyanCat.prototype.drawNyanCat = function() { + var self = this; + var startWidth = this.scoreboardWidth + this.trajectories[0].length; + var color = '\u001b[' + startWidth + 'C'; + var padding = ''; + + write(color); + write('_,------,'); + write('\n'); + + write(color); + padding = self.tick ? ' ' : ' '; + write('_|' + padding + '/\\_/\\ '); + write('\n'); + + write(color); + padding = self.tick ? '_' : '__'; + var tail = self.tick ? '~' : '^'; + var face; + write(tail + '|' + padding + this.face() + ' '); + write('\n'); + + write(color); + padding = self.tick ? ' ' : ' '; + write(padding + '"" "" '); + write('\n'); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Draw nyan cat face. + * + * @return {String} + * @api private + */ + +NyanCat.prototype.face = function() { + var stats = this.stats; + if (stats.failures) { + return '( x .x)'; + } else if (stats.pending) { + return '( o .o)'; + } else if(stats.passes) { + return '( ^ .^)'; + } else { + return '( - .-)'; + } +} + +/** + * Move cursor up `n`. + * + * @param {Number} n + * @api private + */ + +NyanCat.prototype.cursorUp = function(n) { + write('\u001b[' + n + 'A'); +}; + +/** + * Move cursor down `n`. + * + * @param {Number} n + * @api private + */ + +NyanCat.prototype.cursorDown = function(n) { + write('\u001b[' + n + 'B'); +}; + +/** + * Generate rainbow colors. + * + * @return {Array} + * @api private + */ + +NyanCat.prototype.generateColors = function(){ + var colors = []; + + for (var i = 0; i < (6 * 7); i++) { + var pi3 = Math.floor(Math.PI / 3); + var n = (i * (1.0 / 6)); + var r = Math.floor(3 * Math.sin(n) + 3); + var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); + var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); + colors.push(36 * r + 6 * g + b + 16); + } + + return colors; +}; + +/** + * Apply rainbow to the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +NyanCat.prototype.rainbowify = function(str){ + var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; + this.colorIndex += 1; + return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; +}; + +/** + * Stdout helper. + */ + +function write(string) { + process.stdout.write(string); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +NyanCat.prototype = new F; +NyanCat.prototype.constructor = NyanCat; + + +}); // module: reporters/nyan.js + +require.register("reporters/progress.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Progress`. + */ + +exports = module.exports = Progress; + +/** + * General progress bar color. + */ + +Base.colors.progress = 90; + +/** + * Initialize a new `Progress` bar test reporter. + * + * @param {Runner} runner + * @param {Object} options + * @api public + */ + +function Progress(runner, options) { + Base.call(this, runner); + + var self = this + , options = options || {} + , stats = this.stats + , width = Base.window.width * .50 | 0 + , total = runner.total + , complete = 0 + , max = Math.max; + + // default chars + options.open = options.open || '['; + options.complete = options.complete || '▬'; + options.incomplete = options.incomplete || Base.symbols.dot; + options.close = options.close || ']'; + options.verbose = false; + + // tests started + runner.on('start', function(){ + console.log(); + cursor.hide(); + }); + + // tests complete + runner.on('test end', function(){ + complete++; + var incomplete = total - complete + , percent = complete / total + , n = width * percent | 0 + , i = width - n; + + cursor.CR(); + process.stdout.write('\u001b[J'); + process.stdout.write(color('progress', ' ' + options.open)); + process.stdout.write(Array(n).join(options.complete)); + process.stdout.write(Array(i).join(options.incomplete)); + process.stdout.write(color('progress', options.close)); + if (options.verbose) { + process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); + } + }); + + // tests are complete, output some stats + // and the failures if any + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Progress.prototype = new F; +Progress.prototype.constructor = Progress; + + +}); // module: reporters/progress.js + +require.register("reporters/spec.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Spec`. + */ + +exports = module.exports = Spec; + +/** + * Initialize a new `Spec` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Spec(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , indents = 0 + , n = 0; + + function indent() { + return Array(indents).join(' ') + } + + runner.on('start', function(){ + console.log(); + }); + + runner.on('suite', function(suite){ + ++indents; + console.log(color('suite', '%s%s'), indent(), suite.title); + }); + + runner.on('suite end', function(suite){ + --indents; + if (1 == indents) console.log(); + }); + + runner.on('pending', function(test){ + var fmt = indent() + color('pending', ' - %s'); + console.log(fmt, test.title); + }); + + runner.on('pass', function(test){ + if ('fast' == test.speed) { + var fmt = indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s '); + cursor.CR(); + console.log(fmt, test.title); + } else { + var fmt = indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s ') + + color(test.speed, '(%dms)'); + cursor.CR(); + console.log(fmt, test.title, test.duration); + } + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Spec.prototype = new F; +Spec.prototype.constructor = Spec; + + +}); // module: reporters/spec.js + +require.register("reporters/tap.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `TAP`. + */ + +exports = module.exports = TAP; + +/** + * Initialize a new `TAP` reporter. + * + * @param {Runner} runner + * @api public + */ + +function TAP(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , n = 1 + , passes = 0 + , failures = 0; + + runner.on('start', function(){ + var total = runner.grepTotal(runner.suite); + console.log('%d..%d', 1, total); + }); + + runner.on('test end', function(){ + ++n; + }); + + runner.on('pending', function(test){ + console.log('ok %d %s # SKIP -', n, title(test)); + }); + + runner.on('pass', function(test){ + passes++; + console.log('ok %d %s', n, title(test)); + }); + + runner.on('fail', function(test, err){ + failures++; + console.log('not ok %d %s', n, title(test)); + if (err.stack) console.log(err.stack.replace(/^/gm, ' ')); + }); + + runner.on('end', function(){ + console.log('# tests ' + (passes + failures)); + console.log('# pass ' + passes); + console.log('# fail ' + failures); + }); +} + +/** + * Return a TAP-safe title of `test` + * + * @param {Object} test + * @return {String} + * @api private + */ + +function title(test) { + return test.fullTitle().replace(/#/g, ''); +} + +}); // module: reporters/tap.js + +require.register("reporters/xunit.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `XUnit`. + */ + +exports = module.exports = XUnit; + +/** + * Initialize a new `XUnit` reporter. + * + * @param {Runner} runner + * @api public + */ + +function XUnit(runner) { + Base.call(this, runner); + var stats = this.stats + , tests = [] + , self = this; + + runner.on('pending', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + tests.push(test); + }); + + runner.on('fail', function(test){ + tests.push(test); + }); + + runner.on('end', function(){ + console.log(tag('testsuite', { + name: 'Mocha Tests' + , tests: stats.tests + , failures: stats.failures + , errors: stats.failures + , skipped: stats.tests - stats.failures - stats.passes + , timestamp: (new Date).toUTCString() + , time: (stats.duration / 1000) || 0 + }, false)); + + tests.forEach(test); + console.log(''); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +XUnit.prototype = new F; +XUnit.prototype.constructor = XUnit; + + +/** + * Output tag for the given `test.` + */ + +function test(test) { + var attrs = { + classname: test.parent.fullTitle() + , name: test.title + , time: (test.duration / 1000) || 0 + }; + + if ('failed' == test.state) { + var err = test.err; + attrs.message = escape(err.message); + console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); + } else if (test.pending) { + console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); + } else { + console.log(tag('testcase', attrs, true) ); + } +} + +/** + * HTML tag helper. + */ + +function tag(name, attrs, close, content) { + var end = close ? '/>' : '>' + , pairs = [] + , tag; + + for (var key in attrs) { + pairs.push(key + '="' + escape(attrs[key]) + '"'); + } + + tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; + if (content) tag += content + ''; +} + +}); // module: reporters/xunit.js + +require.register("runnable.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:runnable') + , milliseconds = require('./ms'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Object#toString(). + */ + +var toString = Object.prototype.toString; + +/** + * Expose `Runnable`. + */ + +module.exports = Runnable; + +/** + * Initialize a new `Runnable` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Runnable(title, fn) { + this.title = title; + this.fn = fn; + this.async = fn && fn.length; + this.sync = ! this.async; + this._timeout = 2000; + this._slow = 75; + this.timedOut = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Runnable.prototype = new F; +Runnable.prototype.constructor = Runnable; + + +/** + * Set & get timeout `ms`. + * + * @param {Number|String} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._timeout = ms; + if (this.timer) this.resetTimeout(); + return this; +}; + +/** + * Set & get slow `ms`. + * + * @param {Number|String} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.slow = function(ms){ + if (0 === arguments.length) return this._slow; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._slow = ms; + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Runnable.prototype.fullTitle = function(){ + return this.parent.fullTitle() + ' ' + this.title; +}; + +/** + * Clear the timeout. + * + * @api private + */ + +Runnable.prototype.clearTimeout = function(){ + clearTimeout(this.timer); +}; + +/** + * Inspect the runnable void of private properties. + * + * @return {String} + * @api private + */ + +Runnable.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + if ('_' == key[0]) return; + if ('parent' == key) return '#'; + if ('ctx' == key) return '#'; + return val; + }, 2); +}; + +/** + * Reset the timeout. + * + * @api private + */ + +Runnable.prototype.resetTimeout = function(){ + var self = this; + var max_timeout = 10000;//default 10s + if (window && window.__mocha_max_timeout){ + max_timeout = window.__mocha_max_timeout; + } + var ms = this.timeout() || max_timeout; + if (ms > max_timeout){ + ms = max_timeout; + } + + this.clearTimeout(); + this.timer = setTimeout(function(){ + self.callback(new Error('timeout of ' + ms + 'ms exceeded')); + self.timedOut = true; + }, ms); +}; + +/** + * Whitelist these globals for this test run + * + * @api private + */ +Runnable.prototype.globals = function(arr){ + var self = this; + this._allowedGlobals = arr; +}; + +/** + * Run the test and invoke `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runnable.prototype.run = function(fn){ + var self = this + , ms = this.timeout() + , start = new Date + , ctx = this.ctx + , finished + , emitted; + + if (ctx) ctx.runnable(this); + + // called multiple times + function multiple(err) { + if (emitted) return; + emitted = true; + self.emit('error', err || new Error('done() called multiple times')); + } + + // finished + function done(err) { + if (self.timedOut) return; + if (finished) return multiple(err); + self.clearTimeout(); + self.duration = new Date - start; + finished = true; + fn(err); + } + + // for .resetTimeout() + this.callback = done; + + // explicit async with `done` argument + if (this.async) { + this.resetTimeout(); + + try { + this.fn.call(ctx, function(err){ + if (err instanceof Error || toString.call(err) === "[object Error]") return done(err); + if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); + done(); + }); + } catch (err) { + done(err); + } + return; + } + + if (this.asyncOnly) { + return done(new Error('--async-only option in use without declaring `done()`')); + } + + // sync or promise-returning + try { + if (this.pending) { + done(); + } else { + callFn(this.fn); + } + } catch (err) { + done(err); + } + + function callFn(fn) { + var result = fn.call(ctx); + if (result && typeof result.then === 'function') { + self.resetTimeout(); + result.then(function(){ done() }, done); + } else { + done(); + } + } +}; + +}); // module: runnable.js + +require.register("runner.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:runner') + , Test = require('./test') + , utils = require('./utils') + , filter = utils.filter + , keys = utils.keys; + +/** + * Non-enumerable globals. + */ + +var globals = [ + 'setTimeout', + 'clearTimeout', + 'setInterval', + 'clearInterval', + 'XMLHttpRequest', + 'Date' +]; + +/** + * Expose `Runner`. + */ + +module.exports = Runner; + +/** + * Initialize a `Runner` for the given `suite`. + * + * Events: + * + * - `start` execution started + * - `end` execution complete + * - `suite` (suite) test suite execution started + * - `suite end` (suite) all tests (and sub-suites) have finished + * - `test` (test) test execution started + * - `test end` (test) test completed + * - `hook` (hook) hook execution started + * - `hook end` (hook) hook complete + * - `pass` (test) test passed + * - `fail` (test, err) test failed + * - `pending` (test) test pending + * + * @api public + */ + +function Runner(suite) { + var self = this; + this._globals = []; + this._abort = false; + this.suite = suite; + this.total = suite.total(); + this.failures = 0; + this.on('test end', function(test){ self.checkGlobals(test); }); + this.on('hook end', function(hook){ self.checkGlobals(hook); }); + this.grep(/.*/); + this.globals(this.globalProps().concat(extraGlobals())); +} + +/** + * Wrapper for setImmediate, process.nextTick, or browser polyfill. + * + * @param {Function} fn + * @api private + */ + +Runner.immediately = global.setImmediate || process.nextTick; + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Runner.prototype = new F; +Runner.prototype.constructor = Runner; + + +/** + * Run tests with full titles matching `re`. Updates runner.total + * with number of tests matched. + * + * @param {RegExp} re + * @param {Boolean} invert + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.grep = function(re, invert){ + debug('grep %s', re); + this._grep = re; + this._invert = invert; + this.total = this.grepTotal(this.suite); + return this; +}; + +/** + * Returns the number of tests matching the grep search for the + * given suite. + * + * @param {Suite} suite + * @return {Number} + * @api public + */ + +Runner.prototype.grepTotal = function(suite) { + var self = this; + var total = 0; + + suite.eachTest(function(test){ + var match = self._grep.test(test.fullTitle()); + if (self._invert) match = !match; + if (match) total++; + }); + + return total; +}; + +/** + * Return a list of global properties. + * + * @return {Array} + * @api private + */ + +Runner.prototype.globalProps = function() { + var props = utils.keys(global); + + // non-enumerables + for (var i = 0; i < globals.length; ++i) { + if (~utils.indexOf(props, globals[i])) continue; + props.push(globals[i]); + } + + return props; +}; + +/** + * Allow the given `arr` of globals. + * + * @param {Array} arr + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.globals = function(arr){ + if (0 == arguments.length) return this._globals; + debug('globals %j', arr); + this._globals = this._globals.concat(arr); + return this; +}; + +/** + * Check for global variable leaks. + * + * @api private + */ + +Runner.prototype.checkGlobals = function(test){ + if (this.ignoreLeaks) return; + var ok = this._globals; + + var globals = this.globalProps(); + var isNode = process.kill; + var leaks; + + if (test) { + ok = ok.concat(test._allowedGlobals || []); + } + + if(this.prevGlobalsLength == globals.length) return; + this.prevGlobalsLength = globals.length; + + leaks = filterLeaks(ok, globals); + this._globals = this._globals.concat(leaks); + + if (leaks.length > 1) { + this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); + } else if (leaks.length) { + this.fail(test, new Error('global leak detected: ' + leaks[0])); + } +}; + +/** + * Fail the given `test`. + * + * @param {Test} test + * @param {Error} err + * @api private + */ + +Runner.prototype.fail = function(test, err){ + ++this.failures; + test.state = 'failed'; + + if ('string' == typeof err) { + err = new Error('the string "' + err + '" was thrown, throw an Error :)'); + } + + this.emit('fail', test, err); +}; + +/** + * Fail the given `hook` with `err`. + * + * Hook failures work in the following pattern: + * - If bail, then exit + * - Failed `before` hook skips all tests in a suite and subsuites, + * but jumps to corresponding `after` hook + * - Failed `before each` hook skips remaining tests in a + * suite and jumps to corresponding `after each` hook, + * which is run only once + * - Failed `after` hook does not alter + * execution order + * - Failed `after each` hook skips remaining tests in a + * suite and subsuites, but executes other `after each` + * hooks + * + * @param {Hook} hook + * @param {Error} err + * @api private + */ + +Runner.prototype.failHook = function(hook, err){ + this.fail(hook, err); + if (this.suite.bail()) { + this.emit('end'); + } +}; + +/** + * Run hook `name` callbacks and then invoke `fn()`. + * + * @param {String} name + * @param {Function} function + * @api private + */ + +Runner.prototype.hook = function(name, fn){ + var suite = this.suite + , hooks = suite['_' + name] + , self = this + , timer; + + function next(i) { + var hook = hooks[i]; + if (!hook) return fn(); + if (self.failures && suite.bail()) return fn(); + self.currentRunnable = hook; + + hook.ctx.currentTest = self.test; + + self.emit('hook', hook); + + hook.on('error', function(err){ + self.failHook(hook, err); + }); + + hook.run(function(err){ + hook.removeAllListeners('error'); + var testError = hook.error(); + if (testError) self.fail(self.test, testError); + if (err) { + self.failHook(hook, err); + + // stop executing hooks, notify callee of hook err + return fn(err); + } + self.emit('hook end', hook); + delete hook.ctx.currentTest; + next(++i); + }); + } + + Runner.immediately(function(){ + next(0); + }); +}; + +/** + * Run hook `name` for the given array of `suites` + * in order, and callback `fn(err, errSuite)`. + * + * @param {String} name + * @param {Array} suites + * @param {Function} fn + * @api private + */ + +Runner.prototype.hooks = function(name, suites, fn){ + var self = this + , orig = this.suite; + + function next(suite) { + self.suite = suite; + + if (!suite) { + self.suite = orig; + return fn(); + } + + self.hook(name, function(err){ + if (err) { + var errSuite = self.suite; + self.suite = orig; + return fn(err, errSuite); + } + + next(suites.pop()); + }); + } + + next(suites.pop()); +}; + +/** + * Run hooks from the top level down. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookUp = function(name, fn){ + var suites = [this.suite].concat(this.parents()).reverse(); + this.hooks(name, suites, fn); +}; + +/** + * Run hooks from the bottom up. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookDown = function(name, fn){ + var suites = [this.suite].concat(this.parents()); + this.hooks(name, suites, fn); +}; + +/** + * Return an array of parent Suites from + * closest to furthest. + * + * @return {Array} + * @api private + */ + +Runner.prototype.parents = function(){ + var suite = this.suite + , suites = []; + while (suite = suite.parent) suites.push(suite); + return suites; +}; + +/** + * Run the current test and callback `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTest = function(fn){ + var test = this.test + , self = this; + + if (this.asyncOnly) test.asyncOnly = true; + + try { + test.on('error', function(err){ + self.fail(test, err); + }); + test.run(fn); + } catch (err) { + fn(err); + } +}; + +/** + * Run tests in the given `suite` and invoke + * the callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTests = function(suite, fn){ + var self = this + , tests = suite.tests.slice() + , test; + + + function hookErr(err, errSuite, after) { + // before/after Each hook for errSuite failed: + var orig = self.suite; + + // for failed 'after each' hook start from errSuite parent, + // otherwise start from errSuite itself + self.suite = after ? errSuite.parent : errSuite; + + if (self.suite) { + // call hookUp afterEach + self.hookUp('afterEach', function(err2, errSuite2) { + self.suite = orig; + // some hooks may fail even now + if (err2) return hookErr(err2, errSuite2, true); + // report error suite + fn(errSuite); + }); + } else { + // there is no need calling other 'after each' hooks + self.suite = orig; + fn(errSuite); + } + } + + function next(err, errSuite) { + // if we bail after first err + if (self.failures && suite._bail) return fn(); + + if (self._abort) return fn(); + + if (err) return hookErr(err, errSuite, true); + + // next test + test = tests.shift(); + + // all done + if (!test) return fn(); + + // grep + var match = self._grep.test(test.fullTitle()); + if (self._invert) match = !match; + if (!match) return next(); + + // pending + if (test.pending) { + self.emit('pending', test); + self.emit('test end', test); + return next(); + } + + // execute test and hook(s) + self.emit('test', self.test = test); + self.hookDown('beforeEach', function(err, errSuite){ + + if (err) return hookErr(err, errSuite, false); + + self.currentRunnable = self.test; + self.runTest(function(err){ + test = self.test; + + if (err) { + self.fail(test, err); + self.emit('test end', test); + return self.hookUp('afterEach', next); + } + + test.state = 'passed'; + self.emit('pass', test); + self.emit('test end', test); + self.hookUp('afterEach', next); + }); + }); + } + + this.next = next; + next(); +}; + +/** + * Run the given `suite` and invoke the + * callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runSuite = function(suite, fn){ + var total = this.grepTotal(suite) + , self = this + , i = 0; + + debug('run suite %s', suite.fullTitle()); + + if (!total) return fn(); + + this.emit('suite', this.suite = suite); + + function next(errSuite) { + if (errSuite) { + // current suite failed on a hook from errSuite + if (errSuite == suite) { + // if errSuite is current suite + // continue to the next sibling suite + return done(); + } else { + // errSuite is among the parents of current suite + // stop execution of errSuite and all sub-suites + return done(errSuite); + } + } + + if (self._abort) return done(); + + var curr = suite.suites[i++]; + if (!curr) return done(); + self.runSuite(curr, next); + } + + function done(errSuite) { + self.suite = suite; + self.hook('afterAll', function(){ + self.emit('suite end', suite); + fn(errSuite); + }); + } + + this.hook('beforeAll', function(err){ + if (err) return done(); + self.runTests(suite, next); + }); +}; + +/** + * Handle uncaught exceptions. + * + * @param {Error} err + * @api private + */ + +Runner.prototype.uncaught = function(err){ + debug('uncaught exception %s', err.message); + var runnable = this.currentRunnable; + if (!runnable || 'failed' == runnable.state) return; + runnable.clearTimeout(); + err.uncaught = true; + this.fail(runnable, err); + + // recover from test + if ('test' == runnable.type) { + this.emit('test end', runnable); + this.hookUp('afterEach', this.next); + return; + } + + // bail on hooks + this.emit('end'); +}; + +/** + * Run the root suite and invoke `fn(failures)` + * on completion. + * + * @param {Function} fn + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.run = function(fn){ + var self = this + , fn = fn || function(){}; + + function uncaught(err){ + self.uncaught(err); + } + + debug('start'); + + // callback + this.on('end', function(){ + debug('end'); + process.removeListener('uncaughtException', uncaught); + fn(self.failures); + }); + + // run suites + this.emit('start'); + this.runSuite(this.suite, function(){ + debug('finished running'); + self.emit('end'); + }); + + // uncaught exception + process.on('uncaughtException', uncaught); + window.__uncaught = uncaught; + + return this; +}; + +/** + * Cleanly abort execution + * + * @return {Runner} for chaining + * @api public + */ +Runner.prototype.abort = function(){ + debug('aborting'); + this._abort = true; +} + +/** + * Filter leaks with the given globals flagged as `ok`. + * + * @param {Array} ok + * @param {Array} globals + * @return {Array} + * @api private + */ + +function filterLeaks(ok, globals) { + return filter(globals, function(key){ + // Firefox and Chrome exposes iframes as index inside the window object + if (/^d+/.test(key)) return false; + + // in firefox + // if runner runs in an iframe, this iframe's window.getInterface method not init at first + // it is assigned in some seconds + if (global.navigator && /^getInterface/.test(key)) return false; + + // an iframe could be approached by window[iframeIndex] + // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak + if (global.navigator && /^\d+/.test(key)) return false; + + // Opera and IE expose global variables for HTML element IDs (issue #243) + if (/^mocha-/.test(key)) return false; + + var matched = filter(ok, function(ok){ + if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); + return key == ok; + }); + return matched.length == 0 && (!global.navigator || 'onerror' !== key); + }); +} + +/** + * Array of globals dependent on the environment. + * + * @return {Array} + * @api private + */ + + function extraGlobals() { + if (typeof(process) === 'object' && + typeof(process.version) === 'string') { + + var nodeVersion = process.version.split('.').reduce(function(a, v) { + return a << 8 | v; + }); + + // 'errno' was renamed to process._errno in v0.9.11. + + if (nodeVersion < 0x00090B) { + return ['errno']; + } + } + + return []; + } + +}); // module: runner.js + +require.register("suite.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:suite') + , milliseconds = require('./ms') + , utils = require('./utils') + , Hook = require('./hook'); + +/** + * Expose `Suite`. + */ + +exports = module.exports = Suite; + +/** + * Create a new `Suite` with the given `title` + * and parent `Suite`. When a suite with the + * same title is already present, that suite + * is returned to provide nicer reporter + * and more flexible meta-testing. + * + * @param {Suite} parent + * @param {String} title + * @return {Suite} + * @api public + */ + +exports.create = function(parent, title){ + var suite = new Suite(title, parent.ctx); + suite.parent = parent; + if (parent.pending) suite.pending = true; + title = suite.fullTitle(); + parent.addSuite(suite); + return suite; +}; + +/** + * Initialize a new `Suite` with the given + * `title` and `ctx`. + * + * @param {String} title + * @param {Context} ctx + * @api private + */ + +function Suite(title, ctx) { + this.title = title; + this.ctx = ctx; + this.suites = []; + this.tests = []; + this.pending = false; + this._beforeEach = []; + this._beforeAll = []; + this._afterEach = []; + this._afterAll = []; + this.root = !title; + this._timeout = 2000; + this._slow = 75; + this._bail = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Suite.prototype = new F; +Suite.prototype.constructor = Suite; + + +/** + * Return a clone of this `Suite`. + * + * @return {Suite} + * @api private + */ + +Suite.prototype.clone = function(){ + var suite = new Suite(this.title); + debug('clone'); + suite.ctx = this.ctx; + suite.timeout(this.timeout()); + suite.slow(this.slow()); + suite.bail(this.bail()); + return suite; +}; + +/** + * Set timeout `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._timeout = parseInt(ms, 10); + return this; +}; + +/** + * Set slow `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.slow = function(ms){ + if (0 === arguments.length) return this._slow; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('slow %d', ms); + this._slow = ms; + return this; +}; + +/** + * Sets whether to bail after first error. + * + * @parma {Boolean} bail + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.bail = function(bail){ + if (0 == arguments.length) return this._bail; + debug('bail %s', bail); + this._bail = bail; + return this; +}; + +/** + * Run `fn(test[, done])` before running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeAll = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"before all" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._beforeAll.push(hook); + this.emit('beforeAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterAll = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"after all" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._afterAll.push(hook); + this.emit('afterAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` before each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeEach = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"before each" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._beforeEach.push(hook); + this.emit('beforeEach', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterEach = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"after each" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._afterEach.push(hook); + this.emit('afterEach', hook); + return this; +}; + +/** + * Add a test `suite`. + * + * @param {Suite} suite + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addSuite = function(suite){ + suite.parent = this; + suite.timeout(this.timeout()); + suite.slow(this.slow()); + suite.bail(this.bail()); + this.suites.push(suite); + this.emit('suite', suite); + return this; +}; + +/** + * Add a `test` to this suite. + * + * @param {Test} test + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addTest = function(test){ + test.parent = this; + test.timeout(this.timeout()); + test.slow(this.slow()); + test.ctx = this.ctx; + this.tests.push(test); + this.emit('test', test); + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Suite.prototype.fullTitle = function(){ + if (this.parent) { + var full = this.parent.fullTitle(); + if (full) return full + ' ' + this.title; + } + return this.title; +}; + +/** + * Return the total number of tests. + * + * @return {Number} + * @api public + */ + +Suite.prototype.total = function(){ + return utils.reduce(this.suites, function(sum, suite){ + return sum + suite.total(); + }, 0) + this.tests.length; +}; + +/** + * Iterates through each suite recursively to find + * all tests. Applies a function in the format + * `fn(test)`. + * + * @param {Function} fn + * @return {Suite} + * @api private + */ + +Suite.prototype.eachTest = function(fn){ + utils.forEach(this.tests, fn); + utils.forEach(this.suites, function(suite){ + suite.eachTest(fn); + }); + return this; +}; + +}); // module: suite.js + +require.register("test.js", function(module, exports, require){ + +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Test`. + */ + +module.exports = Test; + +/** + * Initialize a new `Test` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Test(title, fn) { + Runnable.call(this, title, fn); + this.pending = !fn; + this.type = 'test'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +function F(){}; +F.prototype = Runnable.prototype; +Test.prototype = new F; +Test.prototype.constructor = Test; + + +}); // module: test.js + +require.register("utils.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var fs = require('browser/fs') + , path = require('browser/path') + , join = path.join + , debug = require('browser/debug')('mocha:watch'); + +/** + * Ignored directories. + */ + +var ignore = ['node_modules', '.git']; + +/** + * Escape special characters in the given string of html. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html){ + return String(html) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>'); +}; + +/** + * Array#forEach (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.forEach = function(arr, fn, scope){ + for (var i = 0, l = arr.length; i < l; i++) + fn.call(scope, arr[i], i); +}; + +/** + * Array#map (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.map = function(arr, fn, scope){ + var result = []; + for (var i = 0, l = arr.length; i < l; i++) + result.push(fn.call(scope, arr[i], i)); + return result; +}; + +/** + * Array#indexOf (<=IE8) + * + * @parma {Array} arr + * @param {Object} obj to find index of + * @param {Number} start + * @api private + */ + +exports.indexOf = function(arr, obj, start){ + for (var i = start || 0, l = arr.length; i < l; i++) { + if (arr[i] === obj) + return i; + } + return -1; +}; + +/** + * Array#reduce (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} initial value + * @api private + */ + +exports.reduce = function(arr, fn, val){ + var rval = val; + + for (var i = 0, l = arr.length; i < l; i++) { + rval = fn(rval, arr[i], i, arr); + } + + return rval; +}; + +/** + * Array#filter (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @api private + */ + +exports.filter = function(arr, fn){ + var ret = []; + + for (var i = 0, l = arr.length; i < l; i++) { + var val = arr[i]; + if (fn(val, i, arr)) ret.push(val); + } + + return ret; +}; + +/** + * Object.keys (<=IE8) + * + * @param {Object} obj + * @return {Array} keys + * @api private + */ + +exports.keys = Object.keys || function(obj) { + var keys = [] + , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 + + for (var key in obj) { + if (has.call(obj, key)) { + keys.push(key); + } + } + + return keys; +}; + +/** + * Watch the given `files` for changes + * and invoke `fn(file)` on modification. + * + * @param {Array} files + * @param {Function} fn + * @api private + */ + +exports.watch = function(files, fn){ + var options = { interval: 100 }; + files.forEach(function(file){ + debug('file %s', file); + fs.watchFile(file, options, function(curr, prev){ + if (prev.mtime < curr.mtime) fn(file); + }); + }); +}; + +/** + * Ignored files. + */ + +function ignored(path){ + return !~ignore.indexOf(path); +} + +/** + * Lookup files in the given `dir`. + * + * @return {Array} + * @api private + */ + +exports.files = function(dir, ret){ + ret = ret || []; + + fs.readdirSync(dir) + .filter(ignored) + .forEach(function(path){ + path = join(dir, path); + if (fs.statSync(path).isDirectory()) { + exports.files(path, ret); + } else if (path.match(/\.(js|coffee|litcoffee|coffee.md)$/)) { + ret.push(path); + } + }); + + return ret; +}; + +/** + * Compute a slug from the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.slug = function(str){ + return str + .toLowerCase() + .replace(/ +/g, '-') + .replace(/[^-\w]/g, ''); +}; + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +exports.clean = function(str) { + str = str + .replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '') + .replace(/^function *\(.*\) *{/, '') + .replace(/\s+\}$/, ''); + + var spaces = str.match(/^\n?( *)/)[1].length + , tabs = str.match(/^\n?(\t*)/)[1].length + , re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm'); + + str = str.replace(re, ''); + + return exports.trim(str); +}; + +/** + * Escape regular expression characters in `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.escapeRegexp = function(str){ + return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); +}; + +/** + * Trim the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.trim = function(str){ + return str.replace(/^\s+|\s+$/g, ''); +}; + +/** + * Parse the given `qs`. + * + * @param {String} qs + * @return {Object} + * @api private + */ + +exports.parseQuery = function(qs){ + return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){ + var i = pair.indexOf('=') + , key = pair.slice(0, i) + , val = pair.slice(++i); + + obj[key] = decodeURIComponent(val); + return obj; + }, {}); +}; + +/** + * Highlight the given string of `js`. + * + * @param {String} js + * @return {String} + * @api private + */ + +function highlight(js) { + return js + .replace(//g, '>') + .replace(/\/\/(.*)/gm, '//$1') + .replace(/('.*?')/gm, '$1') + .replace(/(\d+\.\d+)/gm, '$1') + .replace(/(\d+)/gm, '$1') + .replace(/\bnew *(\w+)/gm, 'new $1') + .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') +} + +/** + * Highlight the contents of tag `name`. + * + * @param {String} name + * @api private + */ + +exports.highlightTags = function(name) { + var code = document.getElementsByTagName(name); + for (var i = 0, len = code.length; i < len; ++i) { + code[i].innerHTML = highlight(code[i].innerHTML); + } +}; + +}); // module: utils.js +// The global object is "self" in Web Workers. +global = (function() { return this; })(); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date; +var setTimeout = global.setTimeout; +var setInterval = global.setInterval; +var clearTimeout = global.clearTimeout; +var clearInterval = global.clearInterval; + +/** + * Node shims. + * + * These are meant only to allow + * mocha.js to run untouched, not + * to allow running node code in + * the browser. + */ + +var process = {}; +process.exit = function(status){}; +process.stdout = {}; + +var uncaughtExceptionHandlers = []; + +/** + * Remove uncaughtException listener. + */ + +process.removeListener = function(e, fn){ + if ('uncaughtException' == e) { + global.onerror = function() {}; + var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn); + if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); } + } +}; + +/** + * Implements uncaughtException listener. + */ + +process.on = function(e, fn){ + if ('uncaughtException' == e) { + global.onerror = function(err, url, line){ + fn(new Error(err + ' (' + url + ':' + line + ')')); + return true; + }; + uncaughtExceptionHandlers.push(fn); + } +}; + +/** + * Expose mocha. + */ + +var Mocha = global.Mocha = require('mocha'), + mocha = global.mocha = new Mocha({ reporter: 'html' }); + +// The BDD UI is registered by default, but no UI will be functional in the +// browser without an explicit call to the overridden `mocha.ui` (see below). +// Ensure that this default UI does not expose its methods to the global scope. +mocha.suite.removeAllListeners('pre-require'); + +var immediateQueue = [] + , immediateTimeout; + +function timeslice() { + var immediateStart = new Date().getTime(); + while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) { + immediateQueue.shift()(); + } + if (immediateQueue.length) { + immediateTimeout = setTimeout(timeslice, 0); + } else { + immediateTimeout = null; + } +} + +/** + * High-performance override of Runner.immediately. + */ + +Mocha.Runner.immediately = function(callback) { + immediateQueue.push(callback); + if (!immediateTimeout) { + immediateTimeout = setTimeout(timeslice, 0); + } +}; + +/** + * Function to allow assertion libraries to throw errors directly into mocha. + * This is useful when running tests in a browser because window.onerror will + * only receive the 'message' attribute of the Error. + */ +mocha.throwError = function(err) { + Mocha.utils.forEach(uncaughtExceptionHandlers, function (fn) { + fn(err); + }); + throw err; +}; + +/** + * Override ui to ensure that the ui functions are initialized. + * Normally this would happen in Mocha.prototype.loadFiles. + */ + +mocha.ui = function(ui){ + Mocha.prototype.ui.call(this, ui); + this.suite.emit('pre-require', global, null, this); + return this; +}; + +/** + * Setup mocha with the given setting options. + */ + +mocha.setup = function(opts){ + if ('string' == typeof opts) opts = { ui: opts }; + for (var opt in opts) this[opt](opts[opt]); + return this; +}; + +/** + * Run mocha, returning the Runner. + */ + +mocha.run = function(fn){ + var options = mocha.options; + mocha.globals('location'); + + var query = Mocha.utils.parseQuery(global.location.search || ''); + if (query.grep) mocha.grep(query.grep); + if (query.invert) mocha.invert(); + + return Mocha.prototype.run.call(mocha, function(){ + // The DOM Document is not available in Web Workers. + if (global.document) { + Mocha.utils.highlightTags('code'); + } + if (fn) fn(); + }); +}; + +/** + * Expose the process shim. + */ + +Mocha.process = process; +})();})(window||global||undefined); \ No newline at end of file diff --git a/tests/mocha/node_modules/commander/History.md b/tests/mocha/node_modules/commander/History.md new file mode 100644 index 0000000000..2e665828cf --- /dev/null +++ b/tests/mocha/node_modules/commander/History.md @@ -0,0 +1,179 @@ + +2.0.0 / 2013-07-18 +================== + + * remove input methods (.prompt, .confirm, etc) + +1.3.2 / 2013-07-18 +================== + + * add support for sub-commands to co-exist with the original command + +1.3.1 / 2013-07-18 +================== + + * add quick .runningCommand hack so you can opt-out of other logic when running a sub command + +1.3.0 / 2013-07-09 +================== + + * add EACCES error handling + * fix sub-command --help + +1.2.0 / 2013-06-13 +================== + + * allow "-" hyphen as an option argument + * support for RegExp coercion + +1.1.1 / 2012-11-20 +================== + + * add more sub-command padding + * fix .usage() when args are present. Closes #106 + +1.1.0 / 2012-11-16 +================== + + * add git-style executable subcommand support. Closes #94 + +1.0.5 / 2012-10-09 +================== + + * fix `--name` clobbering. Closes #92 + * fix examples/help. Closes #89 + +1.0.4 / 2012-09-03 +================== + + * add `outputHelp()` method. + +1.0.3 / 2012-08-30 +================== + + * remove invalid .version() defaulting + +1.0.2 / 2012-08-24 +================== + + * add `--foo=bar` support [arv] + * fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus] + +1.0.1 / 2012-08-03 +================== + + * fix issue #56 + * fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode()) + +1.0.0 / 2012-07-05 +================== + + * add support for optional option descriptions + * add defaulting of `.version()` to package.json's version + +0.6.1 / 2012-06-01 +================== + + * Added: append (yes or no) on confirmation + * Added: allow node.js v0.7.x + +0.6.0 / 2012-04-10 +================== + + * Added `.prompt(obj, callback)` support. Closes #49 + * Added default support to .choose(). Closes #41 + * Fixed the choice example + +0.5.1 / 2011-12-20 +================== + + * Fixed `password()` for recent nodes. Closes #36 + +0.5.0 / 2011-12-04 +================== + + * Added sub-command option support [itay] + +0.4.3 / 2011-12-04 +================== + + * Fixed custom help ordering. Closes #32 + +0.4.2 / 2011-11-24 +================== + + * Added travis support + * Fixed: line-buffered input automatically trimmed. Closes #31 + +0.4.1 / 2011-11-18 +================== + + * Removed listening for "close" on --help + +0.4.0 / 2011-11-15 +================== + + * Added support for `--`. Closes #24 + +0.3.3 / 2011-11-14 +================== + + * Fixed: wait for close event when writing help info [Jerry Hamlet] + +0.3.2 / 2011-11-01 +================== + + * Fixed long flag definitions with values [felixge] + +0.3.1 / 2011-10-31 +================== + + * Changed `--version` short flag to `-V` from `-v` + * Changed `.version()` so it's configurable [felixge] + +0.3.0 / 2011-10-31 +================== + + * Added support for long flags only. Closes #18 + +0.2.1 / 2011-10-24 +================== + + * "node": ">= 0.4.x < 0.7.0". Closes #20 + +0.2.0 / 2011-09-26 +================== + + * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs] + +0.1.0 / 2011-08-24 +================== + + * Added support for custom `--help` output + +0.0.5 / 2011-08-18 +================== + + * Changed: when the user enters nothing prompt for password again + * Fixed issue with passwords beginning with numbers [NuckChorris] + +0.0.4 / 2011-08-15 +================== + + * Fixed `Commander#args` + +0.0.3 / 2011-08-15 +================== + + * Added default option value support + +0.0.2 / 2011-08-15 +================== + + * Added mask support to `Command#password(str[, mask], fn)` + * Added `Command#password(str, fn)` + +0.0.1 / 2010-01-03 +================== + + * Initial release diff --git a/tests/mocha/node_modules/commander/Readme.md b/tests/mocha/node_modules/commander/Readme.md new file mode 100644 index 0000000000..d1644012c5 --- /dev/null +++ b/tests/mocha/node_modules/commander/Readme.md @@ -0,0 +1,195 @@ +# Commander.js + + The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander). + + [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js) + +## Installation + + $ npm install commander + +## Option parsing + + Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('commander'); + +program + .version('0.0.1') + .option('-p, --peppers', 'Add peppers') + .option('-P, --pineapple', 'Add pineapple') + .option('-b, --bbq', 'Add bbq sauce') + .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') + .parse(process.argv); + +console.log('you ordered a pizza with:'); +if (program.peppers) console.log(' - peppers'); +if (program.pineapple) console.log(' - pineapple'); +if (program.bbq) console.log(' - bbq'); +console.log(' - %s cheese', program.cheese); +``` + + Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. + +## Automated --help + + The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free: + +``` + $ ./examples/pizza --help + + Usage: pizza [options] + + Options: + + -V, --version output the version number + -p, --peppers Add peppers + -P, --pineapple Add pineapple + -b, --bbq Add bbq sauce + -c, --cheese Add the specified type of cheese [marble] + -h, --help output usage information + +``` + +## Coercion + +```js +function range(val) { + return val.split('..').map(Number); +} + +function list(val) { + return val.split(','); +} + +program + .version('0.0.1') + .usage('[options] ') + .option('-i, --integer ', 'An integer argument', parseInt) + .option('-f, --float ', 'A float argument', parseFloat) + .option('-r, --range ..', 'A range', range) + .option('-l, --list ', 'A list', list) + .option('-o, --optional [value]', 'An optional value') + .parse(process.argv); + +console.log(' int: %j', program.integer); +console.log(' float: %j', program.float); +console.log(' optional: %j', program.optional); +program.range = program.range || []; +console.log(' range: %j..%j', program.range[0], program.range[1]); +console.log(' list: %j', program.list); +console.log(' args: %j', program.args); +``` + +## Custom help + + You can display arbitrary `-h, --help` information + by listening for "--help". Commander will automatically + exit once you are done so that the remainder of your program + does not execute causing undesired behaviours, for example + in the following executable "stuff" will not output when + `--help` is used. + +```js +#!/usr/bin/env node + +/** + * Module dependencies. + */ + +var program = require('../'); + +function list(val) { + return val.split(',').map(Number); +} + +program + .version('0.0.1') + .option('-f, --foo', 'enable some foo') + .option('-b, --bar', 'enable some bar') + .option('-B, --baz', 'enable some baz'); + +// must be before .parse() since +// node's emit() is immediate + +program.on('--help', function(){ + console.log(' Examples:'); + console.log(''); + console.log(' $ custom-help --help'); + console.log(' $ custom-help -h'); + console.log(''); +}); + +program.parse(process.argv); + +console.log('stuff'); +``` + +yielding the following help output: + +``` + +Usage: custom-help [options] + +Options: + + -h, --help output usage information + -V, --version output the version number + -f, --foo enable some foo + -b, --bar enable some bar + -B, --baz enable some baz + +Examples: + + $ custom-help --help + $ custom-help -h + +``` + +## .outputHelp() + + Output help information without exiting. + +## .help() + + Output help information and exit immediately. + +## Links + + - [API documentation](http://visionmedia.github.com/commander.js/) + - [ascii tables](https://github.com/LearnBoost/cli-table) + - [progress bars](https://github.com/visionmedia/node-progress) + - [more progress bars](https://github.com/substack/node-multimeter) + - [examples](https://github.com/visionmedia/commander.js/tree/master/examples) + +## License + +(The MIT License) + +Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> + +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 copies 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 all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 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. diff --git a/tests/mocha/node_modules/commander/index.js b/tests/mocha/node_modules/commander/index.js new file mode 100644 index 0000000000..d5778a75ba --- /dev/null +++ b/tests/mocha/node_modules/commander/index.js @@ -0,0 +1,847 @@ + +/** + * Module dependencies. + */ + +var EventEmitter = require('events').EventEmitter; +var spawn = require('child_process').spawn; +var fs = require('fs'); +var exists = fs.existsSync; +var path = require('path'); +var dirname = path.dirname; +var basename = path.basename; + +/** + * Expose the root command. + */ + +exports = module.exports = new Command; + +/** + * Expose `Command`. + */ + +exports.Command = Command; + +/** + * Expose `Option`. + */ + +exports.Option = Option; + +/** + * Initialize a new `Option` with the given `flags` and `description`. + * + * @param {String} flags + * @param {String} description + * @api public + */ + +function Option(flags, description) { + this.flags = flags; + this.required = ~flags.indexOf('<'); + this.optional = ~flags.indexOf('['); + this.bool = !~flags.indexOf('-no-'); + flags = flags.split(/[ ,|]+/); + if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift(); + this.long = flags.shift(); + this.description = description || ''; +} + +/** + * Return option name. + * + * @return {String} + * @api private + */ + +Option.prototype.name = function(){ + return this.long + .replace('--', '') + .replace('no-', ''); +}; + +/** + * Check if `arg` matches the short or long flag. + * + * @param {String} arg + * @return {Boolean} + * @api private + */ + +Option.prototype.is = function(arg){ + return arg == this.short + || arg == this.long; +}; + +/** + * Initialize a new `Command`. + * + * @param {String} name + * @api public + */ + +function Command(name) { + this.commands = []; + this.options = []; + this._execs = []; + this._args = []; + this._name = name; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +Command.prototype.__proto__ = EventEmitter.prototype; + +/** + * Add command `name`. + * + * The `.action()` callback is invoked when the + * command `name` is specified via __ARGV__, + * and the remaining arguments are applied to the + * function for access. + * + * When the `name` is "*" an un-matched command + * will be passed as the first arg, followed by + * the rest of __ARGV__ remaining. + * + * Examples: + * + * program + * .version('0.0.1') + * .option('-C, --chdir ', 'change the working directory') + * .option('-c, --config ', 'set config path. defaults to ./deploy.conf') + * .option('-T, --no-tests', 'ignore test hook') + * + * program + * .command('setup') + * .description('run remote setup commands') + * .action(function(){ + * console.log('setup'); + * }); + * + * program + * .command('exec ') + * .description('run the given remote command') + * .action(function(cmd){ + * console.log('exec "%s"', cmd); + * }); + * + * program + * .command('*') + * .description('deploy the given env') + * .action(function(env){ + * console.log('deploying "%s"', env); + * }); + * + * program.parse(process.argv); + * + * @param {String} name + * @param {String} [desc] + * @return {Command} the new command + * @api public + */ + +Command.prototype.command = function(name, desc){ + var args = name.split(/ +/); + var cmd = new Command(args.shift()); + if (desc) cmd.description(desc); + if (desc) this.executables = true; + if (desc) this._execs[cmd._name] = true; + this.commands.push(cmd); + cmd.parseExpectedArgs(args); + cmd.parent = this; + if (desc) return this; + return cmd; +}; + +/** + * Add an implicit `help [cmd]` subcommand + * which invokes `--help` for the given command. + * + * @api private + */ + +Command.prototype.addImplicitHelpCommand = function() { + this.command('help [cmd]', 'display help for [cmd]'); +}; + +/** + * Parse expected `args`. + * + * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`. + * + * @param {Array} args + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parseExpectedArgs = function(args){ + if (!args.length) return; + var self = this; + args.forEach(function(arg){ + switch (arg[0]) { + case '<': + self._args.push({ required: true, name: arg.slice(1, -1) }); + break; + case '[': + self._args.push({ required: false, name: arg.slice(1, -1) }); + break; + } + }); + return this; +}; + +/** + * Register callback `fn` for the command. + * + * Examples: + * + * program + * .command('help') + * .description('display verbose help') + * .action(function(){ + * // output help here + * }); + * + * @param {Function} fn + * @return {Command} for chaining + * @api public + */ + +Command.prototype.action = function(fn){ + var self = this; + this.parent.on(this._name, function(args, unknown){ + // Parse any so-far unknown options + unknown = unknown || []; + var parsed = self.parseOptions(unknown); + + // Output help if necessary + outputHelpIfNecessary(self, parsed.unknown); + + // If there are still any unknown options, then we simply + // die, unless someone asked for help, in which case we give it + // to them, and then we die. + if (parsed.unknown.length > 0) { + self.unknownOption(parsed.unknown[0]); + } + + // Leftover arguments need to be pushed back. Fixes issue #56 + if (parsed.args.length) args = parsed.args.concat(args); + + self._args.forEach(function(arg, i){ + if (arg.required && null == args[i]) { + self.missingArgument(arg.name); + } + }); + + // Always append ourselves to the end of the arguments, + // to make sure we match the number of arguments the user + // expects + if (self._args.length) { + args[self._args.length] = self; + } else { + args.push(self); + } + + fn.apply(this, args); + }); + return this; +}; + +/** + * Define option with `flags`, `description` and optional + * coercion `fn`. + * + * The `flags` string should contain both the short and long flags, + * separated by comma, a pipe or space. The following are all valid + * all will output this way when `--help` is used. + * + * "-p, --pepper" + * "-p|--pepper" + * "-p --pepper" + * + * Examples: + * + * // simple boolean defaulting to false + * program.option('-p, --pepper', 'add pepper'); + * + * --pepper + * program.pepper + * // => Boolean + * + * // simple boolean defaulting to false + * program.option('-C, --no-cheese', 'remove cheese'); + * + * program.cheese + * // => true + * + * --no-cheese + * program.cheese + * // => true + * + * // required argument + * program.option('-C, --chdir ', 'change the working directory'); + * + * --chdir /tmp + * program.chdir + * // => "/tmp" + * + * // optional argument + * program.option('-c, --cheese [type]', 'add cheese [marble]'); + * + * @param {String} flags + * @param {String} description + * @param {Function|Mixed} fn or default + * @param {Mixed} defaultValue + * @return {Command} for chaining + * @api public + */ + +Command.prototype.option = function(flags, description, fn, defaultValue){ + var self = this + , option = new Option(flags, description) + , oname = option.name() + , name = camelcase(oname); + + // default as 3rd arg + if ('function' != typeof fn) defaultValue = fn, fn = null; + + // preassign default value only for --no-*, [optional], or + if (false == option.bool || option.optional || option.required) { + // when --no-* we make sure default is true + if (false == option.bool) defaultValue = true; + // preassign only if we have a default + if (undefined !== defaultValue) self[name] = defaultValue; + } + + // register the option + this.options.push(option); + + // when it's passed assign the value + // and conditionally invoke the callback + this.on(oname, function(val){ + // coercion + if (null != val && fn) val = fn(val); + + // unassigned or bool + if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) { + // if no value, bool true, and we have a default, then use it! + if (null == val) { + self[name] = option.bool + ? defaultValue || true + : false; + } else { + self[name] = val; + } + } else if (null !== val) { + // reassign + self[name] = val; + } + }); + + return this; +}; + +/** + * Parse `argv`, settings options and invoking commands when defined. + * + * @param {Array} argv + * @return {Command} for chaining + * @api public + */ + +Command.prototype.parse = function(argv){ + // implicit help + if (this.executables) this.addImplicitHelpCommand(); + + // store raw args + this.rawArgs = argv; + + // guess name + this._name = this._name || basename(argv[1]); + + // process argv + var parsed = this.parseOptions(this.normalize(argv.slice(2))); + var args = this.args = parsed.args; + + var result = this.parseArgs(this.args, parsed.unknown); + + // executable sub-commands + var name = result.args[0]; + if (this._execs[name]) return this.executeSubCommand(argv, args, parsed.unknown); + + return result; +}; + +/** + * Execute a sub-command executable. + * + * @param {Array} argv + * @param {Array} args + * @param {Array} unknown + * @api private + */ + +Command.prototype.executeSubCommand = function(argv, args, unknown) { + args = args.concat(unknown); + + if (!args.length) this.help(); + if ('help' == args[0] && 1 == args.length) this.help(); + + // --help + if ('help' == args[0]) { + args[0] = args[1]; + args[1] = '--help'; + } + + // executable + var dir = dirname(argv[1]); + var bin = basename(argv[1]) + '-' + args[0]; + + // check for ./ first + var local = path.join(dir, bin); + + // run it + args = args.slice(1); + var proc = spawn(local, args, { stdio: 'inherit', customFds: [0, 1, 2] }); + proc.on('error', function(err){ + if (err.code == "ENOENT") { + console.error('\n %s(1) does not exist, try --help\n', bin); + } else if (err.code == "EACCES") { + console.error('\n %s(1) not executable. try chmod or run with root\n', bin); + } + }); + + this.runningCommand = proc; +}; + +/** + * Normalize `args`, splitting joined short flags. For example + * the arg "-abc" is equivalent to "-a -b -c". + * This also normalizes equal sign and splits "--abc=def" into "--abc def". + * + * @param {Array} args + * @return {Array} + * @api private + */ + +Command.prototype.normalize = function(args){ + var ret = [] + , arg + , index; + + for (var i = 0, len = args.length; i < len; ++i) { + arg = args[i]; + if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) { + arg.slice(1).split('').forEach(function(c){ + ret.push('-' + c); + }); + } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) { + ret.push(arg.slice(0, index), arg.slice(index + 1)); + } else { + ret.push(arg); + } + } + + return ret; +}; + +/** + * Parse command `args`. + * + * When listener(s) are available those + * callbacks are invoked, otherwise the "*" + * event is emitted and those actions are invoked. + * + * @param {Array} args + * @return {Command} for chaining + * @api private + */ + +Command.prototype.parseArgs = function(args, unknown){ + var cmds = this.commands + , len = cmds.length + , name; + + if (args.length) { + name = args[0]; + if (this.listeners(name).length) { + this.emit(args.shift(), args, unknown); + } else { + this.emit('*', args); + } + } else { + outputHelpIfNecessary(this, unknown); + + // If there were no args and we have unknown options, + // then they are extraneous and we need to error. + if (unknown.length > 0) { + this.unknownOption(unknown[0]); + } + } + + return this; +}; + +/** + * Return an option matching `arg` if any. + * + * @param {String} arg + * @return {Option} + * @api private + */ + +Command.prototype.optionFor = function(arg){ + for (var i = 0, len = this.options.length; i < len; ++i) { + if (this.options[i].is(arg)) { + return this.options[i]; + } + } +}; + +/** + * Parse options from `argv` returning `argv` + * void of these options. + * + * @param {Array} argv + * @return {Array} + * @api public + */ + +Command.prototype.parseOptions = function(argv){ + var args = [] + , len = argv.length + , literal + , option + , arg; + + var unknownOptions = []; + + // parse options + for (var i = 0; i < len; ++i) { + arg = argv[i]; + + // literal args after -- + if ('--' == arg) { + literal = true; + continue; + } + + if (literal) { + args.push(arg); + continue; + } + + // find matching Option + option = this.optionFor(arg); + + // option is defined + if (option) { + // requires arg + if (option.required) { + arg = argv[++i]; + if (null == arg) return this.optionMissingArgument(option); + if ('-' == arg[0] && '-' != arg) return this.optionMissingArgument(option, arg); + this.emit(option.name(), arg); + // optional arg + } else if (option.optional) { + arg = argv[i+1]; + if (null == arg || ('-' == arg[0] && '-' != arg)) { + arg = null; + } else { + ++i; + } + this.emit(option.name(), arg); + // bool + } else { + this.emit(option.name()); + } + continue; + } + + // looks like an option + if (arg.length > 1 && '-' == arg[0]) { + unknownOptions.push(arg); + + // If the next argument looks like it might be + // an argument for this option, we pass it on. + // If it isn't, then it'll simply be ignored + if (argv[i+1] && '-' != argv[i+1][0]) { + unknownOptions.push(argv[++i]); + } + continue; + } + + // arg + args.push(arg); + } + + return { args: args, unknown: unknownOptions }; +}; + +/** + * Argument `name` is missing. + * + * @param {String} name + * @api private + */ + +Command.prototype.missingArgument = function(name){ + console.error(); + console.error(" error: missing required argument `%s'", name); + console.error(); + process.exit(1); +}; + +/** + * `Option` is missing an argument, but received `flag` or nothing. + * + * @param {String} option + * @param {String} flag + * @api private + */ + +Command.prototype.optionMissingArgument = function(option, flag){ + console.error(); + if (flag) { + console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag); + } else { + console.error(" error: option `%s' argument missing", option.flags); + } + console.error(); + process.exit(1); +}; + +/** + * Unknown option `flag`. + * + * @param {String} flag + * @api private + */ + +Command.prototype.unknownOption = function(flag){ + console.error(); + console.error(" error: unknown option `%s'", flag); + console.error(); + process.exit(1); +}; + + +/** + * Set the program version to `str`. + * + * This method auto-registers the "-V, --version" flag + * which will print the version number when passed. + * + * @param {String} str + * @param {String} flags + * @return {Command} for chaining + * @api public + */ + +Command.prototype.version = function(str, flags){ + if (0 == arguments.length) return this._version; + this._version = str; + flags = flags || '-V, --version'; + this.option(flags, 'output the version number'); + this.on('version', function(){ + console.log(str); + process.exit(0); + }); + return this; +}; + +/** + * Set the description `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.description = function(str){ + if (0 == arguments.length) return this._description; + this._description = str; + return this; +}; + +/** + * Set / get the command usage `str`. + * + * @param {String} str + * @return {String|Command} + * @api public + */ + +Command.prototype.usage = function(str){ + var args = this._args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }); + + var usage = '[options' + + (this.commands.length ? '] [command' : '') + + ']' + + (this._args.length ? ' ' + args : ''); + + if (0 == arguments.length) return this._usage || usage; + this._usage = str; + + return this; +}; + +/** + * Return the largest option length. + * + * @return {Number} + * @api private + */ + +Command.prototype.largestOptionLength = function(){ + return this.options.reduce(function(max, option){ + return Math.max(max, option.flags.length); + }, 0); +}; + +/** + * Return help for options. + * + * @return {String} + * @api private + */ + +Command.prototype.optionHelp = function(){ + var width = this.largestOptionLength(); + + // Prepend the help information + return [pad('-h, --help', width) + ' ' + 'output usage information'] + .concat(this.options.map(function(option){ + return pad(option.flags, width) + + ' ' + option.description; + })) + .join('\n'); +}; + +/** + * Return command help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.commandHelp = function(){ + if (!this.commands.length) return ''; + return [ + '' + , ' Commands:' + , '' + , this.commands.map(function(cmd){ + var args = cmd._args.map(function(arg){ + return arg.required + ? '<' + arg.name + '>' + : '[' + arg.name + ']'; + }).join(' '); + + return pad(cmd._name + + (cmd.options.length + ? ' [options]' + : '') + ' ' + args, 22) + + (cmd.description() + ? ' ' + cmd.description() + : ''); + }).join('\n').replace(/^/gm, ' ') + , '' + ].join('\n'); +}; + +/** + * Return program help documentation. + * + * @return {String} + * @api private + */ + +Command.prototype.helpInformation = function(){ + return [ + '' + , ' Usage: ' + this._name + ' ' + this.usage() + , '' + this.commandHelp() + , ' Options:' + , '' + , '' + this.optionHelp().replace(/^/gm, ' ') + , '' + , '' + ].join('\n'); +}; + +/** + * Output help information for this command + * + * @api public + */ + +Command.prototype.outputHelp = function(){ + process.stdout.write(this.helpInformation()); + this.emit('--help'); +}; + +/** + * Output help information and exit. + * + * @api public + */ + +Command.prototype.help = function(){ + this.outputHelp(); + process.exit(); +}; + +/** + * Camel-case the given `flag` + * + * @param {String} flag + * @return {String} + * @api private + */ + +function camelcase(flag) { + return flag.split('-').reduce(function(str, word){ + return str + word[0].toUpperCase() + word.slice(1); + }); +} + +/** + * Pad `str` to `width`. + * + * @param {String} str + * @param {Number} width + * @return {String} + * @api private + */ + +function pad(str, width) { + var len = Math.max(0, width - str.length); + return str + Array(len + 1).join(' '); +} + +/** + * Output help information if necessary + * + * @param {Command} command to output help for + * @param {Array} array of options to search for -h or --help + * @api private + */ + +function outputHelpIfNecessary(cmd, options) { + options = options || []; + for (var i = 0; i < options.length; i++) { + if (options[i] == '--help' || options[i] == '-h') { + cmd.outputHelp(); + process.exit(0); + } + } +} diff --git a/tests/mocha/node_modules/commander/package.json b/tests/mocha/node_modules/commander/package.json new file mode 100644 index 0000000000..e25ed273ff --- /dev/null +++ b/tests/mocha/node_modules/commander/package.json @@ -0,0 +1,38 @@ +{ + "name": "commander", + "version": "2.0.0", + "description": "the complete solution for node.js command-line programs", + "keywords": [ + "command", + "option", + "parser", + "prompt", + "stdin" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "repository": { + "type": "git", + "url": "https://github.com/visionmedia/commander.js.git" + }, + "devDependencies": { + "should": ">= 0.0.1" + }, + "scripts": { + "test": "make test" + }, + "main": "index", + "engines": { + "node": ">= 0.6.x" + }, + "readme": "# Commander.js\n\n The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).\n\n [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)\n\n## Installation\n\n $ npm install commander\n\n## Option parsing\n\n Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('commander');\n\nprogram\n .version('0.0.1')\n .option('-p, --peppers', 'Add peppers')\n .option('-P, --pineapple', 'Add pineapple')\n .option('-b, --bbq', 'Add bbq sauce')\n .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')\n .parse(process.argv);\n\nconsole.log('you ordered a pizza with:');\nif (program.peppers) console.log(' - peppers');\nif (program.pineapple) console.log(' - pineapple');\nif (program.bbq) console.log(' - bbq');\nconsole.log(' - %s cheese', program.cheese);\n```\n\n Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as \"--template-engine\" are camel-cased, becoming `program.templateEngine` etc.\n\n## Automated --help\n\n The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:\n\n``` \n $ ./examples/pizza --help\n\n Usage: pizza [options]\n\n Options:\n\n -V, --version output the version number\n -p, --peppers Add peppers\n -P, --pineapple Add pineapple\n -b, --bbq Add bbq sauce\n -c, --cheese Add the specified type of cheese [marble]\n -h, --help output usage information\n\n```\n\n## Coercion\n\n```js\nfunction range(val) {\n return val.split('..').map(Number);\n}\n\nfunction list(val) {\n return val.split(',');\n}\n\nprogram\n .version('0.0.1')\n .usage('[options] ')\n .option('-i, --integer ', 'An integer argument', parseInt)\n .option('-f, --float ', 'A float argument', parseFloat)\n .option('-r, --range ..', 'A range', range)\n .option('-l, --list ', 'A list', list)\n .option('-o, --optional [value]', 'An optional value')\n .parse(process.argv);\n\nconsole.log(' int: %j', program.integer);\nconsole.log(' float: %j', program.float);\nconsole.log(' optional: %j', program.optional);\nprogram.range = program.range || [];\nconsole.log(' range: %j..%j', program.range[0], program.range[1]);\nconsole.log(' list: %j', program.list);\nconsole.log(' args: %j', program.args);\n```\n\n## Custom help\n\n You can display arbitrary `-h, --help` information\n by listening for \"--help\". Commander will automatically\n exit once you are done so that the remainder of your program\n does not execute causing undesired behaviours, for example\n in the following executable \"stuff\" will not output when\n `--help` is used.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('../');\n\nfunction list(val) {\n return val.split(',').map(Number);\n}\n\nprogram\n .version('0.0.1')\n .option('-f, --foo', 'enable some foo')\n .option('-b, --bar', 'enable some bar')\n .option('-B, --baz', 'enable some baz');\n\n// must be before .parse() since\n// node's emit() is immediate\n\nprogram.on('--help', function(){\n console.log(' Examples:');\n console.log('');\n console.log(' $ custom-help --help');\n console.log(' $ custom-help -h');\n console.log('');\n});\n\nprogram.parse(process.argv);\n\nconsole.log('stuff');\n```\n\nyielding the following help output:\n\n```\n\nUsage: custom-help [options]\n\nOptions:\n\n -h, --help output usage information\n -V, --version output the version number\n -f, --foo enable some foo\n -b, --bar enable some bar\n -B, --baz enable some baz\n\nExamples:\n\n $ custom-help --help\n $ custom-help -h\n\n```\n\n## .outputHelp()\n\n Output help information without exiting.\n\n## .help()\n\n Output help information and exit immediately.\n\n## Links\n\n - [API documentation](http://visionmedia.github.com/commander.js/)\n - [ascii tables](https://github.com/LearnBoost/cli-table)\n - [progress bars](https://github.com/visionmedia/node-progress)\n - [more progress bars](https://github.com/substack/node-multimeter)\n - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/commander.js/issues" + }, + "homepage": "https://github.com/visionmedia/commander.js", + "_id": "commander@2.0.0", + "_from": "commander@2.0.0" +} diff --git a/tests/mocha/node_modules/diff/README.md b/tests/mocha/node_modules/diff/README.md new file mode 100644 index 0000000000..95bd8da294 --- /dev/null +++ b/tests/mocha/node_modules/diff/README.md @@ -0,0 +1,101 @@ +# jsdiff + +[![Build Status](https://secure.travis-ci.org/kpdecker/jsdiff.png)](http://travis-ci.org/kpdecker/jsdiff) + +A javascript text differencing implementation. + +Based on the algorithm proposed in +["An O(ND) Difference Algorithm and its Variations" (Myers, 1986)](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927). + +## Installation + + npm install diff + +or + + git clone git://github.com/kpdecker/jsdiff.git + +## API + +* JsDiff.diffChars(oldStr, newStr) + Diffs two blocks of text, comparing character by character. + + Returns a list of change objects (See below). + +* JsDiff.diffWords(oldStr, newStr) + Diffs two blocks of text, comparing word by word. + + Returns a list of change objects (See below). + +* JsDiff.diffLines(oldStr, newStr) + Diffs two blocks of text, comparing line by line. + + Returns a list of change objects (See below). + +* JsDiff.diffCss(oldStr, newStr) + Diffs two blocks of text, comparing CSS tokens. + + Returns a list of change objects (See below). + +* JsDiff.createPatch(fileName, oldStr, newStr, oldHeader, newHeader) + Creates a unified diff patch. + + Parameters: + * fileName : String to be output in the filename sections of the patch + * oldStr : Original string value + * newStr : New string value + * oldHeader : Additional information to include in the old file header + * newHeader : Additional information to include in thew new file header + +* JsDiff.applyPatch(oldStr, diffStr) + Applies a unified diff patch. + + Return a string containing new version of provided data. + +* convertChangesToXML(changes) + Converts a list of changes to a serialized XML format + +### Change Objects +Many of the methods above return change objects. These objects are consist of the following fields: + +* value: Text content +* added: True if the value was inserted into the new string +* removed: True of the value was removed from the old string + +Note that some cases may omit a particular flag field. Comparison on the flag fields should always be done in a truthy or falsy manner. + +## [Example](http://kpdecker.github.com/jsdiff) + +## License + +Software License Agreement (BSD License) + +Copyright (c) 2009-2011, Kevin Decker kpdecker@gmail.com + +All rights reserved. + +Redistribution and use of this software in source and binary forms, with or without modification, +are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above + copyright notice, this list of conditions and the + following disclaimer. + +* Redistributions in binary form must reproduce the above + copyright notice, this list of conditions and the + following disclaimer in the documentation and/or other + materials provided with the distribution. + +* Neither the name of Kevin Decker nor the names of its + contributors may be used to endorse or promote products + derived from this software without specific prior + written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR +IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER +IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT +OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/mocha/node_modules/diff/diff.js b/tests/mocha/node_modules/diff/diff.js new file mode 100644 index 0000000000..a34c22a044 --- /dev/null +++ b/tests/mocha/node_modules/diff/diff.js @@ -0,0 +1,354 @@ +/* See LICENSE file for terms of use */ + +/* + * Text diff implementation. + * + * This library supports the following APIS: + * JsDiff.diffChars: Character by character diff + * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace + * JsDiff.diffLines: Line based diff + * + * JsDiff.diffCss: Diff targeted at CSS content + * + * These methods are based on the implementation proposed in + * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 + */ +var JsDiff = (function() { + /*jshint maxparams: 5*/ + function clonePath(path) { + return { newPos: path.newPos, components: path.components.slice(0) }; + } + function removeEmpty(array) { + var ret = []; + for (var i = 0; i < array.length; i++) { + if (array[i]) { + ret.push(array[i]); + } + } + return ret; + } + function escapeHTML(s) { + var n = s; + n = n.replace(/&/g, '&'); + n = n.replace(//g, '>'); + n = n.replace(/"/g, '"'); + + return n; + } + + var Diff = function(ignoreWhitespace) { + this.ignoreWhitespace = ignoreWhitespace; + }; + Diff.prototype = { + diff: function(oldString, newString) { + // Handle the identity case (this is due to unrolling editLength == 0 + if (newString === oldString) { + return [{ value: newString }]; + } + if (!newString) { + return [{ value: oldString, removed: true }]; + } + if (!oldString) { + return [{ value: newString, added: true }]; + } + + newString = this.tokenize(newString); + oldString = this.tokenize(oldString); + + var newLen = newString.length, oldLen = oldString.length; + var maxEditLength = newLen + oldLen; + var bestPath = [{ newPos: -1, components: [] }]; + + // Seed editLength = 0 + var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); + if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) { + return bestPath[0].components; + } + + for (var editLength = 1; editLength <= maxEditLength; editLength++) { + for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) { + var basePath; + var addPath = bestPath[diagonalPath-1], + removePath = bestPath[diagonalPath+1]; + oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; + if (addPath) { + // No one else is going to attempt to use this value, clear it + bestPath[diagonalPath-1] = undefined; + } + + var canAdd = addPath && addPath.newPos+1 < newLen; + var canRemove = removePath && 0 <= oldPos && oldPos < oldLen; + if (!canAdd && !canRemove) { + bestPath[diagonalPath] = undefined; + continue; + } + + // Select the diagonal that we want to branch from. We select the prior + // path whose position in the new string is the farthest from the origin + // and does not pass the bounds of the diff graph + if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { + basePath = clonePath(removePath); + this.pushComponent(basePath.components, oldString[oldPos], undefined, true); + } else { + basePath = clonePath(addPath); + basePath.newPos++; + this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined); + } + + var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath); + + if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) { + return basePath.components; + } else { + bestPath[diagonalPath] = basePath; + } + } + } + }, + + pushComponent: function(components, value, added, removed) { + var last = components[components.length-1]; + if (last && last.added === added && last.removed === removed) { + // We need to clone here as the component clone operation is just + // as shallow array clone + components[components.length-1] = + {value: this.join(last.value, value), added: added, removed: removed }; + } else { + components.push({value: value, added: added, removed: removed }); + } + }, + extractCommon: function(basePath, newString, oldString, diagonalPath) { + var newLen = newString.length, + oldLen = oldString.length, + newPos = basePath.newPos, + oldPos = newPos - diagonalPath; + while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) { + newPos++; + oldPos++; + + this.pushComponent(basePath.components, newString[newPos], undefined, undefined); + } + basePath.newPos = newPos; + return oldPos; + }, + + equals: function(left, right) { + var reWhitespace = /\S/; + if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) { + return true; + } else { + return left === right; + } + }, + join: function(left, right) { + return left + right; + }, + tokenize: function(value) { + return value; + } + }; + + var CharDiff = new Diff(); + + var WordDiff = new Diff(true); + var WordWithSpaceDiff = new Diff(); + WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { + return removeEmpty(value.split(/(\s+|\b)/)); + }; + + var CssDiff = new Diff(true); + CssDiff.tokenize = function(value) { + return removeEmpty(value.split(/([{}:;,]|\s+)/)); + }; + + var LineDiff = new Diff(); + LineDiff.tokenize = function(value) { + return value.split(/^/m); + }; + + return { + Diff: Diff, + + diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); }, + diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); }, + diffWordsWithSpace: function(oldStr, newStr) { return WordWithSpaceDiff.diff(oldStr, newStr); }, + diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); }, + + diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); }, + + createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { + var ret = []; + + ret.push('Index: ' + fileName); + ret.push('==================================================================='); + ret.push('--- ' + fileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); + ret.push('+++ ' + fileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); + + var diff = LineDiff.diff(oldStr, newStr); + if (!diff[diff.length-1].value) { + diff.pop(); // Remove trailing newline add + } + diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier + + function contextLines(lines) { + return lines.map(function(entry) { return ' ' + entry; }); + } + function eofNL(curRange, i, current) { + var last = diff[diff.length-2], + isLast = i === diff.length-2, + isLastOfType = i === diff.length-3 && (current.added !== last.added || current.removed !== last.removed); + + // Figure out if this is the last line for the given file and missing NL + if (!/\n$/.test(current.value) && (isLast || isLastOfType)) { + curRange.push('\\ No newline at end of file'); + } + } + + var oldRangeStart = 0, newRangeStart = 0, curRange = [], + oldLine = 1, newLine = 1; + for (var i = 0; i < diff.length; i++) { + var current = diff[i], + lines = current.lines || current.value.replace(/\n$/, '').split('\n'); + current.lines = lines; + + if (current.added || current.removed) { + if (!oldRangeStart) { + var prev = diff[i-1]; + oldRangeStart = oldLine; + newRangeStart = newLine; + + if (prev) { + curRange = contextLines(prev.lines.slice(-4)); + oldRangeStart -= curRange.length; + newRangeStart -= curRange.length; + } + } + curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?'+':'-') + entry; })); + eofNL(curRange, i, current); + + if (current.added) { + newLine += lines.length; + } else { + oldLine += lines.length; + } + } else { + if (oldRangeStart) { + // Close out any changes that have been output (or join overlapping) + if (lines.length <= 8 && i < diff.length-2) { + // Overlapping + curRange.push.apply(curRange, contextLines(lines)); + } else { + // end the range and output + var contextSize = Math.min(lines.length, 4); + ret.push( + '@@ -' + oldRangeStart + ',' + (oldLine-oldRangeStart+contextSize) + + ' +' + newRangeStart + ',' + (newLine-newRangeStart+contextSize) + + ' @@'); + ret.push.apply(ret, curRange); + ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); + if (lines.length <= 4) { + eofNL(ret, i, current); + } + + oldRangeStart = 0; newRangeStart = 0; curRange = []; + } + } + oldLine += lines.length; + newLine += lines.length; + } + } + + return ret.join('\n') + '\n'; + }, + + applyPatch: function(oldStr, uniDiff) { + var diffstr = uniDiff.split('\n'); + var diff = []; + var remEOFNL = false, + addEOFNL = false; + + for (var i = (diffstr[0][0]==='I'?4:0); i < diffstr.length; i++) { + if(diffstr[i][0] === '@') { + var meh = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); + diff.unshift({ + start:meh[3], + oldlength:meh[2], + oldlines:[], + newlength:meh[4], + newlines:[] + }); + } else if(diffstr[i][0] === '+') { + diff[0].newlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === '-') { + diff[0].oldlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === ' ') { + diff[0].newlines.push(diffstr[i].substr(1)); + diff[0].oldlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === '\\') { + if (diffstr[i-1][0] === '+') { + remEOFNL = true; + } else if(diffstr[i-1][0] === '-') { + addEOFNL = true; + } + } + } + + var str = oldStr.split('\n'); + for (var i = diff.length - 1; i >= 0; i--) { + var d = diff[i]; + for (var j = 0; j < d.oldlength; j++) { + if(str[d.start-1+j] !== d.oldlines[j]) { + return false; + } + } + Array.prototype.splice.apply(str,[d.start-1,+d.oldlength].concat(d.newlines)); + } + + if (remEOFNL) { + while (!str[str.length-1]) { + str.pop(); + } + } else if (addEOFNL) { + str.push(''); + } + return str.join('\n'); + }, + + convertChangesToXML: function(changes){ + var ret = []; + for ( var i = 0; i < changes.length; i++) { + var change = changes[i]; + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + + ret.push(escapeHTML(change.value)); + + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + } + return ret.join(''); + }, + + // See: http://code.google.com/p/google-diff-match-patch/wiki/API + convertChangesToDMP: function(changes){ + var ret = [], change; + for ( var i = 0; i < changes.length; i++) { + change = changes[i]; + ret.push([(change.added ? 1 : change.removed ? -1 : 0), change.value]); + } + return ret; + } + }; +})(); + +if (typeof module !== 'undefined') { + module.exports = JsDiff; +} diff --git a/tests/mocha/node_modules/diff/package.json b/tests/mocha/node_modules/diff/package.json new file mode 100644 index 0000000000..867fd0ce84 --- /dev/null +++ b/tests/mocha/node_modules/diff/package.json @@ -0,0 +1,51 @@ +{ + "name": "diff", + "version": "1.0.7", + "description": "A javascript text diff implementation.", + "keywords": [ + "diff", + "javascript" + ], + "maintainers": [ + { + "name": "Kevin Decker", + "email": "kpdecker@gmail.com", + "url": "http://incaseofstairs.com" + } + ], + "bugs": { + "url": "http://github.com/kpdecker/jsdiff/issues", + "email": "kpdecker@gmail.com" + }, + "licenses": [ + { + "type": "BSD", + "url": "http://github.com/kpdecker/jsdiff/blob/master/LICENSE" + } + ], + "repository": { + "type": "git", + "url": "git://github.com/kpdecker/jsdiff.git" + }, + "engines": { + "node": ">=0.3.1" + }, + "main": "./diff", + "scripts": { + "test": "mocha test/*.js" + }, + "dependencies": {}, + "devDependencies": { + "mocha": "~1.6", + "should": "~1.2" + }, + "optionalDependencies": {}, + "files": [ + "diff.js" + ], + "readme": "# jsdiff\n\n[![Build Status](https://secure.travis-ci.org/kpdecker/jsdiff.png)](http://travis-ci.org/kpdecker/jsdiff)\n\nA javascript text differencing implementation.\n\nBased on the algorithm proposed in\n[\"An O(ND) Difference Algorithm and its Variations\" (Myers, 1986)](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927).\n\n## Installation\n\n npm install diff\n\nor\n\n git clone git://github.com/kpdecker/jsdiff.git\n\n## API\n\n* JsDiff.diffChars(oldStr, newStr)\n Diffs two blocks of text, comparing character by character.\n\n Returns a list of change objects (See below).\n\n* JsDiff.diffWords(oldStr, newStr)\n Diffs two blocks of text, comparing word by word.\n\n Returns a list of change objects (See below).\n\n* JsDiff.diffLines(oldStr, newStr)\n Diffs two blocks of text, comparing line by line.\n\n Returns a list of change objects (See below).\n\n* JsDiff.diffCss(oldStr, newStr)\n Diffs two blocks of text, comparing CSS tokens.\n\n Returns a list of change objects (See below).\n\n* JsDiff.createPatch(fileName, oldStr, newStr, oldHeader, newHeader)\n Creates a unified diff patch.\n\n Parameters:\n * fileName : String to be output in the filename sections of the patch\n * oldStr : Original string value\n * newStr : New string value\n * oldHeader : Additional information to include in the old file header\n * newHeader : Additional information to include in thew new file header\n\n* JsDiff.applyPatch(oldStr, diffStr)\n Applies a unified diff patch.\n\n Return a string containing new version of provided data.\n\n* convertChangesToXML(changes)\n Converts a list of changes to a serialized XML format\n\n### Change Objects\nMany of the methods above return change objects. These objects are consist of the following fields:\n\n* value: Text content\n* added: True if the value was inserted into the new string\n* removed: True of the value was removed from the old string\n\nNote that some cases may omit a particular flag field. Comparison on the flag fields should always be done in a truthy or falsy manner.\n\n## [Example](http://kpdecker.github.com/jsdiff)\n\n## License\n\nSoftware License Agreement (BSD License)\n\nCopyright (c) 2009-2011, Kevin Decker kpdecker@gmail.com\n\nAll rights reserved.\n\nRedistribution and use of this software in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above\n copyright notice, this list of conditions and the\n following disclaimer.\n\n* Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the\n following disclaimer in the documentation and/or other\n materials provided with the distribution.\n\n* Neither the name of Kevin Decker nor the names of its\n contributors may be used to endorse or promote products\n derived from this software without specific prior\n written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\nCONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\nIN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\nOF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", + "readmeFilename": "README.md", + "homepage": "https://github.com/kpdecker/jsdiff", + "_id": "diff@1.0.7", + "_from": "diff@1.0.7" +} diff --git a/tests/mocha/node_modules/glob/.npmignore b/tests/mocha/node_modules/glob/.npmignore new file mode 100644 index 0000000000..2af4b71c93 --- /dev/null +++ b/tests/mocha/node_modules/glob/.npmignore @@ -0,0 +1,2 @@ +.*.swp +test/a/ diff --git a/tests/mocha/node_modules/glob/.travis.yml b/tests/mocha/node_modules/glob/.travis.yml new file mode 100644 index 0000000000..baa0031d50 --- /dev/null +++ b/tests/mocha/node_modules/glob/.travis.yml @@ -0,0 +1,3 @@ +language: node_js +node_js: + - 0.8 diff --git a/tests/mocha/node_modules/glob/LICENSE b/tests/mocha/node_modules/glob/LICENSE new file mode 100644 index 0000000000..0c44ae716d --- /dev/null +++ b/tests/mocha/node_modules/glob/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) Isaac Z. Schlueter ("Author") +All rights reserved. + +The BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/mocha/node_modules/glob/README.md b/tests/mocha/node_modules/glob/README.md new file mode 100644 index 0000000000..cc69164510 --- /dev/null +++ b/tests/mocha/node_modules/glob/README.md @@ -0,0 +1,250 @@ +# Glob + +Match files using the patterns the shell uses, like stars and stuff. + +This is a glob implementation in JavaScript. It uses the `minimatch` +library to do its matching. + +## Attention: node-glob users! + +The API has changed dramatically between 2.x and 3.x. This library is +now 100% JavaScript, and the integer flags have been replaced with an +options object. + +Also, there's an event emitter class, proper tests, and all the other +things you've come to expect from node modules. + +And best of all, no compilation! + +## Usage + +```javascript +var glob = require("glob") + +// options is optional +glob("**/*.js", options, function (er, files) { + // files is an array of filenames. + // If the `nonull` option is set, and nothing + // was found, then files is ["**/*.js"] + // er is an error object or null. +}) +``` + +## Features + +Please see the [minimatch +documentation](https://github.com/isaacs/minimatch) for more details. + +Supports these glob features: + +* Brace Expansion +* Extended glob matching +* "Globstar" `**` matching + +See: + +* `man sh` +* `man bash` +* `man 3 fnmatch` +* `man 5 gitignore` +* [minimatch documentation](https://github.com/isaacs/minimatch) + +## glob(pattern, [options], cb) + +* `pattern` {String} Pattern to be matched +* `options` {Object} +* `cb` {Function} + * `err` {Error | null} + * `matches` {Array} filenames found matching the pattern + +Perform an asynchronous glob search. + +## glob.sync(pattern, [options]) + +* `pattern` {String} Pattern to be matched +* `options` {Object} +* return: {Array} filenames found matching the pattern + +Perform a synchronous glob search. + +## Class: glob.Glob + +Create a Glob object by instanting the `glob.Glob` class. + +```javascript +var Glob = require("glob").Glob +var mg = new Glob(pattern, options, cb) +``` + +It's an EventEmitter, and starts walking the filesystem to find matches +immediately. + +### new glob.Glob(pattern, [options], [cb]) + +* `pattern` {String} pattern to search for +* `options` {Object} +* `cb` {Function} Called when an error occurs, or matches are found + * `err` {Error | null} + * `matches` {Array} filenames found matching the pattern + +Note that if the `sync` flag is set in the options, then matches will +be immediately available on the `g.found` member. + +### Properties + +* `minimatch` The minimatch object that the glob uses. +* `options` The options object passed in. +* `error` The error encountered. When an error is encountered, the + glob object is in an undefined state, and should be discarded. +* `aborted` Boolean which is set to true when calling `abort()`. There + is no way at this time to continue a glob search after aborting, but + you can re-use the statCache to avoid having to duplicate syscalls. +* `statCache` Collection of all the stat results the glob search + performed. +* `cache` Convenience object. Each field has the following possible + values: + * `false` - Path does not exist + * `true` - Path exists + * `1` - Path exists, and is not a directory + * `2` - Path exists, and is a directory + * `[file, entries, ...]` - Path exists, is a directory, and the + array value is the results of `fs.readdir` + +### Events + +* `end` When the matching is finished, this is emitted with all the + matches found. If the `nonull` option is set, and no match was found, + then the `matches` list contains the original pattern. The matches + are sorted, unless the `nosort` flag is set. +* `match` Every time a match is found, this is emitted with the matched. +* `error` Emitted when an unexpected error is encountered, or whenever + any fs error occurs if `options.strict` is set. +* `abort` When `abort()` is called, this event is raised. + +### Methods + +* `abort` Stop the search. + +### Options + +All the options that can be passed to Minimatch can also be passed to +Glob to change pattern matching behavior. Also, some have been added, +or have glob-specific ramifications. + +All options are false by default, unless otherwise noted. + +All options are added to the glob object, as well. + +* `cwd` The current working directory in which to search. Defaults + to `process.cwd()`. +* `root` The place where patterns starting with `/` will be mounted + onto. Defaults to `path.resolve(options.cwd, "/")` (`/` on Unix + systems, and `C:\` or some such on Windows.) +* `dot` Include `.dot` files in normal matches and `globstar` matches. + Note that an explicit dot in a portion of the pattern will always + match dot files. +* `nomount` By default, a pattern starting with a forward-slash will be + "mounted" onto the root setting, so that a valid filesystem path is + returned. Set this flag to disable that behavior. +* `mark` Add a `/` character to directory matches. Note that this + requires additional stat calls. +* `nosort` Don't sort the results. +* `stat` Set to true to stat *all* results. This reduces performance + somewhat, and is completely unnecessary, unless `readdir` is presumed + to be an untrustworthy indicator of file existence. It will cause + ELOOP to be triggered one level sooner in the case of cyclical + symbolic links. +* `silent` When an unusual error is encountered + when attempting to read a directory, a warning will be printed to + stderr. Set the `silent` option to true to suppress these warnings. +* `strict` When an unusual error is encountered + when attempting to read a directory, the process will just continue on + in search of other matches. Set the `strict` option to raise an error + in these cases. +* `cache` See `cache` property above. Pass in a previously generated + cache object to save some fs calls. +* `statCache` A cache of results of filesystem information, to prevent + unnecessary stat calls. While it should not normally be necessary to + set this, you may pass the statCache from one glob() call to the + options object of another, if you know that the filesystem will not + change between calls. (See "Race Conditions" below.) +* `sync` Perform a synchronous glob search. +* `nounique` In some cases, brace-expanded patterns can result in the + same file showing up multiple times in the result set. By default, + this implementation prevents duplicates in the result set. + Set this flag to disable that behavior. +* `nonull` Set to never return an empty set, instead returning a set + containing the pattern itself. This is the default in glob(3). +* `nocase` Perform a case-insensitive match. Note that case-insensitive + filesystems will sometimes result in glob returning results that are + case-insensitively matched anyway, since readdir and stat will not + raise an error. +* `debug` Set to enable debug logging in minimatch and glob. +* `globDebug` Set to enable debug logging in glob, but not minimatch. + +## Comparisons to other fnmatch/glob implementations + +While strict compliance with the existing standards is a worthwhile +goal, some discrepancies exist between node-glob and other +implementations, and are intentional. + +If the pattern starts with a `!` character, then it is negated. Set the +`nonegate` flag to suppress this behavior, and treat leading `!` +characters normally. This is perhaps relevant if you wish to start the +pattern with a negative extglob pattern like `!(a|B)`. Multiple `!` +characters at the start of a pattern will negate the pattern multiple +times. + +If a pattern starts with `#`, then it is treated as a comment, and +will not match anything. Use `\#` to match a literal `#` at the +start of a line, or set the `nocomment` flag to suppress this behavior. + +The double-star character `**` is supported by default, unless the +`noglobstar` flag is set. This is supported in the manner of bsdglob +and bash 4.1, where `**` only has special significance if it is the only +thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but +`a/**b` will not. + +If an escaped pattern has no matches, and the `nonull` flag is set, +then glob returns the pattern as-provided, rather than +interpreting the character escapes. For example, +`glob.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than +`"*a?"`. This is akin to setting the `nullglob` option in bash, except +that it does not resolve escaped pattern characters. + +If brace expansion is not disabled, then it is performed before any +other interpretation of the glob pattern. Thus, a pattern like +`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded +**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are +checked for validity. Since those two are valid, matching proceeds. + +## Windows + +**Please only use forward-slashes in glob expressions.** + +Though windows uses either `/` or `\` as its path separator, only `/` +characters are used by this glob implementation. You must use +forward-slashes **only** in glob expressions. Back-slashes will always +be interpreted as escape characters, not path separators. + +Results from absolute patterns such as `/foo/*` are mounted onto the +root setting using `path.join`. On windows, this will by default result +in `/foo/*` matching `C:\foo\bar.txt`. + +## Race Conditions + +Glob searching, by its very nature, is susceptible to race conditions, +since it relies on directory walking and such. + +As a result, it is possible that a file that exists when glob looks for +it may have been deleted or modified by the time it returns the result. + +As part of its internal implementation, this program caches all stat +and readdir calls that it makes, in order to cut down on system +overhead. However, this also makes it even more susceptible to races, +especially if the cache or statCache objects are reused between glob +calls. + +Users are thus advised not to use a glob result as a guarantee of +filesystem state in the face of rapid changes. For the vast majority +of operations, this is never a problem. diff --git a/tests/mocha/node_modules/glob/examples/g.js b/tests/mocha/node_modules/glob/examples/g.js new file mode 100644 index 0000000000..be122df002 --- /dev/null +++ b/tests/mocha/node_modules/glob/examples/g.js @@ -0,0 +1,9 @@ +var Glob = require("../").Glob + +var pattern = "test/a/**/[cg]/../[cg]" +console.log(pattern) + +var mg = new Glob(pattern, {mark: true, sync:true}, function (er, matches) { + console.log("matches", matches) +}) +console.log("after") diff --git a/tests/mocha/node_modules/glob/examples/usr-local.js b/tests/mocha/node_modules/glob/examples/usr-local.js new file mode 100644 index 0000000000..327a425e47 --- /dev/null +++ b/tests/mocha/node_modules/glob/examples/usr-local.js @@ -0,0 +1,9 @@ +var Glob = require("../").Glob + +var pattern = "{./*/*,/*,/usr/local/*}" +console.log(pattern) + +var mg = new Glob(pattern, {mark: true}, function (er, matches) { + console.log("matches", matches) +}) +console.log("after") diff --git a/tests/mocha/node_modules/glob/glob.js b/tests/mocha/node_modules/glob/glob.js new file mode 100644 index 0000000000..f0118a4f47 --- /dev/null +++ b/tests/mocha/node_modules/glob/glob.js @@ -0,0 +1,675 @@ +// Approach: +// +// 1. Get the minimatch set +// 2. For each pattern in the set, PROCESS(pattern) +// 3. Store matches per-set, then uniq them +// +// PROCESS(pattern) +// Get the first [n] items from pattern that are all strings +// Join these together. This is PREFIX. +// If there is no more remaining, then stat(PREFIX) and +// add to matches if it succeeds. END. +// readdir(PREFIX) as ENTRIES +// If fails, END +// If pattern[n] is GLOBSTAR +// // handle the case where the globstar match is empty +// // by pruning it out, and testing the resulting pattern +// PROCESS(pattern[0..n] + pattern[n+1 .. $]) +// // handle other cases. +// for ENTRY in ENTRIES (not dotfiles) +// // attach globstar + tail onto the entry +// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $]) +// +// else // not globstar +// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) +// Test ENTRY against pattern[n] +// If fails, continue +// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) +// +// Caveat: +// Cache all stats and readdirs results to minimize syscall. Since all +// we ever care about is existence and directory-ness, we can just keep +// `true` for files, and [children,...] for directories, or `false` for +// things that don't exist. + + + +module.exports = glob + +var fs = require("graceful-fs") +, minimatch = require("minimatch") +, Minimatch = minimatch.Minimatch +, inherits = require("inherits") +, EE = require("events").EventEmitter +, path = require("path") +, isDir = {} +, assert = require("assert").ok + +function glob (pattern, options, cb) { + if (typeof options === "function") cb = options, options = {} + if (!options) options = {} + + if (typeof options === "number") { + deprecated() + return + } + + var g = new Glob(pattern, options, cb) + return g.sync ? g.found : g +} + +glob.fnmatch = deprecated + +function deprecated () { + throw new Error("glob's interface has changed. Please see the docs.") +} + +glob.sync = globSync +function globSync (pattern, options) { + if (typeof options === "number") { + deprecated() + return + } + + options = options || {} + options.sync = true + return glob(pattern, options) +} + + +glob.Glob = Glob +inherits(Glob, EE) +function Glob (pattern, options, cb) { + if (!(this instanceof Glob)) { + return new Glob(pattern, options, cb) + } + + if (typeof cb === "function") { + this.on("error", cb) + this.on("end", function (matches) { + cb(null, matches) + }) + } + + options = options || {} + + this.EOF = {} + this._emitQueue = [] + + this.maxDepth = options.maxDepth || 1000 + this.maxLength = options.maxLength || Infinity + this.cache = options.cache || {} + this.statCache = options.statCache || {} + + this.changedCwd = false + var cwd = process.cwd() + if (!options.hasOwnProperty("cwd")) this.cwd = cwd + else { + this.cwd = options.cwd + this.changedCwd = path.resolve(options.cwd) !== cwd + } + + this.root = options.root || path.resolve(this.cwd, "/") + this.root = path.resolve(this.root) + if (process.platform === "win32") + this.root = this.root.replace(/\\/g, "/") + + this.nomount = !!options.nomount + + if (!pattern) { + throw new Error("must provide pattern") + } + + // base-matching: just use globstar for that. + if (options.matchBase && -1 === pattern.indexOf("/")) { + if (options.noglobstar) { + throw new Error("base matching requires globstar") + } + pattern = "**/" + pattern + } + + this.strict = options.strict !== false + this.dot = !!options.dot + this.mark = !!options.mark + this.sync = !!options.sync + this.nounique = !!options.nounique + this.nonull = !!options.nonull + this.nosort = !!options.nosort + this.nocase = !!options.nocase + this.stat = !!options.stat + + this.debug = !!options.debug || !!options.globDebug + if (this.debug) + this.log = console.error + + this.silent = !!options.silent + + var mm = this.minimatch = new Minimatch(pattern, options) + this.options = mm.options + pattern = this.pattern = mm.pattern + + this.error = null + this.aborted = false + + // list of all the patterns that ** has resolved do, so + // we can avoid visiting multiple times. + this._globstars = {} + + EE.call(this) + + // process each pattern in the minimatch set + var n = this.minimatch.set.length + + // The matches are stored as {: true,...} so that + // duplicates are automagically pruned. + // Later, we do an Object.keys() on these. + // Keep them as a list so we can fill in when nonull is set. + this.matches = new Array(n) + + this.minimatch.set.forEach(iterator.bind(this)) + function iterator (pattern, i, set) { + this._process(pattern, 0, i, function (er) { + if (er) this.emit("error", er) + if (-- n <= 0) this._finish() + }) + } +} + +Glob.prototype.log = function () {} + +Glob.prototype._finish = function () { + assert(this instanceof Glob) + + var nou = this.nounique + , all = nou ? [] : {} + + for (var i = 0, l = this.matches.length; i < l; i ++) { + var matches = this.matches[i] + this.log("matches[%d] =", i, matches) + // do like the shell, and spit out the literal glob + if (!matches) { + if (this.nonull) { + var literal = this.minimatch.globSet[i] + if (nou) all.push(literal) + else all[literal] = true + } + } else { + // had matches + var m = Object.keys(matches) + if (nou) all.push.apply(all, m) + else m.forEach(function (m) { + all[m] = true + }) + } + } + + if (!nou) all = Object.keys(all) + + if (!this.nosort) { + all = all.sort(this.nocase ? alphasorti : alphasort) + } + + if (this.mark) { + // at *some* point we statted all of these + all = all.map(function (m) { + var sc = this.cache[m] + if (!sc) + return m + var isDir = (Array.isArray(sc) || sc === 2) + if (isDir && m.slice(-1) !== "/") { + return m + "/" + } + if (!isDir && m.slice(-1) === "/") { + return m.replace(/\/+$/, "") + } + return m + }, this) + } + + this.log("emitting end", all) + + this.EOF = this.found = all + this.emitMatch(this.EOF) +} + +function alphasorti (a, b) { + a = a.toLowerCase() + b = b.toLowerCase() + return alphasort(a, b) +} + +function alphasort (a, b) { + return a > b ? 1 : a < b ? -1 : 0 +} + +Glob.prototype.abort = function () { + this.aborted = true + this.emit("abort") +} + +Glob.prototype.pause = function () { + if (this.paused) return + if (this.sync) + this.emit("error", new Error("Can't pause/resume sync glob")) + this.paused = true + this.emit("pause") +} + +Glob.prototype.resume = function () { + if (!this.paused) return + if (this.sync) + this.emit("error", new Error("Can't pause/resume sync glob")) + this.paused = false + this.emit("resume") + this._processEmitQueue() + //process.nextTick(this.emit.bind(this, "resume")) +} + +Glob.prototype.emitMatch = function (m) { + if (!this.stat || this.statCache[m] || m === this.EOF) { + this._emitQueue.push(m) + this._processEmitQueue() + } else { + this._stat(m, function(exists, isDir) { + if (exists) { + this._emitQueue.push(m) + this._processEmitQueue() + } + }) + } +} + +Glob.prototype._processEmitQueue = function (m) { + while (!this._processingEmitQueue && + !this.paused) { + this._processingEmitQueue = true + var m = this._emitQueue.shift() + if (!m) { + this._processingEmitQueue = false + break + } + + this.log('emit!', m === this.EOF ? "end" : "match") + + this.emit(m === this.EOF ? "end" : "match", m) + this._processingEmitQueue = false + } +} + +Glob.prototype._process = function (pattern, depth, index, cb_) { + assert(this instanceof Glob) + + var cb = function cb (er, res) { + assert(this instanceof Glob) + if (this.paused) { + if (!this._processQueue) { + this._processQueue = [] + this.once("resume", function () { + var q = this._processQueue + this._processQueue = null + q.forEach(function (cb) { cb() }) + }) + } + this._processQueue.push(cb_.bind(this, er, res)) + } else { + cb_.call(this, er, res) + } + }.bind(this) + + if (this.aborted) return cb() + + if (depth > this.maxDepth) return cb() + + // Get the first [n] parts of pattern that are all strings. + var n = 0 + while (typeof pattern[n] === "string") { + n ++ + } + // now n is the index of the first one that is *not* a string. + + // see if there's anything else + var prefix + switch (n) { + // if not, then this is rather simple + case pattern.length: + prefix = pattern.join("/") + this._stat(prefix, function (exists, isDir) { + // either it's there, or it isn't. + // nothing more to do, either way. + if (exists) { + if (prefix && isAbsolute(prefix) && !this.nomount) { + if (prefix.charAt(0) === "/") { + prefix = path.join(this.root, prefix) + } else { + prefix = path.resolve(this.root, prefix) + } + } + + if (process.platform === "win32") + prefix = prefix.replace(/\\/g, "/") + + this.matches[index] = this.matches[index] || {} + this.matches[index][prefix] = true + this.emitMatch(prefix) + } + return cb() + }) + return + + case 0: + // pattern *starts* with some non-trivial item. + // going to readdir(cwd), but not include the prefix in matches. + prefix = null + break + + default: + // pattern has some string bits in the front. + // whatever it starts with, whether that's "absolute" like /foo/bar, + // or "relative" like "../baz" + prefix = pattern.slice(0, n) + prefix = prefix.join("/") + break + } + + // get the list of entries. + var read + if (prefix === null) read = "." + else if (isAbsolute(prefix) || isAbsolute(pattern.join("/"))) { + if (!prefix || !isAbsolute(prefix)) { + prefix = path.join("/", prefix) + } + read = prefix = path.resolve(prefix) + + // if (process.platform === "win32") + // read = prefix = prefix.replace(/^[a-zA-Z]:|\\/g, "/") + + this.log('absolute: ', prefix, this.root, pattern, read) + } else { + read = prefix + } + + this.log('readdir(%j)', read, this.cwd, this.root) + + return this._readdir(read, function (er, entries) { + if (er) { + // not a directory! + // this means that, whatever else comes after this, it can never match + return cb() + } + + // globstar is special + if (pattern[n] === minimatch.GLOBSTAR) { + // test without the globstar, and with every child both below + // and replacing the globstar. + var s = [ pattern.slice(0, n).concat(pattern.slice(n + 1)) ] + entries.forEach(function (e) { + if (e.charAt(0) === "." && !this.dot) return + // instead of the globstar + s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1))) + // below the globstar + s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n))) + }, this) + + s = s.filter(function (pattern) { + var key = gsKey(pattern) + var seen = !this._globstars[key] + this._globstars[key] = true + return seen + }, this) + + if (!s.length) + return cb() + + // now asyncForEach over this + var l = s.length + , errState = null + s.forEach(function (gsPattern) { + this._process(gsPattern, depth + 1, index, function (er) { + if (errState) return + if (er) return cb(errState = er) + if (--l <= 0) return cb() + }) + }, this) + + return + } + + // not a globstar + // It will only match dot entries if it starts with a dot, or if + // dot is set. Stuff like @(.foo|.bar) isn't allowed. + var pn = pattern[n] + var rawGlob = pattern[n]._glob + , dotOk = this.dot || rawGlob.charAt(0) === "." + + entries = entries.filter(function (e) { + return (e.charAt(0) !== "." || dotOk) && + e.match(pattern[n]) + }) + + // If n === pattern.length - 1, then there's no need for the extra stat + // *unless* the user has specified "mark" or "stat" explicitly. + // We know that they exist, since the readdir returned them. + if (n === pattern.length - 1 && + !this.mark && + !this.stat) { + entries.forEach(function (e) { + if (prefix) { + if (prefix !== "/") e = prefix + "/" + e + else e = prefix + e + } + if (e.charAt(0) === "/" && !this.nomount) { + e = path.join(this.root, e) + } + + if (process.platform === "win32") + e = e.replace(/\\/g, "/") + + this.matches[index] = this.matches[index] || {} + this.matches[index][e] = true + this.emitMatch(e) + }, this) + return cb.call(this) + } + + + // now test all the remaining entries as stand-ins for that part + // of the pattern. + var l = entries.length + , errState = null + if (l === 0) return cb() // no matches possible + entries.forEach(function (e) { + var p = pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1)) + this._process(p, depth + 1, index, function (er) { + if (errState) return + if (er) return cb(errState = er) + if (--l === 0) return cb.call(this) + }) + }, this) + }) + +} + +function gsKey (pattern) { + return '**' + pattern.map(function (p) { + return (p === minimatch.GLOBSTAR) ? '**' : (''+p) + }).join('/') +} + +Glob.prototype._stat = function (f, cb) { + assert(this instanceof Glob) + var abs = f + if (f.charAt(0) === "/") { + abs = path.join(this.root, f) + } else if (this.changedCwd) { + abs = path.resolve(this.cwd, f) + } + + if (f.length > this.maxLength) { + var er = new Error("Path name too long") + er.code = "ENAMETOOLONG" + er.path = f + return this._afterStat(f, abs, cb, er) + } + + this.log('stat', [this.cwd, f, '=', abs]) + + if (!this.stat && this.cache.hasOwnProperty(f)) { + var exists = this.cache[f] + , isDir = exists && (Array.isArray(exists) || exists === 2) + if (this.sync) return cb.call(this, !!exists, isDir) + return process.nextTick(cb.bind(this, !!exists, isDir)) + } + + var stat = this.statCache[abs] + if (this.sync || stat) { + var er + try { + stat = fs.statSync(abs) + } catch (e) { + er = e + } + this._afterStat(f, abs, cb, er, stat) + } else { + fs.stat(abs, this._afterStat.bind(this, f, abs, cb)) + } +} + +Glob.prototype._afterStat = function (f, abs, cb, er, stat) { + var exists + assert(this instanceof Glob) + + if (abs.slice(-1) === "/" && stat && !stat.isDirectory()) { + this.log("should be ENOTDIR, fake it") + + er = new Error("ENOTDIR, not a directory '" + abs + "'") + er.path = abs + er.code = "ENOTDIR" + stat = null + } + + var emit = !this.statCache[abs] + this.statCache[abs] = stat + + if (er || !stat) { + exists = false + } else { + exists = stat.isDirectory() ? 2 : 1 + if (emit) + this.emit('stat', f, stat) + } + this.cache[f] = this.cache[f] || exists + cb.call(this, !!exists, exists === 2) +} + +Glob.prototype._readdir = function (f, cb) { + assert(this instanceof Glob) + var abs = f + if (f.charAt(0) === "/") { + abs = path.join(this.root, f) + } else if (isAbsolute(f)) { + abs = f + } else if (this.changedCwd) { + abs = path.resolve(this.cwd, f) + } + + if (f.length > this.maxLength) { + var er = new Error("Path name too long") + er.code = "ENAMETOOLONG" + er.path = f + return this._afterReaddir(f, abs, cb, er) + } + + this.log('readdir', [this.cwd, f, abs]) + if (this.cache.hasOwnProperty(f)) { + var c = this.cache[f] + if (Array.isArray(c)) { + if (this.sync) return cb.call(this, null, c) + return process.nextTick(cb.bind(this, null, c)) + } + + if (!c || c === 1) { + // either ENOENT or ENOTDIR + var code = c ? "ENOTDIR" : "ENOENT" + , er = new Error((c ? "Not a directory" : "Not found") + ": " + f) + er.path = f + er.code = code + this.log(f, er) + if (this.sync) return cb.call(this, er) + return process.nextTick(cb.bind(this, er)) + } + + // at this point, c === 2, meaning it's a dir, but we haven't + // had to read it yet, or c === true, meaning it's *something* + // but we don't have any idea what. Need to read it, either way. + } + + if (this.sync) { + var er, entries + try { + entries = fs.readdirSync(abs) + } catch (e) { + er = e + } + return this._afterReaddir(f, abs, cb, er, entries) + } + + fs.readdir(abs, this._afterReaddir.bind(this, f, abs, cb)) +} + +Glob.prototype._afterReaddir = function (f, abs, cb, er, entries) { + assert(this instanceof Glob) + if (entries && !er) { + this.cache[f] = entries + // if we haven't asked to stat everything for suresies, then just + // assume that everything in there exists, so we can avoid + // having to stat it a second time. This also gets us one step + // further into ELOOP territory. + if (!this.mark && !this.stat) { + entries.forEach(function (e) { + if (f === "/") e = f + e + else e = f + "/" + e + this.cache[e] = true + }, this) + } + + return cb.call(this, er, entries) + } + + // now handle errors, and cache the information + if (er) switch (er.code) { + case "ENOTDIR": // totally normal. means it *does* exist. + this.cache[f] = 1 + return cb.call(this, er) + case "ENOENT": // not terribly unusual + case "ELOOP": + case "ENAMETOOLONG": + case "UNKNOWN": + this.cache[f] = false + return cb.call(this, er) + default: // some unusual error. Treat as failure. + this.cache[f] = false + if (this.strict) this.emit("error", er) + if (!this.silent) console.error("glob error", er) + return cb.call(this, er) + } +} + +var isAbsolute = process.platform === "win32" ? absWin : absUnix + +function absWin (p) { + if (absUnix(p)) return true + // pull off the device/UNC bit from a windows path. + // from node's lib/path.js + var splitDeviceRe = + /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/ + , result = splitDeviceRe.exec(p) + , device = result[1] || '' + , isUnc = device && device.charAt(1) !== ':' + , isAbsolute = !!result[2] || isUnc // UNC paths are always absolute + + return isAbsolute +} + +function absUnix (p) { + return p.charAt(0) === "/" || p === "" +} diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/.npmignore b/tests/mocha/node_modules/glob/node_modules/graceful-fs/.npmignore new file mode 100644 index 0000000000..c2658d7d1b --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/graceful-fs/.npmignore @@ -0,0 +1 @@ +node_modules/ diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/LICENSE b/tests/mocha/node_modules/glob/node_modules/graceful-fs/LICENSE new file mode 100644 index 0000000000..0c44ae716d --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/graceful-fs/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) Isaac Z. Schlueter ("Author") +All rights reserved. + +The BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/README.md b/tests/mocha/node_modules/glob/node_modules/graceful-fs/README.md new file mode 100644 index 0000000000..eb1a109356 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/graceful-fs/README.md @@ -0,0 +1,26 @@ +# graceful-fs + +graceful-fs functions as a drop-in replacement for the fs module, +making various improvements. + +The improvements are meant to normalize behavior across different +platforms and environments, and to make filesystem access more +resilient to errors. + +## Improvements over fs module + +graceful-fs: + +* Queues up `open` and `readdir` calls, and retries them once + something closes if there is an EMFILE error from too many file + descriptors. +* fixes `lchmod` for Node versions prior to 0.6.2. +* implements `fs.lutimes` if possible. Otherwise it becomes a noop. +* ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or + `lchown` if the user isn't root. +* makes `lchmod` and `lchown` become noops, if not available. +* retries reading a file if `read` results in EAGAIN error. + +On Windows, it retries renaming a file for up to one second if `EACCESS` +or `EPERM` error occurs, likely because antivirus software has locked +the directory. diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/graceful-fs.js b/tests/mocha/node_modules/glob/node_modules/graceful-fs/graceful-fs.js new file mode 100644 index 0000000000..c84db91019 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/graceful-fs/graceful-fs.js @@ -0,0 +1,160 @@ +// Monkey-patching the fs module. +// It's ugly, but there is simply no other way to do this. +var fs = module.exports = require('fs') + +var assert = require('assert') + +// fix up some busted stuff, mostly on windows and old nodes +require('./polyfills.js') + +// The EMFILE enqueuing stuff + +var util = require('util') + +function noop () {} + +var debug = noop +if (util.debuglog) + debug = util.debuglog('gfs') +else if (/\bgfs\b/i.test(process.env.NODE_DEBUG || '')) + debug = function() { + var m = util.format.apply(util, arguments) + m = 'GFS: ' + m.split(/\n/).join('\nGFS: ') + console.error(m) + } + +if (/\bgfs\b/i.test(process.env.NODE_DEBUG || '')) { + process.on('exit', function() { + debug('fds', fds) + debug(queue) + assert.equal(queue.length, 0) + }) +} + + +var originalOpen = fs.open +fs.open = open + +function open(path, flags, mode, cb) { + if (typeof mode === "function") cb = mode, mode = null + if (typeof cb !== "function") cb = noop + new OpenReq(path, flags, mode, cb) +} + +function OpenReq(path, flags, mode, cb) { + this.path = path + this.flags = flags + this.mode = mode + this.cb = cb + Req.call(this) +} + +util.inherits(OpenReq, Req) + +OpenReq.prototype.process = function() { + originalOpen.call(fs, this.path, this.flags, this.mode, this.done) +} + +var fds = {} +OpenReq.prototype.done = function(er, fd) { + debug('open done', er, fd) + if (fd) + fds['fd' + fd] = this.path + Req.prototype.done.call(this, er, fd) +} + + +var originalReaddir = fs.readdir +fs.readdir = readdir + +function readdir(path, cb) { + if (typeof cb !== "function") cb = noop + new ReaddirReq(path, cb) +} + +function ReaddirReq(path, cb) { + this.path = path + this.cb = cb + Req.call(this) +} + +util.inherits(ReaddirReq, Req) + +ReaddirReq.prototype.process = function() { + originalReaddir.call(fs, this.path, this.done) +} + +ReaddirReq.prototype.done = function(er, files) { + if (files && files.sort) + files = files.sort() + Req.prototype.done.call(this, er, files) + onclose() +} + + +var originalClose = fs.close +fs.close = close + +function close (fd, cb) { + debug('close', fd) + if (typeof cb !== "function") cb = noop + delete fds['fd' + fd] + originalClose.call(fs, fd, function(er) { + onclose() + cb(er) + }) +} + + +var originalCloseSync = fs.closeSync +fs.closeSync = closeSync + +function closeSync (fd) { + try { + return originalCloseSync(fd) + } finally { + onclose() + } +} + + +// Req class +function Req () { + // start processing + this.done = this.done.bind(this) + this.failures = 0 + this.process() +} + +Req.prototype.done = function (er, result) { + var tryAgain = false + if (er) { + var code = er.code + var tryAgain = code === "EMFILE" + if (process.platform === "win32") + tryAgain = tryAgain || code === "OK" + } + + if (tryAgain) { + this.failures ++ + enqueue(this) + } else { + var cb = this.cb + cb(er, result) + } +} + +var queue = [] + +function enqueue(req) { + queue.push(req) + debug('enqueue %d %s', queue.length, req.constructor.name, req) +} + +function onclose() { + var req = queue.shift() + if (req) { + debug('process', req.constructor.name, req) + req.process() + } +} diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/package.json b/tests/mocha/node_modules/glob/node_modules/graceful-fs/package.json new file mode 100644 index 0000000000..89d7462c3e --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/graceful-fs/package.json @@ -0,0 +1,49 @@ +{ + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me" + }, + "name": "graceful-fs", + "description": "A drop-in replacement for fs, making various improvements.", + "version": "2.0.3", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/node-graceful-fs.git" + }, + "main": "graceful-fs.js", + "engines": { + "node": ">=0.4.0" + }, + "directories": { + "test": "test" + }, + "scripts": { + "test": "tap test/*.js" + }, + "keywords": [ + "fs", + "module", + "reading", + "retry", + "retries", + "queue", + "error", + "errors", + "handling", + "EMFILE", + "EAGAIN", + "EINVAL", + "EPERM", + "EACCESS" + ], + "license": "BSD", + "readme": "# graceful-fs\n\ngraceful-fs functions as a drop-in replacement for the fs module,\nmaking various improvements.\n\nThe improvements are meant to normalize behavior across different\nplatforms and environments, and to make filesystem access more\nresilient to errors.\n\n## Improvements over fs module\n\ngraceful-fs:\n\n* Queues up `open` and `readdir` calls, and retries them once\n something closes if there is an EMFILE error from too many file\n descriptors.\n* fixes `lchmod` for Node versions prior to 0.6.2.\n* implements `fs.lutimes` if possible. Otherwise it becomes a noop.\n* ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or\n `lchown` if the user isn't root.\n* makes `lchmod` and `lchown` become noops, if not available.\n* retries reading a file if `read` results in EAGAIN error.\n\nOn Windows, it retries renaming a file for up to one second if `EACCESS`\nor `EPERM` error occurs, likely because antivirus software has locked\nthe directory.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/node-graceful-fs/issues" + }, + "homepage": "https://github.com/isaacs/node-graceful-fs", + "_id": "graceful-fs@2.0.3", + "_from": "graceful-fs@~2.0.0" +} diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/polyfills.js b/tests/mocha/node_modules/glob/node_modules/graceful-fs/polyfills.js new file mode 100644 index 0000000000..afc83b3f2c --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/graceful-fs/polyfills.js @@ -0,0 +1,228 @@ +var fs = require('fs') +var constants = require('constants') + +var origCwd = process.cwd +var cwd = null +process.cwd = function() { + if (!cwd) + cwd = origCwd.call(process) + return cwd +} +var chdir = process.chdir +process.chdir = function(d) { + cwd = null + chdir.call(process, d) +} + +// (re-)implement some things that are known busted or missing. + +// lchmod, broken prior to 0.6.2 +// back-port the fix here. +if (constants.hasOwnProperty('O_SYMLINK') && + process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) { + fs.lchmod = function (path, mode, callback) { + callback = callback || noop + fs.open( path + , constants.O_WRONLY | constants.O_SYMLINK + , mode + , function (err, fd) { + if (err) { + callback(err) + return + } + // prefer to return the chmod error, if one occurs, + // but still try to close, and report closing errors if they occur. + fs.fchmod(fd, mode, function (err) { + fs.close(fd, function(err2) { + callback(err || err2) + }) + }) + }) + } + + fs.lchmodSync = function (path, mode) { + var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode) + + // prefer to return the chmod error, if one occurs, + // but still try to close, and report closing errors if they occur. + var err, err2 + try { + var ret = fs.fchmodSync(fd, mode) + } catch (er) { + err = er + } + try { + fs.closeSync(fd) + } catch (er) { + err2 = er + } + if (err || err2) throw (err || err2) + return ret + } +} + + +// lutimes implementation, or no-op +if (!fs.lutimes) { + if (constants.hasOwnProperty("O_SYMLINK")) { + fs.lutimes = function (path, at, mt, cb) { + fs.open(path, constants.O_SYMLINK, function (er, fd) { + cb = cb || noop + if (er) return cb(er) + fs.futimes(fd, at, mt, function (er) { + fs.close(fd, function (er2) { + return cb(er || er2) + }) + }) + }) + } + + fs.lutimesSync = function (path, at, mt) { + var fd = fs.openSync(path, constants.O_SYMLINK) + , err + , err2 + , ret + + try { + var ret = fs.futimesSync(fd, at, mt) + } catch (er) { + err = er + } + try { + fs.closeSync(fd) + } catch (er) { + err2 = er + } + if (err || err2) throw (err || err2) + return ret + } + + } else if (fs.utimensat && constants.hasOwnProperty("AT_SYMLINK_NOFOLLOW")) { + // maybe utimensat will be bound soonish? + fs.lutimes = function (path, at, mt, cb) { + fs.utimensat(path, at, mt, constants.AT_SYMLINK_NOFOLLOW, cb) + } + + fs.lutimesSync = function (path, at, mt) { + return fs.utimensatSync(path, at, mt, constants.AT_SYMLINK_NOFOLLOW) + } + + } else { + fs.lutimes = function (_a, _b, _c, cb) { process.nextTick(cb) } + fs.lutimesSync = function () {} + } +} + + +// https://github.com/isaacs/node-graceful-fs/issues/4 +// Chown should not fail on einval or eperm if non-root. + +fs.chown = chownFix(fs.chown) +fs.fchown = chownFix(fs.fchown) +fs.lchown = chownFix(fs.lchown) + +fs.chownSync = chownFixSync(fs.chownSync) +fs.fchownSync = chownFixSync(fs.fchownSync) +fs.lchownSync = chownFixSync(fs.lchownSync) + +function chownFix (orig) { + if (!orig) return orig + return function (target, uid, gid, cb) { + return orig.call(fs, target, uid, gid, function (er, res) { + if (chownErOk(er)) er = null + cb(er, res) + }) + } +} + +function chownFixSync (orig) { + if (!orig) return orig + return function (target, uid, gid) { + try { + return orig.call(fs, target, uid, gid) + } catch (er) { + if (!chownErOk(er)) throw er + } + } +} + +function chownErOk (er) { + // if there's no getuid, or if getuid() is something other than 0, + // and the error is EINVAL or EPERM, then just ignore it. + // This specific case is a silent failure in cp, install, tar, + // and most other unix tools that manage permissions. + // When running as root, or if other types of errors are encountered, + // then it's strict. + if (!er || (!process.getuid || process.getuid() !== 0) + && (er.code === "EINVAL" || er.code === "EPERM")) return true +} + + +// if lchmod/lchown do not exist, then make them no-ops +if (!fs.lchmod) { + fs.lchmod = function (path, mode, cb) { + process.nextTick(cb) + } + fs.lchmodSync = function () {} +} +if (!fs.lchown) { + fs.lchown = function (path, uid, gid, cb) { + process.nextTick(cb) + } + fs.lchownSync = function () {} +} + + + +// on Windows, A/V software can lock the directory, causing this +// to fail with an EACCES or EPERM if the directory contains newly +// created files. Try again on failure, for up to 1 second. +if (process.platform === "win32") { + var rename_ = fs.rename + fs.rename = function rename (from, to, cb) { + var start = Date.now() + rename_(from, to, function CB (er) { + if (er + && (er.code === "EACCES" || er.code === "EPERM") + && Date.now() - start < 1000) { + return rename_(from, to, CB) + } + cb(er) + }) + } +} + + +// if read() returns EAGAIN, then just try it again. +var read = fs.read +fs.read = function (fd, buffer, offset, length, position, callback_) { + var callback + if (callback_ && typeof callback_ === 'function') { + var eagCounter = 0 + callback = function (er, _, __) { + if (er && er.code === 'EAGAIN' && eagCounter < 10) { + eagCounter ++ + return read.call(fs, fd, buffer, offset, length, position, callback) + } + callback_.apply(this, arguments) + } + } + return read.call(fs, fd, buffer, offset, length, position, callback) +} + +var readSync = fs.readSync +fs.readSync = function (fd, buffer, offset, length, position) { + var eagCounter = 0 + while (true) { + try { + return readSync.call(fs, fd, buffer, offset, length, position) + } catch (er) { + if (er.code === 'EAGAIN' && eagCounter < 10) { + eagCounter ++ + continue + } + throw er + } + } +} + diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/open.js b/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/open.js new file mode 100644 index 0000000000..104f36b0b9 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/open.js @@ -0,0 +1,39 @@ +var test = require('tap').test +var fs = require('../graceful-fs.js') + +test('graceful fs is monkeypatched fs', function (t) { + t.equal(fs, require('fs')) + t.end() +}) + +test('open an existing file works', function (t) { + var fd = fs.openSync(__filename, 'r') + fs.closeSync(fd) + fs.open(__filename, 'r', function (er, fd) { + if (er) throw er + fs.close(fd, function (er) { + if (er) throw er + t.pass('works') + t.end() + }) + }) +}) + +test('open a non-existing file throws', function (t) { + var er + try { + var fd = fs.openSync('this file does not exist', 'r') + } catch (x) { + er = x + } + t.ok(er, 'should throw') + t.notOk(fd, 'should not get an fd') + t.equal(er.code, 'ENOENT') + + fs.open('neither does this file', 'r', function (er, fd) { + t.ok(er, 'should throw') + t.notOk(fd, 'should not get an fd') + t.equal(er.code, 'ENOENT') + t.end() + }) +}) diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/readdir-sort.js b/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/readdir-sort.js new file mode 100644 index 0000000000..aeaedf1c16 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/readdir-sort.js @@ -0,0 +1,21 @@ +var test = require("tap").test +var fs = require("fs") + +var readdir = fs.readdir +fs.readdir = function(path, cb) { + process.nextTick(function() { + cb(null, ["b", "z", "a"]) + }) +} + +var g = require("../") + +test("readdir reorder", function (t) { + g.readdir("whatevers", function (er, files) { + if (er) + throw er + console.error(files) + t.same(files, [ "a", "b", "z" ]) + t.end() + }) +}) diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/LICENSE b/tests/mocha/node_modules/glob/node_modules/inherits/LICENSE new file mode 100644 index 0000000000..dea3013d67 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/inherits/LICENSE @@ -0,0 +1,16 @@ +The ISC License + +Copyright (c) Isaac Z. Schlueter + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted, provided that the above +copyright notice and this permission notice appear in all copies. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. + diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/README.md b/tests/mocha/node_modules/glob/node_modules/inherits/README.md new file mode 100644 index 0000000000..b1c5665855 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/inherits/README.md @@ -0,0 +1,42 @@ +Browser-friendly inheritance fully compatible with standard node.js +[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor). + +This package exports standard `inherits` from node.js `util` module in +node environment, but also provides alternative browser-friendly +implementation through [browser +field](https://gist.github.com/shtylman/4339901). Alternative +implementation is a literal copy of standard one located in standalone +module to avoid requiring of `util`. It also has a shim for old +browsers with no `Object.create` support. + +While keeping you sure you are using standard `inherits` +implementation in node.js environment, it allows bundlers such as +[browserify](https://github.com/substack/node-browserify) to not +include full `util` package to your client code if all you need is +just `inherits` function. It worth, because browser shim for `util` +package is large and `inherits` is often the single function you need +from it. + +It's recommended to use this package instead of +`require('util').inherits` for any code that has chances to be used +not only in node.js but in browser too. + +## usage + +```js +var inherits = require('inherits'); +// then use exactly as the standard one +``` + +## note on version ~1.0 + +Version ~1.0 had completely different motivation and is not compatible +neither with 2.0 nor with standard node.js `inherits`. + +If you are using version ~1.0 and planning to switch to ~2.0, be +careful: + +* new version uses `super_` instead of `super` for referencing + superclass +* new version overwrites current prototype while old one preserves any + existing fields on it diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/inherits.js b/tests/mocha/node_modules/glob/node_modules/inherits/inherits.js new file mode 100644 index 0000000000..29f5e24f57 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/inherits/inherits.js @@ -0,0 +1 @@ +module.exports = require('util').inherits diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/inherits_browser.js b/tests/mocha/node_modules/glob/node_modules/inherits/inherits_browser.js new file mode 100644 index 0000000000..c1e78a75e6 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/inherits/inherits_browser.js @@ -0,0 +1,23 @@ +if (typeof Object.create === 'function') { + // implementation from standard node.js 'util' module + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + ctor.prototype = Object.create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }; +} else { + // old school shim for old browsers + module.exports = function inherits(ctor, superCtor) { + ctor.super_ = superCtor + var TempCtor = function () {} + TempCtor.prototype = superCtor.prototype + ctor.prototype = new TempCtor() + ctor.prototype.constructor = ctor + } +} diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/package.json b/tests/mocha/node_modules/glob/node_modules/inherits/package.json new file mode 100644 index 0000000000..c532ca6d14 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/inherits/package.json @@ -0,0 +1,33 @@ +{ + "name": "inherits", + "description": "Browser-friendly inheritance fully compatible with standard node.js inherits()", + "version": "2.0.1", + "keywords": [ + "inheritance", + "class", + "klass", + "oop", + "object-oriented", + "inherits", + "browser", + "browserify" + ], + "main": "./inherits.js", + "browser": "./inherits_browser.js", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/inherits" + }, + "license": "ISC", + "scripts": { + "test": "node test" + }, + "readme": "Browser-friendly inheritance fully compatible with standard node.js\n[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor).\n\nThis package exports standard `inherits` from node.js `util` module in\nnode environment, but also provides alternative browser-friendly\nimplementation through [browser\nfield](https://gist.github.com/shtylman/4339901). Alternative\nimplementation is a literal copy of standard one located in standalone\nmodule to avoid requiring of `util`. It also has a shim for old\nbrowsers with no `Object.create` support.\n\nWhile keeping you sure you are using standard `inherits`\nimplementation in node.js environment, it allows bundlers such as\n[browserify](https://github.com/substack/node-browserify) to not\ninclude full `util` package to your client code if all you need is\njust `inherits` function. It worth, because browser shim for `util`\npackage is large and `inherits` is often the single function you need\nfrom it.\n\nIt's recommended to use this package instead of\n`require('util').inherits` for any code that has chances to be used\nnot only in node.js but in browser too.\n\n## usage\n\n```js\nvar inherits = require('inherits');\n// then use exactly as the standard one\n```\n\n## note on version ~1.0\n\nVersion ~1.0 had completely different motivation and is not compatible\nneither with 2.0 nor with standard node.js `inherits`.\n\nIf you are using version ~1.0 and planning to switch to ~2.0, be\ncareful:\n\n* new version uses `super_` instead of `super` for referencing\n superclass\n* new version overwrites current prototype while old one preserves any\n existing fields on it\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/inherits/issues" + }, + "homepage": "https://github.com/isaacs/inherits", + "_id": "inherits@2.0.1", + "_from": "inherits@~2.0.1" +} diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/test.js b/tests/mocha/node_modules/glob/node_modules/inherits/test.js new file mode 100644 index 0000000000..fc53012d31 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/inherits/test.js @@ -0,0 +1,25 @@ +var inherits = require('./inherits.js') +var assert = require('assert') + +function test(c) { + assert(c.constructor === Child) + assert(c.constructor.super_ === Parent) + assert(Object.getPrototypeOf(c) === Child.prototype) + assert(Object.getPrototypeOf(Object.getPrototypeOf(c)) === Parent.prototype) + assert(c instanceof Child) + assert(c instanceof Parent) +} + +function Child() { + Parent.call(this) + test(this) +} + +function Parent() {} + +inherits(Child, Parent) + +var c = new Child +test(c) + +console.log('ok') diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/.npmignore b/tests/mocha/node_modules/glob/node_modules/minimatch/.npmignore new file mode 100644 index 0000000000..3c3629e647 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/.npmignore @@ -0,0 +1 @@ +node_modules diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/LICENSE b/tests/mocha/node_modules/glob/node_modules/minimatch/LICENSE new file mode 100644 index 0000000000..05a4010949 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/LICENSE @@ -0,0 +1,23 @@ +Copyright 2009, 2010, 2011 Isaac Z. Schlueter. +All rights reserved. + +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 +copies 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 all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER 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. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/README.md b/tests/mocha/node_modules/glob/node_modules/minimatch/README.md new file mode 100644 index 0000000000..978268e275 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/README.md @@ -0,0 +1,218 @@ +# minimatch + +A minimal matching utility. + +[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.png)](http://travis-ci.org/isaacs/minimatch) + + +This is the matching library used internally by npm. + +Eventually, it will replace the C binding in node-glob. + +It works by converting glob expressions into JavaScript `RegExp` +objects. + +## Usage + +```javascript +var minimatch = require("minimatch") + +minimatch("bar.foo", "*.foo") // true! +minimatch("bar.foo", "*.bar") // false! +minimatch("bar.foo", "*.+(bar|foo)", { debug: true }) // true, and noisy! +``` + +## Features + +Supports these glob features: + +* Brace Expansion +* Extended glob matching +* "Globstar" `**` matching + +See: + +* `man sh` +* `man bash` +* `man 3 fnmatch` +* `man 5 gitignore` + +## Minimatch Class + +Create a minimatch object by instanting the `minimatch.Minimatch` class. + +```javascript +var Minimatch = require("minimatch").Minimatch +var mm = new Minimatch(pattern, options) +``` + +### Properties + +* `pattern` The original pattern the minimatch object represents. +* `options` The options supplied to the constructor. +* `set` A 2-dimensional array of regexp or string expressions. + Each row in the + array corresponds to a brace-expanded pattern. Each item in the row + corresponds to a single path-part. For example, the pattern + `{a,b/c}/d` would expand to a set of patterns like: + + [ [ a, d ] + , [ b, c, d ] ] + + If a portion of the pattern doesn't have any "magic" in it + (that is, it's something like `"foo"` rather than `fo*o?`), then it + will be left as a string rather than converted to a regular + expression. + +* `regexp` Created by the `makeRe` method. A single regular expression + expressing the entire pattern. This is useful in cases where you wish + to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled. +* `negate` True if the pattern is negated. +* `comment` True if the pattern is a comment. +* `empty` True if the pattern is `""`. + +### Methods + +* `makeRe` Generate the `regexp` member if necessary, and return it. + Will return `false` if the pattern is invalid. +* `match(fname)` Return true if the filename matches the pattern, or + false otherwise. +* `matchOne(fileArray, patternArray, partial)` Take a `/`-split + filename, and match it against a single row in the `regExpSet`. This + method is mainly for internal use, but is exposed so that it can be + used by a glob-walker that needs to avoid excessive filesystem calls. + +All other methods are internal, and will be called as necessary. + +## Functions + +The top-level exported function has a `cache` property, which is an LRU +cache set to store 100 items. So, calling these methods repeatedly +with the same pattern and options will use the same Minimatch object, +saving the cost of parsing it multiple times. + +### minimatch(path, pattern, options) + +Main export. Tests a path against the pattern using the options. + +```javascript +var isJS = minimatch(file, "*.js", { matchBase: true }) +``` + +### minimatch.filter(pattern, options) + +Returns a function that tests its +supplied argument, suitable for use with `Array.filter`. Example: + +```javascript +var javascripts = fileList.filter(minimatch.filter("*.js", {matchBase: true})) +``` + +### minimatch.match(list, pattern, options) + +Match against the list of +files, in the style of fnmatch or glob. If nothing is matched, and +options.nonull is set, then return a list containing the pattern itself. + +```javascript +var javascripts = minimatch.match(fileList, "*.js", {matchBase: true})) +``` + +### minimatch.makeRe(pattern, options) + +Make a regular expression object from the pattern. + +## Options + +All options are `false` by default. + +### debug + +Dump a ton of stuff to stderr. + +### nobrace + +Do not expand `{a,b}` and `{1..3}` brace sets. + +### noglobstar + +Disable `**` matching against multiple folder names. + +### dot + +Allow patterns to match filenames starting with a period, even if +the pattern does not explicitly have a period in that spot. + +Note that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot` +is set. + +### noext + +Disable "extglob" style patterns like `+(a|b)`. + +### nocase + +Perform a case-insensitive match. + +### nonull + +When a match is not found by `minimatch.match`, return a list containing +the pattern itself. When set, an empty list is returned if there are +no matches. + +### matchBase + +If set, then patterns without slashes will be matched +against the basename of the path if it contains slashes. For example, +`a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`. + +### nocomment + +Suppress the behavior of treating `#` at the start of a pattern as a +comment. + +### nonegate + +Suppress the behavior of treating a leading `!` character as negation. + +### flipNegate + +Returns from negate expressions the same as if they were not negated. +(Ie, true on a hit, false on a miss.) + + +## Comparisons to other fnmatch/glob implementations + +While strict compliance with the existing standards is a worthwhile +goal, some discrepancies exist between minimatch and other +implementations, and are intentional. + +If the pattern starts with a `!` character, then it is negated. Set the +`nonegate` flag to suppress this behavior, and treat leading `!` +characters normally. This is perhaps relevant if you wish to start the +pattern with a negative extglob pattern like `!(a|B)`. Multiple `!` +characters at the start of a pattern will negate the pattern multiple +times. + +If a pattern starts with `#`, then it is treated as a comment, and +will not match anything. Use `\#` to match a literal `#` at the +start of a line, or set the `nocomment` flag to suppress this behavior. + +The double-star character `**` is supported by default, unless the +`noglobstar` flag is set. This is supported in the manner of bsdglob +and bash 4.1, where `**` only has special significance if it is the only +thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but +`a/**b` will not. + +If an escaped pattern has no matches, and the `nonull` flag is set, +then minimatch.match returns the pattern as-provided, rather than +interpreting the character escapes. For example, +`minimatch.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than +`"*a?"`. This is akin to setting the `nullglob` option in bash, except +that it does not resolve escaped pattern characters. + +If brace expansion is not disabled, then it is performed before any +other interpretation of the glob pattern. Thus, a pattern like +`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded +**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are +checked for validity. Since those two are valid, matching proceeds. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/minimatch.js b/tests/mocha/node_modules/glob/node_modules/minimatch/minimatch.js new file mode 100644 index 0000000000..c633f89fab --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/minimatch.js @@ -0,0 +1,1055 @@ +;(function (require, exports, module, platform) { + +if (module) module.exports = minimatch +else exports.minimatch = minimatch + +if (!require) { + require = function (id) { + switch (id) { + case "sigmund": return function sigmund (obj) { + return JSON.stringify(obj) + } + case "path": return { basename: function (f) { + f = f.split(/[\/\\]/) + var e = f.pop() + if (!e) e = f.pop() + return e + }} + case "lru-cache": return function LRUCache () { + // not quite an LRU, but still space-limited. + var cache = {} + var cnt = 0 + this.set = function (k, v) { + cnt ++ + if (cnt >= 100) cache = {} + cache[k] = v + } + this.get = function (k) { return cache[k] } + } + } + } +} + +minimatch.Minimatch = Minimatch + +var LRU = require("lru-cache") + , cache = minimatch.cache = new LRU({max: 100}) + , GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} + , sigmund = require("sigmund") + +var path = require("path") + // any single thing other than / + // don't need to escape / when using new RegExp() + , qmark = "[^/]" + + // * => any number of characters + , star = qmark + "*?" + + // ** when dots are allowed. Anything goes, except .. and . + // not (^ or / followed by one or two dots followed by $ or /), + // followed by anything, any number of times. + , twoStarDot = "(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?" + + // not a ^ or / followed by a dot, + // followed by anything, any number of times. + , twoStarNoDot = "(?:(?!(?:\\\/|^)\\.).)*?" + + // characters that need to be escaped in RegExp. + , reSpecials = charSet("().*{}+?[]^$\\!") + +// "abc" -> { a:true, b:true, c:true } +function charSet (s) { + return s.split("").reduce(function (set, c) { + set[c] = true + return set + }, {}) +} + +// normalizes slashes. +var slashSplit = /\/+/ + +minimatch.filter = filter +function filter (pattern, options) { + options = options || {} + return function (p, i, list) { + return minimatch(p, pattern, options) + } +} + +function ext (a, b) { + a = a || {} + b = b || {} + var t = {} + Object.keys(b).forEach(function (k) { + t[k] = b[k] + }) + Object.keys(a).forEach(function (k) { + t[k] = a[k] + }) + return t +} + +minimatch.defaults = function (def) { + if (!def || !Object.keys(def).length) return minimatch + + var orig = minimatch + + var m = function minimatch (p, pattern, options) { + return orig.minimatch(p, pattern, ext(def, options)) + } + + m.Minimatch = function Minimatch (pattern, options) { + return new orig.Minimatch(pattern, ext(def, options)) + } + + return m +} + +Minimatch.defaults = function (def) { + if (!def || !Object.keys(def).length) return Minimatch + return minimatch.defaults(def).Minimatch +} + + +function minimatch (p, pattern, options) { + if (typeof pattern !== "string") { + throw new TypeError("glob pattern string required") + } + + if (!options) options = {} + + // shortcut: comments match nothing. + if (!options.nocomment && pattern.charAt(0) === "#") { + return false + } + + // "" only matches "" + if (pattern.trim() === "") return p === "" + + return new Minimatch(pattern, options).match(p) +} + +function Minimatch (pattern, options) { + if (!(this instanceof Minimatch)) { + return new Minimatch(pattern, options, cache) + } + + if (typeof pattern !== "string") { + throw new TypeError("glob pattern string required") + } + + if (!options) options = {} + pattern = pattern.trim() + + // windows: need to use /, not \ + // On other platforms, \ is a valid (albeit bad) filename char. + if (platform === "win32") { + pattern = pattern.split("\\").join("/") + } + + // lru storage. + // these things aren't particularly big, but walking down the string + // and turning it into a regexp can get pretty costly. + var cacheKey = pattern + "\n" + sigmund(options) + var cached = minimatch.cache.get(cacheKey) + if (cached) return cached + minimatch.cache.set(cacheKey, this) + + this.options = options + this.set = [] + this.pattern = pattern + this.regexp = null + this.negate = false + this.comment = false + this.empty = false + + // make the set of regexps etc. + this.make() +} + +Minimatch.prototype.debug = function() {} + +Minimatch.prototype.make = make +function make () { + // don't do it more than once. + if (this._made) return + + var pattern = this.pattern + var options = this.options + + // empty patterns and comments match nothing. + if (!options.nocomment && pattern.charAt(0) === "#") { + this.comment = true + return + } + if (!pattern) { + this.empty = true + return + } + + // step 1: figure out negation, etc. + this.parseNegate() + + // step 2: expand braces + var set = this.globSet = this.braceExpand() + + if (options.debug) this.debug = console.error + + this.debug(this.pattern, set) + + // step 3: now we have a set, so turn each one into a series of path-portion + // matching patterns. + // These will be regexps, except in the case of "**", which is + // set to the GLOBSTAR object for globstar behavior, + // and will not contain any / characters + set = this.globParts = set.map(function (s) { + return s.split(slashSplit) + }) + + this.debug(this.pattern, set) + + // glob --> regexps + set = set.map(function (s, si, set) { + return s.map(this.parse, this) + }, this) + + this.debug(this.pattern, set) + + // filter out everything that didn't compile properly. + set = set.filter(function (s) { + return -1 === s.indexOf(false) + }) + + this.debug(this.pattern, set) + + this.set = set +} + +Minimatch.prototype.parseNegate = parseNegate +function parseNegate () { + var pattern = this.pattern + , negate = false + , options = this.options + , negateOffset = 0 + + if (options.nonegate) return + + for ( var i = 0, l = pattern.length + ; i < l && pattern.charAt(i) === "!" + ; i ++) { + negate = !negate + negateOffset ++ + } + + if (negateOffset) this.pattern = pattern.substr(negateOffset) + this.negate = negate +} + +// Brace expansion: +// a{b,c}d -> abd acd +// a{b,}c -> abc ac +// a{0..3}d -> a0d a1d a2d a3d +// a{b,c{d,e}f}g -> abg acdfg acefg +// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg +// +// Invalid sets are not expanded. +// a{2..}b -> a{2..}b +// a{b}c -> a{b}c +minimatch.braceExpand = function (pattern, options) { + return new Minimatch(pattern, options).braceExpand() +} + +Minimatch.prototype.braceExpand = braceExpand +function braceExpand (pattern, options) { + options = options || this.options + pattern = typeof pattern === "undefined" + ? this.pattern : pattern + + if (typeof pattern === "undefined") { + throw new Error("undefined pattern") + } + + if (options.nobrace || + !pattern.match(/\{.*\}/)) { + // shortcut. no need to expand. + return [pattern] + } + + var escaping = false + + // examples and comments refer to this crazy pattern: + // a{b,c{d,e},{f,g}h}x{y,z} + // expected: + // abxy + // abxz + // acdxy + // acdxz + // acexy + // acexz + // afhxy + // afhxz + // aghxy + // aghxz + + // everything before the first \{ is just a prefix. + // So, we pluck that off, and work with the rest, + // and then prepend it to everything we find. + if (pattern.charAt(0) !== "{") { + this.debug(pattern) + var prefix = null + for (var i = 0, l = pattern.length; i < l; i ++) { + var c = pattern.charAt(i) + this.debug(i, c) + if (c === "\\") { + escaping = !escaping + } else if (c === "{" && !escaping) { + prefix = pattern.substr(0, i) + break + } + } + + // actually no sets, all { were escaped. + if (prefix === null) { + this.debug("no sets") + return [pattern] + } + + var tail = braceExpand.call(this, pattern.substr(i), options) + return tail.map(function (t) { + return prefix + t + }) + } + + // now we have something like: + // {b,c{d,e},{f,g}h}x{y,z} + // walk through the set, expanding each part, until + // the set ends. then, we'll expand the suffix. + // If the set only has a single member, then'll put the {} back + + // first, handle numeric sets, since they're easier + var numset = pattern.match(/^\{(-?[0-9]+)\.\.(-?[0-9]+)\}/) + if (numset) { + this.debug("numset", numset[1], numset[2]) + var suf = braceExpand.call(this, pattern.substr(numset[0].length), options) + , start = +numset[1] + , end = +numset[2] + , inc = start > end ? -1 : 1 + , set = [] + for (var i = start; i != (end + inc); i += inc) { + // append all the suffixes + for (var ii = 0, ll = suf.length; ii < ll; ii ++) { + set.push(i + suf[ii]) + } + } + return set + } + + // ok, walk through the set + // We hope, somewhat optimistically, that there + // will be a } at the end. + // If the closing brace isn't found, then the pattern is + // interpreted as braceExpand("\\" + pattern) so that + // the leading \{ will be interpreted literally. + var i = 1 // skip the \{ + , depth = 1 + , set = [] + , member = "" + , sawEnd = false + , escaping = false + + function addMember () { + set.push(member) + member = "" + } + + this.debug("Entering for") + FOR: for (i = 1, l = pattern.length; i < l; i ++) { + var c = pattern.charAt(i) + this.debug("", i, c) + + if (escaping) { + escaping = false + member += "\\" + c + } else { + switch (c) { + case "\\": + escaping = true + continue + + case "{": + depth ++ + member += "{" + continue + + case "}": + depth -- + // if this closes the actual set, then we're done + if (depth === 0) { + addMember() + // pluck off the close-brace + i ++ + break FOR + } else { + member += c + continue + } + + case ",": + if (depth === 1) { + addMember() + } else { + member += c + } + continue + + default: + member += c + continue + } // switch + } // else + } // for + + // now we've either finished the set, and the suffix is + // pattern.substr(i), or we have *not* closed the set, + // and need to escape the leading brace + if (depth !== 0) { + this.debug("didn't close", pattern) + return braceExpand.call(this, "\\" + pattern, options) + } + + // x{y,z} -> ["xy", "xz"] + this.debug("set", set) + this.debug("suffix", pattern.substr(i)) + var suf = braceExpand.call(this, pattern.substr(i), options) + // ["b", "c{d,e}","{f,g}h"] -> + // [["b"], ["cd", "ce"], ["fh", "gh"]] + var addBraces = set.length === 1 + this.debug("set pre-expanded", set) + set = set.map(function (p) { + return braceExpand.call(this, p, options) + }, this) + this.debug("set expanded", set) + + + // [["b"], ["cd", "ce"], ["fh", "gh"]] -> + // ["b", "cd", "ce", "fh", "gh"] + set = set.reduce(function (l, r) { + return l.concat(r) + }) + + if (addBraces) { + set = set.map(function (s) { + return "{" + s + "}" + }) + } + + // now attach the suffixes. + var ret = [] + for (var i = 0, l = set.length; i < l; i ++) { + for (var ii = 0, ll = suf.length; ii < ll; ii ++) { + ret.push(set[i] + suf[ii]) + } + } + return ret +} + +// parse a component of the expanded set. +// At this point, no pattern may contain "/" in it +// so we're going to return a 2d array, where each entry is the full +// pattern, split on '/', and then turned into a regular expression. +// A regexp is made at the end which joins each array with an +// escaped /, and another full one which joins each regexp with |. +// +// Following the lead of Bash 4.1, note that "**" only has special meaning +// when it is the *only* thing in a path portion. Otherwise, any series +// of * is equivalent to a single *. Globstar behavior is enabled by +// default, and can be disabled by setting options.noglobstar. +Minimatch.prototype.parse = parse +var SUBPARSE = {} +function parse (pattern, isSub) { + var options = this.options + + // shortcuts + if (!options.noglobstar && pattern === "**") return GLOBSTAR + if (pattern === "") return "" + + var re = "" + , hasMagic = !!options.nocase + , escaping = false + // ? => one single character + , patternListStack = [] + , plType + , stateChar + , inClass = false + , reClassStart = -1 + , classStart = -1 + // . and .. never match anything that doesn't start with ., + // even when options.dot is set. + , patternStart = pattern.charAt(0) === "." ? "" // anything + // not (start or / followed by . or .. followed by / or end) + : options.dot ? "(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))" + : "(?!\\.)" + , self = this + + function clearStateChar () { + if (stateChar) { + // we had some state-tracking character + // that wasn't consumed by this pass. + switch (stateChar) { + case "*": + re += star + hasMagic = true + break + case "?": + re += qmark + hasMagic = true + break + default: + re += "\\"+stateChar + break + } + self.debug('clearStateChar %j %j', stateChar, re) + stateChar = false + } + } + + for ( var i = 0, len = pattern.length, c + ; (i < len) && (c = pattern.charAt(i)) + ; i ++ ) { + + this.debug("%s\t%s %s %j", pattern, i, re, c) + + // skip over any that are escaped. + if (escaping && reSpecials[c]) { + re += "\\" + c + escaping = false + continue + } + + SWITCH: switch (c) { + case "/": + // completely not allowed, even escaped. + // Should already be path-split by now. + return false + + case "\\": + clearStateChar() + escaping = true + continue + + // the various stateChar values + // for the "extglob" stuff. + case "?": + case "*": + case "+": + case "@": + case "!": + this.debug("%s\t%s %s %j <-- stateChar", pattern, i, re, c) + + // all of those are literals inside a class, except that + // the glob [!a] means [^a] in regexp + if (inClass) { + this.debug(' in class') + if (c === "!" && i === classStart + 1) c = "^" + re += c + continue + } + + // if we already have a stateChar, then it means + // that there was something like ** or +? in there. + // Handle the stateChar, then proceed with this one. + self.debug('call clearStateChar %j', stateChar) + clearStateChar() + stateChar = c + // if extglob is disabled, then +(asdf|foo) isn't a thing. + // just clear the statechar *now*, rather than even diving into + // the patternList stuff. + if (options.noext) clearStateChar() + continue + + case "(": + if (inClass) { + re += "(" + continue + } + + if (!stateChar) { + re += "\\(" + continue + } + + plType = stateChar + patternListStack.push({ type: plType + , start: i - 1 + , reStart: re.length }) + // negation is (?:(?!js)[^/]*) + re += stateChar === "!" ? "(?:(?!" : "(?:" + this.debug('plType %j %j', stateChar, re) + stateChar = false + continue + + case ")": + if (inClass || !patternListStack.length) { + re += "\\)" + continue + } + + clearStateChar() + hasMagic = true + re += ")" + plType = patternListStack.pop().type + // negation is (?:(?!js)[^/]*) + // The others are (?:) + switch (plType) { + case "!": + re += "[^/]*?)" + break + case "?": + case "+": + case "*": re += plType + case "@": break // the default anyway + } + continue + + case "|": + if (inClass || !patternListStack.length || escaping) { + re += "\\|" + escaping = false + continue + } + + clearStateChar() + re += "|" + continue + + // these are mostly the same in regexp and glob + case "[": + // swallow any state-tracking char before the [ + clearStateChar() + + if (inClass) { + re += "\\" + c + continue + } + + inClass = true + classStart = i + reClassStart = re.length + re += c + continue + + case "]": + // a right bracket shall lose its special + // meaning and represent itself in + // a bracket expression if it occurs + // first in the list. -- POSIX.2 2.8.3.2 + if (i === classStart + 1 || !inClass) { + re += "\\" + c + escaping = false + continue + } + + // finish up the class. + hasMagic = true + inClass = false + re += c + continue + + default: + // swallow any state char that wasn't consumed + clearStateChar() + + if (escaping) { + // no need + escaping = false + } else if (reSpecials[c] + && !(c === "^" && inClass)) { + re += "\\" + } + + re += c + + } // switch + } // for + + + // handle the case where we left a class open. + // "[abc" is valid, equivalent to "\[abc" + if (inClass) { + // split where the last [ was, and escape it + // this is a huge pita. We now have to re-walk + // the contents of the would-be class to re-translate + // any characters that were passed through as-is + var cs = pattern.substr(classStart + 1) + , sp = this.parse(cs, SUBPARSE) + re = re.substr(0, reClassStart) + "\\[" + sp[0] + hasMagic = hasMagic || sp[1] + } + + // handle the case where we had a +( thing at the *end* + // of the pattern. + // each pattern list stack adds 3 chars, and we need to go through + // and escape any | chars that were passed through as-is for the regexp. + // Go through and escape them, taking care not to double-escape any + // | chars that were already escaped. + var pl + while (pl = patternListStack.pop()) { + var tail = re.slice(pl.reStart + 3) + // maybe some even number of \, then maybe 1 \, followed by a | + tail = tail.replace(/((?:\\{2})*)(\\?)\|/g, function (_, $1, $2) { + if (!$2) { + // the | isn't already escaped, so escape it. + $2 = "\\" + } + + // need to escape all those slashes *again*, without escaping the + // one that we need for escaping the | character. As it works out, + // escaping an even number of slashes can be done by simply repeating + // it exactly after itself. That's why this trick works. + // + // I am sorry that you have to see this. + return $1 + $1 + $2 + "|" + }) + + this.debug("tail=%j\n %s", tail, tail) + var t = pl.type === "*" ? star + : pl.type === "?" ? qmark + : "\\" + pl.type + + hasMagic = true + re = re.slice(0, pl.reStart) + + t + "\\(" + + tail + } + + // handle trailing things that only matter at the very end. + clearStateChar() + if (escaping) { + // trailing \\ + re += "\\\\" + } + + // only need to apply the nodot start if the re starts with + // something that could conceivably capture a dot + var addPatternStart = false + switch (re.charAt(0)) { + case ".": + case "[": + case "(": addPatternStart = true + } + + // if the re is not "" at this point, then we need to make sure + // it doesn't match against an empty path part. + // Otherwise a/* will match a/, which it should not. + if (re !== "" && hasMagic) re = "(?=.)" + re + + if (addPatternStart) re = patternStart + re + + // parsing just a piece of a larger pattern. + if (isSub === SUBPARSE) { + return [ re, hasMagic ] + } + + // skip the regexp for non-magical patterns + // unescape anything in it, though, so that it'll be + // an exact match against a file etc. + if (!hasMagic) { + return globUnescape(pattern) + } + + var flags = options.nocase ? "i" : "" + , regExp = new RegExp("^" + re + "$", flags) + + regExp._glob = pattern + regExp._src = re + + return regExp +} + +minimatch.makeRe = function (pattern, options) { + return new Minimatch(pattern, options || {}).makeRe() +} + +Minimatch.prototype.makeRe = makeRe +function makeRe () { + if (this.regexp || this.regexp === false) return this.regexp + + // at this point, this.set is a 2d array of partial + // pattern strings, or "**". + // + // It's better to use .match(). This function shouldn't + // be used, really, but it's pretty convenient sometimes, + // when you just want to work with a regex. + var set = this.set + + if (!set.length) return this.regexp = false + var options = this.options + + var twoStar = options.noglobstar ? star + : options.dot ? twoStarDot + : twoStarNoDot + , flags = options.nocase ? "i" : "" + + var re = set.map(function (pattern) { + return pattern.map(function (p) { + return (p === GLOBSTAR) ? twoStar + : (typeof p === "string") ? regExpEscape(p) + : p._src + }).join("\\\/") + }).join("|") + + // must match entire pattern + // ending in a * or ** will make it less strict. + re = "^(?:" + re + ")$" + + // can match anything, as long as it's not this. + if (this.negate) re = "^(?!" + re + ").*$" + + try { + return this.regexp = new RegExp(re, flags) + } catch (ex) { + return this.regexp = false + } +} + +minimatch.match = function (list, pattern, options) { + var mm = new Minimatch(pattern, options) + list = list.filter(function (f) { + return mm.match(f) + }) + if (options.nonull && !list.length) { + list.push(pattern) + } + return list +} + +Minimatch.prototype.match = match +function match (f, partial) { + this.debug("match", f, this.pattern) + // short-circuit in the case of busted things. + // comments, etc. + if (this.comment) return false + if (this.empty) return f === "" + + if (f === "/" && partial) return true + + var options = this.options + + // windows: need to use /, not \ + // On other platforms, \ is a valid (albeit bad) filename char. + if (platform === "win32") { + f = f.split("\\").join("/") + } + + // treat the test path as a set of pathparts. + f = f.split(slashSplit) + this.debug(this.pattern, "split", f) + + // just ONE of the pattern sets in this.set needs to match + // in order for it to be valid. If negating, then just one + // match means that we have failed. + // Either way, return on the first hit. + + var set = this.set + this.debug(this.pattern, "set", set) + + var splitFile = path.basename(f.join("/")).split("/") + + for (var i = 0, l = set.length; i < l; i ++) { + var pattern = set[i], file = f + if (options.matchBase && pattern.length === 1) { + file = splitFile + } + var hit = this.matchOne(file, pattern, partial) + if (hit) { + if (options.flipNegate) return true + return !this.negate + } + } + + // didn't get any hits. this is success if it's a negative + // pattern, failure otherwise. + if (options.flipNegate) return false + return this.negate +} + +// set partial to true to test if, for example, +// "/a/b" matches the start of "/*/b/*/d" +// Partial means, if you run out of file before you run +// out of pattern, then that's fine, as long as all +// the parts match. +Minimatch.prototype.matchOne = function (file, pattern, partial) { + var options = this.options + + this.debug("matchOne", + { "this": this + , file: file + , pattern: pattern }) + + this.debug("matchOne", file.length, pattern.length) + + for ( var fi = 0 + , pi = 0 + , fl = file.length + , pl = pattern.length + ; (fi < fl) && (pi < pl) + ; fi ++, pi ++ ) { + + this.debug("matchOne loop") + var p = pattern[pi] + , f = file[fi] + + this.debug(pattern, p, f) + + // should be impossible. + // some invalid regexp stuff in the set. + if (p === false) return false + + if (p === GLOBSTAR) { + this.debug('GLOBSTAR', [pattern, p, f]) + + // "**" + // a/**/b/**/c would match the following: + // a/b/x/y/z/c + // a/x/y/z/b/c + // a/b/x/b/x/c + // a/b/c + // To do this, take the rest of the pattern after + // the **, and see if it would match the file remainder. + // If so, return success. + // If not, the ** "swallows" a segment, and try again. + // This is recursively awful. + // + // a/**/b/**/c matching a/b/x/y/z/c + // - a matches a + // - doublestar + // - matchOne(b/x/y/z/c, b/**/c) + // - b matches b + // - doublestar + // - matchOne(x/y/z/c, c) -> no + // - matchOne(y/z/c, c) -> no + // - matchOne(z/c, c) -> no + // - matchOne(c, c) yes, hit + var fr = fi + , pr = pi + 1 + if (pr === pl) { + this.debug('** at the end') + // a ** at the end will just swallow the rest. + // We have found a match. + // however, it will not swallow /.x, unless + // options.dot is set. + // . and .. are *never* matched by **, for explosively + // exponential reasons. + for ( ; fi < fl; fi ++) { + if (file[fi] === "." || file[fi] === ".." || + (!options.dot && file[fi].charAt(0) === ".")) return false + } + return true + } + + // ok, let's see if we can swallow whatever we can. + WHILE: while (fr < fl) { + var swallowee = file[fr] + + this.debug('\nglobstar while', + file, fr, pattern, pr, swallowee) + + // XXX remove this slice. Just pass the start index. + if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { + this.debug('globstar found match!', fr, fl, swallowee) + // found a match. + return true + } else { + // can't swallow "." or ".." ever. + // can only swallow ".foo" when explicitly asked. + if (swallowee === "." || swallowee === ".." || + (!options.dot && swallowee.charAt(0) === ".")) { + this.debug("dot detected!", file, fr, pattern, pr) + break WHILE + } + + // ** swallows a segment, and continue. + this.debug('globstar swallow a segment, and continue') + fr ++ + } + } + // no match was found. + // However, in partial mode, we can't say this is necessarily over. + // If there's more *pattern* left, then + if (partial) { + // ran out of file + this.debug("\n>>> no match, partial?", file, fr, pattern, pr) + if (fr === fl) return true + } + return false + } + + // something other than ** + // non-magic patterns just have to match exactly + // patterns with magic have been turned into regexps. + var hit + if (typeof p === "string") { + if (options.nocase) { + hit = f.toLowerCase() === p.toLowerCase() + } else { + hit = f === p + } + this.debug("string match", p, f, hit) + } else { + hit = f.match(p) + this.debug("pattern match", p, f, hit) + } + + if (!hit) return false + } + + // Note: ending in / means that we'll get a final "" + // at the end of the pattern. This can only match a + // corresponding "" at the end of the file. + // If the file ends in /, then it can only match a + // a pattern that ends in /, unless the pattern just + // doesn't have any more for it. But, a/b/ should *not* + // match "a/b/*", even though "" matches against the + // [^/]*? pattern, except in partial mode, where it might + // simply not be reached yet. + // However, a/b/ should still satisfy a/* + + // now either we fell off the end of the pattern, or we're done. + if (fi === fl && pi === pl) { + // ran out of pattern and filename at the same time. + // an exact hit! + return true + } else if (fi === fl) { + // ran out of file, but still had pattern left. + // this is ok if we're doing the match as part of + // a glob fs traversal. + return partial + } else if (pi === pl) { + // ran out of pattern, still have file left. + // this is only acceptable if we're on the very last + // empty segment of a file with a trailing slash. + // a/* should match a/b/ + var emptyFileEnd = (fi === fl - 1) && (file[fi] === "") + return emptyFileEnd + } + + // should be unreachable. + throw new Error("wtf?") +} + + +// replace stuff like \* with * +function globUnescape (s) { + return s.replace(/\\(.)/g, "$1") +} + + +function regExpEscape (s) { + return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") +} + +})( typeof require === "function" ? require : null, + this, + typeof module === "object" ? module : null, + typeof process === "object" ? process.platform : "win32" + ) diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/.npmignore b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/.npmignore new file mode 100644 index 0000000000..07e6e472cc --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/.npmignore @@ -0,0 +1 @@ +/node_modules diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/CONTRIBUTORS b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/CONTRIBUTORS new file mode 100644 index 0000000000..4a0bc5033a --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/CONTRIBUTORS @@ -0,0 +1,14 @@ +# Authors, sorted by whether or not they are me +Isaac Z. Schlueter +Brian Cottingham +Carlos Brito Lage +Jesse Dailey +Kevin O'Hara +Marco Rogers +Mark Cavage +Marko Mikulicic +Nathan Rajlich +Satheesh Natesan +Trent Mick +ashleybrener +n4kz diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/LICENSE b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/LICENSE new file mode 100644 index 0000000000..05a4010949 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/LICENSE @@ -0,0 +1,23 @@ +Copyright 2009, 2010, 2011 Isaac Z. Schlueter. +All rights reserved. + +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 +copies 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 all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER 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. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/README.md b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/README.md new file mode 100644 index 0000000000..03ee0f9850 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/README.md @@ -0,0 +1,97 @@ +# lru cache + +A cache object that deletes the least-recently-used items. + +## Usage: + +```javascript +var LRU = require("lru-cache") + , options = { max: 500 + , length: function (n) { return n * 2 } + , dispose: function (key, n) { n.close() } + , maxAge: 1000 * 60 * 60 } + , cache = LRU(options) + , otherCache = LRU(50) // sets just the max size + +cache.set("key", "value") +cache.get("key") // "value" + +cache.reset() // empty the cache +``` + +If you put more stuff in it, then items will fall out. + +If you try to put an oversized thing in it, then it'll fall out right +away. + +## Options + +* `max` The maximum size of the cache, checked by applying the length + function to all values in the cache. Not setting this is kind of + silly, since that's the whole purpose of this lib, but it defaults + to `Infinity`. +* `maxAge` Maximum age in ms. Items are not pro-actively pruned out + as they age, but if you try to get an item that is too old, it'll + drop it and return undefined instead of giving it to you. +* `length` Function that is used to calculate the length of stored + items. If you're storing strings or buffers, then you probably want + to do something like `function(n){return n.length}`. The default is + `function(n){return 1}`, which is fine if you want to store `n` + like-sized things. +* `dispose` Function that is called on items when they are dropped + from the cache. This can be handy if you want to close file + descriptors or do other cleanup tasks when items are no longer + accessible. Called with `key, value`. It's called *before* + actually removing the item from the internal cache, so if you want + to immediately put it back in, you'll have to do that in a + `nextTick` or `setTimeout` callback or it won't do anything. +* `stale` By default, if you set a `maxAge`, it'll only actually pull + stale items out of the cache when you `get(key)`. (That is, it's + not pre-emptively doing a `setTimeout` or anything.) If you set + `stale:true`, it'll return the stale value before deleting it. If + you don't set this, then it'll return `undefined` when you try to + get a stale entry, as if it had already been deleted. + +## API + +* `set(key, value)` +* `get(key) => value` + + Both of these will update the "recently used"-ness of the key. + They do what you think. + +* `peek(key)` + + Returns the key value (or `undefined` if not found) without + updating the "recently used"-ness of the key. + + (If you find yourself using this a lot, you *might* be using the + wrong sort of data structure, but there are some use cases where + it's handy.) + +* `del(key)` + + Deletes a key out of the cache. + +* `reset()` + + Clear the cache entirely, throwing away all values. + +* `has(key)` + + Check if a key is in the cache, without updating the recent-ness + or deleting it for being stale. + +* `forEach(function(value,key,cache), [thisp])` + + Just like `Array.prototype.forEach`. Iterates over all the keys + in the cache, in order of recent-ness. (Ie, more recently used + items are iterated over first.) + +* `keys()` + + Return an array of the keys in the cache. + +* `values()` + + Return an array of the values in the cache. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js new file mode 100644 index 0000000000..d1d1381720 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js @@ -0,0 +1,252 @@ +;(function () { // closure for web browsers + +if (typeof module === 'object' && module.exports) { + module.exports = LRUCache +} else { + // just set the global for non-node platforms. + this.LRUCache = LRUCache +} + +function hOP (obj, key) { + return Object.prototype.hasOwnProperty.call(obj, key) +} + +function naiveLength () { return 1 } + +function LRUCache (options) { + if (!(this instanceof LRUCache)) + return new LRUCache(options) + + if (typeof options === 'number') + options = { max: options } + + if (!options) + options = {} + + this._max = options.max + // Kind of weird to have a default max of Infinity, but oh well. + if (!this._max || !(typeof this._max === "number") || this._max <= 0 ) + this._max = Infinity + + this._lengthCalculator = options.length || naiveLength + if (typeof this._lengthCalculator !== "function") + this._lengthCalculator = naiveLength + + this._allowStale = options.stale || false + this._maxAge = options.maxAge || null + this._dispose = options.dispose + this.reset() +} + +// resize the cache when the max changes. +Object.defineProperty(LRUCache.prototype, "max", + { set : function (mL) { + if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity + this._max = mL + if (this._length > this._max) trim(this) + } + , get : function () { return this._max } + , enumerable : true + }) + +// resize the cache when the lengthCalculator changes. +Object.defineProperty(LRUCache.prototype, "lengthCalculator", + { set : function (lC) { + if (typeof lC !== "function") { + this._lengthCalculator = naiveLength + this._length = this._itemCount + for (var key in this._cache) { + this._cache[key].length = 1 + } + } else { + this._lengthCalculator = lC + this._length = 0 + for (var key in this._cache) { + this._cache[key].length = this._lengthCalculator(this._cache[key].value) + this._length += this._cache[key].length + } + } + + if (this._length > this._max) trim(this) + } + , get : function () { return this._lengthCalculator } + , enumerable : true + }) + +Object.defineProperty(LRUCache.prototype, "length", + { get : function () { return this._length } + , enumerable : true + }) + + +Object.defineProperty(LRUCache.prototype, "itemCount", + { get : function () { return this._itemCount } + , enumerable : true + }) + +LRUCache.prototype.forEach = function (fn, thisp) { + thisp = thisp || this + var i = 0; + for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) { + i++ + var hit = this._lruList[k] + if (this._maxAge && (Date.now() - hit.now > this._maxAge)) { + del(this, hit) + if (!this._allowStale) hit = undefined + } + if (hit) { + fn.call(thisp, hit.value, hit.key, this) + } + } +} + +LRUCache.prototype.keys = function () { + var keys = new Array(this._itemCount) + var i = 0 + for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) { + var hit = this._lruList[k] + keys[i++] = hit.key + } + return keys +} + +LRUCache.prototype.values = function () { + var values = new Array(this._itemCount) + var i = 0 + for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) { + var hit = this._lruList[k] + values[i++] = hit.value + } + return values +} + +LRUCache.prototype.reset = function () { + if (this._dispose && this._cache) { + for (var k in this._cache) { + this._dispose(k, this._cache[k].value) + } + } + + this._cache = Object.create(null) // hash of items by key + this._lruList = Object.create(null) // list of items in order of use recency + this._mru = 0 // most recently used + this._lru = 0 // least recently used + this._length = 0 // number of items in the list + this._itemCount = 0 +} + +// Provided for debugging/dev purposes only. No promises whatsoever that +// this API stays stable. +LRUCache.prototype.dump = function () { + return this._cache +} + +LRUCache.prototype.dumpLru = function () { + return this._lruList +} + +LRUCache.prototype.set = function (key, value) { + if (hOP(this._cache, key)) { + // dispose of the old one before overwriting + if (this._dispose) this._dispose(key, this._cache[key].value) + if (this._maxAge) this._cache[key].now = Date.now() + this._cache[key].value = value + this.get(key) + return true + } + + var len = this._lengthCalculator(value) + var age = this._maxAge ? Date.now() : 0 + var hit = new Entry(key, value, this._mru++, len, age) + + // oversized objects fall out of cache automatically. + if (hit.length > this._max) { + if (this._dispose) this._dispose(key, value) + return false + } + + this._length += hit.length + this._lruList[hit.lu] = this._cache[key] = hit + this._itemCount ++ + + if (this._length > this._max) trim(this) + return true +} + +LRUCache.prototype.has = function (key) { + if (!hOP(this._cache, key)) return false + var hit = this._cache[key] + if (this._maxAge && (Date.now() - hit.now > this._maxAge)) { + return false + } + return true +} + +LRUCache.prototype.get = function (key) { + return get(this, key, true) +} + +LRUCache.prototype.peek = function (key) { + return get(this, key, false) +} + +LRUCache.prototype.pop = function () { + var hit = this._lruList[this._lru] + del(this, hit) + return hit || null +} + +LRUCache.prototype.del = function (key) { + del(this, this._cache[key]) +} + +function get (self, key, doUse) { + var hit = self._cache[key] + if (hit) { + if (self._maxAge && (Date.now() - hit.now > self._maxAge)) { + del(self, hit) + if (!self._allowStale) hit = undefined + } else { + if (doUse) use(self, hit) + } + if (hit) hit = hit.value + } + return hit +} + +function use (self, hit) { + shiftLU(self, hit) + hit.lu = self._mru ++ + self._lruList[hit.lu] = hit +} + +function trim (self) { + while (self._lru < self._mru && self._length > self._max) + del(self, self._lruList[self._lru]) +} + +function shiftLU (self, hit) { + delete self._lruList[ hit.lu ] + while (self._lru < self._mru && !self._lruList[self._lru]) self._lru ++ +} + +function del (self, hit) { + if (hit) { + if (self._dispose) self._dispose(hit.key, hit.value) + self._length -= hit.length + self._itemCount -- + delete self._cache[ hit.key ] + shiftLU(self, hit) + } +} + +// classy, since V8 prefers predictable objects. +function Entry (key, value, lu, length, now) { + this.key = key + this.value = value + this.lu = lu + this.length = length + this.now = now +} + +})() diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/package.json b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/package.json new file mode 100644 index 0000000000..4472725df9 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/package.json @@ -0,0 +1,33 @@ +{ + "name": "lru-cache", + "description": "A cache object that deletes the least-recently-used items.", + "version": "2.5.0", + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me" + }, + "scripts": { + "test": "tap test --gc" + }, + "main": "lib/lru-cache.js", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/node-lru-cache.git" + }, + "devDependencies": { + "tap": "", + "weak": "" + }, + "license": { + "type": "MIT", + "url": "http://github.com/isaacs/node-lru-cache/raw/master/LICENSE" + }, + "readme": "# lru cache\n\nA cache object that deletes the least-recently-used items.\n\n## Usage:\n\n```javascript\nvar LRU = require(\"lru-cache\")\n , options = { max: 500\n , length: function (n) { return n * 2 }\n , dispose: function (key, n) { n.close() }\n , maxAge: 1000 * 60 * 60 }\n , cache = LRU(options)\n , otherCache = LRU(50) // sets just the max size\n\ncache.set(\"key\", \"value\")\ncache.get(\"key\") // \"value\"\n\ncache.reset() // empty the cache\n```\n\nIf you put more stuff in it, then items will fall out.\n\nIf you try to put an oversized thing in it, then it'll fall out right\naway.\n\n## Options\n\n* `max` The maximum size of the cache, checked by applying the length\n function to all values in the cache. Not setting this is kind of\n silly, since that's the whole purpose of this lib, but it defaults\n to `Infinity`.\n* `maxAge` Maximum age in ms. Items are not pro-actively pruned out\n as they age, but if you try to get an item that is too old, it'll\n drop it and return undefined instead of giving it to you.\n* `length` Function that is used to calculate the length of stored\n items. If you're storing strings or buffers, then you probably want\n to do something like `function(n){return n.length}`. The default is\n `function(n){return 1}`, which is fine if you want to store `n`\n like-sized things.\n* `dispose` Function that is called on items when they are dropped\n from the cache. This can be handy if you want to close file\n descriptors or do other cleanup tasks when items are no longer\n accessible. Called with `key, value`. It's called *before*\n actually removing the item from the internal cache, so if you want\n to immediately put it back in, you'll have to do that in a\n `nextTick` or `setTimeout` callback or it won't do anything.\n* `stale` By default, if you set a `maxAge`, it'll only actually pull\n stale items out of the cache when you `get(key)`. (That is, it's\n not pre-emptively doing a `setTimeout` or anything.) If you set\n `stale:true`, it'll return the stale value before deleting it. If\n you don't set this, then it'll return `undefined` when you try to\n get a stale entry, as if it had already been deleted.\n\n## API\n\n* `set(key, value)`\n* `get(key) => value`\n\n Both of these will update the \"recently used\"-ness of the key.\n They do what you think.\n\n* `peek(key)`\n\n Returns the key value (or `undefined` if not found) without\n updating the \"recently used\"-ness of the key.\n\n (If you find yourself using this a lot, you *might* be using the\n wrong sort of data structure, but there are some use cases where\n it's handy.)\n\n* `del(key)`\n\n Deletes a key out of the cache.\n\n* `reset()`\n\n Clear the cache entirely, throwing away all values.\n\n* `has(key)`\n\n Check if a key is in the cache, without updating the recent-ness\n or deleting it for being stale.\n\n* `forEach(function(value,key,cache), [thisp])`\n\n Just like `Array.prototype.forEach`. Iterates over all the keys\n in the cache, in order of recent-ness. (Ie, more recently used\n items are iterated over first.)\n\n* `keys()`\n\n Return an array of the keys in the cache.\n\n* `values()`\n\n Return an array of the values in the cache.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/node-lru-cache/issues" + }, + "homepage": "https://github.com/isaacs/node-lru-cache", + "_id": "lru-cache@2.5.0", + "_from": "lru-cache@2" +} diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/basic.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/basic.js new file mode 100644 index 0000000000..f72697c461 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/basic.js @@ -0,0 +1,369 @@ +var test = require("tap").test + , LRU = require("../") + +test("basic", function (t) { + var cache = new LRU({max: 10}) + cache.set("key", "value") + t.equal(cache.get("key"), "value") + t.equal(cache.get("nada"), undefined) + t.equal(cache.length, 1) + t.equal(cache.max, 10) + t.end() +}) + +test("least recently set", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.set("b", "B") + cache.set("c", "C") + t.equal(cache.get("c"), "C") + t.equal(cache.get("b"), "B") + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("lru recently gotten", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.set("b", "B") + cache.get("a") + cache.set("c", "C") + t.equal(cache.get("c"), "C") + t.equal(cache.get("b"), undefined) + t.equal(cache.get("a"), "A") + t.end() +}) + +test("del", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.del("a") + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("max", function (t) { + var cache = new LRU(3) + + // test changing the max, verify that the LRU items get dropped. + cache.max = 100 + for (var i = 0; i < 100; i ++) cache.set(i, i) + t.equal(cache.length, 100) + for (var i = 0; i < 100; i ++) { + t.equal(cache.get(i), i) + } + cache.max = 3 + t.equal(cache.length, 3) + for (var i = 0; i < 97; i ++) { + t.equal(cache.get(i), undefined) + } + for (var i = 98; i < 100; i ++) { + t.equal(cache.get(i), i) + } + + // now remove the max restriction, and try again. + cache.max = "hello" + for (var i = 0; i < 100; i ++) cache.set(i, i) + t.equal(cache.length, 100) + for (var i = 0; i < 100; i ++) { + t.equal(cache.get(i), i) + } + // should trigger an immediate resize + cache.max = 3 + t.equal(cache.length, 3) + for (var i = 0; i < 97; i ++) { + t.equal(cache.get(i), undefined) + } + for (var i = 98; i < 100; i ++) { + t.equal(cache.get(i), i) + } + t.end() +}) + +test("reset", function (t) { + var cache = new LRU(10) + cache.set("a", "A") + cache.set("b", "B") + cache.reset() + t.equal(cache.length, 0) + t.equal(cache.max, 10) + t.equal(cache.get("a"), undefined) + t.equal(cache.get("b"), undefined) + t.end() +}) + + +// Note: `.dump()` is a debugging tool only. No guarantees are made +// about the format/layout of the response. +test("dump", function (t) { + var cache = new LRU(10) + var d = cache.dump(); + t.equal(Object.keys(d).length, 0, "nothing in dump for empty cache") + cache.set("a", "A") + var d = cache.dump() // { a: { key: "a", value: "A", lu: 0 } } + t.ok(d.a) + t.equal(d.a.key, "a") + t.equal(d.a.value, "A") + t.equal(d.a.lu, 0) + + cache.set("b", "B") + cache.get("b") + d = cache.dump() + t.ok(d.b) + t.equal(d.b.key, "b") + t.equal(d.b.value, "B") + t.equal(d.b.lu, 2) + + t.end() +}) + + +test("basic with weighed length", function (t) { + var cache = new LRU({ + max: 100, + length: function (item) { return item.size } + }) + cache.set("key", {val: "value", size: 50}) + t.equal(cache.get("key").val, "value") + t.equal(cache.get("nada"), undefined) + t.equal(cache.lengthCalculator(cache.get("key")), 50) + t.equal(cache.length, 50) + t.equal(cache.max, 100) + t.end() +}) + + +test("weighed length item too large", function (t) { + var cache = new LRU({ + max: 10, + length: function (item) { return item.size } + }) + t.equal(cache.max, 10) + + // should fall out immediately + cache.set("key", {val: "value", size: 50}) + + t.equal(cache.length, 0) + t.equal(cache.get("key"), undefined) + t.end() +}) + +test("least recently set with weighed length", function (t) { + var cache = new LRU({ + max:8, + length: function (item) { return item.length } + }) + cache.set("a", "A") + cache.set("b", "BB") + cache.set("c", "CCC") + cache.set("d", "DDDD") + t.equal(cache.get("d"), "DDDD") + t.equal(cache.get("c"), "CCC") + t.equal(cache.get("b"), undefined) + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("lru recently gotten with weighed length", function (t) { + var cache = new LRU({ + max: 8, + length: function (item) { return item.length } + }) + cache.set("a", "A") + cache.set("b", "BB") + cache.set("c", "CCC") + cache.get("a") + cache.get("b") + cache.set("d", "DDDD") + t.equal(cache.get("c"), undefined) + t.equal(cache.get("d"), "DDDD") + t.equal(cache.get("b"), "BB") + t.equal(cache.get("a"), "A") + t.end() +}) + +test("set returns proper booleans", function(t) { + var cache = new LRU({ + max: 5, + length: function (item) { return item.length } + }) + + t.equal(cache.set("a", "A"), true) + + // should return false for max exceeded + t.equal(cache.set("b", "donuts"), false) + + t.equal(cache.set("b", "B"), true) + t.equal(cache.set("c", "CCCC"), true) + t.end() +}) + +test("drop the old items", function(t) { + var cache = new LRU({ + max: 5, + maxAge: 50 + }) + + cache.set("a", "A") + + setTimeout(function () { + cache.set("b", "b") + t.equal(cache.get("a"), "A") + }, 25) + + setTimeout(function () { + cache.set("c", "C") + // timed out + t.notOk(cache.get("a")) + }, 60) + + setTimeout(function () { + t.notOk(cache.get("b")) + t.equal(cache.get("c"), "C") + }, 90) + + setTimeout(function () { + t.notOk(cache.get("c")) + t.end() + }, 155) +}) + +test("disposal function", function(t) { + var disposed = false + var cache = new LRU({ + max: 1, + dispose: function (k, n) { + disposed = n + } + }) + + cache.set(1, 1) + cache.set(2, 2) + t.equal(disposed, 1) + cache.set(3, 3) + t.equal(disposed, 2) + cache.reset() + t.equal(disposed, 3) + t.end() +}) + +test("disposal function on too big of item", function(t) { + var disposed = false + var cache = new LRU({ + max: 1, + length: function (k) { + return k.length + }, + dispose: function (k, n) { + disposed = n + } + }) + var obj = [ 1, 2 ] + + t.equal(disposed, false) + cache.set("obj", obj) + t.equal(disposed, obj) + t.end() +}) + +test("has()", function(t) { + var cache = new LRU({ + max: 1, + maxAge: 10 + }) + + cache.set('foo', 'bar') + t.equal(cache.has('foo'), true) + cache.set('blu', 'baz') + t.equal(cache.has('foo'), false) + t.equal(cache.has('blu'), true) + setTimeout(function() { + t.equal(cache.has('blu'), false) + t.end() + }, 15) +}) + +test("stale", function(t) { + var cache = new LRU({ + maxAge: 10, + stale: true + }) + + cache.set('foo', 'bar') + t.equal(cache.get('foo'), 'bar') + t.equal(cache.has('foo'), true) + setTimeout(function() { + t.equal(cache.has('foo'), false) + t.equal(cache.get('foo'), 'bar') + t.equal(cache.get('foo'), undefined) + t.end() + }, 15) +}) + +test("lru update via set", function(t) { + var cache = LRU({ max: 2 }); + + cache.set('foo', 1); + cache.set('bar', 2); + cache.del('bar'); + cache.set('baz', 3); + cache.set('qux', 4); + + t.equal(cache.get('foo'), undefined) + t.equal(cache.get('bar'), undefined) + t.equal(cache.get('baz'), 3) + t.equal(cache.get('qux'), 4) + t.end() +}) + +test("least recently set w/ peek", function (t) { + var cache = new LRU(2) + cache.set("a", "A") + cache.set("b", "B") + t.equal(cache.peek("a"), "A") + cache.set("c", "C") + t.equal(cache.get("c"), "C") + t.equal(cache.get("b"), "B") + t.equal(cache.get("a"), undefined) + t.end() +}) + +test("pop the least used item", function (t) { + var cache = new LRU(3) + , last + + cache.set("a", "A") + cache.set("b", "B") + cache.set("c", "C") + + t.equal(cache.length, 3) + t.equal(cache.max, 3) + + // Ensure we pop a, c, b + cache.get("b", "B") + + last = cache.pop() + t.equal(last.key, "a") + t.equal(last.value, "A") + t.equal(cache.length, 2) + t.equal(cache.max, 3) + + last = cache.pop() + t.equal(last.key, "c") + t.equal(last.value, "C") + t.equal(cache.length, 1) + t.equal(cache.max, 3) + + last = cache.pop() + t.equal(last.key, "b") + t.equal(last.value, "B") + t.equal(cache.length, 0) + t.equal(cache.max, 3) + + last = cache.pop() + t.equal(last, null) + t.equal(cache.length, 0) + t.equal(cache.max, 3) + + t.end() +}) diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/foreach.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/foreach.js new file mode 100644 index 0000000000..eefb80d9d1 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/foreach.js @@ -0,0 +1,52 @@ +var test = require('tap').test +var LRU = require('../') + +test('forEach', function (t) { + var l = new LRU(5) + for (var i = 0; i < 10; i ++) { + l.set(i.toString(), i.toString(2)) + } + + var i = 9 + l.forEach(function (val, key, cache) { + t.equal(cache, l) + t.equal(key, i.toString()) + t.equal(val, i.toString(2)) + i -= 1 + }) + + // get in order of most recently used + l.get(6) + l.get(8) + + var order = [ 8, 6, 9, 7, 5 ] + var i = 0 + + l.forEach(function (val, key, cache) { + var j = order[i ++] + t.equal(cache, l) + t.equal(key, j.toString()) + t.equal(val, j.toString(2)) + }) + + t.end() +}) + +test('keys() and values()', function (t) { + var l = new LRU(5) + for (var i = 0; i < 10; i ++) { + l.set(i.toString(), i.toString(2)) + } + + t.similar(l.keys(), ['9', '8', '7', '6', '5']) + t.similar(l.values(), ['1001', '1000', '111', '110', '101']) + + // get in order of most recently used + l.get(6) + l.get(8) + + t.similar(l.keys(), ['8', '6', '9', '7', '5']) + t.similar(l.values(), ['1000', '110', '1001', '111', '101']) + + t.end() +}) diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js new file mode 100644 index 0000000000..7af45b0221 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js @@ -0,0 +1,50 @@ +#!/usr/bin/env node --expose_gc + +var weak = require('weak'); +var test = require('tap').test +var LRU = require('../') +var l = new LRU({ max: 10 }) +var refs = 0 +function X() { + refs ++ + weak(this, deref) +} + +function deref() { + refs -- +} + +test('no leaks', function (t) { + // fill up the cache + for (var i = 0; i < 100; i++) { + l.set(i, new X); + // throw some gets in there, too. + if (i % 2 === 0) + l.get(i / 2) + } + + gc() + + var start = process.memoryUsage() + + // capture the memory + var startRefs = refs + + // do it again, but more + for (var i = 0; i < 10000; i++) { + l.set(i, new X); + // throw some gets in there, too. + if (i % 2 === 0) + l.get(i / 2) + } + + gc() + + var end = process.memoryUsage() + t.equal(refs, startRefs, 'no leaky refs') + + console.error('start: %j\n' + + 'end: %j', start, end); + t.pass(); + t.end(); +}) diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/LICENSE b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/LICENSE new file mode 100644 index 0000000000..0c44ae716d --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/LICENSE @@ -0,0 +1,27 @@ +Copyright (c) Isaac Z. Schlueter ("Author") +All rights reserved. + +The BSD License + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + +1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS +BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR +BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, +WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN +IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/README.md b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/README.md new file mode 100644 index 0000000000..7e365129e4 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/README.md @@ -0,0 +1,53 @@ +# sigmund + +Quick and dirty signatures for Objects. + +This is like a much faster `deepEquals` comparison, which returns a +string key suitable for caches and the like. + +## Usage + +```javascript +function doSomething (someObj) { + var key = sigmund(someObj, maxDepth) // max depth defaults to 10 + var cached = cache.get(key) + if (cached) return cached) + + var result = expensiveCalculation(someObj) + cache.set(key, result) + return result +} +``` + +The resulting key will be as unique and reproducible as calling +`JSON.stringify` or `util.inspect` on the object, but is much faster. +In order to achieve this speed, some differences are glossed over. +For example, the object `{0:'foo'}` will be treated identically to the +array `['foo']`. + +Also, just as there is no way to summon the soul from the scribblings +of a cocain-addled psychoanalyst, there is no way to revive the object +from the signature string that sigmund gives you. In fact, it's +barely even readable. + +As with `sys.inspect` and `JSON.stringify`, larger objects will +produce larger signature strings. + +Because sigmund is a bit less strict than the more thorough +alternatives, the strings will be shorter, and also there is a +slightly higher chance for collisions. For example, these objects +have the same signature: + + var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]} + var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']} + +Like a good Freudian, sigmund is most effective when you already have +some understanding of what you're looking for. It can help you help +yourself, but you must be willing to do some work as well. + +Cycles are handled, and cyclical objects are silently omitted (though +the key is included in the signature output.) + +The second argument is the maximum depth, which defaults to 10, +because that is the maximum object traversal depth covered by most +insurance carriers. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/bench.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/bench.js new file mode 100644 index 0000000000..5acfd6d90d --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/bench.js @@ -0,0 +1,283 @@ +// different ways to id objects +// use a req/res pair, since it's crazy deep and cyclical + +// sparseFE10 and sigmund are usually pretty close, which is to be expected, +// since they are essentially the same algorithm, except that sigmund handles +// regular expression objects properly. + + +var http = require('http') +var util = require('util') +var sigmund = require('./sigmund.js') +var sreq, sres, creq, cres, test + +http.createServer(function (q, s) { + sreq = q + sres = s + sres.end('ok') + this.close(function () { setTimeout(function () { + start() + }, 200) }) +}).listen(1337, function () { + creq = http.get({ port: 1337 }) + creq.on('response', function (s) { cres = s }) +}) + +function start () { + test = [sreq, sres, creq, cres] + // test = sreq + // sreq.sres = sres + // sreq.creq = creq + // sreq.cres = cres + + for (var i in exports.compare) { + console.log(i) + var hash = exports.compare[i]() + console.log(hash) + console.log(hash.length) + console.log('') + } + + require('bench').runMain() +} + +function customWs (obj, md, d) { + d = d || 0 + var to = typeof obj + if (to === 'undefined' || to === 'function' || to === null) return '' + if (d > md || !obj || to !== 'object') return ('' + obj).replace(/[\n ]+/g, '') + + if (Array.isArray(obj)) { + return obj.map(function (i, _, __) { + return customWs(i, md, d + 1) + }).reduce(function (a, b) { return a + b }, '') + } + + var keys = Object.keys(obj) + return keys.map(function (k, _, __) { + return k + ':' + customWs(obj[k], md, d + 1) + }).reduce(function (a, b) { return a + b }, '') +} + +function custom (obj, md, d) { + d = d || 0 + var to = typeof obj + if (to === 'undefined' || to === 'function' || to === null) return '' + if (d > md || !obj || to !== 'object') return '' + obj + + if (Array.isArray(obj)) { + return obj.map(function (i, _, __) { + return custom(i, md, d + 1) + }).reduce(function (a, b) { return a + b }, '') + } + + var keys = Object.keys(obj) + return keys.map(function (k, _, __) { + return k + ':' + custom(obj[k], md, d + 1) + }).reduce(function (a, b) { return a + b }, '') +} + +function sparseFE2 (obj, maxDepth) { + var seen = [] + var soFar = '' + function ch (v, depth) { + if (depth > maxDepth) return + if (typeof v === 'function' || typeof v === 'undefined') return + if (typeof v !== 'object' || !v) { + soFar += v + return + } + if (seen.indexOf(v) !== -1 || depth === maxDepth) return + seen.push(v) + soFar += '{' + Object.keys(v).forEach(function (k, _, __) { + // pseudo-private values. skip those. + if (k.charAt(0) === '_') return + var to = typeof v[k] + if (to === 'function' || to === 'undefined') return + soFar += k + ':' + ch(v[k], depth + 1) + }) + soFar += '}' + } + ch(obj, 0) + return soFar +} + +function sparseFE (obj, maxDepth) { + var seen = [] + var soFar = '' + function ch (v, depth) { + if (depth > maxDepth) return + if (typeof v === 'function' || typeof v === 'undefined') return + if (typeof v !== 'object' || !v) { + soFar += v + return + } + if (seen.indexOf(v) !== -1 || depth === maxDepth) return + seen.push(v) + soFar += '{' + Object.keys(v).forEach(function (k, _, __) { + // pseudo-private values. skip those. + if (k.charAt(0) === '_') return + var to = typeof v[k] + if (to === 'function' || to === 'undefined') return + soFar += k + ch(v[k], depth + 1) + }) + } + ch(obj, 0) + return soFar +} + +function sparse (obj, maxDepth) { + var seen = [] + var soFar = '' + function ch (v, depth) { + if (depth > maxDepth) return + if (typeof v === 'function' || typeof v === 'undefined') return + if (typeof v !== 'object' || !v) { + soFar += v + return + } + if (seen.indexOf(v) !== -1 || depth === maxDepth) return + seen.push(v) + soFar += '{' + for (var k in v) { + // pseudo-private values. skip those. + if (k.charAt(0) === '_') continue + var to = typeof v[k] + if (to === 'function' || to === 'undefined') continue + soFar += k + ch(v[k], depth + 1) + } + } + ch(obj, 0) + return soFar +} + +function noCommas (obj, maxDepth) { + var seen = [] + var soFar = '' + function ch (v, depth) { + if (depth > maxDepth) return + if (typeof v === 'function' || typeof v === 'undefined') return + if (typeof v !== 'object' || !v) { + soFar += v + return + } + if (seen.indexOf(v) !== -1 || depth === maxDepth) return + seen.push(v) + soFar += '{' + for (var k in v) { + // pseudo-private values. skip those. + if (k.charAt(0) === '_') continue + var to = typeof v[k] + if (to === 'function' || to === 'undefined') continue + soFar += k + ':' + ch(v[k], depth + 1) + } + soFar += '}' + } + ch(obj, 0) + return soFar +} + + +function flatten (obj, maxDepth) { + var seen = [] + var soFar = '' + function ch (v, depth) { + if (depth > maxDepth) return + if (typeof v === 'function' || typeof v === 'undefined') return + if (typeof v !== 'object' || !v) { + soFar += v + return + } + if (seen.indexOf(v) !== -1 || depth === maxDepth) return + seen.push(v) + soFar += '{' + for (var k in v) { + // pseudo-private values. skip those. + if (k.charAt(0) === '_') continue + var to = typeof v[k] + if (to === 'function' || to === 'undefined') continue + soFar += k + ':' + ch(v[k], depth + 1) + soFar += ',' + } + soFar += '}' + } + ch(obj, 0) + return soFar +} + +exports.compare = +{ + // 'custom 2': function () { + // return custom(test, 2, 0) + // }, + // 'customWs 2': function () { + // return customWs(test, 2, 0) + // }, + 'JSON.stringify (guarded)': function () { + var seen = [] + return JSON.stringify(test, function (k, v) { + if (typeof v !== 'object' || !v) return v + if (seen.indexOf(v) !== -1) return undefined + seen.push(v) + return v + }) + }, + + 'flatten 10': function () { + return flatten(test, 10) + }, + + // 'flattenFE 10': function () { + // return flattenFE(test, 10) + // }, + + 'noCommas 10': function () { + return noCommas(test, 10) + }, + + 'sparse 10': function () { + return sparse(test, 10) + }, + + 'sparseFE 10': function () { + return sparseFE(test, 10) + }, + + 'sparseFE2 10': function () { + return sparseFE2(test, 10) + }, + + sigmund: function() { + return sigmund(test, 10) + }, + + + // 'util.inspect 1': function () { + // return util.inspect(test, false, 1, false) + // }, + // 'util.inspect undefined': function () { + // util.inspect(test) + // }, + // 'util.inspect 2': function () { + // util.inspect(test, false, 2, false) + // }, + // 'util.inspect 3': function () { + // util.inspect(test, false, 3, false) + // }, + // 'util.inspect 4': function () { + // util.inspect(test, false, 4, false) + // }, + // 'util.inspect Infinity': function () { + // util.inspect(test, false, Infinity, false) + // } +} + +/** results +**/ diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/package.json b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/package.json new file mode 100644 index 0000000000..cb7e2bd4b7 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/package.json @@ -0,0 +1,42 @@ +{ + "name": "sigmund", + "version": "1.0.0", + "description": "Quick and dirty signatures for Objects.", + "main": "sigmund.js", + "directories": { + "test": "test" + }, + "dependencies": {}, + "devDependencies": { + "tap": "~0.3.0" + }, + "scripts": { + "test": "tap test/*.js", + "bench": "node bench.js" + }, + "repository": { + "type": "git", + "url": "git://github.com/isaacs/sigmund" + }, + "keywords": [ + "object", + "signature", + "key", + "data", + "psychoanalysis" + ], + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + }, + "license": "BSD", + "readme": "# sigmund\n\nQuick and dirty signatures for Objects.\n\nThis is like a much faster `deepEquals` comparison, which returns a\nstring key suitable for caches and the like.\n\n## Usage\n\n```javascript\nfunction doSomething (someObj) {\n var key = sigmund(someObj, maxDepth) // max depth defaults to 10\n var cached = cache.get(key)\n if (cached) return cached)\n\n var result = expensiveCalculation(someObj)\n cache.set(key, result)\n return result\n}\n```\n\nThe resulting key will be as unique and reproducible as calling\n`JSON.stringify` or `util.inspect` on the object, but is much faster.\nIn order to achieve this speed, some differences are glossed over.\nFor example, the object `{0:'foo'}` will be treated identically to the\narray `['foo']`.\n\nAlso, just as there is no way to summon the soul from the scribblings\nof a cocain-addled psychoanalyst, there is no way to revive the object\nfrom the signature string that sigmund gives you. In fact, it's\nbarely even readable.\n\nAs with `sys.inspect` and `JSON.stringify`, larger objects will\nproduce larger signature strings.\n\nBecause sigmund is a bit less strict than the more thorough\nalternatives, the strings will be shorter, and also there is a\nslightly higher chance for collisions. For example, these objects\nhave the same signature:\n\n var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]}\n var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']}\n\nLike a good Freudian, sigmund is most effective when you already have\nsome understanding of what you're looking for. It can help you help\nyourself, but you must be willing to do some work as well.\n\nCycles are handled, and cyclical objects are silently omitted (though\nthe key is included in the signature output.)\n\nThe second argument is the maximum depth, which defaults to 10,\nbecause that is the maximum object traversal depth covered by most\ninsurance carriers.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/sigmund/issues" + }, + "homepage": "https://github.com/isaacs/sigmund", + "_id": "sigmund@1.0.0", + "_from": "sigmund@~1.0.0" +} diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/sigmund.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/sigmund.js new file mode 100644 index 0000000000..82c7ab8ce9 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/sigmund.js @@ -0,0 +1,39 @@ +module.exports = sigmund +function sigmund (subject, maxSessions) { + maxSessions = maxSessions || 10; + var notes = []; + var analysis = ''; + var RE = RegExp; + + function psychoAnalyze (subject, session) { + if (session > maxSessions) return; + + if (typeof subject === 'function' || + typeof subject === 'undefined') { + return; + } + + if (typeof subject !== 'object' || !subject || + (subject instanceof RE)) { + analysis += subject; + return; + } + + if (notes.indexOf(subject) !== -1 || session === maxSessions) return; + + notes.push(subject); + analysis += '{'; + Object.keys(subject).forEach(function (issue, _, __) { + // pseudo-private values. skip those. + if (issue.charAt(0) === '_') return; + var to = typeof subject[issue]; + if (to === 'function' || to === 'undefined') return; + analysis += issue; + psychoAnalyze(subject[issue], session + 1); + }); + } + psychoAnalyze(subject, 0); + return analysis; +} + +// vim: set softtabstop=4 shiftwidth=4: diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/test/basic.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/test/basic.js new file mode 100644 index 0000000000..50c53a13e9 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/test/basic.js @@ -0,0 +1,24 @@ +var test = require('tap').test +var sigmund = require('../sigmund.js') + + +// occasionally there are duplicates +// that's an acceptable edge-case. JSON.stringify and util.inspect +// have some collision potential as well, though less, and collision +// detection is expensive. +var hash = '{abc/def/g{0h1i2{jkl' +var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]} +var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']} + +var obj3 = JSON.parse(JSON.stringify(obj1)) +obj3.c = /def/ +obj3.g[2].cycle = obj3 +var cycleHash = '{abc/def/g{0h1i2{jklcycle' + +test('basic', function (t) { + t.equal(sigmund(obj1), hash) + t.equal(sigmund(obj2), hash) + t.equal(sigmund(obj3), cycleHash) + t.end() +}) + diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/package.json b/tests/mocha/node_modules/glob/node_modules/minimatch/package.json new file mode 100644 index 0000000000..f8f545aa3f --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/package.json @@ -0,0 +1,40 @@ +{ + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me" + }, + "name": "minimatch", + "description": "a glob matcher in javascript", + "version": "0.2.14", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/minimatch.git" + }, + "main": "minimatch.js", + "scripts": { + "test": "tap test/*.js" + }, + "engines": { + "node": "*" + }, + "dependencies": { + "lru-cache": "2", + "sigmund": "~1.0.0" + }, + "devDependencies": { + "tap": "" + }, + "license": { + "type": "MIT", + "url": "http://github.com/isaacs/minimatch/raw/master/LICENSE" + }, + "readme": "# minimatch\n\nA minimal matching utility.\n\n[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.png)](http://travis-ci.org/isaacs/minimatch)\n\n\nThis is the matching library used internally by npm.\n\nEventually, it will replace the C binding in node-glob.\n\nIt works by converting glob expressions into JavaScript `RegExp`\nobjects.\n\n## Usage\n\n```javascript\nvar minimatch = require(\"minimatch\")\n\nminimatch(\"bar.foo\", \"*.foo\") // true!\nminimatch(\"bar.foo\", \"*.bar\") // false!\nminimatch(\"bar.foo\", \"*.+(bar|foo)\", { debug: true }) // true, and noisy!\n```\n\n## Features\n\nSupports these glob features:\n\n* Brace Expansion\n* Extended glob matching\n* \"Globstar\" `**` matching\n\nSee:\n\n* `man sh`\n* `man bash`\n* `man 3 fnmatch`\n* `man 5 gitignore`\n\n## Minimatch Class\n\nCreate a minimatch object by instanting the `minimatch.Minimatch` class.\n\n```javascript\nvar Minimatch = require(\"minimatch\").Minimatch\nvar mm = new Minimatch(pattern, options)\n```\n\n### Properties\n\n* `pattern` The original pattern the minimatch object represents.\n* `options` The options supplied to the constructor.\n* `set` A 2-dimensional array of regexp or string expressions.\n Each row in the\n array corresponds to a brace-expanded pattern. Each item in the row\n corresponds to a single path-part. For example, the pattern\n `{a,b/c}/d` would expand to a set of patterns like:\n\n [ [ a, d ]\n , [ b, c, d ] ]\n\n If a portion of the pattern doesn't have any \"magic\" in it\n (that is, it's something like `\"foo\"` rather than `fo*o?`), then it\n will be left as a string rather than converted to a regular\n expression.\n\n* `regexp` Created by the `makeRe` method. A single regular expression\n expressing the entire pattern. This is useful in cases where you wish\n to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled.\n* `negate` True if the pattern is negated.\n* `comment` True if the pattern is a comment.\n* `empty` True if the pattern is `\"\"`.\n\n### Methods\n\n* `makeRe` Generate the `regexp` member if necessary, and return it.\n Will return `false` if the pattern is invalid.\n* `match(fname)` Return true if the filename matches the pattern, or\n false otherwise.\n* `matchOne(fileArray, patternArray, partial)` Take a `/`-split\n filename, and match it against a single row in the `regExpSet`. This\n method is mainly for internal use, but is exposed so that it can be\n used by a glob-walker that needs to avoid excessive filesystem calls.\n\nAll other methods are internal, and will be called as necessary.\n\n## Functions\n\nThe top-level exported function has a `cache` property, which is an LRU\ncache set to store 100 items. So, calling these methods repeatedly\nwith the same pattern and options will use the same Minimatch object,\nsaving the cost of parsing it multiple times.\n\n### minimatch(path, pattern, options)\n\nMain export. Tests a path against the pattern using the options.\n\n```javascript\nvar isJS = minimatch(file, \"*.js\", { matchBase: true })\n```\n\n### minimatch.filter(pattern, options)\n\nReturns a function that tests its\nsupplied argument, suitable for use with `Array.filter`. Example:\n\n```javascript\nvar javascripts = fileList.filter(minimatch.filter(\"*.js\", {matchBase: true}))\n```\n\n### minimatch.match(list, pattern, options)\n\nMatch against the list of\nfiles, in the style of fnmatch or glob. If nothing is matched, and\noptions.nonull is set, then return a list containing the pattern itself.\n\n```javascript\nvar javascripts = minimatch.match(fileList, \"*.js\", {matchBase: true}))\n```\n\n### minimatch.makeRe(pattern, options)\n\nMake a regular expression object from the pattern.\n\n## Options\n\nAll options are `false` by default.\n\n### debug\n\nDump a ton of stuff to stderr.\n\n### nobrace\n\nDo not expand `{a,b}` and `{1..3}` brace sets.\n\n### noglobstar\n\nDisable `**` matching against multiple folder names.\n\n### dot\n\nAllow patterns to match filenames starting with a period, even if\nthe pattern does not explicitly have a period in that spot.\n\nNote that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot`\nis set.\n\n### noext\n\nDisable \"extglob\" style patterns like `+(a|b)`.\n\n### nocase\n\nPerform a case-insensitive match.\n\n### nonull\n\nWhen a match is not found by `minimatch.match`, return a list containing\nthe pattern itself. When set, an empty list is returned if there are\nno matches.\n\n### matchBase\n\nIf set, then patterns without slashes will be matched\nagainst the basename of the path if it contains slashes. For example,\n`a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`.\n\n### nocomment\n\nSuppress the behavior of treating `#` at the start of a pattern as a\ncomment.\n\n### nonegate\n\nSuppress the behavior of treating a leading `!` character as negation.\n\n### flipNegate\n\nReturns from negate expressions the same as if they were not negated.\n(Ie, true on a hit, false on a miss.)\n\n\n## Comparisons to other fnmatch/glob implementations\n\nWhile strict compliance with the existing standards is a worthwhile\ngoal, some discrepancies exist between minimatch and other\nimplementations, and are intentional.\n\nIf the pattern starts with a `!` character, then it is negated. Set the\n`nonegate` flag to suppress this behavior, and treat leading `!`\ncharacters normally. This is perhaps relevant if you wish to start the\npattern with a negative extglob pattern like `!(a|B)`. Multiple `!`\ncharacters at the start of a pattern will negate the pattern multiple\ntimes.\n\nIf a pattern starts with `#`, then it is treated as a comment, and\nwill not match anything. Use `\\#` to match a literal `#` at the\nstart of a line, or set the `nocomment` flag to suppress this behavior.\n\nThe double-star character `**` is supported by default, unless the\n`noglobstar` flag is set. This is supported in the manner of bsdglob\nand bash 4.1, where `**` only has special significance if it is the only\nthing in a path part. That is, `a/**/b` will match `a/x/y/b`, but\n`a/**b` will not.\n\nIf an escaped pattern has no matches, and the `nonull` flag is set,\nthen minimatch.match returns the pattern as-provided, rather than\ninterpreting the character escapes. For example,\n`minimatch.match([], \"\\\\*a\\\\?\")` will return `\"\\\\*a\\\\?\"` rather than\n`\"*a?\"`. This is akin to setting the `nullglob` option in bash, except\nthat it does not resolve escaped pattern characters.\n\nIf brace expansion is not disabled, then it is performed before any\nother interpretation of the glob pattern. Thus, a pattern like\n`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded\n**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are\nchecked for validity. Since those two are valid, matching proceeds.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/minimatch/issues" + }, + "homepage": "https://github.com/isaacs/minimatch", + "_id": "minimatch@0.2.14", + "_from": "minimatch@~0.2.11" +} diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/test/basic.js b/tests/mocha/node_modules/glob/node_modules/minimatch/test/basic.js new file mode 100644 index 0000000000..ae7ac73c77 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/test/basic.js @@ -0,0 +1,399 @@ +// http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test +// +// TODO: Some of these tests do very bad things with backslashes, and will +// most likely fail badly on windows. They should probably be skipped. + +var tap = require("tap") + , globalBefore = Object.keys(global) + , mm = require("../") + , files = [ "a", "b", "c", "d", "abc" + , "abd", "abe", "bb", "bcd" + , "ca", "cb", "dd", "de" + , "bdir/", "bdir/cfile"] + , next = files.concat([ "a-b", "aXb" + , ".x", ".y" ]) + + +var patterns = + [ "http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test" + , ["a*", ["a", "abc", "abd", "abe"]] + , ["X*", ["X*"], {nonull: true}] + + // allow null glob expansion + , ["X*", []] + + // isaacs: Slightly different than bash/sh/ksh + // \\* is not un-escaped to literal "*" in a failed match, + // but it does make it get treated as a literal star + , ["\\*", ["\\*"], {nonull: true}] + , ["\\**", ["\\**"], {nonull: true}] + , ["\\*\\*", ["\\*\\*"], {nonull: true}] + + , ["b*/", ["bdir/"]] + , ["c*", ["c", "ca", "cb"]] + , ["**", files] + + , ["\\.\\./*/", ["\\.\\./*/"], {nonull: true}] + , ["s/\\..*//", ["s/\\..*//"], {nonull: true}] + + , "legendary larry crashes bashes" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/"], {nonull: true}] + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/"], {nonull: true}] + + , "character classes" + , ["[a-c]b*", ["abc", "abd", "abe", "bb", "cb"]] + , ["[a-y]*[^c]", ["abd", "abe", "bb", "bcd", + "bdir/", "ca", "cb", "dd", "de"]] + , ["a*[^c]", ["abd", "abe"]] + , function () { files.push("a-b", "aXb") } + , ["a[X-]b", ["a-b", "aXb"]] + , function () { files.push(".x", ".y") } + , ["[^a-c]*", ["d", "dd", "de"]] + , function () { files.push("a*b/", "a*b/ooo") } + , ["a\\*b/*", ["a*b/ooo"]] + , ["a\\*?/*", ["a*b/ooo"]] + , ["*\\\\!*", [], {null: true}, ["echo !7"]] + , ["*\\!*", ["echo !7"], null, ["echo !7"]] + , ["*.\\*", ["r.*"], null, ["r.*"]] + , ["a[b]c", ["abc"]] + , ["a[\\b]c", ["abc"]] + , ["a?c", ["abc"]] + , ["a\\*c", [], {null: true}, ["abc"]] + , ["", [""], { null: true }, [""]] + + , "http://www.opensource.apple.com/source/bash/bash-23/" + + "bash/tests/glob-test" + , function () { files.push("man/", "man/man1/", "man/man1/bash.1") } + , ["*/man*/bash.*", ["man/man1/bash.1"]] + , ["man/man1/bash.1", ["man/man1/bash.1"]] + , ["a***c", ["abc"], null, ["abc"]] + , ["a*****?c", ["abc"], null, ["abc"]] + , ["?*****??", ["abc"], null, ["abc"]] + , ["*****??", ["abc"], null, ["abc"]] + , ["?*****?c", ["abc"], null, ["abc"]] + , ["?***?****c", ["abc"], null, ["abc"]] + , ["?***?****?", ["abc"], null, ["abc"]] + , ["?***?****", ["abc"], null, ["abc"]] + , ["*******c", ["abc"], null, ["abc"]] + , ["*******?", ["abc"], null, ["abc"]] + , ["a*cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??k***", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??***k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??***k**", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a****c**?**??*****", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["[-abc]", ["-"], null, ["-"]] + , ["[abc-]", ["-"], null, ["-"]] + , ["\\", ["\\"], null, ["\\"]] + , ["[\\\\]", ["\\"], null, ["\\"]] + , ["[[]", ["["], null, ["["]] + , ["[", ["["], null, ["["]] + , ["[*", ["[abc"], null, ["[abc"]] + , "a right bracket shall lose its special meaning and\n" + + "represent itself in a bracket expression if it occurs\n" + + "first in the list. -- POSIX.2 2.8.3.2" + , ["[]]", ["]"], null, ["]"]] + , ["[]-]", ["]"], null, ["]"]] + , ["[a-\z]", ["p"], null, ["p"]] + , ["??**********?****?", [], { null: true }, ["abc"]] + , ["??**********?****c", [], { null: true }, ["abc"]] + , ["?************c****?****", [], { null: true }, ["abc"]] + , ["*c*?**", [], { null: true }, ["abc"]] + , ["a*****c*?**", [], { null: true }, ["abc"]] + , ["a********???*******", [], { null: true }, ["abc"]] + , ["[]", [], { null: true }, ["a"]] + , ["[abc", [], { null: true }, ["["]] + + , "nocase tests" + , ["XYZ", ["xYz"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + , ["ab*", ["ABC"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + , ["[ia]?[ck]", ["ABC", "IjK"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + + // [ pattern, [matches], MM opts, files, TAP opts] + , "onestar/twostar" + , ["{/*,*}", [], {null: true}, ["/asdf/asdf/asdf"]] + , ["{/?,*}", ["/a", "bb"], {null: true} + , ["/a", "/b/b", "/a/b/c", "bb"]] + + , "dots should not match unless requested" + , ["**", ["a/b"], {}, ["a/b", "a/.d", ".a/.d"]] + + // .. and . can only match patterns starting with ., + // even when options.dot is set. + , function () { + files = ["a/./b", "a/../b", "a/c/b", "a/.d/b"] + } + , ["a/*/b", ["a/c/b", "a/.d/b"], {dot: true}] + , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: true}] + , ["a/*/b", ["a/c/b"], {dot:false}] + , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: false}] + + + // this also tests that changing the options needs + // to change the cache key, even if the pattern is + // the same! + , ["**", ["a/b","a/.d",".a/.d"], { dot: true } + , [ ".a/.d", "a/.d", "a/b"]] + + , "paren sets cannot contain slashes" + , ["*(a/b)", ["*(a/b)"], {nonull: true}, ["a/b"]] + + // brace sets trump all else. + // + // invalid glob pattern. fails on bash4 and bsdglob. + // however, in this implementation, it's easier just + // to do the intuitive thing, and let brace-expansion + // actually come before parsing any extglob patterns, + // like the documentation seems to say. + // + // XXX: if anyone complains about this, either fix it + // or tell them to grow up and stop complaining. + // + // bash/bsdglob says this: + // , ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]] + // but we do this instead: + , ["*(a|{b),c)}", ["a", "ab", "ac"], {}, ["a", "ab", "ac", "ad"]] + + // test partial parsing in the presence of comment/negation chars + , ["[!a*", ["[!ab"], {}, ["[!ab", "[ab"]] + , ["[#a*", ["[#ab"], {}, ["[#ab", "[ab"]] + + // like: {a,b|c\\,d\\\|e} except it's unclosed, so it has to be escaped. + , ["+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g" + , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g"] + , {} + , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g", "a", "b\\c"]] + + + // crazy nested {,,} and *(||) tests. + , function () { + files = [ "a", "b", "c", "d" + , "ab", "ac", "ad" + , "bc", "cb" + , "bc,d", "c,db", "c,d" + , "d)", "(b|c", "*(b|c" + , "b|c", "b|cc", "cb|c" + , "x(a|b|c)", "x(a|c)" + , "(a|b|c)", "(a|c)"] + } + , ["*(a|{b,c})", ["a", "b", "c", "ab", "ac"]] + , ["{a,*(b|c,d)}", ["a","(b|c", "*(b|c", "d)"]] + // a + // *(b|c) + // *(b|d) + , ["{a,*(b|{c,d})}", ["a","b", "bc", "cb", "c", "d"]] + , ["*(a|{b|c,c})", ["a", "b", "c", "ab", "ac", "bc", "cb"]] + + + // test various flag settings. + , [ "*(a|{b|c,c})", ["x(a|b|c)", "x(a|c)", "(a|b|c)", "(a|c)"] + , { noext: true } ] + , ["a?b", ["x/y/acb", "acb/"], {matchBase: true} + , ["x/y/acb", "acb/", "acb/d/e", "x/y/acb/d"] ] + , ["#*", ["#a", "#b"], {nocomment: true}, ["#a", "#b", "c#d"]] + + + // begin channelling Boole and deMorgan... + , "negation tests" + , function () { + files = ["d", "e", "!ab", "!abc", "a!b", "\\!a"] + } + + // anything that is NOT a* matches. + , ["!a*", ["\\!a", "d", "e", "!ab", "!abc"]] + + // anything that IS !a* matches. + , ["!a*", ["!ab", "!abc"], {nonegate: true}] + + // anything that IS a* matches + , ["!!a*", ["a!b"]] + + // anything that is NOT !a* matches + , ["!\\!a*", ["a!b", "d", "e", "\\!a"]] + + // negation nestled within a pattern + , function () { + files = [ "foo.js" + , "foo.bar" + // can't match this one without negative lookbehind. + , "foo.js.js" + , "blar.js" + , "foo." + , "boo.js.boo" ] + } + , ["*.!(js)", ["foo.bar", "foo.", "boo.js.boo"] ] + + // https://github.com/isaacs/minimatch/issues/5 + , function () { + files = [ 'a/b/.x/c' + , 'a/b/.x/c/d' + , 'a/b/.x/c/d/e' + , 'a/b/.x' + , 'a/b/.x/' + , 'a/.x/b' + , '.x' + , '.x/' + , '.x/a' + , '.x/a/b' + , 'a/.x/b/.x/c' + , '.x/.x' ] + } + , ["**/.x/**", [ '.x/' + , '.x/a' + , '.x/a/b' + , 'a/.x/b' + , 'a/b/.x/' + , 'a/b/.x/c' + , 'a/b/.x/c/d' + , 'a/b/.x/c/d/e' ] ] + + ] + +var regexps = + [ '/^(?:(?=.)a[^/]*?)$/', + '/^(?:(?=.)X[^/]*?)$/', + '/^(?:(?=.)X[^/]*?)$/', + '/^(?:\\*)$/', + '/^(?:(?=.)\\*[^/]*?)$/', + '/^(?:\\*\\*)$/', + '/^(?:(?=.)b[^/]*?\\/)$/', + '/^(?:(?=.)c[^/]*?)$/', + '/^(?:(?:(?!(?:\\/|^)\\.).)*?)$/', + '/^(?:\\.\\.\\/(?!\\.)(?=.)[^/]*?\\/)$/', + '/^(?:s\\/(?=.)\\.\\.[^/]*?\\/)$/', + '/^(?:\\/\\^root:\\/\\{s\\/(?=.)\\^[^:][^/]*?:[^:][^/]*?:\\([^:]\\)[^/]*?\\.[^/]*?\\$\\/1\\/)$/', + '/^(?:\\/\\^root:\\/\\{s\\/(?=.)\\^[^:][^/]*?:[^:][^/]*?:\\([^:]\\)[^/]*?\\.[^/]*?\\$\\/\u0001\\/)$/', + '/^(?:(?!\\.)(?=.)[a-c]b[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[a-y][^/]*?[^c])$/', + '/^(?:(?=.)a[^/]*?[^c])$/', + '/^(?:(?=.)a[X-]b)$/', + '/^(?:(?!\\.)(?=.)[^a-c][^/]*?)$/', + '/^(?:a\\*b\\/(?!\\.)(?=.)[^/]*?)$/', + '/^(?:(?=.)a\\*[^/]\\/(?!\\.)(?=.)[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\\\\\![^/]*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\![^/]*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\.\\*)$/', + '/^(?:(?=.)a[b]c)$/', + '/^(?:(?=.)a[b]c)$/', + '/^(?:(?=.)a[^/]c)$/', + '/^(?:a\\*c)$/', + 'false', + '/^(?:(?!\\.)(?=.)[^/]*?\\/(?=.)man[^/]*?\\/(?=.)bash\\.[^/]*?)$/', + '/^(?:man\\/man1\\/bash\\.1)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?c)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/', + '/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c)$/', + '/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/])$/', + '/^(?:(?=.)a[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k[^/]*?[^/]*?[^/]*?)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k[^/]*?[^/]*?)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[-abc])$/', + '/^(?:(?!\\.)(?=.)[abc-])$/', + '/^(?:\\\\)$/', + '/^(?:(?!\\.)(?=.)[\\\\])$/', + '/^(?:(?!\\.)(?=.)[\\[])$/', + '/^(?:\\[)$/', + '/^(?:(?=.)\\[(?!\\.)(?=.)[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[\\]])$/', + '/^(?:(?!\\.)(?=.)[\\]-])$/', + '/^(?:(?!\\.)(?=.)[a-z])$/', + '/^(?:(?!\\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/', + '/^(?:(?!\\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/', + '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/', + '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/', + '/^(?:\\[\\])$/', + '/^(?:\\[abc)$/', + '/^(?:(?=.)XYZ)$/i', + '/^(?:(?=.)ab[^/]*?)$/i', + '/^(?:(?!\\.)(?=.)[ia][^/][ck])$/i', + '/^(?:\\/(?!\\.)(?=.)[^/]*?|(?!\\.)(?=.)[^/]*?)$/', + '/^(?:\\/(?!\\.)(?=.)[^/]|(?!\\.)(?=.)[^/]*?)$/', + '/^(?:(?:(?!(?:\\/|^)\\.).)*?)$/', + '/^(?:a\\/(?!(?:^|\\/)\\.{1,2}(?:$|\\/))(?=.)[^/]*?\\/b)$/', + '/^(?:a\\/(?=.)\\.[^/]*?\\/b)$/', + '/^(?:a\\/(?!\\.)(?=.)[^/]*?\\/b)$/', + '/^(?:a\\/(?=.)\\.[^/]*?\\/b)$/', + '/^(?:(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?)$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\(a\\/b\\))$/', + '/^(?:(?!\\.)(?=.)(?:a|b)*|(?!\\.)(?=.)(?:a|c)*)$/', + '/^(?:(?=.)\\[(?=.)\\!a[^/]*?)$/', + '/^(?:(?=.)\\[(?=.)#a[^/]*?)$/', + '/^(?:(?=.)\\+\\(a\\|[^/]*?\\|c\\\\\\\\\\|d\\\\\\\\\\|e\\\\\\\\\\\\\\\\\\|f\\\\\\\\\\\\\\\\\\|g)$/', + '/^(?:(?!\\.)(?=.)(?:a|b)*|(?!\\.)(?=.)(?:a|c)*)$/', + '/^(?:a|(?!\\.)(?=.)[^/]*?\\(b\\|c|d\\))$/', + '/^(?:a|(?!\\.)(?=.)(?:b|c)*|(?!\\.)(?=.)(?:b|d)*)$/', + '/^(?:(?!\\.)(?=.)(?:a|b|c)*|(?!\\.)(?=.)(?:a|c)*)$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\(a\\|b\\|c\\)|(?!\\.)(?=.)[^/]*?\\(a\\|c\\))$/', + '/^(?:(?=.)a[^/]b)$/', + '/^(?:(?=.)#[^/]*?)$/', + '/^(?!^(?:(?=.)a[^/]*?)$).*$/', + '/^(?:(?=.)\\!a[^/]*?)$/', + '/^(?:(?=.)a[^/]*?)$/', + '/^(?!^(?:(?=.)\\!a[^/]*?)$).*$/', + '/^(?:(?!\\.)(?=.)[^/]*?\\.(?:(?!js)[^/]*?))$/', + '/^(?:(?:(?!(?:\\/|^)\\.).)*?\\/\\.x\\/(?:(?!(?:\\/|^)\\.).)*?)$/' ] +var re = 0; + +tap.test("basic tests", function (t) { + var start = Date.now() + + // [ pattern, [matches], MM opts, files, TAP opts] + patterns.forEach(function (c) { + if (typeof c === "function") return c() + if (typeof c === "string") return t.comment(c) + + var pattern = c[0] + , expect = c[1].sort(alpha) + , options = c[2] || {} + , f = c[3] || files + , tapOpts = c[4] || {} + + // options.debug = true + var m = new mm.Minimatch(pattern, options) + var r = m.makeRe() + var expectRe = regexps[re++] + tapOpts.re = String(r) || JSON.stringify(r) + tapOpts.files = JSON.stringify(f) + tapOpts.pattern = pattern + tapOpts.set = m.set + tapOpts.negated = m.negate + + var actual = mm.match(f, pattern, options) + actual.sort(alpha) + + t.equivalent( actual, expect + , JSON.stringify(pattern) + " " + JSON.stringify(expect) + , tapOpts ) + + t.equal(tapOpts.re, expectRe, tapOpts) + }) + + t.comment("time=" + (Date.now() - start) + "ms") + t.end() +}) + +tap.test("global leak test", function (t) { + var globalAfter = Object.keys(global) + t.equivalent(globalAfter, globalBefore, "no new globals, please") + t.end() +}) + +function alpha (a, b) { + return a > b ? 1 : -1 +} diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/test/brace-expand.js b/tests/mocha/node_modules/glob/node_modules/minimatch/test/brace-expand.js new file mode 100644 index 0000000000..7ee278a274 --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/test/brace-expand.js @@ -0,0 +1,33 @@ +var tap = require("tap") + , minimatch = require("../") + +tap.test("brace expansion", function (t) { + // [ pattern, [expanded] ] + ; [ [ "a{b,c{d,e},{f,g}h}x{y,z}" + , [ "abxy" + , "abxz" + , "acdxy" + , "acdxz" + , "acexy" + , "acexz" + , "afhxy" + , "afhxz" + , "aghxy" + , "aghxz" ] ] + , [ "a{1..5}b" + , [ "a1b" + , "a2b" + , "a3b" + , "a4b" + , "a5b" ] ] + , [ "a{b}c", ["a{b}c"] ] + ].forEach(function (tc) { + var p = tc[0] + , expect = tc[1] + t.equivalent(minimatch.braceExpand(p), expect, p) + }) + console.error("ending") + t.end() +}) + + diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/test/caching.js b/tests/mocha/node_modules/glob/node_modules/minimatch/test/caching.js new file mode 100644 index 0000000000..0fec4b0fad --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/test/caching.js @@ -0,0 +1,14 @@ +var Minimatch = require("../minimatch.js").Minimatch +var tap = require("tap") +tap.test("cache test", function (t) { + var mm1 = new Minimatch("a?b") + var mm2 = new Minimatch("a?b") + t.equal(mm1, mm2, "should get the same object") + // the lru should drop it after 100 entries + for (var i = 0; i < 100; i ++) { + new Minimatch("a"+i) + } + mm2 = new Minimatch("a?b") + t.notEqual(mm1, mm2, "cache should have dropped") + t.end() +}) diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/test/defaults.js b/tests/mocha/node_modules/glob/node_modules/minimatch/test/defaults.js new file mode 100644 index 0000000000..25f1f601cd --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/test/defaults.js @@ -0,0 +1,274 @@ +// http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test +// +// TODO: Some of these tests do very bad things with backslashes, and will +// most likely fail badly on windows. They should probably be skipped. + +var tap = require("tap") + , globalBefore = Object.keys(global) + , mm = require("../") + , files = [ "a", "b", "c", "d", "abc" + , "abd", "abe", "bb", "bcd" + , "ca", "cb", "dd", "de" + , "bdir/", "bdir/cfile"] + , next = files.concat([ "a-b", "aXb" + , ".x", ".y" ]) + +tap.test("basic tests", function (t) { + var start = Date.now() + + // [ pattern, [matches], MM opts, files, TAP opts] + ; [ "http://www.bashcookbook.com/bashinfo" + + "/source/bash-1.14.7/tests/glob-test" + , ["a*", ["a", "abc", "abd", "abe"]] + , ["X*", ["X*"], {nonull: true}] + + // allow null glob expansion + , ["X*", []] + + // isaacs: Slightly different than bash/sh/ksh + // \\* is not un-escaped to literal "*" in a failed match, + // but it does make it get treated as a literal star + , ["\\*", ["\\*"], {nonull: true}] + , ["\\**", ["\\**"], {nonull: true}] + , ["\\*\\*", ["\\*\\*"], {nonull: true}] + + , ["b*/", ["bdir/"]] + , ["c*", ["c", "ca", "cb"]] + , ["**", files] + + , ["\\.\\./*/", ["\\.\\./*/"], {nonull: true}] + , ["s/\\..*//", ["s/\\..*//"], {nonull: true}] + + , "legendary larry crashes bashes" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/"], {nonull: true}] + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/" + , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/"], {nonull: true}] + + , "character classes" + , ["[a-c]b*", ["abc", "abd", "abe", "bb", "cb"]] + , ["[a-y]*[^c]", ["abd", "abe", "bb", "bcd", + "bdir/", "ca", "cb", "dd", "de"]] + , ["a*[^c]", ["abd", "abe"]] + , function () { files.push("a-b", "aXb") } + , ["a[X-]b", ["a-b", "aXb"]] + , function () { files.push(".x", ".y") } + , ["[^a-c]*", ["d", "dd", "de"]] + , function () { files.push("a*b/", "a*b/ooo") } + , ["a\\*b/*", ["a*b/ooo"]] + , ["a\\*?/*", ["a*b/ooo"]] + , ["*\\\\!*", [], {null: true}, ["echo !7"]] + , ["*\\!*", ["echo !7"], null, ["echo !7"]] + , ["*.\\*", ["r.*"], null, ["r.*"]] + , ["a[b]c", ["abc"]] + , ["a[\\b]c", ["abc"]] + , ["a?c", ["abc"]] + , ["a\\*c", [], {null: true}, ["abc"]] + , ["", [""], { null: true }, [""]] + + , "http://www.opensource.apple.com/source/bash/bash-23/" + + "bash/tests/glob-test" + , function () { files.push("man/", "man/man1/", "man/man1/bash.1") } + , ["*/man*/bash.*", ["man/man1/bash.1"]] + , ["man/man1/bash.1", ["man/man1/bash.1"]] + , ["a***c", ["abc"], null, ["abc"]] + , ["a*****?c", ["abc"], null, ["abc"]] + , ["?*****??", ["abc"], null, ["abc"]] + , ["*****??", ["abc"], null, ["abc"]] + , ["?*****?c", ["abc"], null, ["abc"]] + , ["?***?****c", ["abc"], null, ["abc"]] + , ["?***?****?", ["abc"], null, ["abc"]] + , ["?***?****", ["abc"], null, ["abc"]] + , ["*******c", ["abc"], null, ["abc"]] + , ["*******?", ["abc"], null, ["abc"]] + , ["a*cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??k***", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??***k", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a**?**cd**?**??***k**", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["a****c**?**??*****", ["abcdecdhjk"], null, ["abcdecdhjk"]] + , ["[-abc]", ["-"], null, ["-"]] + , ["[abc-]", ["-"], null, ["-"]] + , ["\\", ["\\"], null, ["\\"]] + , ["[\\\\]", ["\\"], null, ["\\"]] + , ["[[]", ["["], null, ["["]] + , ["[", ["["], null, ["["]] + , ["[*", ["[abc"], null, ["[abc"]] + , "a right bracket shall lose its special meaning and\n" + + "represent itself in a bracket expression if it occurs\n" + + "first in the list. -- POSIX.2 2.8.3.2" + , ["[]]", ["]"], null, ["]"]] + , ["[]-]", ["]"], null, ["]"]] + , ["[a-\z]", ["p"], null, ["p"]] + , ["??**********?****?", [], { null: true }, ["abc"]] + , ["??**********?****c", [], { null: true }, ["abc"]] + , ["?************c****?****", [], { null: true }, ["abc"]] + , ["*c*?**", [], { null: true }, ["abc"]] + , ["a*****c*?**", [], { null: true }, ["abc"]] + , ["a********???*******", [], { null: true }, ["abc"]] + , ["[]", [], { null: true }, ["a"]] + , ["[abc", [], { null: true }, ["["]] + + , "nocase tests" + , ["XYZ", ["xYz"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + , ["ab*", ["ABC"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + , ["[ia]?[ck]", ["ABC", "IjK"], { nocase: true, null: true } + , ["xYz", "ABC", "IjK"]] + + // [ pattern, [matches], MM opts, files, TAP opts] + , "onestar/twostar" + , ["{/*,*}", [], {null: true}, ["/asdf/asdf/asdf"]] + , ["{/?,*}", ["/a", "bb"], {null: true} + , ["/a", "/b/b", "/a/b/c", "bb"]] + + , "dots should not match unless requested" + , ["**", ["a/b"], {}, ["a/b", "a/.d", ".a/.d"]] + + // .. and . can only match patterns starting with ., + // even when options.dot is set. + , function () { + files = ["a/./b", "a/../b", "a/c/b", "a/.d/b"] + } + , ["a/*/b", ["a/c/b", "a/.d/b"], {dot: true}] + , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: true}] + , ["a/*/b", ["a/c/b"], {dot:false}] + , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: false}] + + + // this also tests that changing the options needs + // to change the cache key, even if the pattern is + // the same! + , ["**", ["a/b","a/.d",".a/.d"], { dot: true } + , [ ".a/.d", "a/.d", "a/b"]] + + , "paren sets cannot contain slashes" + , ["*(a/b)", ["*(a/b)"], {nonull: true}, ["a/b"]] + + // brace sets trump all else. + // + // invalid glob pattern. fails on bash4 and bsdglob. + // however, in this implementation, it's easier just + // to do the intuitive thing, and let brace-expansion + // actually come before parsing any extglob patterns, + // like the documentation seems to say. + // + // XXX: if anyone complains about this, either fix it + // or tell them to grow up and stop complaining. + // + // bash/bsdglob says this: + // , ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]] + // but we do this instead: + , ["*(a|{b),c)}", ["a", "ab", "ac"], {}, ["a", "ab", "ac", "ad"]] + + // test partial parsing in the presence of comment/negation chars + , ["[!a*", ["[!ab"], {}, ["[!ab", "[ab"]] + , ["[#a*", ["[#ab"], {}, ["[#ab", "[ab"]] + + // like: {a,b|c\\,d\\\|e} except it's unclosed, so it has to be escaped. + , ["+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g" + , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g"] + , {} + , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g", "a", "b\\c"]] + + + // crazy nested {,,} and *(||) tests. + , function () { + files = [ "a", "b", "c", "d" + , "ab", "ac", "ad" + , "bc", "cb" + , "bc,d", "c,db", "c,d" + , "d)", "(b|c", "*(b|c" + , "b|c", "b|cc", "cb|c" + , "x(a|b|c)", "x(a|c)" + , "(a|b|c)", "(a|c)"] + } + , ["*(a|{b,c})", ["a", "b", "c", "ab", "ac"]] + , ["{a,*(b|c,d)}", ["a","(b|c", "*(b|c", "d)"]] + // a + // *(b|c) + // *(b|d) + , ["{a,*(b|{c,d})}", ["a","b", "bc", "cb", "c", "d"]] + , ["*(a|{b|c,c})", ["a", "b", "c", "ab", "ac", "bc", "cb"]] + + + // test various flag settings. + , [ "*(a|{b|c,c})", ["x(a|b|c)", "x(a|c)", "(a|b|c)", "(a|c)"] + , { noext: true } ] + , ["a?b", ["x/y/acb", "acb/"], {matchBase: true} + , ["x/y/acb", "acb/", "acb/d/e", "x/y/acb/d"] ] + , ["#*", ["#a", "#b"], {nocomment: true}, ["#a", "#b", "c#d"]] + + + // begin channelling Boole and deMorgan... + , "negation tests" + , function () { + files = ["d", "e", "!ab", "!abc", "a!b", "\\!a"] + } + + // anything that is NOT a* matches. + , ["!a*", ["\\!a", "d", "e", "!ab", "!abc"]] + + // anything that IS !a* matches. + , ["!a*", ["!ab", "!abc"], {nonegate: true}] + + // anything that IS a* matches + , ["!!a*", ["a!b"]] + + // anything that is NOT !a* matches + , ["!\\!a*", ["a!b", "d", "e", "\\!a"]] + + // negation nestled within a pattern + , function () { + files = [ "foo.js" + , "foo.bar" + // can't match this one without negative lookbehind. + , "foo.js.js" + , "blar.js" + , "foo." + , "boo.js.boo" ] + } + , ["*.!(js)", ["foo.bar", "foo.", "boo.js.boo"] ] + + ].forEach(function (c) { + if (typeof c === "function") return c() + if (typeof c === "string") return t.comment(c) + + var pattern = c[0] + , expect = c[1].sort(alpha) + , options = c[2] || {} + , f = c[3] || files + , tapOpts = c[4] || {} + + // options.debug = true + var Class = mm.defaults(options).Minimatch + var m = new Class(pattern, {}) + var r = m.makeRe() + tapOpts.re = String(r) || JSON.stringify(r) + tapOpts.files = JSON.stringify(f) + tapOpts.pattern = pattern + tapOpts.set = m.set + tapOpts.negated = m.negate + + var actual = mm.match(f, pattern, options) + actual.sort(alpha) + + t.equivalent( actual, expect + , JSON.stringify(pattern) + " " + JSON.stringify(expect) + , tapOpts ) + }) + + t.comment("time=" + (Date.now() - start) + "ms") + t.end() +}) + +tap.test("global leak test", function (t) { + var globalAfter = Object.keys(global) + t.equivalent(globalAfter, globalBefore, "no new globals, please") + t.end() +}) + +function alpha (a, b) { + return a > b ? 1 : -1 +} diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/test/extglob-ending-with-state-char.js b/tests/mocha/node_modules/glob/node_modules/minimatch/test/extglob-ending-with-state-char.js new file mode 100644 index 0000000000..6676e2629a --- /dev/null +++ b/tests/mocha/node_modules/glob/node_modules/minimatch/test/extglob-ending-with-state-char.js @@ -0,0 +1,8 @@ +var test = require('tap').test +var minimatch = require('../') + +test('extglob ending with statechar', function(t) { + t.notOk(minimatch('ax', 'a?(b*)')) + t.ok(minimatch('ax', '?(a*|b)')) + t.end() +}) diff --git a/tests/mocha/node_modules/glob/package.json b/tests/mocha/node_modules/glob/package.json new file mode 100644 index 0000000000..bfbbbcca06 --- /dev/null +++ b/tests/mocha/node_modules/glob/package.json @@ -0,0 +1,40 @@ +{ + "author": { + "name": "Isaac Z. Schlueter", + "email": "i@izs.me", + "url": "http://blog.izs.me/" + }, + "name": "glob", + "description": "a little globber", + "version": "3.2.3", + "repository": { + "type": "git", + "url": "git://github.com/isaacs/node-glob.git" + }, + "main": "glob.js", + "engines": { + "node": "*" + }, + "dependencies": { + "minimatch": "~0.2.11", + "graceful-fs": "~2.0.0", + "inherits": "2" + }, + "devDependencies": { + "tap": "~0.4.0", + "mkdirp": "0", + "rimraf": "1" + }, + "scripts": { + "test": "tap test/*.js" + }, + "license": "BSD", + "readme": "# Glob\n\nMatch files using the patterns the shell uses, like stars and stuff.\n\nThis is a glob implementation in JavaScript. It uses the `minimatch`\nlibrary to do its matching.\n\n## Attention: node-glob users!\n\nThe API has changed dramatically between 2.x and 3.x. This library is\nnow 100% JavaScript, and the integer flags have been replaced with an\noptions object.\n\nAlso, there's an event emitter class, proper tests, and all the other\nthings you've come to expect from node modules.\n\nAnd best of all, no compilation!\n\n## Usage\n\n```javascript\nvar glob = require(\"glob\")\n\n// options is optional\nglob(\"**/*.js\", options, function (er, files) {\n // files is an array of filenames.\n // If the `nonull` option is set, and nothing\n // was found, then files is [\"**/*.js\"]\n // er is an error object or null.\n})\n```\n\n## Features\n\nPlease see the [minimatch\ndocumentation](https://github.com/isaacs/minimatch) for more details.\n\nSupports these glob features:\n\n* Brace Expansion\n* Extended glob matching\n* \"Globstar\" `**` matching\n\nSee:\n\n* `man sh`\n* `man bash`\n* `man 3 fnmatch`\n* `man 5 gitignore`\n* [minimatch documentation](https://github.com/isaacs/minimatch)\n\n## glob(pattern, [options], cb)\n\n* `pattern` {String} Pattern to be matched\n* `options` {Object}\n* `cb` {Function}\n * `err` {Error | null}\n * `matches` {Array} filenames found matching the pattern\n\nPerform an asynchronous glob search.\n\n## glob.sync(pattern, [options])\n\n* `pattern` {String} Pattern to be matched\n* `options` {Object}\n* return: {Array} filenames found matching the pattern\n\nPerform a synchronous glob search.\n\n## Class: glob.Glob\n\nCreate a Glob object by instanting the `glob.Glob` class.\n\n```javascript\nvar Glob = require(\"glob\").Glob\nvar mg = new Glob(pattern, options, cb)\n```\n\nIt's an EventEmitter, and starts walking the filesystem to find matches\nimmediately.\n\n### new glob.Glob(pattern, [options], [cb])\n\n* `pattern` {String} pattern to search for\n* `options` {Object}\n* `cb` {Function} Called when an error occurs, or matches are found\n * `err` {Error | null}\n * `matches` {Array} filenames found matching the pattern\n\nNote that if the `sync` flag is set in the options, then matches will\nbe immediately available on the `g.found` member.\n\n### Properties\n\n* `minimatch` The minimatch object that the glob uses.\n* `options` The options object passed in.\n* `error` The error encountered. When an error is encountered, the\n glob object is in an undefined state, and should be discarded.\n* `aborted` Boolean which is set to true when calling `abort()`. There\n is no way at this time to continue a glob search after aborting, but\n you can re-use the statCache to avoid having to duplicate syscalls.\n* `statCache` Collection of all the stat results the glob search\n performed.\n* `cache` Convenience object. Each field has the following possible\n values:\n * `false` - Path does not exist\n * `true` - Path exists\n * `1` - Path exists, and is not a directory\n * `2` - Path exists, and is a directory\n * `[file, entries, ...]` - Path exists, is a directory, and the\n array value is the results of `fs.readdir`\n\n### Events\n\n* `end` When the matching is finished, this is emitted with all the\n matches found. If the `nonull` option is set, and no match was found,\n then the `matches` list contains the original pattern. The matches\n are sorted, unless the `nosort` flag is set.\n* `match` Every time a match is found, this is emitted with the matched.\n* `error` Emitted when an unexpected error is encountered, or whenever\n any fs error occurs if `options.strict` is set.\n* `abort` When `abort()` is called, this event is raised.\n\n### Methods\n\n* `abort` Stop the search.\n\n### Options\n\nAll the options that can be passed to Minimatch can also be passed to\nGlob to change pattern matching behavior. Also, some have been added,\nor have glob-specific ramifications.\n\nAll options are false by default, unless otherwise noted.\n\nAll options are added to the glob object, as well.\n\n* `cwd` The current working directory in which to search. Defaults\n to `process.cwd()`.\n* `root` The place where patterns starting with `/` will be mounted\n onto. Defaults to `path.resolve(options.cwd, \"/\")` (`/` on Unix\n systems, and `C:\\` or some such on Windows.)\n* `dot` Include `.dot` files in normal matches and `globstar` matches.\n Note that an explicit dot in a portion of the pattern will always\n match dot files.\n* `nomount` By default, a pattern starting with a forward-slash will be\n \"mounted\" onto the root setting, so that a valid filesystem path is\n returned. Set this flag to disable that behavior.\n* `mark` Add a `/` character to directory matches. Note that this\n requires additional stat calls.\n* `nosort` Don't sort the results.\n* `stat` Set to true to stat *all* results. This reduces performance\n somewhat, and is completely unnecessary, unless `readdir` is presumed\n to be an untrustworthy indicator of file existence. It will cause\n ELOOP to be triggered one level sooner in the case of cyclical\n symbolic links.\n* `silent` When an unusual error is encountered\n when attempting to read a directory, a warning will be printed to\n stderr. Set the `silent` option to true to suppress these warnings.\n* `strict` When an unusual error is encountered\n when attempting to read a directory, the process will just continue on\n in search of other matches. Set the `strict` option to raise an error\n in these cases.\n* `cache` See `cache` property above. Pass in a previously generated\n cache object to save some fs calls.\n* `statCache` A cache of results of filesystem information, to prevent\n unnecessary stat calls. While it should not normally be necessary to\n set this, you may pass the statCache from one glob() call to the\n options object of another, if you know that the filesystem will not\n change between calls. (See \"Race Conditions\" below.)\n* `sync` Perform a synchronous glob search.\n* `nounique` In some cases, brace-expanded patterns can result in the\n same file showing up multiple times in the result set. By default,\n this implementation prevents duplicates in the result set.\n Set this flag to disable that behavior.\n* `nonull` Set to never return an empty set, instead returning a set\n containing the pattern itself. This is the default in glob(3).\n* `nocase` Perform a case-insensitive match. Note that case-insensitive\n filesystems will sometimes result in glob returning results that are\n case-insensitively matched anyway, since readdir and stat will not\n raise an error.\n* `debug` Set to enable debug logging in minimatch and glob.\n* `globDebug` Set to enable debug logging in glob, but not minimatch.\n\n## Comparisons to other fnmatch/glob implementations\n\nWhile strict compliance with the existing standards is a worthwhile\ngoal, some discrepancies exist between node-glob and other\nimplementations, and are intentional.\n\nIf the pattern starts with a `!` character, then it is negated. Set the\n`nonegate` flag to suppress this behavior, and treat leading `!`\ncharacters normally. This is perhaps relevant if you wish to start the\npattern with a negative extglob pattern like `!(a|B)`. Multiple `!`\ncharacters at the start of a pattern will negate the pattern multiple\ntimes.\n\nIf a pattern starts with `#`, then it is treated as a comment, and\nwill not match anything. Use `\\#` to match a literal `#` at the\nstart of a line, or set the `nocomment` flag to suppress this behavior.\n\nThe double-star character `**` is supported by default, unless the\n`noglobstar` flag is set. This is supported in the manner of bsdglob\nand bash 4.1, where `**` only has special significance if it is the only\nthing in a path part. That is, `a/**/b` will match `a/x/y/b`, but\n`a/**b` will not.\n\nIf an escaped pattern has no matches, and the `nonull` flag is set,\nthen glob returns the pattern as-provided, rather than\ninterpreting the character escapes. For example,\n`glob.match([], \"\\\\*a\\\\?\")` will return `\"\\\\*a\\\\?\"` rather than\n`\"*a?\"`. This is akin to setting the `nullglob` option in bash, except\nthat it does not resolve escaped pattern characters.\n\nIf brace expansion is not disabled, then it is performed before any\nother interpretation of the glob pattern. Thus, a pattern like\n`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded\n**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are\nchecked for validity. Since those two are valid, matching proceeds.\n\n## Windows\n\n**Please only use forward-slashes in glob expressions.**\n\nThough windows uses either `/` or `\\` as its path separator, only `/`\ncharacters are used by this glob implementation. You must use\nforward-slashes **only** in glob expressions. Back-slashes will always\nbe interpreted as escape characters, not path separators.\n\nResults from absolute patterns such as `/foo/*` are mounted onto the\nroot setting using `path.join`. On windows, this will by default result\nin `/foo/*` matching `C:\\foo\\bar.txt`.\n\n## Race Conditions\n\nGlob searching, by its very nature, is susceptible to race conditions,\nsince it relies on directory walking and such.\n\nAs a result, it is possible that a file that exists when glob looks for\nit may have been deleted or modified by the time it returns the result.\n\nAs part of its internal implementation, this program caches all stat\nand readdir calls that it makes, in order to cut down on system\noverhead. However, this also makes it even more susceptible to races,\nespecially if the cache or statCache objects are reused between glob\ncalls.\n\nUsers are thus advised not to use a glob result as a guarantee of\nfilesystem state in the face of rapid changes. For the vast majority\nof operations, this is never a problem.\n", + "readmeFilename": "README.md", + "bugs": { + "url": "https://github.com/isaacs/node-glob/issues" + }, + "homepage": "https://github.com/isaacs/node-glob", + "_id": "glob@3.2.3", + "_from": "glob@3.2.3" +} diff --git a/tests/mocha/node_modules/glob/test/00-setup.js b/tests/mocha/node_modules/glob/test/00-setup.js new file mode 100644 index 0000000000..245afafda4 --- /dev/null +++ b/tests/mocha/node_modules/glob/test/00-setup.js @@ -0,0 +1,176 @@ +// just a little pre-run script to set up the fixtures. +// zz-finish cleans it up + +var mkdirp = require("mkdirp") +var path = require("path") +var i = 0 +var tap = require("tap") +var fs = require("fs") +var rimraf = require("rimraf") + +var files = +[ "a/.abcdef/x/y/z/a" +, "a/abcdef/g/h" +, "a/abcfed/g/h" +, "a/b/c/d" +, "a/bc/e/f" +, "a/c/d/c/b" +, "a/cb/e/f" +] + +var symlinkTo = path.resolve(__dirname, "a/symlink/a/b/c") +var symlinkFrom = "../.." + +files = files.map(function (f) { + return path.resolve(__dirname, f) +}) + +tap.test("remove fixtures", function (t) { + rimraf(path.resolve(__dirname, "a"), function (er) { + t.ifError(er, "remove fixtures") + t.end() + }) +}) + +files.forEach(function (f) { + tap.test(f, function (t) { + var d = path.dirname(f) + mkdirp(d, 0755, function (er) { + if (er) { + t.fail(er) + return t.bailout() + } + fs.writeFile(f, "i like tests", function (er) { + t.ifError(er, "make file") + t.end() + }) + }) + }) +}) + +if (process.platform !== "win32") { + tap.test("symlinky", function (t) { + var d = path.dirname(symlinkTo) + console.error("mkdirp", d) + mkdirp(d, 0755, function (er) { + t.ifError(er) + fs.symlink(symlinkFrom, symlinkTo, "dir", function (er) { + t.ifError(er, "make symlink") + t.end() + }) + }) + }) +} + +;["foo","bar","baz","asdf","quux","qwer","rewq"].forEach(function (w) { + w = "/tmp/glob-test/" + w + tap.test("create " + w, function (t) { + mkdirp(w, function (er) { + if (er) + throw er + t.pass(w) + t.end() + }) + }) +}) + + +// generate the bash pattern test-fixtures if possible +if (process.platform === "win32" || !process.env.TEST_REGEN) { + console.error("Windows, or TEST_REGEN unset. Using cached fixtures.") + return +} + +var spawn = require("child_process").spawn; +var globs = + // put more patterns here. + // anything that would be directly in / should be in /tmp/glob-test + ["test/a/*/+(c|g)/./d" + ,"test/a/**/[cg]/../[cg]" + ,"test/a/{b,c,d,e,f}/**/g" + ,"test/a/b/**" + ,"test/**/g" + ,"test/a/abc{fed,def}/g/h" + ,"test/a/abc{fed/g,def}/**/" + ,"test/a/abc{fed/g,def}/**///**/" + ,"test/**/a/**/" + ,"test/+(a|b|c)/a{/,bc*}/**" + ,"test/*/*/*/f" + ,"test/**/f" + ,"test/a/symlink/a/b/c/a/b/c/a/b/c//a/b/c////a/b/c/**/b/c/**" + ,"{./*/*,/tmp/glob-test/*}" + ,"{/tmp/glob-test/*,*}" // evil owl face! how you taunt me! + ,"test/a/!(symlink)/**" + ] +var bashOutput = {} +var fs = require("fs") + +globs.forEach(function (pattern) { + tap.test("generate fixture " + pattern, function (t) { + var cmd = "shopt -s globstar && " + + "shopt -s extglob && " + + "shopt -s nullglob && " + + // "shopt >&2; " + + "eval \'for i in " + pattern + "; do echo $i; done\'" + var cp = spawn("bash", ["-c", cmd], { cwd: path.dirname(__dirname) }) + var out = [] + cp.stdout.on("data", function (c) { + out.push(c) + }) + cp.stderr.pipe(process.stderr) + cp.on("close", function (code) { + out = flatten(out) + if (!out) + out = [] + else + out = cleanResults(out.split(/\r*\n/)) + + bashOutput[pattern] = out + t.notOk(code, "bash test should finish nicely") + t.end() + }) + }) +}) + +tap.test("save fixtures", function (t) { + var fname = path.resolve(__dirname, "bash-results.json") + var data = JSON.stringify(bashOutput, null, 2) + "\n" + fs.writeFile(fname, data, function (er) { + t.ifError(er) + t.end() + }) +}) + +function cleanResults (m) { + // normalize discrepancies in ordering, duplication, + // and ending slashes. + return m.map(function (m) { + return m.replace(/\/+/g, "/").replace(/\/$/, "") + }).sort(alphasort).reduce(function (set, f) { + if (f !== set[set.length - 1]) set.push(f) + return set + }, []).sort(alphasort).map(function (f) { + // de-windows + return (process.platform !== 'win32') ? f + : f.replace(/^[a-zA-Z]:\\\\/, '/').replace(/\\/g, '/') + }) +} + +function flatten (chunks) { + var s = 0 + chunks.forEach(function (c) { s += c.length }) + var out = new Buffer(s) + s = 0 + chunks.forEach(function (c) { + c.copy(out, s) + s += c.length + }) + + return out.toString().trim() +} + +function alphasort (a, b) { + a = a.toLowerCase() + b = b.toLowerCase() + return a > b ? 1 : a < b ? -1 : 0 +} diff --git a/tests/mocha/node_modules/glob/test/bash-comparison.js b/tests/mocha/node_modules/glob/test/bash-comparison.js new file mode 100644 index 0000000000..239ed1a9c3 --- /dev/null +++ b/tests/mocha/node_modules/glob/test/bash-comparison.js @@ -0,0 +1,63 @@ +// basic test +// show that it does the same thing by default as the shell. +var tap = require("tap") +, child_process = require("child_process") +, bashResults = require("./bash-results.json") +, globs = Object.keys(bashResults) +, glob = require("../") +, path = require("path") + +// run from the root of the project +// this is usually where you're at anyway, but be sure. +process.chdir(path.resolve(__dirname, "..")) + +function alphasort (a, b) { + a = a.toLowerCase() + b = b.toLowerCase() + return a > b ? 1 : a < b ? -1 : 0 +} + +globs.forEach(function (pattern) { + var expect = bashResults[pattern] + // anything regarding the symlink thing will fail on windows, so just skip it + if (process.platform === "win32" && + expect.some(function (m) { + return /\/symlink\//.test(m) + })) + return + + tap.test(pattern, function (t) { + glob(pattern, function (er, matches) { + if (er) + throw er + + // sort and unmark, just to match the shell results + matches = cleanResults(matches) + + t.deepEqual(matches, expect, pattern) + t.end() + }) + }) + + tap.test(pattern + " sync", function (t) { + var matches = cleanResults(glob.sync(pattern)) + + t.deepEqual(matches, expect, "should match shell") + t.end() + }) +}) + +function cleanResults (m) { + // normalize discrepancies in ordering, duplication, + // and ending slashes. + return m.map(function (m) { + return m.replace(/\/+/g, "/").replace(/\/$/, "") + }).sort(alphasort).reduce(function (set, f) { + if (f !== set[set.length - 1]) set.push(f) + return set + }, []).sort(alphasort).map(function (f) { + // de-windows + return (process.platform !== 'win32') ? f + : f.replace(/^[a-zA-Z]:[\/\\]+/, '/').replace(/[\\\/]+/g, '/') + }) +} diff --git a/tests/mocha/node_modules/glob/test/bash-results.json b/tests/mocha/node_modules/glob/test/bash-results.json new file mode 100644 index 0000000000..a9bc347dea --- /dev/null +++ b/tests/mocha/node_modules/glob/test/bash-results.json @@ -0,0 +1,350 @@ +{ + "test/a/*/+(c|g)/./d": [ + "test/a/b/c/./d" + ], + "test/a/**/[cg]/../[cg]": [ + "test/a/abcdef/g/../g", + "test/a/abcfed/g/../g", + "test/a/b/c/../c", + "test/a/c/../c", + "test/a/c/d/c/../c", + "test/a/symlink/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c" + ], + "test/a/{b,c,d,e,f}/**/g": [], + "test/a/b/**": [ + "test/a/b", + "test/a/b/c", + "test/a/b/c/d" + ], + "test/**/g": [ + "test/a/abcdef/g", + "test/a/abcfed/g" + ], + "test/a/abc{fed,def}/g/h": [ + "test/a/abcdef/g/h", + "test/a/abcfed/g/h" + ], + "test/a/abc{fed/g,def}/**/": [ + "test/a/abcdef", + "test/a/abcdef/g", + "test/a/abcfed/g" + ], + "test/a/abc{fed/g,def}/**///**/": [ + "test/a/abcdef", + "test/a/abcdef/g", + "test/a/abcfed/g" + ], + "test/**/a/**/": [ + "test/a", + "test/a/abcdef", + "test/a/abcdef/g", + "test/a/abcfed", + "test/a/abcfed/g", + "test/a/b", + "test/a/b/c", + "test/a/bc", + "test/a/bc/e", + "test/a/c", + "test/a/c/d", + "test/a/c/d/c", + "test/a/cb", + "test/a/cb/e", + "test/a/symlink", + "test/a/symlink/a", + "test/a/symlink/a/b", + "test/a/symlink/a/b/c", + "test/a/symlink/a/b/c/a", + "test/a/symlink/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b" + ], + "test/+(a|b|c)/a{/,bc*}/**": [ + "test/a/abcdef", + "test/a/abcdef/g", + "test/a/abcdef/g/h", + "test/a/abcfed", + "test/a/abcfed/g", + "test/a/abcfed/g/h" + ], + "test/*/*/*/f": [ + "test/a/bc/e/f", + "test/a/cb/e/f" + ], + "test/**/f": [ + "test/a/bc/e/f", + "test/a/cb/e/f" + ], + "test/a/symlink/a/b/c/a/b/c/a/b/c//a/b/c////a/b/c/**/b/c/**": [ + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", + "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c" + ], + "{./*/*,/tmp/glob-test/*}": [ + "./examples/g.js", + "./examples/usr-local.js", + "./node_modules/graceful-fs", + "./node_modules/inherits", + "./node_modules/minimatch", + "./node_modules/mkdirp", + "./node_modules/rimraf", + "./node_modules/tap", + "./test/00-setup.js", + "./test/a", + "./test/bash-comparison.js", + "./test/bash-results.json", + "./test/cwd-test.js", + "./test/globstar-match.js", + "./test/mark.js", + "./test/nocase-nomagic.js", + "./test/pause-resume.js", + "./test/root-nomount.js", + "./test/root.js", + "./test/stat.js", + "./test/zz-cleanup.js", + "/tmp/glob-test/asdf", + "/tmp/glob-test/bar", + "/tmp/glob-test/baz", + "/tmp/glob-test/foo", + "/tmp/glob-test/quux", + "/tmp/glob-test/qwer", + "/tmp/glob-test/rewq" + ], + "{/tmp/glob-test/*,*}": [ + "/tmp/glob-test/asdf", + "/tmp/glob-test/bar", + "/tmp/glob-test/baz", + "/tmp/glob-test/foo", + "/tmp/glob-test/quux", + "/tmp/glob-test/qwer", + "/tmp/glob-test/rewq", + "examples", + "glob.js", + "LICENSE", + "node_modules", + "package.json", + "README.md", + "test" + ], + "test/a/!(symlink)/**": [ + "test/a/abcdef", + "test/a/abcdef/g", + "test/a/abcdef/g/h", + "test/a/abcfed", + "test/a/abcfed/g", + "test/a/abcfed/g/h", + "test/a/b", + "test/a/b/c", + "test/a/b/c/d", + "test/a/bc", + "test/a/bc/e", + "test/a/bc/e/f", + "test/a/c", + "test/a/c/d", + "test/a/c/d/c", + "test/a/c/d/c/b", + "test/a/cb", + "test/a/cb/e", + "test/a/cb/e/f" + ] +} diff --git a/tests/mocha/node_modules/glob/test/cwd-test.js b/tests/mocha/node_modules/glob/test/cwd-test.js new file mode 100644 index 0000000000..352c27efad --- /dev/null +++ b/tests/mocha/node_modules/glob/test/cwd-test.js @@ -0,0 +1,55 @@ +var tap = require("tap") + +var origCwd = process.cwd() +process.chdir(__dirname) + +tap.test("changing cwd and searching for **/d", function (t) { + var glob = require('../') + var path = require('path') + t.test('.', function (t) { + glob('**/d', function (er, matches) { + t.ifError(er) + t.like(matches, [ 'a/b/c/d', 'a/c/d' ]) + t.end() + }) + }) + + t.test('a', function (t) { + glob('**/d', {cwd:path.resolve('a')}, function (er, matches) { + t.ifError(er) + t.like(matches, [ 'b/c/d', 'c/d' ]) + t.end() + }) + }) + + t.test('a/b', function (t) { + glob('**/d', {cwd:path.resolve('a/b')}, function (er, matches) { + t.ifError(er) + t.like(matches, [ 'c/d' ]) + t.end() + }) + }) + + t.test('a/b/', function (t) { + glob('**/d', {cwd:path.resolve('a/b/')}, function (er, matches) { + t.ifError(er) + t.like(matches, [ 'c/d' ]) + t.end() + }) + }) + + t.test('.', function (t) { + glob('**/d', {cwd: process.cwd()}, function (er, matches) { + t.ifError(er) + t.like(matches, [ 'a/b/c/d', 'a/c/d' ]) + t.end() + }) + }) + + t.test('cd -', function (t) { + process.chdir(origCwd) + t.end() + }) + + t.end() +}) diff --git a/tests/mocha/node_modules/glob/test/globstar-match.js b/tests/mocha/node_modules/glob/test/globstar-match.js new file mode 100644 index 0000000000..9b234fa2a8 --- /dev/null +++ b/tests/mocha/node_modules/glob/test/globstar-match.js @@ -0,0 +1,19 @@ +var Glob = require("../glob.js").Glob +var test = require('tap').test + +test('globstar should not have dupe matches', function(t) { + var pattern = 'a/**/[gh]' + var g = new Glob(pattern, { cwd: __dirname }) + var matches = [] + g.on('match', function(m) { + console.error('match %j', m) + matches.push(m) + }) + g.on('end', function(set) { + console.error('set', set) + matches = matches.sort() + set = set.sort() + t.same(matches, set, 'should have same set of matches') + t.end() + }) +}) diff --git a/tests/mocha/node_modules/glob/test/mark.js b/tests/mocha/node_modules/glob/test/mark.js new file mode 100644 index 0000000000..ed68a335c3 --- /dev/null +++ b/tests/mocha/node_modules/glob/test/mark.js @@ -0,0 +1,74 @@ +var test = require("tap").test +var glob = require('../') +process.chdir(__dirname) + +test("mark, no / on pattern", function (t) { + glob("a/*", {mark: true}, function (er, results) { + if (er) + throw er + var expect = [ 'a/abcdef/', + 'a/abcfed/', + 'a/b/', + 'a/bc/', + 'a/c/', + 'a/cb/' ] + + if (process.platform !== "win32") + expect.push('a/symlink/') + + t.same(results, expect) + t.end() + }) +}) + +test("mark=false, no / on pattern", function (t) { + glob("a/*", function (er, results) { + if (er) + throw er + var expect = [ 'a/abcdef', + 'a/abcfed', + 'a/b', + 'a/bc', + 'a/c', + 'a/cb' ] + + if (process.platform !== "win32") + expect.push('a/symlink') + t.same(results, expect) + t.end() + }) +}) + +test("mark=true, / on pattern", function (t) { + glob("a/*/", {mark: true}, function (er, results) { + if (er) + throw er + var expect = [ 'a/abcdef/', + 'a/abcfed/', + 'a/b/', + 'a/bc/', + 'a/c/', + 'a/cb/' ] + if (process.platform !== "win32") + expect.push('a/symlink/') + t.same(results, expect) + t.end() + }) +}) + +test("mark=false, / on pattern", function (t) { + glob("a/*/", function (er, results) { + if (er) + throw er + var expect = [ 'a/abcdef/', + 'a/abcfed/', + 'a/b/', + 'a/bc/', + 'a/c/', + 'a/cb/' ] + if (process.platform !== "win32") + expect.push('a/symlink/') + t.same(results, expect) + t.end() + }) +}) diff --git a/tests/mocha/node_modules/glob/test/nocase-nomagic.js b/tests/mocha/node_modules/glob/test/nocase-nomagic.js new file mode 100644 index 0000000000..d86297098d --- /dev/null +++ b/tests/mocha/node_modules/glob/test/nocase-nomagic.js @@ -0,0 +1,113 @@ +var fs = require('graceful-fs'); +var test = require('tap').test; +var glob = require('../'); + +test('mock fs', function(t) { + var stat = fs.stat + var statSync = fs.statSync + var readdir = fs.readdir + var readdirSync = fs.readdirSync + + function fakeStat(path) { + var ret + switch (path.toLowerCase()) { + case '/tmp': case '/tmp/': + ret = { isDirectory: function() { return true } } + break + case '/tmp/a': + ret = { isDirectory: function() { return false } } + break + } + return ret + } + + fs.stat = function(path, cb) { + var f = fakeStat(path); + if (f) { + process.nextTick(function() { + cb(null, f) + }) + } else { + stat.call(fs, path, cb) + } + } + + fs.statSync = function(path) { + return fakeStat(path) || statSync.call(fs, path) + } + + function fakeReaddir(path) { + var ret + switch (path.toLowerCase()) { + case '/tmp': case '/tmp/': + ret = [ 'a', 'A' ] + break + case '/': + ret = ['tmp', 'tMp', 'tMP', 'TMP'] + } + return ret + } + + fs.readdir = function(path, cb) { + var f = fakeReaddir(path) + if (f) + process.nextTick(function() { + cb(null, f) + }) + else + readdir.call(fs, path, cb) + } + + fs.readdirSync = function(path) { + return fakeReaddir(path) || readdirSync.call(fs, path) + } + + t.pass('mocked') + t.end() +}) + +test('nocase, nomagic', function(t) { + var n = 2 + var want = [ '/TMP/A', + '/TMP/a', + '/tMP/A', + '/tMP/a', + '/tMp/A', + '/tMp/a', + '/tmp/A', + '/tmp/a' ] + glob('/tmp/a', { nocase: true }, function(er, res) { + if (er) + throw er + t.same(res.sort(), want) + if (--n === 0) t.end() + }) + glob('/tmp/A', { nocase: true }, function(er, res) { + if (er) + throw er + t.same(res.sort(), want) + if (--n === 0) t.end() + }) +}) + +test('nocase, with some magic', function(t) { + t.plan(2) + var want = [ '/TMP/A', + '/TMP/a', + '/tMP/A', + '/tMP/a', + '/tMp/A', + '/tMp/a', + '/tmp/A', + '/tmp/a' ] + glob('/tmp/*', { nocase: true }, function(er, res) { + if (er) + throw er + t.same(res.sort(), want) + }) + glob('/tmp/*', { nocase: true }, function(er, res) { + if (er) + throw er + t.same(res.sort(), want) + }) +}) diff --git a/tests/mocha/node_modules/glob/test/pause-resume.js b/tests/mocha/node_modules/glob/test/pause-resume.js new file mode 100644 index 0000000000..e1ffbab1c5 --- /dev/null +++ b/tests/mocha/node_modules/glob/test/pause-resume.js @@ -0,0 +1,73 @@ +// show that no match events happen while paused. +var tap = require("tap") +, child_process = require("child_process") +// just some gnarly pattern with lots of matches +, pattern = "test/a/!(symlink)/**" +, bashResults = require("./bash-results.json") +, patterns = Object.keys(bashResults) +, glob = require("../") +, Glob = glob.Glob +, path = require("path") + +// run from the root of the project +// this is usually where you're at anyway, but be sure. +process.chdir(path.resolve(__dirname, "..")) + +function alphasort (a, b) { + a = a.toLowerCase() + b = b.toLowerCase() + return a > b ? 1 : a < b ? -1 : 0 +} + +function cleanResults (m) { + // normalize discrepancies in ordering, duplication, + // and ending slashes. + return m.map(function (m) { + return m.replace(/\/+/g, "/").replace(/\/$/, "") + }).sort(alphasort).reduce(function (set, f) { + if (f !== set[set.length - 1]) set.push(f) + return set + }, []).sort(alphasort).map(function (f) { + // de-windows + return (process.platform !== 'win32') ? f + : f.replace(/^[a-zA-Z]:\\\\/, '/').replace(/\\/g, '/') + }) +} + +var globResults = [] +tap.test("use a Glob object, and pause/resume it", function (t) { + var g = new Glob(pattern) + , paused = false + , res = [] + , expect = bashResults[pattern] + + g.on("pause", function () { + console.error("pause") + }) + + g.on("resume", function () { + console.error("resume") + }) + + g.on("match", function (m) { + t.notOk(g.paused, "must not be paused") + globResults.push(m) + g.pause() + t.ok(g.paused, "must be paused") + setTimeout(g.resume.bind(g), 10) + }) + + g.on("end", function (matches) { + t.pass("reached glob end") + globResults = cleanResults(globResults) + matches = cleanResults(matches) + t.deepEqual(matches, globResults, + "end event matches should be the same as match events") + + t.deepEqual(matches, expect, + "glob matches should be the same as bash results") + + t.end() + }) +}) + diff --git a/tests/mocha/node_modules/glob/test/root-nomount.js b/tests/mocha/node_modules/glob/test/root-nomount.js new file mode 100644 index 0000000000..3ac5979b05 --- /dev/null +++ b/tests/mocha/node_modules/glob/test/root-nomount.js @@ -0,0 +1,39 @@ +var tap = require("tap") + +var origCwd = process.cwd() +process.chdir(__dirname) + +tap.test("changing root and searching for /b*/**", function (t) { + var glob = require('../') + var path = require('path') + t.test('.', function (t) { + glob('/b*/**', { globDebug: true, root: '.', nomount: true }, function (er, matches) { + t.ifError(er) + t.like(matches, []) + t.end() + }) + }) + + t.test('a', function (t) { + glob('/b*/**', { globDebug: true, root: path.resolve('a'), nomount: true }, function (er, matches) { + t.ifError(er) + t.like(matches, [ '/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f' ]) + t.end() + }) + }) + + t.test('root=a, cwd=a/b', function (t) { + glob('/b*/**', { globDebug: true, root: 'a', cwd: path.resolve('a/b'), nomount: true }, function (er, matches) { + t.ifError(er) + t.like(matches, [ '/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f' ]) + t.end() + }) + }) + + t.test('cd -', function (t) { + process.chdir(origCwd) + t.end() + }) + + t.end() +}) diff --git a/tests/mocha/node_modules/glob/test/root.js b/tests/mocha/node_modules/glob/test/root.js new file mode 100644 index 0000000000..95c23f99ca --- /dev/null +++ b/tests/mocha/node_modules/glob/test/root.js @@ -0,0 +1,46 @@ +var t = require("tap") + +var origCwd = process.cwd() +process.chdir(__dirname) + +var glob = require('../') +var path = require('path') + +t.test('.', function (t) { + glob('/b*/**', { globDebug: true, root: '.' }, function (er, matches) { + t.ifError(er) + t.like(matches, []) + t.end() + }) +}) + + +t.test('a', function (t) { + console.error("root=" + path.resolve('a')) + glob('/b*/**', { globDebug: true, root: path.resolve('a') }, function (er, matches) { + t.ifError(er) + var wanted = [ + '/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f' + ].map(function (m) { + return path.join(path.resolve('a'), m).replace(/\\/g, '/') + }) + + t.like(matches, wanted) + t.end() + }) +}) + +t.test('root=a, cwd=a/b', function (t) { + glob('/b*/**', { globDebug: true, root: 'a', cwd: path.resolve('a/b') }, function (er, matches) { + t.ifError(er) + t.like(matches, [ '/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f' ].map(function (m) { + return path.join(path.resolve('a'), m).replace(/\\/g, '/') + })) + t.end() + }) +}) + +t.test('cd -', function (t) { + process.chdir(origCwd) + t.end() +}) diff --git a/tests/mocha/node_modules/glob/test/stat.js b/tests/mocha/node_modules/glob/test/stat.js new file mode 100644 index 0000000000..62917114b4 --- /dev/null +++ b/tests/mocha/node_modules/glob/test/stat.js @@ -0,0 +1,32 @@ +var glob = require('../') +var test = require('tap').test +var path = require('path') + +test('stat all the things', function(t) { + var g = new glob.Glob('a/*abc*/**', { stat: true, cwd: __dirname }) + var matches = [] + g.on('match', function(m) { + matches.push(m) + }) + var stats = [] + g.on('stat', function(m) { + stats.push(m) + }) + g.on('end', function(eof) { + stats = stats.sort() + matches = matches.sort() + eof = eof.sort() + t.same(stats, matches) + t.same(eof, matches) + var cache = Object.keys(this.statCache) + t.same(cache.map(function (f) { + return path.relative(__dirname, f) + }).sort(), matches) + + cache.forEach(function(c) { + t.equal(typeof this.statCache[c], 'object') + }, this) + + t.end() + }) +}) diff --git a/tests/mocha/node_modules/glob/test/zz-cleanup.js b/tests/mocha/node_modules/glob/test/zz-cleanup.js new file mode 100644 index 0000000000..e085f0fa77 --- /dev/null +++ b/tests/mocha/node_modules/glob/test/zz-cleanup.js @@ -0,0 +1,11 @@ +// remove the fixtures +var tap = require("tap") +, rimraf = require("rimraf") +, path = require("path") + +tap.test("cleanup fixtures", function (t) { + rimraf(path.resolve(__dirname, "a"), function (er) { + t.ifError(er, "removed") + t.end() + }) +}) diff --git a/tests/mocha/node_modules/growl/History.md b/tests/mocha/node_modules/growl/History.md new file mode 100644 index 0000000000..a4b7b49f27 --- /dev/null +++ b/tests/mocha/node_modules/growl/History.md @@ -0,0 +1,63 @@ + +1.7.0 / 2012-12-30 +================== + + * support transient notifications in Gnome + +1.6.1 / 2012-09-25 +================== + + * restore compatibility with node < 0.8 [fgnass] + +1.6.0 / 2012-09-06 +================== + + * add notification center support [drudge] + +1.5.1 / 2012-04-08 +================== + + * Merge pull request #16 from KyleAMathews/patch-1 + * Fixes #15 + +1.5.0 / 2012-02-08 +================== + + * Added windows support [perfusorius] + +1.4.1 / 2011-12-28 +================== + + * Fixed: dont exit(). Closes #9 + +1.4.0 / 2011-12-17 +================== + + * Changed API: `growl.notify()` -> `growl()` + +1.3.0 / 2011-12-17 +================== + + * Added support for Ubuntu/Debian/Linux users [niftylettuce] + * Fixed: send notifications even if title not specified [alessioalex] + +1.2.0 / 2011-10-06 +================== + + * Add support for priority. + +1.1.0 / 2011-03-15 +================== + + * Added optional callbacks + * Added parsing of version + +1.0.1 / 2010-03-26 +================== + + * Fixed; sys.exec -> child_process.exec to support latest node + +1.0.0 / 2010-03-19 +================== + + * Initial release diff --git a/tests/mocha/node_modules/growl/Readme.md b/tests/mocha/node_modules/growl/Readme.md new file mode 100644 index 0000000000..48d717ccb3 --- /dev/null +++ b/tests/mocha/node_modules/growl/Readme.md @@ -0,0 +1,99 @@ +# Growl for nodejs + +Growl support for Nodejs. This is essentially a port of my [Ruby Growl Library](http://github.com/visionmedia/growl). Ubuntu/Linux support added thanks to [@niftylettuce](http://github.com/niftylettuce). + +## Installation + +### Install + +### Mac OS X (Darwin): + + Install [growlnotify(1)](http://growl.info/extras.php#growlnotify). On OS X 10.8, Notification Center is supported using [terminal-notifier](https://github.com/alloy/terminal-notifier). To install: + + $ sudo gem install terminal-notifier + + Install [npm](http://npmjs.org/) and run: + + $ npm install growl + +### Ubuntu (Linux): + + Install `notify-send` through the [libnotify-bin](http://packages.ubuntu.com/libnotify-bin) package: + + $ sudo apt-get install libnotify-bin + + Install [npm](http://npmjs.org/) and run: + + $ npm install growl + +### Windows: + + Download and install [Growl for Windows](http://www.growlforwindows.com/gfw/default.aspx) + + Download [growlnotify](http://www.growlforwindows.com/gfw/help/growlnotify.aspx) - **IMPORTANT :** Unpack growlnotify to a folder that is present in your path! + + Install [npm](http://npmjs.org/) and run: + + $ npm install growl + +## Examples + +Callback functions are optional + + var growl = require('growl') + growl('You have mail!') + growl('5 new messages', { sticky: true }) + growl('5 new emails', { title: 'Email Client', image: 'Safari', sticky: true }) + growl('Message with title', { title: 'Title'}) + growl('Set priority', { priority: 2 }) + growl('Show Safari icon', { image: 'Safari' }) + growl('Show icon', { image: 'path/to/icon.icns' }) + growl('Show image', { image: 'path/to/my.image.png' }) + growl('Show png filesystem icon', { image: 'png' }) + growl('Show pdf filesystem icon', { image: 'article.pdf' }) + growl('Show pdf filesystem icon', { image: 'article.pdf' }, function(err){ + // ... notified + }) + +## Options + + - title + - notification title + - name + - application name + - priority + - priority for the notification (default is 0) + - sticky + - weither or not the notification should remainin until closed + - image + - Auto-detects the context: + - path to an icon sets --iconpath + - path to an image sets --image + - capitalized word sets --appIcon + - filename uses extname as --icon + - otherwise treated as --icon + +## License + +(The MIT License) + +Copyright (c) 2009 TJ Holowaychuk + +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 copies 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 all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 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. diff --git a/tests/mocha/node_modules/growl/lib/growl.js b/tests/mocha/node_modules/growl/lib/growl.js new file mode 100644 index 0000000000..04f4f9b487 --- /dev/null +++ b/tests/mocha/node_modules/growl/lib/growl.js @@ -0,0 +1,234 @@ +// Growl - Copyright TJ Holowaychuk (MIT Licensed) + +/** + * Module dependencies. + */ + +var exec = require('child_process').exec + , fs = require('fs') + , path = require('path') + , exists = fs.existsSync || path.existsSync + , os = require('os') + , quote = JSON.stringify + , cmd; + +function which(name) { + var paths = process.env.PATH.split(':'); + var loc; + + for (var i = 0, len = paths.length; i < len; ++i) { + loc = path.join(paths[i], name); + if (exists(loc)) return loc; + } +} + +switch(os.type()) { + case 'Darwin': + if (which('terminal-notifier')) { + cmd = { + type: "Darwin-NotificationCenter" + , pkg: "terminal-notifier" + , msg: '-message' + , title: '-title' + , subtitle: '-subtitle' + , priority: { + cmd: '-execute' + , range: [] + } + }; + } else { + cmd = { + type: "Darwin-Growl" + , pkg: "growlnotify" + , msg: '-m' + , sticky: '--sticky' + , priority: { + cmd: '--priority' + , range: [ + -2 + , -1 + , 0 + , 1 + , 2 + , "Very Low" + , "Moderate" + , "Normal" + , "High" + , "Emergency" + ] + } + }; + } + break; + case 'Linux': + cmd = { + type: "Linux" + , pkg: "notify-send" + , msg: '' + , sticky: '-t 0' + , icon: '-i' + , priority: { + cmd: '-u' + , range: [ + "low" + , "normal" + , "critical" + ] + } + }; + break; + case 'Windows_NT': + cmd = { + type: "Windows" + , pkg: "growlnotify" + , msg: '' + , sticky: '/s:true' + , title: '/t:' + , icon: '/i:' + , priority: { + cmd: '/p:' + , range: [ + -2 + , -1 + , 0 + , 1 + , 2 + ] + } + }; + break; +} + +/** + * Expose `growl`. + */ + +exports = module.exports = growl; + +/** + * Node-growl version. + */ + +exports.version = '1.4.1' + +/** + * Send growl notification _msg_ with _options_. + * + * Options: + * + * - title Notification title + * - sticky Make the notification stick (defaults to false) + * - priority Specify an int or named key (default is 0) + * - name Application name (defaults to growlnotify) + * - image + * - path to an icon sets --iconpath + * - path to an image sets --image + * - capitalized word sets --appIcon + * - filename uses extname as --icon + * - otherwise treated as --icon + * + * Examples: + * + * growl('New email') + * growl('5 new emails', { title: 'Thunderbird' }) + * growl('Email sent', function(){ + * // ... notification sent + * }) + * + * @param {string} msg + * @param {object} options + * @param {function} fn + * @api public + */ + +function growl(msg, options, fn) { + var image + , args + , options = options || {} + , fn = fn || function(){}; + + // noop + if (!cmd) return fn(new Error('growl not supported on this platform')); + args = [cmd.pkg]; + + // image + if (image = options.image) { + switch(cmd.type) { + case 'Darwin-Growl': + var flag, ext = path.extname(image).substr(1) + flag = flag || ext == 'icns' && 'iconpath' + flag = flag || /^[A-Z]/.test(image) && 'appIcon' + flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image' + flag = flag || ext && (image = ext) && 'icon' + flag = flag || 'icon' + args.push('--' + flag, image) + break; + case 'Linux': + args.push(cmd.icon + " " + image); + // libnotify defaults to sticky, set a hint for transient notifications + if (!options.sticky) args.push('--hint=int:transient:1'); + break; + case 'Windows': + args.push(cmd.icon + quote(image)); + break; + } + } + + // sticky + if (options.sticky) args.push(cmd.sticky); + + // priority + if (options.priority) { + var priority = options.priority + ''; + var checkindexOf = cmd.priority.range.indexOf(priority); + if (~cmd.priority.range.indexOf(priority)) { + args.push(cmd.priority, options.priority); + } + } + + // name + if (options.name && cmd.type === "Darwin-Growl") { + args.push('--name', options.name); + } + + switch(cmd.type) { + case 'Darwin-Growl': + args.push(cmd.msg); + args.push(quote(msg)); + if (options.title) args.push(quote(options.title)); + break; + case 'Darwin-NotificationCenter': + args.push(cmd.msg); + args.push(quote(msg)); + if (options.title) { + args.push(cmd.title); + args.push(quote(options.title)); + } + if (options.subtitle) { + args.push(cmd.subtitle); + args.push(quote(options.title)); + } + break; + case 'Darwin-Growl': + args.push(cmd.msg); + args.push(quote(msg)); + if (options.title) args.push(quote(options.title)); + break; + case 'Linux': + if (options.title) { + args.push(quote(options.title)); + args.push(cmd.msg); + args.push(quote(msg)); + } else { + args.push(quote(msg)); + } + break; + case 'Windows': + args.push(quote(msg)); + if (options.title) args.push(cmd.title + quote(options.title)); + break; + } + + // execute + exec(args.join(' '), fn); +}; diff --git a/tests/mocha/node_modules/growl/package.json b/tests/mocha/node_modules/growl/package.json new file mode 100644 index 0000000000..6565e46de6 --- /dev/null +++ b/tests/mocha/node_modules/growl/package.json @@ -0,0 +1,14 @@ +{ + "name": "growl", + "version": "1.7.0", + "description": "Growl unobtrusive notifications", + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "main": "./lib/growl.js", + "readme": "# Growl for nodejs\n\nGrowl support for Nodejs. This is essentially a port of my [Ruby Growl Library](http://github.com/visionmedia/growl). Ubuntu/Linux support added thanks to [@niftylettuce](http://github.com/niftylettuce). \n\n## Installation\n\n### Install \n\n### Mac OS X (Darwin):\n\n Install [growlnotify(1)](http://growl.info/extras.php#growlnotify). On OS X 10.8, Notification Center is supported using [terminal-notifier](https://github.com/alloy/terminal-notifier). To install:\n \n $ sudo gem install terminal-notifier\n \n Install [npm](http://npmjs.org/) and run:\n \n $ npm install growl\n\n### Ubuntu (Linux):\n\n Install `notify-send` through the [libnotify-bin](http://packages.ubuntu.com/libnotify-bin) package:\n\n $ sudo apt-get install libnotify-bin\n\n Install [npm](http://npmjs.org/) and run:\n \n $ npm install growl\n\n### Windows:\n\n Download and install [Growl for Windows](http://www.growlforwindows.com/gfw/default.aspx)\n\n Download [growlnotify](http://www.growlforwindows.com/gfw/help/growlnotify.aspx) - **IMPORTANT :** Unpack growlnotify to a folder that is present in your path!\n\n Install [npm](http://npmjs.org/) and run:\n \n $ npm install growl\n\n## Examples\n\nCallback functions are optional\n\n var growl = require('growl')\n growl('You have mail!')\n growl('5 new messages', { sticky: true })\n growl('5 new emails', { title: 'Email Client', image: 'Safari', sticky: true })\n growl('Message with title', { title: 'Title'})\n growl('Set priority', { priority: 2 })\n growl('Show Safari icon', { image: 'Safari' })\n growl('Show icon', { image: 'path/to/icon.icns' })\n growl('Show image', { image: 'path/to/my.image.png' })\n growl('Show png filesystem icon', { image: 'png' })\n growl('Show pdf filesystem icon', { image: 'article.pdf' })\n growl('Show pdf filesystem icon', { image: 'article.pdf' }, function(err){\n // ... notified\n })\n\n## Options\n\n - title\n - notification title\n - name\n - application name\n - priority\n - priority for the notification (default is 0)\n - sticky\n - weither or not the notification should remainin until closed\n - image\n - Auto-detects the context:\n - path to an icon sets --iconpath\n - path to an image sets --image\n - capitalized word sets --appIcon\n - filename uses extname as --icon\n - otherwise treated as --icon\n \n## License \n\n(The MIT License)\n\nCopyright (c) 2009 TJ Holowaychuk \n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", + "readmeFilename": "Readme.md", + "_id": "growl@1.7.0", + "_from": "growl@1.7.x" +} diff --git a/tests/mocha/node_modules/growl/test.js b/tests/mocha/node_modules/growl/test.js new file mode 100644 index 0000000000..cf22d90b2c --- /dev/null +++ b/tests/mocha/node_modules/growl/test.js @@ -0,0 +1,20 @@ + +var growl = require('./lib/growl') + +growl('You have mail!') +growl('5 new messages', { sticky: true }) +growl('5 new emails', { title: 'Email Client', image: 'Safari', sticky: true }) +growl('Message with title', { title: 'Title'}) +growl('Set priority', { priority: 2 }) +growl('Show Safari icon', { image: 'Safari' }) +growl('Show icon', { image: 'path/to/icon.icns' }) +growl('Show image', { image: 'path/to/my.image.png' }) +growl('Show png filesystem icon', { image: 'png' }) +growl('Show pdf filesystem icon', { image: 'article.pdf' }) +growl('Show pdf filesystem icon', { image: 'article.pdf' }, function(){ + console.log('callback'); +}) +growl('Show pdf filesystem icon', { title: 'Use show()', image: 'article.pdf' }) +growl('here \' are \n some \\ characters that " need escaping', {}, function(error, stdout, stderr) { + if (error !== null) throw new Error('escaping failed:\n' + stdout + stderr); +}) diff --git a/tests/mocha/node_modules/mkdirp/.npmignore b/tests/mocha/node_modules/mkdirp/.npmignore new file mode 100644 index 0000000000..9303c347ee --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/.npmignore @@ -0,0 +1,2 @@ +node_modules/ +npm-debug.log \ No newline at end of file diff --git a/tests/mocha/node_modules/mkdirp/.travis.yml b/tests/mocha/node_modules/mkdirp/.travis.yml new file mode 100644 index 0000000000..84fd7ca248 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/.travis.yml @@ -0,0 +1,5 @@ +language: node_js +node_js: + - 0.6 + - 0.8 + - 0.9 diff --git a/tests/mocha/node_modules/mkdirp/LICENSE b/tests/mocha/node_modules/mkdirp/LICENSE new file mode 100644 index 0000000000..432d1aeb01 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/LICENSE @@ -0,0 +1,21 @@ +Copyright 2010 James Halliday (mail@substack.net) + +This project is free software released under the MIT/X11 license: + +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 +copies 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 +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER 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. diff --git a/tests/mocha/node_modules/mkdirp/examples/pow.js b/tests/mocha/node_modules/mkdirp/examples/pow.js new file mode 100644 index 0000000000..e6924212e6 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/examples/pow.js @@ -0,0 +1,6 @@ +var mkdirp = require('mkdirp'); + +mkdirp('/tmp/foo/bar/baz', function (err) { + if (err) console.error(err) + else console.log('pow!') +}); diff --git a/tests/mocha/node_modules/mkdirp/index.js b/tests/mocha/node_modules/mkdirp/index.js new file mode 100644 index 0000000000..fda6de8a2c --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/index.js @@ -0,0 +1,82 @@ +var path = require('path'); +var fs = require('fs'); + +module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP; + +function mkdirP (p, mode, f, made) { + if (typeof mode === 'function' || mode === undefined) { + f = mode; + mode = 0777 & (~process.umask()); + } + if (!made) made = null; + + var cb = f || function () {}; + if (typeof mode === 'string') mode = parseInt(mode, 8); + p = path.resolve(p); + + fs.mkdir(p, mode, function (er) { + if (!er) { + made = made || p; + return cb(null, made); + } + switch (er.code) { + case 'ENOENT': + mkdirP(path.dirname(p), mode, function (er, made) { + if (er) cb(er, made); + else mkdirP(p, mode, cb, made); + }); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + fs.stat(p, function (er2, stat) { + // if the stat fails, then that's super weird. + // let the original error be the failure reason. + if (er2 || !stat.isDirectory()) cb(er, made) + else cb(null, made); + }); + break; + } + }); +} + +mkdirP.sync = function sync (p, mode, made) { + if (mode === undefined) { + mode = 0777 & (~process.umask()); + } + if (!made) made = null; + + if (typeof mode === 'string') mode = parseInt(mode, 8); + p = path.resolve(p); + + try { + fs.mkdirSync(p, mode); + made = made || p; + } + catch (err0) { + switch (err0.code) { + case 'ENOENT' : + made = sync(path.dirname(p), mode, made); + sync(p, mode, made); + break; + + // In the case of any other error, just see if there's a dir + // there already. If so, then hooray! If not, then something + // is borked. + default: + var stat; + try { + stat = fs.statSync(p); + } + catch (err1) { + throw err0; + } + if (!stat.isDirectory()) throw err0; + break; + } + } + + return made; +}; diff --git a/tests/mocha/node_modules/mkdirp/package.json b/tests/mocha/node_modules/mkdirp/package.json new file mode 100644 index 0000000000..a71d8b77a9 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/package.json @@ -0,0 +1,34 @@ +{ + "name": "mkdirp", + "description": "Recursively mkdir, like `mkdir -p`", + "version": "0.3.5", + "author": { + "name": "James Halliday", + "email": "mail@substack.net", + "url": "http://substack.net" + }, + "main": "./index", + "keywords": [ + "mkdir", + "directory" + ], + "repository": { + "type": "git", + "url": "http://github.com/substack/node-mkdirp.git" + }, + "scripts": { + "test": "tap test/*.js" + }, + "devDependencies": { + "tap": "~0.4.0" + }, + "license": "MIT", + "readme": "# mkdirp\n\nLike `mkdir -p`, but in node.js!\n\n[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp)\n\n# example\n\n## pow.js\n\n```js\nvar mkdirp = require('mkdirp');\n \nmkdirp('/tmp/foo/bar/baz', function (err) {\n if (err) console.error(err)\n else console.log('pow!')\n});\n```\n\nOutput\n\n```\npow!\n```\n\nAnd now /tmp/foo/bar/baz exists, huzzah!\n\n# methods\n\n```js\nvar mkdirp = require('mkdirp');\n```\n\n## mkdirp(dir, mode, cb)\n\nCreate a new directory and any necessary subdirectories at `dir` with octal\npermission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\n`cb(err, made)` fires with the error or the first directory `made`\nthat had to be created, if any.\n\n## mkdirp.sync(dir, mode)\n\nSynchronously create a new directory and any necessary subdirectories at `dir`\nwith octal permission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\nReturns the first directory that had to be created, if any.\n\n# install\n\nWith [npm](http://npmjs.org) do:\n\n```\nnpm install mkdirp\n```\n\n# license\n\nMIT\n", + "readmeFilename": "readme.markdown", + "bugs": { + "url": "https://github.com/substack/node-mkdirp/issues" + }, + "homepage": "https://github.com/substack/node-mkdirp", + "_id": "mkdirp@0.3.5", + "_from": "mkdirp@0.3.5" +} diff --git a/tests/mocha/node_modules/mkdirp/readme.markdown b/tests/mocha/node_modules/mkdirp/readme.markdown new file mode 100644 index 0000000000..83b0216ab5 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/readme.markdown @@ -0,0 +1,63 @@ +# mkdirp + +Like `mkdir -p`, but in node.js! + +[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp) + +# example + +## pow.js + +```js +var mkdirp = require('mkdirp'); + +mkdirp('/tmp/foo/bar/baz', function (err) { + if (err) console.error(err) + else console.log('pow!') +}); +``` + +Output + +``` +pow! +``` + +And now /tmp/foo/bar/baz exists, huzzah! + +# methods + +```js +var mkdirp = require('mkdirp'); +``` + +## mkdirp(dir, mode, cb) + +Create a new directory and any necessary subdirectories at `dir` with octal +permission string `mode`. + +If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. + +`cb(err, made)` fires with the error or the first directory `made` +that had to be created, if any. + +## mkdirp.sync(dir, mode) + +Synchronously create a new directory and any necessary subdirectories at `dir` +with octal permission string `mode`. + +If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. + +Returns the first directory that had to be created, if any. + +# install + +With [npm](http://npmjs.org) do: + +``` +npm install mkdirp +``` + +# license + +MIT diff --git a/tests/mocha/node_modules/mkdirp/test/chmod.js b/tests/mocha/node_modules/mkdirp/test/chmod.js new file mode 100644 index 0000000000..520dcb8e9b --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/chmod.js @@ -0,0 +1,38 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +var ps = [ '', 'tmp' ]; + +for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); +} + +var file = ps.join('/'); + +test('chmod-pre', function (t) { + var mode = 0744 + mkdirp(file, mode, function (er) { + t.ifError(er, 'should not error'); + fs.stat(file, function (er, stat) { + t.ifError(er, 'should exist'); + t.ok(stat && stat.isDirectory(), 'should be directory'); + t.equal(stat && stat.mode & 0777, mode, 'should be 0744'); + t.end(); + }); + }); +}); + +test('chmod', function (t) { + var mode = 0755 + mkdirp(file, mode, function (er) { + t.ifError(er, 'should not error'); + fs.stat(file, function (er, stat) { + t.ifError(er, 'should exist'); + t.ok(stat && stat.isDirectory(), 'should be directory'); + t.end(); + }); + }); +}); diff --git a/tests/mocha/node_modules/mkdirp/test/clobber.js b/tests/mocha/node_modules/mkdirp/test/clobber.js new file mode 100644 index 0000000000..0eb7099870 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/clobber.js @@ -0,0 +1,37 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +var ps = [ '', 'tmp' ]; + +for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); +} + +var file = ps.join('/'); + +// a file in the way +var itw = ps.slice(0, 3).join('/'); + + +test('clobber-pre', function (t) { + console.error("about to write to "+itw) + fs.writeFileSync(itw, 'I AM IN THE WAY, THE TRUTH, AND THE LIGHT.'); + + fs.stat(itw, function (er, stat) { + t.ifError(er) + t.ok(stat && stat.isFile(), 'should be file') + t.end() + }) +}) + +test('clobber', function (t) { + t.plan(2); + mkdirp(file, 0755, function (err) { + t.ok(err); + t.equal(err.code, 'ENOTDIR'); + t.end(); + }); +}); diff --git a/tests/mocha/node_modules/mkdirp/test/mkdirp.js b/tests/mocha/node_modules/mkdirp/test/mkdirp.js new file mode 100644 index 0000000000..b07cd70c10 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/mkdirp.js @@ -0,0 +1,28 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('woo', function (t) { + t.plan(2); + 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 file = '/tmp/' + [x,y,z].join('/'); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/tests/mocha/node_modules/mkdirp/test/perm.js b/tests/mocha/node_modules/mkdirp/test/perm.js new file mode 100644 index 0000000000..23a7abbd23 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/perm.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('async perm', function (t) { + t.plan(2); + var file = '/tmp/' + (Math.random() * (1<<30)).toString(16); + + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); + +test('async root perm', function (t) { + mkdirp('/tmp', 0755, function (err) { + if (err) t.fail(err); + t.end(); + }); + t.end(); +}); diff --git a/tests/mocha/node_modules/mkdirp/test/perm_sync.js b/tests/mocha/node_modules/mkdirp/test/perm_sync.js new file mode 100644 index 0000000000..f685f60906 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/perm_sync.js @@ -0,0 +1,39 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('sync perm', function (t) { + t.plan(2); + var file = '/tmp/' + (Math.random() * (1<<30)).toString(16) + '.json'; + + mkdirp.sync(file, 0755); + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }); +}); + +test('sync root perm', function (t) { + t.plan(1); + + var file = '/tmp'; + mkdirp.sync(file, 0755); + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }); +}); diff --git a/tests/mocha/node_modules/mkdirp/test/race.js b/tests/mocha/node_modules/mkdirp/test/race.js new file mode 100644 index 0000000000..96a0447636 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/race.js @@ -0,0 +1,41 @@ +var mkdirp = require('../').mkdirp; +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('race', function (t) { + t.plan(4); + var ps = [ '', 'tmp' ]; + + for (var i = 0; i < 25; i++) { + var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); + ps.push(dir); + } + var file = ps.join('/'); + + var res = 2; + mk(file, function () { + if (--res === 0) t.end(); + }); + + mk(file, function () { + if (--res === 0) t.end(); + }); + + function mk (file, cb) { + mkdirp(file, 0755, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + if (cb) cb(); + } + }) + }) + }); + } +}); diff --git a/tests/mocha/node_modules/mkdirp/test/rel.js b/tests/mocha/node_modules/mkdirp/test/rel.js new file mode 100644 index 0000000000..79858243ab --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/rel.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('rel', function (t) { + t.plan(2); + 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) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + process.chdir(cwd); + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/tests/mocha/node_modules/mkdirp/test/return.js b/tests/mocha/node_modules/mkdirp/test/return.js new file mode 100644 index 0000000000..bce68e5613 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/return.js @@ -0,0 +1,25 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('return value', function (t) { + t.plan(4); + 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 file = '/tmp/' + [x,y,z].join('/'); + + // should return the first dir created. + // By this point, it would be profoundly surprising if /tmp didn't + // already exist, since every other test makes things in there. + mkdirp(file, function (err, made) { + t.ifError(err); + t.equal(made, '/tmp/' + x); + mkdirp(file, function (err, made) { + t.ifError(err); + t.equal(made, null); + }); + }); +}); diff --git a/tests/mocha/node_modules/mkdirp/test/return_sync.js b/tests/mocha/node_modules/mkdirp/test/return_sync.js new file mode 100644 index 0000000000..7c222d3558 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/return_sync.js @@ -0,0 +1,24 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('return value', function (t) { + t.plan(2); + 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 file = '/tmp/' + [x,y,z].join('/'); + + // should return the first dir created. + // By this point, it would be profoundly surprising if /tmp didn't + // already exist, since every other test makes things in there. + // Note that this will throw on failure, which will fail the test. + var made = mkdirp.sync(file); + t.equal(made, '/tmp/' + x); + + // making the same file again should have no effect. + made = mkdirp.sync(file); + t.equal(made, null); +}); diff --git a/tests/mocha/node_modules/mkdirp/test/root.js b/tests/mocha/node_modules/mkdirp/test/root.js new file mode 100644 index 0000000000..97ad7a2f35 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/root.js @@ -0,0 +1,18 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('root', function (t) { + // '/' on unix, 'c:/' on windows. + var file = path.resolve('/'); + + mkdirp(file, 0755, function (err) { + if (err) throw err + fs.stat(file, function (er, stat) { + if (er) throw er + t.ok(stat.isDirectory(), 'target is a directory'); + t.end(); + }) + }); +}); diff --git a/tests/mocha/node_modules/mkdirp/test/sync.js b/tests/mocha/node_modules/mkdirp/test/sync.js new file mode 100644 index 0000000000..7530cada84 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/sync.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('sync', function (t) { + t.plan(2); + 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 file = '/tmp/' + [x,y,z].join('/'); + + try { + mkdirp.sync(file, 0755); + } catch (err) { + t.fail(err); + return t.end(); + } + + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0755); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }); + }); +}); diff --git a/tests/mocha/node_modules/mkdirp/test/umask.js b/tests/mocha/node_modules/mkdirp/test/umask.js new file mode 100644 index 0000000000..64ccafe22b --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/umask.js @@ -0,0 +1,28 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('implicit mode from umask', function (t) { + t.plan(2); + 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 file = '/tmp/' + [x,y,z].join('/'); + + mkdirp(file, function (err) { + if (err) t.fail(err); + else path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, 0777 & (~process.umask())); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }) + }) + }); +}); diff --git a/tests/mocha/node_modules/mkdirp/test/umask_sync.js b/tests/mocha/node_modules/mkdirp/test/umask_sync.js new file mode 100644 index 0000000000..35bd5cbbf4 --- /dev/null +++ b/tests/mocha/node_modules/mkdirp/test/umask_sync.js @@ -0,0 +1,32 @@ +var mkdirp = require('../'); +var path = require('path'); +var fs = require('fs'); +var test = require('tap').test; + +test('umask sync modes', function (t) { + t.plan(2); + 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 file = '/tmp/' + [x,y,z].join('/'); + + try { + mkdirp.sync(file); + } catch (err) { + t.fail(err); + return t.end(); + } + + path.exists(file, function (ex) { + if (!ex) t.fail('file not created') + else fs.stat(file, function (err, stat) { + if (err) t.fail(err) + else { + t.equal(stat.mode & 0777, (0777 & (~process.umask()))); + t.ok(stat.isDirectory(), 'target not a directory'); + t.end(); + } + }); + }); +}); diff --git a/tests/mocha/package.json b/tests/mocha/package.json new file mode 100644 index 0000000000..4328f9178c --- /dev/null +++ b/tests/mocha/package.json @@ -0,0 +1,60 @@ +{ + "name": "mocha", + "version": "1.18.2", + "description": "simple, flexible, fun test framework", + "keywords": [ + "mocha", + "test", + "bdd", + "tdd", + "tap" + ], + "author": { + "name": "TJ Holowaychuk", + "email": "tj@vision-media.ca" + }, + "repository": { + "type": "git", + "url": "git://github.com/visionmedia/mocha.git" + }, + "main": "./index", + "bin": { + "mocha": "./bin/mocha", + "_mocha": "./bin/_mocha" + }, + "engines": { + "node": ">= 0.4.x" + }, + "scripts": { + "test": "make test-all" + }, + "dependencies": { + "commander": "2.0.0", + "growl": "1.7.x", + "jade": "0.26.3", + "diff": "1.0.7", + "debug": "*", + "mkdirp": "0.3.5", + "glob": "3.2.3" + }, + "devDependencies": { + "should": ">= 2.0.x", + "coffee-script": "1.2" + }, + "files": [ + "bin", + "images", + "lib", + "index.js", + "mocha.css", + "mocha.js" + ], + "readme": " [![Build Status](https://secure.travis-ci.org/visionmedia/mocha.png)](http://travis-ci.org/visionmedia/mocha)\n\n [![Mocha test framework](http://f.cl.ly/items/3l1k0n2A1U3M1I1L210p/Screen%20Shot%202012-02-24%20at%202.21.43%20PM.png)](http://visionmedia.github.io/mocha)\n\n Mocha is a simple, flexible, fun JavaScript test framework for node.js and the browser. For more information view the [documentation](http://visionmedia.github.io/mocha).\n\n## Contributors\n\n```\n\n project : mocha\n repo age : 2 years, 4 months ago\n commits : 1314\n active : 372 days\n files : 141\n authors :\n 582 TJ Holowaychuk 44.3%\n 389 Tj Holowaychuk 29.6%\n 46 Travis Jeffery 3.5%\n 31 Guillermo Rauch 2.4%\n 13 Attila Domokos 1.0%\n 10 John Firebaugh 0.8%\n 8 Jo Liss 0.6%\n 7 Nathan Rajlich 0.5%\n 6 Mike Pennisi 0.5%\n 6 James Carr 0.5%\n 6 Brendan Nee 0.5%\n 5 Aaron Heckmann 0.4%\n 5 Ryunosuke SATO 0.4%\n 4 hokaccha 0.3%\n 4 Joshua Krall 0.3%\n 4 Xavier Antoviaque 0.3%\n 3 Jesse Dailey 0.2%\n 3 Forbes Lindesay 0.2%\n 3 Sindre Sorhus 0.2%\n 3 Cory Thomas 0.2%\n 3 Fredrik Enestad 0.2%\n 3 Ben Lindsey 0.2%\n 3 Tyson Tate 0.2%\n 3 Mathieu Desvé 0.2%\n 3 Valentin Agachi 0.2%\n 3 Wil Moore III 0.2%\n 3 Merrick Christensen 0.2%\n 3 eiji.ienaga 0.2%\n 3 fool2fish 0.2%\n 3 Nathan Bowser 0.2%\n 3 Paul Miller 0.2%\n 2 Juzer Ali 0.2%\n 2 Pete Hawkins 0.2%\n 2 Jonas Westerlund 0.2%\n 2 Arian Stolwijk 0.2%\n 2 Quang Van 0.2%\n 2 Glen Mailer 0.2%\n 2 Justin DuJardin 0.2%\n 2 FARKAS Máté 0.2%\n 2 Raynos 0.2%\n 2 Michael Riley 0.2%\n 2 Michael Schoonmaker 0.2%\n 2 Domenic Denicola 0.2%\n 2 Simon Gaeremynck 0.2%\n 2 Konstantin Käfer 0.2%\n 2 domenic 0.2%\n 2 Paul Armstrong 0.2%\n 2 fcrisci 0.2%\n 2 Alexander Early 0.2%\n 2 Shawn Krisman 0.2%\n 2 Brian Beck 0.2%\n 2 Nathan Alderson 0.2%\n 2 David Henderson 0.2%\n 2 Timo Tijhof 0.2%\n 2 Ian Storm Taylor 0.2%\n 2 travis jeffery 0.2%\n 1 Matt Smith 0.1%\n 1 Matthew Shanley 0.1%\n 1 Nathan Black 0.1%\n 1 Phil Sung 0.1%\n 1 R56 0.1%\n 1 Refael Ackermann 0.1%\n 1 Richard Dingwall 0.1%\n 1 Romain Prieto 0.1%\n 1 Roman Neuhauser 0.1%\n 1 Roman Shtylman 0.1%\n 1 Russ Bradberry 0.1%\n 1 Russell Munson 0.1%\n 1 Rustem Mustafin 0.1%\n 1 Salehen Shovon Rahman 0.1%\n 1 Sasha Koss 0.1%\n 1 Seiya Konno 0.1%\n 1 Simon Goumaz 0.1%\n 1 Standa Opichal 0.1%\n 1 Stephen Mathieson 0.1%\n 1 Steve Mason 0.1%\n 1 Tapiwa Kelvin 0.1%\n 1 Teddy Zeenny 0.1%\n 1 Tim Ehat 0.1%\n 1 Vadim Nikitin 0.1%\n 1 Victor Costan 0.1%\n 1 Will Langstroth 0.1%\n 1 Yanis Wang 0.1%\n 1 Yuest Wang 0.1%\n 1 abrkn 0.1%\n 1 airportyh 0.1%\n 1 badunk 0.1%\n 1 fengmk2 0.1%\n 1 grasGendarme 0.1%\n 1 lodr 0.1%\n 1 tgautier@yahoo.com 0.1%\n 1 traleig1 0.1%\n 1 vlad 0.1%\n 1 yuitest 0.1%\n 1 Adam Crabtree 0.1%\n 1 Andreas Brekken 0.1%\n 1 Andreas Lind Petersen 0.1%\n 1 Andrew Nesbitt 0.1%\n 1 Andrey Popp 0.1%\n 1 Arnaud Brousseau 0.1%\n 1 Atsuya Takagi 0.1%\n 1 Austin Birch 0.1%\n 1 Bjørge Næss 0.1%\n 1 Brian Lalor 0.1%\n 1 Brian M. Carlson 0.1%\n 1 Brian Moore 0.1%\n 1 Bryan Donovan 0.1%\n 1 Casey Foster 0.1%\n 1 ChrisWren 0.1%\n 1 Corey Butler 0.1%\n 1 Daniel Stockman 0.1%\n 1 Dave McKenna 0.1%\n 1 Di Wu 0.1%\n 1 Dmitry Shirokov 0.1%\n 1 Fedor Indutny 0.1%\n 1 Florian Margaine 0.1%\n 1 Frederico Silva 0.1%\n 1 Fredrik Lindin 0.1%\n 1 Gareth Murphy 0.1%\n 1 Gavin Mogan 0.1%\n 1 Glen Huang 0.1%\n 1 Greg Perkins 0.1%\n 1 Harry Brundage 0.1%\n 1 Herman Junge 0.1%\n 1 Ian Young 0.1%\n 1 Ivan 0.1%\n 1 JP Bochi 0.1%\n 1 Jaakko Salonen 0.1%\n 1 Jakub Nešetřil 0.1%\n 1 James Bowes 0.1%\n 1 James Lal 0.1%\n 1 Jason Barry 0.1%\n 1 Javier Aranda 0.1%\n 1 Jeff Kunkle 0.1%\n 1 Jeremy Martin 0.1%\n 1 Jimmy Cuadra 0.1%\n 1 Jonathan Creamer 0.1%\n 1 Jussi Virtanen 0.1%\n 1 Katie Gengler 0.1%\n 1 Kazuhito Hokamura 0.1%\n 1 Kirill Korolyov 0.1%\n 1 Koen Punt 0.1%\n 1 Laszlo Bacsi 0.1%\n 1 Liam Newman 0.1%\n 1 László Bácsi 0.1%\n 1 Maciej Małecki 0.1%\n 1 Mal Graty 0.1%\n 1 Marc Kuo 0.1%\n 1 Matt Robenolt 0.1%\n```\n\n## Links\n\n - [Google Group](http://groups.google.com/group/mochajs)\n - [Wiki](https://github.com/visionmedia/mocha/wiki)\n - Mocha [Extensions and reporters](https://github.com/visionmedia/mocha/wiki)\n", + "readmeFilename": "Readme.md", + "bugs": { + "url": "https://github.com/visionmedia/mocha/issues" + }, + "homepage": "https://github.com/visionmedia/mocha", + "_id": "mocha@1.18.2", + "_from": "mocha@1.18.2" +} diff --git a/tests/package.json b/tests/package.json index 2b014f8161..6c0e164aff 100644 --- a/tests/package.json +++ b/tests/package.json @@ -17,7 +17,6 @@ "ms": "0.3.0", "should": "*", "coffee-script": "1.2", - "mocha": "1.7.4", "nw_test_loop": "git+https://github.com/owenc4a4/nw_test_loop_without_handle.git", "bignum": "git+https://github.com/owenc4a4/bignum.git", "node-dtrace-provider": "git+https://github.com/chrisa/node-dtrace-provider.git", diff --git a/tests/server/cookie_server.js b/tests/server/cookie_server.js new file mode 100644 index 0000000000..726f137b00 --- /dev/null +++ b/tests/server/cookie_server.js @@ -0,0 +1,71 @@ +var http = require('http'); +var url = require('url'); + +var expires_second = 86400000; + +var id_list = []; + +var request_listener = function(req,res){ + var location = url.parse(req.url,true); + var id = undefined; + var lang = undefined; + var cookies = {}; + var expires = new Date(Date.now()+expires_second).toGMTString(); + var set_cookies = null; + + var cookie_header = req.headers['cookie']; + + if (!cookie_header || cookie_header.length === 0){ + id = Math .random(); + lang = cookies["lang"]||"balabala"; + } else { + var cookie_tokens = cookie_header.split("; "); + for (var i=0;i0){ + headers["Set-Cookie"] = set_cookies; + } + res.writeHead(200,headers); + var html = JSON.stringify(cookies); + res.end(html); +}; + +var server = http.createServer(request_listener); +server.listen(8125); +console.log("Cookie server is running!"); diff --git a/tests/server/server.js b/tests/server/server.js index 9b7d497b3d..f751864fe9 100644 --- a/tests/server/server.js +++ b/tests/server/server.js @@ -85,3 +85,6 @@ for (var i = 0; i < ports.length; i++) { } exports.res_save = res_save; + +//import cookie server +require(__dirname+'/cookie_server.js'); From 1e1c48bc08e238396c4d07e5ef685948b4b7d5f0 Mon Sep 17 00:00:00 2001 From: tinyproxy Date: Wed, 7 May 2014 01:52:36 -0400 Subject: [PATCH 009/492] Append test case for issue 1669 --- .../buff_from_string/index.html | 36 +++++++++ .../buff_from_string/mocha_test.js | 80 +++++++++++++++++++ .../buff_from_string/package.json | 5 ++ .../automatic_tests/buff_from_string/test.py | 55 +++++++++++++ 4 files changed, 176 insertions(+) create mode 100644 tests/automatic_tests/buff_from_string/index.html create mode 100644 tests/automatic_tests/buff_from_string/mocha_test.js create mode 100644 tests/automatic_tests/buff_from_string/package.json create mode 100755 tests/automatic_tests/buff_from_string/test.py diff --git a/tests/automatic_tests/buff_from_string/index.html b/tests/automatic_tests/buff_from_string/index.html new file mode 100644 index 0000000000..0003b8c586 --- /dev/null +++ b/tests/automatic_tests/buff_from_string/index.html @@ -0,0 +1,36 @@ + + + + + + Test + + +

    We are using node.js + . +

    +

    Message: + +

    +

    + +

    + + + + diff --git a/tests/automatic_tests/buff_from_string/mocha_test.js b/tests/automatic_tests/buff_from_string/mocha_test.js new file mode 100644 index 0000000000..668f2841fd --- /dev/null +++ b/tests/automatic_tests/buff_from_string/mocha_test.js @@ -0,0 +1,80 @@ +var assert = require('assert'); +var func = require('./' + global.tests_dir + '/start_app/script.js'); +var result = []; +var spawn = require('child_process').spawn; +var fs = require('fs-extra'); +var is_chromedriver_exists = false; +var path = require('path'); + +describe("buff_from_string", function() { + var results = []; + var server = global.server; + var getResult = function(socket){ + socket.on('data',function(data){ + results = JSON.parse(data.toString()); + }); + }; + before(function(done) { + this.timeout(0); + server.on('connection',getResult); + func.copyExecFiles(function() { + var src_files = [ + "automatic_tests/buff_from_string/index.html", + "automatic_tests/buff_from_string/package.json", + "automatic_tests/buff_from_string/test.py" + ]; + var dst_files = [ + "tmp-nw/index.html", + "tmp-nw/package.json", + "tmp-nw/test.py" + ]; + + if (process.platform == 'win32'){ + src_files.push("automatic_tests/buff_from_string/chromedriver2_server.exe"); + dst_files.push("tmp-nw/chromedriver2_server.exe"); + } else { + src_files.push("automatic_tests/buff_from_string/chromedriver2_server"); + dst_files.push("tmp-nw/chromedriver2_server"); + } + + for (var i=0;i= 2: + port = int(argv[1]) + + +path = os.path +dirname = path.abspath(path.dirname(__file__)) +chromedriver_path = path.join(dirname,"chromedriver2_server") + +nw = webdriver.Chrome(chromedriver_path,service_args=[dirname]) +input_element = nw.find_element_by_id("message") +input_element.send_keys("hello world") + +send_button = nw.find_element_by_id("send-message-btn") +send_button.click() + +time.sleep(1) +results = nw.execute_script('return JSON.stringify(results);') + +connection = socket.create_connection(("localhost",port)) +connection.sendall(results) +connection.close() + +def kill_process_tree(pid): + machine_type = platform() + if "Linux" in machine_type or "Darwin" in machine_type: + import psutil + parent = psutil.Process(spid) + for child in parent.get_children(recursive=True): + child.kill() + parent.kill() + return + elif 'Windows' in machine_type: + import subprocess + dev_null = open(os.devnull,"wb") + subprocess.Popen(['taskkill', '/F', '/T', '/PID', str(pid)],stdout=dev_null,stderr=dev_null) + return + else: + # print "Unknow OS type" + return + +time.sleep(2) +spid = nw.service.process.pid +kill_process_tree(spid) \ No newline at end of file From 77d7f4b74b6dfb6c3be0eda31426a412db642ec4 Mon Sep 17 00:00:00 2001 From: tinyproxy Date: Wed, 7 May 2014 05:59:22 -0400 Subject: [PATCH 010/492] Add test case for issue 1575 --- tests/automatic_tests/nw_fork/fork_module.js | 3 ++ tests/automatic_tests/nw_fork/index.html | 43 ++++++++++++++++++++ tests/automatic_tests/nw_fork/mocha_test.js | 35 ++++++++++++++++ tests/automatic_tests/nw_fork/package.json | 5 +++ 4 files changed, 86 insertions(+) create mode 100644 tests/automatic_tests/nw_fork/fork_module.js create mode 100644 tests/automatic_tests/nw_fork/index.html create mode 100644 tests/automatic_tests/nw_fork/mocha_test.js create mode 100644 tests/automatic_tests/nw_fork/package.json diff --git a/tests/automatic_tests/nw_fork/fork_module.js b/tests/automatic_tests/nw_fork/fork_module.js new file mode 100644 index 0000000000..f1c84094e2 --- /dev/null +++ b/tests/automatic_tests/nw_fork/fork_module.js @@ -0,0 +1,3 @@ +process.on("message",function(m){ + process.send(m); +}); \ No newline at end of file diff --git a/tests/automatic_tests/nw_fork/index.html b/tests/automatic_tests/nw_fork/index.html new file mode 100644 index 0000000000..c094593ad1 --- /dev/null +++ b/tests/automatic_tests/nw_fork/index.html @@ -0,0 +1,43 @@ + + + + + test + + +

    it works!

    + + + diff --git a/tests/automatic_tests/nw_fork/mocha_test.js b/tests/automatic_tests/nw_fork/mocha_test.js new file mode 100644 index 0000000000..0f44732e94 --- /dev/null +++ b/tests/automatic_tests/nw_fork/mocha_test.js @@ -0,0 +1,35 @@ +var assert = require('assert'); +var spawn = require('child_process').spawn; +var path = require('path'); +var result = false; +describe('fork()',function(){ + var server = global.server; + var get_result = function(socket){ + socket.on('data',function(data){ + if (data.toString() == "true"){ + result = true; + } + }); + }; + + before(function(done){ + this.timeout(0); + server.on('connection',get_result); + var app_path = path.join('automatic_tests','nw_fork'); + var port = global.port || 13013; + var child = spawn(process.execPath,[app_path,port]); + child.on('exit',function(){ + done(); + }); + }); + + it("child_process.fork() should have a workaround solution",function(done){ + assert.equal(result,true); + done(); + }); + + after(function(done){ + server.removeListener('connection',get_result); + done(); + }); +}); \ No newline at end of file diff --git a/tests/automatic_tests/nw_fork/package.json b/tests/automatic_tests/nw_fork/package.json new file mode 100644 index 0000000000..113d160a54 --- /dev/null +++ b/tests/automatic_tests/nw_fork/package.json @@ -0,0 +1,5 @@ +{ + "name":"test", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file From 77b557a511790f24cfd01bde6aea4d949cf65006 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Fri, 9 May 2014 06:23:15 +0100 Subject: [PATCH 011/492] Fix: frameless window not draggable after resizing cherry-pick https://chromiumcodereview.appspot.com/12314115/ --- src/browser/native_window_mac.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index 02552df38c..03a89f270c 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -932,6 +932,7 @@ - (NSRect)contentRectForFrameRect:(NSRect)frameRect { webViewHeight - iter->bottom(), iter->width(), iter->height())]; + [controlRegion setAutoresizingMask:NSViewWidthSizable|NSViewHeightSizable]; [webView addSubview:controlRegion]; } } From 9e200256b53c9de6266e0742f06bb6b8e6b49296 Mon Sep 17 00:00:00 2001 From: Keith Cirkel Date: Sat, 10 May 2014 23:54:12 +0100 Subject: [PATCH 012/492] Include Node/Chrome versions in releases --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index ab7e6356e6..7047d6d0dd 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ It's created and developed in the Intel Open Source Technology Center. ## Downloads [v0.9.2 release notes](https://groups.google.com/d/msg/node-webkit/qpBhcWr-hSc/caGjhtl8cEgJ) -Prebuilt binaries (v0.9.2 - Feb 20, 2014): +Prebuilt binaries (v0.9.2 - Feb 20, 2014, based off of Node v0.11.9, Chrome 32.0.1700.107): * Linux: [32bit](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-linux-ia32.tar.gz) / [64bit] (http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-linux-x64.tar.gz) * Windows: [win32](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-win-ia32.zip) @@ -31,7 +31,7 @@ Prebuilt binaries (v0.9.2 - Feb 20, 2014): **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [v0.8.6 release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) -Prebuilt binaries (v0.8.6 - Apr 18, 2014): +Prebuilt binaries (v0.8.6 - Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66): * Linux: [32bit](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-linux-ia32.tar.gz) / [64bit] (http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-linux-x64.tar.gz) * Windows: [win32](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-win-ia32.zip) From 103d857ee5e07475f0c95b8e90ab81d928f198ae Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 28 Apr 2014 14:08:27 +0800 Subject: [PATCH 013/492] Fix: set force close only when dealing with top frames Fix the previous commit in a better way to simulate the previous solution (but do it from renderer): only try to set the flag on the first time. Conflicts: src/renderer/shell_content_renderer_client.cc --- src/renderer/shell_content_renderer_client.cc | 9 +++++++-- src/renderer/shell_content_renderer_client.h | 2 ++ 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index b368fe1c79..77a181b566 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -95,7 +95,8 @@ RenderView* GetCurrentRenderView() { } // namespace -ShellContentRendererClient::ShellContentRendererClient() { +ShellContentRendererClient::ShellContentRendererClient() + :creating_first_context_(true) { } ShellContentRendererClient::~ShellContentRendererClient() { @@ -211,6 +212,7 @@ void ShellContentRendererClient::DidCreateScriptContext( GURL url(frame->document().url()); VLOG(1) << "DidCreateScriptContext: " << url; InstallNodeSymbols(frame, context, url); + creating_first_context_ = false; } bool ShellContentRendererClient::goodForNode(WebKit::WebFrame* frame) @@ -355,7 +357,10 @@ void ShellContentRendererClient::InstallNodeSymbols( int ret; RenderViewImpl* render_view = RenderViewImpl::FromWebView(frame->view()); - render_view->Send(new ShellViewHostMsg_SetForceClose( + if (frame->parent() == NULL && creating_first_context_) { + // do this only for top frames, or initialization of iframe + // could override parent settings here + render_view->Send(new ShellViewHostMsg_SetForceClose( render_view->GetRoutingID(), true, &ret)); } } diff --git a/src/renderer/shell_content_renderer_client.h b/src/renderer/shell_content_renderer_client.h index f8a4f1fa69..3a6aecbcd6 100644 --- a/src/renderer/shell_content_renderer_client.h +++ b/src/renderer/shell_content_renderer_client.h @@ -60,6 +60,8 @@ class ShellContentRendererClient : public ContentRendererClient { scoped_ptr shell_observer_; scoped_ptr window_bindings_; + bool creating_first_context_; + void InstallNodeSymbols(WebKit::WebFrame* frame, v8::Handle context, const GURL& url); void UninstallNodeSymbols(WebKit::WebFrame* frame, From beb0bad7b79b0153b6aee1d101da3cfb98a44e7a Mon Sep 17 00:00:00 2001 From: tinyproxy Date: Wed, 14 May 2014 22:25:51 -0400 Subject: [PATCH 014/492] Port menu shortcut. --- src/api/menu/menu.h | 10 ++++++ src/api/menu/menu_gtk.cc | 31 +++++++++++++++++++ src/api/menuitem/menuitem.h | 13 ++++++++ src/api/menuitem/menuitem_gtk.cc | 52 ++++++++++++++++++++++++++++++++ src/browser/native_window_gtk.cc | 4 +++ src/browser/native_window_gtk.h | 3 ++ 6 files changed, 113 insertions(+) diff --git a/src/api/menu/menu.h b/src/api/menu/menu.h index d066ceb060..4edbea6c36 100644 --- a/src/api/menu/menu.h +++ b/src/api/menu/menu.h @@ -89,6 +89,10 @@ class Menu : public Base { virtual void Call(const std::string& method, const base::ListValue& arguments) OVERRIDE; +#if defined(OS_LINUX) + void UpdateKeys(GtkAccelGroup *gtk_accel_group); +#endif + private: friend class MenuItem; friend class Tray; @@ -101,6 +105,12 @@ class Menu : public Base { void Remove(MenuItem* menu_item, int pos); void Popup(int x, int y, content::Shell*); +#if defined(OS_LINUX) + std::vector menu_items; + GtkAccelGroup *gtk_accel_group; +#endif + + #if defined(OS_MACOSX) friend class nw::NativeWindowCocoa; NSMenu* menu_; diff --git a/src/api/menu/menu_gtk.cc b/src/api/menu/menu_gtk.cc index 17502e68c2..4adadc04e1 100644 --- a/src/api/menu/menu_gtk.cc +++ b/src/api/menu/menu_gtk.cc @@ -27,6 +27,8 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/render_widget_host_view.h" #include "ui/gfx/point.h" +#include "vector" +#include "gtk/gtk.h" namespace nwapi { @@ -86,6 +88,7 @@ void PointMenuPositionFunc(GtkMenu* menu, } // namespace void Menu::Create(const base::DictionaryValue& option) { + gtk_accel_group = NULL; std::string type; if (option.GetString("type", &type) && type == "menubar") menu_ = gtk_menu_bar_new(); @@ -102,14 +105,25 @@ void Menu::Destroy() { } void Menu::Append(MenuItem* menu_item) { + menu_items.push_back(menu_item); + if (GTK_IS_ACCEL_GROUP(gtk_accel_group)){ + menu_item->UpdateKeys(gtk_accel_group); + } gtk_menu_shell_append(GTK_MENU_SHELL(menu_), menu_item->menu_item_); } void Menu::Insert(MenuItem* menu_item, int pos) { + std::vector::iterator begin = menu_items.begin(); + menu_items.insert(begin+pos,menu_item); + if (GTK_IS_ACCEL_GROUP(gtk_accel_group)){ + menu_item->UpdateKeys(gtk_accel_group); + } gtk_menu_shell_insert(GTK_MENU_SHELL(menu_), menu_item->menu_item_, pos); } void Menu::Remove(MenuItem* menu_item, int pos) { + std::vector::iterator begin = menu_items.begin(); + menu_items.erase(begin+pos); gtk_container_remove(GTK_CONTAINER(menu_), menu_item->menu_item_); } @@ -131,4 +145,21 @@ void Menu::Popup(int x, int y, content::Shell* shell) { 3, triggering_event_time); } +void Menu::UpdateKeys(GtkAccelGroup *gtk_accel_group){ + this->gtk_accel_group = gtk_accel_group; + if (!GTK_IS_ACCEL_GROUP(gtk_accel_group)){ + return ; + } else { + std::vector::iterator menu_item_iterator = menu_items.begin(); + std::vector::iterator menu_item_end = menu_items.end(); + while (menu_item_iterator != menu_item_end){ + MenuItem *menu_item = *menu_item_iterator; + if (menu_item!=NULL && GTK_IS_MENU_ITEM(menu_item->menu_item_)){ + menu_item->UpdateKeys(gtk_accel_group); + } + ++menu_item_iterator; + } + } +} + } // namespace nwapi diff --git a/src/api/menuitem/menuitem.h b/src/api/menuitem/menuitem.h index 9a6ec986b5..48a8a82682 100644 --- a/src/api/menuitem/menuitem.h +++ b/src/api/menuitem/menuitem.h @@ -56,6 +56,10 @@ class MenuItem : public Base { virtual void Call(const std::string& method, const base::ListValue& arguments) OVERRIDE; +#if defined(OS_LINUX) + void UpdateKeys(GtkAccelGroup *gtk_accel_group); +#endif + #if defined(OS_MACOSX) || defined(OS_WIN) void OnClick(); #endif @@ -73,6 +77,15 @@ class MenuItem : public Base { void SetChecked(bool checked); void SetSubmenu(Menu* sub_menu); +#if defined(OS_LINUX) + GtkAccelGroup *gtk_accel_group; + GdkModifierType modifiers_mask; + guint keyval; + bool enable_shortcut; + Menu* submenu_; + std::string label_; +#endif + #if defined(OS_MACOSX) std::string type_; diff --git a/src/api/menuitem/menuitem_gtk.cc b/src/api/menuitem/menuitem_gtk.cc index fbd06733d2..9d32608447 100644 --- a/src/api/menuitem/menuitem_gtk.cc +++ b/src/api/menuitem/menuitem_gtk.cc @@ -23,12 +23,14 @@ #include "base/values.h" #include "content/nw/src/api/dispatcher_host.h" #include "content/nw/src/api/menu/menu.h" +#include "gdk/gdkkeysyms.h"//to get keyval from name namespace nwapi { void MenuItem::Create(const base::DictionaryValue& option) { std::string type; option.GetString("type", &type); + submenu_ = NULL; if (type == "separator") { menu_item_ = gtk_separator_menu_item_new(); @@ -60,6 +62,31 @@ void MenuItem::Create(const base::DictionaryValue& option) { int menu_id; if (option.GetInteger("submenu", &menu_id)) SetSubmenu(dispatcher_host()->GetApiObject(menu_id)); + std::string key; + if (option.GetString("key",&key)){ + enable_shortcut = true; + std::string modifiers = ""; + option.GetString("modifiers",&modifiers); + modifiers_mask = GdkModifierType(0); + if (modifiers.size() != 0){ + if (modifiers.find("ctrl") != std::string::npos){ + modifiers_mask = GdkModifierType(modifiers_mask|GDK_CONTROL_MASK); + } + if (modifiers.find("alt") != std::string::npos){ + modifiers_mask = GdkModifierType(modifiers_mask|GDK_MOD1_MASK); + } + if (modifiers.find("super") != std::string::npos){ + modifiers_mask = GdkModifierType(modifiers_mask|GDK_SUPER_MASK); + } + if (modifiers.find("meta") != std::string::npos){ + modifiers_mask = GdkModifierType(modifiers_mask|GDK_META_MASK); + } + } + keyval = gdk_keyval_from_name(key.c_str()); + + } else { + enable_shortcut = false; + } block_active_ = false; g_signal_connect(menu_item_, "activate", @@ -76,6 +103,7 @@ void MenuItem::Destroy() { } void MenuItem::SetLabel(const std::string& label) { + label_ = label; gtk_menu_item_set_label(GTK_MENU_ITEM(menu_item_), label.c_str()); } @@ -106,6 +134,10 @@ void MenuItem::SetChecked(bool checked) { } void MenuItem::SetSubmenu(Menu* sub_menu) { + submenu_ = sub_menu; + if (GTK_IS_ACCEL_GROUP(gtk_accel_group)){ + sub_menu->UpdateKeys(gtk_accel_group); + } if (sub_menu == NULL) gtk_menu_item_remove_submenu(GTK_MENU_ITEM(menu_item_)); else @@ -120,4 +152,24 @@ void MenuItem::OnClick(GtkWidget* widget) { dispatcher_host()->SendEvent(this, "click", args); } + +void MenuItem::UpdateKeys(GtkAccelGroup *gtk_accel_group){ + this->gtk_accel_group = gtk_accel_group; + if (enable_shortcut && GTK_IS_ACCEL_GROUP(gtk_accel_group)){ + gtk_widget_add_accelerator( + menu_item_, + "activate", + gtk_accel_group, + keyval, + modifiers_mask, + GTK_ACCEL_VISIBLE); + } + if (submenu_ != NULL){ + submenu_->UpdateKeys(gtk_accel_group); + } + return; +} + } // namespace nwapi + + diff --git a/src/browser/native_window_gtk.cc b/src/browser/native_window_gtk.cc index 2b1a3fc094..50d24b4bfd 100644 --- a/src/browser/native_window_gtk.cc +++ b/src/browser/native_window_gtk.cc @@ -60,6 +60,9 @@ NativeWindowGtk::NativeWindowGtk(const base::WeakPtr& shell, { window_ = GTK_WINDOW(gtk_window_new(GTK_WINDOW_TOPLEVEL)); + gtk_accel_group = gtk_accel_group_new(); + gtk_window_add_accel_group(window_,gtk_accel_group); + vbox_ = gtk_vbox_new(FALSE, 0); gtk_widget_show(vbox_); gtk_container_add(GTK_CONTAINER(window_), vbox_); @@ -308,6 +311,7 @@ bool NativeWindowGtk::IsKiosk() { } void NativeWindowGtk::SetMenu(nwapi::Menu* menu) { + menu->UpdateKeys(gtk_accel_group); gtk_box_pack_start(GTK_BOX(vbox_), menu->menu_, FALSE, FALSE, 0); gtk_box_reorder_child(GTK_BOX(vbox_), menu->menu_, 0); } diff --git a/src/browser/native_window_gtk.h b/src/browser/native_window_gtk.h index 1dd1b6b0d3..ed1c89159e 100644 --- a/src/browser/native_window_gtk.h +++ b/src/browser/native_window_gtk.h @@ -89,6 +89,9 @@ class NativeWindowGtk : public NativeWindow { // Set WebKit's style from current theme. void SetWebKitColorStyle(); + //Use to bind shortcut + GtkAccelGroup *gtk_accel_group; + // Create toolbar. void CreateToolbar(); From 3dbff7196b2e0e85681cce78c53653958780640e Mon Sep 17 00:00:00 2001 From: tinyproxy Date: Wed, 14 May 2014 22:35:51 -0400 Subject: [PATCH 015/492] Append menu shortcut test case --- tests/manual_tests/menu_shortcut/index.html | 57 +++++++++++++++++++ tests/manual_tests/menu_shortcut/package.json | 5 ++ 2 files changed, 62 insertions(+) create mode 100644 tests/manual_tests/menu_shortcut/index.html create mode 100644 tests/manual_tests/menu_shortcut/package.json diff --git a/tests/manual_tests/menu_shortcut/index.html b/tests/manual_tests/menu_shortcut/index.html new file mode 100644 index 0000000000..83cf3c44cd --- /dev/null +++ b/tests/manual_tests/menu_shortcut/index.html @@ -0,0 +1,57 @@ + + + + + test + + +

    it works!

    +

    +
      +
    1. Press Ctrl+Alt+i. Console will print "hello world" !
    2. +
    3. Press Ctrl+q. This app will quit!
    4. +
    +

    + + + + \ No newline at end of file diff --git a/tests/manual_tests/menu_shortcut/package.json b/tests/manual_tests/menu_shortcut/package.json new file mode 100644 index 0000000000..113d160a54 --- /dev/null +++ b/tests/manual_tests/menu_shortcut/package.json @@ -0,0 +1,5 @@ +{ + "name":"test", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file From 2ee02bf14fdc43e62c26a3b65abf4cf11fbe250c Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 16 May 2014 15:30:07 +0800 Subject: [PATCH 016/492] Fix previous commit --- src/renderer/shell_content_renderer_client.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index 77a181b566..bbc816fc2a 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -362,6 +362,7 @@ void ShellContentRendererClient::InstallNodeSymbols( // could override parent settings here render_view->Send(new ShellViewHostMsg_SetForceClose( render_view->GetRoutingID(), true, &ret)); + } } } From e8df11c56949df7e8854435cba42a36b7244d580 Mon Sep 17 00:00:00 2001 From: libm Date: Tue, 29 Apr 2014 12:18:53 +0800 Subject: [PATCH 017/492] Rename chromedriver2_server to chromedriver following upstream's change. https://src.chromium.org/viewvc/chrome?revision=225192&view=revision --- tools/package_binaries.py | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 0ffdda01db..6d16737314 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -63,13 +63,13 @@ exit(-1) if platform_name != 'win' and not os.path.exists( - os.path.join(project_root, 'chromedriver2_server')): - print 'chromedriver2_server file does not exist.\n' + os.path.join(project_root, 'chromedriver')): + print 'chromedriver file does not exist.\n' exit(-1) if platform_name == 'win' and not os.path.exists( - os.path.join(project_root, 'chromedriver2_server.exe')): - print 'chromedriver2_server file does not exist.\n' + os.path.join(project_root, 'chromedriver.exe')): + print 'chromedriver file does not exist.\n' exit(-1) @@ -98,25 +98,25 @@ 'credits.html', ) -required_chromedriver2_file_win = ( - 'chromedriver2_server.exe', +required_chromedriver_file_win = ( + 'chromedriver.exe', ) -required_chromedriver2_file_others = ( - 'chromedriver2_server', +required_chromedriver_file_others = ( + 'chromedriver', ) if (platform_name == 'linux'): required_file.append(required_file_linux) - required_file.append(required_chromedriver2_file_others) + required_file.append(required_chromedriver_file_others) if (platform_name == 'win'): required_file.append(required_file_win) - required_file.append(required_chromedriver2_file_win); + required_file.append(required_chromedriver_file_win); if (platform_name == 'osx'): required_file.append(required_file_mac) - required_file.append(required_chromedriver2_file_others) + required_file.append(required_chromedriver_file_others) #generate binary tar name @@ -140,7 +140,7 @@ arch = 'ia32' tarname.append('node-webkit-' + nw_version) -tarname.append('chromedriver2-nw-' + nw_version) +tarname.append('chromedriver-nw-' + nw_version) for index in range(len(tarname)): binary_name.append(tarname[index] + '-' + platform_name + '-' + arch); binary_tar.append(binary_name[index] + '.tar.gz') @@ -155,7 +155,7 @@ binary_store_path.append(os.path.join(project_root, 'node-webkit-binaries')) binary_store_path.append(os.path.join(project_root, - 'chromedriver2-binaries')) + 'chromedriver-binaries')) for index in range(len(binary_store_path)): if not os.path.exists(binary_store_path[index]): From a006f872cd9d186af771162e7827d82c2844eef2 Mon Sep 17 00:00:00 2001 From: libm Date: Tue, 20 May 2014 13:31:55 +0800 Subject: [PATCH 018/492] Updated symbol generation process. Now the 'dist' target will depend on nw, chromedriver and symbols. All these binaries will be packed into 'dist' folder under out/Release --- nw.gypi | 75 +++--- tools/package_binaries.py | 463 +++++++++++++++++++++----------------- 2 files changed, 288 insertions(+), 250 deletions(-) diff --git a/nw.gypi b/nw.gypi index 5cedde1553..95e80119a6 100644 --- a/nw.gypi +++ b/nw.gypi @@ -5,11 +5,6 @@ { 'variables': { 'nw_product_name': 'node-webkit', - 'conditions': [ - ['OS=="linux"', { - 'linux_dump_symbols': 1, - }], - ], }, 'target_defaults': { 'configurations': { @@ -588,6 +583,38 @@ 'nw', ], }, + { + 'target_name': 'nw_symbols', + 'type': 'none', + 'conditions': [ + ['OS=="linux"', { + 'actions': [ + { + 'action_name': 'dump_symbols', + 'inputs': [ + '<(DEPTH)/build/linux/dump_app_syms', + '<(PRODUCT_DIR)/dump_syms', + '<(PRODUCT_DIR)/nw', + ], + 'outputs': [ + '<(PRODUCT_DIR)/nw.breakpad.<(target_arch)', + ], + 'action': ['<(DEPTH)/build/linux/dump_app_syms', + '<(PRODUCT_DIR)/dump_syms', + '<(linux_strip_binary)', + '<(PRODUCT_DIR)/nw', + '<@(_outputs)'], + 'message': 'Dumping breakpad symbols to <(_outputs)', + 'process_outputs_as_sources': 1, + }, + ], + 'dependencies': [ + 'nw', + '../breakpad/breakpad.gyp:dump_syms', + ], + }], + ], + }, { 'target_name': 'dist', 'type': 'none', @@ -608,6 +635,7 @@ ], 'dependencies': [ '<(DEPTH)/chrome/chrome.gyp:chromedriver', + 'nw_symbols', ], 'conditions': [ ['OS == "linux"', { @@ -653,7 +681,7 @@ 'VCLinkerTool': { 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS }, - 'VCManifestTool': { + 'VCManifestTool': { 'AdditionalManifestFiles': [ '$(ProjectDir)\\nw\\src\\nw.exe.manifest', ], @@ -925,40 +953,5 @@ }, # target nw_helper_app ], }], # OS=="mac" - ['OS=="linux"', - { 'targets': [ - { - 'target_name': 'nw_symbols', - 'type': 'none', - 'conditions': [ - ['linux_dump_symbols==1', { - 'actions': [ - { - 'action_name': 'dump_symbols', - 'inputs': [ - '<(DEPTH)/build/linux/dump_app_syms', - '<(PRODUCT_DIR)/dump_syms', - '<(PRODUCT_DIR)/nw', - ], - 'outputs': [ - '<(PRODUCT_DIR)/nw.breakpad.<(target_arch)', - ], - 'action': ['<(DEPTH)/build/linux/dump_app_syms', - '<(PRODUCT_DIR)/dump_syms', - '<(linux_strip_binary)', - '<(PRODUCT_DIR)/nw', - '<@(_outputs)'], - 'message': 'Dumping breakpad symbols to <(_outputs)', - 'process_outputs_as_sources': 1, - }, - ], - 'dependencies': [ - 'nw', - '../breakpad/breakpad.gyp:dump_syms', - ], - }], - ], - }], - }], # OS=="linux" ] # conditions } diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 6d16737314..2716a1638d 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -1,224 +1,269 @@ #!/usr/bin/env python +import argparse +import getnwisrelease +import getnwversion +import gzip import os +import platform import shutil -import tarfile import sys - - -script_dir = os.path.dirname(__file__) -nw_root = os.path.normpath(os.path.join(script_dir, os.pardir)) -project_root = os.path.normpath(os.path.join(nw_root, os.pardir, os.pardir)); -#default project path -project_root = os.path.join(project_root, 'out', 'Release') -required_file = [] -tarname = [] -binary_name = [] -binary_tar = [] -binary_store_path = [] -binary_full_path = [] -binary_tar_full_path = [] - -#parse command line arguments -""" --p , the absolute path of executable files -""" -if '-p' in sys.argv: - tmp = sys.argv[sys.argv.index('-p') + 1] - if not os.path.isabs(tmp): - print 'the path is not an absolute path.\n' - exit(-1) - - if not os.path.exists(tmp): - print 'the directory does not exist.\n' +import tarfile +import zipfile + +################################ +# Parse command line args +parser = argparse.ArgumentParser(description='Package nw binaries.') +parser.add_argument('-p','--path',help='Where to find the binaries, like out/Release', required=False) +parser.add_argument('-s','--step',help='Execute specified step. (could be "nw", "chromedriver" or "symbol")', required=False) +args = parser.parse_args() + +################################ +# Init variables. +binaries_location = None # .../out/Release +platform_name = None # win/linux/osx +arch = None # ia32/x64 +step = None # nw/chromedriver/symbol +nw_ver = None # x.xx + +step = args.step +binaries_location = args.path +# If the binaries location is not given, calculate it from script related dir. +if binaries_location == None: + binaries_location = os.path.join(os.path.dirname(__file__), + os.pardir, os.pardir, os.pardir, 'out', 'Release') + +if not os.path.isabs(binaries_location): + binaries_location = os.path.join(os.getcwd(), binaries_location) + +if not os.path.isdir(binaries_location): + print 'Invalid path: ' + binaries_location exit(-1) - - project_root = tmp - +print 'Working on ' + binaries_location -#get platform information if sys.platform.startswith('linux'): - platform_name = 'linux' - -if sys.platform in ('win32', 'cygwin'): - platform_name = 'win' - -if sys.platform == 'darwin': - platform_name = 'osx' - -#judge whether the target exist or not -if platform_name == 'linux' and not os.path.exists( - os.path.join(project_root, 'nw')): - print 'nw file does not exist.\n' - exit(-1) - -if platform_name == 'win' and not os.path.exists( - os.path.join(project_root, 'nw.exe')): - print 'nw file does not exist.\n' - exit(-1) - -if platform_name == 'osx' and not os.path.exists( - os.path.join(project_root, 'node-webkit.app')): - print 'nw file does not exist.\n' - exit(-1) - -if platform_name != 'win' and not os.path.exists( - os.path.join(project_root, 'chromedriver')): - print 'chromedriver file does not exist.\n' - exit(-1) - -if platform_name == 'win' and not os.path.exists( - os.path.join(project_root, 'chromedriver.exe')): - print 'chromedriver file does not exist.\n' - exit(-1) - - -required_file_linux = ( - 'nw', - 'nw.pak', - 'libffmpegsumo.so', - 'nwsnapshot', - 'credits.html', -) - -required_file_win = ( - 'ffmpegsumo.dll', - 'icudt.dll', - 'libEGL.dll', - 'libGLESv2.dll', - 'nw.exe', - 'nw.pak', - 'nwsnapshot.exe', - 'credits.html', -) - -required_file_mac = ( - 'node-webkit.app', - 'nwsnapshot', - 'credits.html', -) - -required_chromedriver_file_win = ( - 'chromedriver.exe', -) - -required_chromedriver_file_others = ( - 'chromedriver', -) - -if (platform_name == 'linux'): - required_file.append(required_file_linux) - required_file.append(required_chromedriver_file_others) - -if (platform_name == 'win'): - required_file.append(required_file_win) - required_file.append(required_chromedriver_file_win); - -if (platform_name == 'osx'): - required_file.append(required_file_mac) - required_file.append(required_chromedriver_file_others) - - -#generate binary tar name -import getnwisrelease -import getnwversion -import platform - -nw_version = 'v' + getnwversion.nw_version -is_release = getnwisrelease.release -if is_release == 0: - nw_version += getnwisrelease.postfix - -bits = platform.architecture()[0] - -if bits == '64bit': - arch = 'x64' + platform_name = 'linux' +elif sys.platform in ('win32', 'cygwin'): + platform_name = 'win' +elif sys.platform == 'darwin': + platform_name = 'osx' else: - arch = 'ia32' - -if (platform_name == 'win' or platform_name == 'osx'): - arch = 'ia32' - -tarname.append('node-webkit-' + nw_version) -tarname.append('chromedriver-nw-' + nw_version) -for index in range(len(tarname)): - binary_name.append(tarname[index] + '-' + platform_name + '-' + arch); - binary_tar.append(binary_name[index] + '.tar.gz') - -#use zip in mac and windows -if platform_name in ('win', 'osx'): - for index in range(len(binary_name)): - binary_tar[index] = binary_name[index] + '.zip' - - -#make directory for binary_tar -binary_store_path.append(os.path.join(project_root, - 'node-webkit-binaries')) -binary_store_path.append(os.path.join(project_root, - 'chromedriver-binaries')) - -for index in range(len(binary_store_path)): - if not os.path.exists(binary_store_path[index]): - os.mkdir(binary_store_path[index]) - -for index in range(len(binary_store_path)): - binary_full_path.append(os.path.join(binary_store_path[index], binary_name[index])) - binary_tar_full_path.append(os.path.join(binary_store_path[index], binary_tar[index])) - -for index in range(len(binary_full_path)): - if os.path.exists(binary_full_path[index]): - shutil.rmtree(binary_full_path[index]) - -for index in range(len(binary_full_path)): - os.mkdir(binary_full_path[index]) - - -#copy file to binary -print 'Begin copy file.' -for index in range(len(required_file)): - for file in required_file[index]: - try: - shutil.copy(os.path.join(project_root, file), - os.path.join(binary_full_path[index], file)) - except: - shutil.copytree(os.path.join(project_root, file), - os.path.join(binary_full_path[index], file)) - -print 'copy file end.\n' - -for index in range(len(binary_tar_full_path)): - if (os.path.isfile(binary_tar_full_path[index])): - os.remove(binary_tar_full_path[index]) - -print 'Begin compress file' - -if platform_name in ('win', 'osx'): - """ - If there are sub directors, this should be modified - """ - import zipfile - for index in range(len(binary_tar_full_path)): - zip = zipfile.ZipFile(binary_tar_full_path[index], 'w', - compression=zipfile.ZIP_DEFLATED) - - for dirpath, dirnames, filenames in os.walk(binary_full_path[index]): - for name in filenames: - path = os.path.normpath(os.path.join(dirpath, name)) - zip.write(path, path.replace(binary_full_path[index] + os.sep, '')) - - zip.close() + print 'Unsupported platform: ' + sys.platform + exit(-1) +_arch = platform.architecture()[0] +if _arch == '64bit': + arch = 'x64' +elif _arch == '32bit': + arch = 'ia32' else: - for index in range(len(binary_tar_full_path)): - tar = tarfile.open(binary_tar_full_path[index], 'w:gz') - tar.add(binary_full_path[index], os.path.basename(binary_full_path[index])) - tar.close() + print 'Unsupported arch: ' + _arch + exit(-1) - -print 'compress file end.\n' +if platform_name == 'win' or platform_name == 'osx': + arch = 'ia32' + +nw_ver = getnwversion.nw_version +if getnwisrelease.release == 0: + nw_ver += getnwisrelease.postfix + +################################ +# Generate targets +# +# target example: +# { +# 'input' : [ 'nw', 'nw.pak', ... ] +# 'output' : 'node-webkit-v0.9.2-linux-x64' +# 'compress' : 'tar.gz' +# 'folder' : True # Optional. More than 2 files will be put into a seprate folder +# # normally, if you want do to this for only 1 file, set this flag. +# } +def generate_target_nw(platform_name, arch, version): + target = {} + # Output + target['output'] = ''.join([ + 'node-webkit-', + 'v', version, + '-', platform_name, + '-', arch]) + # Compress type + if platform_name == 'linux': + target['compress'] = 'tar.gz' + else: + target['compress'] = 'zip' + # Input + if platform_name == 'linux': + target['input'] = [ + 'credits.html', + 'libffmpegsumo.so', + 'nw.pak', + 'nwsnapshot', + 'nw', + ] + elif platform_name == 'win': + target['input'] = [ + 'ffmpegsumo.dll', + 'icudt.dll', + 'libEGL.dll', + 'libGLESv2.dll', + 'nw.exe', + 'nw.pak', + 'nwsnapshot.exe', + 'credits.html', + ] + elif platform_name == 'osx': + target['input'] = [ + 'node-webkit.app', + 'nwsnapshot', + 'credits.html', + ] + else: + print 'Unsupported platform: ' + platform_name + exit(-1) + return target + +def generate_target_chromedriver(platform_name, arch, version): + target = {} + # Output + target['output'] = ''.join([ + 'chromedriver-nw-', + 'v', version, + '-', platform_name, + '-', arch]) + # Compress type + if platform_name == 'linux': + target['compress'] = 'tar.gz' + else: + target['compress'] = 'zip' + # Input + if platform_name == 'win': + target['input'] = ['chromedriver.exe'] + else: + target['input'] = ['chromedriver'] + target['folder'] = True # always create a folder + return target + +def generate_target_symbols(platform_name, arch, version): + target = {} + target['output'] = ''.join(['node-webkit-symbol-', + 'v', version, + '-', platform_name, + '-', arch]) + if platform_name == 'linux': + target['compress'] = 'tar.gz' + target['input'] = ['nw.breakpad.' + arch] + elif platform_name == 'win': + target['compress'] = 'zip' + target['input'] = ['nw.exe.pdb'] + elif platform_name == 'osx': + target['compress'] = 'tar.gz' + target['input'] = [ + 'node-webkit.app.dSYM', + 'node-webkit Helper.app.dSYM', + 'node-webkit Framework.framework.dSYM', + 'ffmpegsumo.so.dSYM', + ] + else: + print 'Unsupported platform: ' + platform_name + exit(-1) + target['folder'] = True + return target + + +################################ +# Make packages +def compress(from_dir, to_dir, fname, compress): + from_dir = os.path.normpath(from_dir) + to_dir = os.path.normpath(to_dir) + _from = os.path.join(from_dir, fname) + _to = os.path.join(to_dir, fname) + if compress == 'zip': + z = zipfile.ZipFile(_to + '.zip', 'w', compression=zipfile.ZIP_DEFLATED) + if os.path.isdir(_from): + for root, dirs, files in os.walk(_from): + for f in files: + _path = os.path.join(root, f) + z.write(_path, _path.replace(from_dir+os.sep, '')) + else: + z.write(_from, fname) + z.close() + elif compress == 'tar.gz': # only for folders + if not os.path.isdir(_from): + print 'Will not create tar.gz for a single file: ' + _from + exit(-1) + with tarfile.open(_to + '.tar.gz', 'w:gz') as tar: + tar.add(_from, arcname=os.path.basename(_from)) + elif compress == 'gz': # only for single file + if os.path.isdir(_from): + print 'Will not create gz for a folder: ' + _from + exit(-1) + f_in = open(_from, 'rb') + f_out = gzip.open(_to + '.gz', 'wb') + f_out.writelines(f_in) + f_out.close() + f_in.close() + else: + print 'Unsupported compression format: ' + compress + exit(-1) + + +def make_packages(targets): + dist_dir = os.path.join(binaries_location, 'dist') + + # check file existance + for t in targets: + for f in t['input']: + print f + src = os.path.join(binaries_location, f) + if not os.path.exists(src): + print 'File does not exist: ', src + exit(-1) + + # clear the output folder + if os.path.exists(dist_dir): + if not os.path.isdir(dist_dir): + print 'Invalid path: ' + dist_dir + exit(-1) + else: + shutil.rmtree(dist_dir) + + # now let's do it + os.mkdir(dist_dir) + for t in targets: + if (t.has_key('folder') and t['folder'] == True) or len(t['input']) > 1: + # copy files into a folder then pack + folder = os.path.join(dist_dir, t['output']) + os.mkdir(folder) + for f in t['input']: + src = os.path.join(binaries_location, f) + dest = os.path.join(folder, f) + if os.path.isdir(src): # like nw.app + shutil.copytree(src, dest) + else: + shutil.copy(src, dest) + compress(dist_dir, dist_dir, t['output'], t['compress']) + # remove temp folders + shutil.rmtree(folder) + else: + # single file + compress(binaries_location, dist_dir, t['input'][0], t['compress']) + + +################################ +# Process targets +targets = [] +if step == 'nw': + targets.append(generate_target_nw(platform_name, arch, nw_ver)) +elif step == 'chromedriver': + targets.append(generate_target_chromedriver(platform_name, arch, nw_ver)) +elif step == 'symbol': + targets.append(generate_target_symbols(platform_name, arch, nw_ver)) +else: + targets.append(generate_target_nw(platform_name, arch, nw_ver)) + targets.append(generate_target_chromedriver(platform_name, arch, nw_ver)) + targets.append(generate_target_symbols(platform_name, arch, nw_ver)) -for index in range(len(binary_store_path)): - print 'the binaries files store in path:', os.path.normpath( - os.path.join(os.getcwd(), binary_store_path[index])) +make_packages(targets) +# vim: et:ts=4:sw=4 From 66adb902ea381502fb5a3fb8d510ef7bc7b0b463 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 20 May 2014 14:27:32 +0800 Subject: [PATCH 019/492] add App.addOriginAccessWhitelistEntry & App.removeOriginAccessWhitelistEntry Fix #1016; Fix #1514 --- src/api/app/app.js | 8 ++++++++ src/api/dispatcher_bindings.cc | 28 ++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+) diff --git a/src/api/app/app.js b/src/api/app/app.js index bb61d736b5..b78410e570 100644 --- a/src/api/app/app.js +++ b/src/api/app/app.js @@ -60,6 +60,14 @@ App.prototype.getProxyForURL = function (url) { return nw.callStaticMethodSync('App', 'getProxyForURL', [ url ]); } +App.prototype.addOriginAccessWhitelistEntry = function(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains) { + return nw.callStaticMethodSync('App', 'AddOriginAccessWhitelistEntry', sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains); +} + +App.prototype.removeOriginAccessWhitelistEntry = function(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains) { + return nw.callStaticMethodSync('App', 'RemoveOriginAccessWhitelistEntry', sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains); +} + App.prototype.__defineGetter__('argv', function() { if (!argv) { var fullArgv = this.fullArgv; diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 84697ce400..14110a94a9 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -33,6 +33,8 @@ #include "content/public/renderer/render_thread.h" #include "content/public/renderer/v8_value_converter.h" #include "grit/nw_resources.h" +#include "third_party/WebKit/public/web/WebSecurityPolicy.h" +#include "url/gurl.h" using content::RenderView; using content::V8ValueConverter; @@ -449,6 +451,32 @@ void DispatcherBindings::CallStaticMethodSync( return; } + if (type == "App" && method == "AddOriginAccessWhitelistEntry") { + std::string sourceOrigin = *v8::String::Utf8Value(args[2]); + std::string destinationProtocol = *v8::String::Utf8Value(args[3]); + std::string destinationHost = *v8::String::Utf8Value(args[4]); + bool allowDestinationSubdomains = args[5]->ToBoolean()->Value(); + + WebKit::WebSecurityPolicy::addOriginAccessWhitelistEntry(GURL(sourceOrigin), + WebKit::WebString::fromUTF8(destinationProtocol), + WebKit::WebString::fromUTF8(destinationHost), + allowDestinationSubdomains); + args.GetReturnValue().Set(v8::Undefined()); + return; + } + if (type == "App" && method == "RemoveOriginAccessWhitelistEntry") { + std::string sourceOrigin = *v8::String::Utf8Value(args[2]); + std::string destinationProtocol = *v8::String::Utf8Value(args[3]); + std::string destinationHost = *v8::String::Utf8Value(args[4]); + bool allowDestinationSubdomains = args[5]->ToBoolean()->Value(); + + WebKit::WebSecurityPolicy::removeOriginAccessWhitelistEntry(GURL(sourceOrigin), + WebKit::WebString::fromUTF8(destinationProtocol), + WebKit::WebString::fromUTF8(destinationHost), + allowDestinationSubdomains); + args.GetReturnValue().Set(v8::Undefined()); + return; + } scoped_ptr value_args( converter->FromV8Value(args[2], v8::Context::GetCurrent())); if (!value_args.get() || From 6c9a0de6d0cc6023ff710626de2e0635997c47c5 Mon Sep 17 00:00:00 2001 From: libm Date: Tue, 20 May 2014 16:01:23 +0800 Subject: [PATCH 020/492] Added aws upload support --- tools/package_binaries.py | 59 +++++++++++++++++++++++++++++++++++---- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 2716a1638d..4bb9fca0ff 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -13,8 +13,18 @@ ################################ # Parse command line args parser = argparse.ArgumentParser(description='Package nw binaries.') -parser.add_argument('-p','--path',help='Where to find the binaries, like out/Release', required=False) -parser.add_argument('-s','--step',help='Execute specified step. (could be "nw", "chromedriver" or "symbol")', required=False) +parser.add_argument('-p','--path', help='Where to find the binaries, like out/Release', required=False) +parser.add_argument('-s','--step', help='Execute specified step. (could be "nw", "chromedriver" or "symbol")', required=False) +# AWS uploader args +# Example: package_binaries.py -u -b linux_32bit -r 123 -n 99 -t my_bucket -i -k +parser.add_argument('-u','--upload', help='Run aws uploader', action='store_true', required=False) +parser.add_argument('-b','--buildername', help='Builder name', required=False) +parser.add_argument('-r','--revision', help='Build revision',required=False) +parser.add_argument('-n','--number', help='Build number', required=False) +parser.add_argument('-t','--bucket', help='AWS bucket name', required=False) +parser.add_argument('-i','--awsid', help='AWS_ACCESS_KEY_ID', required=False) +parser.add_argument('-k','--awskey', help='AWS_SECRET_ACCESS_KEY', required=False) + args = parser.parse_args() ################################ @@ -24,6 +34,7 @@ arch = None # ia32/x64 step = None # nw/chromedriver/symbol nw_ver = None # x.xx +dist_dir = None # .../out/Release/dist step = args.step binaries_location = args.path @@ -38,6 +49,8 @@ if not os.path.isdir(binaries_location): print 'Invalid path: ' + binaries_location exit(-1) +binaries_location = os.path.normpath(binaries_location) +dist_dir = os.path.join(binaries_location, 'dist') print 'Working on ' + binaries_location @@ -208,12 +221,10 @@ def compress(from_dir, to_dir, fname, compress): def make_packages(targets): - dist_dir = os.path.join(binaries_location, 'dist') # check file existance for t in targets: for f in t['input']: - print f src = os.path.join(binaries_location, f) if not os.path.exists(src): print 'File does not exist: ', src @@ -230,6 +241,7 @@ def make_packages(targets): # now let's do it os.mkdir(dist_dir) for t in targets: + print 'Making "' + t['output'] + '.' + t['compress'] + '"' if (t.has_key('folder') and t['folder'] == True) or len(t['input']) > 1: # copy files into a folder then pack folder = os.path.join(dist_dir, t['output']) @@ -263,7 +275,44 @@ def make_packages(targets): targets.append(generate_target_chromedriver(platform_name, arch, nw_ver)) targets.append(generate_target_symbols(platform_name, arch, nw_ver)) -make_packages(targets) +if args.upload != True: + print 'Creating packages...' + make_packages(targets) + exit(0) +################################################################ +# aws uploader + +from datetime import date + +print 'Starting aws uploader...' + +# Init variables +builder_name = args.buildername +got_revision = args.revision +build_number = args.number +bucket_name = args.bucket +awsid = args.awsid +awskey = args.awskey +date = date.today().strftime('%m-%d-%y') + +upload_path = ''.join(['/' + date, + '/' + builder_name + '-build-' + build_number + '-' + got_revision]) + +print 'Upload path: ' + upload_path +file_list = os.listdir(dist_dir) +if len(file_list) == 0: + print 'Cannot find packages!' + exit(-1) + +import boto +conn = boto.connect_s3(awsid, awskey) +bucket = conn.get_bucket(bucket_name) +for f in file_list: + print 'Uploading "' + f + '" ...' + key = bucket.new_key(os.path.join(upload_path, f)) + key.set_contents_from_filename(os.path.join(dist_dir, f)) + +print 'Done.' # vim: et:ts=4:sw=4 From a64c2157ca73f7e463e0e23958f96292abfa7cc8 Mon Sep 17 00:00:00 2001 From: libm Date: Tue, 20 May 2014 21:10:15 +0800 Subject: [PATCH 021/492] Added progress indicator for aws uploading --- tools/package_binaries.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 4bb9fca0ff..3ff859ee27 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -307,10 +307,14 @@ def make_packages(targets): import boto conn = boto.connect_s3(awsid, awskey) bucket = conn.get_bucket(bucket_name) + +def print_progress(transmitted, total): + print ' %d%% transferred of total: %d bytes.' % (transmitted*100/total, total) + for f in file_list: print 'Uploading "' + f + '" ...' key = bucket.new_key(os.path.join(upload_path, f)) - key.set_contents_from_filename(os.path.join(dist_dir, f)) + key.set_contents_from_filename(filename=os.path.join(dist_dir, f), cb=print_progress, num_cb=20, replace=True) print 'Done.' From 13099909554994eb4ba1d84452a23949f3b8fb69 Mon Sep 17 00:00:00 2001 From: libm Date: Wed, 21 May 2014 10:14:23 +0800 Subject: [PATCH 022/492] Better to store aws key in a separate config file. --- tools/package_binaries.py | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 3ff859ee27..ee735c739b 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -22,8 +22,8 @@ parser.add_argument('-r','--revision', help='Build revision',required=False) parser.add_argument('-n','--number', help='Build number', required=False) parser.add_argument('-t','--bucket', help='AWS bucket name', required=False) -parser.add_argument('-i','--awsid', help='AWS_ACCESS_KEY_ID', required=False) -parser.add_argument('-k','--awskey', help='AWS_SECRET_ACCESS_KEY', required=False) +# example file content: {"awsid":"ABCDEF","awskey":"123456"} +parser.add_argument('-k','--keyfile', help='JSNO file containing AWS access id and key', required=False) args = parser.parse_args() @@ -291,10 +291,20 @@ def make_packages(targets): got_revision = args.revision build_number = args.number bucket_name = args.bucket -awsid = args.awsid -awskey = args.awskey +keyfile = args.keyfile date = date.today().strftime('%m-%d-%y') +# Check aws keyfile +if not os.path.exists(keyfile): + print "Cannot find aws key file" + exit(-1) + +import json +json_data = open(keyfile) +data = json.load(json_data) +awsid = data['awsid'] +awskey = data['awskey'] + upload_path = ''.join(['/' + date, '/' + builder_name + '-build-' + build_number + '-' + got_revision]) From 0448be611575ff00833007846fcb1292df6ff5f2 Mon Sep 17 00:00:00 2001 From: libm Date: Wed, 21 May 2014 11:06:12 +0800 Subject: [PATCH 023/492] dump symbols before stripping the nw binary --- nw.gypi | 55 ++++++++++++++++++++++++++----------------------------- 1 file changed, 26 insertions(+), 29 deletions(-) diff --git a/nw.gypi b/nw.gypi index 95e80119a6..f104043a85 100644 --- a/nw.gypi +++ b/nw.gypi @@ -562,27 +562,6 @@ }, ], }, - { - 'target_name': 'strip', - 'type': 'none', - 'actions': [ - { - 'action_name': 'strip_nw_binaries', - 'inputs': [ - '<(PRODUCT_DIR)/nw', - ], - 'outputs': [ - '<(PRODUCT_DIR)/strip_nw.stamp', - ], - 'action': ['strip', - '<@(_inputs)'], - 'message': 'Stripping release executable', - }, - ], - 'dependencies': [ - 'nw', - ], - }, { 'target_name': 'nw_symbols', 'type': 'none', @@ -615,6 +594,31 @@ }], ], }, + { + 'target_name': 'strip', + 'type': 'none', + 'conditions': [ + ['OS=="linux"', { + 'actions': [ + { + 'action_name': 'strip_nw_binaries', + 'inputs': [ + '<(PRODUCT_DIR)/nw', + ], + 'outputs': [ + '<(PRODUCT_DIR)/strip_nw.stamp', + ], + 'action': ['strip', + '<@(_inputs)'], + 'message': 'Stripping release executable', + }, + ], + }], + ], + 'dependencies': [ + 'nw_symbols', + ], + }, { 'target_name': 'dist', 'type': 'none', @@ -635,14 +639,7 @@ ], 'dependencies': [ '<(DEPTH)/chrome/chrome.gyp:chromedriver', - 'nw_symbols', - ], - 'conditions': [ - ['OS == "linux"', { - 'dependencies': [ - 'strip', - ], - }], + 'strip', ], }, { From ad11ea2c796b45484d6040a15a408151ee5ed5ca Mon Sep 17 00:00:00 2001 From: libm Date: Wed, 21 May 2014 12:26:34 +0800 Subject: [PATCH 024/492] Split out aws uploader. Since the uploader is growing big and not very much related to what the package_binaries.py is doing, let's split it out. --- tools/aws_uploader.py | 87 +++++++++++++++++++++++++++++++++++++++ tools/package_binaries.py | 65 +---------------------------- 2 files changed, 89 insertions(+), 63 deletions(-) create mode 100755 tools/aws_uploader.py diff --git a/tools/aws_uploader.py b/tools/aws_uploader.py new file mode 100755 index 0000000000..9ea2a13168 --- /dev/null +++ b/tools/aws_uploader.py @@ -0,0 +1,87 @@ +#!/usr/bin/env python +import argparse +import boto +import datetime +import json +import os + +################################ +# Parse command line args +parser = argparse.ArgumentParser(description='AWS uploader.') +parser.add_argument('-p','--path', help='Optional. Where to find the binaries, normally out/Release/dist', required=False) +parser.add_argument('-b','--buildername', help='Builder name, e.g. linux_32bit', required=True) +parser.add_argument('-r','--revision', help='Commit revision',required=True) +parser.add_argument('-n','--number', help='Build number', required=True) +parser.add_argument('-t','--bucket', help='AWS bucket name', required=True) +parser.add_argument('-k','--keyfile', help='Optional. JSON file containing AWS access id and key, default: ~/.awskey; ' +\ + 'The content of the key file is like {"awsid":"ABCDEF","awskey":"123456"}', required=False) + +args = parser.parse_args() + +################################ +# Check and init variables +dist_dir = args.path +builder_name = args.buildername +got_revision = args.revision +build_number = args.number +bucket_name = args.bucket +keyfile = args.keyfile +date = datetime.date.today().strftime('%m-%d-%Y') + +# If the binaries location is not given, calculate it from script related dir. +if dist_dir == None: + dist_dir = os.path.join(os.path.dirname(__file__), + os.pardir, os.pardir, os.pardir, 'out', 'Release', 'dist') + +if not os.path.isabs(dist_dir): + dist_dir = os.path.join(os.getcwd(), dist_dir) + +if not os.path.isdir(dist_dir): + print 'Invalid path: ' + dist_dir + exit(-1) +dist_dir = os.path.normpath(dist_dir) + +# Check aws keyfile +if keyfile == None: + keyfile = os.path.join(os.getenv('HOME'),'.awskey') + print keyfile +if not os.path.exists(keyfile): + print "Cannot find aws key file" + exit(-1) + +json_data = open(keyfile) +data = json.load(json_data) +if not (data.has_key('awsid') and data.has_key('awskey')): + print "Invalid key file format." + exit(-1) +awsid = data['awsid'] +awskey = data['awskey'] + +upload_path = ''.join(['/' + date, + '/' + builder_name + '-build-' + build_number + '-' + got_revision]) + +file_list = os.listdir(dist_dir) +if len(file_list) == 0: + print 'Cannot find packages!' + exit(-1) + + +def print_progress(transmitted, total): + print ' %d%% transferred of total: %d bytes.' % (transmitted*100/total, total) + + +def aws_upload(upload_path, file_list): + conn = boto.connect_s3(awsid, awskey) + print 'Connecting to S3 ...' + bucket = conn.get_bucket(bucket_name) + print 'Uploading to: ' + upload_path + for f in file_list: + print 'Uploading "' + f + '" ...' + key = bucket.new_key(os.path.join(upload_path, f)) + key.set_contents_from_filename(filename=os.path.join(dist_dir, f), cb=print_progress, num_cb=20, replace=True) + +aws_upload(upload_path, file_list) +print 'Done.' + + +# vim: et:ts=4:sw=4 diff --git a/tools/package_binaries.py b/tools/package_binaries.py index ee735c739b..9b971da236 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -15,16 +15,6 @@ parser = argparse.ArgumentParser(description='Package nw binaries.') parser.add_argument('-p','--path', help='Where to find the binaries, like out/Release', required=False) parser.add_argument('-s','--step', help='Execute specified step. (could be "nw", "chromedriver" or "symbol")', required=False) -# AWS uploader args -# Example: package_binaries.py -u -b linux_32bit -r 123 -n 99 -t my_bucket -i -k -parser.add_argument('-u','--upload', help='Run aws uploader', action='store_true', required=False) -parser.add_argument('-b','--buildername', help='Builder name', required=False) -parser.add_argument('-r','--revision', help='Build revision',required=False) -parser.add_argument('-n','--number', help='Build number', required=False) -parser.add_argument('-t','--bucket', help='AWS bucket name', required=False) -# example file content: {"awsid":"ABCDEF","awskey":"123456"} -parser.add_argument('-k','--keyfile', help='JSNO file containing AWS access id and key', required=False) - args = parser.parse_args() ################################ @@ -275,58 +265,7 @@ def make_packages(targets): targets.append(generate_target_chromedriver(platform_name, arch, nw_ver)) targets.append(generate_target_symbols(platform_name, arch, nw_ver)) -if args.upload != True: - print 'Creating packages...' - make_packages(targets) - exit(0) -################################################################ -# aws uploader - -from datetime import date - -print 'Starting aws uploader...' - -# Init variables -builder_name = args.buildername -got_revision = args.revision -build_number = args.number -bucket_name = args.bucket -keyfile = args.keyfile -date = date.today().strftime('%m-%d-%y') - -# Check aws keyfile -if not os.path.exists(keyfile): - print "Cannot find aws key file" - exit(-1) - -import json -json_data = open(keyfile) -data = json.load(json_data) -awsid = data['awsid'] -awskey = data['awskey'] - -upload_path = ''.join(['/' + date, - '/' + builder_name + '-build-' + build_number + '-' + got_revision]) - -print 'Upload path: ' + upload_path -file_list = os.listdir(dist_dir) -if len(file_list) == 0: - print 'Cannot find packages!' - exit(-1) - -import boto -conn = boto.connect_s3(awsid, awskey) -bucket = conn.get_bucket(bucket_name) - -def print_progress(transmitted, total): - print ' %d%% transferred of total: %d bytes.' % (transmitted*100/total, total) - -for f in file_list: - print 'Uploading "' + f + '" ...' - key = bucket.new_key(os.path.join(upload_path, f)) - key.set_contents_from_filename(filename=os.path.join(dist_dir, f), cb=print_progress, num_cb=20, replace=True) - -print 'Done.' - +print 'Creating packages...' +make_packages(targets) # vim: et:ts=4:sw=4 From d64ab9351f7f6bcb7f62060c784babd25b8667c6 Mon Sep 17 00:00:00 2001 From: libm Date: Wed, 21 May 2014 13:10:59 +0800 Subject: [PATCH 025/492] Fix: cannot get HOME env in windows. --- tools/aws_uploader.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/aws_uploader.py b/tools/aws_uploader.py index 9ea2a13168..7e488b8c3c 100755 --- a/tools/aws_uploader.py +++ b/tools/aws_uploader.py @@ -43,7 +43,7 @@ # Check aws keyfile if keyfile == None: - keyfile = os.path.join(os.getenv('HOME'),'.awskey') + keyfile = os.path.join(os.path.expanduser('~'),'.awskey') print keyfile if not os.path.exists(keyfile): print "Cannot find aws key file" @@ -78,7 +78,7 @@ def aws_upload(upload_path, file_list): for f in file_list: print 'Uploading "' + f + '" ...' key = bucket.new_key(os.path.join(upload_path, f)) - key.set_contents_from_filename(filename=os.path.join(dist_dir, f), cb=print_progress, num_cb=20, replace=True) + key.set_contents_from_filename(filename=os.path.join(dist_dir, f), cb=print_progress, num_cb=50, replace=True) aws_upload(upload_path, file_list) print 'Done.' From 658cacef1a1d934ed5c5d32a4af41fe4802698e8 Mon Sep 17 00:00:00 2001 From: libm Date: Wed, 21 May 2014 13:20:52 +0800 Subject: [PATCH 026/492] Add myself into AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index d334c270bd..5f3166c6a4 100644 --- a/AUTHORS +++ b/AUTHORS @@ -24,3 +24,4 @@ Zhao Zeyi (richardcypher) Fabrice Weinberg Lv Kaiyang Lukas Benes +Lithare Emileit From ead1979d7a8e8c8d1c10700b9c3c6b439d74fb3f Mon Sep 17 00:00:00 2001 From: libm Date: Wed, 21 May 2014 13:46:43 +0800 Subject: [PATCH 027/492] Always use slash for s3 path --- tools/aws_uploader.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/aws_uploader.py b/tools/aws_uploader.py index 7e488b8c3c..3bd537a6ea 100755 --- a/tools/aws_uploader.py +++ b/tools/aws_uploader.py @@ -57,6 +57,7 @@ awsid = data['awsid'] awskey = data['awskey'] +# it's for S3, so always use '/' here upload_path = ''.join(['/' + date, '/' + builder_name + '-build-' + build_number + '-' + got_revision]) @@ -77,7 +78,8 @@ def aws_upload(upload_path, file_list): print 'Uploading to: ' + upload_path for f in file_list: print 'Uploading "' + f + '" ...' - key = bucket.new_key(os.path.join(upload_path, f)) + # use '/' for s3 + key = bucket.new_key(upload_path + '/' + f) key.set_contents_from_filename(filename=os.path.join(dist_dir, f), cb=print_progress, num_cb=50, replace=True) aws_upload(upload_path, file_list) From 1cb8193cb71b4ed8b1b6591335908d9e2d14a0ce Mon Sep 17 00:00:00 2001 From: libm Date: Wed, 21 May 2014 16:29:27 +0800 Subject: [PATCH 028/492] Strip and keep the timestamp. --- nw.gypi | 12 ++++++++++-- tools/strip.sh | 4 ++++ 2 files changed, 14 insertions(+), 2 deletions(-) create mode 100755 tools/strip.sh diff --git a/nw.gypi b/nw.gypi index f104043a85..36b0aca632 100644 --- a/nw.gypi +++ b/nw.gypi @@ -608,7 +608,8 @@ 'outputs': [ '<(PRODUCT_DIR)/strip_nw.stamp', ], - 'action': ['strip', + 'action': ['sh', '<(DEPTH)/content/nw/tools/strip.sh', + '<@(_outputs)', '<@(_inputs)'], 'message': 'Stripping release executable', }, @@ -639,7 +640,14 @@ ], 'dependencies': [ '<(DEPTH)/chrome/chrome.gyp:chromedriver', - 'strip', + 'nw_symbols', + ], + 'conditions': [ + ['OS == "linux"', { + 'dependencies': [ + 'strip', + ], + }], ], }, { diff --git a/tools/strip.sh b/tools/strip.sh new file mode 100755 index 0000000000..a19adf50b0 --- /dev/null +++ b/tools/strip.sh @@ -0,0 +1,4 @@ +#!/bin/sh +touch -r $2 $1 +strip $2 +touch -r $1 $2 From ecd464c7b49f451962e24194397a5e44d72019a6 Mon Sep 17 00:00:00 2001 From: libm Date: Thu, 22 May 2014 12:00:51 +0800 Subject: [PATCH 029/492] Updated symbol generation and strip process. Use the upstream's script (with a minor fix) to generate symbol and strip nw binary in the mean time. Since everything is built under '-g' (common.gyp:linux_dump_symbols=1), the chromedriver and nwsnapshot should also be stripped. --- nw.gypi | 35 ++++++++++++++++++++--------------- tools/dump_app_syms | 43 +++++++++++++++++++++++++++++++++++++++++++ tools/strip.sh | 4 ---- 3 files changed, 63 insertions(+), 19 deletions(-) create mode 100644 tools/dump_app_syms delete mode 100755 tools/strip.sh diff --git a/nw.gypi b/nw.gypi index 36b0aca632..b158b0f1e1 100644 --- a/nw.gypi +++ b/nw.gypi @@ -563,22 +563,25 @@ ], }, { - 'target_name': 'nw_symbols', + 'target_name': 'nw_strip_symbol', 'type': 'none', 'conditions': [ ['OS=="linux"', { + 'variables': { + 'linux_strip_binary': 1, + }, 'actions': [ { - 'action_name': 'dump_symbols', + 'action_name': 'dump_symbol_and_strip', 'inputs': [ - '<(DEPTH)/build/linux/dump_app_syms', + '<(DEPTH)/content/nw/tools/dump_app_syms', '<(PRODUCT_DIR)/dump_syms', '<(PRODUCT_DIR)/nw', ], 'outputs': [ '<(PRODUCT_DIR)/nw.breakpad.<(target_arch)', ], - 'action': ['<(DEPTH)/build/linux/dump_app_syms', + 'action': ['<(DEPTH)/content/nw/tools/dump_app_syms', '<(PRODUCT_DIR)/dump_syms', '<(linux_strip_binary)', '<(PRODUCT_DIR)/nw', @@ -595,7 +598,7 @@ ], }, { - 'target_name': 'strip', + 'target_name': 'strip_binaries', 'type': 'none', 'conditions': [ ['OS=="linux"', { @@ -603,22 +606,23 @@ { 'action_name': 'strip_nw_binaries', 'inputs': [ - '<(PRODUCT_DIR)/nw', + '<(PRODUCT_DIR)/nwsnapshot', + '<(PRODUCT_DIR)/chromedriver', ], 'outputs': [ - '<(PRODUCT_DIR)/strip_nw.stamp', + '<(PRODUCT_DIR)/strip_binaries.stamp', ], - 'action': ['sh', '<(DEPTH)/content/nw/tools/strip.sh', - '<@(_outputs)', + 'action': ['strip', '<@(_inputs)'], - 'message': 'Stripping release executable', + 'message': 'Stripping release binaries', }, ], + 'dependencies': [ + '<(DEPTH)/v8/tools/gyp/v8.gyp:nwsnapshot', + '<(DEPTH)/chrome/chrome.gyp:chromedriver', + ], }], ], - 'dependencies': [ - 'nw_symbols', - ], }, { 'target_name': 'dist', @@ -640,12 +644,12 @@ ], 'dependencies': [ '<(DEPTH)/chrome/chrome.gyp:chromedriver', - 'nw_symbols', + 'nw_strip_symbol', ], 'conditions': [ ['OS == "linux"', { 'dependencies': [ - 'strip', + 'strip_binaries', ], }], ], @@ -960,3 +964,4 @@ }], # OS=="mac" ] # conditions } + diff --git a/tools/dump_app_syms b/tools/dump_app_syms new file mode 100644 index 0000000000..11bf0e62ed --- /dev/null +++ b/tools/dump_app_syms @@ -0,0 +1,43 @@ +#!/bin/sh + +# Copyright (c) 2010 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. +# +# Helper script to run dump_syms on Chrome Linux executables and strip +# them if needed. + +set -e + +usage() { + echo -n "$0 " >&2 + echo " " >&2 +} + + +if [ $# -ne 4 ]; then + usage + exit 1 +fi + +SCRIPTDIR="$(readlink -f "$(dirname "$0")")" +DUMPSYMS="$1" +STRIP_BINARY="$2" +INFILE="$3" +OUTFILE="$4" + +# Dump the symbols from the given binary. +if [ ! -e "$OUTFILE" -o "$INFILE" -nt "$OUTFILE" ]; then +echo "bb" + "$DUMPSYMS" -r "$INFILE" > "$OUTFILE" +fi + +if [ "$STRIP_BINARY" != "0" ]; then + strip "$INFILE" +# To avoid dumpping twice. +echo "aa" + touch "$OUTFILE" +fi + + + diff --git a/tools/strip.sh b/tools/strip.sh deleted file mode 100755 index a19adf50b0..0000000000 --- a/tools/strip.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/sh -touch -r $2 $1 -strip $2 -touch -r $1 $2 From bca612100add59fd752607db2091498a1009f02d Mon Sep 17 00:00:00 2001 From: libm Date: Thu, 22 May 2014 13:08:06 +0800 Subject: [PATCH 030/492] make dump_app_syms executable --- tools/dump_app_syms | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 tools/dump_app_syms diff --git a/tools/dump_app_syms b/tools/dump_app_syms old mode 100644 new mode 100755 From 860cbada4180b2f3e0fbe56a6bb07b00a70d2b74 Mon Sep 17 00:00:00 2001 From: tinyproxy Date: Fri, 16 May 2014 13:23:32 +0800 Subject: [PATCH 031/492] Port menu shortcut. But super and meta modifier does not work yet. --- src/api/menu/menu.h | 12 ++- src/api/menu/menu_win.cc | 22 +++++ src/api/menuitem/menuitem.h | 27 ++++++ src/api/menuitem/menuitem_win.cc | 151 +++++++++++++++++++++++++++++++ src/browser/native_window_win.cc | 24 ++++- src/browser/native_window_win.h | 16 +++- 6 files changed, 247 insertions(+), 5 deletions(-) diff --git a/src/api/menu/menu.h b/src/api/menu/menu.h index 4edbea6c36..fb319c6c1f 100644 --- a/src/api/menu/menu.h +++ b/src/api/menu/menu.h @@ -48,7 +48,7 @@ class NativeWindowGtk; #include "content/nw/src/api/menu/menu_delegate_win.h" #include "ui/views/controls/menu/native_menu_win.h" #include "chrome/browser/status_icons/status_icon_menu_model.h" - +#include "ui/views/focus/focus_manager.h" namespace nw { class NativeWindowWin; } @@ -92,6 +92,10 @@ class Menu : public Base { #if defined(OS_LINUX) void UpdateKeys(GtkAccelGroup *gtk_accel_group); #endif + +#if defined(OS_WIN) + void UpdateKeys(views::FocusManager *focus_manager); +#endif private: friend class MenuItem; @@ -110,7 +114,6 @@ class Menu : public Base { GtkAccelGroup *gtk_accel_group; #endif - #if defined(OS_MACOSX) friend class nw::NativeWindowCocoa; NSMenu* menu_; @@ -122,6 +125,11 @@ class Menu : public Base { void Rebuild(const HMENU *parent_menu = NULL); + //**Never Try to free this pointer** + //We get it from top widget + views::FocusManager *focus_manager_; + std::vector menu_items_; + // Flag to indicate the menu has been modified since last show, so we should // rebuild the menu before next show. bool is_menu_modified_; diff --git a/src/api/menu/menu_win.cc b/src/api/menu/menu_win.cc index b943de7912..976b3f0bd3 100644 --- a/src/api/menu/menu_win.cc +++ b/src/api/menu/menu_win.cc @@ -33,6 +33,9 @@ #include "ui/views/controls/menu/menu_2.h" #include "ui/views/widget/widget.h" +#include "ui/views/focus/focus_manager.h" +#include "vector" + namespace { HBITMAP GetNativeBitmapFromSkBitmap(const SkBitmap& bitmap) { @@ -84,9 +87,12 @@ void Menu::Create(const base::DictionaryValue& option) { menu_model_.reset(new ui::NwMenuModel(menu_delegate_.get())); menu_.reset(new views::NativeMenuWin(menu_model_.get(), NULL)); + focus_manager_ = NULL; + std::string type; if (option.GetString("type", &type) && type == "menubar") menu_->set_is_popup_menu(false); + menu_items_.empty(); } void Menu::Destroy() { @@ -107,6 +113,7 @@ void Menu::Append(MenuItem* menu_item) { menu_model_->AddSeparator(ui::NORMAL_SEPARATOR); is_menu_modified_ = true; + menu_items_.push_back(menu_item); } void Menu::Insert(MenuItem* menu_item, int pos) { @@ -185,4 +192,19 @@ void Menu::Rebuild(const HMENU *parent_menu) { } } +void Menu::UpdateKeys(views::FocusManager *focus_manager){ + if (focus_manager == NULL){ + return ; + } else { + focus_manager_ = focus_manager; + std::vector::iterator it = menu_items_.begin(); + while(it!=menu_items_.end()){ + (*it)->UpdateKeys(focus_manager); + ++it; + } + } +} + + + } // namespace nwapi diff --git a/src/api/menuitem/menuitem.h b/src/api/menuitem/menuitem.h index 48a8a82682..44765f5b1d 100644 --- a/src/api/menuitem/menuitem.h +++ b/src/api/menuitem/menuitem.h @@ -40,13 +40,20 @@ class MenuItemDelegate; #elif defined(OS_WIN) #include "base/strings/string16.h" #include "ui/gfx/image/image.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/views/focus/focus_manager.h" #endif // defined(OS_MACOSX) namespace nwapi { class Menu; +#if defined(OS_WIN) +class MenuItem : public Base , + public ui::AcceleratorTarget { +#else class MenuItem : public Base { +#endif public: MenuItem(int id, const base::WeakPtr& dispatcher_host, @@ -59,6 +66,17 @@ class MenuItem : public Base { #if defined(OS_LINUX) void UpdateKeys(GtkAccelGroup *gtk_accel_group); #endif + +#if defined(OS_WIN) + virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE{ + OnClick(); + return true; + } + virtual bool CanHandleAccelerators() const OVERRIDE { + return true; + } + void UpdateKeys(views::FocusManager *focus_manager); +#endif #if defined(OS_MACOSX) || defined(OS_WIN) void OnClick(); @@ -102,6 +120,13 @@ class MenuItem : public Base { #elif defined(OS_WIN) friend class MenuDelegate; + //**Never Try to free this pointer** + //We get it from top widget + views::FocusManager *focus_manager_; + + ui::Accelerator accelerator_; + + // Flag to indicate we need refresh. bool is_modified_; @@ -113,6 +138,8 @@ class MenuItem : public Base { string16 label_; string16 tooltip_; Menu* submenu_; + bool enable_shortcut_; + #endif DISALLOW_COPY_AND_ASSIGN(MenuItem); diff --git a/src/api/menuitem/menuitem_win.cc b/src/api/menuitem/menuitem_win.cc index 73cbb05bf6..6d0e81072e 100644 --- a/src/api/menuitem/menuitem_win.cc +++ b/src/api/menuitem/menuitem_win.cc @@ -27,6 +27,11 @@ #include "content/nw/src/api/menu/menu.h" #include "content/nw/src/nw_package.h" #include "content/nw/src/nw_shell.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/events/event_constants.h"//for modifier key code +#include "ui/events/keycodes/keyboard_codes.h"//for keycode + +ui::KeyboardCode GetKeycodeFromText(std::string text); namespace nwapi { @@ -37,12 +42,49 @@ void MenuItem::Create(const base::DictionaryValue& option) { type_ = "normal"; submenu_ = NULL; + focus_manager_ = NULL; + option.GetString("type", &type_); option.GetString("label", &label_); option.GetString("tooltip", &tooltip_); option.GetBoolean("checked", &is_checked_); option.GetBoolean("enabled", &is_enabled_); + std::string key; + std::string modifiers; + option.GetString("key",&key); + option.GetString("modifiers",&modifiers); + + ui::KeyboardCode keyval = ui::VKEY_UNKNOWN; + + + if (key.size() == 0){ + enable_shortcut_ = false; + } else { + enable_shortcut_ = true; + keyval = ::GetKeycodeFromText(key); + } + + //only code for ctrl, shift, alt, super and meta modifiers + int modifiers_value = ui::EF_NONE; + if (modifiers.find("ctrl")!=std::string::npos){ + modifiers_value = modifiers_value | ui::EF_CONTROL_DOWN; + } + if (modifiers.find("shift")!=std::string::npos){ + modifiers_value = modifiers_value | ui::EF_SHIFT_DOWN ; + } + if (modifiers.find("alt")!=std::string::npos){ + modifiers_value = modifiers_value | ui::EF_ALT_DOWN; + } + if (modifiers.find("super")!=std::string::npos){ + modifiers_value = modifiers_value | ui::EF_COMMAND_DOWN; + } + if (modifiers.find("meta")!=std::string::npos){ + modifiers_value = modifiers_value | ui::EF_EXTENDED; + } + accelerator_ = ui::Accelerator(keyval,modifiers_value); + + std::string icon; if (option.GetString("icon", &icon) && !icon.empty()) SetIcon(icon); @@ -99,4 +141,113 @@ void MenuItem::SetSubmenu(Menu* menu) { submenu_ = menu; } +void MenuItem::UpdateKeys(views::FocusManager *focus_manager){ + if (focus_manager == NULL){ + return ; + } else { + focus_manager_ = focus_manager; + if (enable_shortcut_){ + focus_manager->RegisterAccelerator( + accelerator_, + ui::AcceleratorManager::kHighPriority, + this); + } + if (submenu_ != NULL){ + submenu_->UpdateKeys(focus_manager); + } + } +} + } // namespace nwapi + + + +ui::KeyboardCode GetKeycodeFromText(std::string text){ + ui::KeyboardCode retval = ui::VKEY_UNKNOWN; + if (text.size() != 0){ + for (unsigned int i=0;i='0' && key<='9'){//handle digital + retval = (ui::KeyboardCode)(ui::VKEY_0 + key - '0'); + } else if (key>='A'&&key<='Z'){//handle alphabet + retval = (ui::KeyboardCode)(ui::VKEY_A + key - 'A'); + } else if (key == '`'){//handle all special symbols + retval = ui::VKEY_OEM_3; + } else if (key == ','){ + retval = ui::VKEY_OEM_COMMA; + } else if (key == '.'){ + retval = ui::VKEY_OEM_PERIOD; + } else if (key == '/'){ + retval = ui::VKEY_OEM_2; + } else if (key == ';'){ + retval = ui::VKEY_OEM_1; + } else if (key == '\''){ + retval = ui::VKEY_OEM_7; + } else if (key == '['){ + retval = ui::VKEY_OEM_4; + } else if (key == ']'){ + retval = ui::VKEY_OEM_6; + } else if (key == '\\'){ + retval = ui::VKEY_OEM_5; + } else if (key == '-'){ + retval = ui::VKEY_OEM_MINUS; + } else if (key == '='){ + retval = ui::VKEY_OEM_PLUS; + } + } else {//handle long key name + if (!text.compare("ESC")){ + retval = ui::VKEY_ESCAPE; + } else if (!text.compare("BACKSPACE")){ + retval = ui::VKEY_BACK; + } else if (!text.compare("F1")){ + retval = ui::VKEY_F1; + } else if (!text.compare("F2")){ + retval = ui::VKEY_F2; + } else if (!text.compare("F3")){ + retval = ui::VKEY_F3; + } else if (!text.compare("F4")){ + retval = ui::VKEY_F4; + } else if (!text.compare("F5")){ + retval = ui::VKEY_F5; + } else if (!text.compare("F6")){ + retval = ui::VKEY_F6; + } else if (!text.compare("F7")){ + retval = ui::VKEY_F7; + } else if (!text.compare("F8")){ + retval = ui::VKEY_F8; + } else if (!text.compare("F9")){ + retval = ui::VKEY_F9; + } else if (!text.compare("F10")){ + retval = ui::VKEY_F10; + } else if (!text.compare("F11")){ + retval = ui::VKEY_F11; + } else if (!text.compare("F12")){ + retval = ui::VKEY_F12; + } else if (!text.compare("INSERT")){ + retval = ui::VKEY_INSERT; + } else if (!text.compare("HOME")){ + retval = ui::VKEY_HOME; + } else if (!text.compare("DELETE")){ + retval = ui::VKEY_DELETE; + } else if (!text.compare("END")){ + retval = ui::VKEY_END; + } else if (!text.compare("PAGEUP")){ + retval = ui::VKEY_PRIOR; + } else if (!text.compare("PAGEDOWN")){ + retval = ui::VKEY_NEXT; + } else if (!text.compare("UP")){ + retval = ui::VKEY_UP; + } else if (!text.compare("LEFT")){ + retval = ui::VKEY_LEFT; + } else if (!text.compare("DOWN")){ + retval = ui::VKEY_DOWN; + } else if (!text.compare("RIGHT")){ + retval = ui::VKEY_RIGHT; + } + } + } + return retval; +} \ No newline at end of file diff --git a/src/browser/native_window_win.cc b/src/browser/native_window_win.cc index d4faaf4c7b..03513befa8 100644 --- a/src/browser/native_window_win.cc +++ b/src/browser/native_window_win.cc @@ -50,6 +50,20 @@ #include "ui/views/widget/widget.h" #include "ui/views/widget/native_widget_win.h" #include "ui/views/window/native_frame_view.h" +#include "ui/events/event_handler.h" + +#include "chrome/browser/ui/views/accelerator_table.h" +#include "base/basictypes.h" +#include "chrome/app/chrome_command_ids.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/events/event_constants.h" +#if defined(USE_ASH) +#include "ash/accelerators/accelerator_table.h" +#endif + + + + namespace nw { @@ -280,6 +294,7 @@ NativeWindowWin::NativeWindowWin(const base::WeakPtr& shell, window_->UpdateWindowIcon(); OnViewWasResized(); + window_->SetInitialFocus(); } NativeWindowWin::~NativeWindowWin() { @@ -478,6 +493,8 @@ void NativeWindowWin::SetMenu(nwapi::Menu* menu) { // menu is nwapi::Menu, menu->menu_ is NativeMenuWin, ::SetMenu((HWND)window_->GetNativeWindow(), menu->menu_->GetNativeMenu()); + + menu->UpdateKeys( window_->GetFocusManager() ); } void NativeWindowWin::SetTitle(const std::string& title) { @@ -642,10 +659,13 @@ void NativeWindowWin::UpdateDraggableRegions( void NativeWindowWin::HandleKeyboardEvent( const content::NativeWebKeyboardEvent& event) { + unhandled_keyboard_event_handler_.HandleKeyboardEvent(event, + GetFocusManager()); // Any unhandled keyboard/character messages should be defproced. // This allows stuff like F10, etc to work correctly. - DefWindowProc(event.os_event.hwnd, event.os_event.message, - event.os_event.wParam, event.os_event.lParam); + + // DefWindowProc(event.os_event.hwnd, event.os_event.message, + // event.os_event.wParam, event.os_event.lParam); } void NativeWindowWin::Layout() { diff --git a/src/browser/native_window_win.h b/src/browser/native_window_win.h index 9fb0591895..00002744a4 100644 --- a/src/browser/native_window_win.h +++ b/src/browser/native_window_win.h @@ -31,6 +31,11 @@ #include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_observer.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/base/accelerators/accelerator_manager.h" +#include "ui/views/controls/webview/unhandled_keyboard_event_handler.h" +#include "ui/events/keycodes/keyboard_codes.h" + namespace views { class WebView; } @@ -104,6 +109,9 @@ class NativeWindowWin : public NativeWindow, virtual gfx::ImageSkia GetWindowIcon() OVERRIDE; virtual bool ShouldShowWindowTitle() const OVERRIDE; virtual bool ShouldHandleOnSize() const OVERRIDE; + views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_; + + // WidgetFocusChangeListener implementation. virtual void OnNativeFocusChange(gfx::NativeView focused_before, @@ -112,6 +120,13 @@ class NativeWindowWin : public NativeWindow, // WidgetObserver implementation virtual void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) OVERRIDE; + virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE{ + return true; + } + virtual bool CanHandleAccelerators() const OVERRIDE{ + return true; + } + protected: // NativeWindow implementation. virtual void AddToolbar() OVERRIDE; @@ -151,7 +166,6 @@ class NativeWindowWin : public NativeWindow, bool is_blur_; scoped_ptr draggable_region_; - // The window's menubar. nwapi::Menu* menu_; From bdd237e8c07a8de6b11410bea349d9f59c949f9b Mon Sep 17 00:00:00 2001 From: tinyproxy Date: Mon, 26 May 2014 17:07:45 +0800 Subject: [PATCH 032/492] Append super and meta modifiers support --- src/api/menuitem/menuitem.h | 19 ++++++++++++++++--- src/api/menuitem/menuitem_win.cc | 7 +++++-- src/browser/native_window_win.cc | 2 -- src/browser/native_window_win.h | 3 +++ 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/src/api/menuitem/menuitem.h b/src/api/menuitem/menuitem.h index 44765f5b1d..8754361421 100644 --- a/src/api/menuitem/menuitem.h +++ b/src/api/menuitem/menuitem.h @@ -68,11 +68,22 @@ class MenuItem : public Base { #endif #if defined(OS_WIN) - virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE{ + virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE{ + if (super_down_flag_){ + if ( ( (::GetKeyState(VK_LWIN) & 0x8000) != 0x8000) + || ( (::GetKeyState(VK_LWIN) & 0x8000) != 0x8000) ){ + return true; + } + } + if (meta_down_flag_){ + if ( (::GetKeyState(VK_APPS) & 0x8000) != 0x8000 ){ + return true; + } + } OnClick(); return true; } - virtual bool CanHandleAccelerators() const OVERRIDE { + virtual bool CanHandleAccelerators() const OVERRIDE { return true; } void UpdateKeys(views::FocusManager *focus_manager); @@ -126,7 +137,6 @@ class MenuItem : public Base { ui::Accelerator accelerator_; - // Flag to indicate we need refresh. bool is_modified_; @@ -140,6 +150,9 @@ class MenuItem : public Base { Menu* submenu_; bool enable_shortcut_; + bool super_down_flag_; + bool meta_down_flag_; + #endif DISALLOW_COPY_AND_ASSIGN(MenuItem); diff --git a/src/api/menuitem/menuitem_win.cc b/src/api/menuitem/menuitem_win.cc index 6d0e81072e..f212e8f37c 100644 --- a/src/api/menuitem/menuitem_win.cc +++ b/src/api/menuitem/menuitem_win.cc @@ -30,6 +30,7 @@ #include "ui/base/accelerators/accelerator.h" #include "ui/events/event_constants.h"//for modifier key code #include "ui/events/keycodes/keyboard_codes.h"//for keycode +#include "base/logging.h" ui::KeyboardCode GetKeycodeFromText(std::string text); @@ -41,6 +42,8 @@ void MenuItem::Create(const base::DictionaryValue& option) { is_enabled_ = true; type_ = "normal"; submenu_ = NULL; + super_down_flag_ = false; + meta_down_flag_ = false; focus_manager_ = NULL; @@ -77,10 +80,10 @@ void MenuItem::Create(const base::DictionaryValue& option) { modifiers_value = modifiers_value | ui::EF_ALT_DOWN; } if (modifiers.find("super")!=std::string::npos){ - modifiers_value = modifiers_value | ui::EF_COMMAND_DOWN; + super_down_flag_ = true; } if (modifiers.find("meta")!=std::string::npos){ - modifiers_value = modifiers_value | ui::EF_EXTENDED; + meta_down_flag_ = true; } accelerator_ = ui::Accelerator(keyval,modifiers_value); diff --git a/src/browser/native_window_win.cc b/src/browser/native_window_win.cc index 03513befa8..f0b2b40290 100644 --- a/src/browser/native_window_win.cc +++ b/src/browser/native_window_win.cc @@ -63,8 +63,6 @@ - - namespace nw { namespace { diff --git a/src/browser/native_window_win.h b/src/browser/native_window_win.h index 00002744a4..2cc3c328c8 100644 --- a/src/browser/native_window_win.h +++ b/src/browser/native_window_win.h @@ -179,6 +179,9 @@ class NativeWindowWin : public NativeWindow, int last_width_; int last_height_; + bool super_down_; + bool meta_down_; + DISALLOW_COPY_AND_ASSIGN(NativeWindowWin); }; From 97d0704df7e9b0533628f381138f6ad053904881 Mon Sep 17 00:00:00 2001 From: libm Date: Thu, 29 May 2014 13:37:46 +0800 Subject: [PATCH 033/492] Move aws key id settings into boto config file. Goto code.google.com/p/boto/wiki/BotoConfig for more information --- tools/aws_uploader.py | 29 ++++++++--------------------- 1 file changed, 8 insertions(+), 21 deletions(-) diff --git a/tools/aws_uploader.py b/tools/aws_uploader.py index 3bd537a6ea..b282cf0e96 100755 --- a/tools/aws_uploader.py +++ b/tools/aws_uploader.py @@ -5,16 +5,20 @@ import json import os + +# Set timeout, for retry +#if not boto.config.has_section('Boto'): +# boto.config.add_section('Boto') +#boto.config.set('Boto','http_socket_timeout','30') + ################################ # Parse command line args -parser = argparse.ArgumentParser(description='AWS uploader.') +parser = argparse.ArgumentParser(description='AWS uploader, please fill in your aws key and id in Boto config (~/.boto)') parser.add_argument('-p','--path', help='Optional. Where to find the binaries, normally out/Release/dist', required=False) parser.add_argument('-b','--buildername', help='Builder name, e.g. linux_32bit', required=True) parser.add_argument('-r','--revision', help='Commit revision',required=True) parser.add_argument('-n','--number', help='Build number', required=True) parser.add_argument('-t','--bucket', help='AWS bucket name', required=True) -parser.add_argument('-k','--keyfile', help='Optional. JSON file containing AWS access id and key, default: ~/.awskey; ' +\ - 'The content of the key file is like {"awsid":"ABCDEF","awskey":"123456"}', required=False) args = parser.parse_args() @@ -25,7 +29,6 @@ got_revision = args.revision build_number = args.number bucket_name = args.bucket -keyfile = args.keyfile date = datetime.date.today().strftime('%m-%d-%Y') # If the binaries location is not given, calculate it from script related dir. @@ -41,22 +44,6 @@ exit(-1) dist_dir = os.path.normpath(dist_dir) -# Check aws keyfile -if keyfile == None: - keyfile = os.path.join(os.path.expanduser('~'),'.awskey') - print keyfile -if not os.path.exists(keyfile): - print "Cannot find aws key file" - exit(-1) - -json_data = open(keyfile) -data = json.load(json_data) -if not (data.has_key('awsid') and data.has_key('awskey')): - print "Invalid key file format." - exit(-1) -awsid = data['awsid'] -awskey = data['awskey'] - # it's for S3, so always use '/' here upload_path = ''.join(['/' + date, '/' + builder_name + '-build-' + build_number + '-' + got_revision]) @@ -72,7 +59,7 @@ def print_progress(transmitted, total): def aws_upload(upload_path, file_list): - conn = boto.connect_s3(awsid, awskey) + conn = boto.connect_s3() print 'Connecting to S3 ...' bucket = conn.get_bucket(bucket_name) print 'Uploading to: ' + upload_path From 26ad78ed0275185ee9cad35a381037ab7777438f Mon Sep 17 00:00:00 2001 From: Gnor Tech Date: Tue, 3 Jun 2014 13:50:26 +0800 Subject: [PATCH 034/492] update with Chromium 35 --- nw.gypi | 21 +- src/api/api_messages.h | 18 +- src/api/bindings_common.cc | 41 ++- src/api/clipboard/clipboard.cc | 2 +- src/api/dispatcher.cc | 89 +++--- src/api/dispatcher.h | 18 +- src/api/dispatcher_bindings.cc | 184 ++++++----- src/api/dispatcher_bindings.h | 4 +- src/api/shell/shell.cc | 6 +- src/api/window/window.cc | 4 +- src/api/window_bindings.cc | 71 +++-- src/api/window_bindings.h | 4 +- src/breakpad_linux.cc | 3 +- src/browser/capture_page_helper.cc | 2 +- src/browser/file_select_helper.cc | 4 +- src/browser/file_select_helper.h | 2 +- src/browser/printing/print_dialog_gtk.cc | 16 +- src/browser/printing/print_dialog_gtk.h | 18 +- src/browser/printing/print_job.cc | 84 ++--- src/browser/printing/print_job.h | 16 +- src/browser/printing/print_job_worker.cc | 15 +- src/browser/printing/print_view_manager.cc | 4 +- src/browser/printing/print_view_manager.h | 2 +- src/browser/printing/printer_query.cc | 2 +- .../printing/printing_message_filter.cc | 6 +- src/browser/shell_devtools_delegate.cc | 2 +- .../shell_download_manager_delegate.cc | 4 +- src/browser/shell_javascript_dialog.h | 8 +- .../shell_javascript_dialog_creator.cc | 20 +- src/browser/shell_javascript_dialog_creator.h | 6 +- src/browser/shell_javascript_dialog_gtk.cc | 12 +- src/browser/shell_login_dialog.cc | 300 ++---------------- src/browser/shell_login_dialog.h | 168 +--------- src/browser/shell_login_dialog_gtk.cc | 71 ++--- src/browser/shell_login_dialog_mac.mm | 41 +-- ...shell_resource_dispatcher_host_delegate.cc | 2 +- src/chrome_breakpad_client.cc | 17 +- src/chrome_breakpad_client.h | 3 + src/common/print_messages.cc | 8 +- src/common/print_messages.h | 14 +- src/geolocation/shell_access_token_store.cc | 4 +- src/geolocation/shell_access_token_store.h | 2 +- src/media/media_capture_devices_dispatcher.cc | 64 ++-- src/media/media_capture_devices_dispatcher.h | 54 +++- src/media/media_internals.cc | 13 +- src/media/media_internals.h | 29 +- src/media/media_stream_devices_controller.cc | 14 +- src/net/app_protocol_handler.cc | 25 +- src/net/shell_network_delegate.cc | 7 +- src/net/shell_network_delegate.h | 4 +- src/net/shell_url_request_context_getter.cc | 14 +- src/nw_package.cc | 22 +- src/nw_shell.cc | 20 +- src/nw_shell.h | 6 +- src/renderer/nw_render_view_observer.cc | 19 +- src/renderer/nw_render_view_observer.h | 10 +- .../prerenderer/prerenderer_client.cc | 2 +- src/renderer/prerenderer/prerenderer_client.h | 6 +- .../printing/print_web_view_helper.cc | 217 +++++++------ src/renderer/printing/print_web_view_helper.h | 71 ++--- .../printing/print_web_view_helper_linux.cc | 10 +- src/renderer/shell_content_renderer_client.cc | 136 ++++---- src/renderer/shell_content_renderer_client.h | 16 +- src/renderer/shell_render_process_observer.cc | 25 +- src/shell_browser_context.cc | 28 +- src/shell_browser_context.h | 37 ++- src/shell_browser_main_parts.cc | 2 +- src/shell_content_browser_client.cc | 21 +- src/shell_content_browser_client.h | 6 +- src/shell_content_client.cc | 6 +- src/shell_content_client.h | 2 +- src/shell_main.cc | 5 +- src/shell_main_delegate.cc | 4 +- 73 files changed, 928 insertions(+), 1285 deletions(-) diff --git a/nw.gypi b/nw.gypi index 5cedde1553..7f1ba04bb3 100644 --- a/nw.gypi +++ b/nw.gypi @@ -37,7 +37,7 @@ '<(DEPTH)/base/base.gyp:base', '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '<(DEPTH)/components/components.gyp:autofill_content_renderer', - '<(DEPTH)/components/components.gyp:browser_context_keyed_service', + '<(DEPTH)/components/components.gyp:keyed_service_content', '<(DEPTH)/content/content.gyp:content_app_browser', '<(DEPTH)/content/content.gyp:content_browser', '<(DEPTH)/content/content.gyp:content_common', @@ -55,11 +55,10 @@ '<(DEPTH)/printing/printing.gyp:printing', '<(DEPTH)/skia/skia.gyp:skia', '<(DEPTH)/third_party/node/node.gyp:node', - '<(DEPTH)/ui/ui.gyp:ui', - '<(DEPTH)/ui/ui.gyp:ui_resources', + '<(DEPTH)/ui/base/ui_base.gyp:ui_base', + '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources', '<(DEPTH)/url/url.gyp:url_lib', '<(DEPTH)/v8/tools/gyp/v8.gyp:v8', - '<(DEPTH)/webkit/glue/webkit_glue.gyp:glue', '<(DEPTH)/third_party/zlib/zlib.gyp:minizip', '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink', 'nw_resources', @@ -71,6 +70,7 @@ '<(DEPTH)/breakpad/src', '<(SHARED_INTERMEDIATE_DIR)/blink', '<(SHARED_INTERMEDIATE_DIR)/blink/bindings', + '<(SHARED_INTERMEDIATE_DIR)/chrome', ], 'cflags_cc': [ '-Wno-error=c++0x-compat', @@ -83,7 +83,6 @@ #'<(DEPTH)/chrome/common/child_process_logging_posix.cc', #'<(DEPTH)/chrome/common/child_process_logging_win.cc', '<(DEPTH)/chrome/common/crash_keys.cc', - '<(DEPTH)/chrome/common/dump_without_crashing.cc', '<(DEPTH)/chrome/common/env_vars.cc', '<(DEPTH)/chrome/browser/crash_upload_list.cc', '<(DEPTH)/chrome/browser/upload_list.cc', @@ -274,8 +273,8 @@ 'src/nw_version.h', 'src/paths_mac.h', 'src/paths_mac.mm', - 'src/renderer/autofill_agent.cc', - 'src/renderer/autofill_agent.h', + # 'src/renderer/autofill_agent.cc', + # 'src/renderer/autofill_agent.h', 'src/renderer/common/render_messages.cc', 'src/renderer/common/render_messages.h', 'src/renderer/prerenderer/prerenderer_client.cc', @@ -378,7 +377,7 @@ '<(SHARED_INTERMEDIATE_DIR)/webkit', ], 'dependencies': [ - '<(DEPTH)/ui/ui.gyp:ui_resources', + '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources', '<(DEPTH)/ui/views/controls/webview/webview.gyp:webview', '<(DEPTH)/ui/views/views.gyp:views', '<(DEPTH)/webkit/webkit_resources.gyp:webkit_resources', @@ -532,7 +531,7 @@ 'type': 'none', 'dependencies': [ '<(DEPTH)/content/browser/devtools/devtools_resources.gyp:devtools_resources', - '<(DEPTH)/ui/ui.gyp:ui_resources', + '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources', 'nw_resources', ], 'variables': { @@ -680,6 +679,10 @@ }, }, }], # OS=="win" + ['OS == "linux"', { + 'ldflags': [ + '-Wl,--whole-archive', 'obj/third_party/node/libnode.a', '-Wl,--no-whole-archive' ], + }], ['OS == "win" or toolkit_uses_gtk == 1', { 'dependencies': [ '<(DEPTH)/sandbox/sandbox.gyp:sandbox', diff --git a/src/api/api_messages.h b/src/api/api_messages.h index 88db56ae0b..e649074172 100644 --- a/src/api/api_messages.h +++ b/src/api/api_messages.h @@ -36,7 +36,7 @@ IPC_STRUCT_TRAITS_END() IPC_MESSAGE_ROUTED3(ShellViewHostMsg_Allocate_Object, int /* object id */, std::string /* type name */, - DictionaryValue /* option */) + base::DictionaryValue /* option */) IPC_MESSAGE_ROUTED1(ShellViewHostMsg_Deallocate_Object, int /* object id */) @@ -45,30 +45,30 @@ IPC_MESSAGE_ROUTED4(ShellViewHostMsg_Call_Object_Method, int /* object id */, std::string /* type name */, std::string /* method name */, - ListValue /* arguments */) + base::ListValue /* arguments */) IPC_SYNC_MESSAGE_ROUTED4_1(ShellViewHostMsg_Call_Object_Method_Sync, int /* object id */, std::string /* type name */, std::string /* method name */, - ListValue /* arguments */, - ListValue /* result */) + base::ListValue /* arguments */, + base::ListValue /* result */) IPC_MESSAGE_ROUTED3(ShellViewHostMsg_Call_Static_Method, std::string /* type name */, std::string /* method name */, - ListValue /* arguments */) + base::ListValue /* arguments */) IPC_SYNC_MESSAGE_ROUTED3_1(ShellViewHostMsg_Call_Static_Method_Sync, std::string /* type name */, std::string /* method name */, - ListValue /* arguments */, - ListValue /* result */) + base::ListValue /* arguments */, + base::ListValue /* result */) IPC_MESSAGE_ROUTED3(ShellViewMsg_Object_On_Event, int /* object id */, std::string /* event name */, - ListValue /* arguments */) + base::ListValue /* arguments */) // Request Shell's id for current render_view_host. IPC_SYNC_MESSAGE_ROUTED0_1(ShellViewHostMsg_GetShellId, @@ -77,7 +77,7 @@ IPC_SYNC_MESSAGE_ROUTED0_1(ShellViewHostMsg_GetShellId, // Create a Shell and returns its routing id. IPC_SYNC_MESSAGE_ROUTED2_1(ShellViewHostMsg_CreateShell, std::string /* url */, - DictionaryValue /* manifest */, + base::DictionaryValue /* manifest */, int /* result */) // Tell browser we have an uncaughtException from node. diff --git a/src/api/bindings_common.cc b/src/api/bindings_common.cc index be1e1c74c7..48db9777e7 100644 --- a/src/api/bindings_common.cc +++ b/src/api/bindings_common.cc @@ -33,8 +33,8 @@ using content::RenderView; using content::RenderThread; using content::V8ValueConverter; -using WebKit::WebFrame; -using WebKit::WebView; +using blink::WebFrame; +using blink::WebView; namespace { RenderView* GetRenderView(v8::Handle ctx) { @@ -53,12 +53,14 @@ RenderView* GetRenderView(v8::Handle ctx) { } RenderView* GetCurrentRenderView() { - v8::Local ctx = v8::Context::GetCurrent(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Local ctx = isolate->GetCurrentContext(); return GetRenderView(ctx); } RenderView* GetEnteredRenderView() { - v8::Local ctx = v8::Context::GetEntered(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::Local ctx = isolate->GetEnteredContext(); return GetRenderView(ctx); } @@ -69,29 +71,31 @@ base::StringPiece GetStringResource(int resource_id) { namespace remote { v8::Handle AllocateId(int routing_id) { - v8::HandleScope scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); int result = 0; RenderThread::Get()->Send(new ShellViewHostMsg_AllocateId( routing_id, &result)); - return scope.Close(v8::Integer::New(result)); + return scope.Escape(v8::Integer::New(isolate, result)); } v8::Handle AllocateObject(int routing_id, int object_id, const std::string& type, v8::Handle options) { - v8::HandleScope handle_scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); scoped_ptr converter(V8ValueConverter::create()); converter->SetStripNullFromObjects(true); scoped_ptr value_option( - converter->FromV8Value(options, v8::Context::GetCurrent())); + converter->FromV8Value(options, isolate->GetCurrentContext())); if (!value_option.get() || !value_option->IsType(base::Value::TYPE_DICTIONARY)) - return v8::ThrowException(v8::Exception::Error(v8::String::New( + return isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to convert 'option' passed to AllocateObject"))); DVLOG(1) << "remote::AllocateObject(routing_id=" << routing_id << ", object_id=" << object_id << ")"; @@ -101,14 +105,15 @@ v8::Handle AllocateObject(int routing_id, object_id, type, *static_cast(value_option.get()))); - return v8::Undefined(); + return v8::Undefined(isolate); } v8::Handle DeallocateObject(int routing_id, int object_id) { RenderThread::Get()->Send(new ShellViewHostMsg_Deallocate_Object( routing_id, object_id)); - return v8::Undefined(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + return v8::Undefined(isolate); } v8::Handle CallObjectMethod(int routing_id, @@ -116,13 +121,14 @@ v8::Handle CallObjectMethod(int routing_id, const std::string& type, const std::string& method, v8::Handle args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); scoped_ptr converter(V8ValueConverter::create()); scoped_ptr value_args( - converter->FromV8Value(args, v8::Context::GetCurrent())); + converter->FromV8Value(args, isolate->GetCurrentContext())); if (!value_args.get() || !value_args->IsType(base::Value::TYPE_LIST)) - return v8::ThrowException(v8::Exception::Error(v8::String::New( + return isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to convert 'args' passed to CallObjectMethod"))); RenderThread::Get()->Send(new ShellViewHostMsg_Call_Object_Method( @@ -131,7 +137,7 @@ v8::Handle CallObjectMethod(int routing_id, type, method, *static_cast(value_args.get()))); - return v8::Undefined(); + return v8::Undefined(isolate); } v8::Handle CallObjectMethodSync(int routing_id, @@ -139,13 +145,14 @@ v8::Handle CallObjectMethodSync(int routing_id, const std::string& type, const std::string& method, v8::Handle args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); scoped_ptr converter(V8ValueConverter::create()); scoped_ptr value_args( - converter->FromV8Value(args, v8::Context::GetCurrent())); + converter->FromV8Value(args, isolate->GetCurrentContext())); if (!value_args.get() || !value_args->IsType(base::Value::TYPE_LIST)) - return v8::ThrowException(v8::Exception::Error(v8::String::New( + return isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to convert 'args' passed to CallObjectMethodSync"))); base::ListValue result; @@ -156,7 +163,7 @@ v8::Handle CallObjectMethodSync(int routing_id, method, *static_cast(value_args.get()), &result)); - return converter->ToV8Value(&result, v8::Context::GetCurrent()); + return converter->ToV8Value(&result, isolate->GetCurrentContext()); } } // namespace remote diff --git a/src/api/clipboard/clipboard.cc b/src/api/clipboard/clipboard.cc index 03ccd2d070..1102bbe0b3 100644 --- a/src/api/clipboard/clipboard.cc +++ b/src/api/clipboard/clipboard.cc @@ -73,7 +73,7 @@ void Clipboard::SetText(std::string& text) { std::string Clipboard::GetText() { ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); - string16 text; + base::string16 text; clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &text); return UTF16ToUTF8(text); } diff --git a/src/api/dispatcher.cc b/src/api/dispatcher.cc index 1e411a00b2..7722148fb3 100644 --- a/src/api/dispatcher.cc +++ b/src/api/dispatcher.cc @@ -35,6 +35,8 @@ #undef LOG #undef ASSERT +#undef FROM_HERE + #if defined(OS_WIN) #define _USE_MATH_DEFINES #include @@ -47,7 +49,8 @@ namespace nwapi { static inline v8::Local v8_str(const char* x) { - return v8::String::New(x); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + return v8::String::NewFromUtf8(isolate, x); } Dispatcher::Dispatcher(content::RenderView* render_view) @@ -67,8 +70,8 @@ bool Dispatcher::OnMessageReceived(const IPC::Message& message) { return handled; } -void Dispatcher::DraggableRegionsChanged(WebKit::WebFrame* frame) { - WebKit::WebVector webregions = +void Dispatcher::DraggableRegionsChanged(blink::WebFrame* frame) { + blink::WebVector webregions = frame->document().draggableRegions(); std::vector regions; for (size_t i = 0; i < webregions.size(); ++i) { @@ -83,8 +86,9 @@ void Dispatcher::DraggableRegionsChanged(WebKit::WebFrame* frame) { void Dispatcher::OnEvent(int object_id, std::string event, const base::ListValue& arguments) { - v8::HandleScope scope; - WebKit::WebView* web_view = render_view()->GetWebView(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + blink::WebView* web_view = render_view()->GetWebView(); if (web_view == NULL) return; @@ -92,36 +96,40 @@ void Dispatcher::OnEvent(int object_id, content::V8ValueConverterImpl converter; v8::Local context = - v8::Local::New(node::g_context->GetIsolate(), node::g_context); + v8::Local::New(isolate, node::g_context); v8::Handle args = converter.ToV8Value(&arguments, context); DCHECK(!args.IsEmpty()) << "Invalid 'arguments' in Dispatcher::OnEvent"; v8::Handle argv[] = { - v8::Integer::New(object_id), v8_str(event.c_str()), args }; + v8::Integer::New(isolate, object_id), v8_str(event.c_str()), args }; // __nwObjectsRegistry.handleEvent(object_id, event, arguments); v8::Handle val = - node::g_context->Global()->Get(v8_str("__nwObjectsRegistry")); + context->Global()->Get(v8_str("__nwObjectsRegistry")); if (val->IsNull() || val->IsUndefined()) return; // need to find out why it's undefined here in debugger v8::Handle objects_registry = val->ToObject(); DVLOG(1) << "handleEvent(object_id=" << object_id << ", event=\"" << event << "\")"; - node::MakeCallback(objects_registry, "handleEvent", 3, argv); + node::MakeCallback(isolate, objects_registry, "handleEvent", 3, argv); } v8::Handle Dispatcher::GetObjectRegistry() { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + v8::Local context = + v8::Local::New(isolate, node::g_context); // need to enter node context to access the registry in // some cases, e.g. normal frame in #1519 - node::g_context->Enter(); + context->Enter(); v8::Handle registry = - node::g_context->Global()->Get(v8_str("__nwObjectsRegistry")); - node::g_context->Exit(); + context->Global()->Get(v8_str("__nwObjectsRegistry")); + context->Exit(); // if (registry->IsNull() || registry->IsUndefined()) // return v8::Undefined(); return registry->ToObject(); } -v8::Handle Dispatcher::GetWindowId(WebKit::WebFrame* frame) { +v8::Handle Dispatcher::GetWindowId(blink::WebFrame* frame) { v8::Handle v8win = frame->mainWorldScriptContext()->Global(); v8::Handle val = v8win->ToObject()->Get(v8_str("__nwWindowId")); @@ -129,7 +137,8 @@ v8::Handle Dispatcher::GetWindowId(WebKit::WebFrame* frame) { } void Dispatcher::ZoomLevelChanged() { - WebKit::WebView* web_view = render_view()->GetWebView(); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + blink::WebView* web_view = render_view()->GetWebView(); float zoom_level = web_view->zoomLevel(); v8::Handle val = GetWindowId(web_view->mainFrame()); @@ -141,23 +150,24 @@ void Dispatcher::ZoomLevelChanged() { if (objects_registry->IsUndefined()) return; - v8::Local args = v8::Array::New(); - args->Set(0, v8::Number::New(zoom_level)); + v8::Local args = v8::Array::New(isolate); + args->Set(0, v8::Number::New(isolate, zoom_level)); v8::Handle argv[] = {val, v8_str("zoom"), args }; - node::MakeCallback(objects_registry, "handleEvent", 3, argv); + node::MakeCallback(isolate, objects_registry, "handleEvent", 3, argv); } -void Dispatcher::DidCreateDocumentElement(WebKit::WebFrame* frame) { +void Dispatcher::DidCreateDocumentElement(blink::WebFrame* frame) { documentCallback("document-start", frame); } -void Dispatcher::DidFinishDocumentLoad(WebKit::WebFrame* frame) { +void Dispatcher::DidFinishDocumentLoad(blink::WebFrame* frame) { documentCallback("document-end", frame); } -void Dispatcher::documentCallback(const char* ev, WebKit::WebFrame* frame) { - WebKit::WebView* web_view = render_view()->GetWebView(); +void Dispatcher::documentCallback(const char* ev, blink::WebFrame* frame) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + blink::WebView* web_view = render_view()->GetWebView(); if (!web_view) return; @@ -171,9 +181,9 @@ void Dispatcher::documentCallback(const char* ev, WebKit::WebFrame* frame) { if (objects_registry->IsUndefined()) return; - v8::Local args = v8::Array::New(); - v8::Handle element = v8::Null(); - WebCore::Frame* core_frame = WebKit::toWebFrameImpl(frame)->frame(); + v8::Local args = v8::Array::New(isolate); + v8::Handle element = v8::Null(isolate); + WebCore::LocalFrame* core_frame = blink::toWebFrameImpl(frame)->frame(); if (core_frame->ownerElement()) { element = WebCore::toV8((WebCore::HTMLElement*)core_frame->ownerElement(), frame->mainWorldScriptContext()->Global(), @@ -182,20 +192,21 @@ void Dispatcher::documentCallback(const char* ev, WebKit::WebFrame* frame) { args->Set(0, element); v8::Handle argv[] = {val, v8_str(ev), args }; - node::MakeCallback(objects_registry, "handleEvent", 3, argv); + node::MakeCallback(isolate, objects_registry, "handleEvent", 3, argv); } void Dispatcher::willHandleNavigationPolicy( content::RenderView* rv, - WebKit::WebFrame* frame, - const WebKit::WebURLRequest& request, - WebKit::WebNavigationPolicy* policy) { + blink::WebFrame* frame, + const blink::WebURLRequest& request, + blink::WebNavigationPolicy* policy) { - WebKit::WebView* web_view = rv->GetWebView(); + blink::WebView* web_view = rv->GetWebView(); if (!web_view) return; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::Context::Scope cscope (web_view->mainFrame()->mainWorldScriptContext()); v8::Handle id_val = nwapi::Dispatcher::GetWindowId(web_view->mainFrame()); @@ -206,11 +217,11 @@ void Dispatcher::willHandleNavigationPolicy( if (objects_registry->IsUndefined()) return; - v8::Local args = v8::Array::New(); - v8::Handle element = v8::Null(); - v8::Handle policy_obj = v8::Object::New(); + v8::Local args = v8::Array::New(isolate); + v8::Handle element = v8::Null(isolate); + v8::Handle policy_obj = v8::Object::New(isolate); - WebCore::Frame* core_frame = WebKit::toWebFrameImpl(frame)->frame(); + WebCore::LocalFrame* core_frame = blink::toWebFrameImpl(frame)->frame(); if (core_frame->ownerElement()) { element = WebCore::toV8((WebCore::HTMLElement*)core_frame->ownerElement(), frame->mainWorldScriptContext()->Global(), @@ -222,21 +233,21 @@ void Dispatcher::willHandleNavigationPolicy( v8::Handle argv[] = {id_val, v8_str("new-win-policy"), args }; - node::MakeCallback(objects_registry, "handleEvent", 3, argv); + node::MakeCallback(isolate, objects_registry, "handleEvent", 3, argv); v8::Local val = policy_obj->Get(v8_str("val")); if (!val->IsString()) return; v8::String::Utf8Value policy_str(val); if (!strcmp(*policy_str, "ignore")) - *policy = WebKit::WebNavigationPolicyIgnore; + *policy = blink::WebNavigationPolicyIgnore; else if (!strcmp(*policy_str, "download")) - *policy = WebKit::WebNavigationPolicyDownload; + *policy = blink::WebNavigationPolicyDownload; else if (!strcmp(*policy_str, "current")) - *policy = WebKit::WebNavigationPolicyCurrentTab; + *policy = blink::WebNavigationPolicyCurrentTab; else if (!strcmp(*policy_str, "new-window")) - *policy = WebKit::WebNavigationPolicyNewWindow; + *policy = blink::WebNavigationPolicyNewWindow; else if (!strcmp(*policy_str, "new-popup")) - *policy = WebKit::WebNavigationPolicyNewPopup; + *policy = blink::WebNavigationPolicyNewPopup; } } // namespace nwapi diff --git a/src/api/dispatcher.h b/src/api/dispatcher.h index 4a59932d57..51be736156 100644 --- a/src/api/dispatcher.h +++ b/src/api/dispatcher.h @@ -34,7 +34,7 @@ namespace content { class RenderView; } -namespace WebKit { +namespace blink { class WebFrame; class WebURLRequest; } @@ -47,22 +47,22 @@ class Dispatcher : public content::RenderViewObserver { virtual ~Dispatcher(); static v8::Handle GetObjectRegistry(); - static v8::Handle GetWindowId(WebKit::WebFrame* frame); + static v8::Handle GetWindowId(blink::WebFrame* frame); static void willHandleNavigationPolicy( content::RenderView* rv, - WebKit::WebFrame* frame, - const WebKit::WebURLRequest& request, - WebKit::WebNavigationPolicy* policy); + blink::WebFrame* frame, + const blink::WebURLRequest& request, + blink::WebNavigationPolicy* policy); private: // RenderViewObserver implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void DraggableRegionsChanged(WebKit::WebFrame* frame) OVERRIDE; + virtual void DraggableRegionsChanged(blink::WebFrame* frame) OVERRIDE; virtual void ZoomLevelChanged() OVERRIDE; - virtual void DidFinishDocumentLoad(WebKit::WebFrame* frame) OVERRIDE; - virtual void DidCreateDocumentElement(WebKit::WebFrame* frame) OVERRIDE; + virtual void DidFinishDocumentLoad(blink::WebFrame* frame) OVERRIDE; + virtual void DidCreateDocumentElement(blink::WebFrame* frame) OVERRIDE; - void documentCallback(const char* ev, WebKit::WebFrame* frame); + void documentCallback(const char* ev, blink::WebFrame* frame); void OnEvent(int object_id, std::string event, diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 84697ce400..60858ba777 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -43,11 +43,12 @@ namespace nwapi { namespace { v8::Handle WrapSource(v8::Handle source) { - v8::HandleScope handle_scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); v8::Handle left = - v8::String::New("(function(nw, exports) {"); - v8::Handle right = v8::String::New("\n})"); - return handle_scope.Close( + v8::String::NewFromUtf8(isolate, "(function(nw, exports) {"); + v8::Handle right = v8::String::NewFromUtf8(isolate, "\n})"); + return handle_scope.Escape( v8::String::Concat(left, v8::String::Concat(source, right))); } @@ -56,14 +57,15 @@ void RequireFromResource(v8::Handle root, v8::Handle gui, v8::Handle name, int resource_id) { - v8::HandleScope scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handle_scope(isolate); - v8::Handle source = v8::String::NewExternal( + v8::Handle source = v8::String::NewExternal(isolate, new StaticV8ExternalAsciiStringResource( GetStringResource(resource_id))); v8::Handle wrapped_source = WrapSource(source); - v8::Handle script(v8::Script::New(wrapped_source, name)); + v8::Handle script(v8::Script::Compile(wrapped_source, name)); v8::Handle func = v8::Handle::Cast(script->Run()); v8::Handle args[] = { root, gui }; func->Call(root, 2, args); @@ -73,7 +75,7 @@ bool MakePathAbsolute(FilePath* file_path) { DCHECK(file_path); FilePath current_directory; - if (!file_util::GetCurrentDirectory(¤t_directory)) + if (!base::GetCurrentDirectory(¤t_directory)) return false; if (file_path->IsAbsolute()) @@ -107,121 +109,128 @@ DispatcherBindings::~DispatcherBindings() { } v8::Handle -DispatcherBindings::GetNativeFunction(v8::Handle name) { - if (name->Equals(v8::String::New("RequireNwGui"))) - return v8::FunctionTemplate::New(RequireNwGui); - else if (name->Equals(v8::String::New("GetAbsolutePath"))) - return v8::FunctionTemplate::New(GetAbsolutePath); - else if (name->Equals(v8::String::New("GetShellIdForCurrentContext"))) - return v8::FunctionTemplate::New(GetShellIdForCurrentContext); - else if (name->Equals(v8::String::New("GetRoutingIDForCurrentContext"))) - return v8::FunctionTemplate::New(GetRoutingIDForCurrentContext); - else if (name->Equals(v8::String::New("CreateShell"))) - return v8::FunctionTemplate::New(CreateShell); - else if (name->Equals(v8::String::New("AllocateObject"))) - return v8::FunctionTemplate::New(AllocateObject); - else if (name->Equals(v8::String::New("DeallocateObject"))) - return v8::FunctionTemplate::New(DeallocateObject); - else if (name->Equals(v8::String::New("CallObjectMethod"))) - return v8::FunctionTemplate::New(CallObjectMethod); - else if (name->Equals(v8::String::New("CallObjectMethodSync"))) - return v8::FunctionTemplate::New(CallObjectMethodSync); - else if (name->Equals(v8::String::New("CallStaticMethod"))) - return v8::FunctionTemplate::New(CallStaticMethod); - else if (name->Equals(v8::String::New("CallStaticMethodSync"))) - return v8::FunctionTemplate::New(CallStaticMethodSync); - else if (name->Equals(v8::String::New("CrashRenderer"))) - return v8::FunctionTemplate::New(CrashRenderer); - else if (name->Equals(v8::String::New("SetCrashDumpDir"))) - return v8::FunctionTemplate::New(SetCrashDumpDir); - else if (name->Equals(v8::String::New("AllocateId"))) - return v8::FunctionTemplate::New(AllocateId); +DispatcherBindings::GetNativeFunctionTemplate( + v8::Isolate* isolate, + v8::Handle name) { + if (name->Equals(v8::String::NewFromUtf8(isolate, "RequireNwGui"))) + return v8::FunctionTemplate::New(isolate, RequireNwGui); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetAbsolutePath"))) + return v8::FunctionTemplate::New(isolate, GetAbsolutePath); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetShellIdForCurrentContext"))) + return v8::FunctionTemplate::New(isolate, GetShellIdForCurrentContext); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetRoutingIDForCurrentContext"))) + return v8::FunctionTemplate::New(isolate, GetRoutingIDForCurrentContext); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "CreateShell"))) + return v8::FunctionTemplate::New(isolate, CreateShell); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "AllocateObject"))) + return v8::FunctionTemplate::New(isolate, AllocateObject); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "DeallocateObject"))) + return v8::FunctionTemplate::New(isolate, DeallocateObject); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "CallObjectMethod"))) + return v8::FunctionTemplate::New(isolate, CallObjectMethod); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "CallObjectMethodSync"))) + return v8::FunctionTemplate::New(isolate, CallObjectMethodSync); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "CallStaticMethod"))) + return v8::FunctionTemplate::New(isolate, CallStaticMethod); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "CallStaticMethodSync"))) + return v8::FunctionTemplate::New(isolate, CallStaticMethodSync); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "CrashRenderer"))) + return v8::FunctionTemplate::New(isolate, CrashRenderer); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "SetCrashDumpDir"))) + return v8::FunctionTemplate::New(isolate, SetCrashDumpDir); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "AllocateId"))) + return v8::FunctionTemplate::New(isolate, AllocateId); NOTREACHED() << "Trying to get an non-exist function in DispatcherBindings:" << *v8::String::Utf8Value(name); - return v8::FunctionTemplate::New(); + return v8::FunctionTemplate::New(isolate); } // static void DispatcherBindings::RequireNwGui(const v8::FunctionCallbackInfo& args) { - v8::HandleScope scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope handle_scope(isolate); // Initialize lazily - v8::Local NwGuiSymbol = v8::String::NewSymbol("nwGui"); + v8::Local NwGuiSymbol = v8::String::NewFromUtf8(isolate, "nwGui", v8::String::kInternalizedString); v8::Local NwGuiHidden = args.This()->Get(NwGuiSymbol); if (NwGuiHidden->IsObject()) { - args.GetReturnValue().Set(scope.Close(NwGuiHidden)); + args.GetReturnValue().Set(handle_scope.Escape(NwGuiHidden)); return; } - v8::Local NwGui = v8::Object::New(); + v8::Local NwGui = v8::Object::New(isolate); args.This()->Set(NwGuiSymbol, NwGui); RequireFromResource(args.This(), - NwGui, v8::String::New("base.js"), IDR_NW_API_BASE_JS); + NwGui, v8::String::NewFromUtf8(isolate, "base.js"), IDR_NW_API_BASE_JS); RequireFromResource(args.This(), - NwGui, v8::String::New("menuitem.js"), IDR_NW_API_MENUITEM_JS); + NwGui, v8::String::NewFromUtf8(isolate, "menuitem.js"), IDR_NW_API_MENUITEM_JS); RequireFromResource(args.This(), - NwGui, v8::String::New("menu.js"), IDR_NW_API_MENU_JS); + NwGui, v8::String::NewFromUtf8(isolate, "menu.js"), IDR_NW_API_MENU_JS); RequireFromResource(args.This(), - NwGui, v8::String::New("tray.js"), IDR_NW_API_TRAY_JS); + NwGui, v8::String::NewFromUtf8(isolate, "tray.js"), IDR_NW_API_TRAY_JS); RequireFromResource(args.This(), - NwGui, v8::String::New("clipboard.js"), IDR_NW_API_CLIPBOARD_JS); + NwGui, v8::String::NewFromUtf8(isolate, "clipboard.js"), IDR_NW_API_CLIPBOARD_JS); RequireFromResource(args.This(), - NwGui, v8::String::New("window.js"), IDR_NW_API_WINDOW_JS); + NwGui, v8::String::NewFromUtf8(isolate, "window.js"), IDR_NW_API_WINDOW_JS); RequireFromResource(args.This(), - NwGui, v8::String::New("shell.js"), IDR_NW_API_SHELL_JS); + NwGui, v8::String::NewFromUtf8(isolate, "shell.js"), IDR_NW_API_SHELL_JS); RequireFromResource(args.This(), - NwGui, v8::String::New("app.js"), IDR_NW_API_APP_JS); + NwGui, v8::String::NewFromUtf8(isolate, "app.js"), IDR_NW_API_APP_JS); - args.GetReturnValue().Set(scope.Close(NwGui)); + args.GetReturnValue().Set(handle_scope.Escape(NwGui)); } // static void DispatcherBindings::GetAbsolutePath(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); FilePath path = FilePath::FromUTF8Unsafe(*v8::String::Utf8Value(args[0])); MakePathAbsolute(&path); #if defined(OS_POSIX) - args.GetReturnValue().Set(v8::String::New(path.value().c_str())); + args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, path.value().c_str())); #else - args.GetReturnValue().Set(v8::String::New(path.AsUTF8Unsafe().c_str())); + args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, path.AsUTF8Unsafe().c_str())); #endif } // static void DispatcherBindings::GetShellIdForCurrentContext(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); RenderView* render_view = GetCurrentRenderView(); if (!render_view) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to get render view in CallStaticMethodSync")))); return; } int id = -1; render_view->Send(new ShellViewHostMsg_GetShellId(MSG_ROUTING_NONE, &id)); - args.GetReturnValue().Set(v8::Integer::New(id)); + args.GetReturnValue().Set(v8::Integer::New(isolate, id)); } // static void DispatcherBindings::GetRoutingIDForCurrentContext(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); RenderView* render_view = GetCurrentRenderView(); if (!render_view) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to get render view in GetRoutingIDForCurrentContext")))); return; } - args.GetReturnValue().Set(v8::Integer::New(render_view->GetRoutingID())); + args.GetReturnValue().Set(v8::Integer::New(isolate, render_view->GetRoutingID())); } // static void DispatcherBindings::CreateShell(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); if (args.Length() < 2) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "CreateShell requries 2 arguments")))); return; } @@ -231,17 +240,17 @@ DispatcherBindings::CreateShell(const v8::FunctionCallbackInfo& args) scoped_ptr converter(V8ValueConverter::create()); scoped_ptr value_manifest( - converter->FromV8Value(args[1], v8::Context::GetCurrent())); + converter->FromV8Value(args[1], isolate->GetCurrentContext())); if (!value_manifest.get() || !value_manifest->IsType(base::Value::TYPE_DICTIONARY)) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to convert 'options' passed to CreateShell")))); return; } RenderView* render_view = GetCurrentRenderView(); if (!render_view) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to get render view in CreateShell")))); return; } @@ -253,15 +262,16 @@ DispatcherBindings::CreateShell(const v8::FunctionCallbackInfo& args) *static_cast(value_manifest.get()), &routing_id)); - args.GetReturnValue().Set(v8::Integer::New(routing_id)); + args.GetReturnValue().Set(v8::Integer::New(isolate, routing_id)); } // static void DispatcherBindings::AllocateId(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); RenderView* render_view = GetCurrentRenderView(); if (!render_view) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to get render view in AllocateId")))); return; } @@ -271,8 +281,9 @@ DispatcherBindings::AllocateId(const v8::FunctionCallbackInfo& args) void DispatcherBindings::AllocateObject(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); if (args.Length() < 3) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "AllocateObject requries 3 arguments")))); return; } @@ -282,7 +293,7 @@ DispatcherBindings::AllocateObject(const v8::FunctionCallbackInfo& ar RenderView* render_view = GetCurrentRenderView(); if (!render_view) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to get render view in AllocateObject")))); return; } @@ -293,15 +304,16 @@ DispatcherBindings::AllocateObject(const v8::FunctionCallbackInfo& ar // static void DispatcherBindings::DeallocateObject(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); RenderView* render_view = GetCurrentRenderView(); if (!render_view) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to get render view in DeallocateObject")))); return; } if (args.Length() < 1) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "DeallocateObject requries 1 arguments")))); return; } @@ -311,8 +323,9 @@ DispatcherBindings::DeallocateObject(const v8::FunctionCallbackInfo& // static void DispatcherBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); if (args.Length() < 4) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "CallObjectMethod requries 4 arguments")))); return; } @@ -325,7 +338,7 @@ DispatcherBindings::CallObjectMethod(const v8::FunctionCallbackInfo& if (!render_view) render_view = GetEnteredRenderView(); if (!render_view) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to get render view in CallObjectMethod")))); return; } @@ -336,8 +349,9 @@ DispatcherBindings::CallObjectMethod(const v8::FunctionCallbackInfo& // static void DispatcherBindings::CallObjectMethodSync( const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); if (args.Length() < 4) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "CallObjectMethodSync requries 4 arguments")))); return; } @@ -348,7 +362,7 @@ void DispatcherBindings::CallObjectMethodSync( RenderView* render_view = GetCurrentRenderView(); if (!render_view) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to get render view in CallObjectMethod")))); return; } @@ -359,8 +373,9 @@ void DispatcherBindings::CallObjectMethodSync( // static void DispatcherBindings::CallStaticMethod( const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); if (args.Length() < 3) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "CallStaticMethod requries 3 arguments")))); return; } @@ -371,17 +386,17 @@ void DispatcherBindings::CallStaticMethod( scoped_ptr converter(V8ValueConverter::create()); scoped_ptr value_args( - converter->FromV8Value(args[2], v8::Context::GetCurrent())); + converter->FromV8Value(args[2], isolate->GetCurrentContext())); if (!value_args.get() || !value_args->IsType(base::Value::TYPE_LIST)) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to convert 'args' passed to CallStaticMethod")))); return; } RenderView* render_view = GetCurrentRenderView(); if (!render_view) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to get render view in CallStaticMethod")))); return; } @@ -391,7 +406,7 @@ void DispatcherBindings::CallStaticMethod( type, method, *static_cast(value_args.get()))); - args.GetReturnValue().Set(v8::Undefined()); + args.GetReturnValue().Set(v8::Undefined(isolate)); } // static @@ -413,8 +428,9 @@ void DispatcherBindings::SetCrashDumpDir( // static void DispatcherBindings::CallStaticMethodSync( const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); if (args.Length() < 3) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "CallStaticMethodSync requries 3 arguments")))); return; } @@ -426,7 +442,7 @@ void DispatcherBindings::CallStaticMethodSync( RenderView* render_view = GetEnteredRenderView(); if (!render_view) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to get render view in CallStaticMethodSync")))); return; } @@ -435,25 +451,25 @@ void DispatcherBindings::CallStaticMethodSync( std::string url = *v8::String::Utf8Value(args[2]); GURL gurl(url); if (!gurl.is_valid()) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Invalid URL passed to App.getProxyForURL()")))); return; } std::string proxy; bool result = content::RenderThread::Get()->ResolveProxy(gurl, &proxy); if (!result) { - args.GetReturnValue().Set(v8::Undefined()); + args.GetReturnValue().Set(v8::Undefined(isolate)); return; } - args.GetReturnValue().Set(v8::String::New(proxy.c_str())); + args.GetReturnValue().Set(v8::String::NewFromUtf8(isolate, proxy.c_str())); return; } scoped_ptr value_args( - converter->FromV8Value(args[2], v8::Context::GetCurrent())); + converter->FromV8Value(args[2], isolate->GetCurrentContext())); if (!value_args.get() || !value_args->IsType(base::Value::TYPE_LIST)) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New( + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to convert 'args' passed to CallStaticMethodSync")))); return; } @@ -465,7 +481,7 @@ void DispatcherBindings::CallStaticMethodSync( method, *static_cast(value_args.get()), &result)); - args.GetReturnValue().Set(converter->ToV8Value(&result, v8::Context::GetCurrent())); + args.GetReturnValue().Set(converter->ToV8Value(&result, isolate->GetCurrentContext())); } } // namespace nwapi diff --git a/src/api/dispatcher_bindings.h b/src/api/dispatcher_bindings.h index f20d600f09..ecdca424d5 100644 --- a/src/api/dispatcher_bindings.h +++ b/src/api/dispatcher_bindings.h @@ -34,7 +34,9 @@ class DispatcherBindings : public v8::Extension { // v8::Extension implementation. virtual v8::Handle - GetNativeFunction(v8::Handle name) OVERRIDE; + GetNativeFunctionTemplate( + v8::Isolate* isolate, + v8::Handle name) OVERRIDE; private: // Helper functions for bindings. diff --git a/src/api/shell/shell.cc b/src/api/shell/shell.cc index b393f7b1f0..ff00722667 100644 --- a/src/api/shell/shell.cc +++ b/src/api/shell/shell.cc @@ -36,15 +36,15 @@ void Shell::Call(const std::string& method, if (method == "OpenExternal") { std::string uri; arguments.GetString(0, &uri); - platform_util::OpenExternal(GURL(uri)); + platform_util::OpenExternal(NULL, GURL(uri)); } else if (method == "OpenItem") { std::string full_path; arguments.GetString(0, &full_path); - platform_util::OpenItem(FilePath::FromUTF8Unsafe(full_path)); + platform_util::OpenItem(NULL, FilePath::FromUTF8Unsafe(full_path)); } else if (method == "ShowItemInFolder") { std::string full_path; arguments.GetString(0, &full_path); - platform_util::ShowItemInFolder(FilePath::FromUTF8Unsafe(full_path)); + platform_util::ShowItemInFolder(NULL, FilePath::FromUTF8Unsafe(full_path)); } else { NOTREACHED() << "Calling unknown method " << method << " of Shell"; } diff --git a/src/api/window/window.cc b/src/api/window/window.cc index 0679c04e5a..d2c3160648 100644 --- a/src/api/window/window.cc +++ b/src/api/window/window.cc @@ -139,8 +139,8 @@ PopulateCookieObject(const net::CanonicalCookie& canonical_cookie) { base::DictionaryValue* result = new base::DictionaryValue(); // A cookie is a raw byte sequence. By explicitly parsing it as UTF-8, we // apply error correction, so the string can be safely passed to the renderer. - result->SetString("name", UTF16ToUTF8(UTF8ToUTF16(canonical_cookie.Name()))); - result->SetString("value", UTF16ToUTF8(UTF8ToUTF16(canonical_cookie.Value()))); + result->SetString("name", base::UTF16ToUTF8(base::UTF8ToUTF16(canonical_cookie.Name()))); + result->SetString("value", base::UTF16ToUTF8(base::UTF8ToUTF16(canonical_cookie.Value()))); result->SetString("domain", canonical_cookie.Domain()); result->SetBoolean("host_only", net::cookie_util::DomainIsHostOnly( canonical_cookie.Domain())); diff --git a/src/api/window_bindings.cc b/src/api/window_bindings.cc index 466a4eeca5..d6436623f1 100644 --- a/src/api/window_bindings.cc +++ b/src/api/window_bindings.cc @@ -32,6 +32,7 @@ using namespace WebCore; #include #endif +#undef FROM_HERE #include "third_party/WebKit/Source/config.h" #include "third_party/WebKit/Source/core/html/HTMLIFrameElement.h" @@ -43,8 +44,8 @@ using namespace WebCore; #undef CHECK #include "V8HTMLIFrameElement.h" -using WebKit::WebScriptSource; -using WebKit::WebFrame; +using blink::WebScriptSource; +using blink::WebFrame; namespace nwapi { @@ -62,30 +63,33 @@ WindowBindings::~WindowBindings() { } v8::Handle -WindowBindings::GetNativeFunction(v8::Handle name) { - if (name->Equals(v8::String::New("BindToShell"))) - return v8::FunctionTemplate::New(BindToShell); - else if (name->Equals(v8::String::New("CallObjectMethod"))) - return v8::FunctionTemplate::New(CallObjectMethod); - else if (name->Equals(v8::String::New("CallObjectMethodSync"))) - return v8::FunctionTemplate::New(CallObjectMethodSync); - else if (name->Equals(v8::String::New("GetWindowObject"))) - return v8::FunctionTemplate::New(GetWindowObject); - else if (name->Equals(v8::String::New("AllocateId"))) - return v8::FunctionTemplate::New(AllocateId); - - return v8::FunctionTemplate::New(); +WindowBindings::GetNativeFunctionTemplate( + v8::Isolate* isolate, + v8::Handle name) { + if (name->Equals(v8::String::NewFromUtf8(isolate, "BindToShell"))) + return v8::FunctionTemplate::New(isolate, BindToShell); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "CallObjectMethod"))) + return v8::FunctionTemplate::New(isolate, CallObjectMethod); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "CallObjectMethodSync"))) + return v8::FunctionTemplate::New(isolate, CallObjectMethodSync); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetWindowObject"))) + return v8::FunctionTemplate::New(isolate, GetWindowObject); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "AllocateId"))) + return v8::FunctionTemplate::New(isolate, AllocateId); + + return v8::FunctionTemplate::New(isolate); } // static void WindowBindings::BindToShell(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); int routing_id = args[0]->Int32Value(); int object_id = args[1]->Int32Value(); - remote::AllocateObject(routing_id, object_id, "Window", v8::Object::New()); + remote::AllocateObject(routing_id, object_id, "Window", v8::Object::New(isolate)); - args.GetReturnValue().Set(v8::Undefined()); + args.GetReturnValue().Set(v8::Undefined(isolate)); } void @@ -99,9 +103,10 @@ WindowBindings::AllocateId(const v8::FunctionCallbackInfo& args) { // static void WindowBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::Local self = args[0]->ToObject(); - int routing_id = self->Get(v8::String::New("routing_id"))->Int32Value(); - int object_id = self->Get(v8::String::New("id"))->Int32Value(); + int routing_id = self->Get(v8::String::NewFromUtf8(isolate, "routing_id"))->Int32Value(); + int object_id = self->Get(v8::String::NewFromUtf8(isolate, "id"))->Int32Value(); std::string method = *v8::String::Utf8Value(args[1]); content::RenderViewImpl* render_view = static_cast( content::RenderViewImpl::FromRoutingID(routing_id)); @@ -110,7 +115,7 @@ WindowBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args if (!render_view) { std::string msg = "Unable to get render view in " + method; - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New(msg.c_str())))); + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, msg.c_str())))); return; } @@ -123,7 +128,7 @@ WindowBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args web_frame = main_frame; }else{ WebCore::HTMLIFrameElement* iframe = WebCore::V8HTMLIFrameElement::toNative(frm); - web_frame = WebKit::WebFrameImpl::fromFrame(iframe->contentFrame()); + web_frame = blink::WebFrameImpl::fromFrame(iframe->contentFrame()); } #if defined(OS_WIN) base::string16 jscript((WCHAR*)*v8::String::Value(args[3])); @@ -141,9 +146,9 @@ WindowBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args main_frame->setDevtoolsJail(NULL); }else{ WebCore::HTMLIFrameElement* iframe = WebCore::V8HTMLIFrameElement::toNative(frm); - main_frame->setDevtoolsJail(WebKit::WebFrameImpl::fromFrame(iframe->contentFrame())); + main_frame->setDevtoolsJail(blink::WebFrameImpl::fromFrame(iframe->contentFrame())); } - args.GetReturnValue().Set(v8::Undefined()); + args.GetReturnValue().Set(v8::Undefined(isolate)); return; } @@ -155,31 +160,32 @@ WindowBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args // static void WindowBindings::CallObjectMethodSync(const v8::FunctionCallbackInfo& args) { - v8::HandleScope scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::EscapableHandleScope scope(isolate); v8::Local self = args[0]->ToObject(); - int routing_id = self->Get(v8::String::New("routing_id"))->Int32Value(); - int object_id = self->Get(v8::String::New("id"))->Int32Value(); + int routing_id = self->Get(v8::String::NewFromUtf8(isolate, "routing_id"))->Int32Value(); + int object_id = self->Get(v8::String::NewFromUtf8(isolate, "id"))->Int32Value(); std::string method = *v8::String::Utf8Value(args[1]); content::RenderViewImpl* render_view = static_cast( content::RenderViewImpl::FromRoutingID(routing_id)); if (!render_view) { std::string msg = "Unable to get render view in " + method; - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New(msg.c_str())))); + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, msg.c_str())))); return; } if (method == "GetZoomLevel") { float zoom_level = render_view->GetWebView()->zoomLevel(); - v8::Local array = v8::Array::New(); - array->Set(0, v8::Number::New(zoom_level)); - args.GetReturnValue().Set(scope.Close(array)); + v8::Local array = v8::Array::New(isolate); + array->Set(0, v8::Number::New(isolate, zoom_level)); + args.GetReturnValue().Set(scope.Escape(array)); return; }else if (method == "SetZoomLevel") { double zoom_level = args[2]->ToNumber()->Value(); render_view->OnSetZoomLevel(zoom_level); - args.GetReturnValue().Set(v8::Undefined()); + args.GetReturnValue().Set(v8::Undefined(isolate)); return; } args.GetReturnValue().Set(remote::CallObjectMethodSync(routing_id, object_id, "Window", method, args[2])); @@ -188,13 +194,14 @@ WindowBindings::CallObjectMethodSync(const v8::FunctionCallbackInfo& // static void WindowBindings::GetWindowObject(const v8::FunctionCallbackInfo& args) { + v8::Isolate* isolate = v8::Isolate::GetCurrent(); int routing_id = args[0]->Int32Value(); // Dark magic to digg out the RenderView from its id. content::RenderViewImpl* render_view = static_cast( content::RenderViewImpl::FromRoutingID(routing_id)); if (!render_view) { - args.GetReturnValue().Set(v8::ThrowException(v8::Exception::Error(v8::String::New("Unable to get render view in GetWindowObject")))); + args.GetReturnValue().Set(isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "Unable to get render view in GetWindowObject")))); return; } // Return the window object. diff --git a/src/api/window_bindings.h b/src/api/window_bindings.h index d141363944..4e2fddca32 100644 --- a/src/api/window_bindings.h +++ b/src/api/window_bindings.h @@ -34,7 +34,9 @@ class WindowBindings : public v8::Extension { // v8::Extension implementation. virtual v8::Handle - GetNativeFunction(v8::Handle name) OVERRIDE; + GetNativeFunctionTemplate( + v8::Isolate* isolate, + v8::Handle name) OVERRIDE; private: static void AllocateId(const v8::FunctionCallbackInfo& args); diff --git a/src/breakpad_linux.cc b/src/breakpad_linux.cc index 0d3d40d3d9..d9d7a3e339 100644 --- a/src/breakpad_linux.cc +++ b/src/breakpad_linux.cc @@ -25,6 +25,7 @@ #include "base/base_switches.h" #include "base/command_line.h" #include "base/debug/crash_logging.h" +#include "base/debug/dump_without_crashing.h" #include "base/files/file_path.h" #include "base/linux_util.h" #include "base/path_service.h" @@ -1384,7 +1385,7 @@ void InitCrashReporter() { SetProcessStartTime(); - breakpad::GetBreakpadClient()->SetDumpWithoutCrashingFunction(&DumpProcess); + base::debug::SetDumpWithoutCrashingFunction(&DumpProcess); #if defined(ADDRESS_SANITIZER) // Register the callback for AddressSanitizer error reporting. __asan_set_error_report_callback(AsanLinuxBreakpadCallback); diff --git a/src/browser/capture_page_helper.cc b/src/browser/capture_page_helper.cc index 3771d1200c..a62634c1a1 100644 --- a/src/browser/capture_page_helper.cc +++ b/src/browser/capture_page_helper.cc @@ -88,7 +88,7 @@ void CapturePageHelper::StartCapturePage(const std::string& image_format_str) { gfx::Rect(), view->GetViewBounds().size(), base::Bind(&CapturePageHelper::CopyFromBackingStoreComplete, - this)); + this), SkBitmap::kARGB_8888_Config); } void CapturePageHelper::CopyFromBackingStoreComplete( diff --git a/src/browser/file_select_helper.cc b/src/browser/file_select_helper.cc index 7b6edfa2f9..100495d741 100644 --- a/src/browser/file_select_helper.cc +++ b/src/browser/file_select_helper.cc @@ -241,7 +241,7 @@ void FileSelectHelper::OnListDone(int id, int error) { scoped_ptr FileSelectHelper::GetFileTypesFromAcceptType( - const std::vector& accept_types) { + const std::vector& accept_types) { scoped_ptr base_file_type( new ui::SelectFileDialog::FileTypeInfo()); if (accept_types.empty()) @@ -474,7 +474,7 @@ bool FileSelectHelper::IsAcceptTypeValid(const std::string& accept_type) { std::string unused; if (accept_type.length() <= 1 || StringToLowerASCII(accept_type) != accept_type || - TrimWhitespaceASCII(accept_type, TRIM_ALL, &unused) != TRIM_NONE) { + base::TrimWhitespaceASCII(accept_type, base::TRIM_ALL, &unused) != base::TRIM_NONE) { return false; } return true; diff --git a/src/browser/file_select_helper.h b/src/browser/file_select_helper.h index 6f1c977be2..e488a4ad1b 100644 --- a/src/browser/file_select_helper.h +++ b/src/browser/file_select_helper.h @@ -146,7 +146,7 @@ class FileSelectHelper // |accept_types| contains only valid lowercased MIME types or file extensions // beginning with a period (.). scoped_ptr GetFileTypesFromAcceptType( - const std::vector& accept_types); + const std::vector& accept_types); // Check the accept type is valid. It is expected to be all lower case with // no whitespace. diff --git a/src/browser/printing/print_dialog_gtk.cc b/src/browser/printing/print_dialog_gtk.cc index 11ca278c76..2d6cdf7c25 100644 --- a/src/browser/printing/print_dialog_gtk.cc +++ b/src/browser/printing/print_dialog_gtk.cc @@ -122,12 +122,12 @@ class GtkPrinterList { // static printing::PrintDialogGtkInterface* PrintDialogGtk::CreatePrintDialog( - PrintingContextGtk* context) { + PrintingContextLinux* context) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); return new PrintDialogGtk(context); } -PrintDialogGtk::PrintDialogGtk(PrintingContextGtk* context) +PrintDialogGtk::PrintDialogGtk(PrintingContextLinux* context) : context_(context), dialog_(NULL), gtk_settings_(NULL), @@ -232,7 +232,7 @@ bool PrintDialogGtk::UpdateSettings(printing::PrintSettings* settings) { void PrintDialogGtk::ShowDialog( gfx::NativeView parent_view, bool has_selection, - const PrintingContextGtk::PrintSettingsCallback& callback) { + const PrintingContextLinux::PrintSettingsCallback& callback) { callback_ = callback; GtkWindow* parent = GTK_WINDOW(gtk_widget_get_toplevel(parent_view)); @@ -266,7 +266,7 @@ void PrintDialogGtk::ShowDialog( } void PrintDialogGtk::PrintDocument(const printing::Metafile* metafile, - const string16& document_name) { + const base::string16& document_name) { // This runs on the print worker thread, does not block the UI thread. DCHECK(!BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -275,7 +275,7 @@ void PrintDialogGtk::PrintDocument(const printing::Metafile* metafile, AddRef(); bool error = false; - if (!file_util::CreateTemporaryFile(&path_to_pdf_)) { + if (!base::CreateTemporaryFile(&path_to_pdf_)) { LOG(ERROR) << "Creating temporary file failed"; error = true; } @@ -365,13 +365,13 @@ void PrintDialogGtk::OnResponse(GtkWidget* dialog, int response_id) { printing::PrintSettingsInitializerGtk::InitPrintSettings( gtk_settings_, page_setup_, &settings); context_->InitWithSettings(settings); - callback_.Run(PrintingContextGtk::OK); + callback_.Run(PrintingContextLinux::OK); callback_.Reset(); return; } case GTK_RESPONSE_DELETE_EVENT: // Fall through. case GTK_RESPONSE_CANCEL: { - callback_.Run(PrintingContextGtk::CANCEL); + callback_.Run(PrintingContextLinux::CANCEL); callback_.Reset(); return; } @@ -382,7 +382,7 @@ void PrintDialogGtk::OnResponse(GtkWidget* dialog, int response_id) { } } -void PrintDialogGtk::SendDocumentToPrinter(const string16& document_name) { +void PrintDialogGtk::SendDocumentToPrinter(const base::string16& document_name) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // If |printer_| is NULL then somehow the GTK printer list changed out under diff --git a/src/browser/printing/print_dialog_gtk.h b/src/browser/printing/print_dialog_gtk.h index 06a14c79be..1eb385cc30 100644 --- a/src/browser/printing/print_dialog_gtk.h +++ b/src/browser/printing/print_dialog_gtk.h @@ -14,7 +14,7 @@ #include "base/sequenced_task_runner_helpers.h" #include "content/public/browser/browser_thread.h" #include "printing/print_dialog_gtk_interface.h" -#include "printing/printing_context_gtk.h" +#include "printing/printing_context_linux.h" #include "ui/base/gtk/gtk_signal.h" namespace printing { @@ -22,7 +22,7 @@ class Metafile; class PrintSettings; } -using printing::PrintingContextGtk; +using printing::PrintingContextLinux; // Needs to be freed on the UI thread to clean up its GTK members variables. class PrintDialogGtk @@ -32,7 +32,7 @@ class PrintDialogGtk public: // Creates and returns a print dialog. static printing::PrintDialogGtkInterface* CreatePrintDialog( - PrintingContextGtk* context); + PrintingContextLinux* context); // printing::PrintDialogGtkInterface implementation. virtual void UseDefaultSettings() OVERRIDE; @@ -42,9 +42,9 @@ class PrintDialogGtk virtual void ShowDialog( gfx::NativeView parent_view, bool has_selection, - const PrintingContextGtk::PrintSettingsCallback& callback) OVERRIDE; + const PrintingContextLinux::PrintSettingsCallback& callback) OVERRIDE; virtual void PrintDocument(const printing::Metafile* metafile, - const string16& document_name) OVERRIDE; + const base::string16& document_name) OVERRIDE; virtual void AddRefToDialog() OVERRIDE; virtual void ReleaseDialog() OVERRIDE; @@ -53,14 +53,14 @@ class PrintDialogGtk content::BrowserThread::UI>; friend class base::DeleteHelper; - explicit PrintDialogGtk(PrintingContextGtk* context); + explicit PrintDialogGtk(PrintingContextLinux* context); virtual ~PrintDialogGtk(); // Handles dialog response. CHROMEGTK_CALLBACK_1(PrintDialogGtk, void, OnResponse, int); // Prints document named |document_name|. - void SendDocumentToPrinter(const string16& document_name); + void SendDocumentToPrinter(const base::string16& document_name); // Handles print job response. static void OnJobCompletedThunk(GtkPrintJob* print_job, @@ -74,8 +74,8 @@ class PrintDialogGtk printing::PrintSettings* settings); // Printing dialog callback. - PrintingContextGtk::PrintSettingsCallback callback_; - PrintingContextGtk* context_; + PrintingContextLinux::PrintSettingsCallback callback_; + PrintingContextLinux* context_; // Print dialog settings. PrintDialogGtk owns |dialog_| and holds references // to the other objects. diff --git a/src/browser/printing/print_job.cc b/src/browser/printing/print_job.cc index d8e5cb79bd..d7dfbedc2d 100644 --- a/src/browser/printing/print_job.cc +++ b/src/browser/printing/print_job.cc @@ -38,10 +38,7 @@ PrintJob::PrintJob() settings_(), is_job_pending_(false), is_canceling_(false), - is_stopping_(false), - is_stopped_(false), - quit_factory_(this), - weak_ptr_factory_(this) { + quit_factory_(this) { DCHECK(ui_message_loop_); // This is normally a UI message loop, but in unit tests, the message loop is // of the 'default' type. @@ -164,16 +161,12 @@ void PrintJob::Stop() { // Be sure to live long enough. scoped_refptr handle(this); - MessageLoop* worker_loop = worker_->message_loop(); - if (worker_loop) { + if (worker_->message_loop()) { ControlledWorkerShutdown(); - - is_job_pending_ = false; - registrar_.Remove(this, content::NOTIFICATION_PRINT_JOB_EVENT, - content::Source(this)); + } else { + // Flush the cached document. + UpdatePrintedDocument(NULL); } - // Flush the cached document. - UpdatePrintedDocument(NULL); } void PrintJob::Cancel() { @@ -225,14 +218,6 @@ bool PrintJob::is_job_pending() const { return is_job_pending_; } -bool PrintJob::is_stopping() const { - return is_stopping_; -} - -bool PrintJob::is_stopped() const { - return is_stopped_; -} - PrintedDocument* PrintJob::document() const { return document_.get(); } @@ -326,53 +311,32 @@ void PrintJob::ControlledWorkerShutdown() { // deadlock is eliminated. worker_->StopSoon(); - // Run a tight message loop until the worker terminates. It may seems like a - // hack but I see no other way to get it to work flawlessly. The issues here - // are: - // - We don't want to run tasks while the thread is quitting. - // - We want this code path to wait on the thread to quit before continuing. - MSG msg; - HANDLE thread_handle = worker_->thread_handle().platform_handle(); - for (; thread_handle;) { - // Note that we don't do any kind of message prioritization since we don't - // execute any pending task or timer. - DWORD result = MsgWaitForMultipleObjects(1, &thread_handle, - FALSE, INFINITE, QS_ALLINPUT); - if (result == WAIT_OBJECT_0 + 1) { - while (PeekMessage(&msg, NULL, 0, 0, TRUE) > 0) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - // Continue looping. - } else if (result == WAIT_OBJECT_0) { - // The thread quit. - break; - } else { - // An error occurred. Assume the thread quit. - NOTREACHED(); - break; - } + // Delay shutdown until the worker terminates. We want this code path + // to wait on the thread to quit before continuing. + if (worker_->IsRunning()) { + base::MessageLoop::current()->PostDelayedTask( + FROM_HERE, + base::Bind(&PrintJob::ControlledWorkerShutdown, this), + base::TimeDelta::FromMilliseconds(100)); + return; } #endif // Now make sure the thread object is cleaned up. Do this on a worker // thread because it may block. - is_stopping_ = true; - base::WorkerPool::PostTaskAndReply( FROM_HERE, - base::Bind(&PrintJobWorker::Stop, - base::Unretained(worker_.get())), - base::Bind(&PrintJob::HoldUntilStopIsCalled, - weak_ptr_factory_.GetWeakPtr(), - scoped_refptr(this)), + base::Bind(&PrintJobWorker::Stop, base::Unretained(worker_.get())), + base::Bind(&PrintJob::HoldUntilStopIsCalled, this), false); + + is_job_pending_ = false; + registrar_.RemoveAll(); + UpdatePrintedDocument(NULL); } -void PrintJob::HoldUntilStopIsCalled(const scoped_refptr&) { - is_stopped_ = true; - is_stopping_ = false; +void PrintJob::HoldUntilStopIsCalled() { } void PrintJob::Quit() { @@ -391,12 +355,8 @@ JobEventDetails::JobEventDetails(Type type, JobEventDetails::~JobEventDetails() { } -PrintedDocument* JobEventDetails::document() const { - return document_; -} +PrintedDocument* JobEventDetails::document() const { return document_.get(); } -PrintedPage* JobEventDetails::page() const { - return page_; -} +PrintedPage* JobEventDetails::page() const { return page_.get(); } } // namespace printing diff --git a/src/browser/printing/print_job.h b/src/browser/printing/print_job.h index 35c3f7bc35..6b20bf40ba 100644 --- a/src/browser/printing/print_job.h +++ b/src/browser/printing/print_job.h @@ -88,12 +88,6 @@ class PrintJob : public PrintJobWorkerOwner, // and the end of the spooling. bool is_job_pending() const; - // Returns true if the worker thread is in the process of stopping. - bool is_stopping() const; - - // Returns true if the worker thread has stopped. - bool is_stopped() const; - // Access the current printed document. Warning: may be NULL. PrintedDocument* document() const; @@ -118,7 +112,7 @@ class PrintJob : public PrintJobWorkerOwner, // Called at shutdown when running a nested message loop. void Quit(); - void HoldUntilStopIsCalled(const scoped_refptr& job); + void HoldUntilStopIsCalled(); content::NotificationRegistrar registrar_; @@ -148,17 +142,9 @@ class PrintJob : public PrintJobWorkerOwner, // the notified calls Cancel() again. bool is_canceling_; - // Is the worker thread stopping. - bool is_stopping_; - - // Is the worker thread stopped. - bool is_stopped_; - // Used at shutdown so that we can quit a nested message loop. base::WeakPtrFactory quit_factory_; - base::WeakPtrFactory weak_ptr_factory_; - DISALLOW_COPY_AND_ASSIGN(PrintJob); }; diff --git a/src/browser/printing/print_job_worker.cc b/src/browser/printing/print_job_worker.cc index 8f86529e68..5e4ed1ed15 100644 --- a/src/browser/printing/print_job_worker.cc +++ b/src/browser/printing/print_job_worker.cc @@ -22,6 +22,7 @@ #include "printing/print_job_constants.h" #include "printing/printed_document.h" #include "printing/printed_page.h" +#include "printing/printing_utils.h" #include "ui/base/l10n/l10n_util.h" using content::BrowserThread; @@ -117,7 +118,7 @@ void PrintJobWorker::GetSettings( } } -void PrintJobWorker::SetSettings(const DictionaryValue* const new_settings) { +void PrintJobWorker::SetSettings(const base::DictionaryValue* const new_settings) { DCHECK_EQ(message_loop(), MessageLoop::current()); BrowserThread::PostTask( @@ -128,13 +129,13 @@ void PrintJobWorker::SetSettings(const DictionaryValue* const new_settings) { } void PrintJobWorker::UpdatePrintSettings( - const DictionaryValue* const new_settings) { + const base::DictionaryValue* const new_settings) { // Create new PageRanges based on |new_settings|. PageRanges new_ranges; - const ListValue* page_range_array; + const base::ListValue* page_range_array; if (new_settings->GetList(kSettingPageRange, &page_range_array)) { for (size_t index = 0; index < page_range_array->GetSize(); ++index) { - const DictionaryValue* dict; + const base::DictionaryValue* dict; if (!page_range_array->GetDictionary(index, &dict)) continue; @@ -216,10 +217,10 @@ void PrintJobWorker::StartPrinting(PrintedDocument* new_document) { return; } - string16 document_name = - printing::PrintBackend::SimplifyDocumentTitle(document_->name()); + base::string16 document_name = + printing::SimplifyDocumentTitle(document_->name()); if (document_name.empty()) { - document_name = printing::PrintBackend::SimplifyDocumentTitle( + document_name = printing::SimplifyDocumentTitle( l10n_util::GetStringUTF16(IDS_DEFAULT_PRINT_DOCUMENT_TITLE)); } PrintingContext::Result result = diff --git a/src/browser/printing/print_view_manager.cc b/src/browser/printing/print_view_manager.cc index 3d71ec9513..8600e01c13 100644 --- a/src/browser/printing/print_view_manager.cc +++ b/src/browser/printing/print_view_manager.cc @@ -136,8 +136,8 @@ void PrintViewManager::RenderProcessGone(base::TerminationStatus status) { } } -string16 PrintViewManager::RenderSourceName() { - string16 name(web_contents()->GetTitle()); +base::string16 PrintViewManager::RenderSourceName() { + base::string16 name(web_contents()->GetTitle()); if (name.empty()) name = l10n_util::GetStringUTF16(IDS_DEFAULT_PRINT_DOCUMENT_TITLE); return name; diff --git a/src/browser/printing/print_view_manager.h b/src/browser/printing/print_view_manager.h index 1670573ba9..6d2898f060 100644 --- a/src/browser/printing/print_view_manager.h +++ b/src/browser/printing/print_view_manager.h @@ -59,7 +59,7 @@ class PrintViewManager : public content::NotificationObserver, void set_observer(PrintViewManagerObserver* observer); // PrintedPagesSource implementation. - virtual string16 RenderSourceName() OVERRIDE; + virtual base::string16 RenderSourceName() OVERRIDE; // content::NotificationObserver implementation. virtual void Observe(int type, diff --git a/src/browser/printing/printer_query.cc b/src/browser/printing/printer_query.cc index 425baaf29e..3bcfb8eb84 100644 --- a/src/browser/printing/printer_query.cc +++ b/src/browser/printing/printer_query.cc @@ -95,7 +95,7 @@ void PrinterQuery::GetSettings( margin_type)); } -void PrinterQuery::SetSettings(const DictionaryValue& new_settings, +void PrinterQuery::SetSettings(const base::DictionaryValue& new_settings, const base::Closure& callback) { StartWorker(callback); diff --git a/src/browser/printing/printing_message_filter.cc b/src/browser/printing/printing_message_filter.cc index 7a1a88f721..08606ac886 100644 --- a/src/browser/printing/printing_message_filter.cc +++ b/src/browser/printing/printing_message_filter.cc @@ -77,7 +77,7 @@ void RenderParamsFromPrintSettings(const printing::PrintSettings& settings, } // namespace PrintingMessageFilter::PrintingMessageFilter(int render_process_id) - : print_job_manager_(NULL), + : BrowserMessageFilter(PrintMsgStart), print_job_manager_(NULL), render_process_id_(render_process_id) { content::ShellContentBrowserClient* browser_client = @@ -344,8 +344,8 @@ void PrintingMessageFilter::OnScriptedPrintReply( } void PrintingMessageFilter::OnUpdatePrintSettings( - int document_cookie, const DictionaryValue& job_settings, - IPC::Message* reply_msg) { + int document_cookie, const base::DictionaryValue& job_settings, + IPC::Message* reply_msg) { scoped_refptr printer_query; print_job_manager_->PopPrinterQuery(document_cookie, &printer_query); diff --git a/src/browser/shell_devtools_delegate.cc b/src/browser/shell_devtools_delegate.cc index b0caa9d698..febfb0b9b5 100644 --- a/src/browser/shell_devtools_delegate.cc +++ b/src/browser/shell_devtools_delegate.cc @@ -114,7 +114,7 @@ Target::Target(WebContents* web_contents) { id_ = agent_host_->GetId(); title_ = UTF16ToUTF8(web_contents->GetTitle()); url_ = web_contents->GetURL(); - last_activity_time_ = web_contents->GetLastSelectedTime(); + last_activity_time_ = web_contents->GetLastActiveTime(); } bool Target::Activate() const { diff --git a/src/browser/shell_download_manager_delegate.cc b/src/browser/shell_download_manager_delegate.cc index 1b2910a31f..b40fd7924f 100644 --- a/src/browser/shell_download_manager_delegate.cc +++ b/src/browser/shell_download_manager_delegate.cc @@ -87,7 +87,7 @@ bool ShellDownloadManagerDelegate::DetermineDownloadTarget( FilePath generated_name = net::GenerateFileName( download->GetURL(), download->GetContentDisposition(), - EmptyString(), + base::EmptyString(), download->GetSuggestedFilename(), download->GetMimeType(), "download"); @@ -109,7 +109,7 @@ void ShellDownloadManagerDelegate::GenerateFilename( const FilePath& suggested_directory) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); if (!base::PathExists(suggested_directory)) - file_util::CreateDirectory(suggested_directory); + base::CreateDirectory(suggested_directory); FilePath suggested_path(suggested_directory.Append(generated_name)); BrowserThread::PostTask( diff --git a/src/browser/shell_javascript_dialog.h b/src/browser/shell_javascript_dialog.h index 2ed17fb235..1057f6526b 100644 --- a/src/browser/shell_javascript_dialog.h +++ b/src/browser/shell_javascript_dialog.h @@ -45,8 +45,8 @@ class ShellJavaScriptDialog { ShellJavaScriptDialogCreator* creator, gfx::NativeWindow parent_window, JavaScriptMessageType message_type, - const string16& message_text, - const string16& default_prompt_text, + const base::string16& message_text, + const base::string16& default_prompt_text, const JavaScriptDialogManager::DialogClosedCallback& callback); ~ShellJavaScriptDialog(); @@ -62,8 +62,8 @@ class ShellJavaScriptDialog { #elif defined(OS_WIN) JavaScriptMessageType message_type_; HWND dialog_win_; - string16 message_text_; - string16 default_prompt_text_; + base::string16 message_text_; + base::string16 default_prompt_text_; static INT_PTR CALLBACK DialogProc(HWND dialog, UINT message, WPARAM wparam, LPARAM lparam); #elif defined(TOOLKIT_GTK) diff --git a/src/browser/shell_javascript_dialog_creator.cc b/src/browser/shell_javascript_dialog_creator.cc index fe1235b42b..4c176b2a1e 100644 --- a/src/browser/shell_javascript_dialog_creator.cc +++ b/src/browser/shell_javascript_dialog_creator.cc @@ -42,13 +42,13 @@ void ShellJavaScriptDialogCreator::RunJavaScriptDialog( const GURL& origin_url, const std::string& accept_lang, JavaScriptMessageType javascript_message_type, - const string16& message_text, - const string16& default_prompt_text, + const base::string16& message_text, + const base::string16& default_prompt_text, const DialogClosedCallback& callback, bool* did_suppress_message) { if (!dialog_request_callback_.is_null()) { dialog_request_callback_.Run(); - callback.Run(true, string16()); + callback.Run(true, base::string16()); dialog_request_callback_.Reset(); return; } @@ -80,12 +80,12 @@ void ShellJavaScriptDialogCreator::RunJavaScriptDialog( void ShellJavaScriptDialogCreator::RunBeforeUnloadDialog( WebContents* web_contents, - const string16& message_text, + const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) { if (!dialog_request_callback_.is_null()) { dialog_request_callback_.Run(); - callback.Run(true, string16()); + callback.Run(true, base::string16()); dialog_request_callback_.Reset(); return; } @@ -93,13 +93,13 @@ void ShellJavaScriptDialogCreator::RunBeforeUnloadDialog( #if defined(OS_MACOSX) || defined(OS_WIN) || defined(TOOLKIT_GTK) if (dialog_.get()) { // Seriously!? - callback.Run(true, string16()); + callback.Run(true, base::string16()); return; } - string16 new_message_text = + base::string16 new_message_text = message_text + - ASCIIToUTF16("\n\nIs it OK to leave/reload this page?"); + base::ASCIIToUTF16("\n\nIs it OK to leave/reload this page?"); gfx::NativeWindow parent_window = web_contents->GetView()->GetTopLevelNativeWindow(); @@ -108,11 +108,11 @@ void ShellJavaScriptDialogCreator::RunBeforeUnloadDialog( parent_window, JAVASCRIPT_MESSAGE_TYPE_CONFIRM, new_message_text, - string16(), // default_prompt_text + base::string16(), // default_prompt_text callback)); #else // TODO: implement ShellJavaScriptDialog for other platforms, drop this #if - callback.Run(true, string16()); + callback.Run(true, base::string16()); return; #endif } diff --git a/src/browser/shell_javascript_dialog_creator.h b/src/browser/shell_javascript_dialog_creator.h index e22cb31ad9..cddf0510ad 100644 --- a/src/browser/shell_javascript_dialog_creator.h +++ b/src/browser/shell_javascript_dialog_creator.h @@ -25,14 +25,14 @@ class ShellJavaScriptDialogCreator : public JavaScriptDialogManager { const GURL& origin_url, const std::string& accept_lang, JavaScriptMessageType javascript_message_type, - const string16& message_text, - const string16& default_prompt_text, + const base::string16& message_text, + const base::string16& default_prompt_text, const DialogClosedCallback& callback, bool* did_suppress_message) OVERRIDE; virtual void RunBeforeUnloadDialog( WebContents* web_contents, - const string16& message_text, + const base::string16& message_text, bool is_reload, const DialogClosedCallback& callback) OVERRIDE; diff --git a/src/browser/shell_javascript_dialog_gtk.cc b/src/browser/shell_javascript_dialog_gtk.cc index cff5458515..133fc98e0d 100644 --- a/src/browser/shell_javascript_dialog_gtk.cc +++ b/src/browser/shell_javascript_dialog_gtk.cc @@ -35,12 +35,12 @@ const char kPromptTextId[] = "content_shell_prompt_text"; // If there's a text entry in the dialog, get the text from the first one and // return it. -string16 GetPromptText(GtkDialog* dialog) { +base::string16 GetPromptText(GtkDialog* dialog) { GtkWidget* widget = static_cast( g_object_get_data(G_OBJECT(dialog), kPromptTextId)); if (widget) - return UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(widget))); - return string16(); + return base::UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(widget))); + return base::string16(); } } // namespace @@ -52,8 +52,8 @@ ShellJavaScriptDialog::ShellJavaScriptDialog( ShellJavaScriptDialogCreator* creator, gfx::NativeWindow parent_window, JavaScriptMessageType message_type, - const string16& message_text, - const string16& default_prompt_text, + const base::string16& message_text, + const base::string16& default_prompt_text, const JavaScriptDialogManager::DialogClosedCallback& callback) : creator_(creator), callback_(callback), @@ -129,7 +129,7 @@ void ShellJavaScriptDialog::OnResponse(GtkWidget* dialog, int response_id) { break; case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_DELETE_EVENT: - callback_.Run(false, string16()); + callback_.Run(false, base::string16()); break; default: NOTREACHED(); diff --git a/src/browser/shell_login_dialog.cc b/src/browser/shell_login_dialog.cc index b103c5efd0..b531b659a9 100644 --- a/src/browser/shell_login_dialog.cc +++ b/src/browser/shell_login_dialog.cc @@ -1,79 +1,30 @@ -// 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. +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#include "content/nw/src/browser/shell_login_dialog.h" +#include "content/shell/browser/shell_login_dialog.h" #include "base/bind.h" #include "base/logging.h" #include "base/strings/utf_string_conversions.h" -#include "chrome/browser/chrome_notification_types.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/notification_registrar.h" -#include "content/public/browser/notification_service.h" #include "content/public/browser/resource_dispatcher_host.h" -#include "content/public/browser/resource_request_info.h" #include "net/base/auth.h" #include "net/url_request/url_request.h" #include "ui/gfx/text_elider.h" -using content::BrowserThread; -using content::ResourceDispatcherHost; - -namespace { -// Helper to remove the ref from an net::URLRequest to the ShellLoginDialog. -// Should only be called from the IO thread, since it accesses an -// net::URLRequest. -void ResetShellLoginDialogForRequest(net::URLRequest* request) { - ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request); -} - -} // namespace - namespace content { -ShellLoginDialog::ShellLoginDialogList ShellLoginDialog::dialog_queue_; - ShellLoginDialog::ShellLoginDialog( net::AuthChallengeInfo* auth_info, - net::URLRequest* request) - : render_process_id_(0), - render_view_id_(0), - auth_info_(auth_info), - request_(request), - handled_auth_(false) { + net::URLRequest* request) : auth_info_(auth_info), + request_(request) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderView( - &render_process_id_, &render_view_id_)) { - NOTREACHED(); - } - - // prevent object destruction on wrong (IO) thread - // paired with ReleaseSoon() - AddRef(); - BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&ShellLoginDialog::PrepDialog, this, - ASCIIToUTF16(auth_info->challenger.ToString()), - UTF8ToUTF16(auth_info->realm))); + base::ASCIIToUTF16(auth_info->challenger.ToString()), + base::UTF8ToUTF16(auth_info->realm))); } void ShellLoginDialog::OnRequestCancelled() { @@ -83,24 +34,9 @@ void ShellLoginDialog::OnRequestCancelled() { base::Bind(&ShellLoginDialog::PlatformRequestCancelled, this)); } -void ShellLoginDialog::UserAcceptedAuth(const string16& username, - const string16& password) { +void ShellLoginDialog::UserAcceptedAuth(const base::string16& username, + const base::string16& password) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - if (TestAndSetAuthHandled()) - return; - - // Calling NotifyAuthSupplied() directly instead of posting a task - // allows other ShellLoginDialog instances to queue their - // CloseContentsDeferred() before ours. Closing dialogs in the - // opposite order as they were created avoids races where remaining - // dialogs in the same tab may be briefly displayed to the user - // before they are removed. - NotifyAuthSupplied(username, password); - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&ShellLoginDialog::CloseContentsDeferred, this)); BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&ShellLoginDialog::SendAuthToRequester, this, @@ -109,25 +45,13 @@ void ShellLoginDialog::UserAcceptedAuth(const string16& username, void ShellLoginDialog::UserCancelledAuth() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (TestAndSetAuthHandled()) - return; - - // Similar to how we deal with notifications above in SetAuth() - if (BrowserThread::CurrentlyOn(BrowserThread::UI)) { - NotifyAuthCancelled(); - } else { - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&ShellLoginDialog::NotifyAuthCancelled, this)); - } - BrowserThread::PostTask( BrowserThread::IO, FROM_HERE, base::Bind(&ShellLoginDialog::SendAuthToRequester, this, - false, string16(), string16())); + false, base::string16(), base::string16())); BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, - base::Bind(&ShellLoginDialog::CloseContentsDeferred, this)); + base::Bind(&ShellLoginDialog::PlatformCleanUp, this)); } ShellLoginDialog::~ShellLoginDialog() { @@ -135,203 +59,49 @@ ShellLoginDialog::~ShellLoginDialog() { // referenced/dereferenced. } -void ShellLoginDialog::PrepDialog(const string16& host, - const string16& realm) { +#if !defined(OS_MACOSX) && !defined(TOOLKIT_GTK) +// Bogus implementations for linking. They are never called because +// ResourceDispatcherHostDelegate::CreateLoginDelegate returns NULL. +// TODO: implement ShellLoginDialog for other platforms, drop this #if +void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) {} +void ShellLoginDialog::PlatformCleanUp() {} +void ShellLoginDialog::PlatformRequestCancelled() {} +#endif + +void ShellLoginDialog::PrepDialog(const base::string16& host, + const base::string16& realm) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); // The realm is controlled by the remote server, so there is no reason to // believe it is of a reasonable length. - string16 elided_realm; + base::string16 elided_realm; gfx::ElideString(realm, 120, &elided_realm); - string16 explanation = - ASCIIToUTF16("The server ") + host + - ASCIIToUTF16(" requires a username and password."); + base::string16 explanation = + base::ASCIIToUTF16("The server ") + host + + base::ASCIIToUTF16(" requires a username and password."); if (!elided_realm.empty()) { - explanation += ASCIIToUTF16(" The server says: "); + explanation += base::ASCIIToUTF16(" The server says: "); explanation += elided_realm; - explanation += ASCIIToUTF16("."); + explanation += base::ASCIIToUTF16("."); } - AddObservers(); - dialog_queue_.push_back(this); PlatformCreateDialog(explanation); - if (dialog_queue_.size() == 1) - PlatformShowDialog(); -} - -void ShellLoginDialog::HandleQueueOnClose() -{ - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ShellLoginDialogList::iterator i( - std::find(dialog_queue_.begin(), dialog_queue_.end(), this)); - - // Ignore the second invocation. - if (i == dialog_queue_.end()) - return; - - bool removed_topmost_dialog = i == dialog_queue_.begin(); - dialog_queue_.erase(i); - if (!dialog_queue_.empty() && removed_topmost_dialog) { - ShellLoginDialog* next_dlg = dialog_queue_.front(); - next_dlg->PlatformShowDialog(); - } } void ShellLoginDialog::SendAuthToRequester(bool success, - const string16& username, - const string16& password) { + const base::string16& username, + const base::string16& password) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - if (success) { + if (success) request_->SetAuth(net::AuthCredentials(username, password)); - } else + else request_->CancelAuth(); ResourceDispatcherHost::Get()->ClearLoginDelegateForRequest(request_); -} - -void ShellLoginDialog::NotifyAuthSupplied(const string16& username, - const string16& password) { - - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - content::NotificationService* service = - content::NotificationService::current(); - - AuthSuppliedLoginNotificationDetails details(this, username, password); - - service->Notify(chrome::NOTIFICATION_AUTH_SUPPLIED, - content::Source(this), - content::Details(&details)); -} - -void ShellLoginDialog::NotifyAuthCancelled() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(WasAuthHandled()); - - content::NotificationService* service = - content::NotificationService::current(); - - AuthSuppliedLoginNotificationDetails details(this, string16(), string16()); - - service->Notify(chrome::NOTIFICATION_AUTH_CANCELLED, - content::Source(this), - content::Details(&details)); -} - - -void ShellLoginDialog::Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - DCHECK(type == chrome::NOTIFICATION_AUTH_SUPPLIED || - type == chrome::NOTIFICATION_AUTH_CANCELLED); - - // Break out early if we aren't interested in the notification. - if (WasAuthHandled()) - return; - - LoginNotificationDetails* login_details = - content::Details(details).ptr(); - - // WasAuthHandled() should always test positive before we publish - // AUTH_SUPPLIED or AUTH_CANCELLED notifications. - DCHECK(login_details->handler() != this); - - // Only handle notification for the identical auth info. - if (!login_details->handler()->auth_info()->Equals(*auth_info())) - return; - - // Set or cancel the auth in this handler. - if (type == chrome::NOTIFICATION_AUTH_SUPPLIED) { - AuthSuppliedLoginNotificationDetails* supplied_details = - content::Details(details).ptr(); - UserAcceptedAuth(supplied_details->username(), supplied_details->password()); - } else { - DCHECK(type == chrome::NOTIFICATION_AUTH_CANCELLED); - UserCancelledAuth(); - } -} - -// Returns whether authentication had been handled (SetAuth or CancelAuth). -bool ShellLoginDialog::WasAuthHandled() const { - base::AutoLock lock(handled_auth_lock_); - bool was_handled = handled_auth_; - return was_handled; -} - -// Marks authentication as handled and returns the previous handled state. -bool ShellLoginDialog::TestAndSetAuthHandled() { - base::AutoLock lock(handled_auth_lock_); - bool was_handled = handled_auth_; - handled_auth_ = true; - return was_handled; -} - -// Closes the view_contents from the UI loop. -void ShellLoginDialog::CloseContentsDeferred() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - HandleQueueOnClose(); - PlatformCleanUp(); -} - -void ShellLoginDialog::AddObservers() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // This is probably OK; we need to listen to everything and we break out of - // the Observe() if we aren't handling the same auth_info(). - registrar_.reset(new content::NotificationRegistrar); - registrar_->Add(this, chrome::NOTIFICATION_AUTH_SUPPLIED, - content::NotificationService::AllBrowserContextsAndSources()); - registrar_->Add(this, chrome::NOTIFICATION_AUTH_CANCELLED, - content::NotificationService::AllBrowserContextsAndSources()); -} - -void ShellLoginDialog::RemoveObservers() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - registrar_.reset(); -} - -void ShellLoginDialog::ReleaseSoon() { - if (!TestAndSetAuthHandled()) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&ShellLoginDialog::CancelAuthDeferred, this)); - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&ShellLoginDialog::NotifyAuthCancelled, this)); - } BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&ShellLoginDialog::RemoveObservers, this)); - - // Delete this object once all InvokeLaters have been called. - BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this); -} - -// Calls SetAuth from the IO loop. -void ShellLoginDialog::SetAuthDeferred(const string16& username, - const string16& password) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - if (request_) { - request_->SetAuth(net::AuthCredentials(username, password)); - ResetShellLoginDialogForRequest(request_); - } -} - -// Calls CancelAuth from the IO loop. -void ShellLoginDialog::CancelAuthDeferred() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - - if (request_) { - request_->CancelAuth(); - // Verify that CancelAuth doesn't destroy the request via our delegate. - DCHECK(request_ != NULL); - ResetShellLoginDialogForRequest(request_); - } + BrowserThread::UI, FROM_HERE, + base::Bind(&ShellLoginDialog::PlatformCleanUp, this)); } } // namespace content diff --git a/src/browser/shell_login_dialog.h b/src/browser/shell_login_dialog.h index 48f0e617b3..db70cb6e3d 100644 --- a/src/browser/shell_login_dialog.h +++ b/src/browser/shell_login_dialog.h @@ -1,33 +1,12 @@ -// 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_LOGIN_DIALOG_H_ -#define CONTENT_NW_SRC_BROWSER_SHELL_LOGIN_DIALOG_H_ - -#include -#include "base/basictypes.h" +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_SHELL_BROWSER_SHELL_LOGIN_DIALOG_H_ +#define CONTENT_SHELL_BROWSER_SHELL_LOGIN_DIALOG_H_ + #include "base/compiler_specific.h" -#include "base/memory/scoped_ptr.h" #include "base/strings/string16.h" -#include "base/synchronization/lock.h" -#include "content/public/browser/notification_observer.h" #include "content/public/browser/resource_dispatcher_host_login_delegate.h" #if defined(TOOLKIT_GTK) @@ -42,11 +21,6 @@ class ShellLoginDialogHelper; #endif // __OBJC__ #endif // defined(OS_MACOSX) -namespace content { -class RenderViewHostDelegate; -class NotificationRegistrar; -} // namespace content - namespace net { class AuthChallengeInfo; class URLRequest; @@ -56,9 +30,7 @@ namespace content { // This class provides a dialog box to ask the user for credentials. Useful in // ResourceDispatcherHostDelegate::CreateLoginDelegate. -class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate, - public content::NotificationObserver -{ +class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate { public: // Threading: IO thread. ShellLoginDialog(net::AuthChallengeInfo* auth_info, net::URLRequest* request); @@ -71,64 +43,20 @@ class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate, // the aforementioned platform specific code may not have access to private // members. Not to be called from client code. // Threading: UI thread. - void UserAcceptedAuth(const string16& username, const string16& password); + void UserAcceptedAuth(const base::string16& username, + const base::string16& password); void UserCancelledAuth(); - // Implements the content::NotificationObserver interface. - // Listens for AUTH_SUPPLIED and AUTH_CANCELLED notifications from other - // LoginHandlers so that this LoginHandler has the chance to dismiss itself - // if it was waiting for the same authentication. - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; - - // Who/where/what asked for the authentication. - const net::AuthChallengeInfo* auth_info() const { return auth_info_.get(); } - - // Returns whether authentication had been handled (SetAuth or CancelAuth). - bool WasAuthHandled() const; - - // Performs necessary cleanup before deletion. - void ReleaseSoon(); - protected: // Threading: any virtual ~ShellLoginDialog(); - int render_process_id_; - int render_view_id_; - private: - - // popup next dialog in queue on closing of this dialog - void HandleQueueOnClose(); - - // Calls SetAuth from the IO loop. - void SetAuthDeferred(const string16& username, - const string16& password); - - // Calls CancelAuth from the IO loop. - void CancelAuthDeferred(); - - // Closes the view_contents from the UI loop. - void CloseContentsDeferred(); - - // Marks authentication as handled and returns the previous handled - // state. - bool TestAndSetAuthHandled(); - - // Notify observers that authentication is supplied. - void NotifyAuthSupplied(const string16& username, - const string16& password); - - void NotifyAuthCancelled(); // All the methods that begin with Platform need to be implemented by the // platform specific LoginDialog implementation. // Creates the dialog. // Threading: UI thread. - void PlatformCreateDialog(const string16& message); - - void PlatformShowDialog(); + void PlatformCreateDialog(const base::string16& message); // Called from the destructor to let each platform do any necessary cleanup. // Threading: UI thread. void PlatformCleanUp(); @@ -138,19 +66,13 @@ class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate, // Sets up dialog creation. // Threading: UI thread. - void PrepDialog(const string16& host, const string16& realm); + void PrepDialog(const base::string16& host, const base::string16& realm); // Sends the authentication to the requester. // Threading: IO thread. void SendAuthToRequester(bool success, - const string16& username, - const string16& password); - - // Starts observing notifications from other LoginHandlers. - void AddObservers(); - - // Stops observing notifications from other LoginHandlers. - void RemoveObservers(); + const base::string16& username, + const base::string16& password); // Who/where/what asked for the authentication. // Threading: IO thread. @@ -160,77 +82,17 @@ class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate, // Threading: IO thread. net::URLRequest* request_; - // True if we've handled auth (SetAuth or CancelAuth has been called). - bool handled_auth_; - mutable base::Lock handled_auth_lock_; - - // Observes other login handlers so this login handler can respond. - // This is only accessed on the UI thread. - scoped_ptr registrar_; - - typedef std::deque ShellLoginDialogList; - - static ShellLoginDialogList dialog_queue_; - #if defined(OS_MACOSX) // Threading: UI thread. ShellLoginDialogHelper* helper_; // owned - base::string16 message_; -#elif defined(OS_WIN) - HWND dialog_win_; - string16 message_text_; - static INT_PTR CALLBACK DialogProc(HWND dialog, UINT message, WPARAM wparam, - LPARAM lparam); #elif defined(TOOLKIT_GTK) GtkWidget* username_entry_; GtkWidget* password_entry_; GtkWidget* root_; CHROMEGTK_CALLBACK_1(ShellLoginDialog, void, OnResponse, int); - CHROMEGTK_CALLBACK_0(ShellLoginDialog, void, OnDestroy); #endif }; -// Details to provide the content::NotificationObserver. Used by the automation -// proxy for testing. -class LoginNotificationDetails { - public: - explicit LoginNotificationDetails(ShellLoginDialog* handler) - : handler_(handler) {} - ShellLoginDialog* handler() const { return handler_; } - - private: - LoginNotificationDetails() {} - - ShellLoginDialog* handler_; // Where to send the response. - - DISALLOW_COPY_AND_ASSIGN(LoginNotificationDetails); -}; - - -// Details to provide the NotificationObserver. Used by the automation proxy -// for testing and by other LoginHandlers to dismiss themselves when an -// identical auth is supplied. -class AuthSuppliedLoginNotificationDetails : public LoginNotificationDetails { - public: - AuthSuppliedLoginNotificationDetails(ShellLoginDialog* handler, - const string16& username, - const string16& password) - : LoginNotificationDetails(handler), - username_(username), - password_(password) {} - const string16& username() const { return username_; } - const string16& password() const { return password_; } - - private: - // The username that was used for the authentication. - const string16 username_; - - // The password that was used for the authentication. - const string16 password_; - - DISALLOW_COPY_AND_ASSIGN(AuthSuppliedLoginNotificationDetails); -}; - } // namespace content -#endif // CONTENT_NW_SRC_BROWSER_SHELL_LOGIN_DIALOG_H_ +#endif // CONTENT_SHELL_BROWSER_SHELL_LOGIN_DIALOG_H_ diff --git a/src/browser/shell_login_dialog_gtk.cc b/src/browser/shell_login_dialog_gtk.cc index e2a6447966..7ac1f583a0 100644 --- a/src/browser/shell_login_dialog_gtk.cc +++ b/src/browser/shell_login_dialog_gtk.cc @@ -1,24 +1,8 @@ -// 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_login_dialog.h" +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/shell/browser/shell_login_dialog.h" #include @@ -26,7 +10,7 @@ #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/resource_dispatcher_host.h" #include "content/public/browser/resource_request_info.h" #include "content/public/browser/web_contents.h" @@ -35,21 +19,20 @@ namespace content { -void ShellLoginDialog::PlatformCreateDialog(const string16& message) { +void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); int render_process_id; - int render_view_id; - if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderView( - &render_process_id, &render_view_id)) { + int render_frame_id; + if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderFrame( + &render_process_id, &render_frame_id)) { NOTREACHED(); } WebContents* web_contents = NULL; - RenderViewHost* render_view_host = - RenderViewHost::FromID(render_process_id, render_view_id); - if (render_view_host) - web_contents = WebContents::FromRenderViewHost(render_view_host); + RenderFrameHost* render_frame_host = + RenderFrameHost::FromID(render_process_id, render_frame_id); + web_contents = WebContents::FromRenderFrameHost(render_frame_host); DCHECK(web_contents); gfx::NativeWindow parent_window = @@ -62,7 +45,7 @@ void ShellLoginDialog::PlatformCreateDialog(const string16& message) { "Please log in."); GtkWidget* content_area = gtk_dialog_get_content_area(GTK_DIALOG(root_)); - GtkWidget* label = gtk_label_new(UTF16ToUTF8(message).c_str()); + GtkWidget* label = gtk_label_new(base::UTF16ToUTF8(message).c_str()); gtk_label_set_line_wrap(GTK_LABEL(label), TRUE); gtk_box_pack_start(GTK_BOX(content_area), label, FALSE, FALSE, 0); @@ -94,34 +77,24 @@ void ShellLoginDialog::PlatformCreateDialog(const string16& message) { gtk_box_pack_start(GTK_BOX(content_area), table, FALSE, FALSE, 0); g_signal_connect(root_, "response", G_CALLBACK(OnResponseThunk), this); - g_signal_connect(root_, "destroy", G_CALLBACK(OnDestroyThunk), this); - gtk_widget_grab_focus(username_entry_); + gtk_widget_show_all(GTK_WIDGET(root_)); } void ShellLoginDialog::PlatformCleanUp() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (root_) { - gtk_widget_destroy(root_); - root_ = NULL; - } } void ShellLoginDialog::PlatformRequestCancelled() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); } -void ShellLoginDialog::PlatformShowDialog() { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - gtk_widget_show_all(GTK_WIDGET(root_)); -} - void ShellLoginDialog::OnResponse(GtkWidget* sender, int response_id) { switch (response_id) { case GTK_RESPONSE_OK: UserAcceptedAuth( - UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(username_entry_))), - UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(password_entry_)))); + base::UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(username_entry_))), + base::UTF8ToUTF16(gtk_entry_get_text(GTK_ENTRY(password_entry_)))); break; case GTK_RESPONSE_CANCEL: case GTK_RESPONSE_DELETE_EVENT: @@ -131,15 +104,7 @@ void ShellLoginDialog::OnResponse(GtkWidget* sender, int response_id) { NOTREACHED(); } -} - -void ShellLoginDialog::OnDestroy(GtkWidget* widget) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - - // The web contents modal dialog is going to delete itself; clear our pointer. - root_ = NULL; - - ReleaseSoon(); + gtk_widget_destroy(root_); } } // namespace content diff --git a/src/browser/shell_login_dialog_mac.mm b/src/browser/shell_login_dialog_mac.mm index eb4ae0ec0d..3e014e8791 100644 --- a/src/browser/shell_login_dialog_mac.mm +++ b/src/browser/shell_login_dialog_mac.mm @@ -1,24 +1,8 @@ -// 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_login_dialog.h" +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/shell/browser/shell_login_dialog.h" #import @@ -80,14 +64,11 @@ - (void)focus { - (void)alertDidEnd:(NSAlert*)alert returnCode:(int)returnCode contextInfo:(void*)contextInfo { + if (returnCode == NSRunStoppedResponse) + return; content::ShellLoginDialog* this_dialog = reinterpret_cast(contextInfo); - if (returnCode == NSRunStoppedResponse) { - this_dialog->ReleaseSoon(); - return; - } - if (returnCode == NSAlertFirstButtonReturn) { this_dialog->UserAcceptedAuth( base::SysNSStringToUTF16([usernameField_ stringValue]), @@ -106,17 +87,14 @@ - (void)cancel { namespace content { -void ShellLoginDialog::PlatformCreateDialog(const string16& message) { +void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); helper_ = [[ShellLoginDialogHelper alloc] init]; - message_ = message; -} -void ShellLoginDialog::PlatformShowDialog() { // Show the modal dialog. NSAlert* alert = [helper_ alert]; [alert setDelegate:helper_]; - [alert setInformativeText:base::SysUTF16ToNSString(message_)]; + [alert setInformativeText:base::SysUTF16ToNSString(message)]; [alert setMessageText:@"Please log in."]; [alert addButtonWithTitle:@"OK"]; NSButton* other = [alert addButtonWithTitle:@"Cancel"]; @@ -134,7 +112,6 @@ - (void)cancel { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); [helper_ release]; helper_ = nil; - ReleaseSoon(); } void ShellLoginDialog::PlatformRequestCancelled() { diff --git a/src/browser/shell_resource_dispatcher_host_delegate.cc b/src/browser/shell_resource_dispatcher_host_delegate.cc index 2bc22885aa..918df3340b 100644 --- a/src/browser/shell_resource_dispatcher_host_delegate.cc +++ b/src/browser/shell_resource_dispatcher_host_delegate.cc @@ -63,7 +63,7 @@ bool ShellResourceDispatcherHostDelegate::HandleExternalProtocol( BrowserThread::PostTask( BrowserThread::FILE, FROM_HERE, - base::Bind(&platform_util::OpenExternal, url)); + base::Bind(&platform_util::OpenExternal2, url)); #endif return true; diff --git a/src/chrome_breakpad_client.cc b/src/chrome_breakpad_client.cc index f73a28203b..3dff5afbd0 100644 --- a/src/chrome_breakpad_client.cc +++ b/src/chrome_breakpad_client.cc @@ -37,7 +37,7 @@ #endif #if defined(OS_POSIX) -#include "chrome/common/dump_without_crashing.h" +#include "base/debug/dump_without_crashing.h" #endif #if defined(OS_WIN) || defined(OS_MACOSX) @@ -306,12 +306,6 @@ bool ChromeBreakpadClient::GetCrashDumpLocation(base::FilePath* crash_dir) { return PathService::Get(chrome::DIR_CRASH_DUMPS, crash_dir); } -#if defined(OS_POSIX) -void ChromeBreakpadClient::SetDumpWithoutCrashingFunction(void (*function)()) { - logging::SetDumpWithoutCrashingFunction(function); -} -#endif - size_t ChromeBreakpadClient::RegisterCrashKeys() { return crash_keys::RegisterChromeCrashKeys(); } @@ -332,4 +326,13 @@ int ChromeBreakpadClient::GetAndroidMinidumpDescriptor() { } #endif +bool ChromeBreakpadClient::EnableBreakpadForProcess( + const std::string& process_type) { + return process_type == switches::kRendererProcess || + process_type == switches::kPluginProcess || + process_type == switches::kPpapiPluginProcess || + process_type == switches::kZygoteProcess || + process_type == switches::kGpuProcess; +} + } // namespace chrome diff --git a/src/chrome_breakpad_client.h b/src/chrome_breakpad_client.h index 10d09805df..7e79a092e6 100644 --- a/src/chrome_breakpad_client.h +++ b/src/chrome_breakpad_client.h @@ -68,6 +68,9 @@ class ChromeBreakpadClient : public breakpad::BreakpadClient { virtual void InstallAdditionalFilters(BreakpadRef breakpad) OVERRIDE; #endif + virtual bool EnableBreakpadForProcess( + const std::string& process_type) OVERRIDE; + private: DISALLOW_COPY_AND_ASSIGN(ChromeBreakpadClient); }; diff --git a/src/common/print_messages.cc b/src/common/print_messages.cc index d829fb54cd..f4fae5cc88 100644 --- a/src/common/print_messages.cc +++ b/src/common/print_messages.cc @@ -24,7 +24,7 @@ PrintMsg_Print_Params::PrintMsg_Print_Params() preview_ui_id(-1), preview_request_id(0), is_first_request(false), - print_scaling_option(WebKit::WebPrintScalingOptionSourceSize), + print_scaling_option(blink::WebPrintScalingOptionSourceSize), print_to_pdf(false), display_header_footer(false), title(), @@ -50,11 +50,11 @@ void PrintMsg_Print_Params::Reset() { preview_ui_id = -1; preview_request_id = 0; is_first_request = false; - print_scaling_option = WebKit::WebPrintScalingOptionSourceSize; + print_scaling_option = blink::WebPrintScalingOptionSourceSize; print_to_pdf = false; display_header_footer = false; - title = string16(); - url = string16(); + title = base::string16(); + url = base::string16(); should_print_backgrounds = false; } diff --git a/src/common/print_messages.h b/src/common/print_messages.h index d154bff752..4e3f99fab5 100644 --- a/src/common/print_messages.h +++ b/src/common/print_messages.h @@ -42,11 +42,11 @@ struct PrintMsg_Print_Params { int32 preview_ui_id; int preview_request_id; bool is_first_request; - WebKit::WebPrintScalingOption print_scaling_option; + blink::WebPrintScalingOption print_scaling_option; bool print_to_pdf; bool display_header_footer; - string16 title; - string16 url; + base::string16 title; + base::string16 url; bool should_print_backgrounds; }; @@ -75,7 +75,7 @@ struct PrintHostMsg_RequestPrintPreview_Params { #define IPC_MESSAGE_START PrintMsgStart IPC_ENUM_TRAITS(printing::MarginType) -IPC_ENUM_TRAITS(WebKit::WebPrintScalingOption) +IPC_ENUM_TRAITS(blink::WebPrintScalingOption) // Parameters for a render request. IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params) @@ -287,7 +287,7 @@ IPC_MESSAGE_ROUTED0(PrintMsg_PrintNodeUnderContextMenu) // showing the print dialog. (This is the final step in the print preview // workflow.) IPC_MESSAGE_ROUTED1(PrintMsg_PrintForPrintPreview, - DictionaryValue /* settings */) + base::DictionaryValue /* settings */) // Tells the render view to switch the CSS to print media type, renders every // requested pages and switch back the CSS to display media type. @@ -305,7 +305,7 @@ IPC_MESSAGE_ROUTED1(PrintMsg_SetScriptedPrintingBlocked, // requested pages for print preview using the given |settings|. This gets // called multiple times as the user updates settings. IPC_MESSAGE_ROUTED1(PrintMsg_PrintPreview, - DictionaryValue /* settings */) + base::DictionaryValue /* settings */) // Like PrintMsg_PrintPages, but using the print preview document's frame/node. IPC_MESSAGE_ROUTED0(PrintMsg_PrintForSystemDialog) @@ -350,7 +350,7 @@ IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_GetDefaultPrintSettings, // |job_settings|. IPC_SYNC_MESSAGE_ROUTED2_1(PrintHostMsg_UpdatePrintSettings, int /* document_cookie */, - DictionaryValue /* job_settings */, + base::DictionaryValue /* job_settings */, PrintMsg_PrintPages_Params /* current_settings */) // It's the renderer that controls the printing process when it is generated diff --git a/src/geolocation/shell_access_token_store.cc b/src/geolocation/shell_access_token_store.cc index 35e39e1a03..d1c53dc8b7 100644 --- a/src/geolocation/shell_access_token_store.cc +++ b/src/geolocation/shell_access_token_store.cc @@ -44,12 +44,12 @@ void ShellAccessTokenStore::RespondOnOriginatingThread( // Since content_shell is a test executable, rather than an end user program, // we provide a dummy access_token set to avoid hitting the server. AccessTokenSet access_token_set; - access_token_set[GURL()] = ASCIIToUTF16("chromium_content_shell"); + access_token_set[GURL()] = base::ASCIIToUTF16("chromium_content_shell"); callback.Run(access_token_set, system_request_context_); } void ShellAccessTokenStore::SaveAccessToken( - const GURL& server_url, const string16& access_token) { + const GURL& server_url, const base::string16& access_token) { } } // namespace content diff --git a/src/geolocation/shell_access_token_store.h b/src/geolocation/shell_access_token_store.h index 82ee0f888e..205d89ffc9 100644 --- a/src/geolocation/shell_access_token_store.h +++ b/src/geolocation/shell_access_token_store.h @@ -28,7 +28,7 @@ class ShellAccessTokenStore : public content::AccessTokenStore { const LoadAccessTokensCallbackType& callback) OVERRIDE; virtual void SaveAccessToken( - const GURL& server_url, const string16& access_token) OVERRIDE; + const GURL& server_url, const base::string16& access_token) OVERRIDE; content::ShellBrowserContext* shell_browser_context_; net::URLRequestContextGetter* system_request_context_; diff --git a/src/media/media_capture_devices_dispatcher.cc b/src/media/media_capture_devices_dispatcher.cc index 0a4d02ae7e..5e697f6732 100644 --- a/src/media/media_capture_devices_dispatcher.cc +++ b/src/media/media_capture_devices_dispatcher.cc @@ -4,14 +4,16 @@ #include "base/memory/singleton.h" +#include "content/public/browser/media_observer.h" #include "content/nw/src/media/media_capture_devices_dispatcher.h" #include "content/public/browser/browser_thread.h" -#include "content/public/browser/media_devices_monitor.h" +#include "content/public/browser/media_capture_devices.h" #include "content/public/common/media_stream_request.h" using content::BrowserThread; using content::MediaStreamDevices; +using content::MediaCaptureDevices; namespace { @@ -31,28 +33,26 @@ const content::MediaStreamDevice* FindDeviceWithId( } MediaCaptureDevicesDispatcher::MediaCaptureDevicesDispatcher() - : devices_enumerated_(false) {} +{} MediaCaptureDevicesDispatcher::~MediaCaptureDevicesDispatcher() {} -void MediaCaptureDevicesDispatcher::AudioCaptureDevicesChanged( - const MediaStreamDevices& devices) { +void MediaCaptureDevicesDispatcher::OnAudioCaptureDevicesChanged() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, - base::Bind(&MediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread, - this, devices)); + base::Bind( + &MediaCaptureDevicesDispatcher::NotifyAudioDevicesChangedOnUIThread, + base::Unretained(this))); } -void MediaCaptureDevicesDispatcher::VideoCaptureDevicesChanged( - const MediaStreamDevices& devices) { +void MediaCaptureDevicesDispatcher::OnVideoCaptureDevicesChanged() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, - base::Bind(&MediaCaptureDevicesDispatcher::UpdateVideoDevicesOnUIThread, - this, devices)); + base::Bind( + &MediaCaptureDevicesDispatcher::NotifyVideoDevicesChangedOnUIThread, + base::Unretained(this))); } void MediaCaptureDevicesDispatcher::AddObserver(Observer* observer) { @@ -69,25 +69,13 @@ void MediaCaptureDevicesDispatcher::RemoveObserver(Observer* observer) { const MediaStreamDevices& MediaCaptureDevicesDispatcher::GetAudioCaptureDevices() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (!devices_enumerated_) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&content::EnsureMonitorCaptureDevices)); - devices_enumerated_ = true; - } - return audio_devices_; + return MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices(); } const MediaStreamDevices& MediaCaptureDevicesDispatcher::GetVideoCaptureDevices() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (!devices_enumerated_) { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&content::EnsureMonitorCaptureDevices)); - devices_enumerated_ = true; - } - return video_devices_; + return MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices(); } void MediaCaptureDevicesDispatcher::OnCreatingAudioStream( @@ -101,22 +89,16 @@ void MediaCaptureDevicesDispatcher::OnCreatingAudioStream( base::Unretained(this), render_process_id, render_view_id)); } -void MediaCaptureDevicesDispatcher::UpdateAudioDevicesOnUIThread( - const content::MediaStreamDevices& devices) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - devices_enumerated_ = true; - audio_devices_ = devices; +void MediaCaptureDevicesDispatcher::NotifyAudioDevicesChangedOnUIThread() { + MediaStreamDevices devices = GetAudioCaptureDevices(); FOR_EACH_OBSERVER(Observer, observers_, - OnUpdateAudioDevices(audio_devices_)); + OnUpdateAudioDevices(devices)); } -void MediaCaptureDevicesDispatcher::UpdateVideoDevicesOnUIThread( - const content::MediaStreamDevices& devices){ - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - devices_enumerated_ = true; - video_devices_ = devices; +void MediaCaptureDevicesDispatcher::NotifyVideoDevicesChangedOnUIThread() { + MediaStreamDevices devices = GetVideoCaptureDevices(); FOR_EACH_OBSERVER(Observer, observers_, - OnUpdateVideoDevices(video_devices_)); + OnUpdateVideoDevices(devices)); } void MediaCaptureDevicesDispatcher::OnCreatingAudioStreamOnUIThread( @@ -165,3 +147,9 @@ MediaCaptureDevicesDispatcher::GetFirstAvailableVideoDevice() { return &(*video_devices.begin()); } +void MediaCaptureDevicesDispatcher::Observe( + int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} diff --git a/src/media/media_capture_devices_dispatcher.h b/src/media/media_capture_devices_dispatcher.h index 18c6fd0d03..2e707570a2 100644 --- a/src/media/media_capture_devices_dispatcher.h +++ b/src/media/media_capture_devices_dispatcher.h @@ -8,12 +8,16 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" +#include "content/public/browser/media_observer.h" +#include "content/public/browser/notification_observer.h" +#include "content/public/browser/notification_registrar.h" +#include "content/public/browser/web_contents_delegate.h" #include "content/public/common/media_stream_request.h" // This observer is owned by MediaInternals and deleted when MediaInternals // is deleted. -class MediaCaptureDevicesDispatcher - : public base::RefCountedThreadSafe { +class MediaCaptureDevicesDispatcher : public content::MediaObserver, + public content::NotificationObserver { public: class Observer { public: @@ -27,6 +31,13 @@ class MediaCaptureDevicesDispatcher virtual void OnUpdateVideoDevices( const content::MediaStreamDevices& devices) {} + // Handle an information update related to a media stream request. + virtual void OnRequestUpdate( + int render_process_id, + int render_view_id, + const content::MediaStreamDevice& device, + const content::MediaRequestState state) {} + virtual void OnCreatingAudioStream(int render_process_id, int render_view_id) {} @@ -36,15 +47,29 @@ class MediaCaptureDevicesDispatcher MediaCaptureDevicesDispatcher(); virtual ~MediaCaptureDevicesDispatcher(); - // Called on IO thread when one audio device is plugged in or unplugged. - void AudioCaptureDevicesChanged(const content::MediaStreamDevices& devices); - - // Called on IO thread when one video device is plugged in or unplugged. - void VideoCaptureDevicesChanged(const content::MediaStreamDevices& devices); + void NotifyAudioDevicesChangedOnUIThread(); + void NotifyVideoDevicesChangedOnUIThread(); + // Overridden from content::MediaObserver: + virtual void OnAudioCaptureDevicesChanged() OVERRIDE; + virtual void OnVideoCaptureDevicesChanged() OVERRIDE; void OnCreatingAudioStream(int render_process_id, - int render_view_id); - - + int render_view_id) OVERRIDE; + + // content::NotificationObserver implementation. + virtual void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) OVERRIDE; + + + virtual void OnAudioStreamPlaying( + int render_process_id, + int render_frame_id, + int stream_id, + const ReadPowerAndClipCallback& power_read_callback) OVERRIDE {} + virtual void OnAudioStreamStopped( + int render_process_id, + int render_frame_id, + int stream_id) OVERRIDE {} // Methods for observers. Called on UI thread. // Observers should add themselves on construction and remove themselves // on destruction. @@ -60,6 +85,15 @@ class MediaCaptureDevicesDispatcher const content::MediaStreamDevice* GetRequestedVideoDevice(const std::string& requested_video_device_id); + + virtual void OnMediaRequestStateChanged( + int render_process_id, + int render_view_id, + int page_request_id, + const GURL& security_origin, + const content::MediaStreamDevice& device, + content::MediaRequestState state) {} + // Returns the first available audio or video device, or NULL if no devices // are available. const content::MediaStreamDevice* GetFirstAvailableAudioDevice(); diff --git a/src/media/media_internals.cc b/src/media/media_internals.cc index 56ed21b09d..ee171558c1 100644 --- a/src/media/media_internals.cc +++ b/src/media/media_internals.cc @@ -89,22 +89,21 @@ MediaInternals* MediaInternals::GetInstance() { MediaInternals::~MediaInternals() {} -void MediaInternals::OnAudioCaptureDevicesChanged( - const content::MediaStreamDevices& devices) { +void MediaInternals::OnAudioCaptureDevicesChanged() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - media_devices_dispatcher_->AudioCaptureDevicesChanged(devices); + media_devices_dispatcher_->OnAudioCaptureDevicesChanged(); } -void MediaInternals::OnVideoCaptureDevicesChanged( - const content::MediaStreamDevices& devices) { +void MediaInternals::OnVideoCaptureDevicesChanged() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - media_devices_dispatcher_->VideoCaptureDevicesChanged(devices); + media_devices_dispatcher_->OnVideoCaptureDevicesChanged(); } void MediaInternals::OnMediaRequestStateChanged( int render_process_id, int render_view_id, int page_request_id, + const GURL& security_origin, const content::MediaStreamDevice& device, content::MediaRequestState state) { } @@ -119,7 +118,7 @@ void MediaInternals::OnCreatingAudioStream( media_devices_dispatcher_->OnCreatingAudioStream(render_process_id, render_view_id); } -scoped_refptr +MediaCaptureDevicesDispatcher* MediaInternals::GetMediaCaptureDevicesDispatcher() { return media_devices_dispatcher_; } diff --git a/src/media/media_internals.h b/src/media/media_internals.h index b4e7af4ffb..3a2f79bcff 100644 --- a/src/media/media_internals.h +++ b/src/media/media_internals.h @@ -42,14 +42,13 @@ class MediaInternals : public content::MediaObserver { static MediaInternals* GetInstance(); // Overridden from content::MediaObserver: - virtual void OnAudioCaptureDevicesChanged( - const content::MediaStreamDevices& devices) OVERRIDE; - virtual void OnVideoCaptureDevicesChanged( - const content::MediaStreamDevices& devices) OVERRIDE; + virtual void OnAudioCaptureDevicesChanged() OVERRIDE; + virtual void OnVideoCaptureDevicesChanged() OVERRIDE; virtual void OnMediaRequestStateChanged( int render_process_id, int render_view_id, int page_request_id, + const GURL& security_origin, const content::MediaStreamDevice& device, content::MediaRequestState state) OVERRIDE; virtual void OnAudioStreamPlayingChanged( @@ -62,6 +61,15 @@ class MediaInternals : public content::MediaObserver { virtual void OnCreatingAudioStream(int render_process_id, int render_view_id) OVERRIDE; + virtual void OnAudioStreamPlaying( + int render_process_id, + int render_frame_id, + int stream_id, + const ReadPowerAndClipCallback& power_read_callback) OVERRIDE {} + virtual void OnAudioStreamStopped( + int render_process_id, + int render_frame_id, + int stream_id) OVERRIDE {} // Methods for observers. // Observers should add themselves on construction and remove themselves // on destruction. @@ -70,8 +78,7 @@ class MediaInternals : public content::MediaObserver { void SendEverything(); scoped_refptr GetMediaStreamCaptureIndicator(); - scoped_refptr - GetMediaCaptureDevicesDispatcher(); + MediaCaptureDevicesDispatcher* GetMediaCaptureDevicesDispatcher(); private: friend class MediaInternalsTest; @@ -83,7 +90,7 @@ class MediaInternals : public content::MediaObserver { // (host, stream_id) is a unique id for the audio stream. // |host| will never be dereferenced. void UpdateAudioStream(void* host, int stream_id, - const std::string& property, Value* value); + const std::string& property, base::Value* value); // Removes |item| from |data_|. void DeleteItem(const std::string& item); @@ -91,14 +98,14 @@ class MediaInternals : public content::MediaObserver { // Sets data_.id.property = value and notifies attached UIs using update_fn. // id may be any depth, e.g. "video.decoders.1.2.3" void UpdateItem(const std::string& update_fn, const std::string& id, - const std::string& property, Value* value); + const std::string& property, base::Value* value); // Calls javascript |function|(|value|) on each attached UI. - void SendUpdate(const std::string& function, Value* value); + void SendUpdate(const std::string& function, base::Value* value); - DictionaryValue data_; + base::DictionaryValue data_; ObserverList observers_; - scoped_refptr media_devices_dispatcher_; + MediaCaptureDevicesDispatcher* media_devices_dispatcher_; DISALLOW_COPY_AND_ASSIGN(MediaInternals); }; diff --git a/src/media/media_stream_devices_controller.cc b/src/media/media_stream_devices_controller.cc index 866c080876..29942a0300 100644 --- a/src/media/media_stream_devices_controller.cc +++ b/src/media/media_stream_devices_controller.cc @@ -8,7 +8,7 @@ #include "content/nw/src/media/media_capture_devices_dispatcher.h" #include "content/nw/src/media/media_internals.h" #include "content/public/browser/browser_thread.h" -#include "content/public/common/desktop_media_id.h" +#include "content/public/browser/desktop_media_id.h" #include "content/public/common/media_stream_request.h" using content::BrowserThread; @@ -185,11 +185,14 @@ void MediaStreamDevicesController::Accept(bool update_content_setting) { break; } - callback_.Run(devices, scoped_ptr()); + callback_.Run(devices, + devices.empty() ? + content::MEDIA_DEVICE_NO_HARDWARE : content::MEDIA_DEVICE_OK, + scoped_ptr()); } void MediaStreamDevicesController::Deny(bool update_content_setting) { - callback_.Run(content::MediaStreamDevices(), scoped_ptr()); + callback_.Run(content::MediaStreamDevices(), content::MEDIA_DEVICE_NO_HARDWARE, scoped_ptr()); } bool MediaStreamDevicesController::IsAudioDeviceBlockedByPolicy() const { @@ -233,7 +236,10 @@ void MediaStreamDevicesController::HandleTapMediaRequest() { content::MEDIA_DESKTOP_VIDEO_CAPTURE, media_id.ToString(), "Screen")); } - callback_.Run(devices, scoped_ptr()); + callback_.Run(devices, + devices.empty() ? + content::MEDIA_DEVICE_NO_HARDWARE : content::MEDIA_DEVICE_OK, + scoped_ptr()); } bool MediaStreamDevicesController::IsSchemeSecure() const { diff --git a/src/net/app_protocol_handler.cc b/src/net/app_protocol_handler.cc index da867b8644..2b61c4be16 100644 --- a/src/net/app_protocol_handler.cc +++ b/src/net/app_protocol_handler.cc @@ -51,15 +51,14 @@ net::HttpResponseHeaders* BuildHttpHeaders( last_modified_time.ToInternalValue()); hash = base::SHA1HashString(hash); std::string etag; - if (base::Base64Encode(hash, &etag)) { - raw_headers.append(1, '\0'); - raw_headers.append("ETag: \""); - raw_headers.append(etag); - raw_headers.append("\""); - // Also force revalidation. - raw_headers.append(1, '\0'); - raw_headers.append("cache-control: no-cache"); - } + base::Base64Encode(hash, &etag); + raw_headers.append(1, '\0'); + raw_headers.append("ETag: \""); + raw_headers.append(etag); + raw_headers.append("\""); + // Also force revalidation. + raw_headers.append(1, '\0'); + raw_headers.append("cache-control: no-cache"); } raw_headers.append(2, '\0'); @@ -74,8 +73,8 @@ void ReadMimeTypeFromFile(const base::FilePath& filename, base::Time GetFileLastModifiedTime(const base::FilePath& filename) { if (base::PathExists(filename)) { - base::PlatformFileInfo info; - if (file_util::GetFileInfo(filename, &info)) + base::File::Info info; + if (base::GetFileInfo(filename, &info)) return info.last_modified; } return base::Time(); @@ -83,8 +82,8 @@ base::Time GetFileLastModifiedTime(const base::FilePath& filename) { base::Time GetFileCreationTime(const base::FilePath& filename) { if (base::PathExists(filename)) { - base::PlatformFileInfo info; - if (file_util::GetFileInfo(filename, &info)) + base::File::Info info; + if (base::GetFileInfo(filename, &info)) return info.creation_time; } return base::Time(); diff --git a/src/net/shell_network_delegate.cc b/src/net/shell_network_delegate.cc index 3485e276c1..3142e12238 100644 --- a/src/net/shell_network_delegate.cc +++ b/src/net/shell_network_delegate.cc @@ -75,7 +75,7 @@ void ShellNetworkDelegate::OnURLRequestDestroyed(net::URLRequest* request) { } void ShellNetworkDelegate::OnPACScriptError(int line_number, - const string16& error) { + const base::string16& error) { } ShellNetworkDelegate::AuthRequiredResponse ShellNetworkDelegate::OnAuthRequired( @@ -113,9 +113,4 @@ int ShellNetworkDelegate::OnBeforeSocketStreamConnect( return net::OK; } -void ShellNetworkDelegate::OnRequestWaitStateChange( - const net::URLRequest& request, - RequestWaitState waiting) { -} - } // namespace content diff --git a/src/net/shell_network_delegate.h b/src/net/shell_network_delegate.h index 14c0bf08b7..11cc34f4cd 100644 --- a/src/net/shell_network_delegate.h +++ b/src/net/shell_network_delegate.h @@ -57,7 +57,7 @@ class ShellNetworkDelegate : public net::NetworkDelegate { virtual void OnCompleted(net::URLRequest* request, bool started) OVERRIDE; virtual void OnURLRequestDestroyed(net::URLRequest* request) OVERRIDE; virtual void OnPACScriptError(int line_number, - const string16& error) OVERRIDE; + const base::string16& error) OVERRIDE; virtual AuthRequiredResponse OnAuthRequired( net::URLRequest* request, const net::AuthChallengeInfo& auth_info, @@ -75,8 +75,6 @@ class ShellNetworkDelegate : public net::NetworkDelegate { virtual int OnBeforeSocketStreamConnect( net::SocketStream* stream, const net::CompletionCallback& callback) OVERRIDE; - virtual void OnRequestWaitStateChange(const net::URLRequest& request, - RequestWaitState state) OVERRIDE; DISALLOW_COPY_AND_ASSIGN(ShellNetworkDelegate); }; diff --git a/src/net/shell_url_request_context_getter.cc b/src/net/shell_url_request_context_getter.cc index 5020b71771..0595186d07 100644 --- a/src/net/shell_url_request_context_getter.cc +++ b/src/net/shell_url_request_context_getter.cc @@ -176,11 +176,11 @@ net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() { FilePath cookie_path = data_path_.Append(FILE_PATH_LITERAL("cookies")); scoped_refptr cookie_store = NULL; - cookie_store = content::CreatePersistentCookieStore( - cookie_path, - false, - NULL, - new NWCookieMonsterDelegate(browser_context_)); + + content::CookieStoreConfig cookie_config( + cookie_path, content::CookieStoreConfig::PERSISTANT_SESSION_COOKIES, + NULL, new NWCookieMonsterDelegate(browser_context_)); + cookie_store = content::CreateCookieStore(cookie_config); cookie_store->GetCookieMonster()->SetPersistSessionCookies(true); storage_->set_cookie_store(cookie_store); @@ -199,7 +199,7 @@ net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() { storage_->set_http_user_agent_settings( new net::StaticHttpUserAgentSettings( net::HttpUtil::GenerateAcceptLanguageHeader(accept_lang), - EmptyString())); + base::EmptyString())); scoped_ptr host_resolver( net::HostResolver::CreateDefaultResolver(NULL)); @@ -270,7 +270,7 @@ net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() { new net::URLRequestJobFactoryImpl()); InstallProtocolHandlers(job_factory.get(), &protocol_handlers_); job_factory->SetProtocolHandler( - chrome::kFileScheme, + content::kFileScheme, new net::FileProtocolHandler( content::BrowserThread::GetBlockingPool()-> GetTaskRunnerWithShutdownBehavior( diff --git a/src/nw_package.cc b/src/nw_package.cc index 6131cfca21..e78c6d0564 100644 --- a/src/nw_package.cc +++ b/src/nw_package.cc @@ -45,9 +45,11 @@ #include "ui/gfx/image/image_skia_rep.h" #include "ui/gfx/codec/png_codec.h" +namespace base { bool IsSwitch(const CommandLine::StringType& string, CommandLine::StringType* switch_string, CommandLine::StringType* switch_value); +} namespace nw { @@ -64,7 +66,7 @@ bool MakePathAbsolute(FilePath* file_path) { DCHECK(file_path); FilePath current_directory; - if (!file_util::GetCurrentDirectory(¤t_directory)) + if (!base::GetCurrentDirectory(¤t_directory)) return false; if (file_path->IsAbsolute()) @@ -266,7 +268,7 @@ bool Package::InitFromPath() { // Parse file. std::string error; JSONFileValueSerializer serializer(manifest_path); - scoped_ptr root(serializer.Deserialize(NULL, &error)); + scoped_ptr root(serializer.Deserialize(NULL, &error)); if (!root.get()) { ReportError("Unable to parse package.json", error.empty() ? @@ -274,14 +276,14 @@ bool Package::InitFromPath() { manifest_path.AsUTF8Unsafe() : error); return false; - } else if (!root->IsType(Value::TYPE_DICTIONARY)) { + } else if (!root->IsType(base::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(root.release())); + root_.reset(static_cast(root.release())); // Save origin package info // Since we will change some value in root_, @@ -355,7 +357,7 @@ bool Package::ExtractPath() { // Read symbolic link. #if defined(OS_POSIX) FilePath target; - if (file_util::ReadSymbolicLink(path_, &target)) + if (base::ReadSymbolicLink(path_, &target)) path_ = target; #endif @@ -378,9 +380,9 @@ bool Package::ExtractPackage(const FilePath& zip_file, FilePath* where) { if (!scoped_temp_dir_.IsValid()) { #if defined(OS_WIN) - if (!file_util::CreateNewTempDirectory(L"nw", where)) { + if (!base::CreateNewTempDirectory(L"nw", where)) { #else - if (!file_util::CreateNewTempDirectory("nw", where)) { + if (!base::CreateNewTempDirectory("nw", where)) { #endif ReportError("Cannot extract package", "Unable to create temporary directory."); @@ -411,7 +413,7 @@ void Package::ReadChromiumArgs() { tokenizer.set_quote_chars("\'"); while (tokenizer.GetNext()) { std::string token = tokenizer.token(); - RemoveChars(token, "\'", &token); + base::RemoveChars(token, "\'", &token); chromium_args.push_back(token); } @@ -423,12 +425,12 @@ void Package::ReadChromiumArgs() { // 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)) + if (!base::IsSwitch(ASCIIToWide(chromium_args[i]), &key, &value)) continue; command_line->AppendSwitchASCII(WideToASCII(key), WideToASCII(value)); #else - if (!IsSwitch(chromium_args[i], &key, &value)) + if (!base::IsSwitch(chromium_args[i], &key, &value)) continue; command_line->AppendSwitchASCII(key, value); #endif diff --git a/src/nw_shell.cc b/src/nw_shell.cc index ffb76671eb..dcde623269 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -154,7 +154,7 @@ Shell* Shell::FromRenderViewHost(RenderViewHost* rvh) { return windows_[i]; }else{ WebContentsImpl* impl = static_cast(web_contents); - RenderViewHostManager* rvhm = impl->GetRenderManagerForTesting(); + RenderFrameHostManager* rvhm = impl->GetRenderManagerForTesting(); if (rvhm && static_cast(rvhm->pending_render_view_host()) == rvh) return windows_[i]; } @@ -289,9 +289,9 @@ void Shell::PrintCriticalError(const std::string& title, error_page_url = "data:text/html;base64,VW5hYmxlIHRvIGZpbmQgbncucGFrLgo="; } else { std::string content_with_no_newline, content_with_no_space; - ReplaceChars(net::EscapeForHTML(content), + base::ReplaceChars(net::EscapeForHTML(content), "\n", "
    ", &content_with_no_newline); - ReplaceChars(content_with_no_newline, + base::ReplaceChars(content_with_no_newline, " ", " ", &content_with_no_space); std::vector subst; @@ -399,7 +399,7 @@ void Shell::ShowDevTools(const char* jail_id, bool headless) { if (nodejs()) { std::string jscript = std::string("require('nw.gui').Window.get().__setDevToolsJail('") + (jail_id ? jail_id : "(null)") + "');"; - inspected_rvh->ExecuteJavascriptInWebFrame(string16(), UTF8ToUTF16(jscript.c_str())); + inspected_rvh->ExecuteJavascriptInWebFrame(base::string16(), base::UTF8ToUTF16(jscript.c_str())); } scoped_refptr agent(DevToolsAgentHost::GetOrCreateFor(inspected_rvh)); @@ -448,7 +448,7 @@ void Shell::ShowDevTools(const char* jail_id, bool headless) { DevToolsAgentHost::GetOrCreateFor(inspected_rvh).get()); int rh_id = shell->web_contents_->GetRenderProcessHost()->GetID(); - ChildProcessSecurityPolicyImpl::GetInstance()->GrantScheme(rh_id, chrome::kFileScheme); + ChildProcessSecurityPolicyImpl::GetInstance()->GrantScheme(rh_id, content::kFileScheme); ChildProcessSecurityPolicyImpl::GetInstance()->GrantScheme(rh_id, "app"); shell->is_devtools_ = true; shell->devtools_owner_ = weak_ptr_factory_.GetWeakPtr(); @@ -539,7 +539,7 @@ bool Shell::IsPopupOrPanel(const WebContents* source) const { // Window opened by window.open void Shell::WebContentsCreated(WebContents* source_contents, int64 source_frame_id, - const string16& frame_name, + const base::string16& frame_name, const GURL& target_url, WebContents* new_contents) { // Create with package's manifest @@ -547,7 +547,7 @@ void Shell::WebContentsCreated(WebContents* source_contents, GetPackage()->window()->DeepCopy()); // Get window features - WebKit::WebWindowFeatures features = new_contents->GetWindowFeatures(); + blink::WebWindowFeatures features = new_contents->GetWindowFeatures(); manifest->SetBoolean(switches::kmResizable, features.resizable); manifest->SetBoolean(switches::kmFullscreen, features.fullscreen); if (features.widthSet) @@ -604,9 +604,9 @@ JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() { bool Shell::AddMessageToConsole(WebContents* source, int32 level, - const string16& message, + const base::string16& message, int32 line_no, - const string16& source_id) { + const base::string16& source_id) { return false; } @@ -639,7 +639,7 @@ void Shell::Observe(int type, Details >(details).ptr(); if (title->first) { - string16 text = title->first->GetTitle(); + base::string16 text = title->first->GetTitle(); window()->SetTitle(UTF16ToUTF8(text)); } } else if (type == NOTIFICATION_RENDERER_PROCESS_CLOSED) { diff --git a/src/nw_shell.h b/src/nw_shell.h index 45b8636de7..c6781ded9e 100644 --- a/src/nw_shell.h +++ b/src/nw_shell.h @@ -150,7 +150,7 @@ class Shell : public WebContentsDelegate, virtual bool IsPopupOrPanel(const WebContents* source) const OVERRIDE; virtual void WebContentsCreated(WebContents* source_contents, int64 source_frame_id, - const string16& frame_name, + const base::string16& frame_name, const GURL& target_url, WebContents* new_contents) OVERRIDE; #if defined(OS_WIN) @@ -175,9 +175,9 @@ class Shell : public WebContentsDelegate, const NativeWebKeyboardEvent& event) OVERRIDE; virtual bool AddMessageToConsole(WebContents* source, int32 level, - const string16& message, + const base::string16& message, int32 line_no, - const string16& source_id) OVERRIDE; + const base::string16& source_id) OVERRIDE; virtual void RequestMediaAccessPermission( WebContents* web_contents, const MediaStreamRequest& request, diff --git a/src/renderer/nw_render_view_observer.cc b/src/renderer/nw_render_view_observer.cc index 68b438d079..6e6b2d059a 100644 --- a/src/renderer/nw_render_view_observer.cc +++ b/src/renderer/nw_render_view_observer.cc @@ -33,15 +33,14 @@ #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebView.h" -#include "webkit/glue/webkit_glue.h" using content::RenderView; using content::RenderViewImpl; -using WebKit::WebFrame; -using WebKit::WebRect; -using WebKit::WebScriptSource; -using WebKit::WebSize; +using blink::WebFrame; +using blink::WebRect; +using blink::WebScriptSource; +using blink::WebSize; namespace nw { @@ -80,7 +79,7 @@ void NwRenderViewObserver::OnCaptureSnapshot() { Send(new NwViewHostMsg_Snapshot(routing_id(), snapshot)); } -void NwRenderViewObserver::DidFinishDocumentLoad(WebKit::WebFrame* frame) { +void NwRenderViewObserver::DidFinishDocumentLoad(blink::WebFrame* frame) { RenderViewImpl* rv = RenderViewImpl::FromWebView(frame->view()); if (!rv) return; @@ -88,7 +87,7 @@ void NwRenderViewObserver::DidFinishDocumentLoad(WebKit::WebFrame* frame) { OnDocumentCallback(rv, js_fn, frame); } -void NwRenderViewObserver::DidCreateDocumentElement(WebKit::WebFrame* frame) { +void NwRenderViewObserver::DidCreateDocumentElement(blink::WebFrame* frame) { RenderViewImpl* rv = RenderViewImpl::FromWebView(frame->view()); if (!rv) return; @@ -98,7 +97,7 @@ void NwRenderViewObserver::DidCreateDocumentElement(WebKit::WebFrame* frame) { void NwRenderViewObserver::OnDocumentCallback(RenderViewImpl* rv, const std::string& js_fn, - WebKit::WebFrame* frame) { + blink::WebFrame* frame) { if (js_fn.empty()) return; std::string content; @@ -113,7 +112,7 @@ void NwRenderViewObserver::OnDocumentCallback(RenderViewImpl* rv, frame->executeScriptAndReturnValue(WebScriptSource(jscript)); } -bool NwRenderViewObserver::CaptureSnapshot(WebKit::WebView* view, +bool NwRenderViewObserver::CaptureSnapshot(blink::WebView* view, SkBitmap* snapshot) { view->layout(); const WebSize& size = view->size(); @@ -132,7 +131,7 @@ bool NwRenderViewObserver::CaptureSnapshot(WebKit::WebView* view, SkBaseDevice* device = skia::GetTopDevice(*canvas); const SkBitmap& bitmap = device->accessBitmap(false); - if (!bitmap.copyTo(snapshot, SkBitmap::kARGB_8888_Config)) + if (!bitmap.copyTo(snapshot, SkBitmapConfigToColorType(SkBitmap::kARGB_8888_Config))) return false; return true; diff --git a/src/renderer/nw_render_view_observer.h b/src/renderer/nw_render_view_observer.h index d697ff9c4c..0449c1db08 100644 --- a/src/renderer/nw_render_view_observer.h +++ b/src/renderer/nw_render_view_observer.h @@ -29,7 +29,7 @@ namespace content { class RenderViewImpl; } -namespace WebKit { +namespace blink { class WebView; } @@ -42,8 +42,8 @@ class NwRenderViewObserver : public content::RenderViewObserver { // RenderViewObserver implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void DidCreateDocumentElement(WebKit::WebFrame* frame) OVERRIDE; - virtual void DidFinishDocumentLoad(WebKit::WebFrame* frame) OVERRIDE; + virtual void DidCreateDocumentElement(blink::WebFrame* frame) OVERRIDE; + virtual void DidFinishDocumentLoad(blink::WebFrame* frame) OVERRIDE; private: @@ -51,11 +51,11 @@ class NwRenderViewObserver : public content::RenderViewObserver { // Capture a snapshot of a view. This is used to allow an extension // to get a snapshot of a tab using chrome.tabs.captureVisibleTab(). - bool CaptureSnapshot(WebKit::WebView* view, SkBitmap* snapshot); + bool CaptureSnapshot(blink::WebView* view, SkBitmap* snapshot); void OnDocumentCallback(content::RenderViewImpl* rv, const std::string& js_fn, - WebKit::WebFrame* frame); + blink::WebFrame* frame); DISALLOW_COPY_AND_ASSIGN(NwRenderViewObserver); }; diff --git a/src/renderer/prerenderer/prerenderer_client.cc b/src/renderer/prerenderer/prerenderer_client.cc index cbe5f08d47..22d4d1bd5b 100644 --- a/src/renderer/prerenderer/prerenderer_client.cc +++ b/src/renderer/prerenderer/prerenderer_client.cc @@ -37,7 +37,7 @@ PrerendererClient::~PrerendererClient() { } void PrerendererClient::willAddPrerender( - WebKit::WebPrerender* prerender) { + blink::WebPrerender* prerender) { } } // namespace prerender diff --git a/src/renderer/prerenderer/prerenderer_client.h b/src/renderer/prerenderer/prerenderer_client.h index 8bcea1422f..42ed0063b9 100644 --- a/src/renderer/prerenderer/prerenderer_client.h +++ b/src/renderer/prerenderer/prerenderer_client.h @@ -28,15 +28,15 @@ namespace prerender { class PrerendererClient : public content::RenderViewObserver, - public WebKit::WebPrerendererClient { + public blink::WebPrerendererClient { public: explicit PrerendererClient(content::RenderView* render_view); private: virtual ~PrerendererClient(); - // Implements WebKit::WebPrerendererClient - virtual void willAddPrerender(WebKit::WebPrerender* prerender) OVERRIDE; + // Implements blink::WebPrerendererClient + virtual void willAddPrerender(blink::WebPrerender* prerender) OVERRIDE; }; } // namespace prerender diff --git a/src/renderer/printing/print_web_view_helper.cc b/src/renderer/printing/print_web_view_helper.cc index 395f9969cf..8e5c18b3bc 100644 --- a/src/renderer/printing/print_web_view_helper.cc +++ b/src/renderer/printing/print_web_view_helper.cc @@ -24,6 +24,7 @@ #include "content/public/renderer/render_view.h" #include "grit/nw_resources.h" //#include "grit/generated_resources.h" +#include "net/base/escape.h" #include "printing/metafile.h" #include "printing/metafile_impl.h" #include "printing/units.h" @@ -60,13 +61,13 @@ const char kPageLoadScriptFormat[] = const char kPageSetupScriptFormat[] = "setup(%s);"; -void ExecuteScript(WebKit::WebFrame* frame, +void ExecuteScript(blink::WebFrame* frame, const char* script_format, const base::Value& parameters) { std::string json; base::JSONWriter::Write(¶meters, &json); std::string script = base::StringPrintf(script_format, json.c_str()); - frame->executeScript(WebKit::WebString(UTF8ToUTF16(script))); + frame->executeScript(blink::WebString(base::UTF8ToUTF16(script))); } int GetDPI(const PrintMsg_Print_Params* print_params) { @@ -88,13 +89,13 @@ bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params& params) { PrintMsg_Print_Params GetCssPrintParams( - WebKit::WebFrame* frame, + blink::WebFrame* frame, int page_index, const PrintMsg_Print_Params& page_params) { PrintMsg_Print_Params page_css_params = page_params; int dpi = GetDPI(&page_params); - WebKit::WebSize page_size_in_pixels( + blink::WebSize page_size_in_pixels( ConvertUnit(page_params.page_size.width(), dpi, kPixelsPerInch), ConvertUnit(page_params.page_size.height(), dpi, kPixelsPerInch)); int margin_top_in_pixels = @@ -111,7 +112,7 @@ PrintMsg_Print_Params GetCssPrintParams( page_params.margin_left, dpi, kPixelsPerInch); - WebKit::WebSize original_page_size_in_pixels = page_size_in_pixels; + blink::WebSize original_page_size_in_pixels = page_size_in_pixels; if (frame) { frame->pageSizeAndMarginsInPixels(page_index, @@ -238,7 +239,7 @@ void EnsureOrientationMatches(const PrintMsg_Print_Params& css_params, void ComputeWebKitPrintParamsInDesiredDpi( const PrintMsg_Print_Params& print_params, - WebKit::WebPrintParams* webkit_print_params) { + blink::WebPrintParams* webkit_print_params) { int dpi = GetDPI(&print_params); webkit_print_params->printerDPI = dpi; webkit_print_params->printScalingOption = print_params.print_scaling_option; @@ -271,18 +272,18 @@ void ComputeWebKitPrintParamsInDesiredDpi( print_params.desired_dpi); } -bool PrintingNodeOrPdfFrame(const WebKit::WebFrame* frame, - const WebKit::WebNode& node) { +bool PrintingNodeOrPdfFrame(const blink::WebFrame* frame, + const blink::WebNode& node) { if (!node.isNull()) return true; if (!frame->document().isPluginDocument()) return false; - WebKit::WebPlugin* plugin = - frame->document().to().plugin(); + blink::WebPlugin* plugin = + frame->document().to().plugin(); return plugin && plugin->supportsPaginatedPrint(); } -bool PrintingFrameHasPageSizeStyle(WebKit::WebFrame* frame, +bool PrintingFrameHasPageSizeStyle(blink::WebFrame* frame, int total_page_count) { if (!frame) return false; @@ -296,15 +297,15 @@ bool PrintingFrameHasPageSizeStyle(WebKit::WebFrame* frame, return frame_has_custom_page_size_style; } -MarginType GetMarginsForPdf(WebKit::WebFrame* frame, - const WebKit::WebNode& node) { +MarginType GetMarginsForPdf(blink::WebFrame* frame, + const blink::WebNode& node) { if (frame->isPrintScalingDisabledForPlugin(node)) return NO_MARGINS; else return PRINTABLE_AREA_MARGINS; } -bool FitToPageEnabled(const DictionaryValue& job_settings) { +bool FitToPageEnabled(const base::DictionaryValue& job_settings) { bool fit_to_paper_size = false; if (!job_settings.GetBoolean(kSettingFitToPageEnabled, &fit_to_paper_size)) { NOTREACHED(); @@ -313,7 +314,7 @@ bool FitToPageEnabled(const DictionaryValue& job_settings) { } PrintMsg_Print_Params CalculatePrintParamsForCss( - WebKit::WebFrame* frame, + blink::WebFrame* frame, int page_index, const PrintMsg_Print_Params& page_params, bool ignore_css_margins, @@ -369,12 +370,12 @@ bool IsPrintThrottlingDisabled() { // static - Not anonymous so that platform implementations can use it. void PrintWebViewHelper::PrintHeaderAndFooter( - WebKit::WebCanvas* canvas, + blink::WebCanvas* canvas, int page_number, int total_pages, float webkit_scale_factor, const PageSizeMargins& page_layout, - const DictionaryValue& header_footer_info, + const base::DictionaryValue& header_footer_info, const PrintMsg_Print_Params& params) { skia::VectorPlatformDeviceSkia* device = static_cast(canvas->getTopDevice()); @@ -383,16 +384,16 @@ void PrintWebViewHelper::PrintHeaderAndFooter( SkAutoCanvasRestore auto_restore(canvas, true); canvas->scale(1 / webkit_scale_factor, 1 / webkit_scale_factor); - WebKit::WebSize page_size(page_layout.margin_left + page_layout.margin_right + + blink::WebSize page_size(page_layout.margin_left + page_layout.margin_right + page_layout.content_width, page_layout.margin_top + page_layout.margin_bottom + page_layout.content_height); - WebKit::WebView* web_view = WebKit::WebView::create(NULL); + blink::WebView* web_view = blink::WebView::create(NULL); web_view->settings()->setJavaScriptEnabled(true); - web_view->initializeMainFrame(NULL); - WebKit::WebFrame* frame = web_view->mainFrame(); + blink::WebFrame* frame = blink::WebFrame::create(NULL); + web_view->setMainFrame(frame); base::StringValue html( ResourceBundle::GetSharedInstance().GetLocalizedString( @@ -410,7 +411,7 @@ void PrintWebViewHelper::PrintHeaderAndFooter( ExecuteScript(frame, kPageSetupScriptFormat, *options); - WebKit::WebPrintParams webkit_params(page_size); + blink::WebPrintParams webkit_params(page_size); webkit_params.printerDPI = GetDPI(¶ms); frame->printBegin(webkit_params); @@ -423,12 +424,12 @@ void PrintWebViewHelper::PrintHeaderAndFooter( } // static - Not anonymous so that platform implementations can use it. -float PrintWebViewHelper::RenderPageContent(WebKit::WebFrame* frame, +float PrintWebViewHelper::RenderPageContent(blink::WebFrame* frame, int page_number, const gfx::Rect& canvas_area, const gfx::Rect& content_area, double scale_factor, - WebKit::WebCanvas* canvas) { + blink::WebCanvas* canvas) { SkAutoCanvasRestore auto_restore(canvas, true); if (content_area != canvas_area) { canvas->translate((content_area.x() - canvas_area.x()) / scale_factor, @@ -448,12 +449,12 @@ float PrintWebViewHelper::RenderPageContent(WebKit::WebFrame* frame, // Class that calls the Begin and End print functions on the frame and changes // the size of the view temporarily to support full page printing.. -class PrepareFrameAndViewForPrint : public WebKit::WebViewClient, - public WebKit::WebFrameClient { +class PrepareFrameAndViewForPrint : public blink::WebViewClient, + public blink::WebFrameClient { public: PrepareFrameAndViewForPrint(const PrintMsg_Print_Params& params, - WebKit::WebFrame* frame, - const WebKit::WebNode& node, + blink::WebFrame* frame, + const blink::WebNode& node, bool ignore_css_margins); virtual ~PrepareFrameAndViewForPrint(); @@ -465,11 +466,11 @@ class PrepareFrameAndViewForPrint : public WebKit::WebViewClient, // Prepares frame for printing. void StartPrinting(); - WebKit::WebFrame* frame() const { + blink::WebFrame* frame() const { return frame_; } - const WebKit::WebNode& node() const { + const blink::WebNode& node() const { return node_to_print_; } @@ -487,7 +488,7 @@ class PrepareFrameAndViewForPrint : public WebKit::WebViewClient, } protected: - // WebKit::WebViewClient override: + // blink::WebViewClient override: virtual void didStopLoading(); virtual void CallOnReady(); @@ -499,10 +500,10 @@ class PrepareFrameAndViewForPrint : public WebKit::WebViewClient, base::WeakPtrFactory weak_ptr_factory_; - WebKit::WebFrame* frame_; - WebKit::WebNode node_to_print_; + blink::WebFrame* frame_; + blink::WebNode node_to_print_; bool owns_web_view_; - WebKit::WebPrintParams web_print_params_; + blink::WebPrintParams web_print_params_; gfx::Size prev_view_size_; gfx::Size prev_scroll_offset_; int expected_pages_count_; @@ -516,8 +517,8 @@ class PrepareFrameAndViewForPrint : public WebKit::WebViewClient, PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint( const PrintMsg_Print_Params& params, - WebKit::WebFrame* frame, - const WebKit::WebNode& node, + blink::WebFrame* frame, + const blink::WebNode& node, bool ignore_css_margins) : weak_ptr_factory_(this), frame_(frame), @@ -532,7 +533,7 @@ PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint( !PrintingNodeOrPdfFrame(frame_, node_to_print_)) { bool fit_to_page = ignore_css_margins && print_params.print_scaling_option == - WebKit::WebPrintScalingOptionFitToPrintableArea; + blink::WebPrintScalingOptionFitToPrintableArea; print_params = CalculatePrintParamsForCss(frame_, 0, print_params, ignore_css_margins, fit_to_page, NULL); @@ -559,10 +560,10 @@ void PrepareFrameAndViewForPrint::ResizeForPrinting() { if (!frame_) return; - WebKit::WebView* web_view = frame_->view(); + blink::WebView* web_view = frame_->view(); // Backup size and offset. - if (WebKit::WebFrame* web_frame = web_view->mainFrame()) + if (blink::WebFrame* web_frame = web_view->mainFrame()) prev_scroll_offset_ = web_frame->scrollOffset(); prev_view_size_ = web_view->size(); @@ -572,7 +573,7 @@ void PrepareFrameAndViewForPrint::ResizeForPrinting() { void PrepareFrameAndViewForPrint::StartPrinting() { ResizeForPrinting(); - WebKit::WebView* web_view = frame_->view(); + blink::WebView* web_view = frame_->view(); web_view->settings()->setShouldPrintBackgrounds(should_print_backgrounds_); // TODO(vitalybuka): Update call after // https://bugs.webkit.org/show_bug.cgi?id=107718 is fixed. @@ -594,7 +595,8 @@ void PrepareFrameAndViewForPrint::CopySelection( const WebPreferences& preferences) { ResizeForPrinting(); std::string url_str = "data:text/html;charset=utf-8,"; - url_str.append(frame_->selectionAsMarkup().utf8()); + url_str.append( + net::EscapeQueryParamValue(frame()->selectionAsMarkup().utf8(), false)); RestoreSize(); // Create a new WebView with the same settings as the current display one. // Except that we disable javascript (don't want any active content running @@ -603,16 +605,16 @@ void PrepareFrameAndViewForPrint::CopySelection( prefs.javascript_enabled = false; prefs.java_enabled = false; - WebKit::WebView* web_view = WebKit::WebView::create(this); + blink::WebView* web_view = blink::WebView::create(this); owns_web_view_ = true; content::ApplyWebPreferences(prefs, web_view); - web_view->initializeMainFrame(this); + web_view->setMainFrame(blink::WebFrame::create(this)); frame_ = web_view->mainFrame(); node_to_print_.reset(); // When loading is done this will call didStopLoading() and that will do the // actual printing. - frame_->loadRequest(WebKit::WebURLRequest(GURL(url_str))); + frame_->loadRequest(blink::WebURLRequest(GURL(url_str))); } void PrepareFrameAndViewForPrint::didStopLoading() { @@ -635,16 +637,16 @@ gfx::Size PrepareFrameAndViewForPrint::GetPrintCanvasSize() const { void PrepareFrameAndViewForPrint::RestoreSize() { if (frame_) { - WebKit::WebView* web_view = frame_->view(); + blink::WebView* web_view = frame_->view(); web_view->resize(prev_view_size_); - if (WebKit::WebFrame* web_frame = web_view->mainFrame()) + if (blink::WebFrame* web_frame = web_view->mainFrame()) web_frame->setScrollOffset(prev_scroll_offset_); } } void PrepareFrameAndViewForPrint::FinishPrinting() { if (frame_) { - WebKit::WebView* web_view = frame_->view(); + blink::WebView* web_view = frame_->view(); if (is_printing_started_) { is_printing_started_ = false; frame_->printEnd(); @@ -684,7 +686,7 @@ PrintWebViewHelper::PrintWebViewHelper(content::RenderView* render_view) PrintWebViewHelper::~PrintWebViewHelper() {} bool PrintWebViewHelper::IsScriptInitiatedPrintAllowed( - WebKit::WebFrame* frame, bool user_initiated) { + blink::WebFrame* frame, bool user_initiated) { if (is_scripted_printing_blocked_) return false; // If preview is enabled, then the print dialog is tab modal, and the user @@ -699,7 +701,7 @@ bool PrintWebViewHelper::IsScriptInitiatedPrintAllowed( } // Prints |frame| which called window.print(). -void PrintWebViewHelper::PrintPage(WebKit::WebFrame* frame, +void PrintWebViewHelper::PrintPage(blink::WebFrame* frame, bool user_initiated) { DCHECK(frame); @@ -711,7 +713,7 @@ void PrintWebViewHelper::PrintPage(WebKit::WebFrame* frame, print_preview_context_.InitWithFrame(frame); RequestPrintPreview(PRINT_PREVIEW_SCRIPTED); } else { - Print(frame, WebKit::WebNode()); + Print(frame, blink::WebNode()); } } @@ -721,8 +723,6 @@ bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER(PrintMsg_PrintPages, OnPrintPages) IPC_MESSAGE_HANDLER(PrintMsg_PrintForSystemDialog, OnPrintForSystemDialog) IPC_MESSAGE_HANDLER(PrintMsg_InitiatePrintPreview, OnInitiatePrintPreview) - IPC_MESSAGE_HANDLER(PrintMsg_PrintNodeUnderContextMenu, - OnPrintNodeUnderContextMenu) IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview, OnPrintPreview) IPC_MESSAGE_HANDLER(PrintMsg_PrintForPrintPreview, OnPrintForPrintPreview) IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone, OnPrintingDone) @@ -736,7 +736,7 @@ bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) { } void PrintWebViewHelper::OnPrintForPrintPreview( - const DictionaryValue& job_settings) { + const base::DictionaryValue& job_settings) { DCHECK(is_preview_enabled_); // If still not finished with earlier print request simply ignore. if (prep_frame_view_) @@ -744,14 +744,14 @@ void PrintWebViewHelper::OnPrintForPrintPreview( if (!render_view()->GetWebView()) return; - WebKit::WebFrame* main_frame = render_view()->GetWebView()->mainFrame(); + blink::WebFrame* main_frame = render_view()->GetWebView()->mainFrame(); if (!main_frame) return; - WebKit::WebDocument document = main_frame->document(); + blink::WebDocument document = main_frame->document(); // with id="pdf-viewer" is created in // chrome/browser/resources/print_preview/print_preview.js - WebKit::WebElement pdf_element = document.getElementById("pdf-viewer"); + blink::WebElement pdf_element = document.getElementById("pdf-viewer"); if (pdf_element.isNull()) { NOTREACHED(); return; @@ -761,7 +761,7 @@ void PrintWebViewHelper::OnPrintForPrintPreview( // on return. base::AutoReset set_printing_flag(&print_for_preview_, true); - WebKit::WebFrame* pdf_frame = pdf_element.document().frame(); + blink::WebFrame* pdf_frame = pdf_element.document().frame(); if (!UpdatePrintSettings(pdf_frame, pdf_element, job_settings)) { LOG(ERROR) << "UpdatePrintSettings failed"; DidFinishPrinting(FAIL_PRINT); @@ -787,7 +787,7 @@ void PrintWebViewHelper::OnPrintForPrintPreview( } } -bool PrintWebViewHelper::GetPrintFrame(WebKit::WebFrame** frame) { +bool PrintWebViewHelper::GetPrintFrame(blink::WebFrame** frame) { DCHECK(frame); DCHECK(render_view()->GetWebView()); if (!render_view()->GetWebView()) @@ -802,13 +802,13 @@ bool PrintWebViewHelper::GetPrintFrame(WebKit::WebFrame** frame) { } void PrintWebViewHelper::OnPrintPages() { - WebKit::WebFrame* frame; + blink::WebFrame* frame; if (GetPrintFrame(&frame)) - Print(frame, WebKit::WebNode()); + Print(frame, blink::WebNode()); } void PrintWebViewHelper::OnPrintForSystemDialog() { - WebKit::WebFrame* frame = print_preview_context_.source_frame(); + blink::WebFrame* frame = print_preview_context_.source_frame(); if (!frame) { NOTREACHED(); return; @@ -835,7 +835,7 @@ void PrintWebViewHelper::GetPageSizeAndContentAreaFromPageLayout( } void PrintWebViewHelper::UpdateFrameMarginsCssInfo( - const DictionaryValue& settings) { + const base::DictionaryValue& settings) { int margins_type = 0; if (!settings.GetInteger(kSettingMarginsType, &margins_type)) margins_type = DEFAULT_MARGINS; @@ -843,36 +843,36 @@ void PrintWebViewHelper::UpdateFrameMarginsCssInfo( } bool PrintWebViewHelper::IsPrintToPdfRequested( - const DictionaryValue& job_settings) { + const base::DictionaryValue& job_settings) { bool print_to_pdf = false; if (!job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf)) NOTREACHED(); return print_to_pdf; } -WebKit::WebPrintScalingOption PrintWebViewHelper::GetPrintScalingOption( - bool source_is_html, const DictionaryValue& job_settings, +blink::WebPrintScalingOption PrintWebViewHelper::GetPrintScalingOption( + bool source_is_html, const base::DictionaryValue& job_settings, const PrintMsg_Print_Params& params) { DCHECK(!print_for_preview_); if (params.print_to_pdf) - return WebKit::WebPrintScalingOptionSourceSize; + return blink::WebPrintScalingOptionSourceSize; if (!source_is_html) { if (!FitToPageEnabled(job_settings)) - return WebKit::WebPrintScalingOptionNone; + return blink::WebPrintScalingOptionNone; bool no_plugin_scaling = print_preview_context_.source_frame()->isPrintScalingDisabledForPlugin( print_preview_context_.source_node()); if (params.is_first_request && no_plugin_scaling) - return WebKit::WebPrintScalingOptionNone; + return blink::WebPrintScalingOptionNone; } - return WebKit::WebPrintScalingOptionFitToPrintableArea; + return blink::WebPrintScalingOptionFitToPrintableArea; } -void PrintWebViewHelper::OnPrintPreview(const DictionaryValue& settings) { +void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue& settings) { DCHECK(is_preview_enabled_); print_preview_context_.OnPrintPreview(); @@ -1030,7 +1030,6 @@ bool PrintWebViewHelper::FinalizePrintReadyDocument() { DCHECK_GT(buf_size, 0u); PrintHostMsg_DidPreviewDocument_Params preview_params; - preview_params.reuse_existing_data = false; preview_params.data_size = buf_size; preview_params.document_cookie = print_pages_params_->params.document_cookie; preview_params.expected_pages_count = @@ -1063,13 +1062,9 @@ void PrintWebViewHelper::SetScriptedPrintBlocked(bool blocked) { is_scripted_printing_blocked_ = blocked; } -void PrintWebViewHelper::OnPrintNodeUnderContextMenu() { - PrintNode(render_view()->GetContextMenuNode()); -} - void PrintWebViewHelper::OnInitiatePrintPreview(bool selection_only) { DCHECK(is_preview_enabled_); - WebKit::WebFrame* frame; + blink::WebFrame* frame; if (GetPrintFrame(&frame)) { print_preview_context_.InitWithFrame(frame); RequestPrintPreview(selection_only ? @@ -1084,7 +1079,7 @@ void PrintWebViewHelper::OnInitiatePrintPreview(bool selection_only) { } } -void PrintWebViewHelper::PrintNode(const WebKit::WebNode& node) { +void PrintWebViewHelper::PrintNode(const blink::WebNode& node) { if (node.isNull() || !node.document().frame()) { // This can occur when the context menu refers to an invalid WebNode. // See http://crbug.com/100890#c17 for a repro case. @@ -1106,15 +1101,15 @@ void PrintWebViewHelper::PrintNode(const WebKit::WebNode& node) { print_preview_context_.InitWithNode(node); RequestPrintPreview(PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE); } else { - WebKit::WebNode duplicate_node(node); + blink::WebNode duplicate_node(node); Print(duplicate_node.document().frame(), duplicate_node); } print_node_in_progress_ = false; } -void PrintWebViewHelper::Print(WebKit::WebFrame* frame, - const WebKit::WebNode& node) { +void PrintWebViewHelper::Print(blink::WebFrame* frame, + const blink::WebNode& node) { // If still not finished with earlier print request simply ignore. if (prep_frame_view_) return; @@ -1223,8 +1218,8 @@ void PrintWebViewHelper::FinishFramePrinting() { } #if defined(OS_MACOSX) || defined(OS_WIN) -bool PrintWebViewHelper::PrintPagesNative(WebKit::WebFrame* frame, - const WebKit::WebNode& node, +bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, + const blink::WebNode& node, int page_count, const gfx::Size& canvas_size) { const PrintMsg_PrintPages_Params& params = *print_pages_params_; @@ -1252,7 +1247,7 @@ bool PrintWebViewHelper::PrintPagesNative(WebKit::WebFrame* frame, // static - Not anonymous so that platform implementations can use it. void PrintWebViewHelper::ComputePageLayoutInPointsForCss( - WebKit::WebFrame* frame, + blink::WebFrame* frame, int page_index, const PrintMsg_Print_Params& page_params, bool ignore_css_margins, @@ -1261,7 +1256,7 @@ void PrintWebViewHelper::ComputePageLayoutInPointsForCss( PrintMsg_Print_Params params = CalculatePrintParamsForCss( frame, page_index, page_params, ignore_css_margins, page_params.print_scaling_option == - WebKit::WebPrintScalingOptionFitToPrintableArea, + blink::WebPrintScalingOptionFitToPrintableArea, scale_factor); CalculatePageLayoutFromPrintParams(params, page_layout_in_points); } @@ -1289,18 +1284,18 @@ bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) { settings.pages.clear(); settings.params.print_scaling_option = - WebKit::WebPrintScalingOptionSourceSize; + blink::WebPrintScalingOptionSourceSize; if (fit_to_paper_size) { settings.params.print_scaling_option = - WebKit::WebPrintScalingOptionFitToPrintableArea; + blink::WebPrintScalingOptionFitToPrintableArea; } print_pages_params_.reset(new PrintMsg_PrintPages_Params(settings)); return result; } -bool PrintWebViewHelper::CalculateNumberOfPages(WebKit::WebFrame* frame, - const WebKit::WebNode& node, +bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebFrame* frame, + const blink::WebNode& node, int* number_of_pages) { DCHECK(frame); bool fit_to_paper_size = !(PrintingNodeOrPdfFrame(frame, node)); @@ -1323,12 +1318,12 @@ bool PrintWebViewHelper::CalculateNumberOfPages(WebKit::WebFrame* frame, } bool PrintWebViewHelper::UpdatePrintSettings( - WebKit::WebFrame* frame, - const WebKit::WebNode& node, - const DictionaryValue& passed_job_settings) { + blink::WebFrame* frame, + const blink::WebNode& node, + const base::DictionaryValue& passed_job_settings) { DCHECK(is_preview_enabled_); - const DictionaryValue* job_settings = &passed_job_settings; - DictionaryValue modified_job_settings; + const base::DictionaryValue* job_settings = &passed_job_settings; + base::DictionaryValue modified_job_settings; if (job_settings->empty()) { if (!print_for_preview_) print_preview_context_.set_error(PREVIEW_ERROR_BAD_SETTING); @@ -1365,7 +1360,7 @@ bool PrintWebViewHelper::UpdatePrintSettings( print_preview_context_.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS); } else { // PrintForPrintPreview - WebKit::WebFrame* print_frame = NULL; + blink::WebFrame* print_frame = NULL; // This may not be the right frame, but the alert will be modal, // therefore it works well enough. GetPrintFrame(&print_frame); @@ -1408,7 +1403,7 @@ bool PrintWebViewHelper::UpdatePrintSettings( // Header/Footer: Set |header_footer_info_|. if (settings.params.display_header_footer) { - header_footer_info_.reset(new DictionaryValue()); + header_footer_info_.reset(new base::DictionaryValue()); header_footer_info_->SetDouble(kSettingHeaderFooterDate, base::Time::Now().ToJsTime()); header_footer_info_->SetString(kSettingHeaderFooterURL, @@ -1425,8 +1420,8 @@ bool PrintWebViewHelper::UpdatePrintSettings( return true; } -bool PrintWebViewHelper::GetPrintSettingsFromUser(WebKit::WebFrame* frame, - const WebKit::WebNode& node, +bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame* frame, + const blink::WebNode& node, int expected_pages_count) { PrintHostMsg_ScriptedPrint_Params params; PrintMsg_PrintPages_Params print_settings; @@ -1443,7 +1438,7 @@ bool PrintWebViewHelper::GetPrintSettingsFromUser(WebKit::WebFrame* frame, // PrintHostMsg_ScriptedPrint will reset print_scaling_option, so we save the // value before and restore it afterwards. - WebKit::WebPrintScalingOption scaling_option = + blink::WebPrintScalingOption scaling_option = print_pages_params_->params.print_scaling_option; print_pages_params_.reset(); @@ -1457,8 +1452,8 @@ bool PrintWebViewHelper::GetPrintSettingsFromUser(WebKit::WebFrame* frame, return (print_settings.params.dpi && print_settings.params.document_cookie); } -bool PrintWebViewHelper::RenderPagesForPrint(WebKit::WebFrame* frame, - const WebKit::WebNode& node) { +bool PrintWebViewHelper::RenderPagesForPrint(blink::WebFrame* frame, + const blink::WebNode& node) { if (prep_frame_view_) return false; const PrintMsg_PrintPages_Params& params = *print_pages_params_; @@ -1498,7 +1493,7 @@ bool PrintWebViewHelper::CopyMetafileDataToSharedMem( #endif // defined(OS_POSIX) bool PrintWebViewHelper::IsScriptInitiatedPrintTooFrequent( - WebKit::WebFrame* frame) { + blink::WebFrame* frame) { const int kMinSecondsToIgnoreJavascriptInitiatedPrint = 2; const int kMaxSecondsToIgnoreJavascriptInitiatedPrint = 32; bool too_frequent = false; @@ -1526,11 +1521,11 @@ bool PrintWebViewHelper::IsScriptInitiatedPrintTooFrequent( if (!too_frequent) return false; - WebKit::WebString message( - WebKit::WebString::fromUTF8("Ignoring too frequent calls to print().")); + blink::WebString message( + blink::WebString::fromUTF8("Ignoring too frequent calls to print().")); frame->addMessageToConsole( - WebKit::WebConsoleMessage( - WebKit::WebConsoleMessage::LevelWarning, message)); + blink::WebConsoleMessage( + blink::WebConsoleMessage::LevelWarning, message)); return true; } @@ -1639,7 +1634,7 @@ PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() { } void PrintWebViewHelper::PrintPreviewContext::InitWithFrame( - WebKit::WebFrame* web_frame) { + blink::WebFrame* web_frame) { DCHECK(web_frame); DCHECK(!IsRendering()); state_ = INITIALIZED; @@ -1648,7 +1643,7 @@ void PrintWebViewHelper::PrintPreviewContext::InitWithFrame( } void PrintWebViewHelper::PrintPreviewContext::InitWithNode( - const WebKit::WebNode& web_node) { + const blink::WebNode& web_node) { DCHECK(!web_node.isNull()); DCHECK(web_node.document().frame()); DCHECK(!IsRendering()); @@ -1815,27 +1810,27 @@ void PrintWebViewHelper::PrintPreviewContext::set_error( error_ = error; } -WebKit::WebFrame* PrintWebViewHelper::PrintPreviewContext::source_frame() { +blink::WebFrame* PrintWebViewHelper::PrintPreviewContext::source_frame() { // TODO(thestig) turn this back into a DCHECK when http://crbug.com/118303 is // resolved. CHECK(state_ != UNINITIALIZED); return source_frame_; } -const WebKit::WebNode& +const blink::WebNode& PrintWebViewHelper::PrintPreviewContext::source_node() const { DCHECK(state_ != UNINITIALIZED); return source_node_; } -WebKit::WebFrame* PrintWebViewHelper::PrintPreviewContext::prepared_frame() { +blink::WebFrame* PrintWebViewHelper::PrintPreviewContext::prepared_frame() { // TODO(thestig) turn this back into a DCHECK when http://crbug.com/118303 is // resolved. CHECK(state_ != UNINITIALIZED); return prep_frame_view_->frame(); } -const WebKit::WebNode& +const blink::WebNode& PrintWebViewHelper::PrintPreviewContext::prepared_node() const { DCHECK(state_ != UNINITIALIZED); return prep_frame_view_->node(); diff --git a/src/renderer/printing/print_web_view_helper.h b/src/renderer/printing/print_web_view_helper.h index 1bcd47dc8a..5298812be6 100644 --- a/src/renderer/printing/print_web_view_helper.h +++ b/src/renderer/printing/print_web_view_helper.h @@ -28,7 +28,7 @@ namespace base { class DictionaryValue; } -namespace WebKit { +namespace blink { class WebFrame; class WebView; } @@ -48,7 +48,7 @@ class PrintWebViewHelper explicit PrintWebViewHelper(content::RenderView* render_view); virtual ~PrintWebViewHelper(); - void PrintNode(const WebKit::WebNode& node); + void PrintNode(const blink::WebNode& node); private: friend class PrintWebViewHelperTestBase; @@ -92,7 +92,7 @@ class PrintWebViewHelper // RenderViewObserver implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void PrintPage(WebKit::WebFrame* frame, bool user_initiated) OVERRIDE; + virtual void PrintPage(blink::WebFrame* frame, bool user_initiated) OVERRIDE; // Message handlers --------------------------------------------------------- @@ -129,7 +129,7 @@ class PrintWebViewHelper // option is disabled for initiator renderer plugin. // // In all other cases, we scale the source page to fit the printable area. - WebKit::WebPrintScalingOption GetPrintScalingOption( + blink::WebPrintScalingOption GetPrintScalingOption( bool source_is_html, const base::DictionaryValue& job_settings, const PrintMsg_Print_Params& params); @@ -157,9 +157,6 @@ class PrintWebViewHelper // Finalize the print ready preview document. bool FinalizePrintReadyDocument(); - // Print / preview the node under the context menu. - void OnPrintNodeUnderContextMenu(); - // Print the pages for print preview. Do not display the native print dialog // for user settings. |job_settings| has new print job settings values. void OnPrintForPrintPreview(const base::DictionaryValue& job_settings); @@ -172,7 +169,7 @@ class PrintWebViewHelper // Main printing code ------------------------------------------------------- - void Print(WebKit::WebFrame* frame, const WebKit::WebNode& node); + void Print(blink::WebFrame* frame, const blink::WebNode& node); // Notification when printing is done - signal tear-down/free resources. void DidFinishPrinting(PrintingResult result); @@ -184,29 +181,29 @@ class PrintWebViewHelper bool InitPrintSettings(bool fit_to_paper_size); // Calculate number of pages in source document. - bool CalculateNumberOfPages(WebKit::WebFrame* frame, - const WebKit::WebNode& node, + bool CalculateNumberOfPages(blink::WebFrame* frame, + const blink::WebNode& node, int* number_of_pages); // Update the current print settings with new |passed_job_settings|. // |passed_job_settings| dictionary contains print job details such as printer // name, number of copies, page range, etc. - bool UpdatePrintSettings(WebKit::WebFrame* frame, - const WebKit::WebNode& node, + bool UpdatePrintSettings(blink::WebFrame* frame, + const blink::WebNode& node, const base::DictionaryValue& passed_job_settings); // Get final print settings from the user. // Return false if the user cancels or on error. - bool GetPrintSettingsFromUser(WebKit::WebFrame* frame, - const WebKit::WebNode& node, + bool GetPrintSettingsFromUser(blink::WebFrame* frame, + const blink::WebNode& node, int expected_pages_count); // Page Printing / Rendering ------------------------------------------------ void OnFramePreparedForPrintPages(); void PrintPages(); - bool PrintPagesNative(WebKit::WebFrame* frame, - const WebKit::WebNode& node, + bool PrintPagesNative(blink::WebFrame* frame, + const blink::WebNode& node, int page_count, const gfx::Size& canvas_size); void FinishFramePrinting(); @@ -215,23 +212,23 @@ class PrintWebViewHelper #if defined(USE_X11) void PrintPageInternal(const PrintMsg_PrintPage_Params& params, const gfx::Size& canvas_size, - WebKit::WebFrame* frame, + blink::WebFrame* frame, Metafile* metafile); #else void PrintPageInternal(const PrintMsg_PrintPage_Params& params, const gfx::Size& canvas_size, - WebKit::WebFrame* frame); + blink::WebFrame* frame); #endif // Render the frame for printing. - bool RenderPagesForPrint(WebKit::WebFrame* frame, - const WebKit::WebNode& node); + bool RenderPagesForPrint(blink::WebFrame* frame, + const blink::WebNode& node); // Platform specific helper function for rendering page(s) to |metafile|. #if defined(OS_WIN) void RenderPage(const PrintMsg_Print_Params& params, int page_number, - WebKit::WebFrame* frame, + blink::WebFrame* frame, bool is_preview, Metafile* metafile, double* scale_factor, @@ -240,7 +237,7 @@ class PrintWebViewHelper #elif defined(OS_MACOSX) void RenderPage(const PrintMsg_Print_Params& params, int page_number, - WebKit::WebFrame* frame, + blink::WebFrame* frame, bool is_preview, Metafile* metafile, gfx::Size* page_size, @@ -251,12 +248,12 @@ class PrintWebViewHelper // |page_number| is zero-based. // When method is called, canvas should be setup to draw to |canvas_area| // with |scale_factor|. - static float RenderPageContent(WebKit::WebFrame* frame, + static float RenderPageContent(blink::WebFrame* frame, int page_number, const gfx::Rect& canvas_area, const gfx::Rect& content_area, double scale_factor, - WebKit::WebCanvas* canvas); + blink::WebCanvas* canvas); // Helper methods ----------------------------------------------------------- @@ -265,7 +262,7 @@ class PrintWebViewHelper // Helper method to get page layout in points and fit to page if needed. static void ComputePageLayoutInPointsForCss( - WebKit::WebFrame* frame, + blink::WebFrame* frame, int page_index, const PrintMsg_Print_Params& default_params, bool ignore_css_margins, @@ -275,7 +272,7 @@ class PrintWebViewHelper // Given the |device| and |canvas| to draw on, prints the appropriate headers // and footers using strings from |header_footer_info| on to the canvas. static void PrintHeaderAndFooter( - WebKit::WebCanvas* canvas, + blink::WebCanvas* canvas, int page_number, int total_pages, float webkit_scale_factor, @@ -283,7 +280,7 @@ class PrintWebViewHelper const base::DictionaryValue& header_footer_info, const PrintMsg_Print_Params& params); - bool GetPrintFrame(WebKit::WebFrame** frame); + bool GetPrintFrame(blink::WebFrame** frame); // This reports the current time - |start_time| as the time to render a page. void ReportPreviewPageRenderTime(base::TimeTicks start_time); @@ -293,11 +290,11 @@ class PrintWebViewHelper // Return true if script initiated printing is currently // allowed. |user_initiated| should be true when a user event triggered the // script, most likely by pressing a print button on the page. - bool IsScriptInitiatedPrintAllowed(WebKit::WebFrame* frame, + bool IsScriptInitiatedPrintAllowed(blink::WebFrame* frame, bool user_initiated); // Returns true if script initiated printing occurs too often. - bool IsScriptInitiatedPrintTooFrequent(WebKit::WebFrame* frame); + bool IsScriptInitiatedPrintTooFrequent(blink::WebFrame* frame); // Reset the counter for script initiated printing. // Scripted printing will be allowed to continue. @@ -356,8 +353,8 @@ class PrintWebViewHelper // Initializes the print preview context. Need to be called to set // the |web_frame| / |web_node| to generate the print preview for. - void InitWithFrame(WebKit::WebFrame* web_frame); - void InitWithNode(const WebKit::WebNode& web_node); + void InitWithFrame(blink::WebFrame* web_frame); + void InitWithNode(const blink::WebNode& web_node); // Does bookkeeping at the beginning of print preview. void OnPrintPreview(); @@ -397,16 +394,16 @@ class PrintWebViewHelper // Getters // Original frame for which preview was requested. - WebKit::WebFrame* source_frame(); + blink::WebFrame* source_frame(); // Original node for which preview was requested. - const WebKit::WebNode& source_node() const; + const blink::WebNode& source_node() const; // Frame to be use to render preview. May be the same as source_frame(), or // generated from it, e.g. copy of selected block. - WebKit::WebFrame* prepared_frame(); + blink::WebFrame* prepared_frame(); // Node to be use to render preview. May be the same as source_node(), or // generated from it, e.g. copy of selected block. - const WebKit::WebNode& prepared_node() const; + const blink::WebNode& prepared_node() const; int total_page_count() const; bool generate_draft_pages() const; @@ -426,8 +423,8 @@ class PrintWebViewHelper void ClearContext(); // Specifies what to render for print preview. - WebKit::WebFrame* source_frame_; - WebKit::WebNode source_node_; + blink::WebFrame* source_frame_; + blink::WebNode source_node_; scoped_ptr prep_frame_view_; scoped_ptr metafile_; diff --git a/src/renderer/printing/print_web_view_helper_linux.cc b/src/renderer/printing/print_web_view_helper_linux.cc index 0039d99522..a55fd9d3d6 100644 --- a/src/renderer/printing/print_web_view_helper_linux.cc +++ b/src/renderer/printing/print_web_view_helper_linux.cc @@ -20,8 +20,8 @@ namespace printing { -using WebKit::WebFrame; -using WebKit::WebNode; +using blink::WebFrame; +using blink::WebNode; bool PrintWebViewHelper::RenderPreviewPage( int page_number, @@ -54,8 +54,8 @@ bool PrintWebViewHelper::RenderPreviewPage( return PreviewPageRendered(page_number, draft_metafile.get()); } -bool PrintWebViewHelper::PrintPagesNative(WebKit::WebFrame* frame, - const WebKit::WebNode& node, +bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, + const blink::WebNode& node, int page_count, const gfx::Size& canvas_size) { NativeMetafile metafile; @@ -88,7 +88,7 @@ bool PrintWebViewHelper::PrintPagesNative(WebKit::WebFrame* frame, PrintPageInternal(page_params, canvas_size, frame, &metafile); } - // WebKit::printEnd() for PDF should be called before metafile is closed. + // blink::printEnd() for PDF should be called before metafile is closed. FinishFramePrinting(); metafile.FinishDocument(); diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index 77a181b566..075c2e7e1d 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -41,7 +41,6 @@ #include "content/nw/src/nw_version.h" #include "components/autofill/content/renderer/autofill_agent.h" #include "components/autofill/content/renderer/password_autofill_agent.h" -#include "content/nw/src/renderer/autofill_agent.h" #include "content/nw/src/renderer/nw_render_view_observer.h" #include "content/nw/src/renderer/prerenderer/prerenderer_client.h" #include "content/nw/src/renderer/printing/print_web_view_helper.h" @@ -68,10 +67,10 @@ using content::RenderViewImpl; using autofill::AutofillAgent; using autofill::PasswordAutofillAgent; using net::ProxyBypassRules; -using WebKit::WebFrame; -using WebKit::WebView; -using WebKit::WebString; -using WebKit::WebSecurityPolicy; +using blink::WebFrame; +using blink::WebView; +using blink::WebString; +using blink::WebSecurityPolicy; namespace content { @@ -106,10 +105,10 @@ void ShellContentRendererClient::RenderThreadStarted() { // Change working directory. CommandLine* command_line = CommandLine::ForCurrentProcess(); if (command_line->HasSwitch(switches::kWorkingDirectory)) { - file_util::SetCurrentDirectory( + base::SetCurrentDirectory( command_line->GetSwitchValuePath(switches::kWorkingDirectory)); } - +#if 0 int argc = 1; char* argv[] = { const_cast("node"), NULL, NULL }; std::string node_main; @@ -138,10 +137,11 @@ void ShellContentRendererClient::RenderThreadStarted() { } // Initialize node after render thread is started. if (!snapshot_path.empty()) { - v8::V8::Initialize(snapshot_path.c_str()); + v8::V8::Initialize(); //FIXME }else v8::V8::Initialize(); - v8::HandleScope scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); // Install window bindings into node. The Window API is implemented in node's // context, so when a Shell changes to a new location and destroy previous @@ -154,19 +154,18 @@ void ShellContentRendererClient::RenderThreadStarted() { node::g_context.Reset(v8::Isolate::GetCurrent(), v8::Context::New(v8::Isolate::GetCurrent(), &extension_configuration)); - node::g_context->SetSecurityToken(v8::String::NewSymbol("nw-token", 8)); - node::g_context->Enter(); + v8::Local context = + v8::Local::New(isolate, node::g_context); + context->SetSecurityToken(v8::String::NewFromUtf8(isolate, "nw-token", v8::String::kInternalizedString)); + context->Enter(); - node::g_context->SetEmbedderData(0, v8::String::NewSymbol("node")); + context->SetEmbedderData(0, v8::String::NewFromUtf8(isolate, "node", v8::String::kInternalizedString)); // Setup node.js. - v8::Local context = - v8::Local::New(node::g_context->GetIsolate(), node::g_context); - node::SetupContext(argc, argv, context); #if !defined(OS_WIN) - v8::Local script = v8::Script::New(v8::String::New(( + v8::Local script = v8::Script::Compile(v8::String::NewFromUtf8(isolate, ( "process.__nwfds_to_close = [" + base::StringPrintf("%d", base::GlobalDescriptors::GetInstance()->Get(kPrimaryIPCChannel)) + "];" @@ -174,11 +173,14 @@ void ShellContentRendererClient::RenderThreadStarted() { CHECK(*script); script->Run(); #endif + +#endif //0 + // Start observers. shell_observer_.reset(new ShellRenderProcessObserver()); - WebString file_scheme(ASCIIToUTF16("file")); - WebString app_scheme(ASCIIToUTF16("app")); + WebString file_scheme(base::ASCIIToUTF16("file")); + WebString app_scheme(base::ASCIIToUTF16("app")); // file: resources should be allowed to receive CORS requests. WebSecurityPolicy::registerURLSchemeAsCORSEnabled(file_scheme); WebSecurityPolicy::registerURLSchemeAsCORSEnabled(app_scheme); @@ -193,11 +195,11 @@ void ShellContentRendererClient::RenderViewCreated(RenderView* render_view) { new printing::PrintWebViewHelper(render_view); #endif - nw::AutofillAgent* autofill_agent = new nw::AutofillAgent(render_view); + // FIXME: nw::AutofillAgent* autofill_agent = new nw::AutofillAgent(render_view); // The PageClickTracker is a RenderViewObserver, and hence will be freed when // the RenderView is destroyed. - new autofill::PageClickTracker(render_view, autofill_agent); + // FIXME: new autofill::PageClickTracker(render_view, autofill_agent); // PasswordAutofillAgent* password_autofill_agent = // new PasswordAutofillAgent(render_view); @@ -205,7 +207,7 @@ void ShellContentRendererClient::RenderViewCreated(RenderView* render_view) { } void ShellContentRendererClient::DidCreateScriptContext( - WebKit::WebFrame* frame, + blink::WebFrame* frame, v8::Handle context, int extension_group, int world_id) { @@ -215,7 +217,7 @@ void ShellContentRendererClient::DidCreateScriptContext( creating_first_context_ = false; } -bool ShellContentRendererClient::goodForNode(WebKit::WebFrame* frame) +bool ShellContentRendererClient::goodForNode(blink::WebFrame* frame) { RenderViewImpl* rv = RenderViewImpl::FromWebView(frame->view()); GURL url(frame->document().url()); @@ -231,13 +233,17 @@ bool ShellContentRendererClient::goodForNode(WebKit::WebFrame* frame) } bool ShellContentRendererClient::WillSetSecurityToken( - WebKit::WebFrame* frame, + blink::WebFrame* frame, v8::Handle context) { GURL url(frame->document().url()); VLOG(1) << "WillSetSecurityToken: " << url; if (goodForNode(frame)) { // Override context's security token - context->SetSecurityToken(node::g_context->GetSecurityToken()); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + v8::Local g_context = + v8::Local::New(isolate, node::g_context); + context->SetSecurityToken(g_context->GetSecurityToken()); frame->document().securityOrigin().grantUniversalAccess(); int ret = 0; @@ -256,19 +262,22 @@ bool ShellContentRendererClient::WillSetSecurityToken( } void ShellContentRendererClient::InstallNodeSymbols( - WebKit::WebFrame* frame, + blink::WebFrame* frame, v8::Handle context, const GURL& url) { - v8::HandleScope handle_scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + v8::Local g_context = + v8::Local::New(isolate, node::g_context); static bool installed_once = false; - v8::Local nodeGlobal = node::g_context->Global(); + v8::Local nodeGlobal = g_context->Global(); v8::Local v8Global = context->Global(); // Use WebKit's console globally - nodeGlobal->Set(v8::String::New("console"), - v8Global->Get(v8::String::New("console"))); + nodeGlobal->Set(v8::String::NewFromUtf8(isolate, "console"), + v8Global->Get(v8::String::NewFromUtf8(isolate, "console"))); // Do we integrate node? bool use_node = goodForNode(frame); @@ -281,11 +290,11 @@ void ShellContentRendererClient::InstallNodeSymbols( if (use_node || is_nw_protocol) { frame->setNodeJS(true); - v8::Local symbols = v8::Array::New(4); - symbols->Set(0, v8::String::New("global")); - symbols->Set(1, v8::String::New("process")); - symbols->Set(2, v8::String::New("Buffer")); - symbols->Set(3, v8::String::New("root")); + v8::Local symbols = v8::Array::New(isolate, 4); + symbols->Set(0, v8::String::NewFromUtf8(isolate, "global")); + symbols->Set(1, v8::String::NewFromUtf8(isolate, "process")); + symbols->Set(2, v8::String::NewFromUtf8(isolate, "Buffer")); + symbols->Set(3, v8::String::NewFromUtf8(isolate, "root")); for (unsigned i = 0; i < symbols->Length(); ++i) { v8::Local key = symbols->Get(i); @@ -300,13 +309,13 @@ void ShellContentRendererClient::InstallNodeSymbols( // reference to the closure created by the call back and leak // memory (see #203) - nodeGlobal->Set(v8::String::New("window"), v8Global); + nodeGlobal->Set(v8::String::NewFromUtf8(isolate, "window"), v8Global); // Listen uncaughtException with ReportException. - v8::Local cb = v8::FunctionTemplate::New(ReportException)-> + v8::Local cb = v8::FunctionTemplate::New(isolate, ReportException)-> GetFunction(); - v8::Local argv[] = { v8::String::New("uncaughtException"), cb }; - node::MakeCallback(node::g_env->process_object(), "on", 2, argv); + v8::Local argv[] = { v8::String::NewFromUtf8(isolate, "uncaughtException"), cb }; + node::MakeCallback(isolate, node::g_env->process_object(), "on", 2, argv); } } @@ -314,10 +323,10 @@ void ShellContentRendererClient::InstallNodeSymbols( RenderViewImpl* rv = RenderViewImpl::FromWebView(frame->view()); std::string root_path = rv->renderer_preferences_.nw_app_root_path.AsUTF8Unsafe(); #if defined(OS_WIN) - ReplaceChars(root_path, "\\", "\\\\", &root_path); + base::ReplaceChars(root_path, "\\", "\\\\", &root_path); #endif - ReplaceChars(root_path, "'", "\\'", &root_path); - v8::Local script = v8::Script::New(v8::String::New(( + base::ReplaceChars(root_path, "'", "\\'", &root_path); + v8::Local script = v8::Script::Compile(v8::String::NewFromUtf8(isolate, ( // Make node's relative modules work "if (!process.mainModule.filename) {" " var root = '" + root_path + "';" @@ -330,13 +339,13 @@ void ShellContentRendererClient::InstallNodeSymbols( "process.mainModule.paths = global.require('module')._nodeModulePaths(process.cwd());" "process.mainModule.loaded = true;" "}").c_str() - )); + )); CHECK(*script); script->Run(); } if (use_node || is_nw_protocol) { - v8::Local script = v8::Script::New(v8::String::New( + v8::Local script = v8::Script::Compile(v8::String::NewFromUtf8(isolate, // Overload require "window.require = function(name) {" " if (name == 'nw.gui')" @@ -349,7 +358,7 @@ void ShellContentRendererClient::InstallNodeSymbols( "process.versions['chromium'] = '" CHROME_VERSION "';" )); script->Run(); - v8::Local script2 = v8::Script::New(v8::String::New( + v8::Local script2 = v8::Script::Compile(v8::String::NewFromUtf8(isolate, " nwDispatcher.requireNwGui().Window.get();" )); script2->Run(); @@ -362,32 +371,34 @@ void ShellContentRendererClient::InstallNodeSymbols( // could override parent settings here render_view->Send(new ShellViewHostMsg_SetForceClose( render_view->GetRoutingID(), true, &ret)); + } } } // static void ShellContentRendererClient::ReportException( const v8::FunctionCallbackInfo& args) { - v8::HandleScope handle_scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); // Do nothing if user is listening to uncaughtException. v8::Local listeners_v = - node::g_env->process_object()->Get(v8::String::New("listeners")); + node::g_env->process_object()->Get(v8::String::NewFromUtf8(isolate, "listeners")); v8::Local listeners = v8::Local::Cast(listeners_v); - v8::Local argv[1] = { v8::String::New("uncaughtException") }; + v8::Local argv[1] = { v8::String::NewFromUtf8(isolate, "uncaughtException") }; v8::Local ret = listeners->Call(node::g_env->process_object(), 1, argv); v8::Local listener_array = v8::Local::Cast(ret); uint32_t length = listener_array->Length(); if (length > 1) { - args.GetReturnValue().Set(v8::Undefined()); + args.GetReturnValue().Set(v8::Undefined(isolate)); return; } // Print stacktrace. - v8::Local stack_symbol = v8::String::New("stack"); + v8::Local stack_symbol = v8::String::NewFromUtf8(isolate, "stack"); std::string error; v8::Local exception = args[0]->ToObject(); @@ -398,7 +409,7 @@ void ShellContentRendererClient::ReportException( RenderView* render_view = GetCurrentRenderView(); if (!render_view) { - args.GetReturnValue().Set(v8::Undefined()); + args.GetReturnValue().Set(v8::Undefined(isolate)); return; } @@ -406,21 +417,22 @@ void ShellContentRendererClient::ReportException( render_view->GetRoutingID(), error)); - args.GetReturnValue().Set(v8::Undefined()); + args.GetReturnValue().Set(v8::Undefined(isolate)); } void ShellContentRendererClient::UninstallNodeSymbols( - WebKit::WebFrame* frame, + blink::WebFrame* frame, v8::Handle context) { - v8::HandleScope handle_scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); v8::Local v8Global = context->Global(); - v8::Local symbols = v8::Array::New(5); - symbols->Set(0, v8::String::New("global")); - symbols->Set(1, v8::String::New("process")); - symbols->Set(2, v8::String::New("Buffer")); - symbols->Set(3, v8::String::New("root")); - symbols->Set(4, v8::String::New("require")); + v8::Local symbols = v8::Array::New(isolate, 5); + symbols->Set(0, v8::String::NewFromUtf8(isolate, "global")); + symbols->Set(1, v8::String::NewFromUtf8(isolate, "process")); + symbols->Set(2, v8::String::NewFromUtf8(isolate, "Buffer")); + symbols->Set(3, v8::String::NewFromUtf8(isolate, "root")); + symbols->Set(4, v8::String::NewFromUtf8(isolate, "require")); for (unsigned i = 0; i < symbols->Length(); ++i) { v8::Local key = symbols->Get(i)->ToString(); @@ -431,9 +443,9 @@ void ShellContentRendererClient::UninstallNodeSymbols( void ShellContentRendererClient::willHandleNavigationPolicy( RenderView* rv, - WebKit::WebFrame* frame, - const WebKit::WebURLRequest& request, - WebKit::WebNavigationPolicy* policy) { + blink::WebFrame* frame, + const blink::WebURLRequest& request, + blink::WebNavigationPolicy* policy) { nwapi::Dispatcher::willHandleNavigationPolicy(rv, frame, request, policy); } diff --git a/src/renderer/shell_content_renderer_client.h b/src/renderer/shell_content_renderer_client.h index 3a6aecbcd6..2e73788093 100644 --- a/src/renderer/shell_content_renderer_client.h +++ b/src/renderer/shell_content_renderer_client.h @@ -44,17 +44,17 @@ class ShellContentRendererClient : public ContentRendererClient { virtual void RenderThreadStarted() OVERRIDE; virtual void RenderViewCreated(RenderView* render_view) OVERRIDE; - virtual void DidCreateScriptContext(WebKit::WebFrame* frame, + virtual void DidCreateScriptContext(blink::WebFrame* frame, v8::Handle context, int extension_group, int world_id) OVERRIDE; - virtual bool WillSetSecurityToken(WebKit::WebFrame* frame, + virtual bool WillSetSecurityToken(blink::WebFrame* frame, v8::Handle) OVERRIDE; virtual void willHandleNavigationPolicy(RenderView* rv, - WebKit::WebFrame* frame, - const WebKit::WebURLRequest& request, - WebKit::WebNavigationPolicy* policy) OVERRIDE; + blink::WebFrame* frame, + const blink::WebURLRequest& request, + blink::WebNavigationPolicy* policy) OVERRIDE; private: scoped_ptr shell_observer_; @@ -62,11 +62,11 @@ class ShellContentRendererClient : public ContentRendererClient { bool creating_first_context_; - void InstallNodeSymbols(WebKit::WebFrame* frame, + void InstallNodeSymbols(blink::WebFrame* frame, v8::Handle context, const GURL& url); - void UninstallNodeSymbols(WebKit::WebFrame* frame, + void UninstallNodeSymbols(blink::WebFrame* frame, v8::Handle context); - bool goodForNode(WebKit::WebFrame* frame); + bool goodForNode(blink::WebFrame* frame); // Catch node uncaughtException. static void ReportException(const v8::FunctionCallbackInfo& args); diff --git a/src/renderer/shell_render_process_observer.cc b/src/renderer/shell_render_process_observer.cc index 5441b59fcf..325290f47f 100644 --- a/src/renderer/shell_render_process_observer.cc +++ b/src/renderer/shell_render_process_observer.cc @@ -25,8 +25,7 @@ #include "content/public/renderer/render_thread.h" #include "content/nw/src/api/api_messages.h" #include "content/nw/src/api/dispatcher_bindings.h" -#include "content/shell/renderer/gc_extension.h" -#include "webkit/glue/webkit_glue.h" +//#include "content/shell/renderer/gc_extension.h" #include "third_party/node/src/node.h" #undef CHECK #include "third_party/node/src/node_internals.h" @@ -35,7 +34,7 @@ #include "third_party/WebKit/public/web/WebRuntimeFeatures.h" #include "v8/include/v8.h" -using WebKit::WebRuntimeFeatures; +using blink::WebRuntimeFeatures; namespace content { @@ -72,36 +71,38 @@ void ShellRenderProcessObserver::WebKitInitialized() { } void ShellRenderProcessObserver::OnOpen(const std::string& path) { - v8::HandleScope handle_scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); // the App object is stored in process["_nw_app"]. v8::Local process = node::g_env->process_object(); - v8::Local app_symbol = v8::String::NewSymbol("_nw_app"); + v8::Local app_symbol = v8::String::NewFromUtf8(isolate, "_nw_app", v8::String::kInternalizedString); if (process->Has(app_symbol)) { // process["_nw_app"].emit(path). v8::Local app = process->Get(app_symbol)->ToObject(); v8::Local emit = v8::Local::Cast( - app->Get(v8::String::New("emit"))); + app->Get(v8::String::NewFromUtf8(isolate, "emit"))); v8::Local argv[] = { - v8::String::New("open"), v8::String::New(path.c_str()) + v8::String::NewFromUtf8(isolate, "open"), v8::String::NewFromUtf8(isolate, path.c_str()) }; emit->Call(app, 2, argv); } } void ShellRenderProcessObserver::OnReopen() { - v8::HandleScope handle_scope; + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); // the App object is stored in process["_nw_app"]. v8::Local process = node::g_env->process_object(); - v8::Local app_symbol = v8::String::NewSymbol("_nw_app"); + v8::Local app_symbol = v8::String::NewFromUtf8(isolate, "_nw_app", v8::String::kInternalizedString); if (process->Has(app_symbol)) { // process["_nw_app"].emit(path). v8::Local app = process->Get(app_symbol)->ToObject(); v8::Local emit = v8::Local::Cast( - app->Get(v8::String::New("emit"))); + app->Get(v8::String::NewFromUtf8(isolate, "emit"))); v8::Local argv[] = { - v8::String::New("reopen") + v8::String::NewFromUtf8(isolate, "reopen") }; emit->Call(app, 1, argv); } @@ -109,7 +110,7 @@ void ShellRenderProcessObserver::OnReopen() { void ShellRenderProcessObserver::OnClearCache() { if (webkit_initialized_) - WebKit::WebCache::clear(); + blink::WebCache::clear(); } } // namespace content diff --git a/src/shell_browser_context.cc b/src/shell_browser_context.cc index e7edd8176e..48a56e4c67 100644 --- a/src/shell_browser_context.cc +++ b/src/shell_browser_context.cc @@ -127,7 +127,7 @@ void ShellBrowserContext::InitWhileIOAllowed() { #endif if (!base::PathExists(path_)) - file_util::CreateDirectory(path_); + base::CreateDirectory(path_); } FilePath ShellBrowserContext::GetPath() const { @@ -154,7 +154,9 @@ net::URLRequestContextGetter* ShellBrowserContext::GetRequestContext() { } net::URLRequestContextGetter* ShellBrowserContext::CreateRequestContext( - ProtocolHandlerMap* protocol_handlers) { + ProtocolHandlerMap* protocol_handlers, + ProtocolHandlerScopedVector protocol_interceptors) { + DCHECK(!url_request_getter_); CommandLine* cmd_line = CommandLine::ForCurrentProcess(); std::string auth_server_whitelist = @@ -228,20 +230,36 @@ quota::SpecialStoragePolicy* ShellBrowserContext::GetSpecialStoragePolicy() { return NULL; } -void ShellBrowserContext::RequestMIDISysExPermission( +void ShellBrowserContext::RequestMidiSysExPermission( int render_process_id, int render_view_id, int bridge_id, const GURL& requesting_frame, - const MIDISysExPermissionCallback& callback) { + bool user_gesture, + const MidiSysExPermissionCallback& callback) { callback.Run(true); } -void ShellBrowserContext::CancelMIDISysExPermissionRequest( +void ShellBrowserContext::CancelMidiSysExPermissionRequest( int render_process_id, int render_view_id, int bridge_id, const GURL& requesting_frame) { } +void ShellBrowserContext::RequestProtectedMediaIdentifierPermission( + int render_process_id, + int render_view_id, + int bridge_id, + int group_id, + const GURL& requesting_frame, + const ProtectedMediaIdentifierPermissionCallback& callback) { + callback.Run(true); +} + +void ShellBrowserContext::CancelProtectedMediaIdentifierPermissionRequests( + int group_id) { +} + + } // namespace content diff --git a/src/shell_browser_context.h b/src/shell_browser_context.h index 372c243b7c..ff42d55f74 100644 --- a/src/shell_browser_context.h +++ b/src/shell_browser_context.h @@ -51,25 +51,36 @@ class ShellBrowserContext : public BrowserContext { virtual GeolocationPermissionContext* GetGeolocationPermissionContext() OVERRIDE; virtual quota::SpecialStoragePolicy* GetSpecialStoragePolicy() OVERRIDE; - virtual void RequestMIDISysExPermission( + + virtual void RequestMidiSysExPermission( int render_process_id, int render_view_id, int bridge_id, const GURL& requesting_frame, - const MIDISysExPermissionCallback& callback) OVERRIDE; - virtual void CancelMIDISysExPermissionRequest( - int render_process_id, - int render_view_id, - int bridge_id, - const GURL& requesting_frame) OVERRIDE; - - - net::URLRequestContextGetter* CreateRequestContext( - ProtocolHandlerMap* protocol_handlers); - net::URLRequestContextGetter* CreateRequestContextForStoragePartition( + bool user_gesture, + const MidiSysExPermissionCallback& callback) OVERRIDE; + virtual void CancelMidiSysExPermissionRequest( + int render_process_id, + int render_view_id, + int bridge_id, + const GURL& requesting_frame) OVERRIDE; + virtual void RequestProtectedMediaIdentifierPermission( + int render_process_id, + int render_view_id, + int bridge_id, + int group_id, + const GURL& requesting_frame, + const ProtectedMediaIdentifierPermissionCallback& callback) OVERRIDE; + virtual void CancelProtectedMediaIdentifierPermissionRequests( + int group_id) OVERRIDE; + + virtual net::URLRequestContextGetter* CreateRequestContext( + ProtocolHandlerMap* protocol_handlers, + ProtocolHandlerScopedVector protocol_interceptors) OVERRIDE; + virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition( const base::FilePath& partition_path, bool in_memory, - ProtocolHandlerMap* protocol_handlers); + ProtocolHandlerMap* protocol_handlers) OVERRIDE; bool pinning_renderer() { return !disable_pinning_renderer_; } void set_pinning_renderer(bool val) { disable_pinning_renderer_ = !val; } diff --git a/src/shell_browser_main_parts.cc b/src/shell_browser_main_parts.cc index f12b8aa500..a64c5ce1fb 100644 --- a/src/shell_browser_main_parts.cc +++ b/src/shell_browser_main_parts.cc @@ -141,7 +141,7 @@ void ShellBrowserMainParts::PostMainMessageLoopRun() { void ShellBrowserMainParts::PostMainMessageLoopStart() { #if defined(TOOLKIT_GTK) - printing::PrintingContextGtk::SetCreatePrintDialogFunction( + printing::PrintingContextLinux::SetCreatePrintDialogFunction( &PrintDialogGtk::CreatePrintDialog); #endif } diff --git a/src/shell_content_browser_client.cc b/src/shell_content_browser_client.cc index 3b5b63cc8e..6965b595e2 100644 --- a/src/shell_content_browser_client.cc +++ b/src/shell_content_browser_client.cc @@ -66,10 +66,10 @@ #include "ui/base/ui_base_switches.h" #include "content/common/dom_storage/dom_storage_map.h" #include "webkit/common/webpreferences.h" -#include "webkit/common/user_agent/user_agent_util.h" +#include "content/public/common/user_agent.h" #include "content/common/plugin_list.h" #include "content/public/browser/plugin_service.h" - +#include "chrome/common/chrome_switches.h" #if defined(OS_LINUX) #include "base/linux_util.h" #include "content/nw/src/crash_handler_host_linux.h" @@ -128,8 +128,8 @@ bool ShellContentBrowserClient::GetUserAgentManifest(std::string* agent) { ReplaceSubstringsAfterOffset(&user_agent, 0, "%name", name); ReplaceSubstringsAfterOffset(&user_agent, 0, "%ver", version); ReplaceSubstringsAfterOffset(&user_agent, 0, "%nwver", NW_VERSION_STRING); - ReplaceSubstringsAfterOffset(&user_agent, 0, "%webkit_ver", webkit_glue::GetWebKitVersion()); - ReplaceSubstringsAfterOffset(&user_agent, 0, "%osinfo", webkit_glue::BuildOSInfo()); + ReplaceSubstringsAfterOffset(&user_agent, 0, "%webkit_ver", content::GetWebKitVersion()); + ReplaceSubstringsAfterOffset(&user_agent, 0, "%osinfo", content::BuildOSInfo()); *agent = user_agent; return true; } @@ -157,6 +157,8 @@ WebContentsViewPort* ShellContentBrowserClient::OverrideCreateWebContentsView( } std::string ShellContentBrowserClient::GetApplicationLocale() { + base::ThreadRestrictions::ScopedAllowIO allow_io; + CommandLine* cmd_line = CommandLine::ForCurrentProcess(); std::string pref_locale; if (cmd_line->HasSwitch(switches::kLang)) { @@ -331,10 +333,11 @@ bool ShellContentBrowserClient::IsSuitableHost(RenderProcessHost* process_host, net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext( BrowserContext* content_browser_context, - ProtocolHandlerMap* protocol_handlers) { + ProtocolHandlerMap* protocol_handlers, + ProtocolHandlerScopedVector protocol_interceptors) { ShellBrowserContext* shell_browser_context = ShellBrowserContextForBrowserContext(content_browser_context); - return shell_browser_context->CreateRequestContext(protocol_handlers); + return shell_browser_context->CreateRequestContext(protocol_handlers, protocol_interceptors.Pass()); } net::URLRequestContextGetter* @@ -371,7 +374,7 @@ void ShellContentBrowserClient::RenderProcessHostCreated( // Grant file: scheme to the whole process, since we impose // per-view access checks. content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme( - host->GetID(), chrome::kFileScheme); + host->GetID(), content::kFileScheme); content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme( host->GetID(), "app"); @@ -387,8 +390,8 @@ bool ShellContentBrowserClient::IsHandledURL(const GURL& url) { // Keep in sync with ProtocolHandlers added by // ShellURLRequestContextGetter::GetURLRequestContext(). static const char* const kProtocolList[] = { - chrome::kFileSystemScheme, - chrome::kFileScheme, + content::kFileSystemScheme, + content::kFileScheme, "app", }; for (size_t i = 0; i < arraysize(kProtocolList); ++i) { diff --git a/src/shell_content_browser_client.h b/src/shell_content_browser_client.h index a6d54eebc8..ceda35317b 100644 --- a/src/shell_content_browser_client.h +++ b/src/shell_content_browser_client.h @@ -37,7 +37,7 @@ class ShellContentBrowserClient : public ContentBrowserClient { RenderViewHostDelegateView** render_view_host_delegate_view, const WebContents::CreateParams& params) OVERRIDE; virtual std::string GetApplicationLocale() OVERRIDE; - virtual void AppendExtraCommandLineSwitches(CommandLine* command_line, + virtual void AppendExtraCommandLineSwitches(base::CommandLine* command_line, int child_process_id) OVERRIDE; virtual void ResourceDispatcherHostCreated() OVERRIDE; virtual AccessTokenStore* CreateAccessTokenStore() OVERRIDE; @@ -65,7 +65,7 @@ class ShellContentBrowserClient : public ContentBrowserClient { virtual void RenderProcessHostCreated(RenderProcessHost* host) OVERRIDE; virtual net::URLRequestContextGetter* CreateRequestContext( BrowserContext* browser_context, - ProtocolHandlerMap* protocol_handlers) OVERRIDE; + ProtocolHandlerMap* protocol_handlers, ProtocolHandlerScopedVector protocol_interceptors) OVERRIDE; virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition( BrowserContext* browser_context, const base::FilePath& partition_path, @@ -86,7 +86,7 @@ class ShellContentBrowserClient : public ContentBrowserClient { std::vector* additional_schemes) OVERRIDE; #if defined(OS_POSIX) && !defined(OS_MACOSX) virtual void GetAdditionalMappedFilesForChildProcess( - const CommandLine& command_line, + const base::CommandLine& command_line, int child_process_id, std::vector* mappings) OVERRIDE; #endif diff --git a/src/shell_content_client.cc b/src/shell_content_client.cc index 4b42ed7e77..581940d71c 100644 --- a/src/shell_content_client.cc +++ b/src/shell_content_client.cc @@ -24,9 +24,9 @@ #include "content/nw/src/api/api_messages.h" #include "content/nw/src/nw_version.h" #include "content/nw/src/renderer/common/render_messages.h" +#include "content/public/common/user_agent.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" -#include "webkit/common/user_agent/user_agent_util.h" namespace content { @@ -34,10 +34,10 @@ ShellContentClient::~ShellContentClient() { } std::string ShellContentClient::GetUserAgent() const { - return webkit_glue::BuildUserAgentFromProduct("Chrome/" CHROME_VERSION); + return content::BuildUserAgentFromProduct("Chrome/" CHROME_VERSION); } -string16 ShellContentClient::GetLocalizedString(int message_id) const { +base::string16 ShellContentClient::GetLocalizedString(int message_id) const { return l10n_util::GetStringUTF16(message_id); } diff --git a/src/shell_content_client.h b/src/shell_content_client.h index 09f4701611..1284655387 100644 --- a/src/shell_content_client.h +++ b/src/shell_content_client.h @@ -18,7 +18,7 @@ class ShellContentClient : public ContentClient { virtual ~ShellContentClient(); virtual std::string GetUserAgent() const OVERRIDE; - virtual string16 GetLocalizedString(int message_id) const OVERRIDE; + virtual base::string16 GetLocalizedString(int message_id) const OVERRIDE; virtual base::StringPiece GetDataResource( int resource_id, ui::ScaleFactor scale_factor) const OVERRIDE; diff --git a/src/shell_main.cc b/src/shell_main.cc index 2148f4f3be..02b706163b 100644 --- a/src/shell_main.cc +++ b/src/shell_main.cc @@ -49,7 +49,10 @@ int main(int argc, const char** argv) { return ::ContentMain(argc, argv); #else content::ShellMainDelegate delegate; - return content::ContentMain(argc, argv, &delegate); + content::ContentMainParams params(&delegate); + params.argc = argc; + params.argv = argv; + return content::ContentMain(params); #endif // OS_MACOSX } diff --git a/src/shell_main_delegate.cc b/src/shell_main_delegate.cc index 0d9b2bfafe..c132a66a6b 100644 --- a/src/shell_main_delegate.cc +++ b/src/shell_main_delegate.cc @@ -70,7 +70,7 @@ using base::FilePath; #define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \ content::RegisterIPCLogger(msg_id, logger) #include "content/nw/src/common/common_message_generator.h" -#include "components/autofill/core/common/autofill_messages.h" +//#include "components/autofill/core/common/autofill_messages.h" #endif namespace { @@ -130,7 +130,7 @@ bool ShellMainDelegate::BasicStartupComplete(int* exit_code) { #endif InitLogging(); - net::CookieMonster::EnableFileScheme(); + // FIXME: net::CookieMonster::EnableFileScheme(); SetContentClient(&content_client_); return false; From 3b9f9767c1bebfc555cddf4d52b27feef71a223b Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 5 Jun 2014 13:46:37 +0800 Subject: [PATCH 035/492] Support for 'single-instance' when app is started in folder Fix #515 --- src/shell_browser_main_parts.cc | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/shell_browser_main_parts.cc b/src/shell_browser_main_parts.cc index f12b8aa500..94a2d1cbe0 100644 --- a/src/shell_browser_main_parts.cc +++ b/src/shell_browser_main_parts.cc @@ -199,10 +199,6 @@ void ShellBrowserMainParts::Init() { bool ShellBrowserMainParts::ProcessSingletonNotificationCallback( const CommandLine& command_line, const base::FilePath& current_directory) { - if (!package_->self_extract()) { - // We're in runtime mode, create the new app. - return false; - } // Don't reuse current instance if 'single-instance' is specified to false. bool single_instance; From 2ec10f2170f686c1f1d01a2a0b3b95070a2975ad Mon Sep 17 00:00:00 2001 From: Gnor Tech Date: Fri, 6 Jun 2014 09:45:57 +0800 Subject: [PATCH 036/492] Fix navigation from urlbar --- src/api/dispatcher.cc | 3 ++- src/nw_shell.cc | 14 +++++++++----- src/renderer/shell_content_renderer_client.cc | 15 +++++++++++++++ src/renderer/shell_content_renderer_client.h | 3 +++ 4 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/api/dispatcher.cc b/src/api/dispatcher.cc index 7722148fb3..474a3b4db7 100644 --- a/src/api/dispatcher.cc +++ b/src/api/dispatcher.cc @@ -207,7 +207,6 @@ void Dispatcher::willHandleNavigationPolicy( return; v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::Context::Scope cscope (web_view->mainFrame()->mainWorldScriptContext()); v8::Handle id_val = nwapi::Dispatcher::GetWindowId(web_view->mainFrame()); if (id_val->IsNull() || id_val->IsUndefined()) @@ -217,6 +216,8 @@ void Dispatcher::willHandleNavigationPolicy( if (objects_registry->IsUndefined()) return; + v8::Context::Scope cscope (web_view->mainFrame()->mainWorldScriptContext()); + v8::Local args = v8::Array::New(isolate); v8::Handle element = v8::Null(isolate); v8::Handle policy_obj = v8::Object::New(isolate); diff --git a/src/nw_shell.cc b/src/nw_shell.cc index dcde623269..c9e1db9ef8 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -312,11 +312,15 @@ nw::Package* Shell::GetPackage() { } void Shell::LoadURL(const GURL& url) { - web_contents_->GetController().LoadURL( - url, - Referrer(), - PAGE_TRANSITION_TYPED, - std::string()); + NavigationController::LoadURLParams params(url); + params.transition_type = PageTransitionFromInt( + PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR); + web_contents_->GetController().LoadURLWithParams(params); + // web_contents_->GetController().LoadURL( + // url, + // Referrer(), + // PAGE_TRANSITION_TYPED, + // std::string()); web_contents_->GetView()->Focus(); window()->SetToolbarButtonEnabled(nw::NativeWindow::BUTTON_FORWARD, false); } diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index 075c2e7e1d..f724b8bc6f 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -221,6 +221,17 @@ bool ShellContentRendererClient::goodForNode(blink::WebFrame* frame) { RenderViewImpl* rv = RenderViewImpl::FromWebView(frame->view()); GURL url(frame->document().url()); + + // the way to tell the loading URL is not reliable in some cases + // like navigation and window.open. Fortunately we are in + // willHandleNavigationPolicy callback so we can use the request url + // from there + + if (url.is_empty() && in_nav_cb_) { + ASSERT(!in_nav_url_.empty()); + url = GURL(in_nav_url_); + } + ProxyBypassRules rules; rules.ParseFromString(rv->renderer_preferences_.nw_remote_page_rules); bool force_on = rules.Matches(url); @@ -238,6 +249,7 @@ bool ShellContentRendererClient::WillSetSecurityToken( GURL url(frame->document().url()); VLOG(1) << "WillSetSecurityToken: " << url; if (goodForNode(frame)) { + VLOG(1) << "GOOD FOR NODE"; // Override context's security token v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::HandleScope scope(isolate); @@ -447,7 +459,10 @@ void ShellContentRendererClient::willHandleNavigationPolicy( const blink::WebURLRequest& request, blink::WebNavigationPolicy* policy) { + in_nav_cb_ = true; + in_nav_url_ = request.url().string().utf8(); nwapi::Dispatcher::willHandleNavigationPolicy(rv, frame, request, policy); + in_nav_cb_ = false; } } // namespace content diff --git a/src/renderer/shell_content_renderer_client.h b/src/renderer/shell_content_renderer_client.h index 2e73788093..9243ac3055 100644 --- a/src/renderer/shell_content_renderer_client.h +++ b/src/renderer/shell_content_renderer_client.h @@ -60,6 +60,9 @@ class ShellContentRendererClient : public ContentRendererClient { scoped_ptr shell_observer_; scoped_ptr window_bindings_; + bool in_nav_cb_; + std::string in_nav_url_; + bool creating_first_context_; void InstallNodeSymbols(blink::WebFrame* frame, From 7c3aadeaa601aea1ed88ad6b39352ae5fd8a78d6 Mon Sep 17 00:00:00 2001 From: libm Date: Thu, 5 Jun 2014 17:12:38 +0800 Subject: [PATCH 037/492] Flush stdout to inform buildbot that it is not hang. Added retry and let 'node-webkit-' bundle to be uploaded first. --- tools/aws_uploader.py | 23 +++++++++++++++++++++-- tools/package_binaries.py | 2 ++ 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/tools/aws_uploader.py b/tools/aws_uploader.py index b282cf0e96..872a332339 100755 --- a/tools/aws_uploader.py +++ b/tools/aws_uploader.py @@ -4,6 +4,8 @@ import datetime import json import os +import sys +import time # Set timeout, for retry @@ -53,24 +55,41 @@ print 'Cannot find packages!' exit(-1) +# move node-webkit- to the top of the list. +for i in range(len(file_list)): + fname = file_list[i] + if fname.startswith('node-webkit-v'): + del file_list[i] + file_list.insert(0,fname) + break def print_progress(transmitted, total): print ' %d%% transferred of total: %d bytes.' % (transmitted*100/total, total) + sys.stdout.flush() def aws_upload(upload_path, file_list): conn = boto.connect_s3() print 'Connecting to S3 ...' + sys.stdout.flush() bucket = conn.get_bucket(bucket_name) print 'Uploading to: ' + upload_path for f in file_list: print 'Uploading "' + f + '" ...' + sys.stdout.flush() # use '/' for s3 key = bucket.new_key(upload_path + '/' + f) key.set_contents_from_filename(filename=os.path.join(dist_dir, f), cb=print_progress, num_cb=50, replace=True) -aws_upload(upload_path, file_list) -print 'Done.' +for retry in range(3): + try: + aws_upload(upload_path, file_list) + break + except Exception, e: + print e + sys.stdout.flush() + time.sleep(30) #wait for 30s and try again. +print 'Done.' # vim: et:ts=4:sw=4 diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 9b971da236..7803683c49 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -111,6 +111,8 @@ def generate_target_nw(platform_name, arch, version): 'libGLESv2.dll', 'nw.exe', 'nw.pak', + 'nw.exp', + 'nw.lib', 'nwsnapshot.exe', 'credits.html', ] From 545fe0bd2e061308d20f6f9fea0495165eb3b7cf Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 8 Jun 2014 19:41:32 +0800 Subject: [PATCH 038/492] fix autofill agent --- nw.gypi | 14 +- src/browser/autofill_popup_controller.h | 88 +++ src/browser/autofill_popup_controller_impl.cc | 650 ++++++++++++++++++ src/browser/autofill_popup_controller_impl.h | 213 ++++++ src/browser/autofill_popup_view.h | 63 ++ src/browser/autofill_popup_view_delegate.h | 62 ++ src/browser/autofill_popup_view_gtk.cc | 327 +++++++++ src/browser/autofill_popup_view_gtk.h | 100 +++ src/browser/nw_form_database_service.cc | 127 ++++ src/browser/nw_form_database_service.h | 67 ++ src/browser/popup_controller_common.cc | 162 +++++ src/browser/popup_controller_common.h | 105 +++ src/browser/tab_autofill_manager_delegate.cc | 140 ++++ src/browser/tab_autofill_manager_delegate.h | 98 +++ src/nw_shell.cc | 20 +- src/renderer/shell_content_renderer_client.cc | 14 +- src/shell_browser_context.cc | 9 + src/shell_browser_context.h | 7 + src/shell_browser_main_parts.cc | 3 + src/shell_main_delegate.cc | 2 +- 20 files changed, 2266 insertions(+), 5 deletions(-) create mode 100644 src/browser/autofill_popup_controller.h create mode 100644 src/browser/autofill_popup_controller_impl.cc create mode 100644 src/browser/autofill_popup_controller_impl.h create mode 100644 src/browser/autofill_popup_view.h create mode 100644 src/browser/autofill_popup_view_delegate.h create mode 100644 src/browser/autofill_popup_view_gtk.cc create mode 100644 src/browser/autofill_popup_view_gtk.h create mode 100644 src/browser/nw_form_database_service.cc create mode 100644 src/browser/nw_form_database_service.h create mode 100644 src/browser/popup_controller_common.cc create mode 100644 src/browser/popup_controller_common.h create mode 100644 src/browser/tab_autofill_manager_delegate.cc create mode 100644 src/browser/tab_autofill_manager_delegate.h diff --git a/nw.gypi b/nw.gypi index 7f1ba04bb3..944f95af5a 100644 --- a/nw.gypi +++ b/nw.gypi @@ -38,6 +38,8 @@ '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', '<(DEPTH)/components/components.gyp:autofill_content_renderer', '<(DEPTH)/components/components.gyp:keyed_service_content', + '<(DEPTH)/components/components_resources.gyp:components_resources', + '<(DEPTH)/components/components.gyp:autofill_content_browser', '<(DEPTH)/content/content.gyp:content_app_browser', '<(DEPTH)/content/content.gyp:content_browser', '<(DEPTH)/content/content.gyp:content_common', @@ -169,6 +171,12 @@ 'src/api/window/window.h', 'src/browser/app_controller_mac.h', 'src/browser/app_controller_mac.mm', + 'src/browser/autofill_popup_view_gtk.cc', + 'src/browser/autofill_popup_view_gtk.h', + 'src/browser/autofill_popup_controller_impl.cc', + 'src/browser/autofill_popup_controller_impl.h', + 'src/browser/tab_autofill_manager_delegate.cc', + 'src/browser/tab_autofill_manager_delegate.h', 'src/browser/capture_page_helper.h', 'src/browser/capture_page_helper.cc', 'src/browser/color_chooser_gtk.cc', @@ -191,6 +199,10 @@ 'src/browser/native_window_win.h', 'src/browser/net_disk_cache_remover.cc', 'src/browser/net_disk_cache_remover.h', + 'src/browser/nw_form_database_service.cc', + 'src/browser/nw_form_database_service.h', + 'src/browser/popup_controller_common.cc', + 'src/browser/popup_controller_common.h', 'src/browser/printing/print_dialog_gtk.cc', 'src/browser/printing/print_dialog_gtk.h', 'src/browser/printing/print_job.cc', @@ -273,8 +285,6 @@ 'src/nw_version.h', 'src/paths_mac.h', 'src/paths_mac.mm', - # 'src/renderer/autofill_agent.cc', - # 'src/renderer/autofill_agent.h', 'src/renderer/common/render_messages.cc', 'src/renderer/common/render_messages.h', 'src/renderer/prerenderer/prerenderer_client.cc', diff --git a/src/browser/autofill_popup_controller.h b/src/browser/autofill_popup_controller.h new file mode 100644 index 0000000000..da66f3e987 --- /dev/null +++ b/src/browser/autofill_popup_controller.h @@ -0,0 +1,88 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_H_ +#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_H_ + +#include + +#include "base/compiler_specific.h" +#include "base/strings/string16.h" +#include "content/nw/src/browser/autofill_popup_view_delegate.h" + +namespace gfx { +class FontList; +class Point; +class Rect; +class RectF; +} + +namespace autofill { + +// This interface provides data to an AutofillPopupView. +class AutofillPopupController : public AutofillPopupViewDelegate { + public: + // Recalculates the height and width of the popup and triggers a redraw. + virtual void UpdateBoundsAndRedrawPopup() = 0; + + // Accepts the suggestion at |index|. + virtual void AcceptSuggestion(size_t index) = 0; + + // Gets the resource value for the given resource, returning -1 if the + // resource isn't recognized. + virtual int GetIconResourceID(const base::string16& resource_name) const = 0; + + // Returns true if the given index refers to an element that can be deleted. + virtual bool CanDelete(size_t index) const = 0; + + // Returns true if the given index refers to an element that is a warning + // rather than an Autofill suggestion. + virtual bool IsWarning(size_t index) const = 0; + + // Updates the bounds of the popup and initiates a redraw. + virtual void SetPopupBounds(const gfx::Rect& bounds) = 0; + + // Returns the bounds of the item at |index| in the popup, relative to + // the top left of the popup. + virtual gfx::Rect GetRowBounds(size_t index) = 0; + + // The bounds of the form field element (screen coordinates). + virtual const gfx::RectF& element_bounds() const = 0; + + // If the current popup should be displayed in RTL mode. + virtual bool IsRTL() const = 0; + + // TODO(csharp): The names, subtexts and icon getters can probably be adjusted + // to take in the row index and return a single element, instead of the + // whole vector. + // The main labels for each autofill item. + virtual const std::vector& names() const = 0; + + // Smaller labels for each autofill item. + virtual const std::vector& subtexts() const = 0; + + // A string which identifies the icon to be shown for each autofill item. + virtual const std::vector& icons() const = 0; + + // Identifier for the row. + virtual const std::vector& identifiers() const = 0; + +#if !defined(OS_ANDROID) + // The same font can vary based on the type of data it is showing, + // so we need to know the row. + virtual const gfx::FontList& GetNameFontListForRow(size_t index) const = 0; + virtual const gfx::FontList& subtext_font_list() const = 0; +#endif + + // Returns the index of the selected line. A line is "selected" when it is + // hovered or has keyboard focus. + virtual int selected_line() const = 0; + + protected: + virtual ~AutofillPopupController() {} +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_H_ diff --git a/src/browser/autofill_popup_controller_impl.cc b/src/browser/autofill_popup_controller_impl.cc new file mode 100644 index 0000000000..c85210e31b --- /dev/null +++ b/src/browser/autofill_popup_controller_impl.cc @@ -0,0 +1,650 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/autofill_popup_controller_impl.h" + +#include +#include + +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "content/nw/src/browser/autofill_popup_view.h" +#include "chrome/browser/ui/autofill/popup_constants.h" +#include "components/autofill/core/browser/autofill_popup_delegate.h" +#include "components/autofill/core/browser/popup_item_ids.h" +#include "content/public/browser/native_web_keyboard_event.h" +#include "grit/component_scaled_resources.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/events/event.h" +#include "ui/gfx/rect_conversions.h" +#include "ui/gfx/screen.h" +#include "ui/gfx/text_elider.h" +#include "ui/gfx/text_utils.h" +#include "ui/gfx/vector2d.h" + +using base::WeakPtr; + +namespace autofill { +namespace { + +// Used to indicate that no line is currently selected by the user. +const int kNoSelection = -1; + +// The vertical height of each row in pixels. +const size_t kRowHeight = 24; + +// The vertical height of a separator in pixels. +const size_t kSeparatorHeight = 1; + +#if !defined(OS_ANDROID) +// Size difference between name and subtext in pixels. +const int kLabelFontSizeDelta = -2; + +const size_t kNamePadding = AutofillPopupView::kNamePadding; +const size_t kIconPadding = AutofillPopupView::kIconPadding; +const size_t kEndPadding = AutofillPopupView::kEndPadding; +#endif + +struct DataResource { + const char* name; + int id; +}; + +const DataResource kDataResources[] = { + { "americanExpressCC", IDR_AUTOFILL_CC_AMEX }, + { "dinersCC", IDR_AUTOFILL_CC_DINERS }, + { "discoverCC", IDR_AUTOFILL_CC_DISCOVER }, + { "genericCC", IDR_AUTOFILL_CC_GENERIC }, + { "jcbCC", IDR_AUTOFILL_CC_JCB }, + { "masterCardCC", IDR_AUTOFILL_CC_MASTERCARD }, + { "visaCC", IDR_AUTOFILL_CC_VISA }, +}; + +} // namespace + +// static +WeakPtr AutofillPopupControllerImpl::GetOrCreate( + WeakPtr previous, + WeakPtr delegate, + content::WebContents* web_contents, + gfx::NativeView container_view, + const gfx::RectF& element_bounds, + base::i18n::TextDirection text_direction) { + DCHECK(!previous.get() || previous->delegate_.get() == delegate.get()); + + if (previous.get() && previous->web_contents() == web_contents && + previous->container_view() == container_view && + previous->element_bounds() == element_bounds) { + previous->ClearState(); + return previous; + } + + if (previous.get()) + previous->Hide(); + + AutofillPopupControllerImpl* controller = + new AutofillPopupControllerImpl( + delegate, web_contents, container_view, element_bounds, + text_direction); + return controller->GetWeakPtr(); +} + +AutofillPopupControllerImpl::AutofillPopupControllerImpl( + base::WeakPtr delegate, + content::WebContents* web_contents, + gfx::NativeView container_view, + const gfx::RectF& element_bounds, + base::i18n::TextDirection text_direction) + : controller_common_(new PopupControllerCommon(element_bounds, + container_view, + web_contents)), + view_(NULL), + delegate_(delegate), + text_direction_(text_direction), + hide_on_outside_click_(false), + weak_ptr_factory_(this) { + ClearState(); + controller_common_->SetKeyPressCallback( + base::Bind(&AutofillPopupControllerImpl::HandleKeyPressEvent, + base::Unretained(this))); +#if !defined(OS_ANDROID) + subtext_font_list_ = name_font_list_.DeriveWithSizeDelta(kLabelFontSizeDelta); +#if defined(OS_MACOSX) + // There is no italic version of the system font. + warning_font_list_ = name_font_list_; +#else + warning_font_list_ = name_font_list_.DeriveWithStyle(gfx::Font::ITALIC); +#endif +#endif +} + +AutofillPopupControllerImpl::~AutofillPopupControllerImpl() {} + +void AutofillPopupControllerImpl::Show( + const std::vector& names, + const std::vector& subtexts, + const std::vector& icons, + const std::vector& identifiers) { + SetValues(names, subtexts, icons, identifiers); + +#if !defined(OS_ANDROID) + // Android displays the long text with ellipsis using the view attributes. + + UpdatePopupBounds(); + int popup_width = popup_bounds().width(); + + // Elide the name and subtext strings so that the popup fits in the available + // space. + for (size_t i = 0; i < names_.size(); ++i) { + int name_width = gfx::GetStringWidth(names_[i], GetNameFontListForRow(i)); + int subtext_width = gfx::GetStringWidth(subtexts_[i], subtext_font_list()); + int total_text_length = name_width + subtext_width; + + // The line can have no strings if it represents a UI element, such as + // a separator line. + if (total_text_length == 0) + continue; + + int available_width = popup_width - RowWidthWithoutText(i); + + // Each field recieves space in proportion to its length. + int name_size = available_width * name_width / total_text_length; + names_[i] = gfx::ElideText(names_[i], + GetNameFontListForRow(i), + name_size, + gfx::ELIDE_AT_END); + + int subtext_size = available_width * subtext_width / total_text_length; + subtexts_[i] = gfx::ElideText(subtexts_[i], + subtext_font_list(), + subtext_size, + gfx::ELIDE_AT_END); + } +#endif + + if (!view_) { + view_ = AutofillPopupView::Create(this); + + // It is possible to fail to create the popup, in this case + // treat the popup as hiding right away. + if (!view_) { + Hide(); + return; + } + + ShowView(); + } else { + UpdateBoundsAndRedrawPopup(); + } + + delegate_->OnPopupShown(); + controller_common_->RegisterKeyPressCallback(); +} + +void AutofillPopupControllerImpl::UpdateDataListValues( + const std::vector& values, + const std::vector& labels) { + // Remove all the old data list values, which should always be at the top of + // the list if they are present. + while (!identifiers_.empty() && + identifiers_[0] == POPUP_ITEM_ID_DATALIST_ENTRY) { + names_.erase(names_.begin()); + subtexts_.erase(subtexts_.begin()); + icons_.erase(icons_.begin()); + identifiers_.erase(identifiers_.begin()); + } + + // If there are no new data list values, exit (clearing the separator if there + // is one). + if (values.empty()) { + if (!identifiers_.empty() && identifiers_[0] == POPUP_ITEM_ID_SEPARATOR) { + names_.erase(names_.begin()); + subtexts_.erase(subtexts_.begin()); + icons_.erase(icons_.begin()); + identifiers_.erase(identifiers_.begin()); + } + + // The popup contents have changed, so either update the bounds or hide it. + if (HasSuggestions()) + UpdateBoundsAndRedrawPopup(); + else + Hide(); + + return; + } + + // Add a separator if there are any other values. + if (!identifiers_.empty() && identifiers_[0] != POPUP_ITEM_ID_SEPARATOR) { + names_.insert(names_.begin(), base::string16()); + subtexts_.insert(subtexts_.begin(), base::string16()); + icons_.insert(icons_.begin(), base::string16()); + identifiers_.insert(identifiers_.begin(), POPUP_ITEM_ID_SEPARATOR); + } + + + names_.insert(names_.begin(), values.begin(), values.end()); + subtexts_.insert(subtexts_.begin(), labels.begin(), labels.end()); + + // Add the values that are the same for all data list elements. + icons_.insert(icons_.begin(), values.size(), base::string16()); + identifiers_.insert( + identifiers_.begin(), values.size(), POPUP_ITEM_ID_DATALIST_ENTRY); + + UpdateBoundsAndRedrawPopup(); +} + +void AutofillPopupControllerImpl::Hide() { + controller_common_->RemoveKeyPressCallback(); + if (delegate_.get()) + delegate_->OnPopupHidden(); + + if (view_) + view_->Hide(); + + delete this; +} + +void AutofillPopupControllerImpl::ViewDestroyed() { + // The view has already been destroyed so clear the reference to it. + view_ = NULL; + + Hide(); +} + +bool AutofillPopupControllerImpl::HandleKeyPressEvent( + const content::NativeWebKeyboardEvent& event) { + switch (event.windowsKeyCode) { + case ui::VKEY_UP: + SelectPreviousLine(); + return true; + case ui::VKEY_DOWN: + SelectNextLine(); + return true; + case ui::VKEY_PRIOR: // Page up. + SetSelectedLine(0); + return true; + case ui::VKEY_NEXT: // Page down. + SetSelectedLine(names().size() - 1); + return true; + case ui::VKEY_ESCAPE: + Hide(); + return true; + case ui::VKEY_DELETE: + return (event.modifiers & content::NativeWebKeyboardEvent::ShiftKey) && + RemoveSelectedLine(); + case ui::VKEY_TAB: + // A tab press should cause the selected line to be accepted, but still + // return false so the tab key press propagates and changes the cursor + // location. + AcceptSelectedLine(); + return false; + case ui::VKEY_RETURN: + return AcceptSelectedLine(); + default: + return false; + } +} + +void AutofillPopupControllerImpl::UpdateBoundsAndRedrawPopup() { +#if !defined(OS_ANDROID) + // TODO(csharp): Since UpdatePopupBounds can change the position of the popup, + // the popup could end up jumping from above the element to below it. + // It is unclear if it is better to keep the popup where it was, or if it + // should try and move to its desired position. + UpdatePopupBounds(); +#endif + + view_->UpdateBoundsAndRedrawPopup(); +} + +void AutofillPopupControllerImpl::SetSelectionAtPoint(const gfx::Point& point) { + SetSelectedLine(LineFromY(point.y())); +} + +bool AutofillPopupControllerImpl::AcceptSelectedLine() { + if (selected_line_ == kNoSelection) + return false; + + DCHECK_GE(selected_line_, 0); + DCHECK_LT(selected_line_, static_cast(names_.size())); + + if (!CanAccept(identifiers_[selected_line_])) + return false; + + AcceptSuggestion(selected_line_); + return true; +} + +void AutofillPopupControllerImpl::SelectionCleared() { + SetSelectedLine(kNoSelection); +} + +bool AutofillPopupControllerImpl::ShouldRepostEvent( + const ui::MouseEvent& event) { + return delegate_->ShouldRepostEvent(event); +} + +bool AutofillPopupControllerImpl::ShouldHideOnOutsideClick() const { + return hide_on_outside_click_; +} + +void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) { + delegate_->DidAcceptSuggestion(full_names_[index], identifiers_[index]); +} + +int AutofillPopupControllerImpl::GetIconResourceID( + const base::string16& resource_name) const { + for (size_t i = 0; i < arraysize(kDataResources); ++i) { + if (resource_name == base::ASCIIToUTF16(kDataResources[i].name)) + return kDataResources[i].id; + } + + return -1; +} + +bool AutofillPopupControllerImpl::CanDelete(size_t index) const { + // TODO(isherman): Native AddressBook suggestions on Mac and Android should + // not be considered to be deleteable. + int id = identifiers_[index]; + return id > 0 || id == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || + id == POPUP_ITEM_ID_PASSWORD_ENTRY; +} + +bool AutofillPopupControllerImpl::IsWarning(size_t index) const { + return identifiers_[index] == POPUP_ITEM_ID_WARNING_MESSAGE; +} + +gfx::Rect AutofillPopupControllerImpl::GetRowBounds(size_t index) { + int top = kPopupBorderThickness; + for (size_t i = 0; i < index; ++i) { + top += GetRowHeightFromId(identifiers()[i]); + } + + return gfx::Rect( + kPopupBorderThickness, + top, + popup_bounds_.width() - 2 * kPopupBorderThickness, + GetRowHeightFromId(identifiers()[index])); +} + +void AutofillPopupControllerImpl::SetPopupBounds(const gfx::Rect& bounds) { + popup_bounds_ = bounds; + UpdateBoundsAndRedrawPopup(); +} + +const gfx::Rect& AutofillPopupControllerImpl::popup_bounds() const { + return popup_bounds_; +} + +content::WebContents* AutofillPopupControllerImpl::web_contents() { + return controller_common_->web_contents(); +} + +gfx::NativeView AutofillPopupControllerImpl::container_view() { + return controller_common_->container_view(); +} + +const gfx::RectF& AutofillPopupControllerImpl::element_bounds() const { + return controller_common_->element_bounds(); +} + +bool AutofillPopupControllerImpl::IsRTL() const { + return text_direction_ == base::i18n::RIGHT_TO_LEFT; +} + +const std::vector& AutofillPopupControllerImpl::names() const { + return names_; +} + +const std::vector& AutofillPopupControllerImpl::subtexts() + const { + return subtexts_; +} + +const std::vector& AutofillPopupControllerImpl::icons() const { + return icons_; +} + +const std::vector& AutofillPopupControllerImpl::identifiers() const { + return identifiers_; +} + +#if !defined(OS_ANDROID) +const gfx::FontList& AutofillPopupControllerImpl::GetNameFontListForRow( + size_t index) const { + if (identifiers_[index] == POPUP_ITEM_ID_WARNING_MESSAGE) + return warning_font_list_; + + return name_font_list_; +} + +const gfx::FontList& AutofillPopupControllerImpl::subtext_font_list() const { + return subtext_font_list_; +} +#endif + +int AutofillPopupControllerImpl::selected_line() const { + return selected_line_; +} + +void AutofillPopupControllerImpl::set_hide_on_outside_click( + bool hide_on_outside_click) { + hide_on_outside_click_ = hide_on_outside_click; +} + +void AutofillPopupControllerImpl::SetSelectedLine(int selected_line) { + if (selected_line_ == selected_line) + return; + + if (selected_line_ != kNoSelection && + static_cast(selected_line_) < identifiers_.size()) + InvalidateRow(selected_line_); + + if (selected_line != kNoSelection) + InvalidateRow(selected_line); + + selected_line_ = selected_line; + + if (selected_line_ != kNoSelection) { + delegate_->DidSelectSuggestion(names_[selected_line_], + identifiers_[selected_line_]); + } else { + delegate_->ClearPreviewedForm(); + } +} + +void AutofillPopupControllerImpl::SelectNextLine() { + int new_selected_line = selected_line_ + 1; + + // Skip over any lines that can't be selected. + while (static_cast(new_selected_line) < names_.size() && + !CanAccept(identifiers()[new_selected_line])) { + ++new_selected_line; + } + + if (new_selected_line >= static_cast(names_.size())) + new_selected_line = 0; + + SetSelectedLine(new_selected_line); +} + +void AutofillPopupControllerImpl::SelectPreviousLine() { + int new_selected_line = selected_line_ - 1; + + // Skip over any lines that can't be selected. + while (new_selected_line > kNoSelection && + !CanAccept(identifiers()[new_selected_line])) { + --new_selected_line; + } + + if (new_selected_line <= kNoSelection) + new_selected_line = names_.size() - 1; + + SetSelectedLine(new_selected_line); +} + +bool AutofillPopupControllerImpl::RemoveSelectedLine() { + if (selected_line_ == kNoSelection) + return false; + + DCHECK_GE(selected_line_, 0); + DCHECK_LT(selected_line_, static_cast(names_.size())); + + if (!CanDelete(selected_line_)) + return false; + + delegate_->RemoveSuggestion(full_names_[selected_line_], + identifiers_[selected_line_]); + + // Remove the deleted element. + names_.erase(names_.begin() + selected_line_); + full_names_.erase(full_names_.begin() + selected_line_); + subtexts_.erase(subtexts_.begin() + selected_line_); + icons_.erase(icons_.begin() + selected_line_); + identifiers_.erase(identifiers_.begin() + selected_line_); + + SetSelectedLine(kNoSelection); + + if (HasSuggestions()) { + delegate_->ClearPreviewedForm(); + UpdateBoundsAndRedrawPopup(); + } else { + Hide(); + } + + return true; +} + +int AutofillPopupControllerImpl::LineFromY(int y) { + int current_height = kPopupBorderThickness; + + for (size_t i = 0; i < identifiers().size(); ++i) { + current_height += GetRowHeightFromId(identifiers()[i]); + + if (y <= current_height) + return i; + } + + // The y value goes beyond the popup so stop the selection at the last line. + return identifiers().size() - 1; +} + +int AutofillPopupControllerImpl::GetRowHeightFromId(int identifier) const { + if (identifier == POPUP_ITEM_ID_SEPARATOR) + return kSeparatorHeight; + + return kRowHeight; +} + +bool AutofillPopupControllerImpl::CanAccept(int id) { + return id != POPUP_ITEM_ID_SEPARATOR && id != POPUP_ITEM_ID_WARNING_MESSAGE; +} + +bool AutofillPopupControllerImpl::HasSuggestions() { + return identifiers_.size() != 0 && + (identifiers_[0] > 0 || + identifiers_[0] == POPUP_ITEM_ID_AUTOCOMPLETE_ENTRY || + identifiers_[0] == POPUP_ITEM_ID_PASSWORD_ENTRY || + identifiers_[0] == POPUP_ITEM_ID_DATALIST_ENTRY); +} + +void AutofillPopupControllerImpl::SetValues( + const std::vector& names, + const std::vector& subtexts, + const std::vector& icons, + const std::vector& identifiers) { + names_ = names; + full_names_ = names; + subtexts_ = subtexts; + icons_ = icons; + identifiers_ = identifiers; +} + +void AutofillPopupControllerImpl::ShowView() { + view_->Show(); +} + +void AutofillPopupControllerImpl::InvalidateRow(size_t row) { + DCHECK(0 <= row); + DCHECK(row < identifiers_.size()); + view_->InvalidateRow(row); +} + +#if !defined(OS_ANDROID) +int AutofillPopupControllerImpl::GetDesiredPopupWidth() const { + int popup_width = controller_common_->RoundedElementBounds().width(); + DCHECK_EQ(names().size(), subtexts().size()); + for (size_t i = 0; i < names().size(); ++i) { + int row_size = + gfx::GetStringWidth(names()[i], name_font_list_) + + gfx::GetStringWidth(subtexts()[i], subtext_font_list_) + + RowWidthWithoutText(i); + + popup_width = std::max(popup_width, row_size); + } + + return popup_width; +} + +int AutofillPopupControllerImpl::GetDesiredPopupHeight() const { + int popup_height = 2 * kPopupBorderThickness; + + for (size_t i = 0; i < identifiers().size(); ++i) { + popup_height += GetRowHeightFromId(identifiers()[i]); + } + + return popup_height; +} + +int AutofillPopupControllerImpl::RowWidthWithoutText(int row) const { + int row_size = kEndPadding; + + if (!subtexts_[row].empty()) + row_size += kNamePadding; + + // Add the Autofill icon size, if required. + if (!icons_[row].empty()) { + int icon_width = ui::ResourceBundle::GetSharedInstance().GetImageNamed( + GetIconResourceID(icons_[row])).Width(); + row_size += icon_width + kIconPadding; + } + + // Add the padding at the end. + row_size += kEndPadding; + + // Add room for the popup border. + row_size += 2 * kPopupBorderThickness; + + return row_size; +} + +void AutofillPopupControllerImpl::UpdatePopupBounds() { + int popup_required_width = GetDesiredPopupWidth(); + int popup_height = GetDesiredPopupHeight(); + + popup_bounds_ = controller_common_->GetPopupBounds(popup_height, + popup_required_width); +} +#endif // !defined(OS_ANDROID) + +WeakPtr AutofillPopupControllerImpl::GetWeakPtr() { + return weak_ptr_factory_.GetWeakPtr(); +} + +void AutofillPopupControllerImpl::ClearState() { + // Don't clear view_, because otherwise the popup will have to get regenerated + // and this will cause flickering. + + popup_bounds_ = gfx::Rect(); + + names_.clear(); + subtexts_.clear(); + icons_.clear(); + identifiers_.clear(); + full_names_.clear(); + + selected_line_ = kNoSelection; +} + +} // namespace autofill diff --git a/src/browser/autofill_popup_controller_impl.h b/src/browser/autofill_popup_controller_impl.h new file mode 100644 index 0000000000..899c50b145 --- /dev/null +++ b/src/browser/autofill_popup_controller_impl.h @@ -0,0 +1,213 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_IMPL_H_ +#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_IMPL_H_ + +#include "base/gtest_prod_util.h" +#include "base/i18n/rtl.h" +#include "base/memory/weak_ptr.h" +#include "base/strings/string16.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller.h" +#include "chrome/browser/ui/autofill/popup_controller_common.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/rect_f.h" + +namespace autofill { + +class AutofillPopupDelegate; +class AutofillPopupView; + +// This class is a controller for an AutofillPopupView. It implements +// AutofillPopupController to allow calls from AutofillPopupView. The +// other, public functions are available to its instantiator. +class AutofillPopupControllerImpl : public AutofillPopupController { + public: + // Creates a new |AutofillPopupControllerImpl|, or reuses |previous| if the + // construction arguments are the same. |previous| may be invalidated by this + // call. The controller will listen for keyboard input routed to + // |web_contents| while the popup is showing, unless |web_contents| is NULL. + static base::WeakPtr GetOrCreate( + base::WeakPtr previous, + base::WeakPtr delegate, + content::WebContents* web_contents, + gfx::NativeView container_view, + const gfx::RectF& element_bounds, + base::i18n::TextDirection text_direction); + + // Shows the popup, or updates the existing popup with the given values. + void Show(const std::vector& names, + const std::vector& subtexts, + const std::vector& icons, + const std::vector& identifiers); + + // Updates the data list values currently shown with the popup. + void UpdateDataListValues(const std::vector& values, + const std::vector& labels); + + // Hides the popup and destroys the controller. This also invalidates + // |delegate_|. + virtual void Hide() OVERRIDE; + + // Invoked when the view was destroyed by by someone other than this class. + virtual void ViewDestroyed() OVERRIDE; + + bool HandleKeyPressEvent(const content::NativeWebKeyboardEvent& event); + + // Tells the view to capture mouse events. Must be called before |Show()|. + void set_hide_on_outside_click(bool hide_on_outside_click); + + protected: + FRIEND_TEST_ALL_PREFIXES(AutofillExternalDelegateBrowserTest, + CloseWidgetAndNoLeaking); + FRIEND_TEST_ALL_PREFIXES(AutofillPopupControllerUnitTest, + ProperlyResetController); + + AutofillPopupControllerImpl(base::WeakPtr delegate, + content::WebContents* web_contents, + gfx::NativeView container_view, + const gfx::RectF& element_bounds, + base::i18n::TextDirection text_direction); + virtual ~AutofillPopupControllerImpl(); + + // AutofillPopupController implementation. + virtual void UpdateBoundsAndRedrawPopup() OVERRIDE; + virtual void SetSelectionAtPoint(const gfx::Point& point) OVERRIDE; + virtual bool AcceptSelectedLine() OVERRIDE; + virtual void SelectionCleared() OVERRIDE; + virtual bool ShouldRepostEvent(const ui::MouseEvent& event) OVERRIDE; + virtual bool ShouldHideOnOutsideClick() const OVERRIDE; + virtual void AcceptSuggestion(size_t index) OVERRIDE; + virtual int GetIconResourceID( + const base::string16& resource_name) const OVERRIDE; + virtual bool CanDelete(size_t index) const OVERRIDE; + virtual bool IsWarning(size_t index) const OVERRIDE; + virtual gfx::Rect GetRowBounds(size_t index) OVERRIDE; + virtual void SetPopupBounds(const gfx::Rect& bounds) OVERRIDE; + virtual const gfx::Rect& popup_bounds() const OVERRIDE; + virtual gfx::NativeView container_view() OVERRIDE; + virtual const gfx::RectF& element_bounds() const OVERRIDE; + virtual bool IsRTL() const OVERRIDE; + + virtual const std::vector& names() const OVERRIDE; + virtual const std::vector& subtexts() const OVERRIDE; + virtual const std::vector& icons() const OVERRIDE; + virtual const std::vector& identifiers() const OVERRIDE; +#if !defined(OS_ANDROID) + virtual const gfx::FontList& GetNameFontListForRow( + size_t index) const OVERRIDE; + virtual const gfx::FontList& subtext_font_list() const OVERRIDE; +#endif + virtual int selected_line() const OVERRIDE; + + content::WebContents* web_contents(); + + // Change which line is currently selected by the user. + void SetSelectedLine(int selected_line); + + // Increase the selected line by 1, properly handling wrapping. + void SelectNextLine(); + + // Decrease the selected line by 1, properly handling wrapping. + void SelectPreviousLine(); + + // The user has removed a suggestion. + bool RemoveSelectedLine(); + + // Convert a y-coordinate to the closest line. + int LineFromY(int y); + + // Returns the height of a row depending on its type. + int GetRowHeightFromId(int identifier) const; + + // Returns true if the given id refers to an element that can be accepted. + bool CanAccept(int id); + + // Returns true if the popup still has non-options entries to show the user. + bool HasSuggestions(); + + // Set the Autofill entry values. Exposed to allow tests to set these values + // without showing the popup. + void SetValues(const std::vector& names, + const std::vector& subtexts, + const std::vector& icons, + const std::vector& identifier); + + AutofillPopupView* view() { return view_; } + + // |view_| pass throughs (virtual for testing). + virtual void ShowView(); + virtual void InvalidateRow(size_t row); + + // Protected so tests can access. +#if !defined(OS_ANDROID) + // Calculates the desired width of the popup based on its contents. + int GetDesiredPopupWidth() const; + + // Calculates the desired height of the popup based on its contents. + int GetDesiredPopupHeight() const; + + // Calculate the width of the row, excluding all the text. This provides + // the size of the row that won't be reducible (since all the text can be + // elided if there isn't enough space). + int RowWidthWithoutText(int row) const; +#endif + + base::WeakPtr GetWeakPtr(); + + // Contains common popup functionality such as popup layout. Protected for + // testing. + scoped_ptr controller_common_; + + private: + // Clear the internal state of the controller. This is needed to ensure that + // when the popup is reused it doesn't leak values between uses. + void ClearState(); + +#if !defined(OS_ANDROID) + // Calculates and sets the bounds of the popup, including placing it properly + // to prevent it from going off the screen. + void UpdatePopupBounds(); +#endif + + AutofillPopupView* view_; // Weak reference. + base::WeakPtr delegate_; + + // The bounds of the Autofill popup. + gfx::Rect popup_bounds_; + + // The text direction of the popup. + base::i18n::TextDirection text_direction_; + + // The current Autofill query values. + std::vector names_; + std::vector subtexts_; + std::vector icons_; + std::vector identifiers_; + + // Since names_ can be elided to ensure that it fits on the screen, we need to + // keep an unelided copy of the names to be able to pass to the delegate. + std::vector full_names_; + +#if !defined(OS_ANDROID) + // The fonts for the popup text. + gfx::FontList name_font_list_; + gfx::FontList subtext_font_list_; + gfx::FontList warning_font_list_; +#endif + + // The line that is currently selected by the user. + // |kNoSelection| indicates that no line is currently selected. + int selected_line_; + + // Whether the popup view should hide on mouse presses outside of it. + bool hide_on_outside_click_; + + base::WeakPtrFactory weak_ptr_factory_; +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_CONTROLLER_IMPL_H_ diff --git a/src/browser/autofill_popup_view.h b/src/browser/autofill_popup_view.h new file mode 100644 index 0000000000..d01f7740a2 --- /dev/null +++ b/src/browser/autofill_popup_view.h @@ -0,0 +1,63 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ +#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ + +#include "ui/gfx/native_widget_types.h" + +namespace gfx { +class Rect; +} + +namespace ui { +class KeyEvent; +} + +namespace autofill { + +class AutofillPopupController; + +// The interface for creating and controlling a platform-dependent +// AutofillPopupView. +class AutofillPopupView { + public: + // The minimum amount of padding between the Autofill name and subtext, + // in pixels. + static const size_t kNamePadding = 15; + + // The amount of padding between icons in pixels. + static const int kIconPadding = 5; + + // The amount of padding at the end of the popup in pixels. + static const int kEndPadding = 3; + + // Height of the delete icon in pixels. + static const int kDeleteIconHeight = 16; + + // Width of the delete icon in pixels. + static const int kDeleteIconWidth = 16; + + // Displays the Autofill popup and fills it in with data from the controller. + virtual void Show() = 0; + + // Hides the popup from view. This will cause the popup to be deleted. + virtual void Hide() = 0; + + // Invalidates the given row and redraw it. + virtual void InvalidateRow(size_t row) = 0; + + // Refreshes the position of the popup. + virtual void UpdateBoundsAndRedrawPopup() = 0; + + // Factory function for creating the view. + static AutofillPopupView* Create(AutofillPopupController* controller); + + protected: + virtual ~AutofillPopupView() {} +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_VIEW_H_ diff --git a/src/browser/autofill_popup_view_delegate.h b/src/browser/autofill_popup_view_delegate.h new file mode 100644 index 0000000000..15836cb260 --- /dev/null +++ b/src/browser/autofill_popup_view_delegate.h @@ -0,0 +1,62 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_VIEW_DELEGATE_H_ +#define CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_VIEW_DELEGATE_H_ + +#include "ui/gfx/native_widget_types.h" + +namespace gfx { +class Point; +class Rect; +} + +namespace ui { +class MouseEvent; +} + +namespace autofill { + +// Base class for Controllers of Autofill style popups. This interface is +// used by the relevant views to communicate with the controller. +class AutofillPopupViewDelegate { + public: + // Called when the popup should be hidden. Controller will be deleted after + // the view has been hidden and destroyed. + virtual void Hide() = 0; + + // Called whent the popup view was destroyed. + virtual void ViewDestroyed() = 0; + + // The user has selected |point|, e.g. by hovering the mouse cursor. |point| + // must be in popup coordinates. + virtual void SetSelectionAtPoint(const gfx::Point& point) = 0; + + // The user has accepted the currently selected line. Returns whether there + // was a selection to accept. + virtual bool AcceptSelectedLine() = 0; + + // The user cleared the current selection, e.g. by moving the mouse cursor + // out of the popup bounds. + virtual void SelectionCleared() = 0; + + // Whether |event| should be reposted to the native window management. + virtual bool ShouldRepostEvent(const ui::MouseEvent& event) = 0; + + // Whether the view should be hidden on outside mouse presses. + virtual bool ShouldHideOnOutsideClick() const = 0; + + // The actual bounds of the popup. + virtual const gfx::Rect& popup_bounds() const = 0; + + // The view that the form field element sits in. + virtual gfx::NativeView container_view() = 0; + + protected: + virtual ~AutofillPopupViewDelegate() {} +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_AUTOFILL_POPUP_VIEW_DELEGATE_H_ diff --git a/src/browser/autofill_popup_view_gtk.cc b/src/browser/autofill_popup_view_gtk.cc new file mode 100644 index 0000000000..7aaf87e23f --- /dev/null +++ b/src/browser/autofill_popup_view_gtk.cc @@ -0,0 +1,327 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/autofill_popup_view_gtk.h" + +#include +#include + +#include "base/logging.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller.h" +#include "chrome/browser/ui/gtk/gtk_util.h" +#include "components/autofill/core/browser/popup_item_ids.h" +#include "grit/ui_resources.h" +#include "ui/base/gtk/gtk_hig_constants.h" +#include "ui/base/gtk/gtk_windowing.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/geometry/point.h" +#include "ui/gfx/geometry/rect.h" +#include "ui/gfx/gtk_compat.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/pango_util.h" +#include "ui/gfx/text_utils.h" +#include "ui/gfx/image/cairo_cached_surface.h" + + +namespace { + +const GdkColor kBorderColor = GDK_COLOR_RGB(0xc7, 0xca, 0xce); +const GdkColor kHoveredBackgroundColor = GDK_COLOR_RGB(0xcd, 0xcd, 0xcd); +const GdkColor kNameColor = GDK_COLOR_RGB(0x00, 0x00, 0x00); +const GdkColor kWarningColor = GDK_COLOR_RGB(0x7f, 0x7f, 0x7f); +const GdkColor kSubtextColor = GDK_COLOR_RGB(0x7f, 0x7f, 0x7f); + +} // namespace + +namespace gtk_util { + +void SetLayoutText(PangoLayout* layout, const base::string16& text) { + // Pango is really easy to overflow and send into a computational death + // spiral that can corrupt the screen. Assume that we'll never have more than + // 2000 characters, which should be a safe assumption until we all get robot + // eyes. http://crbug.com/66576 + std::string text_utf8 = base::UTF16ToUTF8(text); + if (text_utf8.length() > 2000) + text_utf8 = text_utf8.substr(0, 2000); + + pango_layout_set_text(layout, text_utf8.data(), text_utf8.length()); +} + +void DrawFullImage(cairo_t* cr, + GtkWidget* widget, + const gfx::Image& image, + gint dest_x, + gint dest_y) { + gfx::CairoCachedSurface* surface = image.ToCairo(); + surface->SetSource(cr, widget, dest_x, dest_y); + cairo_pattern_set_extend(cairo_get_source(cr), CAIRO_EXTEND_REPEAT); + cairo_rectangle(cr, dest_x, dest_y, surface->Width(), surface->Height()); + cairo_fill(cr); +} + +} + +namespace autofill { + +AutofillPopupViewGtk::AutofillPopupViewGtk( + AutofillPopupController* controller) + : controller_(controller), + window_(gtk_window_new(GTK_WINDOW_POPUP)) { + gtk_window_set_resizable(GTK_WINDOW(window_), FALSE); + gtk_widget_set_app_paintable(window_, TRUE); + gtk_widget_set_double_buffered(window_, TRUE); + + // Setup the window to ensure it receives the expose event. + gtk_widget_add_events(window_, GDK_BUTTON_MOTION_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_EXPOSURE_MASK | + GDK_POINTER_MOTION_MASK); + + GtkWidget* toplevel_window = gtk_widget_get_toplevel( + controller->container_view()); + signals_.Connect(toplevel_window, "configure-event", + G_CALLBACK(HandleConfigureThunk), this); + g_signal_connect(window_, "expose-event", + G_CALLBACK(HandleExposeThunk), this); + g_signal_connect(window_, "leave-notify-event", + G_CALLBACK(HandleLeaveThunk), this); + g_signal_connect(window_, "motion-notify-event", + G_CALLBACK(HandleMotionThunk), this); + g_signal_connect(window_, "button-release-event", + G_CALLBACK(HandleButtonReleaseThunk), this); + + // Cache the layout so we don't have to create it for every expose. + layout_ = gtk_widget_create_pango_layout(window_, NULL); +} + +AutofillPopupViewGtk::~AutofillPopupViewGtk() { + g_object_unref(layout_); + gtk_widget_destroy(window_); +} + +void AutofillPopupViewGtk::Hide() { + delete this; +} + +void AutofillPopupViewGtk::Show() { + UpdateBoundsAndRedrawPopup(); + + gtk_widget_show(window_); + + GtkWidget* parent_window = + gtk_widget_get_toplevel(controller_->container_view()); + ui::StackPopupWindow(window_, parent_window); +} + +void AutofillPopupViewGtk::InvalidateRow(size_t row) { + GdkRectangle row_rect = controller_->GetRowBounds(row).ToGdkRectangle(); + GdkWindow* gdk_window = gtk_widget_get_window(window_); + gdk_window_invalidate_rect(gdk_window, &row_rect, FALSE); +} + +void AutofillPopupViewGtk::UpdateBoundsAndRedrawPopup() { + gtk_widget_set_size_request(window_, + controller_->popup_bounds().width(), + controller_->popup_bounds().height()); + gtk_window_move(GTK_WINDOW(window_), + controller_->popup_bounds().x(), + controller_->popup_bounds().y()); + + GdkWindow* gdk_window = gtk_widget_get_window(window_); + GdkRectangle popup_rect = controller_->popup_bounds().ToGdkRectangle(); + if (gdk_window != NULL) + gdk_window_invalidate_rect(gdk_window, &popup_rect, FALSE); +} + +gboolean AutofillPopupViewGtk::HandleConfigure(GtkWidget* widget, + GdkEventConfigure* event) { + controller_->Hide(); + return FALSE; +} + +gboolean AutofillPopupViewGtk::HandleButtonRelease(GtkWidget* widget, + GdkEventButton* event) { + // We only care about the left click. + if (event->button != 1) + return FALSE; + + controller_->SetSelectionAtPoint(gfx::Point(event->x, event->y)); + controller_->AcceptSelectedLine(); + return TRUE; +} + +gboolean AutofillPopupViewGtk::HandleExpose(GtkWidget* widget, + GdkEventExpose* event) { + cairo_t* cr = gdk_cairo_create(GDK_DRAWABLE(gtk_widget_get_window(widget))); + gdk_cairo_rectangle(cr, &event->area); + cairo_clip(cr); + + // Draw the 1px border around the entire window. + gdk_cairo_set_source_color(cr, &kBorderColor); + gdk_cairo_rectangle(cr, &widget->allocation); + cairo_stroke(cr); + SetUpLayout(); + + gfx::Rect damage_rect(event->area); + + for (size_t i = 0; i < controller_->names().size(); ++i) { + gfx::Rect line_rect = controller_->GetRowBounds(i); + // Only repaint and layout damaged lines. + if (!line_rect.Intersects(damage_rect)) + continue; + + if (controller_->identifiers()[i] == POPUP_ITEM_ID_SEPARATOR) + DrawSeparator(cr, line_rect); + else + DrawAutofillEntry(cr, i, line_rect); + } + + cairo_destroy(cr); + + return TRUE; +} + +gboolean AutofillPopupViewGtk::HandleLeave(GtkWidget* widget, + GdkEventCrossing* event) { + controller_->SelectionCleared(); + + return FALSE; +} + +gboolean AutofillPopupViewGtk::HandleMotion(GtkWidget* widget, + GdkEventMotion* event) { + controller_->SetSelectionAtPoint(gfx::Point(event->x, event->y)); + + return TRUE; +} + +void AutofillPopupViewGtk::SetUpLayout() { + pango_layout_set_width(layout_, window_->allocation.width * PANGO_SCALE); + pango_layout_set_height(layout_, window_->allocation.height * PANGO_SCALE); +} + +void AutofillPopupViewGtk::SetLayoutText(const base::string16& text, + const gfx::FontList& font_list, + const GdkColor text_color) { + PangoAttrList* attrs = pango_attr_list_new(); + + PangoAttribute* fg_attr = pango_attr_foreground_new(text_color.red, + text_color.green, + text_color.blue); + pango_attr_list_insert(attrs, fg_attr); // Ownership taken. + + pango_layout_set_attributes(layout_, attrs); // Ref taken. + pango_attr_list_unref(attrs); + + gfx::ScopedPangoFontDescription font_description( + pango_font_description_from_string( + font_list.GetFontDescriptionString().c_str())); + pango_layout_set_font_description(layout_, font_description.get()); + + gtk_util::SetLayoutText(layout_, text); + + // The popup is already the correct size for the text, so set the width to -1 + // to prevent additional wrapping or ellipsization. + pango_layout_set_width(layout_, -1); +} + +void AutofillPopupViewGtk::DrawSeparator(cairo_t* cairo_context, + const gfx::Rect& separator_rect) { + cairo_save(cairo_context); + cairo_move_to(cairo_context, 0, separator_rect.y()); + cairo_line_to(cairo_context, + separator_rect.width(), + separator_rect.y() + separator_rect.height()); + cairo_stroke(cairo_context); + cairo_restore(cairo_context); +} + +void AutofillPopupViewGtk::DrawAutofillEntry(cairo_t* cairo_context, + size_t index, + const gfx::Rect& entry_rect) { + if (controller_->selected_line() == static_cast(index)) { + gdk_cairo_set_source_color(cairo_context, &kHoveredBackgroundColor); + cairo_rectangle(cairo_context, entry_rect.x(), entry_rect.y(), + entry_rect.width(), entry_rect.height()); + cairo_fill(cairo_context); + } + + // Draw the value. + SetLayoutText(controller_->names()[index], + controller_->GetNameFontListForRow(index), + controller_->IsWarning(index) ? kWarningColor : kNameColor); + int value_text_width = + gfx::GetStringWidth(controller_->names()[index], + controller_->GetNameFontListForRow(index)); + + // Center the text within the line. + int row_height = entry_rect.height(); + int value_content_y = std::max( + entry_rect.y(), + entry_rect.y() + + (row_height - + controller_->GetNameFontListForRow(index).GetHeight()) / 2); + + bool is_rtl = controller_->IsRTL(); + int value_content_x = is_rtl ? + entry_rect.width() - value_text_width - kEndPadding : kEndPadding; + + cairo_save(cairo_context); + cairo_move_to(cairo_context, value_content_x, value_content_y); + pango_cairo_show_layout(cairo_context, layout_); + cairo_restore(cairo_context); + + // Use this to figure out where all the other Autofill items should be placed. + int x_align_left = is_rtl ? kEndPadding : entry_rect.width() - kEndPadding; + + // Draw the Autofill icon, if one exists + if (!controller_->icons()[index].empty()) { + int icon = controller_->GetIconResourceID(controller_->icons()[index]); + DCHECK_NE(-1, icon); + const gfx::Image& image = + ui::ResourceBundle::GetSharedInstance().GetImageNamed(icon); + int icon_y = entry_rect.y() + (row_height - image.Height()) / 2; + + x_align_left += is_rtl ? 0 : -image.Width(); + + cairo_save(cairo_context); + gtk_util::DrawFullImage(cairo_context, + window_, + image, + x_align_left, + icon_y); + cairo_restore(cairo_context); + + x_align_left += is_rtl ? image.Width() + kIconPadding : -kIconPadding; + } + + // Draw the subtext. + SetLayoutText(controller_->subtexts()[index], + controller_->subtext_font_list(), + kSubtextColor); + if (!is_rtl) { + x_align_left -= gfx::GetStringWidth(controller_->subtexts()[index], + controller_->subtext_font_list()); + } + + // Center the text within the line. + int subtext_content_y = std::max( + entry_rect.y(), + entry_rect.y() + + (row_height - controller_->subtext_font_list().GetHeight()) / 2); + + cairo_save(cairo_context); + cairo_move_to(cairo_context, x_align_left, subtext_content_y); + pango_cairo_show_layout(cairo_context, layout_); + cairo_restore(cairo_context); +} + +AutofillPopupView* AutofillPopupView::Create( + AutofillPopupController* controller) { + return new AutofillPopupViewGtk(controller); +} + +} // namespace autofill diff --git a/src/browser/autofill_popup_view_gtk.h b/src/browser/autofill_popup_view_gtk.h new file mode 100644 index 0000000000..7cc5456d68 --- /dev/null +++ b/src/browser/autofill_popup_view_gtk.h @@ -0,0 +1,100 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_GTK_AUTOFILL_AUTOFILL_POPUP_VIEW_GTK_H_ +#define CHROME_BROWSER_UI_GTK_AUTOFILL_AUTOFILL_POPUP_VIEW_GTK_H_ + +#include +#include + +#include "base/compiler_specific.h" +#include "base/strings/string16.h" +#include "chrome/browser/ui/autofill/autofill_popup_view.h" +#include "ui/base/glib/glib_integers.h" +#include "ui/base/gtk/gtk_signal.h" +#include "ui/base/gtk/gtk_signal_registrar.h" + +class Profile; + +namespace content { +class RenderViewHost; +} + +namespace gfx { +class FontList; +class Rect; +} + +typedef struct _GdkEventButton GdkEventButton; +typedef struct _GdkEventConfigure GdkEventConfigure; +typedef struct _GdkEventCrossing GdkEventCrossing; +typedef struct _GdkEventExpose GdkEventExpose; +typedef struct _GdkEventKey GdkEventKey; +typedef struct _GdkEventMotion GdkEventMotion; +typedef struct _GdkColor GdkColor; +typedef struct _GtkWidget GtkWidget; + +namespace autofill { + +class AutofillPopupController; + +// Gtk implementation for AutofillPopupView interface. +class AutofillPopupViewGtk : public AutofillPopupView { + public: + explicit AutofillPopupViewGtk(AutofillPopupController* controller); + + private: + virtual ~AutofillPopupViewGtk(); + + // AutofillPopupView implementation. + virtual void Hide() OVERRIDE; + virtual void Show() OVERRIDE; + virtual void InvalidateRow(size_t row) OVERRIDE; + virtual void UpdateBoundsAndRedrawPopup() OVERRIDE; + + CHROMEGTK_CALLBACK_1(AutofillPopupViewGtk, gboolean, HandleConfigure, + GdkEventConfigure*); + CHROMEGTK_CALLBACK_1(AutofillPopupViewGtk, gboolean, HandleButtonRelease, + GdkEventButton*); + CHROMEGTK_CALLBACK_1(AutofillPopupViewGtk, gboolean, HandleExpose, + GdkEventExpose*); + CHROMEGTK_CALLBACK_1(AutofillPopupViewGtk, gboolean, HandleLeave, + GdkEventCrossing*) + CHROMEGTK_CALLBACK_1(AutofillPopupViewGtk, gboolean, HandleMotion, + GdkEventMotion*); + + // Set up the pango layout to display the autofill results. + void SetUpLayout(); + + // Set up the pango layout to print the given text and have it's width match + // the text's (this gives us better control when placing the text box). + void SetLayoutText(const base::string16& text, + const gfx::FontList& font_list, + const GdkColor text_color); + + // Draw the separator as the given |separator_rect|. + void DrawSeparator(cairo_t* cairo_context, const gfx::Rect& separator_rect); + + // Draw the given autofill entry in |entry_rect|. + void DrawAutofillEntry(cairo_t* cairo_context, + size_t index, + const gfx::Rect& entry_rect); + + // Set the initial bounds of the popup to show, including the placement + // of it. + void SetInitialBounds(); + + AutofillPopupController* controller_; // Weak reference. + + ui::GtkSignalRegistrar signals_; + + GtkWidget* window_; // Strong reference. + PangoLayout* layout_; // Strong reference. + + DISALLOW_COPY_AND_ASSIGN(AutofillPopupViewGtk); +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_GTK_AUTOFILL_AUTOFILL_POPUP_VIEW_GTK_H_ diff --git a/src/browser/nw_form_database_service.cc b/src/browser/nw_form_database_service.cc new file mode 100644 index 0000000000..52d599909c --- /dev/null +++ b/src/browser/nw_form_database_service.cc @@ -0,0 +1,127 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/nw_form_database_service.h" +#include "base/logging.h" +#include "base/synchronization/waitable_event.h" +#include "components/autofill/core/browser/webdata/autofill_table.h" +#include "components/webdata/common/webdata_constants.h" +#include "content/public/browser/browser_thread.h" +//#include "ui/base/l10n/l10n_util.h" + +using base::WaitableEvent; +using content::BrowserThread; + +namespace { + +// Callback to handle database error. It seems chrome uses this to +// display an error dialog box only. +void DatabaseErrorCallback(sql::InitStatus status) { + LOG(WARNING) << "initializing autocomplete database failed"; +} + +} // namespace + +namespace nw { + +NwFormDatabaseService::NwFormDatabaseService(const base::FilePath path) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + web_database_ = new WebDatabaseService(path.Append(kWebDataFilename), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB)); + web_database_->AddTable( + scoped_ptr(new autofill::AutofillTable( + ""))); + web_database_->LoadDatabase(); + + autofill_data_ = new autofill::AutofillWebDataService( + web_database_, + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI), + BrowserThread::GetMessageLoopProxyForThread(BrowserThread::DB), + base::Bind(&DatabaseErrorCallback)); + autofill_data_->Init(); +} + +NwFormDatabaseService::~NwFormDatabaseService() { + Shutdown(); +} + +void NwFormDatabaseService::Shutdown() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(result_map_.empty()); + // TODO(sgurun) we don't run into this logic right now, + // but if we do, then we need to implement cancellation + // of pending queries. + autofill_data_->ShutdownOnUIThread(); + web_database_->ShutdownDatabase(); +} + +scoped_refptr +NwFormDatabaseService::get_autofill_webdata_service() { + return autofill_data_; +} + +void NwFormDatabaseService::ClearFormData() { + BrowserThread::PostTask( + BrowserThread::DB, + FROM_HERE, + base::Bind(&NwFormDatabaseService::ClearFormDataImpl, + base::Unretained(this))); +} + +void NwFormDatabaseService::ClearFormDataImpl() { + base::Time begin; + base::Time end = base::Time::Max(); + autofill_data_->RemoveFormElementsAddedBetween(begin, end); + autofill_data_->RemoveAutofillDataModifiedBetween(begin, end); +} + +bool NwFormDatabaseService::HasFormData() { + WaitableEvent completion(false, false); + bool result = false; + BrowserThread::PostTask( + BrowserThread::DB, + FROM_HERE, + base::Bind(&NwFormDatabaseService::HasFormDataImpl, + base::Unretained(this), + &completion, + &result)); + completion.Wait(); + return result; +} + +void NwFormDatabaseService::HasFormDataImpl( + WaitableEvent* completion, + bool* result) { + WebDataServiceBase::Handle pending_query_handle = + autofill_data_->HasFormElements(this); + PendingQuery query; + query.result = result; + query.completion = completion; + result_map_[pending_query_handle] = query; +} + +void NwFormDatabaseService::OnWebDataServiceRequestDone( + WebDataServiceBase::Handle h, + const WDTypedResult* result) { + + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::DB)); + bool has_form_data = false; + if (result) { + DCHECK_EQ(AUTOFILL_VALUE_RESULT, result->GetType()); + const WDResult* autofill_result = + static_cast*>(result); + has_form_data = autofill_result->GetValue(); + } + QueryMap::const_iterator it = result_map_.find(h); + if (it == result_map_.end()) { + LOG(WARNING) << "Received unexpected callback from web data service"; + return; + } + *(it->second.result) = has_form_data; + it->second.completion->Signal(); + result_map_.erase(h); +} + +} // namespace android_webview diff --git a/src/browser/nw_form_database_service.h b/src/browser/nw_form_database_service.h new file mode 100644 index 0000000000..ce7b132ce2 --- /dev/null +++ b/src/browser/nw_form_database_service.h @@ -0,0 +1,67 @@ +// Copyright (c) 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NW_BROWSER_AW_FORM_DATABASE_SERVICE_H_ +#define NW_BROWSER_AW_FORM_DATABASE_SERVICE_H_ + +#include "base/basictypes.h" +#include "base/files/file_path.h" +#include "components/autofill/core/browser/webdata/autofill_webdata_service.h" +#include "components/webdata/common/web_data_service_consumer.h" +#include "components/webdata/common/web_database_service.h" + +namespace base { +class WaitableEvent; +}; + +namespace nw { + +// Handles the database operations necessary to implement the autocomplete +// functionality. This includes creating and initializing the components that +// handle the database backend, and providing a synchronous interface when +// needed (the chromium database components have an async. interface). +class NwFormDatabaseService : public WebDataServiceConsumer { + public: + NwFormDatabaseService(const base::FilePath path); + + virtual ~NwFormDatabaseService(); + + void Shutdown(); + + // Returns whether the database has any data stored. May do + // IO access and block. + bool HasFormData(); + + // Clear any saved form data. Executes asynchronously. + void ClearFormData(); + + scoped_refptr + get_autofill_webdata_service(); + + // WebDataServiceConsumer implementation. + virtual void OnWebDataServiceRequestDone( + WebDataServiceBase::Handle h, + const WDTypedResult* result) OVERRIDE; + + private: + struct PendingQuery { + bool* result; + base::WaitableEvent* completion; + }; + typedef std::map QueryMap; + + void ClearFormDataImpl(); + void HasFormDataImpl(base::WaitableEvent* completion, bool* result); + + QueryMap result_map_; + + scoped_refptr autofill_data_; + scoped_refptr web_database_; + + DISALLOW_COPY_AND_ASSIGN(NwFormDatabaseService); +}; + +} // namespace android_webview + +#endif // ANDROID_WEBVIEW_BROWSER_AW_FORM_DATABASE_SERVICE_H_ diff --git a/src/browser/popup_controller_common.cc b/src/browser/popup_controller_common.cc new file mode 100644 index 0000000000..9b6796e6eb --- /dev/null +++ b/src/browser/popup_controller_common.cc @@ -0,0 +1,162 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/popup_controller_common.h" + +#include +#include + +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "ui/gfx/display.h" +#include "ui/gfx/rect_conversions.h" +#include "ui/gfx/screen.h" +#include "ui/gfx/vector2d.h" + +namespace autofill { + +PopupControllerCommon::PopupControllerCommon( + const gfx::RectF& element_bounds, + const gfx::NativeView container_view, + content::WebContents* web_contents) + : element_bounds_(element_bounds), + container_view_(container_view), + web_contents_(web_contents), + key_press_event_target_(NULL) {} +PopupControllerCommon::~PopupControllerCommon() {} + +void PopupControllerCommon::SetKeyPressCallback( + content::RenderWidgetHost::KeyPressEventCallback callback) { + DCHECK(key_press_event_callback_.is_null()); + key_press_event_callback_ = callback; +} + +void PopupControllerCommon::RegisterKeyPressCallback() { + if (web_contents_ && !key_press_event_target_) { + key_press_event_target_ = web_contents_->GetRenderViewHost(); + key_press_event_target_->AddKeyPressEventCallback( + key_press_event_callback_); + } +} + +void PopupControllerCommon::RemoveKeyPressCallback() { + if (web_contents_ && (!web_contents_->IsBeingDestroyed()) && + key_press_event_target_ == web_contents_->GetRenderViewHost()) { + web_contents_->GetRenderViewHost()->RemoveKeyPressEventCallback( + key_press_event_callback_); + } + key_press_event_target_ = NULL; +} + +gfx::Display PopupControllerCommon::GetDisplayNearestPoint( + const gfx::Point& point) const { + return gfx::Screen::GetScreenFor(container_view_)->GetDisplayNearestPoint( + point); +} + +const gfx::Rect PopupControllerCommon::RoundedElementBounds() const { + return gfx::ToEnclosingRect(element_bounds_); +} + +std::pair PopupControllerCommon::CalculatePopupXAndWidth( + const gfx::Display& left_display, + const gfx::Display& right_display, + int popup_required_width) const { + int leftmost_display_x = left_display.bounds().x(); + int rightmost_display_x = + right_display.GetSizeInPixel().width() + right_display.bounds().x(); + + // Calculate the start coordinates for the popup if it is growing right or + // the end position if it is growing to the left, capped to screen space. + int right_growth_start = std::max(leftmost_display_x, + std::min(rightmost_display_x, + RoundedElementBounds().x())); + int left_growth_end = std::max(leftmost_display_x, + std::min(rightmost_display_x, + RoundedElementBounds().right())); + + int right_available = rightmost_display_x - right_growth_start; + int left_available = left_growth_end - leftmost_display_x; + + int popup_width = std::min(popup_required_width, + std::max(right_available, left_available)); + + // If there is enough space for the popup on the right, show it there, + // otherwise choose the larger size. + if (right_available >= popup_width || right_available >= left_available) + return std::make_pair(right_growth_start, popup_width); + else + return std::make_pair(left_growth_end - popup_width, popup_width); +} + +std::pair PopupControllerCommon::CalculatePopupYAndHeight( + const gfx::Display& top_display, + const gfx::Display& bottom_display, + int popup_required_height) const { + int topmost_display_y = top_display.bounds().y(); + int bottommost_display_y = + bottom_display.GetSizeInPixel().height() + bottom_display.bounds().y(); + + // Calculate the start coordinates for the popup if it is growing down or + // the end position if it is growing up, capped to screen space. + int top_growth_end = std::max(topmost_display_y, + std::min(bottommost_display_y, + RoundedElementBounds().y())); + int bottom_growth_start = std::max(topmost_display_y, + std::min(bottommost_display_y, + RoundedElementBounds().bottom())); + + int top_available = bottom_growth_start - topmost_display_y; + int bottom_available = bottommost_display_y - top_growth_end; + + // TODO(csharp): Restrict the popup height to what is available. + if (bottom_available >= popup_required_height || + bottom_available >= top_available) { + // The popup can appear below the field. + return std::make_pair(bottom_growth_start, popup_required_height); + } else { + // The popup must appear above the field. + return std::make_pair(top_growth_end - popup_required_height, + popup_required_height); + } +} + +gfx::Rect PopupControllerCommon::GetPopupBounds( + int popup_required_height, + int popup_required_width) const { + // This is the top left point of the popup if the popup is above the element + // and grows to the left (since that is the highest and furthest left the + // popup go could). + gfx::Point top_left_corner_of_popup = RoundedElementBounds().origin() + + gfx::Vector2d(RoundedElementBounds().width() - popup_required_width, + -popup_required_height); + + // This is the bottom right point of the popup if the popup is below the + // element and grows to the right (since the is the lowest and furthest right + // the popup could go). + gfx::Point bottom_right_corner_of_popup = RoundedElementBounds().origin() + + gfx::Vector2d(popup_required_width, + RoundedElementBounds().height() + popup_required_height); + + gfx::Display top_left_display = GetDisplayNearestPoint( + top_left_corner_of_popup); + gfx::Display bottom_right_display = GetDisplayNearestPoint( + bottom_right_corner_of_popup); + + std::pair popup_x_and_width = + CalculatePopupXAndWidth(top_left_display, + bottom_right_display, + popup_required_width); + std::pair popup_y_and_height = + CalculatePopupYAndHeight(top_left_display, + bottom_right_display, + popup_required_height); + + return gfx::Rect(popup_x_and_width.first, + popup_y_and_height.first, + popup_x_and_width.second, + popup_y_and_height.second); +} + +} // namespace autofill diff --git a/src/browser/popup_controller_common.h b/src/browser/popup_controller_common.h new file mode 100644 index 0000000000..da1ad40c35 --- /dev/null +++ b/src/browser/popup_controller_common.h @@ -0,0 +1,105 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_AUTOFILL_POPUP_CONTROLLER_COMMON_H_ +#define CHROME_BROWSER_UI_AUTOFILL_POPUP_CONTROLLER_COMMON_H_ + +#include "content/public/browser/render_widget_host.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/rect_f.h" + +namespace content { +struct NativeWebKeyboardEvent; +class RenderViewHost; +class WebContents; +} + +namespace gfx { +class Display; +} + +namespace autofill { + +// Class that controls common functionality for Autofill style popups. Can +// determine the correct location of a popup of a desired size and can register +// a handler to key press events. +class PopupControllerCommon { + public: + PopupControllerCommon(const gfx::RectF& element_bounds, + gfx::NativeView container_view, + content::WebContents* web_contents); + virtual ~PopupControllerCommon(); + + const gfx::RectF& element_bounds() const { return element_bounds_; } + gfx::NativeView container_view() { return container_view_; } + content::WebContents* web_contents() { return web_contents_; } + + // Returns the enclosing rectangle for |element_bounds_|. + const gfx::Rect RoundedElementBounds() const; + + // Returns the bounds that the popup should be placed at, given the desired + // width and height. By default this places the popup below |element_bounds| + // but it will be placed above if there isn't enough space. + gfx::Rect GetPopupBounds(int desired_height, int desired_width) const; + + // Callback used to register with RenderViewHost. This can only be set once, + // or else a callback may be registered that will not be removed + // (crbug.com/338070). Call will crash if callback is already set. + void SetKeyPressCallback(content::RenderWidgetHost::KeyPressEventCallback); + + // Register listener for key press events with the current RenderViewHost + // associated with |web_contents_|. If callback has already been registered, + // this has no effect. + void RegisterKeyPressCallback(); + + // Remove previously registered callback, assuming that the current + // RenderViewHost is the same as when it was originally registered. Safe to + // call even if the callback is not currently registered. + void RemoveKeyPressCallback(); + + protected: + // A helper function to get the display closest to the given point (virtual + // for testing). + virtual gfx::Display GetDisplayNearestPoint(const gfx::Point& point) const; + + private: + // Calculates the width of the popup and the x position of it. These values + // will stay on the screen. + std::pair CalculatePopupXAndWidth( + const gfx::Display& left_display, + const gfx::Display& right_display, + int popup_required_width) const; + + // Calculates the height of the popup and the y position of it. These values + // will stay on the screen. + std::pair CalculatePopupYAndHeight( + const gfx::Display& top_display, + const gfx::Display& bottom_display, + int popup_required_height) const; + + // The bounds of the text element that is the focus of the popup. + // These coordinates are in screen space. + gfx::RectF element_bounds_; + + // Weak reference + gfx::NativeView container_view_; + + // The WebContents in which this object should listen for keyboard events + // while showing the popup. Can be NULL, in which case this object will not + // listen for keyboard events. + content::WebContents* web_contents_; + + // The RenderViewHost that this object has registered its keyboard press + // callback with. + content::RenderViewHost* key_press_event_target_; + + content::RenderWidgetHost::KeyPressEventCallback key_press_event_callback_; + + DISALLOW_COPY_AND_ASSIGN(PopupControllerCommon); +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_POPUP_CONTROLLER_COMMON_H_ diff --git a/src/browser/tab_autofill_manager_delegate.cc b/src/browser/tab_autofill_manager_delegate.cc new file mode 100644 index 0000000000..143e79f729 --- /dev/null +++ b/src/browser/tab_autofill_manager_delegate.cc @@ -0,0 +1,140 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h" + +#include "base/logging.h" +#include "base/prefs/pref_service.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" +#include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/content/common/autofill_messages.h" +#include "components/autofill/core/common/autofill_pref_names.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents_view.h" +#include "content/nw/src/shell_browser_context.h" +#include "content/nw/src/browser/nw_form_database_service.h" +#include "ui/gfx/rect.h" + +#if defined(OS_ANDROID) +#include "chrome/browser/ui/android/autofill/autofill_logger_android.h" +#endif + +DEFINE_WEB_CONTENTS_USER_DATA_KEY(autofill::TabAutofillManagerDelegate); + +namespace autofill { + +TabAutofillManagerDelegate::TabAutofillManagerDelegate( + content::WebContents* web_contents) + : content::WebContentsObserver(web_contents), + web_contents_(web_contents) { + DCHECK(web_contents); +} + +TabAutofillManagerDelegate::~TabAutofillManagerDelegate() { + // NOTE: It is too late to clean up the autofill popup; that cleanup process + // requires that the WebContents instance still be valid and it is not at + // this point (in particular, the WebContentsImpl destructor has already + // finished running and we are now in the base class destructor). + DCHECK(!popup_controller_); +} + +void TabAutofillManagerDelegate::TabActivated() { +} + +PersonalDataManager* TabAutofillManagerDelegate::GetPersonalDataManager() { + return NULL; +} + +scoped_refptr + TabAutofillManagerDelegate::GetDatabase() { + nw::NwFormDatabaseService* service = + static_cast( + web_contents_->GetBrowserContext())->GetFormDatabaseService(); + return service->get_autofill_webdata_service(); +} + +PrefService* TabAutofillManagerDelegate::GetPrefs() { + return NULL; +} + +void TabAutofillManagerDelegate::ShowAutofillSettings() { + NOTIMPLEMENTED(); +} + +void TabAutofillManagerDelegate::ConfirmSaveCreditCard( + const AutofillMetrics& metric_logger, + const base::Closure& save_card_callback) { + NOTIMPLEMENTED(); +} + +void TabAutofillManagerDelegate::ShowRequestAutocompleteDialog( + const FormData& form, + const GURL& source_url, + const base::Callback& callback) { + NOTIMPLEMENTED(); +} + +void TabAutofillManagerDelegate::ShowAutofillPopup( + const gfx::RectF& element_bounds, + base::i18n::TextDirection text_direction, + const std::vector& values, + const std::vector& labels, + const std::vector& icons, + const std::vector& identifiers, + base::WeakPtr delegate) { + // Convert element_bounds to be in screen space. + gfx::Rect client_area; + web_contents_->GetView()->GetContainerBounds(&client_area); + gfx::RectF element_bounds_in_screen_space = + element_bounds + client_area.OffsetFromOrigin(); + + // Will delete or reuse the old |popup_controller_|. + popup_controller_ = AutofillPopupControllerImpl::GetOrCreate( + popup_controller_, + delegate, + web_contents(), + web_contents()->GetView()->GetNativeView(), + element_bounds_in_screen_space, + text_direction); + + popup_controller_->Show(values, labels, icons, identifiers); +} + +void TabAutofillManagerDelegate::UpdateAutofillPopupDataListValues( + const std::vector& values, + const std::vector& labels) { + if (popup_controller_.get()) + popup_controller_->UpdateDataListValues(values, labels); +} + +void TabAutofillManagerDelegate::HideAutofillPopup() { + if (popup_controller_.get()) + popup_controller_->Hide(); + +} + +bool TabAutofillManagerDelegate::IsAutocompleteEnabled() { + return true; +} + +void TabAutofillManagerDelegate::HideRequestAutocompleteDialog() { + NOTIMPLEMENTED(); +} + +void TabAutofillManagerDelegate::WebContentsDestroyed( + content::WebContents* web_contents) { + HideAutofillPopup(); +} + +void TabAutofillManagerDelegate::DetectAccountCreationForms( + const std::vector& forms) { + NOTIMPLEMENTED(); +} + +void TabAutofillManagerDelegate::DidFillOrPreviewField( + const base::string16& autofilled_value, + const base::string16& profile_full_name) { +} + +} // namespace autofill diff --git a/src/browser/tab_autofill_manager_delegate.h b/src/browser/tab_autofill_manager_delegate.h new file mode 100644 index 0000000000..6830858bbd --- /dev/null +++ b/src/browser/tab_autofill_manager_delegate.h @@ -0,0 +1,98 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_AUTOFILL_TAB_AUTOFILL_MANAGER_DELEGATE_H_ +#define CHROME_BROWSER_UI_AUTOFILL_TAB_AUTOFILL_MANAGER_DELEGATE_H_ + +#include "base/callback.h" +#include "base/compiler_specific.h" +#include "base/i18n/rtl.h" +#include "base/memory/weak_ptr.h" +#include "components/autofill/core/browser/autofill_manager_delegate.h" +#include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/web_contents_user_data.h" + +namespace content { +struct FrameNavigateParams; +struct LoadCommittedDetails; +class WebContents; +} + +namespace autofill { + +class AutofillDialogController; +class AutofillPopupControllerImpl; +struct FormData; + +// Chrome implementation of AutofillManagerDelegate. +class TabAutofillManagerDelegate + : public AutofillManagerDelegate, + public content::WebContentsUserData, + public content::WebContentsObserver { + public: + virtual ~TabAutofillManagerDelegate(); + + // Called when the tab corresponding to |this| instance is activated. + void TabActivated(); + + // AutofillManagerDelegate implementation. + virtual PersonalDataManager* GetPersonalDataManager() OVERRIDE; + virtual scoped_refptr + GetDatabase() OVERRIDE; + virtual PrefService* GetPrefs() OVERRIDE; + virtual void HideRequestAutocompleteDialog() OVERRIDE; + virtual void ShowAutofillSettings() OVERRIDE; + virtual void ConfirmSaveCreditCard( + const AutofillMetrics& metric_logger, + const base::Closure& save_card_callback) OVERRIDE; + virtual void ShowRequestAutocompleteDialog( + const FormData& form, + const GURL& source_url, + const base::Callback& callback) OVERRIDE; + virtual void ShowAutofillPopup( + const gfx::RectF& element_bounds, + base::i18n::TextDirection text_direction, + const std::vector& values, + const std::vector& labels, + const std::vector& icons, + const std::vector& identifiers, + base::WeakPtr delegate) OVERRIDE; + virtual void UpdateAutofillPopupDataListValues( + const std::vector& values, + const std::vector& labels) OVERRIDE; + virtual void HideAutofillPopup() OVERRIDE; + virtual bool IsAutocompleteEnabled() OVERRIDE; + virtual void DetectAccountCreationForms( + const std::vector& forms) OVERRIDE; + virtual void DidFillOrPreviewField( + const base::string16& autofilled_value, + const base::string16& profile_full_name) OVERRIDE; + + // content::WebContentsObserver implementation. + virtual void WebContentsDestroyed( + content::WebContents* web_contents) OVERRIDE; + + // Exposed for testing. + AutofillDialogController* GetDialogControllerForTesting() { + return dialog_controller_.get(); + } + void SetDialogControllerForTesting( + const base::WeakPtr& dialog_controller) { + dialog_controller_ = dialog_controller; + } + + private: + explicit TabAutofillManagerDelegate(content::WebContents* web_contents); + friend class content::WebContentsUserData; + + content::WebContents* const web_contents_; + base::WeakPtr dialog_controller_; + base::WeakPtr popup_controller_; + + DISALLOW_COPY_AND_ASSIGN(TabAutofillManagerDelegate); +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_AUTOFILL_TAB_AUTOFILL_MANAGER_DELEGATE_H_ diff --git a/src/nw_shell.cc b/src/nw_shell.cc index c9e1db9ef8..ce77d85b3c 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -52,6 +52,7 @@ #include "content/nw/src/browser/native_window.h" #include "content/nw/src/browser/shell_devtools_delegate.h" #include "content/nw/src/browser/shell_javascript_dialog_creator.h" +#include "content/nw/src/browser/tab_autofill_manager_delegate.h" #include "content/nw/src/common/shell_switches.h" #include "content/nw/src/media/media_stream_devices_controller.h" #include "content/nw/src/nw_package.h" @@ -64,6 +65,9 @@ #include "net/base/escape.h" #include "ui/base/resource/resource_bundle.h" +#include "components/autofill/content/browser/content_autofill_driver.h" +#include "components/autofill/core/browser/autofill_manager.h" + #if defined(OS_WIN) #include "content/nw/src/browser/native_window_win.h" @@ -196,6 +200,13 @@ Shell::Shell(WebContents* web_contents, base::DictionaryValue* manifest) // Initialize window after we set window_, because some operations of // NativeWindow requires the window_ to be non-NULL. window_->InitFromManifest(manifest); + + autofill::TabAutofillManagerDelegate::CreateForWebContents(web_contents); + autofill::ContentAutofillDriver::CreateForWebContentsAndDelegate( + web_contents, + autofill::TabAutofillManagerDelegate::FromWebContents(web_contents), + "", + autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER); } Shell::~Shell() { @@ -542,7 +553,7 @@ bool Shell::IsPopupOrPanel(const WebContents* source) const { // Window opened by window.open void Shell::WebContentsCreated(WebContents* source_contents, - int64 source_frame_id, + int source_frame_id, const base::string16& frame_name, const GURL& target_url, WebContents* new_contents) { @@ -571,6 +582,13 @@ void Shell::WebContentsCreated(WebContents* source_contents, // in Chromium 32 RenderViewCreated will not be called so the case // should be handled here new nwapi::DispatcherHost(new_contents->GetRenderViewHost()); + + autofill::TabAutofillManagerDelegate::CreateForWebContents(new_contents); + autofill::ContentAutofillDriver::CreateForWebContentsAndDelegate( + new_contents, + autofill::TabAutofillManagerDelegate::FromWebContents(new_contents), + "", + autofill::AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER); } #if defined(OS_WIN) diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index f724b8bc6f..f2aec43300 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -32,6 +32,9 @@ #include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" #include "components/autofill/content/renderer/page_click_tracker.h" +#include "components/autofill/content/renderer/autofill_agent.h" +#include "components/autofill/content/renderer/password_autofill_agent.h" +#include "components/autofill/content/renderer/password_generation_agent.h" #include "content/common/view_messages.h" #include "content/nw/src/api/dispatcher.h" #include "content/nw/src/api/api_messages.h" @@ -66,6 +69,7 @@ using content::RenderView; using content::RenderViewImpl; using autofill::AutofillAgent; using autofill::PasswordAutofillAgent; +using autofill::PasswordGenerationAgent; using net::ProxyBypassRules; using blink::WebFrame; using blink::WebView; @@ -195,7 +199,15 @@ void ShellContentRendererClient::RenderViewCreated(RenderView* render_view) { new printing::PrintWebViewHelper(render_view); #endif - // FIXME: nw::AutofillAgent* autofill_agent = new nw::AutofillAgent(render_view); + PasswordGenerationAgent* password_generation_agent = + new PasswordGenerationAgent(render_view); + PasswordAutofillAgent* password_autofill_agent = + new PasswordAutofillAgent(render_view); + new AutofillAgent(render_view, + password_autofill_agent, + password_generation_agent); + // FIXME: + // nw::AutofillAgent* autofill_agent = new nw::AutofillAgent(render_view); // The PageClickTracker is a RenderViewObserver, and hence will be freed when // the RenderView is destroyed. diff --git a/src/shell_browser_context.cc b/src/shell_browser_context.cc index 48a56e4c67..272954906b 100644 --- a/src/shell_browser_context.cc +++ b/src/shell_browser_context.cc @@ -31,6 +31,7 @@ #include "content/public/browser/storage_partition.h" #include "content/public/common/content_switches.h" #include "content/nw/src/browser/shell_download_manager_delegate.h" +#include "content/nw/src/browser/nw_form_database_service.h" #include "content/nw/src/common/shell_switches.h" #include "content/nw/src/net/shell_url_request_context_getter.h" #include "content/nw/src/nw_package.h" @@ -92,6 +93,14 @@ ShellBrowserContext::~ShellBrowserContext() { } } +void ShellBrowserContext::PreMainMessageLoopRun() { + form_database_service_.reset(new nw::NwFormDatabaseService(path_)); +} + +nw::NwFormDatabaseService* ShellBrowserContext::GetFormDatabaseService() { + return form_database_service_.get(); +} + void ShellBrowserContext::InitWhileIOAllowed() { CommandLine* cmd_line = CommandLine::ForCurrentProcess(); if (cmd_line->HasSwitch(switches::kIgnoreCertificateErrors)) { diff --git a/src/shell_browser_context.h b/src/shell_browser_context.h index ff42d55f74..cf0bacc5dd 100644 --- a/src/shell_browser_context.h +++ b/src/shell_browser_context.h @@ -16,6 +16,7 @@ namespace nw { class Package; +class NwFormDatabaseService; } namespace content { @@ -82,6 +83,11 @@ class ShellBrowserContext : public BrowserContext { bool in_memory, ProtocolHandlerMap* protocol_handlers) OVERRIDE; + nw::NwFormDatabaseService* GetFormDatabaseService(); + + // Maps to BrowserMainParts::PreMainMessageLoopRun. + void PreMainMessageLoopRun(); + bool pinning_renderer() { return !disable_pinning_renderer_; } void set_pinning_renderer(bool val) { disable_pinning_renderer_ = !val; } @@ -102,6 +108,7 @@ class ShellBrowserContext : public BrowserContext { scoped_ptr resource_context_; scoped_refptr download_manager_delegate_; scoped_refptr url_request_getter_; + scoped_ptr form_database_service_; DISALLOW_COPY_AND_ASSIGN(ShellBrowserContext); }; diff --git a/src/shell_browser_main_parts.cc b/src/shell_browser_main_parts.cc index a64c5ce1fb..67a4ead068 100644 --- a/src/shell_browser_main_parts.cc +++ b/src/shell_browser_main_parts.cc @@ -114,6 +114,7 @@ void ShellBrowserMainParts::PreMainMessageLoopStart() { #endif void ShellBrowserMainParts::PreMainMessageLoopRun() { + #if !defined(OS_MACOSX) Init(); #endif @@ -156,6 +157,8 @@ void ShellBrowserMainParts::Init() { CommandLine& command_line = *CommandLine::ForCurrentProcess(); browser_context_.reset(new ShellBrowserContext(false, package())); + browser_context_->PreMainMessageLoopRun(); + off_the_record_browser_context_.reset( new ShellBrowserContext(true, package())); diff --git a/src/shell_main_delegate.cc b/src/shell_main_delegate.cc index c132a66a6b..4ffaa4c0c8 100644 --- a/src/shell_main_delegate.cc +++ b/src/shell_main_delegate.cc @@ -70,7 +70,7 @@ using base::FilePath; #define IPC_LOG_TABLE_ADD_ENTRY(msg_id, logger) \ content::RegisterIPCLogger(msg_id, logger) #include "content/nw/src/common/common_message_generator.h" -//#include "components/autofill/core/common/autofill_messages.h" +#include "components/autofill/content/common/autofill_messages.h" #endif namespace { From 50df8ef05a6a591b1ebc649664552633df6333f2 Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 8 Jun 2014 19:43:20 +0800 Subject: [PATCH 039/492] fix for mac --- src/nw_shell.cc | 2 +- src/nw_shell.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/nw_shell.cc b/src/nw_shell.cc index ce77d85b3c..100b9f336c 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -501,7 +501,7 @@ WebContents* Shell::OpenURLFromTab(WebContents* source, return source; } -void Shell::LoadingStateChanged(WebContents* source) { +void Shell::LoadingStateChanged(WebContents* source, bool to_different_document) { int current_index = web_contents_->GetController().GetCurrentEntryIndex(); int max_index = web_contents_->GetController().GetEntryCount() - 1; diff --git a/src/nw_shell.h b/src/nw_shell.h index c6781ded9e..f869f226c7 100644 --- a/src/nw_shell.h +++ b/src/nw_shell.h @@ -142,14 +142,15 @@ class Shell : public WebContentsDelegate, // content::WebContentsDelegate implementation. virtual WebContents* OpenURLFromTab(WebContents* source, const OpenURLParams& params) OVERRIDE; - virtual void LoadingStateChanged(WebContents* source) OVERRIDE; + virtual void LoadingStateChanged(WebContents* source, + bool to_different_document) 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, + int source_frame_id, const base::string16& frame_name, const GURL& target_url, WebContents* new_contents) OVERRIDE; From d3fb0da79f72ec8cc23779ed05a30264c78c00cf Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Sun, 8 Jun 2014 19:43:23 +0800 Subject: [PATCH 040/492] [nw10] rebase fix on mac --- nw.gypi | 9 + src/breakpad_mac.mm | 10 +- src/browser/autofill_popup_view_bridge.h | 53 ++++ src/browser/autofill_popup_view_bridge.mm | 81 +++++ src/browser/autofill_popup_view_cocoa.h | 33 ++ src/browser/autofill_popup_view_cocoa.mm | 285 ++++++++++++++++++ src/browser/shell_javascript_dialog_mac.mm | 6 +- ...shell_resource_dispatcher_host_delegate.cc | 9 +- .../shell_resource_dispatcher_host_delegate.h | 2 - src/browser/standard_menus_mac.mm | 2 +- src/chrome_breakpad_client.h | 4 - src/media/media_internals.cc | 4 - src/media/media_internals.h | 7 - src/net/shell_network_delegate.cc | 3 +- src/net/shell_network_delegate.h | 3 +- src/nw_shell.cc | 3 +- src/nw_shell.h | 4 +- .../printing/print_web_view_helper_mac.mm | 4 +- src/shell_browser_context.cc | 16 +- src/shell_browser_context.h | 14 +- src/shell_browser_main_parts.h | 2 + src/shell_content_browser_client.cc | 5 +- src/shell_content_browser_client.h | 5 +- src/shell_content_main.cc | 5 +- 24 files changed, 513 insertions(+), 56 deletions(-) create mode 100644 src/browser/autofill_popup_view_bridge.h create mode 100644 src/browser/autofill_popup_view_bridge.mm create mode 100644 src/browser/autofill_popup_view_cocoa.h create mode 100644 src/browser/autofill_popup_view_cocoa.mm diff --git a/nw.gypi b/nw.gypi index 944f95af5a..0f141b2608 100644 --- a/nw.gypi +++ b/nw.gypi @@ -173,6 +173,10 @@ 'src/browser/app_controller_mac.mm', 'src/browser/autofill_popup_view_gtk.cc', 'src/browser/autofill_popup_view_gtk.h', + 'src/browser/autofill_popup_view_cocoa.h', + 'src/browser/autofill_popup_view_cocoa.mm', + 'src/browser/autofill_popup_view_bridge.h', + 'src/browser/autofill_popup_view_bridge.mm', 'src/browser/autofill_popup_controller_impl.cc', 'src/browser/autofill_popup_controller_impl.h', 'src/browser/tab_autofill_manager_delegate.cc', @@ -369,6 +373,11 @@ '<(DEPTH)/breakpad/breakpad.gyp:breakpad', '<(DEPTH)/components/components.gyp:breakpad_component', ], + 'link_settings': { + 'libraries': [ + '$(SDKROOT)/System/Library/Frameworks/AddressBook.framework', + ], + }, }], ['toolkit_uses_gtk == 1', { 'dependencies': [ diff --git a/src/breakpad_mac.mm b/src/breakpad_mac.mm index 9b60ea12f9..48dc09e729 100644 --- a/src/breakpad_mac.mm +++ b/src/breakpad_mac.mm @@ -12,6 +12,7 @@ #import "base/basictypes.h" #include "base/command_line.h" #include "base/debug/crash_logging.h" +#include "base/debug/dump_without_crashing.h" #include "base/file_util.h" #include "base/files/file_path.h" #import "base/logging.h" @@ -29,6 +30,7 @@ #include "content/nw/src/paths_mac.h" //#include "policy/policy_constants.h" + namespace { BreakpadRef gBreakpadRef = NULL; @@ -147,6 +149,8 @@ bool IsCrashReporterEnabled() { return gBreakpadRef != NULL; } +namespace breakpad { + // Only called for a branded build of Chrome.app. void InitCrashReporter() { DCHECK(!gBreakpadRef); @@ -254,7 +258,7 @@ void InitCrashReporter() { } logging::SetLogMessageHandler(&FatalMessageHandler); - breakpad::GetBreakpadClient()->SetDumpWithoutCrashingFunction( + base::debug::SetDumpWithoutCrashingFunction( &DumpHelper::DumpWithoutCrashing); // abort() sends SIGABRT, which breakpad does not intercept. @@ -266,6 +270,8 @@ void InitCrashReporter() { CHECK(0 == sigaction(SIGABRT, &sigact, NULL)); } +} //namespace breakpad + void InitCrashProcessInfo() { if (gBreakpadRef == NULL) { return; @@ -292,3 +298,5 @@ bool SetCrashDumpPath(const char* path) { BreakpadSetKeyValue(gBreakpadRef, @BREAKPAD_DUMP_DIRECTORY, base::SysUTF8ToNSString(path)); return true; } + + diff --git a/src/browser/autofill_popup_view_bridge.h b/src/browser/autofill_popup_view_bridge.h new file mode 100644 index 0000000000..09119f4a97 --- /dev/null +++ b/src/browser/autofill_popup_view_bridge.h @@ -0,0 +1,53 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_VIEW_BRIDGE_H_ +#define CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_VIEW_BRIDGE_H_ + +#include + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "chrome/browser/ui/autofill/autofill_popup_view.h" + +@class AutofillPopupViewCocoa; +@class NSWindow; + +namespace autofill { + +class AutofillPopupController; + +// Mac implementation for AutofillPopupView interface. +// Serves as a bridge to the Objective-C class AutofillPopupViewCocoa which +// actually implements the view. +class AutofillPopupViewBridge : public AutofillPopupView { + public: + explicit AutofillPopupViewBridge(AutofillPopupController* controller); + + private: + virtual ~AutofillPopupViewBridge(); + + // AutofillPopupView implementation. + virtual void Hide() OVERRIDE; + virtual void Show() OVERRIDE; + virtual void InvalidateRow(size_t row) OVERRIDE; + virtual void UpdateBoundsAndRedrawPopup() OVERRIDE; + + // Set the initial bounds of the popup to show, including the placement + // of it. + void SetInitialBounds(); + + // The controller for this view. + AutofillPopupController* controller_; // Weak reference. + + // The native Cocoa window and view. + NSWindow* window_; // Weak reference, owns itself. + AutofillPopupViewCocoa* view_; // Weak reference, owned by the |window_|. + + DISALLOW_COPY_AND_ASSIGN(AutofillPopupViewBridge); +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_VIEW_BRIDGE_H_ diff --git a/src/browser/autofill_popup_view_bridge.mm b/src/browser/autofill_popup_view_bridge.mm new file mode 100644 index 0000000000..dc6e59a5fe --- /dev/null +++ b/src/browser/autofill_popup_view_bridge.mm @@ -0,0 +1,81 @@ +// 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. + +#import + +#include "content/nw/src/browser/autofill_popup_view_bridge.h" + +#include "base/logging.h" +#include "content/nw/src/browser/autofill_popup_controller.h" +#import "content/nw/src/browser/autofill_popup_view_cocoa.h" +#include "ui/base/cocoa/window_size_constants.h" +#include "ui/gfx/rect.h" + +namespace autofill { + +AutofillPopupViewBridge::AutofillPopupViewBridge( + AutofillPopupController* controller) + : controller_(controller) { + window_ = + [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:YES]; + // Telling Cocoa that the window is opaque enables some drawing optimizations. + [window_ setOpaque:YES]; + + view_ = [[[AutofillPopupViewCocoa alloc] + initWithController:controller_ + frame:NSZeroRect] autorelease]; + [window_ setContentView:view_]; +} + +AutofillPopupViewBridge::~AutofillPopupViewBridge() { + [view_ controllerDestroyed]; + + // Remove the child window before closing, otherwise it can mess up + // display ordering. + [[window_ parentWindow] removeChildWindow:window_]; + + [window_ close]; +} + +void AutofillPopupViewBridge::Hide() { + delete this; +} + +void AutofillPopupViewBridge::Show() { + UpdateBoundsAndRedrawPopup(); + [[controller_->container_view() window] addChildWindow:window_ + ordered:NSWindowAbove]; +} + +void AutofillPopupViewBridge::InvalidateRow(size_t row) { + NSRect dirty_rect = + NSRectFromCGRect(controller_->GetRowBounds(row).ToCGRect()); + [view_ setNeedsDisplayInRect:dirty_rect]; +} + +void AutofillPopupViewBridge::UpdateBoundsAndRedrawPopup() { + NSRect frame = NSRectFromCGRect(controller_->popup_bounds().ToCGRect()); + + // Flip coordinates back into Cocoa-land. The controller's platform-neutral + // coordinate space places the origin at the top-left of the first screen, + // whereas Cocoa's coordinate space expects the origin to be at the + // bottom-left of this same screen. + NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; + frame.origin.y = NSMaxY([screen frame]) - NSMaxY(frame); + + // TODO(isherman): The view should support scrolling if the popup gets too + // big to fit on the screen. + [window_ setFrame:frame display:YES]; + [view_ setNeedsDisplay:YES]; +} + +AutofillPopupView* AutofillPopupView::Create( + AutofillPopupController* controller) { + return new AutofillPopupViewBridge(controller); +} + +} // namespace autofill diff --git a/src/browser/autofill_popup_view_cocoa.h b/src/browser/autofill_popup_view_cocoa.h new file mode 100644 index 0000000000..c51a6ed8d0 --- /dev/null +++ b/src/browser/autofill_popup_view_cocoa.h @@ -0,0 +1,33 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_CONTENT_VIEW_H_ +#define CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_CONTENT_VIEW_H_ + +#import + +#import "ui/base/cocoa/base_view.h" + +namespace autofill { +class AutofillPopupController; +} // namespace autofill + +// Draws the native Autofill popup view on Mac. +@interface AutofillPopupViewCocoa : BaseView { + @private + // The cross-platform controller for this view. + __weak autofill::AutofillPopupController* controller_; +} + +// Designated initializer. +- (id)initWithController:(autofill::AutofillPopupController*)controller + frame:(NSRect)frame; + +// Informs the view that its controller has been (or will imminently be) +// destroyed. +- (void)controllerDestroyed; + +@end + +#endif // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_CONTENT_VIEW_H_ diff --git a/src/browser/autofill_popup_view_cocoa.mm b/src/browser/autofill_popup_view_cocoa.mm new file mode 100644 index 0000000000..387e6ef82e --- /dev/null +++ b/src/browser/autofill_popup_view_cocoa.mm @@ -0,0 +1,285 @@ +// 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. + +#import "content/nw/src/browser/autofill_popup_view_cocoa.h" + +#include "base/logging.h" +#include "base/strings/sys_string_conversions.h" +#include "content/nw/src/browser/autofill_popup_controller.h" +#include "chrome/browser/ui/autofill/popup_constants.h" +#include "content/nw/src/browser/autofill_popup_view_bridge.h" +#include "components/autofill/core/browser/popup_item_ids.h" +#include "grit/ui_resources.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/point.h" +#include "ui/gfx/rect.h" + +using autofill::AutofillPopupView; + +namespace { + +NSColor* BackgroundColor() { + return [NSColor whiteColor]; +} + +// The color of the border around the popup. +NSColor* BorderColor() { + return [NSColor colorForControlTint:[NSColor currentControlTint]]; +} + +NSColor* SeparatorColor() { + return [NSColor colorWithCalibratedWhite:220 / 255.0 alpha:1]; +} + +NSColor* HighlightColor() { + return [NSColor selectedControlColor]; +} + +NSColor* NameColor() { + return [NSColor blackColor]; +} + +NSColor* WarningColor() { + return [NSColor grayColor]; +} + +NSColor* SubtextColor() { + return [NSColor grayColor]; +} + +} // namespace + +#pragma mark - +#pragma mark Private methods + +@interface AutofillPopupViewCocoa () + +// Draws a thin separator in the popup UI. +- (void)drawSeparatorWithBounds:(NSRect)bounds; + +// Draws an Autofill suggestion in the given |bounds|, labeled with the given +// |name| and |subtext| hint. If the suggestion |isSelected|, then it is drawn +// with a highlight. |index| determines the font to use, as well as the icon, +// if the row requires it -- such as for credit cards. +- (void)drawSuggestionWithName:(NSString*)name + subtext:(NSString*)subtext + index:(size_t)index + bounds:(NSRect)bounds + selected:(BOOL)isSelected; + +// Returns the icon for the row with the given |index|, or |nil| if there is +// none. +- (NSImage*)iconAtIndex:(size_t)index; + +@end + +@implementation AutofillPopupViewCocoa + +#pragma mark - +#pragma mark Initialisers + +- (id)initWithFrame:(NSRect)frame { + NOTREACHED(); + return [self initWithController:NULL frame:frame]; +} + +- (id)initWithController:(autofill::AutofillPopupController*)controller + frame:(NSRect)frame { + self = [super initWithFrame:frame]; + if (self) + controller_ = controller; + + return self; +} + +#pragma mark - +#pragma mark NSView implementation: + +// A slight optimization for drawing: +// https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaViewsGuide/Optimizing/Optimizing.html +- (BOOL)isOpaque { + return YES; +} + +- (BOOL)isFlipped { + // Flipped so that it's easier to share controller logic with other OSes. + return YES; +} + +- (void)drawRect:(NSRect)dirtyRect { + // If the view is in the process of being destroyed, don't bother drawing. + if (!controller_) + return; + + // Draw the popup's background and border. + // The inset is needed since the border is centered on the |path|. + // TODO(isherman): We should consider using asset-based drawing for the + // border, creating simple bitmaps for the view's border and background, and + // drawing them using NSDrawNinePartImage(). + CGFloat inset = autofill::kPopupBorderThickness / 2.0; + NSRect borderRect = NSInsetRect([self bounds], inset, inset); + NSBezierPath* path = [NSBezierPath bezierPathWithRect:borderRect]; + [BackgroundColor() setFill]; + [path fill]; + [path setLineWidth:autofill::kPopupBorderThickness]; + [BorderColor() setStroke]; + [path stroke]; + + for (size_t i = 0; i < controller_->names().size(); ++i) { + // Skip rows outside of the dirty rect. + NSRect rowBounds = + NSRectFromCGRect(controller_->GetRowBounds(i).ToCGRect()); + if (!NSIntersectsRect(rowBounds, dirtyRect)) + continue; + + if (controller_->identifiers()[i] == autofill::POPUP_ITEM_ID_SEPARATOR) { + [self drawSeparatorWithBounds:rowBounds]; + } else { + NSString* name = SysUTF16ToNSString(controller_->names()[i]); + NSString* subtext = SysUTF16ToNSString(controller_->subtexts()[i]); + BOOL isSelected = static_cast(i) == controller_->selected_line(); + [self drawSuggestionWithName:name + subtext:subtext + index:i + bounds:rowBounds + selected:isSelected]; + } + } +} + +- (void)mouseUp:(NSEvent*)theEvent { + // If the view is in the process of being destroyed, abort. + if (!controller_) + return; + + NSPoint location = [self convertPoint:[theEvent locationInWindow] + fromView:nil]; + + if (NSPointInRect(location, [self bounds])) { + controller_->SetSelectionAtPoint(gfx::Point(NSPointToCGPoint(location))); + controller_->AcceptSelectedLine(); + } +} + +- (void)mouseMoved:(NSEvent*)theEvent { + // If the view is in the process of being destroyed, abort. + if (!controller_) + return; + + NSPoint location = [self convertPoint:[theEvent locationInWindow] + fromView:nil]; + + controller_->SetSelectionAtPoint(gfx::Point(NSPointToCGPoint(location))); +} + +- (void)mouseDragged:(NSEvent*)theEvent { + [self mouseMoved:theEvent]; +} + +- (void)mouseExited:(NSEvent*)theEvent { + // If the view is in the process of being destroyed, abort. + if (!controller_) + return; + + controller_->SelectionCleared(); +} + +#pragma mark - +#pragma mark Public API: + +- (void)controllerDestroyed { + // Since the |controller_| either already has been destroyed or is about to + // be, about the only thing we can safely do with it is to null it out. + controller_ = NULL; +} + +#pragma mark - +#pragma mark Private API: + +- (void)drawSeparatorWithBounds:(NSRect)bounds { + [SeparatorColor() set]; + [NSBezierPath fillRect:bounds]; +} + +- (void)drawSuggestionWithName:(NSString*)name + subtext:(NSString*)subtext + index:(size_t)index + bounds:(NSRect)bounds + selected:(BOOL)isSelected { + // If this row is selected, highlight it. + if (isSelected) { + [HighlightColor() set]; + [NSBezierPath fillRect:bounds]; + } + + BOOL isRTL = controller_->IsRTL(); + + NSColor* nameColor = + controller_->IsWarning(index) ? WarningColor() : NameColor(); + NSDictionary* nameAttributes = + [NSDictionary dictionaryWithObjectsAndKeys: + controller_->GetNameFontListForRow(index).GetPrimaryFont(). + GetNativeFont(), + NSFontAttributeName, nameColor, NSForegroundColorAttributeName, + nil]; + NSSize nameSize = [name sizeWithAttributes:nameAttributes]; + CGFloat x = bounds.origin.x + + (isRTL ? + bounds.size.width - AutofillPopupView::kEndPadding - nameSize.width : + AutofillPopupView::kEndPadding); + CGFloat y = bounds.origin.y + (bounds.size.height - nameSize.height) / 2; + + [name drawAtPoint:NSMakePoint(x, y) withAttributes:nameAttributes]; + + // The x-coordinate will be updated as each element is drawn. + x = bounds.origin.x + + (isRTL ? + AutofillPopupView::kEndPadding : + bounds.size.width - AutofillPopupView::kEndPadding); + + // Draw the Autofill icon, if one exists. + NSImage* icon = [self iconAtIndex:index]; + if (icon) { + NSSize iconSize = [icon size]; + x += isRTL ? 0 : -iconSize.width; + y = bounds.origin.y + (bounds.size.height - iconSize.height) / 2; + [icon drawInRect:NSMakeRect(x, y, iconSize.width, iconSize.height) + fromRect:NSZeroRect + operation:NSCompositeSourceOver + fraction:1.0 + respectFlipped:YES + hints:nil]; + + x += isRTL ? + iconSize.width + AutofillPopupView::kIconPadding : + -AutofillPopupView::kIconPadding; + } + + // Draw the subtext. + NSDictionary* subtextAttributes = + [NSDictionary dictionaryWithObjectsAndKeys: + controller_->subtext_font_list().GetPrimaryFont().GetNativeFont(), + NSFontAttributeName, SubtextColor(), NSForegroundColorAttributeName, + nil]; + NSSize subtextSize = [subtext sizeWithAttributes:subtextAttributes]; + x += isRTL ? 0 : -subtextSize.width; + y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2; + + [subtext drawAtPoint:NSMakePoint(x, y) withAttributes:subtextAttributes]; +} + +- (NSImage*)iconAtIndex:(size_t)index { + if (controller_->icons()[index].empty()) + return nil; + + int iconId = controller_->GetIconResourceID(controller_->icons()[index]); + DCHECK_NE(-1, iconId); + + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + return rb.GetNativeImageNamed(iconId).ToNSImage(); +} + +@end diff --git a/src/browser/shell_javascript_dialog_mac.mm b/src/browser/shell_javascript_dialog_mac.mm index ca03d0db25..a35c621b5e 100644 --- a/src/browser/shell_javascript_dialog_mac.mm +++ b/src/browser/shell_javascript_dialog_mac.mm @@ -82,7 +82,7 @@ - (void)alertDidEnd:(NSAlert*)alert return; bool success = returnCode == NSAlertFirstButtonReturn; - string16 input; + base::string16 input; if (textField_) input = base::SysNSStringToUTF16([textField_ stringValue]); @@ -105,8 +105,8 @@ - (void)cancel { ShellJavaScriptDialogCreator* creator, gfx::NativeWindow parent_window, JavaScriptMessageType message_type, - const string16& message_text, - const string16& default_prompt_text, + const base::string16& message_text, + const base::string16& default_prompt_text, const JavaScriptDialogManager::DialogClosedCallback& callback) : creator_(creator), callback_(callback) { diff --git a/src/browser/shell_resource_dispatcher_host_delegate.cc b/src/browser/shell_resource_dispatcher_host_delegate.cc index 918df3340b..a9cbc7eb81 100644 --- a/src/browser/shell_resource_dispatcher_host_delegate.cc +++ b/src/browser/shell_resource_dispatcher_host_delegate.cc @@ -33,13 +33,6 @@ ShellResourceDispatcherHostDelegate::ShellResourceDispatcherHostDelegate() { ShellResourceDispatcherHostDelegate::~ShellResourceDispatcherHostDelegate() { } -bool ShellResourceDispatcherHostDelegate::AcceptAuthRequest( - net::URLRequest* request, - net::AuthChallengeInfo* auth_info) { - // Why not give it a try? - return true; -} - ResourceDispatcherHostLoginDelegate* ShellResourceDispatcherHostDelegate::CreateLoginDelegate( net::AuthChallengeInfo* auth_info, net::URLRequest* request) { @@ -56,7 +49,7 @@ bool ShellResourceDispatcherHostDelegate::HandleExternalProtocol( const GURL& url, int child_id, int route_id) { #if defined(OS_MACOSX) // This must run on the UI thread on OS X. - platform_util::OpenExternal(url); + platform_util::OpenExternal2(url); #else // Otherwise put this work on the file thread. On Windows ShellExecute may // block for a significant amount of time, and it shouldn't hurt on Linux. diff --git a/src/browser/shell_resource_dispatcher_host_delegate.h b/src/browser/shell_resource_dispatcher_host_delegate.h index d3a3386219..3679ba7d40 100644 --- a/src/browser/shell_resource_dispatcher_host_delegate.h +++ b/src/browser/shell_resource_dispatcher_host_delegate.h @@ -18,8 +18,6 @@ class ShellResourceDispatcherHostDelegate virtual ~ShellResourceDispatcherHostDelegate(); // ResourceDispatcherHostDelegate implementation. - virtual bool AcceptAuthRequest(net::URLRequest* request, - net::AuthChallengeInfo* auth_info) OVERRIDE; virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate( net::AuthChallengeInfo* auth_info, net::URLRequest* request) OVERRIDE; virtual bool HandleExternalProtocol(const GURL& url, diff --git a/src/browser/standard_menus_mac.mm b/src/browser/standard_menus_mac.mm index 649cdd70ac..80ac54c770 100644 --- a/src/browser/standard_menus_mac.mm +++ b/src/browser/standard_menus_mac.mm @@ -47,7 +47,7 @@ - (void)setAppleMenu:(NSMenu *)menu; void StandardMenusMac::BuildAppleMenu() { NSMenu* appleMenu = [[NSMenu alloc] initWithTitle:@""]; - string16 name = base::UTF8ToUTF16(app_name_); + base::string16 name = base::UTF8ToUTF16(app_name_); [appleMenu addItemWithTitle:l10n_util::GetNSStringFWithFixup(IDS_ABOUT_MAC, name) action:@selector(orderFrontStandardAboutPanel:) keyEquivalent:@""]; diff --git a/src/chrome_breakpad_client.h b/src/chrome_breakpad_client.h index 7e79a092e6..489e8fe512 100644 --- a/src/chrome_breakpad_client.h +++ b/src/chrome_breakpad_client.h @@ -46,10 +46,6 @@ class ChromeBreakpadClient : public breakpad::BreakpadClient { virtual bool GetCrashDumpLocation(base::FilePath* crash_dir) OVERRIDE; -#if defined(OS_POSIX) - virtual void SetDumpWithoutCrashingFunction(void (*function)()) OVERRIDE; -#endif - virtual size_t RegisterCrashKeys() OVERRIDE; virtual bool IsRunningUnattended() OVERRIDE; diff --git a/src/media/media_internals.cc b/src/media/media_internals.cc index ee171558c1..e8546ea141 100644 --- a/src/media/media_internals.cc +++ b/src/media/media_internals.cc @@ -108,10 +108,6 @@ void MediaInternals::OnMediaRequestStateChanged( content::MediaRequestState state) { } -void MediaInternals::OnAudioStreamPlayingChanged( - int render_process_id, int render_view_id, int stream_id, bool playing, float power_dbfs, bool clipped) { -} - void MediaInternals::OnCreatingAudioStream( int render_process_id, int render_view_id) { diff --git a/src/media/media_internals.h b/src/media/media_internals.h index 3a2f79bcff..74254297b9 100644 --- a/src/media/media_internals.h +++ b/src/media/media_internals.h @@ -51,13 +51,6 @@ class MediaInternals : public content::MediaObserver { const GURL& security_origin, const content::MediaStreamDevice& device, content::MediaRequestState state) OVERRIDE; - virtual void OnAudioStreamPlayingChanged( - int render_process_id, - int render_view_id, - int stream_id, - bool playing, - float power_dbfs, - bool clipped) OVERRIDE; virtual void OnCreatingAudioStream(int render_process_id, int render_view_id) OVERRIDE; diff --git a/src/net/shell_network_delegate.cc b/src/net/shell_network_delegate.cc index 3142e12238..3be947bc1c 100644 --- a/src/net/shell_network_delegate.cc +++ b/src/net/shell_network_delegate.cc @@ -53,7 +53,8 @@ int ShellNetworkDelegate::OnHeadersReceived( net::URLRequest* request, const net::CompletionCallback& callback, const net::HttpResponseHeaders* original_response_headers, - scoped_refptr* override_response_headers) { + scoped_refptr* override_response_headers, + GURL* allowed_unsafe_redirect_url) { return net::OK; } diff --git a/src/net/shell_network_delegate.h b/src/net/shell_network_delegate.h index 11cc34f4cd..6f381d72be 100644 --- a/src/net/shell_network_delegate.h +++ b/src/net/shell_network_delegate.h @@ -48,7 +48,8 @@ class ShellNetworkDelegate : public net::NetworkDelegate { const net::CompletionCallback& callback, const net::HttpResponseHeaders* original_response_headers, scoped_refptr* - override_response_headers) OVERRIDE; + override_response_headers, + GURL* allowed_unsafe_redirect_url) OVERRIDE; virtual void OnBeforeRedirect(net::URLRequest* request, const GURL& new_location) OVERRIDE; virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE; diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 100b9f336c..2e545806d6 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -599,7 +599,8 @@ void Shell::WebContentsFocused(content::WebContents* web_contents) { #endif content::ColorChooser* -Shell::OpenColorChooser(content::WebContents* web_contents, SkColor color) { +Shell::OpenColorChooser(content::WebContents* web_contents, SkColor color, + const std::vector& suggestions) { return nw::ShowColorChooser(web_contents, color); } diff --git a/src/nw_shell.h b/src/nw_shell.h index f869f226c7..a2b80adb79 100644 --- a/src/nw_shell.h +++ b/src/nw_shell.h @@ -158,7 +158,9 @@ class Shell : public WebContentsDelegate, virtual void WebContentsFocused(WebContents* contents) OVERRIDE; #endif virtual content::ColorChooser* OpenColorChooser( - content::WebContents* web_contents, SkColor color) OVERRIDE; + content::WebContents* web_contents, + SkColor color, + const std::vector& suggestions) OVERRIDE; virtual void RunFileChooser( content::WebContents* web_contents, const content::FileChooserParams& params) OVERRIDE; diff --git a/src/renderer/printing/print_web_view_helper_mac.mm b/src/renderer/printing/print_web_view_helper_mac.mm index e777ca76cb..4904ed787c 100644 --- a/src/renderer/printing/print_web_view_helper_mac.mm +++ b/src/renderer/printing/print_web_view_helper_mac.mm @@ -21,7 +21,7 @@ namespace printing { -using WebKit::WebFrame; +using blink::WebFrame; void PrintWebViewHelper::PrintPageInternal( const PrintMsg_PrintPage_Params& params, @@ -125,7 +125,7 @@ skia::RefPtr canvas = skia::AdoptRef(new skia::VectorCanvas(device)); - WebKit::WebCanvas* canvas_ptr = canvas.get(); + blink::WebCanvas* canvas_ptr = canvas.get(); MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile); skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_); skia::SetIsPreviewMetafile(*canvas, is_preview); diff --git a/src/shell_browser_context.cc b/src/shell_browser_context.cc index 272954906b..b807feef2e 100644 --- a/src/shell_browser_context.cc +++ b/src/shell_browser_context.cc @@ -194,6 +194,14 @@ net::URLRequestContextGetter* ShellBrowserContext::CreateRequestContext( return url_request_getter_.get(); } +net::URLRequestContextGetter* + ShellBrowserContext::CreateRequestContextForStoragePartition( + const base::FilePath& partition_path, + bool in_memory, + ProtocolHandlerMap* protocol_handlers) { + return NULL; +} + net::URLRequestContextGetter* ShellBrowserContext::GetRequestContextForRenderProcess( int renderer_child_id) { @@ -218,14 +226,6 @@ net::URLRequestContextGetter* return GetRequestContext(); } -net::URLRequestContextGetter* - ShellBrowserContext::CreateRequestContextForStoragePartition( - const base::FilePath& partition_path, - bool in_memory, - ProtocolHandlerMap* protocol_handlers) { - return NULL; -} - ResourceContext* ShellBrowserContext::GetResourceContext() { return resource_context_.get(); } diff --git a/src/shell_browser_context.h b/src/shell_browser_context.h index cf0bacc5dd..7b8b05ef33 100644 --- a/src/shell_browser_context.h +++ b/src/shell_browser_context.h @@ -75,18 +75,18 @@ class ShellBrowserContext : public BrowserContext { virtual void CancelProtectedMediaIdentifierPermissionRequests( int group_id) OVERRIDE; + nw::NwFormDatabaseService* GetFormDatabaseService(); + + // Maps to BrowserMainParts::PreMainMessageLoopRun. + void PreMainMessageLoopRun(); + virtual net::URLRequestContextGetter* CreateRequestContext( ProtocolHandlerMap* protocol_handlers, - ProtocolHandlerScopedVector protocol_interceptors) OVERRIDE; + ProtocolHandlerScopedVector protocol_interceptors); virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition( const base::FilePath& partition_path, bool in_memory, - ProtocolHandlerMap* protocol_handlers) OVERRIDE; - - nw::NwFormDatabaseService* GetFormDatabaseService(); - - // Maps to BrowserMainParts::PreMainMessageLoopRun. - void PreMainMessageLoopRun(); + ProtocolHandlerMap* protocol_handlers); bool pinning_renderer() { return !disable_pinning_renderer_; } void set_pinning_renderer(bool val) { disable_pinning_renderer_ = !val; } diff --git a/src/shell_browser_main_parts.h b/src/shell_browser_main_parts.h index 3bf22eac74..f9ff060aff 100644 --- a/src/shell_browser_main_parts.h +++ b/src/shell_browser_main_parts.h @@ -20,8 +20,10 @@ namespace nw { class Package; } +namespace base { class CommandLine; class FilePath; +} namespace printing { class PrintJobManager; diff --git a/src/shell_content_browser_client.cc b/src/shell_content_browser_client.cc index 6965b595e2..dee937bf31 100644 --- a/src/shell_content_browser_client.cc +++ b/src/shell_content_browser_client.cc @@ -345,7 +345,8 @@ ShellContentBrowserClient::CreateRequestContextForStoragePartition( BrowserContext* content_browser_context, const base::FilePath& partition_path, bool in_memory, - ProtocolHandlerMap* protocol_handlers) { + ProtocolHandlerMap* protocol_handlers, + ProtocolHandlerScopedVector protocol_interceptors) { ShellBrowserContext* shell_browser_context = ShellBrowserContextForBrowserContext(content_browser_context); return shell_browser_context->CreateRequestContextForStoragePartition( @@ -366,7 +367,7 @@ printing::PrintJobManager* ShellContentBrowserClient::print_job_manager() { return shell_browser_main_parts_->print_job_manager(); } -void ShellContentBrowserClient::RenderProcessHostCreated( +void ShellContentBrowserClient::RenderProcessWillLaunch( RenderProcessHost* host) { int id = host->GetID(); if (!master_rph_) diff --git a/src/shell_content_browser_client.h b/src/shell_content_browser_client.h index ceda35317b..2ae08193af 100644 --- a/src/shell_content_browser_client.h +++ b/src/shell_content_browser_client.h @@ -62,7 +62,7 @@ class ShellContentBrowserClient : public ContentBrowserClient { return shell_browser_main_parts_; } virtual printing::PrintJobManager* print_job_manager(); - virtual void RenderProcessHostCreated(RenderProcessHost* host) OVERRIDE; + virtual void RenderProcessWillLaunch(RenderProcessHost* host) OVERRIDE; virtual net::URLRequestContextGetter* CreateRequestContext( BrowserContext* browser_context, ProtocolHandlerMap* protocol_handlers, ProtocolHandlerScopedVector protocol_interceptors) OVERRIDE; @@ -70,7 +70,8 @@ class ShellContentBrowserClient : public ContentBrowserClient { BrowserContext* browser_context, const base::FilePath& partition_path, bool in_memory, - ProtocolHandlerMap* protocol_handlers) OVERRIDE; + ProtocolHandlerMap* protocol_handlers, + ProtocolHandlerScopedVector protocol_interceptors) OVERRIDE; virtual void AllowCertificateError( int render_process_id, int render_view_id, diff --git a/src/shell_content_main.cc b/src/shell_content_main.cc index d92b581f5b..68ced4eb4a 100644 --- a/src/shell_content_main.cc +++ b/src/shell_content_main.cc @@ -27,6 +27,9 @@ int ContentMain(int argc, const char** argv) { content::ShellMainDelegate delegate; - return content::ContentMain(argc, argv, &delegate); + content::ContentMainParams params(&delegate); + params.argc = argc; + params.argv = argv; + return content::ContentMain(params); } #endif // OS_MACOSX From 5521a96ffd6bfbd642dd8398f64beef647380f48 Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 8 Jun 2014 22:58:24 +0800 Subject: [PATCH 041/492] [nw10] fix merge --- src/api/dispatcher_bindings.cc | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 52de17ade0..fefa7aedbb 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -473,11 +473,11 @@ void DispatcherBindings::CallStaticMethodSync( std::string destinationHost = *v8::String::Utf8Value(args[4]); bool allowDestinationSubdomains = args[5]->ToBoolean()->Value(); - WebKit::WebSecurityPolicy::addOriginAccessWhitelistEntry(GURL(sourceOrigin), - WebKit::WebString::fromUTF8(destinationProtocol), - WebKit::WebString::fromUTF8(destinationHost), + blink::WebSecurityPolicy::addOriginAccessWhitelistEntry(GURL(sourceOrigin), + blink::WebString::fromUTF8(destinationProtocol), + blink::WebString::fromUTF8(destinationHost), allowDestinationSubdomains); - args.GetReturnValue().Set(v8::Undefined()); + args.GetReturnValue().Set(v8::Undefined(isolate)); return; } if (type == "App" && method == "RemoveOriginAccessWhitelistEntry") { @@ -486,11 +486,11 @@ void DispatcherBindings::CallStaticMethodSync( std::string destinationHost = *v8::String::Utf8Value(args[4]); bool allowDestinationSubdomains = args[5]->ToBoolean()->Value(); - WebKit::WebSecurityPolicy::removeOriginAccessWhitelistEntry(GURL(sourceOrigin), - WebKit::WebString::fromUTF8(destinationProtocol), - WebKit::WebString::fromUTF8(destinationHost), + blink::WebSecurityPolicy::removeOriginAccessWhitelistEntry(GURL(sourceOrigin), + blink::WebString::fromUTF8(destinationProtocol), + blink::WebString::fromUTF8(destinationHost), allowDestinationSubdomains); - args.GetReturnValue().Set(v8::Undefined()); + args.GetReturnValue().Set(v8::Undefined(isolate)); return; } scoped_ptr value_args( From eff1e977c46a77aecb7b789519ba448b3b5ea583 Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 8 Jun 2014 22:58:41 +0800 Subject: [PATCH 042/492] [nw10] disable nwsnapshot for now --- nw.gypi | 4 ++-- tools/package_binaries.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/nw.gypi b/nw.gypi index 5eb2c66f39..881a7c2d91 100644 --- a/nw.gypi +++ b/nw.gypi @@ -624,7 +624,7 @@ { 'action_name': 'strip_nw_binaries', 'inputs': [ - '<(PRODUCT_DIR)/nwsnapshot', +# '<(PRODUCT_DIR)/nwsnapshot', '<(PRODUCT_DIR)/chromedriver', ], 'outputs': [ @@ -636,7 +636,7 @@ }, ], 'dependencies': [ - '<(DEPTH)/v8/tools/gyp/v8.gyp:nwsnapshot', +# '<(DEPTH)/v8/tools/gyp/v8.gyp:nwsnapshot', '<(DEPTH)/chrome/chrome.gyp:chromedriver', ], }], diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 7803683c49..131c334ef0 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -100,7 +100,7 @@ def generate_target_nw(platform_name, arch, version): 'credits.html', 'libffmpegsumo.so', 'nw.pak', - 'nwsnapshot', +# 'nwsnapshot', 'nw', ] elif platform_name == 'win': @@ -113,13 +113,13 @@ def generate_target_nw(platform_name, arch, version): 'nw.pak', 'nw.exp', 'nw.lib', - 'nwsnapshot.exe', +# 'nwsnapshot.exe', 'credits.html', ] elif platform_name == 'osx': target['input'] = [ 'node-webkit.app', - 'nwsnapshot', +# 'nwsnapshot', 'credits.html', ] else: From c7545514bbf520d5b93b78283321f49c203db336 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 9 Jun 2014 16:06:34 +0800 Subject: [PATCH 043/492] [nw10] add icudtl; disable osx dsym dist for now --- tools/package_binaries.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 131c334ef0..3dd3f024da 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -102,6 +102,7 @@ def generate_target_nw(platform_name, arch, version): 'nw.pak', # 'nwsnapshot', 'nw', + 'icudtl.dat', ] elif platform_name == 'win': target['input'] = [ @@ -163,10 +164,10 @@ def generate_target_symbols(platform_name, arch, version): elif platform_name == 'osx': target['compress'] = 'tar.gz' target['input'] = [ - 'node-webkit.app.dSYM', - 'node-webkit Helper.app.dSYM', - 'node-webkit Framework.framework.dSYM', - 'ffmpegsumo.so.dSYM', +# 'node-webkit.app.dSYM', +# 'node-webkit Helper.app.dSYM', +# 'node-webkit Framework.framework.dSYM', +# 'ffmpegsumo.so.dSYM', ] else: print 'Unsupported platform: ' + platform_name From 2c5c3527f32c986dbcc2d934eb66c02f19fdbddc Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 9 Jun 2014 16:07:34 +0800 Subject: [PATCH 044/492] bump version to 0.10.0-pre --- src/mac/app-Info.plist | 2 +- src/nw_version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mac/app-Info.plist b/src/mac/app-Info.plist index be7fbba31c..269b46ee9e 100644 --- a/src/mac/app-Info.plist +++ b/src/mac/app-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.9.2 + 0.10.0 NSPrincipalClass NSApplication LSMinimumSystemVersion diff --git a/src/nw_version.h b/src/nw_version.h index 036c443eaf..ff73d73747 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -22,9 +22,9 @@ #define NW_VERSION_H #define NW_MAJOR_VERSION 0 -#define NW_MINOR_VERSION 9 -#define NW_PATCH_VERSION 2 -#define NW_VERSION_IS_RELEASE 1 +#define NW_MINOR_VERSION 10 +#define NW_PATCH_VERSION 0 +#define NW_VERSION_IS_RELEASE 0 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) From f52ffef437bbab748fa841a21e476c4ec841c124 Mon Sep 17 00:00:00 2001 From: gitchs Date: Mon, 9 Jun 2014 17:17:15 +0800 Subject: [PATCH 045/492] Add app single instance test case --- .../app-single-instance/app/index.html | 22 +++++++++ .../app-single-instance/app/package.json | 5 +++ .../app-single-instance/mocha_test.js | 45 +++++++++++++++++++ 3 files changed, 72 insertions(+) create mode 100644 tests/automatic_tests/app-single-instance/app/index.html create mode 100644 tests/automatic_tests/app-single-instance/app/package.json create mode 100644 tests/automatic_tests/app-single-instance/mocha_test.js diff --git a/tests/automatic_tests/app-single-instance/app/index.html b/tests/automatic_tests/app-single-instance/app/index.html new file mode 100644 index 0000000000..95bbaf1f1f --- /dev/null +++ b/tests/automatic_tests/app-single-instance/app/index.html @@ -0,0 +1,22 @@ + + + + APP Single Instance + + +
    + + + \ No newline at end of file diff --git a/tests/automatic_tests/app-single-instance/app/package.json b/tests/automatic_tests/app-single-instance/app/package.json new file mode 100644 index 0000000000..cb2c05e819 --- /dev/null +++ b/tests/automatic_tests/app-single-instance/app/package.json @@ -0,0 +1,5 @@ +{ + "name":"ASI", + "main":"index.html", + "single-instance":true +} \ No newline at end of file diff --git a/tests/automatic_tests/app-single-instance/mocha_test.js b/tests/automatic_tests/app-single-instance/mocha_test.js new file mode 100644 index 0000000000..d860165136 --- /dev/null +++ b/tests/automatic_tests/app-single-instance/mocha_test.js @@ -0,0 +1,45 @@ +var child_process = require('child_process') +var server = global.server; +var server_port = global.port; +var assert = require('assert'); +var path = require('path'); + +describe('Single Instance APP', function() { + var counter = 0; + var pushData = function(socket) { + socket.on('data', function(data) { + counter += 1; + }) + }; + var runApp = function(path){ + var spawn = child_process.spawn; + var child = spawn(process.execPath,[path,server_port]); + return child; + }; + + before(function(done) { + server.on('connection',pushData); + var app_path = path.join(global.tests_dir,'app-single-instance/app'); + console.log(app_path); + console.log(process.cwd()); + var child1 = runApp(app_path); + var child2 = runApp(app_path); + var child3 = runApp(app_path); + setTimeout(function(){ + child1.kill(); + child2.kill(); + child3.kill(); + done(); + },1000); + }); + + it('app should be single instance', function(done) { + assert.equal(counter,1); + done(); + }); + + after(function(done) { + server.removeListener('connection',pushData); + done(); + }); +}); \ No newline at end of file From f9b6f3f84ac6e1c462d7a0843128fe612aba22c7 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Mon, 9 Jun 2014 22:01:55 +0800 Subject: [PATCH 046/492] [nw10] rebase fix: icudct.dat and force linking all objs in node --- nw.gypi | 2 ++ src/shell_main_delegate.cc | 14 +++++++++----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/nw.gypi b/nw.gypi index 881a7c2d91..34d6256635 100644 --- a/nw.gypi +++ b/nw.gypi @@ -832,6 +832,7 @@ 'mac_bundle': 1, 'mac_bundle_resources': [ 'src/mac/English.lproj/HttpAuth.xib', + '<(PRODUCT_DIR)/icudtl.dat', '<(PRODUCT_DIR)/nw.pak', '<(PRODUCT_DIR)/locale/en-US.pak', '<(PRODUCT_DIR)/locale/am.pak', @@ -897,6 +898,7 @@ 'src/shell_content_main.cc', 'src/shell_content_main.h', ], + 'xcode_settings': { 'OTHER_LDFLAGS': [ '-Wl,-force_load,libnode.a' ], }, 'copies': [ { # Copy FFmpeg binaries for audio/video support. diff --git a/src/shell_main_delegate.cc b/src/shell_main_delegate.cc index 4ffaa4c0c8..eab8324cb7 100644 --- a/src/shell_main_delegate.cc +++ b/src/shell_main_delegate.cc @@ -129,6 +129,15 @@ bool ShellMainDelegate::BasicStartupComplete(int* exit_code) { logging::LogEventProvider::Initialize(kContentShellProviderName); #endif +#if defined(OS_MACOSX) + // Needs to happen before InitializeResourceBundle() and before + // WebKitTestPlatformInitialize() are called. + OverrideFrameworkBundlePath(); + OverrideChildProcessPath(); + // FIXME: EnsureCorrectResolutionSettings(); + l10n_util::OverrideLocaleWithUserDefault(); +#endif // OS_MACOSX + InitLogging(); // FIXME: net::CookieMonster::EnableFileScheme(); @@ -144,11 +153,6 @@ void ShellMainDelegate::PreSandboxStartup() { pref_locale = command_line->GetSwitchValueASCII(switches::kLang); } -#if defined(OS_MACOSX) - OverrideFrameworkBundlePath(); - OverrideChildProcessPath(); - l10n_util::OverrideLocaleWithUserDefault(); -#endif // OS_MACOSX InitializeResourceBundle(pref_locale); std::string process_type = From a3e2ef0b9972d4329c409915800d5c61c06a7722 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 10 Jun 2014 21:15:31 +0800 Subject: [PATCH 047/492] [nw10] fix crash: return object_registry correctly without scope --- src/api/dispatcher.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/api/dispatcher.cc b/src/api/dispatcher.cc index 474a3b4db7..53bd51da90 100644 --- a/src/api/dispatcher.cc +++ b/src/api/dispatcher.cc @@ -115,7 +115,6 @@ void Dispatcher::OnEvent(int object_id, v8::Handle Dispatcher::GetObjectRegistry() { v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::HandleScope scope(isolate); v8::Local context = v8::Local::New(isolate, node::g_context); // need to enter node context to access the registry in @@ -124,6 +123,7 @@ v8::Handle Dispatcher::GetObjectRegistry() { v8::Handle registry = context->Global()->Get(v8_str("__nwObjectsRegistry")); context->Exit(); + ASSERT(!(registry->IsNull() || registry->IsUndefined())); // if (registry->IsNull() || registry->IsUndefined()) // return v8::Undefined(); return registry->ToObject(); @@ -138,6 +138,8 @@ v8::Handle Dispatcher::GetWindowId(blink::WebFrame* frame) { void Dispatcher::ZoomLevelChanged() { v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + blink::WebView* web_view = render_view()->GetWebView(); float zoom_level = web_view->zoomLevel(); @@ -168,6 +170,7 @@ void Dispatcher::DidFinishDocumentLoad(blink::WebFrame* frame) { void Dispatcher::documentCallback(const char* ev, blink::WebFrame* frame) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); blink::WebView* web_view = render_view()->GetWebView(); + v8::HandleScope scope(isolate); if (!web_view) return; From d3b9084fa9fd19cfede1de100f571a023ebaf212 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 11 Jun 2014 21:30:24 +0800 Subject: [PATCH 048/492] debugging friendly embedded scripts --- src/api/dispatcher_bindings.cc | 16 ++++-- src/renderer/shell_content_renderer_client.cc | 49 +++++++++++++------ 2 files changed, 45 insertions(+), 20 deletions(-) diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index fefa7aedbb..7bd6e551cd 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -67,10 +67,18 @@ void RequireFromResource(v8::Handle root, GetStringResource(resource_id))); v8::Handle wrapped_source = WrapSource(source); - v8::Handle script(v8::Script::Compile(wrapped_source, name)); - v8::Handle func = v8::Handle::Cast(script->Run()); - v8::Handle args[] = { root, gui }; - func->Call(root, 2, args); + { + v8::TryCatch try_catch; + v8::Handle script(v8::Script::Compile(wrapped_source, name)); + v8::Handle func = v8::Handle::Cast(script->Run()); + v8::Handle args[] = { root, gui }; + func->Call(root, 2, args); + if (try_catch.HasCaught()) { + v8::String::Utf8Value stack(try_catch.StackTrace()); + LOG(FATAL) << *stack; + } + } + } bool MakePathAbsolute(FilePath* file_path) { diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index f2aec43300..c570ee73c5 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -169,11 +169,12 @@ void ShellContentRendererClient::RenderThreadStarted() { node::SetupContext(argc, argv, context); #if !defined(OS_WIN) - v8::Local script = v8::Script::Compile(v8::String::NewFromUtf8(isolate, ( + v8::Local script = + v8::Script::Compile(v8::String::NewFromUtf8(isolate, ( "process.__nwfds_to_close = [" + base::StringPrintf("%d", base::GlobalDescriptors::GetInstance()->Get(kPrimaryIPCChannel)) + - "];" - ).c_str())); + "];").c_str()), + v8::String::NewFromUtf8(isolate, "nwfds")); CHECK(*script); script->Run(); #endif @@ -362,30 +363,46 @@ void ShellContentRendererClient::InstallNodeSymbols( "if (window.location.href.indexOf('app://') === 0) {process.mainModule.filename = root + '/' + process.mainModule.filename}" "process.mainModule.paths = global.require('module')._nodeModulePaths(process.cwd());" "process.mainModule.loaded = true;" - "}").c_str() - )); + "}").c_str()), + v8::String::NewFromUtf8(isolate, "process_main")); CHECK(*script); script->Run(); } if (use_node || is_nw_protocol) { - v8::Local script = v8::Script::Compile(v8::String::NewFromUtf8(isolate, + v8::Context::Scope cscope(context); + { + v8::TryCatch try_catch; + v8::Local script = v8::Script::Compile(v8::String::NewFromUtf8(isolate, // Overload require - "window.require = function(name) {" - " if (name == 'nw.gui')" - " return nwDispatcher.requireNwGui();" - " return global.require(name);" - "};" + "window.require = function(name) { \n" + " if (name == 'nw.gui') \n" + " return nwDispatcher.requireNwGui(); \n" + " return global.require(name); \n" + "}; \n" // Save node-webkit version "process.versions['node-webkit'] = '" NW_VERSION_STRING "';" "process.versions['chromium'] = '" CHROME_VERSION "';" - )); - script->Run(); - v8::Local script2 = v8::Script::Compile(v8::String::NewFromUtf8(isolate, + )); + script->Run(); + if (try_catch.HasCaught()) { + v8::Handle message = try_catch.Message(); + LOG(FATAL) << *v8::String::Utf8Value(message->Get()); + } + } + { + v8::TryCatch try_catch; + v8::Local script2 = v8::Script::Compile(v8::String::NewFromUtf8(isolate, " nwDispatcher.requireNwGui().Window.get();" - )); - script2->Run(); + ), + v8::String::NewFromUtf8(isolate, "initial_require")); + script2->Run(); + if (try_catch.HasCaught()) { + v8::Handle message = try_catch.Message(); + LOG(FATAL) << *v8::String::Utf8Value(message->Get()); + } + } } else { int ret; RenderViewImpl* render_view = RenderViewImpl::FromWebView(frame->view()); From c4c7113b569f4ab800c2c140e01102ef20179d73 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 11 Jun 2014 21:31:07 +0800 Subject: [PATCH 049/492] Enter Node context in RequireNwGui --- src/api/dispatcher_bindings.cc | 8 ++++++++ src/renderer/shell_content_renderer_client.cc | 5 ++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 7bd6e551cd..77893d23ee 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -33,6 +33,9 @@ #include "content/public/renderer/render_thread.h" #include "content/public/renderer/v8_value_converter.h" #include "grit/nw_resources.h" +#include "third_party/node/src/node.h" +#include "third_party/node/src/node_internals.h" +#include "third_party/node/src/req_wrap.h" #include "third_party/WebKit/public/web/WebSecurityPolicy.h" #include "url/gurl.h" @@ -170,6 +173,10 @@ DispatcherBindings::RequireNwGui(const v8::FunctionCallbackInfo& args return; } + v8::Local g_context = + v8::Local::New(isolate, node::g_context); + + g_context->Enter(); v8::Local NwGui = v8::Object::New(isolate); args.This()->Set(NwGuiSymbol, NwGui); RequireFromResource(args.This(), @@ -189,6 +196,7 @@ DispatcherBindings::RequireNwGui(const v8::FunctionCallbackInfo& args RequireFromResource(args.This(), NwGui, v8::String::NewFromUtf8(isolate, "app.js"), IDR_NW_API_APP_JS); + g_context->Exit(); args.GetReturnValue().Set(handle_scope.Escape(NwGui)); } diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index c570ee73c5..2349c21aa0 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -321,10 +321,13 @@ void ShellContentRendererClient::InstallNodeSymbols( symbols->Set(2, v8::String::NewFromUtf8(isolate, "Buffer")); symbols->Set(3, v8::String::NewFromUtf8(isolate, "root")); + g_context->Enter(); for (unsigned i = 0; i < symbols->Length(); ++i) { v8::Local key = symbols->Get(i); - v8Global->Set(key, nodeGlobal->Get(key)); + v8::Local val = nodeGlobal->Get(key); + v8Global->Set(key, val); } + g_context->Exit(); if (!installed_once) { installed_once = true; From 2380387a07c981e0eca9c4544a9f37f40fe97994 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 11 Jun 2014 22:22:55 +0800 Subject: [PATCH 050/492] fix release build --- src/api/dispatcher_bindings.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 77893d23ee..b3738b4d7a 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -34,6 +34,7 @@ #include "content/public/renderer/v8_value_converter.h" #include "grit/nw_resources.h" #include "third_party/node/src/node.h" +#undef CHECK #include "third_party/node/src/node_internals.h" #include "third_party/node/src/req_wrap.h" #include "third_party/WebKit/public/web/WebSecurityPolicy.h" From e243822e384e4cfe0144f09f4d17e49689b6b977 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 13 Jun 2014 08:38:26 +0800 Subject: [PATCH 051/492] use correct dispatcher host to receive and send messages --- src/api/dispatcher_host.cc | 8 ++++++-- src/api/dispatcher_host.h | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/api/dispatcher_host.cc b/src/api/dispatcher_host.cc index 9bd3d33a3b..39a7e4f1f9 100644 --- a/src/api/dispatcher_host.cc +++ b/src/api/dispatcher_host.cc @@ -38,6 +38,7 @@ #include "content/nw/src/shell_browser_context.h" #include "content/nw/src/nw_shell.h" #include "content/public/browser/render_process_host.h" +#include "content/public/browser/render_view_host.h" using content::WebContents; using content::ShellBrowserContext; @@ -94,10 +95,13 @@ void DispatcherHost::SendEvent(Base* object, } bool DispatcherHost::Send(IPC::Message* message) { - return content::WebContentsObserver::Send(message); + return render_view_host_->Send(message); } -bool DispatcherHost::OnMessageReceived(const IPC::Message& message) { +bool DispatcherHost::OnMessageReceived(content::RenderViewHost* render_view_host, + const IPC::Message& message) { + if (render_view_host != render_view_host_) + return false; bool handled = true; base::ThreadRestrictions::ScopedAllowIO allow_io; base::ThreadRestrictions::ScopedAllowWait allow_wait; diff --git a/src/api/dispatcher_host.h b/src/api/dispatcher_host.h index 2c904de25f..2df23476a6 100644 --- a/src/api/dispatcher_host.h +++ b/src/api/dispatcher_host.h @@ -89,7 +89,7 @@ class DispatcherHost : public content::WebContentsObserver { // RenderViewHostObserver implementation. // WebContentsObserver implementation: - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual bool OnMessageReceived(content::RenderViewHost* render_view_host, const IPC::Message& message) OVERRIDE; void OnAllocateObject(int object_id, const std::string& type, From 20f2ad70b65273cddbbdb8cf78950f1cb540208d Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 13 Jun 2014 09:31:15 +0800 Subject: [PATCH 052/492] passing window object to API JS API JS is now executing from Node context so window ref is needed --- src/api/dispatcher_bindings.cc | 26 +++++++++++++++----------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index b3738b4d7a..358a633705 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -52,7 +52,7 @@ v8::Handle WrapSource(v8::Handle source) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::EscapableHandleScope handle_scope(isolate); v8::Handle left = - v8::String::NewFromUtf8(isolate, "(function(nw, exports) {"); + v8::String::NewFromUtf8(isolate, "(function(nw, exports, window) {"); v8::Handle right = v8::String::NewFromUtf8(isolate, "\n})"); return handle_scope.Escape( v8::String::Concat(left, v8::String::Concat(source, right))); @@ -61,6 +61,7 @@ v8::Handle WrapSource(v8::Handle source) { // Similar to node's `require` function, save functions in `exports`. void RequireFromResource(v8::Handle root, v8::Handle gui, + v8::Handle window, v8::Handle name, int resource_id) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); @@ -75,8 +76,8 @@ void RequireFromResource(v8::Handle root, v8::TryCatch try_catch; v8::Handle script(v8::Script::Compile(wrapped_source, name)); v8::Handle func = v8::Handle::Cast(script->Run()); - v8::Handle args[] = { root, gui }; - func->Call(root, 2, args); + v8::Handle args[] = { root, gui, window }; + func->Call(root, 3, args); if (try_catch.HasCaught()) { v8::String::Utf8Value stack(try_catch.StackTrace()); LOG(FATAL) << *stack; @@ -174,6 +175,9 @@ DispatcherBindings::RequireNwGui(const v8::FunctionCallbackInfo& args return; } + v8::Local context = isolate->GetEnteredContext(); + v8::Local global = context->Global(); + ASSERT(!global->IsUndefined()); v8::Local g_context = v8::Local::New(isolate, node::g_context); @@ -181,21 +185,21 @@ DispatcherBindings::RequireNwGui(const v8::FunctionCallbackInfo& args v8::Local NwGui = v8::Object::New(isolate); args.This()->Set(NwGuiSymbol, NwGui); RequireFromResource(args.This(), - NwGui, v8::String::NewFromUtf8(isolate, "base.js"), IDR_NW_API_BASE_JS); + NwGui, global, v8::String::NewFromUtf8(isolate, "base.js"), IDR_NW_API_BASE_JS); RequireFromResource(args.This(), - NwGui, v8::String::NewFromUtf8(isolate, "menuitem.js"), IDR_NW_API_MENUITEM_JS); + NwGui, global, v8::String::NewFromUtf8(isolate, "menuitem.js"), IDR_NW_API_MENUITEM_JS); RequireFromResource(args.This(), - NwGui, v8::String::NewFromUtf8(isolate, "menu.js"), IDR_NW_API_MENU_JS); + NwGui, global, v8::String::NewFromUtf8(isolate, "menu.js"), IDR_NW_API_MENU_JS); RequireFromResource(args.This(), - NwGui, v8::String::NewFromUtf8(isolate, "tray.js"), IDR_NW_API_TRAY_JS); + NwGui, global, v8::String::NewFromUtf8(isolate, "tray.js"), IDR_NW_API_TRAY_JS); RequireFromResource(args.This(), - NwGui, v8::String::NewFromUtf8(isolate, "clipboard.js"), IDR_NW_API_CLIPBOARD_JS); + NwGui, global, v8::String::NewFromUtf8(isolate, "clipboard.js"), IDR_NW_API_CLIPBOARD_JS); RequireFromResource(args.This(), - NwGui, v8::String::NewFromUtf8(isolate, "window.js"), IDR_NW_API_WINDOW_JS); + NwGui, global, v8::String::NewFromUtf8(isolate, "window.js"), IDR_NW_API_WINDOW_JS); RequireFromResource(args.This(), - NwGui, v8::String::NewFromUtf8(isolate, "shell.js"), IDR_NW_API_SHELL_JS); + NwGui, global, v8::String::NewFromUtf8(isolate, "shell.js"), IDR_NW_API_SHELL_JS); RequireFromResource(args.This(), - NwGui, v8::String::NewFromUtf8(isolate, "app.js"), IDR_NW_API_APP_JS); + NwGui, global, v8::String::NewFromUtf8(isolate, "app.js"), IDR_NW_API_APP_JS); g_context->Exit(); args.GetReturnValue().Set(handle_scope.Escape(NwGui)); From caced490f1933c95069c5d2a6a8a553b8fdbbaec Mon Sep 17 00:00:00 2001 From: Jefry Date: Wed, 4 Jun 2014 15:56:34 +0800 Subject: [PATCH 053/492] [WIN] implement the SetBadgeLabel for windows --- src/browser/native_window_win.cc | 51 +++++++++++++++++++++++++++++++- 1 file changed, 50 insertions(+), 1 deletion(-) diff --git a/src/browser/native_window_win.cc b/src/browser/native_window_win.cc index f0b2b40290..4ca6d2bb6a 100644 --- a/src/browser/native_window_win.cc +++ b/src/browser/native_window_win.cc @@ -43,6 +43,10 @@ #include "ui/gfx/native_widget_types.h" #include "ui/gfx/win/hwnd_util.h" #include "ui/gfx/path.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/icon_util.h" +#include "ui/gfx/font_list.h" +#include "ui/gfx/platform_font.h" #include "ui/gfx/image/image_skia_operations.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/layout/box_layout.h" @@ -470,8 +474,53 @@ void NativeWindowWin::FlashFrame(bool flash) { window_->FlashFrame(flash); } +HICON createBadgeIcon(const HWND hWnd, const TCHAR *value, const int sizeX, const int sizeY) { + // canvas for the overlay icon + gfx::Canvas canvas(gfx::Size(sizeX, sizeY), 1, false); + + // drawing red circle + SkPaint paint; + paint.setColor(SK_ColorRED); + canvas.DrawCircle(gfx::Point(sizeX/2, sizeY/2), sizeX/2, paint); + + // drawing the text + gfx::PlatformFont *platform_font = gfx::PlatformFont::CreateDefault(); + const int fontSize = sizeY*0.65f; + gfx::Font font(platform_font->GetFontName(), fontSize); + platform_font->Release(); + platform_font = NULL; + const int yMargin = (sizeY - fontSize) / 2; + canvas.DrawStringRectWithFlags(value, gfx::FontList(font), SK_ColorWHITE, gfx::Rect(sizeX, fontSize+yMargin+1), gfx::Canvas::TEXT_ALIGN_CENTER); + + // return the canvas as windows native icon handle + return IconUtil::CreateHICONFromSkBitmap(canvas.ExtractImageRep().sk_bitmap()); +} + void NativeWindowWin::SetBadgeLabel(const std::string& badge) { - // TODO + base::win::ScopedComPtr taskbar; + HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, + CLSCTX_INPROC_SERVER); + + if (FAILED(result)) { + VLOG(1) << "Failed creating a TaskbarList3 object: " << result; + return; + } + + result = taskbar->HrInit(); + if (FAILED(result)) { + LOG(ERROR) << "Failed initializing an ITaskbarList3 interface."; + return; + } + + HICON icon = NULL; + HWND hWnd = window_->GetNativeWindow(); + if (badge.size()) + icon = createBadgeIcon(hWnd, UTF8ToUTF16(badge).c_str(), 32, 32); + + taskbar->SetOverlayIcon(hWnd, icon, _T("Status")); + DestroyIcon(icon); + + } void NativeWindowWin::SetKiosk(bool kiosk) { From 1213d7360d5eec9bacbe74cfea15daa507848553 Mon Sep 17 00:00:00 2001 From: Jefry Date: Fri, 13 Jun 2014 10:16:24 +0800 Subject: [PATCH 054/492] [WIN] badge feature, fix the indentation, add my name to Authors --- AUTHORS | 1 + src/browser/native_window_win.cc | 74 ++++++++++++++++---------------- 2 files changed, 37 insertions(+), 38 deletions(-) diff --git a/AUTHORS b/AUTHORS index 5f3166c6a4..c34ff377b7 100644 --- a/AUTHORS +++ b/AUTHORS @@ -25,3 +25,4 @@ Fabrice Weinberg Lv Kaiyang Lukas Benes Lithare Emileit +Jefry Tedjokusumo \ No newline at end of file diff --git a/src/browser/native_window_win.cc b/src/browser/native_window_win.cc index 4ca6d2bb6a..8f9d5a06ab 100644 --- a/src/browser/native_window_win.cc +++ b/src/browser/native_window_win.cc @@ -475,52 +475,50 @@ void NativeWindowWin::FlashFrame(bool flash) { } HICON createBadgeIcon(const HWND hWnd, const TCHAR *value, const int sizeX, const int sizeY) { - // canvas for the overlay icon - gfx::Canvas canvas(gfx::Size(sizeX, sizeY), 1, false); + // canvas for the overlay icon + gfx::Canvas canvas(gfx::Size(sizeX, sizeY), 1, false); - // drawing red circle - SkPaint paint; - paint.setColor(SK_ColorRED); - canvas.DrawCircle(gfx::Point(sizeX/2, sizeY/2), sizeX/2, paint); + // drawing red circle + SkPaint paint; + paint.setColor(SK_ColorRED); + canvas.DrawCircle(gfx::Point(sizeX / 2, sizeY / 2), sizeX / 2, paint); - // drawing the text - gfx::PlatformFont *platform_font = gfx::PlatformFont::CreateDefault(); - const int fontSize = sizeY*0.65f; - gfx::Font font(platform_font->GetFontName(), fontSize); - platform_font->Release(); - platform_font = NULL; - const int yMargin = (sizeY - fontSize) / 2; - canvas.DrawStringRectWithFlags(value, gfx::FontList(font), SK_ColorWHITE, gfx::Rect(sizeX, fontSize+yMargin+1), gfx::Canvas::TEXT_ALIGN_CENTER); + // drawing the text + gfx::PlatformFont *platform_font = gfx::PlatformFont::CreateDefault(); + const int fontSize = sizeY*0.65f; + gfx::Font font(platform_font->GetFontName(), fontSize); + platform_font->Release(); + platform_font = NULL; + const int yMargin = (sizeY - fontSize) / 2; + canvas.DrawStringRectWithFlags(value, gfx::FontList(font), SK_ColorWHITE, gfx::Rect(sizeX, fontSize + yMargin + 1), gfx::Canvas::TEXT_ALIGN_CENTER); - // return the canvas as windows native icon handle - return IconUtil::CreateHICONFromSkBitmap(canvas.ExtractImageRep().sk_bitmap()); + // return the canvas as windows native icon handle + return IconUtil::CreateHICONFromSkBitmap(canvas.ExtractImageRep().sk_bitmap()); } void NativeWindowWin::SetBadgeLabel(const std::string& badge) { - base::win::ScopedComPtr taskbar; - HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, - CLSCTX_INPROC_SERVER); - - if (FAILED(result)) { - VLOG(1) << "Failed creating a TaskbarList3 object: " << result; - return; - } - - result = taskbar->HrInit(); - if (FAILED(result)) { - LOG(ERROR) << "Failed initializing an ITaskbarList3 interface."; - return; - } - - HICON icon = NULL; - HWND hWnd = window_->GetNativeWindow(); - if (badge.size()) - icon = createBadgeIcon(hWnd, UTF8ToUTF16(badge).c_str(), 32, 32); - - taskbar->SetOverlayIcon(hWnd, icon, _T("Status")); - DestroyIcon(icon); + base::win::ScopedComPtr taskbar; + HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, + CLSCTX_INPROC_SERVER); + + if (FAILED(result)) { + VLOG(1) << "Failed creating a TaskbarList3 object: " << result; + return; + } + + result = taskbar->HrInit(); + if (FAILED(result)) { + LOG(ERROR) << "Failed initializing an ITaskbarList3 interface."; + return; + } + HICON icon = NULL; + HWND hWnd = window_->GetNativeWindow(); + if (badge.size()) + icon = createBadgeIcon(hWnd, UTF8ToUTF16(badge).c_str(), 32, 32); + taskbar->SetOverlayIcon(hWnd, icon, _T("Status")); + DestroyIcon(icon); } void NativeWindowWin::SetKiosk(bool kiosk) { From c3477922c8bcb9cbb7ab0f90063a599749d09e6b Mon Sep 17 00:00:00 2001 From: libm Date: Mon, 16 Jun 2014 11:56:01 +0800 Subject: [PATCH 055/492] Added a switch to skip one specified step --- tools/package_binaries.py | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 3dd3f024da..9720a728f7 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -10,11 +10,14 @@ import tarfile import zipfile +steps = ['nw', 'chromedriver', 'symbol'] ################################ # Parse command line args parser = argparse.ArgumentParser(description='Package nw binaries.') parser.add_argument('-p','--path', help='Where to find the binaries, like out/Release', required=False) -parser.add_argument('-s','--step', help='Execute specified step. (could be "nw", "chromedriver" or "symbol")', required=False) +group = parser.add_mutually_exclusive_group() +group.add_argument('-s','--step', choices=steps, help='Execute specified step.', required=False) +group.add_argument('-n','--skip', choices=steps, help='Skip specified step.', required=False) args = parser.parse_args() ################################ @@ -23,10 +26,12 @@ platform_name = None # win/linux/osx arch = None # ia32/x64 step = None # nw/chromedriver/symbol +skip = None nw_ver = None # x.xx dist_dir = None # .../out/Release/dist step = args.step +skip = args.skip binaries_location = args.path # If the binaries location is not given, calculate it from script related dir. if binaries_location == None: @@ -253,20 +258,20 @@ def make_packages(targets): # single file compress(binaries_location, dist_dir, t['input'][0], t['compress']) - +# must be aligned with steps +generators = {} +generators['nw'] = generate_target_nw +generators['chromedriver'] = generate_target_chromedriver +generators['symbol'] = generate_target_symbols ################################ # Process targets targets = [] -if step == 'nw': - targets.append(generate_target_nw(platform_name, arch, nw_ver)) -elif step == 'chromedriver': - targets.append(generate_target_chromedriver(platform_name, arch, nw_ver)) -elif step == 'symbol': - targets.append(generate_target_symbols(platform_name, arch, nw_ver)) -else: - targets.append(generate_target_nw(platform_name, arch, nw_ver)) - targets.append(generate_target_chromedriver(platform_name, arch, nw_ver)) - targets.append(generate_target_symbols(platform_name, arch, nw_ver)) +for s in steps: + if (step != None) and (s != step): + continue + if (skip != None) and (s == skip): + continue + targets.append(generators[s](platform_name, arch, nw_ver)) print 'Creating packages...' make_packages(targets) From 2ccd9f82691d8286dc7a68934245415688ba1953 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 18 Jun 2014 10:04:41 +0800 Subject: [PATCH 056/492] update upstream version to 35 --- src/nw_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nw_version.h b/src/nw_version.h index ff73d73747..370d613f86 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -43,7 +43,7 @@ #define NW_VERSION "v" NW_VERSION_STRING -#define CHROME_VERSION "32.0.1700.107" +#define CHROME_VERSION "35.0.1916.113" #define NW_VERSION_AT_LEAST(major, minor, patch) \ (( (major) < NW_MAJOR_VERSION) \ From 99e94314ba6bf13828cddea3fc7986c299fc7337 Mon Sep 17 00:00:00 2001 From: Kevin Fan Date: Sun, 15 Jun 2014 07:05:42 +0800 Subject: [PATCH 057/492] rebase fix for windows; build ok --- nw.gypi | 16 +- src/api/clipboard/clipboard.cc | 2 +- src/api/menu/menu_delegate_win.cc | 2 +- src/api/menu/menu_delegate_win.h | 2 +- src/api/menu/menu_win.cc | 2 +- src/api/menuitem/menuitem.h | 4 +- src/api/menuitem/menuitem_win.cc | 6 +- src/api/tray/tray_win.cc | 2 +- src/breakpad_win.cc | 10 +- src/browser/autofill_popup_base_view.cc | 282 ++++++++++++++++++ src/browser/autofill_popup_base_view.h | 98 ++++++ src/browser/autofill_popup_view_views.cc | 141 +++++++++ src/browser/autofill_popup_view_views.h | 49 +++ src/browser/color_chooser_dialog.cc | 8 +- src/browser/file_select_helper.cc | 4 +- src/browser/native_window_toolbar_win.cc | 10 +- src/browser/native_window_toolbar_win.h | 2 +- src/browser/native_window_win.cc | 33 +- src/browser/native_window_win.h | 2 +- src/browser/printing/print_view_manager.cc | 2 +- src/browser/shell_devtools_delegate.cc | 2 +- .../shell_download_manager_delegate_win.cc | 2 +- src/browser/shell_javascript_dialog_win.cc | 8 +- src/browser/shell_login_dialog.h | 5 + src/browser/shell_login_dialog_win.cc | 6 +- src/chrome_breakpad_client.cc | 8 +- src/hard_error_handler_win.cc | 2 +- src/nw_package.cc | 5 +- src/nw_shell.cc | 2 +- .../printing/print_web_view_helper_win.cc | 2 +- src/shell.rc | 2 +- src/shell_browser_main_parts.cc | 2 +- src/shell_main.cc | 8 +- 33 files changed, 657 insertions(+), 74 deletions(-) create mode 100644 src/browser/autofill_popup_base_view.cc create mode 100644 src/browser/autofill_popup_base_view.h create mode 100644 src/browser/autofill_popup_view_views.cc create mode 100644 src/browser/autofill_popup_view_views.h diff --git a/nw.gypi b/nw.gypi index 34d6256635..0a26e2bf80 100644 --- a/nw.gypi +++ b/nw.gypi @@ -166,12 +166,16 @@ 'src/api/window/window.h', 'src/browser/app_controller_mac.h', 'src/browser/app_controller_mac.mm', + 'src/browser/autofill_popup_base_view.cc', + 'src/browser/autofill_popup_base_view.h', 'src/browser/autofill_popup_view_gtk.cc', 'src/browser/autofill_popup_view_gtk.h', 'src/browser/autofill_popup_view_cocoa.h', 'src/browser/autofill_popup_view_cocoa.mm', 'src/browser/autofill_popup_view_bridge.h', 'src/browser/autofill_popup_view_bridge.mm', + 'src/browser/autofill_popup_view_views.cc', + 'src/browser/autofill_popup_view_views.h', 'src/browser/autofill_popup_controller_impl.cc', 'src/browser/autofill_popup_controller_impl.h', 'src/browser/tab_autofill_manager_delegate.cc', @@ -236,7 +240,7 @@ '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', + #FIXME 'src/browser/shell_login_dialog_win.cc', 'src/browser/shell_login_dialog.cc', 'src/browser/shell_login_dialog.h', 'src/browser/shell_resource_dispatcher_host_delegate.cc', @@ -708,11 +712,11 @@ 'VCLinkerTool': { 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS }, - 'VCManifestTool': { - 'AdditionalManifestFiles': [ - '$(ProjectDir)\\nw\\src\\nw.exe.manifest', - ], - }, + #'VCManifestTool': { + # 'AdditionalManifestFiles': [ + # '$(ProjectDir)\\nw\\src\\nw.exe.manifest', + # ], + # }, }, 'conditions': [ ['OS=="win" and win_use_allocator_shim==1', { diff --git a/src/api/clipboard/clipboard.cc b/src/api/clipboard/clipboard.cc index 1102bbe0b3..399d13616c 100644 --- a/src/api/clipboard/clipboard.cc +++ b/src/api/clipboard/clipboard.cc @@ -75,7 +75,7 @@ std::string Clipboard::GetText() { ui::Clipboard* clipboard = ui::Clipboard::GetForCurrentThread(); base::string16 text; clipboard->ReadText(ui::CLIPBOARD_TYPE_COPY_PASTE, &text); - return UTF16ToUTF8(text); + return base::UTF16ToUTF8(text); } void Clipboard::Clear() { diff --git a/src/api/menu/menu_delegate_win.cc b/src/api/menu/menu_delegate_win.cc index 7718deb93a..37941590df 100644 --- a/src/api/menu/menu_delegate_win.cc +++ b/src/api/menu/menu_delegate_win.cc @@ -62,7 +62,7 @@ bool MenuDelegate::IsItemForCommandIdDynamic(int command_id) const { return item->is_modified_; } -string16 MenuDelegate::GetLabelForCommandId(int command_id) const { +base::string16 MenuDelegate::GetLabelForCommandId(int command_id) const { MenuItem* item = dispatcher_host_->GetApiObject(command_id); return item->label_; } diff --git a/src/api/menu/menu_delegate_win.h b/src/api/menu/menu_delegate_win.h index 80ac9d03bf..bda6a80075 100644 --- a/src/api/menu/menu_delegate_win.h +++ b/src/api/menu/menu_delegate_win.h @@ -40,7 +40,7 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate { ui::Accelerator* accelerator) { return false; } virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE; - virtual string16 GetLabelForCommandId(int command_id) const OVERRIDE; + virtual base::string16 GetLabelForCommandId(int command_id) const OVERRIDE; virtual bool GetIconForCommandId(int command_id, gfx::Image* icon) const OVERRIDE; diff --git a/src/api/menu/menu_win.cc b/src/api/menu/menu_win.cc index 976b3f0bd3..508ba61c84 100644 --- a/src/api/menu/menu_win.cc +++ b/src/api/menu/menu_win.cc @@ -131,7 +131,7 @@ void Menu::Insert(MenuItem* menu_item, int pos) { } void Menu::Remove(MenuItem* menu_item, int pos) { - menu_model_->RemoveAt(pos); + menu_model_->RemoveItemAt(pos); is_menu_modified_ = true; } diff --git a/src/api/menuitem/menuitem.h b/src/api/menuitem/menuitem.h index 8754361421..4225c744c2 100644 --- a/src/api/menuitem/menuitem.h +++ b/src/api/menuitem/menuitem.h @@ -145,8 +145,8 @@ class MenuItem : public Base { bool is_enabled_; gfx::Image icon_; std::string type_; - string16 label_; - string16 tooltip_; + base::string16 label_; + base::string16 tooltip_; Menu* submenu_; bool enable_shortcut_; diff --git a/src/api/menuitem/menuitem_win.cc b/src/api/menuitem/menuitem_win.cc index f212e8f37c..9fac6a48ce 100644 --- a/src/api/menuitem/menuitem_win.cc +++ b/src/api/menuitem/menuitem_win.cc @@ -112,7 +112,7 @@ void MenuItem::OnClick() { void MenuItem::SetLabel(const std::string& label) { is_modified_ = true; - label_ = UTF8ToUTF16(label); + label_ = base::UTF8ToUTF16(label); } void MenuItem::SetIcon(const std::string& icon) { @@ -129,7 +129,7 @@ void MenuItem::SetIcon(const std::string& icon) { } void MenuItem::SetTooltip(const std::string& tooltip) { - tooltip_ = UTF8ToUTF16(tooltip); + tooltip_ = base::UTF8ToUTF16(tooltip); } void MenuItem::SetEnabled(bool enabled) { @@ -253,4 +253,4 @@ ui::KeyboardCode GetKeycodeFromText(std::string text){ } } return retval; -} \ No newline at end of file +} diff --git a/src/api/tray/tray_win.cc b/src/api/tray/tray_win.cc index 7fb61b6b46..a90e65bb83 100644 --- a/src/api/tray/tray_win.cc +++ b/src/api/tray/tray_win.cc @@ -87,7 +87,7 @@ void Tray::SetIcon(const std::string& path) { } void Tray::SetTooltip(const std::string& tooltip) { - status_icon_->SetToolTip(UTF8ToUTF16(tooltip)); + status_icon_->SetToolTip(base::UTF8ToUTF16(tooltip)); } void Tray::SetMenu(Menu* menu) { diff --git a/src/breakpad_win.cc b/src/breakpad_win.cc index 9405704764..88c15f5d31 100644 --- a/src/breakpad_win.cc +++ b/src/breakpad_win.cc @@ -269,9 +269,9 @@ google_breakpad::CustomClientInfo* GetCustomInfo(const std::wstring& exe_path, // Common g_custom_entries. g_custom_entries->push_back( - google_breakpad::CustomInfoEntry(L"ver", UTF16ToWide(version).c_str())); + google_breakpad::CustomInfoEntry(L"ver", base::UTF16ToWide(version).c_str())); g_custom_entries->push_back( - google_breakpad::CustomInfoEntry(L"prod", UTF16ToWide(product).c_str())); + google_breakpad::CustomInfoEntry(L"prod", base::UTF16ToWide(product).c_str())); g_custom_entries->push_back( google_breakpad::CustomInfoEntry(L"plat", L"Win32")); g_custom_entries->push_back( @@ -287,7 +287,7 @@ google_breakpad::CustomClientInfo* GetCustomInfo(const std::wstring& exe_path, if (!special_build.empty()) g_custom_entries->push_back(google_breakpad::CustomInfoEntry( - L"special", UTF16ToWide(special_build).c_str())); + L"special", base::UTF16ToWide(special_build).c_str())); if (type == L"plugin" || type == L"ppapi") { std::wstring plugin_path = @@ -659,7 +659,7 @@ static void InitPipeNameEnvVar(bool is_per_user_install) { pipe_name = kGoogleUpdatePipeName; pipe_name += user_sid; } - env->SetVar(kPipeNameVar, WideToASCII(pipe_name)); + env->SetVar(kPipeNameVar, base::UTF16ToASCII(pipe_name)); } void InitDefaultCrashCallback(LPTOP_LEVEL_EXCEPTION_FILTER filter) { @@ -717,7 +717,7 @@ void InitCrashReporter() { InitDefaultCrashCallback(default_filter); return; } - std::wstring pipe_name = ASCIIToWide(pipe_name_ascii); + std::wstring pipe_name = base::ASCIIToWide(pipe_name_ascii); #ifdef _WIN64 // The protocol for connecting to the out-of-process Breakpad crash diff --git a/src/browser/autofill_popup_base_view.cc b/src/browser/autofill_popup_base_view.cc new file mode 100644 index 0000000000..ef87bcb065 --- /dev/null +++ b/src/browser/autofill_popup_base_view.cc @@ -0,0 +1,282 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/autofill_popup_base_view.h" + +#include "base/bind.h" +#include "base/location.h" +#include "base/message_loop/message_loop.h" +#include "chrome/browser/ui/autofill/popup_constants.h" +#include "ui/gfx/point.h" +#include "ui/gfx/screen.h" +#include "ui/views/border.h" +#include "ui/views/event_utils.h" +#include "ui/views/widget/widget.h" + +#if defined(USE_AURA) +#include "ui/wm/core/window_animations.h" +#endif + +namespace autofill { + +const SkColor AutofillPopupBaseView::kBorderColor = + SkColorSetARGB(0xFF, 0xC7, 0xCA, 0xCE); +const SkColor AutofillPopupBaseView::kHoveredBackgroundColor = + SkColorSetARGB(0xFF, 0xCD, 0xCD, 0xCD); +const SkColor AutofillPopupBaseView::kItemTextColor = + SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F); +const SkColor AutofillPopupBaseView::kPopupBackground = + SkColorSetARGB(0xFF, 0xFF, 0xFF, 0xFF); +const SkColor AutofillPopupBaseView::kValueTextColor = + SkColorSetARGB(0xFF, 0x00, 0x00, 0x00); +const SkColor AutofillPopupBaseView::kWarningTextColor = + SkColorSetARGB(0xFF, 0x7F, 0x7F, 0x7F); + +AutofillPopupBaseView::AutofillPopupBaseView( + AutofillPopupViewDelegate* delegate, + views::Widget* observing_widget) + : delegate_(delegate), + observing_widget_(observing_widget), + weak_ptr_factory_(this) {} + +AutofillPopupBaseView::~AutofillPopupBaseView() { + if (delegate_) { + delegate_->ViewDestroyed(); + + RemoveObserver(); + } +} + +void AutofillPopupBaseView::DoShow() { + if (!GetWidget()) { + observing_widget_->AddObserver(this); + + views::FocusManager* focus_manager = observing_widget_->GetFocusManager(); + focus_manager->RegisterAccelerator( + ui::Accelerator(ui::VKEY_RETURN, ui::EF_NONE), + ui::AcceleratorManager::kNormalPriority, + this); + focus_manager->RegisterAccelerator( + ui::Accelerator(ui::VKEY_ESCAPE, ui::EF_NONE), + ui::AcceleratorManager::kNormalPriority, + this); + + // The widget is destroyed by the corresponding NativeWidget, so we use + // a weak pointer to hold the reference and don't have to worry about + // deletion. + views::Widget* widget = new views::Widget; + views::Widget::InitParams params(views::Widget::InitParams::TYPE_POPUP); + params.delegate = this; + params.parent = container_view(); + widget->Init(params); + widget->SetContentsView(this); +#if defined(USE_AURA) + // No animation for popup appearance (too distracting). + wm::SetWindowVisibilityAnimationTransition( + widget->GetNativeView(), wm::ANIMATE_HIDE); +#endif + } + + SetBorder(views::Border::CreateSolidBorder(kPopupBorderThickness, + kBorderColor)); + + DoUpdateBoundsAndRedrawPopup(); + GetWidget()->Show(); + + if (ShouldHideOnOutsideClick()) + GetWidget()->SetCapture(this); +} + +void AutofillPopupBaseView::DoHide() { + // The controller is no longer valid after it hides us. + delegate_ = NULL; + + RemoveObserver(); + + if (GetWidget()) { + // Don't call CloseNow() because some of the functions higher up the stack + // assume the the widget is still valid after this point. + // http://crbug.com/229224 + // NOTE: This deletes |this|. + GetWidget()->Close(); + } else { + delete this; + } +} + +void AutofillPopupBaseView::RemoveObserver() { + observing_widget_->GetFocusManager()->UnregisterAccelerators(this); + observing_widget_->RemoveObserver(this); +} + +void AutofillPopupBaseView::DoUpdateBoundsAndRedrawPopup() { + GetWidget()->SetBounds(delegate_->popup_bounds()); + SchedulePaint(); +} + +void AutofillPopupBaseView::OnWidgetBoundsChanged(views::Widget* widget, + const gfx::Rect& new_bounds) { + DCHECK_EQ(widget, observing_widget_); + HideController(); +} + +void AutofillPopupBaseView::OnMouseCaptureLost() { + ClearSelection(); +} + +bool AutofillPopupBaseView::OnMouseDragged(const ui::MouseEvent& event) { + if (HitTestPoint(event.location())) { + SetSelection(event.location()); + + // We must return true in order to get future OnMouseDragged and + // OnMouseReleased events. + return true; + } + + // If we move off of the popup, we lose the selection. + ClearSelection(); + return false; +} + +void AutofillPopupBaseView::OnMouseExited(const ui::MouseEvent& event) { + // Pressing return causes the cursor to hide, which will generate an + // OnMouseExited event. Pressing return should activate the current selection + // via AcceleratorPressed, so we need to let that run first. + base::MessageLoop::current()->PostTask( + FROM_HERE, + base::Bind(&AutofillPopupBaseView::ClearSelection, + weak_ptr_factory_.GetWeakPtr())); +} + +void AutofillPopupBaseView::OnMouseMoved(const ui::MouseEvent& event) { + if (HitTestPoint(event.location())) + SetSelection(event.location()); + else + ClearSelection(); +} + +bool AutofillPopupBaseView::OnMousePressed(const ui::MouseEvent& event) { + if (HitTestPoint(event.location())) + return true; + + if (ShouldHideOnOutsideClick()) { + GetWidget()->ReleaseCapture(); + + gfx::Point screen_loc = event.location(); + views::View::ConvertPointToScreen(this, &screen_loc); + + ui::MouseEvent mouse_event = event; + mouse_event.set_location(screen_loc); + + if (ShouldRepostEvent(mouse_event)) { + gfx::NativeView native_view = GetWidget()->GetNativeView(); + gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); + gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc); + views::RepostLocatedEvent(window, mouse_event); + } + + HideController(); + // |this| is now deleted. + } + + return false; +} + +void AutofillPopupBaseView::OnMouseReleased(const ui::MouseEvent& event) { + // Because this view can can be shown in response to a mouse press, it can + // receive an OnMouseReleased event just after showing. This breaks the mouse + // capture, so restart capturing here. + if (ShouldHideOnOutsideClick() && GetWidget()) + GetWidget()->SetCapture(this); + + // We only care about the left click. + if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location())) + AcceptSelection(event.location()); +} + +void AutofillPopupBaseView::OnGestureEvent(ui::GestureEvent* event) { + switch (event->type()) { + case ui::ET_GESTURE_TAP_DOWN: + case ui::ET_GESTURE_SCROLL_BEGIN: + case ui::ET_GESTURE_SCROLL_UPDATE: + if (HitTestPoint(event->location())) + SetSelection(event->location()); + else + ClearSelection(); + break; + case ui::ET_GESTURE_TAP: + case ui::ET_GESTURE_SCROLL_END: + if (HitTestPoint(event->location())) + AcceptSelection(event->location()); + else + ClearSelection(); + break; + case ui::ET_GESTURE_TAP_CANCEL: + case ui::ET_SCROLL_FLING_START: + ClearSelection(); + break; + default: + return; + } + event->SetHandled(); +} + +bool AutofillPopupBaseView::AcceleratorPressed( + const ui::Accelerator& accelerator) { + DCHECK_EQ(accelerator.modifiers(), ui::EF_NONE); + + if (accelerator.key_code() == ui::VKEY_ESCAPE) { + HideController(); + return true; + } + + if (accelerator.key_code() == ui::VKEY_RETURN) + return delegate_->AcceptSelectedLine(); + + NOTREACHED(); + return false; +} + +void AutofillPopupBaseView::SetSelection(const gfx::Point& point) { + if (delegate_) + delegate_->SetSelectionAtPoint(point); +} + +void AutofillPopupBaseView::AcceptSelection(const gfx::Point& point) { + if (!delegate_) + return; + + delegate_->SetSelectionAtPoint(point); + delegate_->AcceptSelectedLine(); +} + +void AutofillPopupBaseView::ClearSelection() { + if (delegate_) + delegate_->SelectionCleared(); +} + +bool AutofillPopupBaseView::ShouldHideOnOutsideClick() { + if (delegate_) + return delegate_->ShouldHideOnOutsideClick(); + + // |this| instance should be in the process of being destroyed, so the return + // value shouldn't matter. + return false; +} + +void AutofillPopupBaseView::HideController() { + if (delegate_) + delegate_->Hide(); +} + +bool AutofillPopupBaseView::ShouldRepostEvent(const ui::MouseEvent& event) { + return delegate_->ShouldRepostEvent(event); +} + +gfx::NativeView AutofillPopupBaseView::container_view() { + return delegate_->container_view(); +} + + +} // namespace autofill diff --git a/src/browser/autofill_popup_base_view.h b/src/browser/autofill_popup_base_view.h new file mode 100644 index 0000000000..e379f3d98b --- /dev/null +++ b/src/browser/autofill_popup_base_view.h @@ -0,0 +1,98 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_BASE_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_BASE_VIEW_H_ + +#include "base/memory/weak_ptr.h" +#include "content/nw/src/browser/autofill_popup_view_delegate.h" +#include "ui/views/widget/widget_delegate.h" +#include "ui/views/widget/widget_observer.h" + +namespace content { +class WebContents; +} + +namespace gfx { +class Point; +} + +namespace autofill { + +// Class that deals with the event handling for Autofill-style popups. This +// class should only be instantiated by sub-classes. +class AutofillPopupBaseView : public views::WidgetDelegateView, + public views::WidgetObserver { + protected: + explicit AutofillPopupBaseView(AutofillPopupViewDelegate* delegate, + views::Widget* observing_widget); + virtual ~AutofillPopupBaseView(); + + // Show this popup. Idempotent. + void DoShow(); + + // Hide the widget and delete |this|. + void DoHide(); + + // Update size of popup and paint. + void DoUpdateBoundsAndRedrawPopup(); + + static const SkColor kBorderColor; + static const SkColor kHoveredBackgroundColor; + static const SkColor kItemTextColor; + static const SkColor kPopupBackground; + static const SkColor kValueTextColor; + static const SkColor kWarningTextColor; + + private: + friend class AutofillPopupBaseViewTest; + + // views::Views implementation. + virtual void OnMouseCaptureLost() OVERRIDE; + virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE; + virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE; + virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE; + virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; + virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE; + virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; + virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; + + // views::WidgetObserver implementation. + virtual void OnWidgetBoundsChanged(views::Widget* widget, + const gfx::Rect& new_bounds) OVERRIDE; + + // Stop observing the |observing_widget_|. + void RemoveObserver(); + + void SetSelection(const gfx::Point& point); + void AcceptSelection(const gfx::Point& point); + void ClearSelection(); + + // If the popup should be hidden if the user clicks outside it's bounds. + bool ShouldHideOnOutsideClick(); + + // Hide the controller of this view. This assumes that doing so will + // eventually hide this view in the process. + void HideController(); + + // Returns true if this event should be passed along. + bool ShouldRepostEvent(const ui::MouseEvent& event); + + // Must return the container view for this popup. + gfx::NativeView container_view(); + + // Controller for this popup. Weak reference. + AutofillPopupViewDelegate* delegate_; + + // The widget that |this| observes. Weak reference. + views::Widget* observing_widget_; + + base::WeakPtrFactory weak_ptr_factory_; + + DISALLOW_COPY_AND_ASSIGN(AutofillPopupBaseView); +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_BASE_VIEW_H_ diff --git a/src/browser/autofill_popup_view_views.cc b/src/browser/autofill_popup_view_views.cc new file mode 100644 index 0000000000..b92c9e92fb --- /dev/null +++ b/src/browser/autofill_popup_view_views.cc @@ -0,0 +1,141 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/autofill_popup_view_views.h" + +#include "content/nw/src/browser/autofill_popup_controller.h" +#include "components/autofill/core/browser/popup_item_ids.h" +#include "grit/ui_resources.h" +#include "ui/base/resource/resource_bundle.h" +#include "ui/events/keycodes/keyboard_codes.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/image/image.h" +#include "ui/gfx/native_widget_types.h" +#include "ui/gfx/point.h" +#include "ui/gfx/rect.h" +#include "ui/gfx/text_utils.h" +#include "ui/views/border.h" +#include "ui/views/widget/widget.h" + +namespace autofill { + +AutofillPopupViewViews::AutofillPopupViewViews( + AutofillPopupController* controller, views::Widget* observing_widget) + : AutofillPopupBaseView(controller, observing_widget), + controller_(controller) {} + +AutofillPopupViewViews::~AutofillPopupViewViews() {} + +void AutofillPopupViewViews::Show() { + DoShow(); +} + +void AutofillPopupViewViews::Hide() { + // The controller is no longer valid after it hides us. + controller_ = NULL; + + DoHide(); +} + +void AutofillPopupViewViews::UpdateBoundsAndRedrawPopup() { + DoUpdateBoundsAndRedrawPopup(); +} + +void AutofillPopupViewViews::OnPaint(gfx::Canvas* canvas) { + if (!controller_) + return; + + canvas->DrawColor(kPopupBackground); + OnPaintBorder(canvas); + + for (size_t i = 0; i < controller_->names().size(); ++i) { + gfx::Rect line_rect = controller_->GetRowBounds(i); + + if (controller_->identifiers()[i] == POPUP_ITEM_ID_SEPARATOR) { + canvas->DrawRect(line_rect, kItemTextColor); + } else { + DrawAutofillEntry(canvas, i, line_rect); + } + } +} + +void AutofillPopupViewViews::InvalidateRow(size_t row) { + SchedulePaintInRect(controller_->GetRowBounds(row)); +} + +void AutofillPopupViewViews::DrawAutofillEntry(gfx::Canvas* canvas, + int index, + const gfx::Rect& entry_rect) { + if (controller_->selected_line() == index) + canvas->FillRect(entry_rect, kHoveredBackgroundColor); + + const bool is_rtl = controller_->IsRTL(); + const int value_text_width = + gfx::GetStringWidth(controller_->names()[index], + controller_->GetNameFontListForRow(index)); + const int value_content_x = is_rtl ? + entry_rect.width() - value_text_width - kEndPadding : kEndPadding; + + canvas->DrawStringRectWithFlags( + controller_->names()[index], + controller_->GetNameFontListForRow(index), + controller_->IsWarning(index) ? kWarningTextColor : kValueTextColor, + gfx::Rect(value_content_x, + entry_rect.y(), + value_text_width, + entry_rect.height()), + gfx::Canvas::TEXT_ALIGN_CENTER); + + // Use this to figure out where all the other Autofill items should be placed. + int x_align_left = is_rtl ? kEndPadding : entry_rect.width() - kEndPadding; + + // Draw the Autofill icon, if one exists + ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); + int row_height = controller_->GetRowBounds(index).height(); + if (!controller_->icons()[index].empty()) { + int icon = controller_->GetIconResourceID(controller_->icons()[index]); + DCHECK_NE(-1, icon); + const gfx::ImageSkia* image = rb.GetImageSkiaNamed(icon); + int icon_y = entry_rect.y() + (row_height - image->height()) / 2; + + x_align_left += is_rtl ? 0 : -image->width(); + + canvas->DrawImageInt(*image, x_align_left, icon_y); + + x_align_left += is_rtl ? image->width() + kIconPadding : -kIconPadding; + } + + // Draw the name text. + const int subtext_width = + gfx::GetStringWidth(controller_->subtexts()[index], + controller_->subtext_font_list()); + if (!is_rtl) + x_align_left -= subtext_width; + + canvas->DrawStringRectWithFlags( + controller_->subtexts()[index], + controller_->subtext_font_list(), + kItemTextColor, + gfx::Rect(x_align_left, + entry_rect.y(), + subtext_width, + entry_rect.height()), + gfx::Canvas::TEXT_ALIGN_CENTER); +} + +AutofillPopupView* AutofillPopupView::Create( + AutofillPopupController* controller) { + views::Widget* observing_widget = + views::Widget::GetTopLevelWidgetForNativeView( + controller->container_view()); + + // If the top level widget can't be found, cancel the popup since we can't + // fully set it up. + if (!observing_widget) + return NULL; + + return new AutofillPopupViewViews(controller, observing_widget); +} + +} // namespace autofill diff --git a/src/browser/autofill_popup_view_views.h b/src/browser/autofill_popup_view_views.h new file mode 100644 index 0000000000..a10f9d1a3f --- /dev/null +++ b/src/browser/autofill_popup_view_views.h @@ -0,0 +1,49 @@ +// 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. + +#ifndef CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_VIEW_VIEWS_H_ +#define CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_VIEW_VIEWS_H_ + +#include "content/nw/src/browser/autofill_popup_view.h" +#include "content/nw/src/browser/autofill_popup_base_view.h" + +class AutofillPopupController; + +namespace autofill { + +// Views toolkit implementation for AutofillPopupView. +class AutofillPopupViewViews : public AutofillPopupBaseView, + public AutofillPopupView { + public: + // The observing widget should be the top level widget for the native + // view, which we need to listen to for several signals that indicate the + // popup should be closed. + AutofillPopupViewViews(AutofillPopupController* controller, + views::Widget* observing_widget); + + private: + virtual ~AutofillPopupViewViews(); + + // AutofillPopupView implementation. + virtual void Show() OVERRIDE; + virtual void Hide() OVERRIDE; + virtual void InvalidateRow(size_t row) OVERRIDE; + virtual void UpdateBoundsAndRedrawPopup() OVERRIDE; + + // views::Views implementation + virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; + + // Draw the given autofill entry in |entry_rect|. + void DrawAutofillEntry(gfx::Canvas* canvas, + int index, + const gfx::Rect& entry_rect); + + AutofillPopupController* controller_; // Weak reference. + + DISALLOW_COPY_AND_ASSIGN(AutofillPopupViewViews); +}; + +} // namespace autofill + +#endif // CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_VIEW_VIEWS_H_ diff --git a/src/browser/color_chooser_dialog.cc b/src/browser/color_chooser_dialog.cc index 5697a8be4c..3f27e3da93 100644 --- a/src/browser/color_chooser_dialog.cc +++ b/src/browser/color_chooser_dialog.cc @@ -32,8 +32,8 @@ ColorChooserDialog::ColorChooserDialog(views::ColorChooserListener* listener, : listener_(listener) { DCHECK(listener_); CopyCustomColors(g_custom_colors, custom_colors_); - ExecuteOpenParams execute_params(initial_color, BeginRun(owning_window), - owning_window); + ExecuteOpenParams execute_params(initial_color, BeginRun((HWND)owning_window), + (HWND)owning_window); execute_params.run_state.dialog_thread->message_loop()->PostTask(FROM_HERE, base::Bind(&ColorChooserDialog::ExecuteOpen, this, execute_params)); } @@ -41,8 +41,8 @@ ColorChooserDialog::ColorChooserDialog(views::ColorChooserListener* listener, ColorChooserDialog::~ColorChooserDialog() { } -bool ColorChooserDialog::IsRunning(HWND owning_hwnd) const { - return listener_ && IsRunningDialogForOwner(owning_hwnd); +bool ColorChooserDialog::IsRunning(gfx::NativeWindow owning_hwnd) const { + return listener_ && IsRunningDialogForOwner((HWND)owning_hwnd); } void ColorChooserDialog::ListenerDestroyed() { diff --git a/src/browser/file_select_helper.cc b/src/browser/file_select_helper.cc index 100495d741..8efbe57d1f 100644 --- a/src/browser/file_select_helper.cc +++ b/src/browser/file_select_helper.cc @@ -258,7 +258,7 @@ FileSelectHelper::GetFileTypesFromAcceptType( int valid_type_count = 0; int description_id = 0; for (size_t i = 0; i < accept_types.size(); ++i) { - std::string ascii_type = UTF16ToASCII(accept_types[i]); + std::string ascii_type = base::UTF16ToASCII(accept_types[i]); if (!IsAcceptTypeValid(ascii_type)) continue; @@ -399,7 +399,7 @@ void FileSelectHelper::RunFileChooserOnUIThread( FilePath working_path = params.initial_path; gfx::NativeWindow owning_window = - platform_util::GetTopLevel(render_view_host_->GetView()->GetNativeView()); + (gfx::NativeWindow)::GetAncestor((HWND)render_view_host_->GetView()->GetNativeView(), GA_ROOT); select_file_dialog_->SelectFile( dialog_type_, diff --git a/src/browser/native_window_toolbar_win.cc b/src/browser/native_window_toolbar_win.cc index 1c125f5233..985169a031 100644 --- a/src/browser/native_window_toolbar_win.cc +++ b/src/browser/native_window_toolbar_win.cc @@ -95,13 +95,13 @@ void NativeWindowToolbarWin::ViewHierarchyChanged( void NativeWindowToolbarWin::ContentsChanged( views::Textfield* sender, - const string16& new_contents) { + const base::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(); + base::string16 url_string = url_entry_->text(); if (!url_string.empty()) { GURL url(url_string); if (!url.has_scheme()) @@ -165,8 +165,8 @@ void NativeWindowToolbarWin::InitToolbar() { SetIsLoading(true); AddChildView(stop_or_refresh_button_); - url_entry_ = new views::Textfield(views::Textfield::STYLE_DEFAULT); - url_entry_->SetController(this); + url_entry_ = new views::Textfield(); + url_entry_->set_controller(this); AddChildView(url_entry_); devtools_button_ = new views::ImageButton(this); @@ -215,7 +215,7 @@ void NativeWindowToolbarWin::SetButtonEnabled( } void NativeWindowToolbarWin::SetUrlEntry(const std::string& url) { - url_entry_->SetText(UTF8ToUTF16(url)); + url_entry_->SetText(base::UTF8ToUTF16(url)); } void NativeWindowToolbarWin::SetIsLoading(bool loading) { diff --git a/src/browser/native_window_toolbar_win.h b/src/browser/native_window_toolbar_win.h index 81cc82bf9a..a3358170f8 100644 --- a/src/browser/native_window_toolbar_win.h +++ b/src/browser/native_window_toolbar_win.h @@ -61,7 +61,7 @@ class NativeWindowToolbarWin : public views::WidgetDelegateView, // Overridden from TextfieldController: virtual void ContentsChanged(views::Textfield* sender, - const string16& new_contents) OVERRIDE; + const base::string16& new_contents) OVERRIDE; virtual bool HandleKeyEvent(views::Textfield* sender, const ui::KeyEvent& key_event) OVERRIDE; diff --git a/src/browser/native_window_win.cc b/src/browser/native_window_win.cc index 8f9d5a06ab..5dc85c04e0 100644 --- a/src/browser/native_window_win.cc +++ b/src/browser/native_window_win.cc @@ -52,8 +52,9 @@ #include "ui/views/layout/box_layout.h" #include "ui/views/views_delegate.h" #include "ui/views/widget/widget.h" -#include "ui/views/widget/native_widget_win.h" #include "ui/views/window/native_frame_view.h" +#include "ui/views/win/hwnd_util.h" +#include "ui/views/widget/native_widget_private.h" #include "ui/events/event_handler.h" #include "chrome/browser/ui/views/accelerator_table.h" @@ -83,7 +84,7 @@ bool IsParent(gfx::NativeView child, gfx::NativeView possible_parent) { return true; #endif gfx::NativeView parent = child; - while ((parent = platform_util::GetParent(parent))) { + while ((parent = (gfx::NativeView)::GetParent((HWND)parent))) { if (possible_parent == parent) return true; } @@ -296,7 +297,7 @@ NativeWindowWin::NativeWindowWin(const base::WeakPtr& shell, window_->UpdateWindowIcon(); OnViewWasResized(); - window_->SetInitialFocus(); + window_->SetInitialFocus(ui::SHOW_STATE_NORMAL); } NativeWindowWin::~NativeWindowWin() { @@ -383,18 +384,18 @@ void NativeWindowWin::SetResizable(bool resizable) { resizable_ = resizable; // Show/Hide the maximize button. - DWORD style = ::GetWindowLong((HWND)window_->GetNativeView(), GWL_STYLE); + DWORD style = ::GetWindowLong(views::HWNDForWidget(window_), GWL_STYLE); if (resizable) style |= WS_MAXIMIZEBOX; else style &= ~WS_MAXIMIZEBOX; - ::SetWindowLong((HWND)window_->GetNativeView(), GWL_STYLE, style); + ::SetWindowLong(views::HWNDForWidget(window_), GWL_STYLE, style); } void NativeWindowWin::SetShowInTaskbar(bool show) { if (show == false && base::win::GetVersion() < base::win::VERSION_VISTA) { // Change the owner of native window. Only needed on Windows XP. - ::SetWindowLong(window_->GetNativeView(), + ::SetWindowLong(views::HWNDForWidget(window_), GWL_HWNDPARENT, (LONG)ui::GetHiddenWindow()); } @@ -414,9 +415,9 @@ void NativeWindowWin::SetShowInTaskbar(bool show) { } if (show) - result = taskbar->AddTab(window_->GetNativeWindow()); + result = taskbar->AddTab(views::HWNDForWidget(window_)); else - result = taskbar->DeleteTab(window_->GetNativeWindow()); + result = taskbar->DeleteTab(views::HWNDForWidget(window_)); if (FAILED(result)) { LOG(ERROR) << "Failed to change the show in taskbar attribute"; @@ -513,11 +514,11 @@ void NativeWindowWin::SetBadgeLabel(const std::string& badge) { } HICON icon = NULL; - HWND hWnd = window_->GetNativeWindow(); + HWND hWnd = views::HWNDForWidget(window_); if (badge.size()) - icon = createBadgeIcon(hWnd, UTF8ToUTF16(badge).c_str(), 32, 32); + icon = createBadgeIcon(hWnd, base::UTF8ToUTF16(badge).c_str(), 32, 32); - taskbar->SetOverlayIcon(hWnd, icon, _T("Status")); + taskbar->SetOverlayIcon(hWnd, icon, L"Status"); DestroyIcon(icon); } @@ -537,7 +538,7 @@ void NativeWindowWin::SetMenu(nwapi::Menu* menu) { menu->Rebuild(); // menu is nwapi::Menu, menu->menu_ is NativeMenuWin, - ::SetMenu((HWND)window_->GetNativeWindow(), menu->menu_->GetNativeMenu()); + ::SetMenu(views::HWNDForWidget(window_), menu->menu_->GetNativeMenu()); menu->UpdateKeys( window_->GetFocusManager() ); } @@ -612,8 +613,8 @@ const views::Widget* NativeWindowWin::GetWidget() const { return window_; } -string16 NativeWindowWin::GetWindowTitle() const { - return UTF8ToUTF16(title_); +base::string16 NativeWindowWin::GetWindowTitle() const { + return base::UTF8ToUTF16(title_); } void NativeWindowWin::DeleteDelegate() { @@ -810,7 +811,7 @@ void NativeWindowWin::OnViewWasResized() { gfx::Path path; path.addRect(0, 0, width, height); SetWindowRgn((HWND)web_contents()->GetView()->GetNativeView(), - path.CreateNativeRegion(), + (HRGN)path.CreateNativeRegion(), 1); SkRegion* rgn = new SkRegion; @@ -827,8 +828,10 @@ void NativeWindowWin::OnViewWasResized() { SkRegion::kUnion_Op); } } +#if 0 //FIXME if (web_contents()->GetRenderViewHost()->GetView()) web_contents()->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn); +#endif } } // namespace nw diff --git a/src/browser/native_window_win.h b/src/browser/native_window_win.h index 2cc3c328c8..c63c4ce596 100644 --- a/src/browser/native_window_win.h +++ b/src/browser/native_window_win.h @@ -102,7 +102,7 @@ class NativeWindowWin : public NativeWindow, virtual bool CanMaximize() const OVERRIDE; virtual views::Widget* GetWidget() OVERRIDE; virtual const views::Widget* GetWidget() const OVERRIDE; - virtual string16 GetWindowTitle() const OVERRIDE; + virtual base::string16 GetWindowTitle() const OVERRIDE; virtual void DeleteDelegate() OVERRIDE; virtual views::View* GetInitiallyFocusedView() OVERRIDE; virtual gfx::ImageSkia GetWindowAppIcon() OVERRIDE; diff --git a/src/browser/printing/print_view_manager.cc b/src/browser/printing/print_view_manager.cc index 8600e01c13..836da15c00 100644 --- a/src/browser/printing/print_view_manager.cc +++ b/src/browser/printing/print_view_manager.cc @@ -201,7 +201,7 @@ void PrintViewManager::OnDidPrintPage( const CommandLine* cmdline = CommandLine::ForCurrentProcess(); int raster_size = std::min(params.page_size.GetArea(), kMaxRasterSizeInPixels); - if (big_emf || (cmdline && cmdline->HasSwitch(switches::kPrintRaster))) { + if (big_emf) { scoped_ptr raster_metafile( metafile->RasterizeMetafile(raster_size)); if (raster_metafile.get()) { diff --git a/src/browser/shell_devtools_delegate.cc b/src/browser/shell_devtools_delegate.cc index febfb0b9b5..bf58db0f0a 100644 --- a/src/browser/shell_devtools_delegate.cc +++ b/src/browser/shell_devtools_delegate.cc @@ -112,7 +112,7 @@ Target::Target(WebContents* web_contents) { agent_host_ = DevToolsAgentHost::GetOrCreateFor(web_contents->GetRenderViewHost()); id_ = agent_host_->GetId(); - title_ = UTF16ToUTF8(web_contents->GetTitle()); + title_ = base::UTF16ToUTF8(web_contents->GetTitle()); url_ = web_contents->GetURL(); last_activity_time_ = web_contents->GetLastActiveTime(); } diff --git a/src/browser/shell_download_manager_delegate_win.cc b/src/browser/shell_download_manager_delegate_win.cc index 38aab6be6a..e993b29062 100644 --- a/src/browser/shell_download_manager_delegate_win.cc +++ b/src/browser/shell_download_manager_delegate_win.cc @@ -56,7 +56,7 @@ void ShellDownloadManagerDelegate::ChooseDownloadPath( OPENFILENAME save_as; ZeroMemory(&save_as, sizeof(save_as)); save_as.lStructSize = sizeof(OPENFILENAME); - save_as.hwndOwner = item->GetWebContents()->GetView()->GetNativeView(); + save_as.hwndOwner = (HWND)item->GetWebContents()->GetView()->GetNativeView(); save_as.lpstrFile = file_name; save_as.nMaxFile = arraysize(file_name); diff --git a/src/browser/shell_javascript_dialog_win.cc b/src/browser/shell_javascript_dialog_win.cc index 7e192d3b3c..3611e3fd5a 100644 --- a/src/browser/shell_javascript_dialog_win.cc +++ b/src/browser/shell_javascript_dialog_win.cc @@ -50,7 +50,7 @@ INT_PTR CALLBACK ShellJavaScriptDialog::DialogProc(HWND dialog, GetWindowLongPtr(dialog, DWL_USER)); if (owner->dialog_win_) { owner->dialog_win_ = 0; - owner->callback_.Run(false, string16()); + owner->callback_.Run(false, base::string16()); owner->creator_->DialogClosed(owner); } break; @@ -58,7 +58,7 @@ INT_PTR CALLBACK ShellJavaScriptDialog::DialogProc(HWND dialog, case WM_COMMAND: { ShellJavaScriptDialog* owner = reinterpret_cast( GetWindowLongPtr(dialog, DWL_USER)); - string16 user_input; + base::string16 user_input; bool finish = false; bool result; switch (LOWORD(wparam)) { @@ -95,8 +95,8 @@ ShellJavaScriptDialog::ShellJavaScriptDialog( ShellJavaScriptDialogCreator* creator, gfx::NativeWindow parent_window, JavaScriptMessageType message_type, - const string16& message_text, - const string16& default_prompt_text, + const base::string16& message_text, + const base::string16& default_prompt_text, const JavaScriptDialogManager::DialogClosedCallback& callback) : creator_(creator), callback_(callback), diff --git a/src/browser/shell_login_dialog.h b/src/browser/shell_login_dialog.h index db70cb6e3d..75450339e5 100644 --- a/src/browser/shell_login_dialog.h +++ b/src/browser/shell_login_dialog.h @@ -90,6 +90,11 @@ class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate { GtkWidget* password_entry_; GtkWidget* root_; CHROMEGTK_CALLBACK_1(ShellLoginDialog, void, OnResponse, int); +#elif defined(OS_WIN) +INT_PTR CALLBACK DialogProc(HWND dialog, + UINT message, + WPARAM wparam, + LPARAM lparam); #endif }; diff --git a/src/browser/shell_login_dialog_win.cc b/src/browser/shell_login_dialog_win.cc index 358cedf035..2787067ff6 100644 --- a/src/browser/shell_login_dialog_win.cc +++ b/src/browser/shell_login_dialog_win.cc @@ -65,8 +65,8 @@ INT_PTR CALLBACK ShellLoginDialog::DialogProc(HWND dialog, ShellLoginDialog* owner = reinterpret_cast( GetWindowLongPtr(dialog, DWL_USER)); if (LOWORD(wparam) == IDOK) { - string16 username; - string16 password; + base::string16 username; + base::string16 password; size_t length = GetWindowTextLength(GetDlgItem(dialog, IDC_USERNAMEEDIT)) + 1; GetDlgItemText(dialog, IDC_USERNAMEEDIT, @@ -91,7 +91,7 @@ INT_PTR CALLBACK ShellLoginDialog::DialogProc(HWND dialog, return 0; } -void ShellLoginDialog::PlatformCreateDialog(const string16& message) { +void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); WebContents* web_contents = NULL; diff --git a/src/chrome_breakpad_client.cc b/src/chrome_breakpad_client.cc index 3dff5afbd0..a41ff3e367 100644 --- a/src/chrome_breakpad_client.cc +++ b/src/chrome_breakpad_client.cc @@ -116,13 +116,7 @@ void ChromeBreakpadClient::GetProductNameAndVersion( if (!version_info->is_official_build()) version->append(base::ASCIIToUTF16("-devel")); - const CommandLine& command = *CommandLine::ForCurrentProcess(); - if (command.HasSwitch(switches::kChromeFrame)) { - *product_name = base::ASCIIToUTF16("ChromeFrame"); - } else { - *product_name = version_info->product_short_name(); - } - + *product_name = version_info->product_short_name(); *special_build = version_info->special_build(); } else { // No version info found. Make up the values. diff --git a/src/hard_error_handler_win.cc b/src/hard_error_handler_win.cc index 0b07edc66c..cf93adcc3b 100644 --- a/src/hard_error_handler_win.cc +++ b/src/hard_error_handler_win.cc @@ -57,7 +57,7 @@ void RaiseHardErrorMsg(long nt_status, const std::string& p1, if (!count) return; count += p1.size() + p2.size() + 1; - string16 message; + base::string16 message; ::wsprintf(WriteInto(&message, count), msg_template, p1.c_str(), p2.c_str()); // The MB_SERVICE_NOTIFICATION causes this message to be displayed by // csrss. This means that we are not creating windows or pumping WM messages diff --git a/src/nw_package.cc b/src/nw_package.cc index e78c6d0564..537ce0df7c 100644 --- a/src/nw_package.cc +++ b/src/nw_package.cc @@ -30,6 +30,7 @@ #include "base/strings/string_number_conversions.h" #include "base/strings/string_tokenizer.h" #include "base/strings/string_util.h" +#include "base/strings/utf_string_conversions.h" #include "base/threading/thread_restrictions.h" #include "base/values.h" #include "third_party/zlib/google/zip.h" @@ -427,8 +428,8 @@ void Package::ReadChromiumArgs() { // string here is safe beacuse we use ASCII only. if (!base::IsSwitch(ASCIIToWide(chromium_args[i]), &key, &value)) continue; - command_line->AppendSwitchASCII(WideToASCII(key), - WideToASCII(value)); + command_line->AppendSwitchASCII(base::UTF16ToASCII(key), + base::UTF16ToASCII(value)); #else if (!base::IsSwitch(chromium_args[i], &key, &value)) continue; diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 2e545806d6..551dcb5d9a 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -663,7 +663,7 @@ void Shell::Observe(int type, if (title->first) { base::string16 text = title->first->GetTitle(); - window()->SetTitle(UTF16ToUTF8(text)); + window()->SetTitle(base::UTF16ToUTF8(text)); } } else if (type == NOTIFICATION_RENDERER_PROCESS_CLOSED) { exit_code_ = diff --git a/src/renderer/printing/print_web_view_helper_win.cc b/src/renderer/printing/print_web_view_helper_win.cc index c49d7b6f32..7f5c1418b6 100644 --- a/src/renderer/printing/print_web_view_helper_win.cc +++ b/src/renderer/printing/print_web_view_helper_win.cc @@ -27,7 +27,7 @@ namespace printing { -using WebKit::WebFrame; +using blink::WebFrame; void PrintWebViewHelper::PrintPageInternal( const PrintMsg_PrintPage_Params& params, diff --git a/src/shell.rc b/src/shell.rc index a68a5d49f4..bd4cc2e050 100644 --- a/src/shell.rc +++ b/src/shell.rc @@ -146,4 +146,4 @@ END IDR_MAINFRAME ICON "resources\\nw.ico" ///////////////////////////////////////////////////////////////////////////// -CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "nw.exe.manifest" \ No newline at end of file +//CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "nw.exe.manifest" diff --git a/src/shell_browser_main_parts.cc b/src/shell_browser_main_parts.cc index 4666dad901..d9b87a70f7 100644 --- a/src/shell_browser_main_parts.cc +++ b/src/shell_browser_main_parts.cc @@ -211,7 +211,7 @@ bool ShellBrowserMainParts::ProcessSingletonNotificationCallback( return false; #if defined(OS_WIN) - std::string cmd = UTF16ToUTF8(command_line.GetCommandLineString()); + std::string cmd = base::UTF16ToUTF8(command_line.GetCommandLineString()); #else std::string cmd = command_line.GetCommandLineString(); #endif diff --git a/src/shell_main.cc b/src/shell_main.cc index 02b706163b..e7ee9641c4 100644 --- a/src/shell_main.cc +++ b/src/shell_main.cc @@ -24,6 +24,7 @@ #include "sandbox/win/src/sandbox_types.h" #if defined(OS_WIN) +#include "base/win/win_util.h" #include "content/public/app/startup_helper_win.h" #endif @@ -37,7 +38,12 @@ int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) { sandbox::SandboxInterfaceInfo sandbox_info = {0}; content::InitializeSandboxInfo(&sandbox_info); content::ShellMainDelegate delegate; - return content::ContentMain(instance, &sandbox_info, &delegate); + content::ContentMainParams params(&delegate); + params.instance = instance; + params.sandbox_info = &sandbox_info; + int rv = content::ContentMain(params); + base::win::SetShouldCrashOnProcessDetach(false); + return rv; } #else From d9a1fe2f8d10281d2c8c3b2a87b98f6315090fbf Mon Sep 17 00:00:00 2001 From: Kevin Fan Date: Sun, 15 Jun 2014 17:06:22 +0800 Subject: [PATCH 058/492] trying to fix start err --- nw.gypi | 7 +++++++ src/browser/native_window_win.cc | 1 + src/shell_browser_main_parts.cc | 27 +++++++++++++++++++++++++++ src/shell_browser_main_parts.h | 4 +++- 4 files changed, 38 insertions(+), 1 deletion(-) diff --git a/nw.gypi b/nw.gypi index 0a26e2bf80..f907302a16 100644 --- a/nw.gypi +++ b/nw.gypi @@ -339,6 +339,13 @@ '<(DEPTH)/base/allocator/allocator.gyp:allocator', ], }], + ['use_aura==1', { + 'dependencies': [ + '<(DEPTH)/ui/views/views.gyp:views', + '<(DEPTH)/ui/views/views.gyp:views_test_support', + '<(DEPTH)/ui/views/controls/webview/webview.gyp:webview', + ], + }], ['(os_posix==1 and OS != "mac" and linux_use_tcmalloc==1)', { 'dependencies': [ # This is needed by content/app/content_main_runner.cc diff --git a/src/browser/native_window_win.cc b/src/browser/native_window_win.cc index 5dc85c04e0..008ef2561b 100644 --- a/src/browser/native_window_win.cc +++ b/src/browser/native_window_win.cc @@ -276,6 +276,7 @@ NativeWindowWin::NativeWindowWin(const base::WeakPtr& shell, window_ = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.delegate = this; + params.top_level = true; params.remove_standard_frame = !has_frame(); params.use_system_default_icon = true; window_->Init(params); diff --git a/src/shell_browser_main_parts.cc b/src/shell_browser_main_parts.cc index d9b87a70f7..bb1c46447e 100644 --- a/src/shell_browser_main_parts.cc +++ b/src/shell_browser_main_parts.cc @@ -52,6 +52,13 @@ #include "content/nw/src/browser/printing/print_dialog_gtk.h" #endif +#if defined(USE_AURA) +#include "ui/aura/env.h" +#include "ui/gfx/screen.h" +#include "ui/views/test/desktop_test_views_delegate.h" +#include "ui/views/widget/desktop_aura/desktop_screen.h" +#endif // defined(USE_AURA) + using base::MessageLoop; namespace { @@ -149,9 +156,29 @@ void ShellBrowserMainParts::PostMainMessageLoopStart() { int ShellBrowserMainParts::PreCreateThreads() { net::ProxyResolverV8::RememberDefaultIsolate(); +#if defined(USE_AURA) + gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, + views::CreateDesktopScreen()); +#endif return 0; } +void ShellBrowserMainParts::PostDestroyThreads() { +#if defined(USE_AURA) + aura::Env::DeleteInstance(); + delete views::ViewsDelegate::views_delegate; +#endif +} + +void ShellBrowserMainParts::ToolkitInitialized() { +#if defined(USE_AURA) + aura::Env::CreateInstance(); + + DCHECK(!views::ViewsDelegate::views_delegate); + new views::DesktopTestViewsDelegate; +#endif +} + void ShellBrowserMainParts::Init() { package_.reset(new nw::Package()); CommandLine& command_line = *CommandLine::ForCurrentProcess(); diff --git a/src/shell_browser_main_parts.h b/src/shell_browser_main_parts.h index f9ff060aff..dc17fddcdd 100644 --- a/src/shell_browser_main_parts.h +++ b/src/shell_browser_main_parts.h @@ -47,7 +47,9 @@ class ShellBrowserMainParts : public BrowserMainParts { virtual void PostMainMessageLoopStart() OVERRIDE; virtual bool MainMessageLoopRun(int* result_code) OVERRIDE; virtual void PostMainMessageLoopRun() OVERRIDE; - virtual int PreCreateThreads() OVERRIDE; + virtual int PreCreateThreads() OVERRIDE; + virtual void PostDestroyThreads() OVERRIDE; + virtual void ToolkitInitialized() OVERRIDE; // Init browser context and every thing void Init(); From 40486d8a774619776011c143d4b6765cf633f9ca Mon Sep 17 00:00:00 2001 From: Kevin Fan Date: Sun, 15 Jun 2014 19:31:20 +0800 Subject: [PATCH 059/492] fix build on linux --- src/browser/file_select_helper.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/browser/file_select_helper.cc b/src/browser/file_select_helper.cc index 8efbe57d1f..c41b131658 100644 --- a/src/browser/file_select_helper.cc +++ b/src/browser/file_select_helper.cc @@ -398,8 +398,13 @@ void FileSelectHelper::RunFileChooserOnUIThread( FilePath default_file_name = params.default_file_name; FilePath working_path = params.initial_path; +#if defined(OS_WIN) gfx::NativeWindow owning_window = (gfx::NativeWindow)::GetAncestor((HWND)render_view_host_->GetView()->GetNativeView(), GA_ROOT); +#else + gfx::NativeWindow owning_window = + platform_util::GetTopLevel(render_view_host_->GetView()->GetNativeView()); +#endif select_file_dialog_->SelectFile( dialog_type_, From f639aad29b29974180869c8f9a6109ddb96291d6 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 18 Jun 2014 13:39:07 +0800 Subject: [PATCH 060/492] use autofill_popup_view_views only on windows --- nw.gypi | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/nw.gypi b/nw.gypi index f907302a16..9096751478 100644 --- a/nw.gypi +++ b/nw.gypi @@ -166,16 +166,12 @@ 'src/api/window/window.h', 'src/browser/app_controller_mac.h', 'src/browser/app_controller_mac.mm', - 'src/browser/autofill_popup_base_view.cc', - 'src/browser/autofill_popup_base_view.h', 'src/browser/autofill_popup_view_gtk.cc', 'src/browser/autofill_popup_view_gtk.h', 'src/browser/autofill_popup_view_cocoa.h', 'src/browser/autofill_popup_view_cocoa.mm', 'src/browser/autofill_popup_view_bridge.h', 'src/browser/autofill_popup_view_bridge.mm', - 'src/browser/autofill_popup_view_views.cc', - 'src/browser/autofill_popup_view_views.h', 'src/browser/autofill_popup_controller_impl.cc', 'src/browser/autofill_popup_controller_impl.h', 'src/browser/tab_autofill_manager_delegate.cc', @@ -353,6 +349,12 @@ ], }], ['OS=="win"', { + 'sources': [ + 'src/browser/autofill_popup_base_view.cc', + 'src/browser/autofill_popup_base_view.h', + 'src/browser/autofill_popup_view_views.cc', + 'src/browser/autofill_popup_view_views.h', + ], 'dependencies': [ '<(DEPTH)/breakpad/breakpad.gyp:breakpad_handler', '<(DEPTH)/breakpad/breakpad.gyp:breakpad_sender', From ce7eb2b9b7ee1504d4b3d01f00bb9c8705fb46fd Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 18 Jun 2014 14:30:48 +0800 Subject: [PATCH 061/492] rename dir 'locale' to 'locales' --- nw.gypi | 108 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 54 insertions(+), 54 deletions(-) diff --git a/nw.gypi b/nw.gypi index 9096751478..17a95fdadc 100644 --- a/nw.gypi +++ b/nw.gypi @@ -442,7 +442,7 @@ ], }, { - 'destination': '<(PRODUCT_DIR)/locale', + 'destination': '<(PRODUCT_DIR)/locales', 'files': [ '<(SHARED_INTERMEDIATE_DIR)/content/en-US.pak', '<(SHARED_INTERMEDIATE_DIR)/content/am.pak', @@ -847,59 +847,59 @@ 'src/mac/English.lproj/HttpAuth.xib', '<(PRODUCT_DIR)/icudtl.dat', '<(PRODUCT_DIR)/nw.pak', - '<(PRODUCT_DIR)/locale/en-US.pak', - '<(PRODUCT_DIR)/locale/am.pak', - '<(PRODUCT_DIR)/locale/ar.pak', - '<(PRODUCT_DIR)/locale/bg.pak', - '<(PRODUCT_DIR)/locale/bn.pak', - '<(PRODUCT_DIR)/locale/ca.pak', - '<(PRODUCT_DIR)/locale/cs.pak', - '<(PRODUCT_DIR)/locale/da.pak', - '<(PRODUCT_DIR)/locale/de.pak', - '<(PRODUCT_DIR)/locale/el.pak', - '<(PRODUCT_DIR)/locale/en-GB.pak', - '<(PRODUCT_DIR)/locale/es.pak', - '<(PRODUCT_DIR)/locale/es-419.pak', - '<(PRODUCT_DIR)/locale/et.pak', - '<(PRODUCT_DIR)/locale/fa.pak', - '<(PRODUCT_DIR)/locale/fi.pak', - '<(PRODUCT_DIR)/locale/fil.pak', - '<(PRODUCT_DIR)/locale/fr.pak', - '<(PRODUCT_DIR)/locale/gu.pak', - '<(PRODUCT_DIR)/locale/hi.pak', - '<(PRODUCT_DIR)/locale/hr.pak', - '<(PRODUCT_DIR)/locale/hu.pak', - '<(PRODUCT_DIR)/locale/id.pak', - '<(PRODUCT_DIR)/locale/it.pak', - '<(PRODUCT_DIR)/locale/iw.pak', - '<(PRODUCT_DIR)/locale/ja.pak', - '<(PRODUCT_DIR)/locale/kn.pak', - '<(PRODUCT_DIR)/locale/ko.pak', - '<(PRODUCT_DIR)/locale/lt.pak', - '<(PRODUCT_DIR)/locale/lv.pak', - '<(PRODUCT_DIR)/locale/ml.pak', - '<(PRODUCT_DIR)/locale/mr.pak', - '<(PRODUCT_DIR)/locale/ms.pak', - '<(PRODUCT_DIR)/locale/nl.pak', - '<(PRODUCT_DIR)/locale/no.pak', - '<(PRODUCT_DIR)/locale/pl.pak', - '<(PRODUCT_DIR)/locale/pt-BR.pak', - '<(PRODUCT_DIR)/locale/pt-PT.pak', - '<(PRODUCT_DIR)/locale/ro.pak', - '<(PRODUCT_DIR)/locale/ru.pak', - '<(PRODUCT_DIR)/locale/sk.pak', - '<(PRODUCT_DIR)/locale/sl.pak', - '<(PRODUCT_DIR)/locale/sr.pak', - '<(PRODUCT_DIR)/locale/sv.pak', - '<(PRODUCT_DIR)/locale/sw.pak', - '<(PRODUCT_DIR)/locale/ta.pak', - '<(PRODUCT_DIR)/locale/te.pak', - '<(PRODUCT_DIR)/locale/th.pak', - '<(PRODUCT_DIR)/locale/tr.pak', - '<(PRODUCT_DIR)/locale/uk.pak', - '<(PRODUCT_DIR)/locale/vi.pak', - '<(PRODUCT_DIR)/locale/zh-CN.pak', - '<(PRODUCT_DIR)/locale/zh-TW.pak', + '<(PRODUCT_DIR)/locales/en-US.pak', + '<(PRODUCT_DIR)/locales/am.pak', + '<(PRODUCT_DIR)/locales/ar.pak', + '<(PRODUCT_DIR)/locales/bg.pak', + '<(PRODUCT_DIR)/locales/bn.pak', + '<(PRODUCT_DIR)/locales/ca.pak', + '<(PRODUCT_DIR)/locales/cs.pak', + '<(PRODUCT_DIR)/locales/da.pak', + '<(PRODUCT_DIR)/locales/de.pak', + '<(PRODUCT_DIR)/locales/el.pak', + '<(PRODUCT_DIR)/locales/en-GB.pak', + '<(PRODUCT_DIR)/locales/es.pak', + '<(PRODUCT_DIR)/locales/es-419.pak', + '<(PRODUCT_DIR)/locales/et.pak', + '<(PRODUCT_DIR)/locales/fa.pak', + '<(PRODUCT_DIR)/locales/fi.pak', + '<(PRODUCT_DIR)/locales/fil.pak', + '<(PRODUCT_DIR)/locales/fr.pak', + '<(PRODUCT_DIR)/locales/gu.pak', + '<(PRODUCT_DIR)/locales/hi.pak', + '<(PRODUCT_DIR)/locales/hr.pak', + '<(PRODUCT_DIR)/locales/hu.pak', + '<(PRODUCT_DIR)/locales/id.pak', + '<(PRODUCT_DIR)/locales/it.pak', + '<(PRODUCT_DIR)/locales/iw.pak', + '<(PRODUCT_DIR)/locales/ja.pak', + '<(PRODUCT_DIR)/locales/kn.pak', + '<(PRODUCT_DIR)/locales/ko.pak', + '<(PRODUCT_DIR)/locales/lt.pak', + '<(PRODUCT_DIR)/locales/lv.pak', + '<(PRODUCT_DIR)/locales/ml.pak', + '<(PRODUCT_DIR)/locales/mr.pak', + '<(PRODUCT_DIR)/locales/ms.pak', + '<(PRODUCT_DIR)/locales/nl.pak', + '<(PRODUCT_DIR)/locales/no.pak', + '<(PRODUCT_DIR)/locales/pl.pak', + '<(PRODUCT_DIR)/locales/pt-BR.pak', + '<(PRODUCT_DIR)/locales/pt-PT.pak', + '<(PRODUCT_DIR)/locales/ro.pak', + '<(PRODUCT_DIR)/locales/ru.pak', + '<(PRODUCT_DIR)/locales/sk.pak', + '<(PRODUCT_DIR)/locales/sl.pak', + '<(PRODUCT_DIR)/locales/sr.pak', + '<(PRODUCT_DIR)/locales/sv.pak', + '<(PRODUCT_DIR)/locales/sw.pak', + '<(PRODUCT_DIR)/locales/ta.pak', + '<(PRODUCT_DIR)/locales/te.pak', + '<(PRODUCT_DIR)/locales/th.pak', + '<(PRODUCT_DIR)/locales/tr.pak', + '<(PRODUCT_DIR)/locales/uk.pak', + '<(PRODUCT_DIR)/locales/vi.pak', + '<(PRODUCT_DIR)/locales/zh-CN.pak', + '<(PRODUCT_DIR)/locales/zh-TW.pak', ], 'dependencies': [ 'nw_lib', From 26748730c1cce796a2fbee4357dec85354ecdc68 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 18 Jun 2014 14:36:19 +0800 Subject: [PATCH 062/492] [WIN] ship icudtl.dat instead of icudt.dll --- tools/package_binaries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 9720a728f7..1fae66e941 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -112,7 +112,7 @@ def generate_target_nw(platform_name, arch, version): elif platform_name == 'win': target['input'] = [ 'ffmpegsumo.dll', - 'icudt.dll', + 'icudtl.dat', 'libEGL.dll', 'libGLESv2.dll', 'nw.exe', From b54c2e79065f0ba45ecf836794ec3b7f6db01f95 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 18 Jun 2014 14:45:05 +0800 Subject: [PATCH 063/492] Ship locales dir in linux & win --- tools/package_binaries.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 1fae66e941..15bcaa7ab9 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -108,6 +108,7 @@ def generate_target_nw(platform_name, arch, version): # 'nwsnapshot', 'nw', 'icudtl.dat', + 'locales', ] elif platform_name == 'win': target['input'] = [ @@ -121,6 +122,7 @@ def generate_target_nw(platform_name, arch, version): 'nw.lib', # 'nwsnapshot.exe', 'credits.html', + 'locales', ] elif platform_name == 'osx': target['input'] = [ From ab6ff3cb4635a1e822d765d606cbf8c74316e8f0 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Thu, 19 Jun 2014 10:58:28 +0800 Subject: [PATCH 064/492] Fix getting new windows --- src/nw_shell.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 551dcb5d9a..afd90634ef 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -594,7 +594,8 @@ void Shell::WebContentsCreated(WebContents* source_contents, #if defined(OS_WIN) void Shell::WebContentsFocused(content::WebContents* web_contents) { NativeWindowWin* win = static_cast(window_.get()); - win->web_view_->OnWebContentsFocused(web_contents); + if (win) // on aura this function is called in the middle of window creation + win->web_view_->OnWebContentsFocused(web_contents); } #endif From 16e11e8711997cc4034363dbbcdca8aa03ae68bd Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 19 Jun 2014 22:21:56 +0800 Subject: [PATCH 065/492] Revert "Ship locales dir in linux & win" This reverts commit b54c2e79065f0ba45ecf836794ec3b7f6db01f95. locales dir is only needed in debug build --- tools/package_binaries.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 15bcaa7ab9..1fae66e941 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -108,7 +108,6 @@ def generate_target_nw(platform_name, arch, version): # 'nwsnapshot', 'nw', 'icudtl.dat', - 'locales', ] elif platform_name == 'win': target['input'] = [ @@ -122,7 +121,6 @@ def generate_target_nw(platform_name, arch, version): 'nw.lib', # 'nwsnapshot.exe', 'credits.html', - 'locales', ] elif platform_name == 'osx': target['input'] = [ From 95488e93925998d9d9bfbf6c4b40559f96fb5f45 Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 19 Jun 2014 22:22:34 +0800 Subject: [PATCH 066/492] turn on manifest for tooltip --- nw.gypi | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/nw.gypi b/nw.gypi index 17a95fdadc..dcf96d61b7 100644 --- a/nw.gypi +++ b/nw.gypi @@ -721,11 +721,11 @@ 'VCLinkerTool': { 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS }, - #'VCManifestTool': { - # 'AdditionalManifestFiles': [ - # '$(ProjectDir)\\nw\\src\\nw.exe.manifest', - # ], - # }, + 'VCManifestTool': { + 'AdditionalManifestFiles': [ + '$(ProjectDir)\\nw\\src\\nw.exe.manifest', + ], + }, }, 'conditions': [ ['OS=="win" and win_use_allocator_shim==1', { From 12419ebb30a9854a97feabc045ca03fd27b04d50 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Thu, 6 Mar 2014 09:37:31 +0800 Subject: [PATCH 067/492] [OSX] menu proposal from Chris make ClearMenu non-pure virtual as well --- src/api/menu/menu_mac.mm | 15 ++----- src/api/menuitem/menuitem.h | 11 ++--- src/api/menuitem/menuitem.js | 8 +++- src/api/menuitem/menuitem_delegate_mac.mm | 8 ++-- src/api/menuitem/menuitem_mac.mm | 55 ++++++++++++++++++----- src/api/window/window.cc | 2 + src/api/window_bindings.js | 4 ++ src/browser/native_window.h | 9 ++-- src/browser/native_window_mac.h | 1 + src/browser/native_window_mac.mm | 24 +++++----- 10 files changed, 89 insertions(+), 48 deletions(-) diff --git a/src/api/menu/menu_mac.mm b/src/api/menu/menu_mac.mm index 538b0f7bda..1274bad0c0 100644 --- a/src/api/menu/menu_mac.mm +++ b/src/api/menu/menu_mac.mm @@ -1,16 +1,16 @@ // Copyright (c) 2012 Intel Corp // Copyright (c) 2012 The Chromium Authors -// -// Permission is hereby granted, free of charge, to any person obtaining a copy +// +// 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 @@ -35,13 +35,6 @@ void Menu::Create(const base::DictionaryValue& option) { menu_ = [[NSMenu alloc] initWithTitle:@"NW Menu"]; [menu_ setAutoenablesItems:NO]; - - std::string type; - if (option.GetString("type", &type) && type == "menubar") { - // Preserve the apple menu. - [menu_ addItem:[[[NSMenuItem alloc] - initWithTitle:@"" action:nil keyEquivalent:@""] autorelease]]; - } } void Menu::Destroy() { diff --git a/src/api/menuitem/menuitem.h b/src/api/menuitem/menuitem.h index 4225c744c2..9302401ef1 100644 --- a/src/api/menuitem/menuitem.h +++ b/src/api/menuitem/menuitem.h @@ -1,16 +1,16 @@ // Copyright (c) 2012 Intel Corp // Copyright (c) 2012 The Chromium Authors -// -// Permission is hereby granted, free of charge, to any person obtaining a copy +// +// 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 @@ -19,7 +19,7 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #ifndef CONTENT_NW_SRC_API_MENUITEM_MENUITEM_H_ -#define CONTENT_NW_SRC_API_MENUITEM_MENUITEM_H_ +#define CONTENT_NW_SRC_API_MENUITEM_MENUITEM_H_ #include "base/compiler_specific.h" #include "content/nw/src/api/base/base.h" @@ -102,6 +102,7 @@ class MenuItem : public Base { void SetLabel(const std::string& label); void SetIcon(const std::string& icon); void SetTooltip(const std::string& tooltip); + void SetKey(const std::string& key); void SetEnabled(bool enabled); void SetChecked(bool checked); void SetSubmenu(Menu* sub_menu); diff --git a/src/api/menuitem/menuitem.js b/src/api/menuitem/menuitem.js index 0d372d9141..bacff28344 100644 --- a/src/api/menuitem/menuitem.js +++ b/src/api/menuitem/menuitem.js @@ -83,6 +83,10 @@ function MenuItem(option) { option.tooltip = ''; if (!option.hasOwnProperty('enabled')) option.enabled = true; + if (!option.hasOwnProperty('key')) + option.key = ""; + if (!option.hasOwnProperty('modifiers')) + option.modifiers = ""; } require('util').inherits(MenuItem, exports.Base); @@ -123,14 +127,14 @@ MenuItem.prototype.__defineSetter__('tooltip', function(val) { MenuItem.prototype.__defineGetter__('checked', function() { if (this.type != 'checkbox') return undefined; - + return this.handleGetter('checked'); }); MenuItem.prototype.__defineSetter__('checked', function(val) { if (this.type != 'checkbox') throw new String("'checked' property is only available for checkbox"); - + this.handleSetter('checked', 'SetChecked', Boolean, val); }); diff --git a/src/api/menuitem/menuitem_delegate_mac.mm b/src/api/menuitem/menuitem_delegate_mac.mm index a3ccd08a9b..5223f5d6d8 100644 --- a/src/api/menuitem/menuitem_delegate_mac.mm +++ b/src/api/menuitem/menuitem_delegate_mac.mm @@ -1,16 +1,16 @@ // Copyright (c) 2012 Intel Corp // Copyright (c) 2012 The Chromium Authors -// -// Permission is hereby granted, free of charge, to any person obtaining a copy +// +// 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 diff --git a/src/api/menuitem/menuitem_mac.mm b/src/api/menuitem/menuitem_mac.mm index d907adb33f..36c8f6c55c 100644 --- a/src/api/menuitem/menuitem_mac.mm +++ b/src/api/menuitem/menuitem_mac.mm @@ -1,16 +1,16 @@ // Copyright (c) 2012 Intel Corp // Copyright (c) 2012 The Chromium Authors -// -// Permission is hereby granted, free of charge, to any person obtaining a copy +// +// 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 @@ -43,13 +43,23 @@ std::string label; option.GetString("label", &label); - menu_item_ = [[NSMenuItem alloc] - initWithTitle:[NSString stringWithUTF8String:label.c_str()] - action: @selector(invoke:) - keyEquivalent: @""]; - - delegate_ = [[MenuItemDelegate alloc] initWithMenuItem:this]; - [menu_item_ setTarget:delegate_]; + std::string selector; + option.GetString("selector", &selector); + + if(!selector.empty()) { + menu_item_ = [[NSMenuItem alloc] + initWithTitle:[NSString stringWithUTF8String:label.c_str()] + action: NSSelectorFromString([NSString stringWithUTF8String:selector.c_str()]) + keyEquivalent: @""]; + delegate_ = [MenuItemDelegate alloc]; + } else { + menu_item_ = [[NSMenuItem alloc] + initWithTitle:[NSString stringWithUTF8String:label.c_str()] + action: @selector(invoke:) + keyEquivalent: @""]; + delegate_ = [[MenuItemDelegate alloc] initWithMenuItem:this]; + [menu_item_ setTarget:delegate_]; + } if (type == "checkbox") { bool checked = false; @@ -69,6 +79,25 @@ if (option.GetString("tooltip", &tooltip)) SetTooltip(tooltip); + std::string key; + if (option.GetString("key", &key)) + SetKey(key); + + std::string modifiers; + if (option.GetString("modifiers", &modifiers)) { + NSUInteger mask = 0; + NSString* nsmodifiers = [NSString stringWithUTF8String:modifiers.c_str()]; + if([nsmodifiers rangeOfString:@"shift"].location != NSNotFound) + mask = mask|NSShiftKeyMask; + if([nsmodifiers rangeOfString:@"cmd"].location != NSNotFound) + mask = mask|NSCommandKeyMask; + if([nsmodifiers rangeOfString:@"alt"].location != NSNotFound) + mask = mask|NSAlternateKeyMask; + if([nsmodifiers rangeOfString:@"ctrl"].location != NSNotFound) + mask = mask|NSControlKeyMask; + [menu_item_ setKeyEquivalentModifierMask:mask]; + } + int menu_id; if (option.GetInteger("submenu", &menu_id)) SetSubmenu(dispatcher_host()->GetApiObject(menu_id)); @@ -94,6 +123,10 @@ [menu_item_ setTitle:[NSString stringWithUTF8String:label.c_str()]]; } +void MenuItem::SetKey(const std::string& key) { + [menu_item_ setKeyEquivalent:[NSString stringWithUTF8String:key.c_str()]]; +} + void MenuItem::SetIcon(const std::string& icon) { if (!icon.empty()) { NSImage* image = [[NSImage alloc] diff --git a/src/api/window/window.cc b/src/api/window/window.cc index d2c3160648..3d475b269f 100644 --- a/src/api/window/window.cc +++ b/src/api/window/window.cc @@ -265,6 +265,8 @@ void Window::Call(const std::string& method, int id; if (arguments.GetInteger(0, &id)) shell_->window()->SetMenu(dispatcher_host()->GetApiObject(id)); + } else if (method == "ClearMenu") { + shell_->window()->ClearMenu(); } else if (method == "Reload") { int type; if (arguments.GetInteger(0, &type)) diff --git a/src/api/window_bindings.js b/src/api/window_bindings.js index 4ab3ba6248..1e4e45e0e3 100644 --- a/src/api/window_bindings.js +++ b/src/api/window_bindings.js @@ -212,6 +212,10 @@ Window.prototype.__defineGetter__('zoomLevel', function() { }); Window.prototype.__defineSetter__('menu', function(menu) { + if(!menu) { + CallObjectMethod(this, "ClearMenu", []); + return; + } if (v8_util.getConstructorName(menu) != 'Menu') throw new String("'menu' property requries a valid Menu"); diff --git a/src/browser/native_window.h b/src/browser/native_window.h index 79c76dca7c..fff9e11347 100644 --- a/src/browser/native_window.h +++ b/src/browser/native_window.h @@ -1,16 +1,16 @@ // Copyright (c) 2012 Intel Corp // Copyright (c) 2012 The Chromium Authors -// -// Permission is hereby granted, free of charge, to any person obtaining a copy +// +// 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 @@ -96,6 +96,7 @@ class NativeWindow { virtual void SetKiosk(bool kiosk) = 0; virtual bool IsKiosk() = 0; virtual void SetMenu(nwapi::Menu* menu) = 0; + virtual void ClearMenu() {} virtual void SetInitialFocus(bool accept_focus) = 0; virtual bool InitialFocus() = 0; diff --git a/src/browser/native_window_mac.h b/src/browser/native_window_mac.h index 99151269c0..b5a5817b63 100644 --- a/src/browser/native_window_mac.h +++ b/src/browser/native_window_mac.h @@ -68,6 +68,7 @@ class NativeWindowCocoa : public NativeWindow { virtual void SetKiosk(bool kiosk) OVERRIDE; virtual bool IsKiosk() OVERRIDE; virtual void SetMenu(nwapi::Menu* menu) OVERRIDE; + virtual void ClearMenu() OVERRIDE; virtual void SetToolbarButtonEnabled(TOOLBAR_BUTTON button, bool enabled) OVERRIDE; virtual void SetToolbarUrlEntry(const std::string& url) OVERRIDE; diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index 03a89f270c..2afb7a095f 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -651,7 +651,7 @@ - (NSRect)contentRectForFrameRect:(NSRect)frameRect { if (kiosk) { NSApplicationPresentationOptions options = NSApplicationPresentationHideDock + - NSApplicationPresentationHideMenuBar + + NSApplicationPresentationHideMenuBar + NSApplicationPresentationDisableAppleMenu + NSApplicationPresentationDisableProcessSwitching + NSApplicationPresentationDisableForceQuit + @@ -672,15 +672,17 @@ - (NSRect)contentRectForFrameRect:(NSRect)frameRect { } void NativeWindowCocoa::SetMenu(nwapi::Menu* menu) { - bool no_edit_menu = false; - shell_->GetPackage()->root()->GetBoolean("no-edit-menu", &no_edit_menu); + if(menu == nil) { + NSMenu *menu = [[NSMenu alloc] initWithTitle:@""]; + [NSApp setMainMenu:menu]; + } else { + [NSApp setMainMenu:menu->menu_]; + } +} - StandardMenusMac standard_menus(shell_->GetPackage()->GetName()); - [NSApp setMainMenu:menu->menu_]; - standard_menus.BuildAppleMenu(); - if (!no_edit_menu) - standard_menus.BuildEditMenu(); - standard_menus.BuildWindowMenu(); +void NativeWindowCocoa::ClearMenu() { + NSMenu *menu = [[NSMenu alloc] initWithTitle:@""]; + [NSApp setMainMenu:menu]; } void NativeWindowCocoa::SetInitialFocus(bool accept_focus) { @@ -738,7 +740,7 @@ - (NSRect)contentRectForFrameRect:(NSRect)frameRect { if (toolbar_delegate_) [toolbar_delegate_ setUrl:base::SysUTF8ToNSString(url)]; } - + void NativeWindowCocoa::SetToolbarIsLoading(bool loading) { if (toolbar_delegate_) [toolbar_delegate_ setIsLoading:loading]; @@ -792,7 +794,7 @@ - (NSRect)contentRectForFrameRect:(NSRect)frameRect { event.type == content::NativeWebKeyboardEvent::Char) return; - + DVLOG(1) << "NativeWindowCocoa::HandleKeyboardEvent - redispatch"; // // The event handling to get this strictly right is a tangle; cheat here a bit From 0c68d70f10324ce1b499ffb7f72e9fb4e8b9c84e Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 26 Mar 2014 10:29:36 +0800 Subject: [PATCH 068/492] access built-in menus Conflicts: src/api/dispatcher_bindings.cc --- nw.gypi | 1 + src/api/dispatcher_bindings.cc | 11 +++- src/api/dispatcher_bindings.h | 5 ++ src/api/dispatcher_bindings.js | 7 ++ src/api/dispatcher_bindings_mac.mm | 75 ++++++++++++++++++++++ src/api/menu/menu.js | 100 +++++++++++++++++++++++++++++ src/browser/app_controller_mac.mm | 2 + 7 files changed, 200 insertions(+), 1 deletion(-) create mode 100644 src/api/dispatcher_bindings_mac.mm diff --git a/nw.gypi b/nw.gypi index dcf96d61b7..94929c50c0 100644 --- a/nw.gypi +++ b/nw.gypi @@ -137,6 +137,7 @@ 'src/api/dispatcher.h', 'src/api/dispatcher_bindings.cc', 'src/api/dispatcher_bindings.h', + 'src/api/dispatcher_bindings_mac.mm', 'src/api/dispatcher_host.cc', 'src/api/dispatcher_host.h', 'src/api/window_bindings.cc', diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 358a633705..356da6ba57 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -48,6 +48,7 @@ namespace nwapi { namespace { + v8::Handle WrapSource(v8::Handle source) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::EscapableHandleScope handle_scope(isolate); @@ -118,6 +119,9 @@ DispatcherBindings::DispatcherBindings() NULL, // dependencies array. GetStringResource( IDR_NW_API_DISPATCHER_BINDINGS_JS).size()) { +#if defined(OS_MACOSX) + InitMsgIDMap(); +#endif } DispatcherBindings::~DispatcherBindings() { @@ -155,7 +159,12 @@ DispatcherBindings::GetNativeFunctionTemplate( return v8::FunctionTemplate::New(isolate, SetCrashDumpDir); else if (name->Equals(v8::String::NewFromUtf8(isolate, "AllocateId"))) return v8::FunctionTemplate::New(isolate, AllocateId); - +#if defined(OS_MACOSX) + else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetNSStringWithFixup"))) + return v8::FunctionTemplate::New(isolate, GetNSStringWithFixup); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetNSStringFWithFixup"))) + return v8::FunctionTemplate::New(isolate, GetNSStringFWithFixup); +#endif NOTREACHED() << "Trying to get an non-exist function in DispatcherBindings:" << *v8::String::Utf8Value(name); return v8::FunctionTemplate::New(isolate); diff --git a/src/api/dispatcher_bindings.h b/src/api/dispatcher_bindings.h index ecdca424d5..f44f23aedf 100644 --- a/src/api/dispatcher_bindings.h +++ b/src/api/dispatcher_bindings.h @@ -64,6 +64,11 @@ class DispatcherBindings : public v8::Extension { static void CallStaticMethodSync(const v8::FunctionCallbackInfo& args); static void CrashRenderer(const v8::FunctionCallbackInfo& args); static void SetCrashDumpDir(const v8::FunctionCallbackInfo& args); +#if defined(OS_MACOSX) + static void InitMsgIDMap(); + static void GetNSStringWithFixup(const v8::FunctionCallbackInfo& args); + static void GetNSStringFWithFixup(const v8::FunctionCallbackInfo& args); +#endif DISALLOW_COPY_AND_ASSIGN(DispatcherBindings); }; diff --git a/src/api/dispatcher_bindings.js b/src/api/dispatcher_bindings.js index 1dab320210..6c1939f505 100644 --- a/src/api/dispatcher_bindings.js +++ b/src/api/dispatcher_bindings.js @@ -38,6 +38,9 @@ var nwDispatcher = nwDispatcher || {}; native function CrashRenderer(); native function SetCrashDumpDir(); + native function GetNSStringWithFixup(); + native function GetNSStringFWithFixup(); + nwDispatcher.requireNwGui = RequireNwGui; // Request a new object from browser @@ -97,4 +100,8 @@ var nwDispatcher = nwDispatcher || {}; nwDispatcher.crashRenderer = CrashRenderer; nwDispatcher.setCrashDumpDir = SetCrashDumpDir; nwDispatcher.allocateId = AllocateId; + + nwDispatcher.getNSStringWithFixup = GetNSStringWithFixup; + nwDispatcher.getNSStringFWithFixup = GetNSStringFWithFixup; + })(); diff --git a/src/api/dispatcher_bindings_mac.mm b/src/api/dispatcher_bindings_mac.mm new file mode 100644 index 0000000000..a14b2a83cf --- /dev/null +++ b/src/api/dispatcher_bindings_mac.mm @@ -0,0 +1,75 @@ +#include "content/nw/src/api/dispatcher_bindings.h" + +#include + +#include "grit/nw_strings.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/base/l10n/l10n_util_mac.h" + +#import + +namespace nwapi { + +typedef struct { + std::string msgstr; + int msgid; +} MsgMapEntry; + +const MsgMapEntry msg_map[] = { + { "IDS_ABOUT_MAC", IDS_ABOUT_MAC }, + { "IDS_HIDE_APP_MAC", IDS_HIDE_APP_MAC}, + { "IDS_HIDE_OTHERS_MAC", IDS_HIDE_OTHERS_MAC}, + { "IDS_SHOW_ALL_MAC", IDS_SHOW_ALL_MAC }, + { "IDS_EXIT_MAC", IDS_EXIT_MAC }, + { "IDS_EDIT_MENU_MAC", IDS_EDIT_MENU_MAC }, + { "IDS_EDIT_UNDO_MAC", IDS_EDIT_UNDO_MAC }, + { "IDS_EDIT_REDO_MAC", IDS_EDIT_REDO_MAC }, + { "IDS_CUT_MAC", IDS_CUT_MAC }, + { "IDS_COPY_MAC", IDS_COPY_MAC }, + { "IDS_PASTE_MAC", IDS_PASTE_MAC }, + { "IDS_EDIT_DELETE_MAC", IDS_EDIT_DELETE_MAC }, + { "IDS_EDIT_SELECT_ALL_MAC", IDS_EDIT_SELECT_ALL_MAC }, + { "IDS_WINDOW_MENU_MAC", IDS_WINDOW_MENU_MAC }, + { "IDS_MINIMIZE_WINDOW_MAC", IDS_MINIMIZE_WINDOW_MAC }, + { "IDS_CLOSE_WINDOW_MAC", IDS_CLOSE_WINDOW_MAC }, + { "IDS_ALL_WINDOWS_FRONT_MAC", IDS_ALL_WINDOWS_FRONT_MAC }, +}; + +typedef base::hash_map MsgIDMap; +MsgIDMap g_msgid_map; + +void DispatcherBindings::InitMsgIDMap() { + g_msgid_map.clear(); + for (size_t i = 0; i < arraysize(msg_map); i++) { + g_msgid_map.insert(std::make_pair(msg_map[i].msgstr, msg_map[i].msgid)); + } +} + +// static +void DispatcherBindings::GetNSStringWithFixup( + const v8::FunctionCallbackInfo& args) { + std::string msgstr = *v8::String::Utf8Value(args[0]); + MsgIDMap::iterator it = g_msgid_map.find(msgstr); + if (it != g_msgid_map.end()) { + int msgid = it->second; + args.GetReturnValue().Set(v8::String::New([l10n_util::GetNSStringWithFixup(msgid) UTF8String])); + return; + } + args.GetReturnValue().Set(v8::Undefined()); +} + +// static +void DispatcherBindings::GetNSStringFWithFixup( + const v8::FunctionCallbackInfo& args) { + std::string msgstr = *v8::String::Utf8Value(args[0]); + base::string16 arg = *v8::String::Value(args[1]); + MsgIDMap::iterator it = g_msgid_map.find(msgstr); + if (it != g_msgid_map.end()) { + int msgid = it->second; + args.GetReturnValue().Set(v8::String::New([l10n_util::GetNSStringFWithFixup(msgid, arg) UTF8String])); + return; + } + args.GetReturnValue().Set(v8::Undefined()); +} + +} // namespace nwapi diff --git a/src/api/menu/menu.js b/src/api/menu/menu.js index c33bfd489c..c20a98033f 100644 --- a/src/api/menu/menu.js +++ b/src/api/menu/menu.js @@ -69,4 +69,104 @@ Menu.prototype.popup = function(x, y) { nw.callObjectMethod(this, 'Popup', [ x, y ]); } +if (require('os').platform() === 'darwin'){ + Menu.prototype.createMacBuiltin = function (app_name) { + var appleMenu = new Menu(); + appleMenu.append(new exports.MenuItem({ + label: nw.getNSStringFWithFixup("IDS_ABOUT_MAC", app_name), + selector: "orderFrontStandardAboutPanel:" + })); + appleMenu.append(new exports.MenuItem({ + type: "separator" + })); + appleMenu.append(new exports.MenuItem({ + label: nw.getNSStringFWithFixup("IDS_HIDE_APP_MAC", app_name), + selector: "hide:", + key: "h" + })); + appleMenu.append(new exports.MenuItem({ + label: nw.getNSStringFWithFixup("IDS_HIDE_OTHERS_MAC", app_name), + selector: "hideOtherApplications:", + key: "h", + modifiers: "cmd-alt" + })); + appleMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_SHOW_ALL_MAC"), + selector: "unhideAllApplications:", + })); + appleMenu.append(new exports.MenuItem({ + type: "separator" + })); + appleMenu.append(new exports.MenuItem({ + label: nw.getNSStringFWithFixup("IDS_EXIT_MAC", app_name), + selector: "closeAllWindowsQuit:", + key: "q" + })); + this.append(new exports.MenuItem({ label:'', submenu: appleMenu})); + + var editMenu = new Menu(); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_EDIT_UNDO_MAC"), + selector: "undo:", + key: "z" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_EDIT_REDO_MAC"), + selector: "redo:", + key: "z", + modifiers: "cmd-shift" + })); + editMenu.append(new exports.MenuItem({ + type: "separator" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_CUT_MAC"), + selector: "cut:", + key: "x" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_COPY_MAC"), + selector: "copy:", + key: "c" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_PASTE_MAC"), + selector: "paste:", + key: "v" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_EDIT_DELETE_MAC"), + selector: "delete:", + key: "" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_EDIT_SELECT_ALL_MAC"), + selector: "selectAll:", + key: "a" + })); + this.append(new exports.MenuItem({ label: nw.getNSStringWithFixup("IDS_EDIT_MENU_MAC"), + submenu: editMenu})); + + var winMenu = new Menu(); + winMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_MINIMIZE_WINDOW_MAC"), + selector: "performMiniaturize:", + key: "m" + })); + winMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_CLOSE_WINDOW_MAC"), + selector: "performClose:", + key: "w" + })); + winMenu.append(new exports.MenuItem({ + type: "separator" + })); + winMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_ALL_WINDOWS_FRONT_MAC"), + selector: "arrangeInFront:", + })); + this.append(new exports.MenuItem({ label: nw.getNSStringWithFixup("IDS_WINDOW_MENU_MAC"), + submenu: winMenu})); + } +} exports.Menu = Menu; diff --git a/src/browser/app_controller_mac.mm b/src/browser/app_controller_mac.mm index 2c329a7c89..e774be4178 100644 --- a/src/browser/app_controller_mac.mm +++ b/src/browser/app_controller_mac.mm @@ -66,12 +66,14 @@ - (void) applicationDidFinishLaunching: (NSNotification *) note { [NSApp setMainMenu:[[[NSMenu alloc] init] autorelease]]; [[NSApp mainMenu] addItem:[[[NSMenuItem alloc] initWithTitle:@"" action:nil keyEquivalent:@""] autorelease]]; +#if 0 nw::StandardMenusMac standard_menus( browser_client->shell_browser_main_parts()->package()->GetName()); standard_menus.BuildAppleMenu(); if (!no_edit_menu) standard_menus.BuildEditMenu(); standard_menus.BuildWindowMenu(); +#endif } - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication From 03f17be55e7bc64bd2fa9a9ffdf24ce0d0db8c6b Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 20 Jun 2014 09:45:52 +0800 Subject: [PATCH 069/492] Fix menu & shortcut support --- src/api/dispatcher_bindings.cc | 5 +++++ src/api/menuitem/menuitem_gtk.cc | 1 + 2 files changed, 6 insertions(+) diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 356da6ba57..0cba7e46da 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -164,6 +164,11 @@ DispatcherBindings::GetNativeFunctionTemplate( return v8::FunctionTemplate::New(isolate, GetNSStringWithFixup); else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetNSStringFWithFixup"))) return v8::FunctionTemplate::New(isolate, GetNSStringFWithFixup); +#else + else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetNSStringWithFixup"))) + return v8::FunctionTemplate::New(isolate); + else if (name->Equals(v8::String::NewFromUtf8(isolate, "GetNSStringFWithFixup"))) + return v8::FunctionTemplate::New(isolate); #endif NOTREACHED() << "Trying to get an non-exist function in DispatcherBindings:" << *v8::String::Utf8Value(name); diff --git a/src/api/menuitem/menuitem_gtk.cc b/src/api/menuitem/menuitem_gtk.cc index 9d32608447..f01651273f 100644 --- a/src/api/menuitem/menuitem_gtk.cc +++ b/src/api/menuitem/menuitem_gtk.cc @@ -31,6 +31,7 @@ void MenuItem::Create(const base::DictionaryValue& option) { std::string type; option.GetString("type", &type); submenu_ = NULL; + gtk_accel_group = NULL; if (type == "separator") { menu_item_ = gtk_separator_menu_item_new(); From b0b72b40aef07b74e44db3ea88e0f783140e16b2 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 20 Jun 2014 09:46:01 +0800 Subject: [PATCH 070/492] Fix menu testcase --- tests/manual_tests/menu/index.html | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/manual_tests/menu/index.html b/tests/manual_tests/menu/index.html index 2ad4665f53..e1e772fa4b 100644 --- a/tests/manual_tests/menu/index.html +++ b/tests/manual_tests/menu/index.html @@ -196,7 +196,6 @@ menubar.append(new gui.MenuItem({ label: 'Sub2', submenu: sub2})); win.menu = menubar; - gc(); + + \ No newline at end of file diff --git a/tests/automatic_tests/inject-js/mocha_test.js b/tests/automatic_tests/inject-js/mocha_test.js new file mode 100644 index 0000000000..cd353d30c3 --- /dev/null +++ b/tests/automatic_tests/inject-js/mocha_test.js @@ -0,0 +1,59 @@ +var path = require('path'); +var spawn = require('child_process').spawn; +var server = global.server; +var server_port = global.port; +var assert = require('assert'); + + + +describe('inject-js',function(){ + var result = null; + var child = null; + + var connection_handler_callback = undefined; + var connection_handler = function(socket){ + socket.on('data',function(data){ + result = JSON.parse(data); + if (typeof connection_handler_callback === 'function'){ + (connection_handler_callback)(); + } + }); + }; + + before(function(done){ + this.timeout(0); + var app_path = path.join(global.tests_dir,'inject-js'); + var exec_argv = [app_path,server_port]; + child = spawn(process.execPath,exec_argv); + server.on('connection',connection_handler); + connection_handler_callback = done; + }); + + after(function(done){ + server.removeListener('connection',connection_handler); + child.kill(); + done(); + }); + + it('result.length should equal 4',function(done){ + assert.notEqual(result,null); + assert.equal(result.length,4); + done(); + }); + it('inject-js-start should run first',function(done){ + assert.equal(result[0],'inject-js-start'); + done(); + }); + it('document script should run after inject-js-start',function(done){ + assert.equal(result[1],'script-start'); + done(); + }); + it('inject-js-end should before window.onload',function(done){ + assert.equal(result[2],'inject-js-end'); + done(); + }); + it('inject-js-start should run last',function(done){ + assert.equal(result[3],'onload'); + done(); + }); +}); \ No newline at end of file diff --git a/tests/automatic_tests/inject-js/package.json b/tests/automatic_tests/inject-js/package.json new file mode 100644 index 0000000000..d36df79c46 --- /dev/null +++ b/tests/automatic_tests/inject-js/package.json @@ -0,0 +1,6 @@ +{ + "name":"nw_1403514049", + "main":"index.html", + "inject-js-end":"./end.js", + "inject-js-start":"./start.js" +} \ No newline at end of file diff --git a/tests/automatic_tests/inject-js/start.js b/tests/automatic_tests/inject-js/start.js new file mode 100644 index 0000000000..5dd62d1045 --- /dev/null +++ b/tests/automatic_tests/inject-js/start.js @@ -0,0 +1,6 @@ +var result = result ||[]; +result.push('inject-js-start'); + +window.onload = function(){ + result.push('onload') +}; \ No newline at end of file diff --git a/tests/automatic_tests/window-document-event/iframe.html b/tests/automatic_tests/window-document-event/iframe.html new file mode 100644 index 0000000000..bdcdcbb44e --- /dev/null +++ b/tests/automatic_tests/window-document-event/iframe.html @@ -0,0 +1,13 @@ + + + + + + + +

    Iframe

    + + + \ No newline at end of file diff --git a/tests/automatic_tests/window-document-event/index.html b/tests/automatic_tests/window-document-event/index.html new file mode 100644 index 0000000000..a3c77ec8ec --- /dev/null +++ b/tests/automatic_tests/window-document-event/index.html @@ -0,0 +1,60 @@ + + + + + test + + +

    it works!

    + + + + \ No newline at end of file diff --git a/tests/automatic_tests/window-document-event/mocha_test.js b/tests/automatic_tests/window-document-event/mocha_test.js new file mode 100644 index 0000000000..8d1f0a4efc --- /dev/null +++ b/tests/automatic_tests/window-document-event/mocha_test.js @@ -0,0 +1,77 @@ +var path = require('path'); +var spawn = require('child_process').spawn; +var server = global.server; +var server_port = global.port; +var assert = require('assert'); + +describe('document-start/end',function(){ + + var results = undefined; + var connection_handler_callback = undefined; + var connection_handler = function(socket){ + socket.on('data',function(data){ + results = JSON.parse(data+""); + if (typeof connection_handler_callback == 'function'){ + (connection_handler_callback)(); + } + }) + }; + var child = null; + before(function(done){ + this.timeout(0); + server.on('connection',connection_handler); + var app_path = path.join(global.tests_dir,'window-document-event'); + var exec_argv = [app_path,server_port]; + child = spawn(process.execPath,exec_argv); + connection_handler_callback = done; + //we call done when we receive data from child + }); + after(function(done){ + server.removeListener('connection',connection_handler); + child.kill(); + done(); + }); + + it('results should not equal undefined',function(done){ + assert.notEqual(results,undefined); + done(); + }) + + it('new window document-start run first',function(done){ + assert.equal(results[0]['flag'],true) + assert.equal(results[0]['name'],'top-window-document-start') + done(); + }); + it('new window script run between document-start and document-end',function(done){ + assert.equal(results[1],'new-window-script'); + done(); + }); + it('new window document-end should run before onload event',function(done){ + assert.equal(results[2]['flag'],true) + assert.equal(results[2]['name'],'top-window-document-end') + done(); + }); + it('new window onload should run last',function(done){ + assert.equal(results[3],'onload-from-new-window'); + done(); + }); + + it('iframe document-start should run first',function(done){ + assert.equal(results[4]['flag'],true) + assert.equal(results[4]['name'],'iframe-document-start') + done(); + }); + it('iframe script run between document-start and document-end',function(done){ + assert.equal(results[5],'iframe-script'); + done(); + }); + it('iframe document-end should run later',function(done){ + assert.equal(results[6]['flag'],true) + assert.equal(results[6]['name'],'iframe-document-end') + done(); + }); + it('iframe onload should run last',function(done){ + assert.equal(results[7],'onload-from-iframe'); + done(); + }); +}); \ No newline at end of file diff --git a/tests/automatic_tests/window-document-event/new_win.html b/tests/automatic_tests/window-document-event/new_win.html new file mode 100644 index 0000000000..aa328ef904 --- /dev/null +++ b/tests/automatic_tests/window-document-event/new_win.html @@ -0,0 +1,17 @@ + + + + + + + +

    New Window

    + + + + \ No newline at end of file diff --git a/tests/automatic_tests/window-document-event/package.json b/tests/automatic_tests/window-document-event/package.json new file mode 100644 index 0000000000..85ea1d2a75 --- /dev/null +++ b/tests/automatic_tests/window-document-event/package.json @@ -0,0 +1,5 @@ +{ + "name":"nw_1403587578", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file diff --git a/tests/automatic_tests/window-eval/iframe.html b/tests/automatic_tests/window-eval/iframe.html new file mode 100644 index 0000000000..ab1d2c0ffa --- /dev/null +++ b/tests/automatic_tests/window-eval/iframe.html @@ -0,0 +1,14 @@ + + + + + test + + +

    iframe

    + + + + \ No newline at end of file diff --git a/tests/automatic_tests/window-eval/index.html b/tests/automatic_tests/window-eval/index.html new file mode 100644 index 0000000000..8df0e04e5a --- /dev/null +++ b/tests/automatic_tests/window-eval/index.html @@ -0,0 +1,32 @@ + + + + + test + + +

    it works!

    + + + + + \ No newline at end of file diff --git a/tests/automatic_tests/window-eval/mocha_test.js b/tests/automatic_tests/window-eval/mocha_test.js new file mode 100644 index 0000000000..f595fbbb74 --- /dev/null +++ b/tests/automatic_tests/window-eval/mocha_test.js @@ -0,0 +1,42 @@ +var server = global.server; +var server_port = global.port; +var result = false; +var assert = require('assert'); +var spawn = require('child_process').spawn; +var path = require('path'); + +var connection_handler_callback = undefined; +var connection_handler = function(socket){ + socket.on('data',function(data){ + if (data.toString() == "success"){ + result = true; + } + if (typeof connection_handler_callback === 'function'){ + (connection_handler_callback)(); + } + }) +}; + +describe('Window.eval',function(){ + var child = null; + + before(function(done){ + this.timeout(0); + server.on('connection',connection_handler); + var app_path = path.join(global.tests_dir,'window-eval'); + var exec_args = [app_path,server_port]; + child = spawn(process.execPath,exec_args); + connection_handler_callback = done; + }); + + after(function(done){ + server.removeListener('connection',connection_handler); + child.kill(); + done(); + }); + + it("Window.eval should works",function(done){ + assert.equal(result,true); + done(); + }); +}) \ No newline at end of file diff --git a/tests/automatic_tests/window-eval/package.json b/tests/automatic_tests/window-eval/package.json new file mode 100644 index 0000000000..a33ab28774 --- /dev/null +++ b/tests/automatic_tests/window-eval/package.json @@ -0,0 +1,5 @@ +{ + "name":"nw_1403254112", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file diff --git a/tests/manual_tests/capture_page/index.html b/tests/manual_tests/capture_page/index.html new file mode 100644 index 0000000000..3b9f43407b --- /dev/null +++ b/tests/manual_tests/capture_page/index.html @@ -0,0 +1,58 @@ + + + + + + +
    +

    Please wait 1s for nw to render page

    +

    If you see a capture in popup window, this case passes

    +
    + +
    +
    + + diff --git a/tests/manual_tests/capture_page/package.json b/tests/manual_tests/capture_page/package.json new file mode 100644 index 0000000000..a4b8075bcc --- /dev/null +++ b/tests/manual_tests/capture_page/package.json @@ -0,0 +1,5 @@ +{ + "name":"nw_1403500501", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file diff --git a/tests/manual_tests/capture_page/popup.html b/tests/manual_tests/capture_page/popup.html new file mode 100644 index 0000000000..1b8fe22c83 --- /dev/null +++ b/tests/manual_tests/capture_page/popup.html @@ -0,0 +1,23 @@ + + + Popup window + + + +
    + + +
    +
    + + + + +
    + + \ No newline at end of file diff --git a/tests/manual_tests/drag_window/index.html b/tests/manual_tests/drag_window/index.html new file mode 100644 index 0000000000..c5db2bb4f2 --- /dev/null +++ b/tests/manual_tests/drag_window/index.html @@ -0,0 +1,26 @@ + + + + + + + + + +
    +

    Drag me

    +

    Moviable -> Success

    +

    Otherwise -> Fail

    +
    + + + \ No newline at end of file diff --git a/tests/manual_tests/drag_window/package.json b/tests/manual_tests/drag_window/package.json new file mode 100644 index 0000000000..462d8ec405 --- /dev/null +++ b/tests/manual_tests/drag_window/package.json @@ -0,0 +1,8 @@ +{ + "name":"nw_drag_window", + "main":"index.html", + "window":{ + "toolbar":false, + "frame":false + } +} \ No newline at end of file diff --git a/tests/manual_tests/new_win_policy/app/iframe.html b/tests/manual_tests/new_win_policy/app/iframe.html new file mode 100644 index 0000000000..8e8dbe6dac --- /dev/null +++ b/tests/manual_tests/new_win_policy/app/iframe.html @@ -0,0 +1,17 @@ + + + + + test + + +

    iframe

    + IFRAME MANUAL CLICK LINK + + + + \ No newline at end of file diff --git a/tests/manual_tests/new_win_policy/app/index.html b/tests/manual_tests/new_win_policy/app/index.html new file mode 100644 index 0000000000..f8c9fe706b --- /dev/null +++ b/tests/manual_tests/new_win_policy/app/index.html @@ -0,0 +1,61 @@ + + + + + test + + + WINDOW MANUAL CLICK LINK + + + + + \ No newline at end of file diff --git a/tests/manual_tests/new_win_policy/app/package.json b/tests/manual_tests/new_win_policy/app/package.json new file mode 100644 index 0000000000..4a1a3c79a7 --- /dev/null +++ b/tests/manual_tests/new_win_policy/app/package.json @@ -0,0 +1,7 @@ +{ + "name":"nw_1403592293", + "main":"index.html", + "dependencies":{}, + "window":{ + } +} \ No newline at end of file diff --git a/tests/manual_tests/new_win_policy/index.html b/tests/manual_tests/new_win_policy/index.html new file mode 100644 index 0000000000..7bafa87bc3 --- /dev/null +++ b/tests/manual_tests/new_win_policy/index.html @@ -0,0 +1,74 @@ + + + + + test + + + + + +
    +
      +
    • ignore() => ignore the request, navigation won't happen.
    • +
    • forceCurrent() => force the link to be opened in the same frame.
    • +
    • forceDownload() => force the link to be a downloadable, or open by external program.
    • +
    • forceNewWindow() => force the link to be opened in a new window.
    • +
    • forceNewPopup() => force the link to be opened in a new popup window
    • +
    • Please make sure there are no overlapping windows when running this case
    • +
    +
    + +
    +

    From Top Window

    +
    +
    +
    +
    +
    +
    +
    + +
    +

    From Iframe

    +
    +
    +
    +
    +
    +
    +
    + + + + \ No newline at end of file diff --git a/tests/manual_tests/new_win_policy/package.json b/tests/manual_tests/new_win_policy/package.json new file mode 100644 index 0000000000..2dd65fd458 --- /dev/null +++ b/tests/manual_tests/new_win_policy/package.json @@ -0,0 +1,5 @@ +{ + "name":"nw_1403590714", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file diff --git a/tests/manual_tests/skip_taskbar/app/index.html b/tests/manual_tests/skip_taskbar/app/index.html new file mode 100644 index 0000000000..40468dff9c --- /dev/null +++ b/tests/manual_tests/skip_taskbar/app/index.html @@ -0,0 +1,16 @@ + + + + + test + + +

    + + + + \ No newline at end of file diff --git a/tests/manual_tests/skip_taskbar/index.html b/tests/manual_tests/skip_taskbar/index.html new file mode 100644 index 0000000000..15cf5f6a77 --- /dev/null +++ b/tests/manual_tests/skip_taskbar/index.html @@ -0,0 +1,178 @@ + + + + + + test + + + + + + + +
    +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    + +
    +
    +

    +
    +
    +
    + + + + diff --git a/tests/manual_tests/skip_taskbar/package.json b/tests/manual_tests/skip_taskbar/package.json new file mode 100644 index 0000000000..b3912d1507 --- /dev/null +++ b/tests/manual_tests/skip_taskbar/package.json @@ -0,0 +1,5 @@ +{ + "name":"nw_1403508585", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file From e1de61fa158d813d18719d239537e4c7b6a4a0bd Mon Sep 17 00:00:00 2001 From: gitchs Date: Wed, 25 Jun 2014 14:45:19 +0800 Subject: [PATCH 089/492] Update node-main test case --- tests/automatic_tests/node-main/mocha_test.js | 25 +++++++-- .../reference-node-main/index.html | 51 +++++++++++++++++++ .../reference-node-main/index.js | 24 +++++++++ .../reference-node-main/package.json | 6 +++ 4 files changed, 102 insertions(+), 4 deletions(-) create mode 100644 tests/automatic_tests/reference-node-main/index.html create mode 100644 tests/automatic_tests/reference-node-main/index.js create mode 100644 tests/automatic_tests/reference-node-main/package.json diff --git a/tests/automatic_tests/node-main/mocha_test.js b/tests/automatic_tests/node-main/mocha_test.js index 4205726b60..101d0daded 100644 --- a/tests/automatic_tests/node-main/mocha_test.js +++ b/tests/automatic_tests/node-main/mocha_test.js @@ -1,5 +1,6 @@ var path = require('path'); var app_test = require('./nw_test_app'); +var assert = require('assert'); describe('node-main', function() { describe('create http server in node-main', function() { @@ -33,8 +34,8 @@ describe('node-main', function() { }, 3000); //child.app.stderr.on('data', function(d){ console.log ('app' + d);}); - }) - }) + }) + }); describe('call require() in app', function() { it('nw should can require modules', function(done) { @@ -53,6 +54,22 @@ describe('node-main', function() { } }); }) - }) + }); + + describe('reference node-main module',function(){ + it('nw should be able to reference node-main module',function(done){ + this.timeout(0); + + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'reference-node-main'), + end: function(data, app) { + app.kill(); + assert.equal(data,true); + done(); + } + }); + }); + }); -}) \ No newline at end of file +}) diff --git a/tests/automatic_tests/reference-node-main/index.html b/tests/automatic_tests/reference-node-main/index.html new file mode 100644 index 0000000000..6337e14bed --- /dev/null +++ b/tests/automatic_tests/reference-node-main/index.html @@ -0,0 +1,51 @@ + + + + + test + + + + + + \ No newline at end of file diff --git a/tests/automatic_tests/reference-node-main/index.js b/tests/automatic_tests/reference-node-main/index.js new file mode 100644 index 0000000000..04b94f07a4 --- /dev/null +++ b/tests/automatic_tests/reference-node-main/index.js @@ -0,0 +1,24 @@ +exports.message = "hello world"; +exports.port = 10000; +exports.ready = false; + +var server = require('net').createServer(); +server.on('connection',function(socket){ + socket.on('data',function(data){ + socket.write(data); + }); +}); + +server.on('error',function(){ + try{ + server.close(); + }catch(e){ + exports.port += 1; + setTimeout(function(){ + server.listen(exports.port); + },0); + } +}); +server.listen(exports.port,function(){ + exports.ready = true; +}); diff --git a/tests/automatic_tests/reference-node-main/package.json b/tests/automatic_tests/reference-node-main/package.json new file mode 100644 index 0000000000..486c567b08 --- /dev/null +++ b/tests/automatic_tests/reference-node-main/package.json @@ -0,0 +1,6 @@ +{ + "name":"nw_1403596464", + "main":"index.html", + "dependencies":{}, + "node-main":"./index.js" +} \ No newline at end of file From 6e48dd5250d4ddeb2d42fd9dcdf11f8a476adadb Mon Sep 17 00:00:00 2001 From: "Chaobin,Zhang" Date: Thu, 27 Mar 2014 13:24:19 +0800 Subject: [PATCH 090/492] [API] Implement register/unregister global desktop keyboard shortcut on Winodws. - Introduce GlobalShortcutListener; - New api object: Shortcut({'key': '...', 'active': ..., 'failed': ...}); - New api: App.registerGlobalHotkey, App.unregisterGlobalHotkey. --- nw.gypi | 8 + src/api/app/app.cc | 24 +- src/api/app/app.js | 15 + src/api/dispatcher_bindings.cc | 2 + src/api/dispatcher_host.cc | 5 + src/api/dispatcher_host.h | 5 +- src/api/shortcut/global_shortcut_listener.cc | 138 +++++++ src/api/shortcut/global_shortcut_listener.h | 115 ++++++ .../shortcut/global_shortcut_listener_mac.h | 122 ++++++ .../shortcut/global_shortcut_listener_mac.mm | 391 ++++++++++++++++++ .../shortcut/global_shortcut_listener_win.cc | 121 ++++++ .../shortcut/global_shortcut_listener_win.h | 67 +++ .../shortcut/global_shortcut_listener_x11.cc | 197 +++++++++ .../shortcut/global_shortcut_listener_x11.h | 89 ++++ src/api/shortcut/shorcut.js | 66 +++ src/api/shortcut/shortcut.cc | 163 ++++++++ src/api/shortcut/shortcut.h | 55 +++ src/api/shortcut/shortcut_constants.cc | 49 +++ src/api/shortcut/shortcut_constants.h | 52 +++ src/resources/nw_resources.grd | 1 + 20 files changed, 1679 insertions(+), 6 deletions(-) create mode 100644 src/api/shortcut/global_shortcut_listener.cc create mode 100644 src/api/shortcut/global_shortcut_listener.h create mode 100644 src/api/shortcut/global_shortcut_listener_mac.h create mode 100644 src/api/shortcut/global_shortcut_listener_mac.mm create mode 100644 src/api/shortcut/global_shortcut_listener_win.cc create mode 100644 src/api/shortcut/global_shortcut_listener_win.h create mode 100644 src/api/shortcut/global_shortcut_listener_x11.cc create mode 100644 src/api/shortcut/global_shortcut_listener_x11.h create mode 100644 src/api/shortcut/shorcut.js create mode 100644 src/api/shortcut/shortcut.cc create mode 100644 src/api/shortcut/shortcut.h create mode 100644 src/api/shortcut/shortcut_constants.cc create mode 100644 src/api/shortcut/shortcut_constants.h diff --git a/nw.gypi b/nw.gypi index d16e9b5126..13edf09394 100644 --- a/nw.gypi +++ b/nw.gypi @@ -159,6 +159,14 @@ 'src/api/menuitem/menuitem_delegate_mac.mm', 'src/api/shell/shell.cc', 'src/api/shell/shell.h', + 'src/api/shortcut/global_shortcut_listener.cc', + 'src/api/shortcut/global_shortcut_listener.h', + 'src/api/shortcut/global_shortcut_listener_win.cc', + 'src/api/shortcut/global_shortcut_listener_win.h', + 'src/api/shortcut/shortcut.cc', + 'src/api/shortcut/shortcut.h', + 'src/api/shortcut/shortcut_constants.cc', + 'src/api/shortcut/shortcut_constants.h', 'src/api/tray/tray.cc', 'src/api/tray/tray.h', 'src/api/tray/tray_gtk.cc', diff --git a/src/api/app/app.cc b/src/api/app/app.cc index e6481ffdeb..88fc6d7d07 100644 --- a/src/api/app/app.cc +++ b/src/api/app/app.cc @@ -25,6 +25,9 @@ #include "base/message_loop/message_loop.h" #include "base/values.h" #include "content/nw/src/api/api_messages.h" +#include "content/nw/src/api/dispatcher_host.h" +#include "content/nw/src/api/shortcut/global_shortcut_listener.h" +#include "content/nw/src/api/shortcut/shortcut.h" #include "content/nw/src/breakpad_linux.h" #include "content/nw/src/browser/native_window.h" #include "content/nw/src/browser/net_disk_cache_remover.h" @@ -76,18 +79,31 @@ void App::Call(const std::string& method, const base::ListValue& arguments) { if (method == "Quit") { Quit(); - return; } else if (method == "CloseAllWindows") { CloseAllWindows(); - return; } else if (method == "CrashBrowser") { int* ptr = NULL; *ptr = 1; + } else if (method == "RegisterGlobalHotKey") { + int object_id = -1; + arguments.GetInteger(0, &object_id); + Shortcut* shortcut = + static_cast(DispatcherHost::GetApiObject(object_id)); + bool success = GlobalShortcutListener::GetInstance()->RegisterAccelerator( + shortcut->GetAccelerator(), shortcut); + if (!success) + shortcut->OnFailed("Register global desktop keyboard shortcut failed."); + } else if (method == "UnregisterGlobalHotKey") { + int object_id = -1; + arguments.GetInteger(0, &object_id); + Shortcut* shortcut = + static_cast(DispatcherHost::GetApiObject(object_id)); + GlobalShortcutListener::GetInstance()->UnregisterAccelerators(shortcut); + } else { + NOTREACHED() << "Calling unknown method " << method << " of App."; } - NOTREACHED() << "Calling unknown method " << method << " of App"; } - // static void App::Call(Shell* shell, const std::string& method, diff --git a/src/api/app/app.js b/src/api/app/app.js index b78410e570..8fa4d03640 100644 --- a/src/api/app/app.js +++ b/src/api/app/app.js @@ -19,6 +19,7 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. var argv, fullArgv, dataPath, manifest; +var v8_util = process.binding('v8_util'); function App() { } @@ -68,6 +69,20 @@ App.prototype.removeOriginAccessWhitelistEntry = function(sourceOrigin, destinat return nw.callStaticMethodSync('App', 'RemoveOriginAccessWhitelistEntry', sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains); } +App.prototype.registerGlobalHotKey = function(shortcut) { + if (v8_util.getConstructorName(shortcut) != "Shortcut") + throw new TypeError("Invaild parameter, need Shortcut object."); + + nw.callStaticMethod('App', 'RegisterGlobalHotKey', [ shortcut.id ]); +} + +App.prototype.unregisterGlobalHotKey = function(shortcut) { + if (v8_util.getConstructorName(shortcut) != "Shortcut") + throw new TypeError("Invaild parameter, need Shortcut object."); + + nw.callStaticMethod('App', 'UnregisterGlobalHotKey', [ shortcut.id ]); +} + App.prototype.__defineGetter__('argv', function() { if (!argv) { var fullArgv = this.fullArgv; diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 0cba7e46da..10987a574c 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -214,6 +214,8 @@ DispatcherBindings::RequireNwGui(const v8::FunctionCallbackInfo& args NwGui, global, v8::String::NewFromUtf8(isolate, "shell.js"), IDR_NW_API_SHELL_JS); RequireFromResource(args.This(), NwGui, global, v8::String::NewFromUtf8(isolate, "app.js"), IDR_NW_API_APP_JS); + RequireFromResource(args.This(), + NwGui, global, v8::String::NewFromUtf8("shortcut.js"), IDR_NW_API_SHORTCUT_JS); g_context->Exit(); args.GetReturnValue().Set(handle_scope.Escape(NwGui)); diff --git a/src/api/dispatcher_host.cc b/src/api/dispatcher_host.cc index 39a7e4f1f9..350d4899ef 100644 --- a/src/api/dispatcher_host.cc +++ b/src/api/dispatcher_host.cc @@ -32,6 +32,7 @@ #include "content/nw/src/api/menu/menu.h" #include "content/nw/src/api/menuitem/menuitem.h" #include "content/nw/src/api/shell/shell.h" +#include "content/nw/src/api/shortcut/shortcut.h" #include "content/nw/src/api/tray/tray.h" #include "content/nw/src/api/window/window.h" #include "content/nw/src/common/shell_switches.h" @@ -79,10 +80,12 @@ void DispatcherHost::ClearObjectRegistry() { objects_registry_.Clear(); } +// static Base* DispatcherHost::GetApiObject(int id) { return objects_registry_.Lookup(id); } +// static int DispatcherHost::AllocateId() { return next_object_id_++; } @@ -152,6 +155,8 @@ void DispatcherHost::OnAllocateObject(int object_id, new Clipboard(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); } else if (type == "Window") { objects_registry_.AddWithID(new Window(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); + } else if (type == "Shortcut") { + objects_registry_.AddWithID(new Shortcut(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); } else { LOG(ERROR) << "Allocate an object of unknown type: " << type; objects_registry_.AddWithID(new Base(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); diff --git a/src/api/dispatcher_host.h b/src/api/dispatcher_host.h index 2df23476a6..e9384ca98e 100644 --- a/src/api/dispatcher_host.h +++ b/src/api/dispatcher_host.h @@ -52,12 +52,13 @@ class DispatcherHost : public content::WebContentsObserver { virtual ~DispatcherHost(); // Get C++ object from its id. - Base* GetApiObject(int id); + static Base* GetApiObject(int id); static int AllocateId(); + // Helper function to convert type. template - T* GetApiObject(int id) { + static T* GetApiObject(int id) { return static_cast(GetApiObject(id)); } diff --git a/src/api/shortcut/global_shortcut_listener.cc b/src/api/shortcut/global_shortcut_listener.cc new file mode 100644 index 0000000000..a27de1f752 --- /dev/null +++ b/src/api/shortcut/global_shortcut_listener.cc @@ -0,0 +1,138 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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/shortcut/global_shortcut_listener.h" + +#include "base/logging.h" +#include "content/public/browser/browser_thread.h" +#include "ui/base/accelerators/accelerator.h" + +using content::BrowserThread; + +namespace nwapi { + +GlobalShortcutListener::GlobalShortcutListener() + : shortcut_handling_suspended_(false) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + +GlobalShortcutListener::~GlobalShortcutListener() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(accelerator_map_.empty()); // Make sure we've cleaned up. +} + +bool GlobalShortcutListener::RegisterAccelerator( + const ui::Accelerator& accelerator, Observer* observer) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (IsShortcutHandlingSuspended()) + return false; + + AcceleratorMap::const_iterator it = accelerator_map_.find(accelerator); + if (it != accelerator_map_.end()) { + // The accelerator has been registered. + return false; + } + + if (!RegisterAcceleratorImpl(accelerator)) { + // If the platform-specific registration fails, mostly likely the shortcut + // has been registered by other native applications. + return false; + } + + if (accelerator_map_.empty()) + StartListening(); + + accelerator_map_[accelerator] = observer; + return true; +} + +void GlobalShortcutListener::UnregisterAccelerator( + const ui::Accelerator& accelerator, Observer* observer) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (IsShortcutHandlingSuspended()) + return; + + AcceleratorMap::iterator it = accelerator_map_.find(accelerator); + // We should never get asked to unregister something that we didn't register. + DCHECK(it != accelerator_map_.end()); + // The caller should call this function with the right observer. + DCHECK(it->second == observer); + + UnregisterAcceleratorImpl(accelerator); + accelerator_map_.erase(it); + if (accelerator_map_.empty()) + StopListening(); +} + +void GlobalShortcutListener::UnregisterAccelerators(Observer* observer) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (IsShortcutHandlingSuspended()) + return; + + AcceleratorMap::iterator it = accelerator_map_.begin(); + while (it != accelerator_map_.end()) { + if (it->second == observer) { + AcceleratorMap::iterator to_remove = it++; + UnregisterAccelerator(to_remove->first, observer); + } else { + ++it; + } + } +} + +void GlobalShortcutListener::SetShortcutHandlingSuspended(bool suspended) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + if (shortcut_handling_suspended_ == suspended) + return; + + shortcut_handling_suspended_ = suspended; + for (AcceleratorMap::iterator it = accelerator_map_.begin(); + it != accelerator_map_.end(); + ++it) { + // On Linux, when shortcut handling is suspended we cannot simply early + // return in NotifyKeyPressed (similar to what we do for non-global + // shortcuts) because we'd eat the keyboard event thereby preventing the + // user from setting the shortcut. Therefore we must unregister while + // handling is suspended and register when handling resumes. + if (shortcut_handling_suspended_) + UnregisterAcceleratorImpl(it->first); + else + RegisterAcceleratorImpl(it->first); + } +} + +bool GlobalShortcutListener::IsShortcutHandlingSuspended() const { + return shortcut_handling_suspended_; +} + +void GlobalShortcutListener::NotifyKeyPressed( + const ui::Accelerator& accelerator) { + AcceleratorMap::iterator iter = accelerator_map_.find(accelerator); + if (iter == accelerator_map_.end()) { + // This should never occur, because if it does, we have failed to unregister + // or failed to clean up the map after unregistering the shortcut. + NOTREACHED(); + return; // No-one is listening to this key. + } + + iter->second->OnKeyPressed(accelerator); +} + +} // namespace nwapi diff --git a/src/api/shortcut/global_shortcut_listener.h b/src/api/shortcut/global_shortcut_listener.h new file mode 100644 index 0000000000..633aca7658 --- /dev/null +++ b/src/api/shortcut/global_shortcut_listener.h @@ -0,0 +1,115 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_H_ +#define CONTENT_NW_SRC_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_H_ + +#include + +#include "base/basictypes.h" +#include "ui/events/keycodes/keyboard_codes.h" + +namespace ui { +class Accelerator; +} + +namespace nwapi { + +// Platform-neutral implementation of a class that keeps track of observers and +// monitors keystrokes. It relays messages to the appropriate observer when a +// global shortcut has been struck by the user. +class GlobalShortcutListener { + public: + class Observer { + public: + // Called when your global shortcut (|accelerator|) is struck. + virtual void OnKeyPressed(const ui::Accelerator& accelerator) = 0; + }; + + virtual ~GlobalShortcutListener(); + + static GlobalShortcutListener* GetInstance(); + + // Register an observer for when a certain |accelerator| is struck. Returns + // true if register successfully, or false if 1) the specificied |accelerator| + // has been registered by another caller or other native applications, or + // 2) shortcut handling is suspended. + // + // Note that we do not support recognizing that an accelerator has been + // registered by another application on all platforms. This is a per-platform + // consideration. + bool RegisterAccelerator(const ui::Accelerator& accelerator, + Observer* observer); + + // Stop listening for the given |accelerator|, does nothing if shortcut + // handling is suspended. + void UnregisterAccelerator(const ui::Accelerator& accelerator, + Observer* observer); + + // Stop listening for all accelerators of the given |observer|, does nothing + // if shortcut handling is suspended. + void UnregisterAccelerators(Observer* observer); + + // Suspend/Resume global shortcut handling. Note that when suspending, + // RegisterAccelerator/UnregisterAccelerator/UnregisterAccelerators are not + // allowed to be called until shortcut handling has been resumed. + void SetShortcutHandlingSuspended(bool suspended); + + // Returns whether shortcut handling is currently suspended. + bool IsShortcutHandlingSuspended() const; + + protected: + GlobalShortcutListener(); + + // Called by platform specific implementations of this class whenever a key + // is struck. Only called for keys that have an observer registered. + void NotifyKeyPressed(const ui::Accelerator& accelerator); + + private: + // The following methods are implemented by platform-specific implementations + // of this class. + // + // Start/StopListening are called when transitioning between zero and nonzero + // registered accelerators. StartListening will be called after + // RegisterAcceleratorImpl and StopListening will be called after + // UnregisterAcceleratorImpl. + // + // For RegisterAcceleratorImpl, implementations return false if registration + // did not complete successfully. + virtual void StartListening() = 0; + virtual void StopListening() = 0; + virtual bool RegisterAcceleratorImpl(const ui::Accelerator& accelerator) = 0; + virtual void UnregisterAcceleratorImpl( + const ui::Accelerator& accelerator) = 0; + + // The map of accelerators that have been successfully registered as global + // shortcuts and their observer. + typedef std::map AcceleratorMap; + AcceleratorMap accelerator_map_; + + // Keeps track of whether shortcut handling is currently suspended. + bool shortcut_handling_suspended_; + + DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListener); +}; + +} // namespace nwapi + +#endif // CONTENT_NW_SRC_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_H_ diff --git a/src/api/shortcut/global_shortcut_listener_mac.h b/src/api/shortcut/global_shortcut_listener_mac.h new file mode 100644 index 0000000000..d1ed0d6354 --- /dev/null +++ b/src/api/shortcut/global_shortcut_listener_mac.h @@ -0,0 +1,122 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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 CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_ +#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_ + +#include "chrome/browser/extensions/global_shortcut_listener.h" + +#include +#include + +#include + +#include "base/mac/scoped_nsobject.h" + +namespace extensions { + +// Mac-specific implementation of the GlobalShortcutListener class that +// listens for global shortcuts. Handles basic keyboard intercepting and +// forwards its output to the base class for processing. +// +// This class does two things: +// 1. Intercepts media keys. Uses an event tap for intercepting media keys +// (PlayPause, NextTrack, PreviousTrack). +// 2. Binds keyboard shortcuts (hot keys). Carbon RegisterEventHotKey API for +// binding to non-media key global hot keys (eg. Command-Shift-1). +class GlobalShortcutListenerMac : public GlobalShortcutListener { + public: + GlobalShortcutListenerMac(); + virtual ~GlobalShortcutListenerMac(); + + private: + typedef int KeyId; + typedef std::map AcceleratorIdMap; + typedef std::map IdAcceleratorMap; + typedef std::map IdHotKeyRefMap; + + // Keyboard event callbacks. + void OnHotKeyEvent(EventHotKeyID hot_key_id); + bool OnMediaKeyEvent(int key_code); + + // GlobalShortcutListener implementation. + virtual void StartListening() OVERRIDE; + virtual void StopListening() OVERRIDE; + virtual bool RegisterAcceleratorImpl( + const ui::Accelerator& accelerator) OVERRIDE; + virtual void UnregisterAcceleratorImpl( + const ui::Accelerator& accelerator) OVERRIDE; + + // Mac-specific functions for registering hot keys with modifiers. + bool RegisterHotKey(const ui::Accelerator& accelerator, KeyId hot_key_id); + void UnregisterHotKey(const ui::Accelerator& accelerator); + + // Enable and disable the media key event tap. + void StartWatchingMediaKeys(); + void StopWatchingMediaKeys(); + + // Enable and disable the hot key event handler. + void StartWatchingHotKeys(); + void StopWatchingHotKeys(); + + // Whether or not any media keys are currently registered. + bool IsAnyMediaKeyRegistered(); + + // Whether or not any hot keys are currently registered. + bool IsAnyHotKeyRegistered(); + + // The callback for when an event tap happens. + static CGEventRef EventTapCallback( + CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon); + + // The callback for when a hot key event happens. + static OSStatus HotKeyHandler( + EventHandlerCallRef next_handler, EventRef event, void* user_data); + + // Whether this object is listening for global shortcuts. + bool is_listening_; + + // The hotkey identifier for the next global shortcut that is added. + KeyId hot_key_id_; + + // A map of all hotkeys (media keys and shortcuts) mapping to their + // corresponding hotkey IDs. For quickly finding if an accelerator is + // registered. + AcceleratorIdMap accelerator_ids_; + + // The inverse map for quickly looking up accelerators by hotkey id. + IdAcceleratorMap id_accelerators_; + + // Keyboard shortcut IDs to hotkeys map for unregistration. + IdHotKeyRefMap id_hot_key_refs_; + + // Event tap for intercepting mac media keys. + CFMachPortRef event_tap_; + CFRunLoopSourceRef event_tap_source_; + + // Event handler for keyboard shortcut hot keys. + EventHandlerRef event_handler_; + + DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerMac); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_ diff --git a/src/api/shortcut/global_shortcut_listener_mac.mm b/src/api/shortcut/global_shortcut_listener_mac.mm new file mode 100644 index 0000000000..b7052fe0b3 --- /dev/null +++ b/src/api/shortcut/global_shortcut_listener_mac.mm @@ -0,0 +1,391 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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 "chrome/browser/extensions/global_shortcut_listener_mac.h" + +#include +#import +#include + +#import "base/mac/foundation_util.h" +#include "chrome/common/extensions/command.h" +#include "content/public/browser/browser_thread.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/events/event.h" +#import "ui/events/keycodes/keyboard_code_conversion_mac.h" + +using content::BrowserThread; +using extensions::GlobalShortcutListenerMac; + +namespace { + +// The media keys subtype. No official docs found, but widely known. +// http://lists.apple.com/archives/cocoa-dev/2007/Aug/msg00499.html +const int kSystemDefinedEventMediaKeysSubtype = 8; + +ui::KeyboardCode MediaKeyCodeToKeyboardCode(int key_code) { + switch (key_code) { + case NX_KEYTYPE_PLAY: + return ui::VKEY_MEDIA_PLAY_PAUSE; + case NX_KEYTYPE_PREVIOUS: + case NX_KEYTYPE_REWIND: + return ui::VKEY_MEDIA_PREV_TRACK; + case NX_KEYTYPE_NEXT: + case NX_KEYTYPE_FAST: + return ui::VKEY_MEDIA_NEXT_TRACK; + } + return ui::VKEY_UNKNOWN; +} + +} // namespace + +namespace extensions { + +// static +GlobalShortcutListener* GlobalShortcutListener::GetInstance() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + static GlobalShortcutListenerMac* instance = + new GlobalShortcutListenerMac(); + return instance; +} + +GlobalShortcutListenerMac::GlobalShortcutListenerMac() + : is_listening_(false), + hot_key_id_(0), + event_tap_(NULL), + event_tap_source_(NULL), + event_handler_(NULL) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + +GlobalShortcutListenerMac::~GlobalShortcutListenerMac() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // By this point, UnregisterAccelerator should have been called for all + // keyboard shortcuts. Still we should clean up. + if (is_listening_) + StopListening(); + + // If keys are still registered, make sure we stop the tap. Again, this + // should never happen. + if (IsAnyMediaKeyRegistered()) + StopWatchingMediaKeys(); + + if (IsAnyHotKeyRegistered()) + StopWatchingHotKeys(); +} + +void GlobalShortcutListenerMac::StartListening() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + DCHECK(!accelerator_ids_.empty()); + DCHECK(!id_accelerators_.empty()); + DCHECK(!is_listening_); + + is_listening_ = true; +} + +void GlobalShortcutListenerMac::StopListening() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + DCHECK(accelerator_ids_.empty()); // Make sure the set is clean. + DCHECK(id_accelerators_.empty()); + DCHECK(is_listening_); + + is_listening_ = false; +} + +void GlobalShortcutListenerMac::OnHotKeyEvent(EventHotKeyID hot_key_id) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // This hot key should be registered. + DCHECK(id_accelerators_.find(hot_key_id.id) != id_accelerators_.end()); + // Look up the accelerator based on this hot key ID. + const ui::Accelerator& accelerator = id_accelerators_[hot_key_id.id]; + NotifyKeyPressed(accelerator); +} + +bool GlobalShortcutListenerMac::OnMediaKeyEvent(int media_key_code) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + ui::KeyboardCode key_code = MediaKeyCodeToKeyboardCode(media_key_code); + // Create an accelerator corresponding to the keyCode. + ui::Accelerator accelerator(key_code, 0); + // Look for a match with a bound hot_key. + if (accelerator_ids_.find(accelerator) != accelerator_ids_.end()) { + // If matched, callback to the event handling system. + NotifyKeyPressed(accelerator); + return true; + } + return false; +} + +bool GlobalShortcutListenerMac::RegisterAcceleratorImpl( + const ui::Accelerator& accelerator) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(accelerator_ids_.find(accelerator) == accelerator_ids_.end()); + + if (Command::IsMediaKey(accelerator)) { + if (!IsAnyMediaKeyRegistered()) { + // If this is the first media key registered, start the event tap. + StartWatchingMediaKeys(); + } + } else { + // Register hot_key if they are non-media keyboard shortcuts. + if (!RegisterHotKey(accelerator, hot_key_id_)) + return false; + + if (!IsAnyHotKeyRegistered()) { + StartWatchingHotKeys(); + } + } + + // Store the hotkey-ID mappings we will need for lookup later. + id_accelerators_[hot_key_id_] = accelerator; + accelerator_ids_[accelerator] = hot_key_id_; + ++hot_key_id_; + return true; +} + +void GlobalShortcutListenerMac::UnregisterAcceleratorImpl( + const ui::Accelerator& accelerator) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK(accelerator_ids_.find(accelerator) != accelerator_ids_.end()); + + // Unregister the hot_key if it's a keyboard shortcut. + if (!Command::IsMediaKey(accelerator)) + UnregisterHotKey(accelerator); + + // Remove hot_key from the mappings. + KeyId key_id = accelerator_ids_[accelerator]; + id_accelerators_.erase(key_id); + accelerator_ids_.erase(accelerator); + + if (Command::IsMediaKey(accelerator)) { + // If we unregistered a media key, and now no media keys are registered, + // stop the media key tap. + if (!IsAnyMediaKeyRegistered()) + StopWatchingMediaKeys(); + } else { + // If we unregistered a hot key, and no more hot keys are registered, remove + // the hot key handler. + if (!IsAnyHotKeyRegistered()) { + StopWatchingHotKeys(); + } + } +} + +bool GlobalShortcutListenerMac::RegisterHotKey( + const ui::Accelerator& accelerator, KeyId hot_key_id) { + EventHotKeyID event_hot_key_id; + + // Signature uniquely identifies the application that owns this hot_key. + event_hot_key_id.signature = base::mac::CreatorCodeForApplication(); + event_hot_key_id.id = hot_key_id; + + // Translate ui::Accelerator modifiers to cmdKey, altKey, etc. + int modifiers = 0; + modifiers |= (accelerator.IsShiftDown() ? shiftKey : 0); + modifiers |= (accelerator.IsCtrlDown() ? controlKey : 0); + modifiers |= (accelerator.IsAltDown() ? optionKey : 0); + modifiers |= (accelerator.IsCmdDown() ? cmdKey : 0); + + int key_code = ui::MacKeyCodeForWindowsKeyCode(accelerator.key_code(), 0, + NULL, NULL); + + // Register the event hot key. + EventHotKeyRef hot_key_ref; + OSStatus status = RegisterEventHotKey(key_code, modifiers, event_hot_key_id, + GetApplicationEventTarget(), 0, &hot_key_ref); + if (status != noErr) + return false; + + id_hot_key_refs_[hot_key_id] = hot_key_ref; + return true; +} + +void GlobalShortcutListenerMac::UnregisterHotKey( + const ui::Accelerator& accelerator) { + // Ensure this accelerator is already registered. + DCHECK(accelerator_ids_.find(accelerator) != accelerator_ids_.end()); + // Get the ref corresponding to this accelerator. + KeyId key_id = accelerator_ids_[accelerator]; + EventHotKeyRef ref = id_hot_key_refs_[key_id]; + // Unregister the event hot key. + UnregisterEventHotKey(ref); + + // Remove the event from the mapping. + id_hot_key_refs_.erase(key_id); +} + +void GlobalShortcutListenerMac::StartWatchingMediaKeys() { + // Make sure there's no existing event tap. + DCHECK(event_tap_ == NULL); + DCHECK(event_tap_source_ == NULL); + + // Add an event tap to intercept the system defined media key events. + event_tap_ = CGEventTapCreate(kCGSessionEventTap, + kCGHeadInsertEventTap, + kCGEventTapOptionDefault, + CGEventMaskBit(NX_SYSDEFINED), + EventTapCallback, + this); + if (event_tap_ == NULL) { + LOG(ERROR) << "Error: failed to create event tap."; + return; + } + + event_tap_source_ = CFMachPortCreateRunLoopSource(kCFAllocatorSystemDefault, + event_tap_, 0); + if (event_tap_source_ == NULL) { + LOG(ERROR) << "Error: failed to create new run loop source."; + return; + } + + CFRunLoopAddSource(CFRunLoopGetCurrent(), event_tap_source_, + kCFRunLoopCommonModes); +} + +void GlobalShortcutListenerMac::StopWatchingMediaKeys() { + CFRunLoopRemoveSource(CFRunLoopGetCurrent(), event_tap_source_, + kCFRunLoopCommonModes); + // Ensure both event tap and source are initialized. + DCHECK(event_tap_ != NULL); + DCHECK(event_tap_source_ != NULL); + + // Invalidate the event tap. + CFMachPortInvalidate(event_tap_); + CFRelease(event_tap_); + event_tap_ = NULL; + + // Release the event tap source. + CFRelease(event_tap_source_); + event_tap_source_ = NULL; +} + +void GlobalShortcutListenerMac::StartWatchingHotKeys() { + DCHECK(!event_handler_); + EventHandlerUPP hot_key_function = NewEventHandlerUPP(HotKeyHandler); + EventTypeSpec event_type; + event_type.eventClass = kEventClassKeyboard; + event_type.eventKind = kEventHotKeyPressed; + InstallApplicationEventHandler( + hot_key_function, 1, &event_type, this, &event_handler_); +} + +void GlobalShortcutListenerMac::StopWatchingHotKeys() { + DCHECK(event_handler_); + RemoveEventHandler(event_handler_); + event_handler_ = NULL; +} + +bool GlobalShortcutListenerMac::IsAnyMediaKeyRegistered() { + // Iterate through registered accelerators, looking for media keys. + AcceleratorIdMap::iterator it; + for (it = accelerator_ids_.begin(); it != accelerator_ids_.end(); ++it) { + if (Command::IsMediaKey(it->first)) + return true; + } + return false; +} + +bool GlobalShortcutListenerMac::IsAnyHotKeyRegistered() { + AcceleratorIdMap::iterator it; + for (it = accelerator_ids_.begin(); it != accelerator_ids_.end(); ++it) { + if (!Command::IsMediaKey(it->first)) + return true; + } + return false; +} + +// Processed events should propagate if they aren't handled by any listeners. +// For events that don't matter, this handler should return as quickly as +// possible. +// Returning event causes the event to propagate to other applications. +// Returning NULL prevents the event from propagating. +// static +CGEventRef GlobalShortcutListenerMac::EventTapCallback( + CGEventTapProxy proxy, CGEventType type, CGEventRef event, void* refcon) { + GlobalShortcutListenerMac* shortcut_listener = + static_cast(refcon); + + // Handle the timeout case by re-enabling the tap. + if (type == kCGEventTapDisabledByTimeout) { + CGEventTapEnable(shortcut_listener->event_tap_, TRUE); + return event; + } + + // Convert the CGEvent to an NSEvent for access to the data1 field. + NSEvent* ns_event = [NSEvent eventWithCGEvent:event]; + if (ns_event == nil) { + return event; + } + + // Ignore events that are not system defined media keys. + if (type != NX_SYSDEFINED || + [ns_event type] != NSSystemDefined || + [ns_event subtype] != kSystemDefinedEventMediaKeysSubtype) { + return event; + } + + NSInteger data1 = [ns_event data1]; + // Ignore media keys that aren't previous, next and play/pause. + // Magical constants are from http://weblog.rogueamoeba.com/2007/09/29/ + int key_code = (data1 & 0xFFFF0000) >> 16; + if (key_code != NX_KEYTYPE_PLAY && key_code != NX_KEYTYPE_NEXT && + key_code != NX_KEYTYPE_PREVIOUS && key_code != NX_KEYTYPE_FAST && + key_code != NX_KEYTYPE_REWIND) { + return event; + } + + int key_flags = data1 & 0x0000FFFF; + bool is_key_pressed = ((key_flags & 0xFF00) >> 8) == 0xA; + + // If the key wasn't pressed (eg. was released), ignore this event. + if (!is_key_pressed) + return event; + + // Now we have a media key that we care about. Send it to the caller. + bool was_handled = shortcut_listener->OnMediaKeyEvent(key_code); + + // Prevent event from proagating to other apps if handled by Chrome. + if (was_handled) + return NULL; + + // By default, pass the event through. + return event; +} + +// static +OSStatus GlobalShortcutListenerMac::HotKeyHandler( + EventHandlerCallRef next_handler, EventRef event, void* user_data) { + // Extract the hotkey from the event. + EventHotKeyID hot_key_id; + OSStatus result = GetEventParameter(event, kEventParamDirectObject, + typeEventHotKeyID, NULL, sizeof(hot_key_id), NULL, &hot_key_id); + if (result != noErr) + return result; + + GlobalShortcutListenerMac* shortcut_listener = + static_cast(user_data); + shortcut_listener->OnHotKeyEvent(hot_key_id); + return noErr; +} + +} // namespace extensions diff --git a/src/api/shortcut/global_shortcut_listener_win.cc b/src/api/shortcut/global_shortcut_listener_win.cc new file mode 100644 index 0000000000..73ca5ca299 --- /dev/null +++ b/src/api/shortcut/global_shortcut_listener_win.cc @@ -0,0 +1,121 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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/shortcut/global_shortcut_listener_win.h" + +#include "base/win/win_util.h" +#include "content/public/browser/browser_thread.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/events/event_constants.h" +#include "ui/events/keycodes/keyboard_code_conversion_win.h" + +using content::BrowserThread; + +namespace nwapi { + +// static +GlobalShortcutListener* GlobalShortcutListener::GetInstance() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + static GlobalShortcutListenerWin* instance = + new GlobalShortcutListenerWin(); + return instance; +} + +GlobalShortcutListenerWin::GlobalShortcutListenerWin() + : is_listening_(false) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + +GlobalShortcutListenerWin::~GlobalShortcutListenerWin() { + if (is_listening_) + StopListening(); +} + +void GlobalShortcutListenerWin::StartListening() { + DCHECK(!is_listening_); // Don't start twice. + DCHECK(!hotkey_ids_.empty()); // Also don't start if no hotkey is registered. + gfx::SingletonHwnd::GetInstance()->AddObserver(this); + is_listening_ = true; +} + +void GlobalShortcutListenerWin::StopListening() { + DCHECK(is_listening_); // No point if we are not already listening. + DCHECK(hotkey_ids_.empty()); // Make sure the map is clean before ending. + gfx::SingletonHwnd::GetInstance()->RemoveObserver(this); + is_listening_ = false; +} + +void GlobalShortcutListenerWin::OnWndProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + if (message != WM_HOTKEY) + return; + + int key_code = HIWORD(lparam); + int modifiers = 0; + modifiers |= (LOWORD(lparam) & MOD_SHIFT) ? ui::EF_SHIFT_DOWN : 0; + modifiers |= (LOWORD(lparam) & MOD_ALT) ? ui::EF_ALT_DOWN : 0; + modifiers |= (LOWORD(lparam) & MOD_CONTROL) ? ui::EF_CONTROL_DOWN : 0; + ui::Accelerator accelerator( + ui::KeyboardCodeForWindowsKeyCode(key_code), modifiers); + + NotifyKeyPressed(accelerator); +} + +bool GlobalShortcutListenerWin::RegisterAcceleratorImpl( + const ui::Accelerator& accelerator) { + DCHECK(hotkey_ids_.find(accelerator) == hotkey_ids_.end()); + + int modifiers = 0; + modifiers |= accelerator.IsShiftDown() ? MOD_SHIFT : 0; + modifiers |= accelerator.IsCtrlDown() ? MOD_CONTROL : 0; + modifiers |= accelerator.IsAltDown() ? MOD_ALT : 0; + static int hotkey_id = 0; + bool success = !!RegisterHotKey( + gfx::SingletonHwnd::GetInstance()->hwnd(), + hotkey_id, + modifiers, + accelerator.key_code()); + + if (!success) { + // Most likely error: 1409 (Hotkey already registered). + return false; + } + + hotkey_ids_[accelerator] = hotkey_id++; + return true; +} + +void GlobalShortcutListenerWin::UnregisterAcceleratorImpl( + const ui::Accelerator& accelerator) { + HotkeyIdMap::iterator it = hotkey_ids_.find(accelerator); + DCHECK(it != hotkey_ids_.end()); + + bool success = !!UnregisterHotKey( + gfx::SingletonHwnd::GetInstance()->hwnd(), it->second); + // This call should always succeed, as long as we pass in the right HWND and + // an id we've used to register before. + DCHECK(success); + + hotkey_ids_.erase(it); +} + +} // namespace nwapi diff --git a/src/api/shortcut/global_shortcut_listener_win.h b/src/api/shortcut/global_shortcut_listener_win.h new file mode 100644 index 0000000000..9993bf5138 --- /dev/null +++ b/src/api/shortcut/global_shortcut_listener_win.h @@ -0,0 +1,67 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_WIN_H_ +#define CONTENT_NW_SRC_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_WIN_H_ + +#include + +#include "content/nw/src/api/shortcut/global_shortcut_listener.h" +#include "ui/gfx/win/singleton_hwnd.h" + +namespace nwapi { + +// Windows-specific implementation of the GlobalShortcutListener class that +// listens for global shortcuts. Handles setting up a keyboard hook and +// forwarding its output to the base class for processing. +class GlobalShortcutListenerWin : public GlobalShortcutListener, + public gfx::SingletonHwnd::Observer { + public: + GlobalShortcutListenerWin(); + virtual ~GlobalShortcutListenerWin(); + + private: + // The implementation of our Window Proc, called by SingletonHwnd. + virtual void OnWndProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) OVERRIDE; + + // GlobalShortcutListener implementation. + virtual void StartListening() OVERRIDE; + virtual void StopListening() OVERRIDE; + virtual bool RegisterAcceleratorImpl( + const ui::Accelerator& accelerator) OVERRIDE; + virtual void UnregisterAcceleratorImpl( + const ui::Accelerator& accelerator) OVERRIDE; + + // Whether this object is listening for global shortcuts. + bool is_listening_; + + // A map of registered accelerators and their registration ids. + typedef std::map HotkeyIdMap; + HotkeyIdMap hotkey_ids_; + + DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerWin); +}; + +} // namespace nwapi + +#endif // CONTENT_NW_SRC_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_WIN_H_ diff --git a/src/api/shortcut/global_shortcut_listener_x11.cc b/src/api/shortcut/global_shortcut_listener_x11.cc new file mode 100644 index 0000000000..766cefed0f --- /dev/null +++ b/src/api/shortcut/global_shortcut_listener_x11.cc @@ -0,0 +1,197 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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 "chrome/browser/extensions/global_shortcut_listener_x11.h" + +#include "content/public/browser/browser_thread.h" +#include "ui/base/accelerators/accelerator.h" +#include "ui/events/keycodes/keyboard_code_conversion_x.h" +#include "ui/gfx/x/x11_error_tracker.h" +#include "ui/gfx/x/x11_types.h" + +#if defined(TOOLKIT_GTK) +#include +#else +#include "base/message_loop/message_pump_x11.h" +#endif + +using content::BrowserThread; + +namespace { + +// The modifiers masks used for grabing keys. Due to XGrabKey only working on +// exact modifiers, we need to grab all key combination including zero or more +// of the following: Num lock, Caps lock and Scroll lock. So that we can make +// sure the behavior of global shortcuts is consistent on all platforms. +const unsigned int kModifiersMasks[] = { + 0, // No additional modifier. + Mod2Mask, // Num lock + LockMask, // Caps lock + Mod5Mask, // Scroll lock + Mod2Mask | LockMask, + Mod2Mask | Mod5Mask, + LockMask | Mod5Mask, + Mod2Mask | LockMask | Mod5Mask +}; + +int GetNativeModifiers(const ui::Accelerator& accelerator) { + int modifiers = 0; + modifiers |= accelerator.IsShiftDown() ? ShiftMask : 0; + modifiers |= accelerator.IsCtrlDown() ? ControlMask : 0; + modifiers |= accelerator.IsAltDown() ? Mod1Mask : 0; + + return modifiers; +} + +} // namespace + +namespace extensions { + +// static +GlobalShortcutListener* GlobalShortcutListener::GetInstance() { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + static GlobalShortcutListenerX11* instance = + new GlobalShortcutListenerX11(); + return instance; +} + +GlobalShortcutListenerX11::GlobalShortcutListenerX11() + : is_listening_(false), + x_display_(gfx::GetXDisplay()), + x_root_window_(DefaultRootWindow(x_display_)) { + CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); +} + +GlobalShortcutListenerX11::~GlobalShortcutListenerX11() { + if (is_listening_) + StopListening(); +} + +void GlobalShortcutListenerX11::StartListening() { + DCHECK(!is_listening_); // Don't start twice. + DCHECK(!registered_hot_keys_.empty()); // Also don't start if no hotkey is + // registered. +#if defined(TOOLKIT_GTK) + gdk_window_add_filter(gdk_get_default_root_window(), + &GlobalShortcutListenerX11::OnXEventThunk, + this); +#else + base::MessagePumpX11::Current()->AddDispatcherForRootWindow(this); +#endif + + is_listening_ = true; +} + +void GlobalShortcutListenerX11::StopListening() { + DCHECK(is_listening_); // No point if we are not already listening. + DCHECK(registered_hot_keys_.empty()); // Make sure the set is clean before + // ending. + +#if defined(TOOLKIT_GTK) + gdk_window_remove_filter(NULL, + &GlobalShortcutListenerX11::OnXEventThunk, + this); +#else + base::MessagePumpX11::Current()->RemoveDispatcherForRootWindow(this); +#endif + + is_listening_ = false; +} + +#if !defined(TOOLKIT_GTK) +uint32_t GlobalShortcutListenerX11::Dispatch(const base::NativeEvent& event) { + if (event->type == KeyPress) + OnXKeyPressEvent(event); + + return POST_DISPATCH_NONE; +} +#endif + +bool GlobalShortcutListenerX11::RegisterAcceleratorImpl( + const ui::Accelerator& accelerator) { + DCHECK(registered_hot_keys_.find(accelerator) == registered_hot_keys_.end()); + + int modifiers = GetNativeModifiers(accelerator); + KeyCode keycode = XKeysymToKeycode(x_display_, + XKeysymForWindowsKeyCode(accelerator.key_code(), false)); + gfx::X11ErrorTracker err_tracker; + + // Because XGrabKey only works on the exact modifiers mask, we should register + // our hot keys with modifiers that we want to ignore, including Num lock, + // Caps lock, Scroll lock. See comment about |kModifiersMasks|. + for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) { + XGrabKey(x_display_, keycode, modifiers | kModifiersMasks[i], + x_root_window_, False, GrabModeAsync, GrabModeAsync); + } + + if (err_tracker.FoundNewError()) { + // We may have part of the hotkeys registered, clean up. + for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) { + XUngrabKey(x_display_, keycode, modifiers | kModifiersMasks[i], + x_root_window_); + } + + return false; + } + + registered_hot_keys_.insert(accelerator); + return true; +} + +void GlobalShortcutListenerX11::UnregisterAcceleratorImpl( + const ui::Accelerator& accelerator) { + DCHECK(registered_hot_keys_.find(accelerator) != registered_hot_keys_.end()); + + int modifiers = GetNativeModifiers(accelerator); + KeyCode keycode = XKeysymToKeycode(x_display_, + XKeysymForWindowsKeyCode(accelerator.key_code(), false)); + + for (size_t i = 0; i < arraysize(kModifiersMasks); ++i) { + XUngrabKey(x_display_, keycode, modifiers | kModifiersMasks[i], + x_root_window_); + } + registered_hot_keys_.erase(accelerator); +} + +#if defined(TOOLKIT_GTK) +GdkFilterReturn GlobalShortcutListenerX11::OnXEvent(GdkXEvent* gdk_x_event, + GdkEvent* gdk_event) { + XEvent* x_event = static_cast(gdk_x_event); + if (x_event->type == KeyPress) + OnXKeyPressEvent(x_event); + + return GDK_FILTER_CONTINUE; +} +#endif + +void GlobalShortcutListenerX11::OnXKeyPressEvent(::XEvent* x_event) { + DCHECK(x_event->type == KeyPress); + int modifiers = 0; + modifiers |= (x_event->xkey.state & ShiftMask) ? ui::EF_SHIFT_DOWN : 0; + modifiers |= (x_event->xkey.state & ControlMask) ? ui::EF_CONTROL_DOWN : 0; + modifiers |= (x_event->xkey.state & Mod1Mask) ? ui::EF_ALT_DOWN : 0; + + ui::Accelerator accelerator( + ui::KeyboardCodeFromXKeyEvent(x_event), modifiers); + if (registered_hot_keys_.find(accelerator) != registered_hot_keys_.end()) + NotifyKeyPressed(accelerator); +} + +} // namespace extensions diff --git a/src/api/shortcut/global_shortcut_listener_x11.h b/src/api/shortcut/global_shortcut_listener_x11.h new file mode 100644 index 0000000000..c42d2e2e40 --- /dev/null +++ b/src/api/shortcut/global_shortcut_listener_x11.h @@ -0,0 +1,89 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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 CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_ +#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_ + +#include +#include + +#include "base/message_loop/message_pump_dispatcher.h" +#include "chrome/browser/extensions/global_shortcut_listener.h" + +#if defined(TOOLKIT_GTK) +#include +#include "ui/base/gtk/gtk_signal.h" +#endif // defined(TOOLKIT_GTK) + +namespace extensions { + +// X11-specific implementation of the GlobalShortcutListener class that +// listens for global shortcuts. Handles basic keyboard intercepting and +// forwards its output to the base class for processing. +class GlobalShortcutListenerX11 + : +#if !defined(TOOLKIT_GTK) + public base::MessagePumpDispatcher, +#endif + public GlobalShortcutListener { + public: + GlobalShortcutListenerX11(); + virtual ~GlobalShortcutListenerX11(); + +#if !defined(TOOLKIT_GTK) + // base::MessagePumpDispatcher implementation. + virtual uint32_t Dispatch(const base::NativeEvent& event) OVERRIDE; +#endif + + private: + // GlobalShortcutListener implementation. + virtual void StartListening() OVERRIDE; + virtual void StopListening() OVERRIDE; + virtual bool RegisterAcceleratorImpl( + const ui::Accelerator& accelerator) OVERRIDE; + virtual void UnregisterAcceleratorImpl( + const ui::Accelerator& accelerator) OVERRIDE; + +#if defined(TOOLKIT_GTK) + // Callback for XEvents of the default root window. + CHROMEG_CALLBACK_1(GlobalShortcutListenerX11, GdkFilterReturn, + OnXEvent, GdkXEvent*, GdkEvent*); +#endif + + // Invoked when a global shortcut is pressed. + void OnXKeyPressEvent(::XEvent* x_event); + + // Whether this object is listening for global shortcuts. + bool is_listening_; + + // The x11 default display and the native root window. + ::Display* x_display_; + ::Window x_root_window_; + + // A set of registered accelerators. + typedef std::set RegisteredHotKeys; + RegisteredHotKeys registered_hot_keys_; + + DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerX11); +}; + +} // namespace extensions + +#endif // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_ diff --git a/src/api/shortcut/shorcut.js b/src/api/shortcut/shorcut.js new file mode 100644 index 0000000000..653842208b --- /dev/null +++ b/src/api/shortcut/shorcut.js @@ -0,0 +1,66 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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. + +var v8_util = process.binding('v8_util'); + +function Shortcut(option) { + if (typeof option != 'object') + throw new String('Invalid option.'); + + if (!option.hasOwnProperty('key')) + throw new TypeError("Shortcut requires 'key' to specify key combinations."); + + option.key = String(option.key); + this.key = option.key; + + if (option.hasOwnProperty('active')) { + if (typeof option.active != 'function') + throw new TypeError("'active' must be a valid function."); + else + this.active = option.active; + } + + if (option.hasOwnProperty('failed')) { + if (typeof option.failed != 'function') + throw new TypeError("'failed' must be a valid function."); + else + this.failed = option.failed; + } + + v8_util.setHiddenValue(this, 'option', option); + nw.allocateObject(this, option); +} + +require('util').inherits(Shortcut, exports.Base); + +Shortcut.prototype.handleEvent = function(ev) { + if (ev == 'active') { + if (typeof this.active == 'function') + this.active(); + } else if (ev == 'failed') { + if (typeof this.failed == 'function') + this.failed(arguments[1]); + } + + // Emit generate event handler + exports.Base.prototype.handleEvent.apply(this, arguments); +} + +exports.Shortcut = Shortcut; diff --git a/src/api/shortcut/shortcut.cc b/src/api/shortcut/shortcut.cc new file mode 100644 index 0000000000..a93b8aa540 --- /dev/null +++ b/src/api/shortcut/shortcut.cc @@ -0,0 +1,163 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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/shortcut/shortcut.h" + +#include + +#include "base/compiler_specific.h" +#include "base/strings/string_split.h" +#include "base/values.h" +#include "content/nw/src/api/dispatcher_host.h" +#include "content/nw/src/api/shortcut/shortcut_constants.h" + +namespace nwapi { + +ui::Accelerator Parse(const std::string& shortcut) { + std::vector tokens; + base::SplitString(shortcut, '+', &tokens); + if (tokens.size() == 0) { + return ui::Accelerator(); + } + + int modifiers = ui::EF_NONE; + ui::KeyboardCode key = ui::VKEY_UNKNOWN; + for (size_t i = 0; i < tokens.size(); i++) { + if (tokens[i] == kKeyCtrl) { +#if defined(OS_MACOSX) + modifiers |= ui::EF_COMMAND_DOWN; +#else + modifiers |= ui::EF_CONTROL_DOWN; +#endif + } else if (tokens[i] == kKeyAlt) { + modifiers |= ui::EF_ALT_DOWN; + } else if (tokens[i] == kKeyShift) { + modifiers |= ui::EF_SHIFT_DOWN; + } else if (tokens[i].size() == 1 || // A-Z, 0-9. + tokens[i] == kKeyComma || + tokens[i] == kKeyPeriod || + tokens[i] == kKeyUp || + tokens[i] == kKeyDown || + tokens[i] == kKeyLeft || + tokens[i] == kKeyRight || + tokens[i] == kKeyIns || + tokens[i] == kKeyDel || + tokens[i] == kKeyHome || + tokens[i] == kKeyEnd || + tokens[i] == kKeyPgUp || + tokens[i] == kKeyPgDwn || + tokens[i] == kKeyTab || + tokens[i] == kKeyMediaNextTrack || + tokens[i] == kKeyMediaPlayPause || + tokens[i] == kKeyMediaPrevTrack || + tokens[i] == kKeyMediaStop) { + if (key != ui::VKEY_UNKNOWN) { + // Multiple key assignments. + key = ui::VKEY_UNKNOWN; + break; + } + + if (tokens[i] == kKeyComma) { + key = ui::VKEY_OEM_COMMA; + } else if (tokens[i] == kKeyPeriod) { + key = ui::VKEY_OEM_PERIOD; + } else if (tokens[i] == kKeyUp) { + key = ui::VKEY_UP; + } else if (tokens[i] == kKeyDown) { + key = ui::VKEY_DOWN; + } else if (tokens[i] == kKeyLeft) { + key = ui::VKEY_LEFT; + } else if (tokens[i] == kKeyRight) { + key = ui::VKEY_RIGHT; + } else if (tokens[i] == kKeyIns) { + key = ui::VKEY_INSERT; + } else if (tokens[i] == kKeyDel) { + key = ui::VKEY_DELETE; + } else if (tokens[i] == kKeyHome) { + key = ui::VKEY_HOME; + } else if (tokens[i] == kKeyEnd) { + key = ui::VKEY_END; + } else if (tokens[i] == kKeyPgUp) { + key = ui::VKEY_PRIOR; + } else if (tokens[i] == kKeyPgDwn) { + key = ui::VKEY_NEXT; + } else if (tokens[i] == kKeyTab) { + key = ui::VKEY_TAB; + } else if (tokens[i] == kKeyMediaNextTrack) { + key = ui::VKEY_MEDIA_NEXT_TRACK; + } else if (tokens[i] == kKeyMediaPlayPause) { + key = ui::VKEY_MEDIA_PLAY_PAUSE; + } else if (tokens[i] == kKeyMediaPrevTrack) { + key = ui::VKEY_MEDIA_PREV_TRACK; + } else if (tokens[i] == kKeyMediaStop) { + key = ui::VKEY_MEDIA_STOP; + } else if (tokens[i].size() == 1 && + tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') { + key = static_cast(ui::VKEY_A + (tokens[i][0] - 'A')); + } else if (tokens[i].size() == 1 && + tokens[i][0] >= '0' && tokens[i][0] <= '9') { + key = static_cast(ui::VKEY_0 + (tokens[i][0] - '0')); + } else { + key = ui::VKEY_UNKNOWN; + break; + } + } + } + + return ui::Accelerator(key, modifiers); +} + +Shortcut::Shortcut(int id, + const base::WeakPtr& dispatcher_host, + const base::DictionaryValue& option) + : Base(id, dispatcher_host, option) { + std::string shortcut; + option.GetString("key", &shortcut); + accelerator_ = Parse(shortcut); + if (accelerator_.key_code() == ui::VKEY_UNKNOWN) + OnFailed("Can not parse shortcut: " + shortcut + "."); +} + +Shortcut::~Shortcut() { +} + +void Shortcut::OnActive() { + base::ListValue args; + dispatcher_host()->SendEvent(this, "active", args); +} + +void Shortcut::OnFailed(const std::string failed_msg) { + base::ListValue args; + args.AppendString(failed_msg); + dispatcher_host()->SendEvent(this, "failed", args); +} + +void Shortcut::OnKeyPressed(const ui::Accelerator& accelerator) { + if (accelerator != accelerator_) { + // This should never occur, because if it does, GlobalShortcutListener + // notifes us with wrong accelerator. + NOTREACHED(); + return; + } + + OnActive(); +} + +} // namespace nwapi diff --git a/src/api/shortcut/shortcut.h b/src/api/shortcut/shortcut.h new file mode 100644 index 0000000000..9bff68602f --- /dev/null +++ b/src/api/shortcut/shortcut.h @@ -0,0 +1,55 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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_API_SHORTCUT_SHORTCUT_H_ +#define CONTENT_NW_SRC_API_SHORTCUT_SHORTCUT_H_ + +#include + +#include "content/nw/src/api/base/base.h" +#include "content/nw/src/api/shortcut/global_shortcut_listener.h" +#include "ui/base/accelerators/accelerator.h" + +namespace nwapi { + +class Shortcut : public Base, public GlobalShortcutListener::Observer { + public: + Shortcut(int id, + const base::WeakPtr& dispatcher_host, + const base::DictionaryValue& option); + virtual ~Shortcut(); + + const ui::Accelerator& GetAccelerator() const { + return accelerator_; + } + + void OnActive(); + void OnFailed(const std::string failed_msg); + + // GlobalShortcutListener::Observer implementation. + virtual void OnKeyPressed(const ui::Accelerator& accelerator); + + private: + ui::Accelerator accelerator_; +}; + +} // namespace nwapi + +#endif // CONTENT_NW_SRC_API_SHORTCUT_SHORTCUT_H_ diff --git a/src/api/shortcut/shortcut_constants.cc b/src/api/shortcut/shortcut_constants.cc new file mode 100644 index 0000000000..f2fc2d373d --- /dev/null +++ b/src/api/shortcut/shortcut_constants.cc @@ -0,0 +1,49 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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/shortcut/shortcut_constants.h" + +namespace nwapi { + +const char kKeyAlt[] = "Alt"; +const char kKeyComma[] = "Comma"; +const char kKeyCommand[] = "Command"; +const char kKeyCtrl[] = "Ctrl"; +const char kKeyDel[] = "Delete"; +const char kKeyDown[] = "Down"; +const char kKeyEnd[] = "End"; +const char kKeyHome[] = "Home"; +const char kKeyIns[] = "Insert"; +const char kKeyLeft[] = "Left"; +const char kKeyMacCtrl[] = "MacCtrl"; +const char kKeyMediaNextTrack[] = "MediaNextTrack"; +const char kKeyMediaPlayPause[] = "MediaPlayPause"; +const char kKeyMediaPrevTrack[] = "MediaPrevTrack"; +const char kKeyMediaStop[] = "MediaStop"; +const char kKeyPgDwn[] = "PageDown"; +const char kKeyPgUp[] = "PageUp"; +const char kKeyPeriod[] = "Period"; +const char kKeyRight[] = "Right"; +const char kKeySeparator[] = "+"; +const char kKeyShift[] = "Shift"; +const char kKeyTab[] = "Tab"; +const char kKeyUp[] = "Up"; + +} // namespace nwapi diff --git a/src/api/shortcut/shortcut_constants.h b/src/api/shortcut/shortcut_constants.h new file mode 100644 index 0000000000..8459851e16 --- /dev/null +++ b/src/api/shortcut/shortcut_constants.h @@ -0,0 +1,52 @@ +// Copyright (c) 2014 Intel Corp +// Copyright (c) 2014 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 +// all 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_API_SHORTCUT_SHORTCUT_CONSTANTS_H_ +#define CONTENT_NW_SRC_API_SHORTCUT_SHORTCUT_CONSTANTS_H_ + +namespace nwapi { + +extern const char kKeyAlt[]; +extern const char kKeyComma[]; +extern const char kKeyCommand[]; +extern const char kKeyCtrl[]; +extern const char kKeyDel[]; +extern const char kKeyDown[]; +extern const char kKeyEnd[]; +extern const char kKeyHome[]; +extern const char kKeyIns[]; +extern const char kKeyLeft[]; +extern const char kKeyMacCtrl[]; +extern const char kKeyMediaNextTrack[]; +extern const char kKeyMediaPlayPause[]; +extern const char kKeyMediaPrevTrack[]; +extern const char kKeyMediaStop[]; +extern const char kKeyPgDwn[]; +extern const char kKeyPgUp[]; +extern const char kKeyPeriod[]; +extern const char kKeyRight[]; +extern const char kKeySeparator[]; +extern const char kKeyShift[]; +extern const char kKeyTab[]; +extern const char kKeyUp[]; + +} // namespace nwapi + +#endif // CONTENT_NW_SRC_API_SHORTCUT_SHORTCUT_CONSTANTS_H_ diff --git a/src/resources/nw_resources.grd b/src/resources/nw_resources.grd index f181878e56..98f18da3d4 100644 --- a/src/resources/nw_resources.grd +++ b/src/resources/nw_resources.grd @@ -48,6 +48,7 @@ + From 46d7e6cacbd5595ef57a9ef2d2afeb5ce4c9c361 Mon Sep 17 00:00:00 2001 From: "Chaobin,Zhang" Date: Thu, 27 Mar 2014 19:27:48 +0800 Subject: [PATCH 091/492] [Test] Manual test case for global keyboard shortcut. --- tests/manual_tests/global_hotkey/index.html | 51 +++++++++++++++++++ tests/manual_tests/global_hotkey/package.json | 7 +++ 2 files changed, 58 insertions(+) create mode 100644 tests/manual_tests/global_hotkey/index.html create mode 100644 tests/manual_tests/global_hotkey/package.json diff --git a/tests/manual_tests/global_hotkey/index.html b/tests/manual_tests/global_hotkey/index.html new file mode 100644 index 0000000000..213b9e2456 --- /dev/null +++ b/tests/manual_tests/global_hotkey/index.html @@ -0,0 +1,51 @@ + + + + HotKey Demo + + + + +
    Now you can try to press 'Alt+Shit+A', 'Ctrl+K', 'Alt+B', 'Ctrl+Alt+C'.
    + +
    
    +  
    +
    diff --git a/tests/manual_tests/global_hotkey/package.json b/tests/manual_tests/global_hotkey/package.json
    new file mode 100644
    index 0000000000..58e5f668ae
    --- /dev/null
    +++ b/tests/manual_tests/global_hotkey/package.json
    @@ -0,0 +1,7 @@
    +{
    +  "name" : "Hotkey-demo",
    +  "main" : "index.html",
    +  "window" : {
    +    "width": 850
    +  }
    +}
    
    From d48e0795b8f69c24e6fdc1e0a9772daf1c2e8001 Mon Sep 17 00:00:00 2001
    From: Chaobin Zhang 
    Date: Thu, 27 Mar 2014 20:08:48 +0800
    Subject: [PATCH 092/492] [API] Finish register global desktop keyboard
     shortcut on linux.
    
    ---
     nw.gypi                                          |  2 ++
     src/api/shortcut/global_shortcut_listener_x11.cc | 10 +++++-----
     src/api/shortcut/global_shortcut_listener_x11.h  | 13 +++++++------
     3 files changed, 14 insertions(+), 11 deletions(-)
    
    diff --git a/nw.gypi b/nw.gypi
    index 13edf09394..ef48bfe984 100644
    --- a/nw.gypi
    +++ b/nw.gypi
    @@ -161,6 +161,8 @@
             'src/api/shell/shell.h',
             'src/api/shortcut/global_shortcut_listener.cc',
             'src/api/shortcut/global_shortcut_listener.h',
    +        'src/api/shortcut/global_shortcut_listener_x11.cc',
    +        'src/api/shortcut/global_shortcut_listener_x11.h',
             'src/api/shortcut/global_shortcut_listener_win.cc',
             'src/api/shortcut/global_shortcut_listener_win.h',
             'src/api/shortcut/shortcut.cc',
    diff --git a/src/api/shortcut/global_shortcut_listener_x11.cc b/src/api/shortcut/global_shortcut_listener_x11.cc
    index 766cefed0f..1d1d087df2 100644
    --- a/src/api/shortcut/global_shortcut_listener_x11.cc
    +++ b/src/api/shortcut/global_shortcut_listener_x11.cc
    @@ -18,12 +18,12 @@
     // 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 "chrome/browser/extensions/global_shortcut_listener_x11.h"
    +#include "content/nw/src/api/shortcut/global_shortcut_listener_x11.h"
     
    +#include "base/x11/x11_error_tracker.h"
     #include "content/public/browser/browser_thread.h"
     #include "ui/base/accelerators/accelerator.h"
     #include "ui/events/keycodes/keyboard_code_conversion_x.h"
    -#include "ui/gfx/x/x11_error_tracker.h"
     #include "ui/gfx/x/x11_types.h"
     
     #if defined(TOOLKIT_GTK)
    @@ -62,7 +62,7 @@ int GetNativeModifiers(const ui::Accelerator& accelerator) {
     
     }  // namespace
     
    -namespace extensions {
    +namespace nwapi {
     
     // static
     GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
    @@ -131,7 +131,7 @@ bool GlobalShortcutListenerX11::RegisterAcceleratorImpl(
       int modifiers = GetNativeModifiers(accelerator);
       KeyCode keycode = XKeysymToKeycode(x_display_,
           XKeysymForWindowsKeyCode(accelerator.key_code(), false));
    -  gfx::X11ErrorTracker err_tracker;
    +  base::X11ErrorTracker err_tracker;
     
       // Because XGrabKey only works on the exact modifiers mask, we should register
       // our hot keys with modifiers that we want to ignore, including Num lock,
    @@ -194,4 +194,4 @@ void GlobalShortcutListenerX11::OnXKeyPressEvent(::XEvent* x_event) {
         NotifyKeyPressed(accelerator);
     }
     
    -}  // namespace extensions
    +}  // namespace nwapi
    diff --git a/src/api/shortcut/global_shortcut_listener_x11.h b/src/api/shortcut/global_shortcut_listener_x11.h
    index c42d2e2e40..72d16bc517 100644
    --- a/src/api/shortcut/global_shortcut_listener_x11.h
    +++ b/src/api/shortcut/global_shortcut_listener_x11.h
    @@ -18,21 +18,22 @@
     // 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 CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_
    -#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_
    +#ifndef CONTENT_NW_SRC_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_X11_H_
    +#define CONTENT_NW_SRC_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_X11_H_
     
     #include 
     #include 
     
    +#include "base/compiler_specific.h"
     #include "base/message_loop/message_pump_dispatcher.h"
    -#include "chrome/browser/extensions/global_shortcut_listener.h"
    +#include "content/nw/src/api/shortcut/global_shortcut_listener.h"
     
     #if defined(TOOLKIT_GTK)
     #include 
     #include "ui/base/gtk/gtk_signal.h"
     #endif  // defined(TOOLKIT_GTK)
     
    -namespace extensions {
    +namespace nwapi {
     
     // X11-specific implementation of the GlobalShortcutListener class that
     // listens for global shortcuts. Handles basic keyboard intercepting and
    @@ -84,6 +85,6 @@ class GlobalShortcutListenerX11
       DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerX11);
     };
     
    -}  // namespace extensions
    +}  // namespace nwapi
     
    -#endif  // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_X11_H_
    +#endif  // CONTENT_NW_SRC_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_X11_H_
    
    From 626292d96c469a156c69cefec81d12fa55bc517b Mon Sep 17 00:00:00 2001
    From: "Chaobin,Zhang" 
    Date: Thu, 27 Mar 2014 21:50:51 +0800
    Subject: [PATCH 093/492] [Test] Automatic test case for keyboard shortcut.
    
    ---
     tests/automatic_tests/shortcut/mocha_test.js | 110 +++++++++++++++++++
     1 file changed, 110 insertions(+)
     create mode 100644 tests/automatic_tests/shortcut/mocha_test.js
    
    diff --git a/tests/automatic_tests/shortcut/mocha_test.js b/tests/automatic_tests/shortcut/mocha_test.js
    new file mode 100644
    index 0000000000..16eed5174d
    --- /dev/null
    +++ b/tests/automatic_tests/shortcut/mocha_test.js
    @@ -0,0 +1,110 @@
    +var gui = require('nw.gui');
    +var assert = require('assert');
    +require('should');
    +
    +describe('Shortcut', function() {
    +  describe('.key', function() {
    +    it('should be undefined if no key specified.', function() {
    +      var shortcut;
    +      try {
    +        shortcut = new gui.Shortcut();
    +      } catch (err) {}
    +      assert.equal(shortcut, undefined);
    +    });
    +
    +    it('should be an object if key specified.', function() {
    +      var shortcut;
    +      try {
    +        shortcut = new gui.Shortcut({"key": "Alt+Shift+S"});
    +      } catch (err) {}
    +
    +      shortcut.should.be.a('object');
    +      assert.equal(shortcut.key, "Alt+Shift+S");
    +    });
    +  });
    +
    +  describe('.active', function() {
    +    it('should be undefined if active is not an function object.', function() {
    +      var shortcut;
    +      try {
    +        shortcut = new gui.Shortcut({key: 'Alt+Shift+S', active: "foo"});
    +      } catch(err) {}
    +
    +      assert.equal(shortcut, undefined);
    +    });
    +
    +    it('should be an object if "key" and "active" specified.', function() {
    +      var onActive = function() {};
    +      var shortcut = new gui.Shortcut({key: 'Alt+Shift+S', active: onActive});
    +
    +      shortcut.should.be.a('object');
    +      assert.equal(shortcut.active, onActive);
    +    });
    +  });
    +
    +  describe('.failed', function() {
    +    it('should be undefined if "failed" is not a function object.', function() {
    +      var shortcut;
    +      try {
    +        shortcut = new gui.Shortcut({key: 'Alt+Shift+S', failed: "foo"});
    +      } catch(err) {}
    +
    +      assert.equal(shortcut, undefined);
    +    });
    +
    +    it('should be an object if "key" and "failed" specified.', function() {
    +      var onFailed = function() {};
    +      var shortcut = new gui.Shortcut({key: 'Alt+Shift+S', failed: onFailed});
    +
    +      shortcut.should.be.a('object');
    +      assert.equal(shortcut.failed, onFailed);
    +    });
    +  });
    +});
    +
    +describe('App.registerGlobalHotKey', function() {
    +  it('should register failed if the parameter is not an Shortcut object.',
    +    function(done) {
    +      var object = new Object();
    +      try {
    +        gui.App.registerGlobalHotKey(object);
    +      } catch(err) {
    +        done();
    +      }
    +    }
    +  );
    +
    +  it('should register failed if the same key has been registered.',
    +    function(done) {
    +      var shortcut = new gui.Shortcut({key: "Alt+Shift+S"});
    +      shortcut.failed = function(msg) {
    +        assert.equal(msg, "Register global desktop keyboard shortcut failed.");
    +        done();
    +      };
    +
    +      gui.App.registerGlobalHotKey(shortcut);
    +      gui.App.registerGlobalHotKey(shortcut);
    +    }
    +  );
    +
    +  it('should register failed for invalid key.', function(done) {
    +    var shortcut = new gui.Shortcut({key: "foo"});
    +    shortcut.failed = function(msg) {
    +      done();
    +    }
    +    gui.App.registerGlobalHotKey(shortcut);
    +  });
    +});
    +
    +describe('App.unregisterGlobalHotKey', function() {
    +  it('should unregister failed if the parameter is not an Shortcut object.',
    +    function(done) {
    +      var object = new Object();
    +      try {
    +        gui.App.unregisterGlobalHotKey(object);
    +      } catch(err) {
    +        done();
    +      }
    +    }
    +  );
    +});
    
    From eea05f43fc647992961ceaaf7a061087d3a4f578 Mon Sep 17 00:00:00 2001
    From: Chaobin Zhang 
    Date: Fri, 28 Mar 2014 09:11:55 +0800
    Subject: [PATCH 094/492] Remove DCHECK limitation of GlobalShortcutListener.
    
    ---
     src/api/app/app.cc                           | 3 ++-
     src/api/shortcut/global_shortcut_listener.cc | 5 ++---
     2 files changed, 4 insertions(+), 4 deletions(-)
    
    diff --git a/src/api/app/app.cc b/src/api/app/app.cc
    index 88fc6d7d07..a46de388dc 100644
    --- a/src/api/app/app.cc
    +++ b/src/api/app/app.cc
    @@ -98,7 +98,8 @@ void App::Call(const std::string& method,
         arguments.GetInteger(0, &object_id);
         Shortcut* shortcut =
             static_cast(DispatcherHost::GetApiObject(object_id));
    -    GlobalShortcutListener::GetInstance()->UnregisterAccelerators(shortcut);
    +    GlobalShortcutListener::GetInstance()->UnregisterAccelerator(
    +        shortcut->GetAccelerator(), shortcut);
       } else {
         NOTREACHED() << "Calling unknown method " << method << " of App.";
       }
    diff --git a/src/api/shortcut/global_shortcut_listener.cc b/src/api/shortcut/global_shortcut_listener.cc
    index a27de1f752..f0fc047252 100644
    --- a/src/api/shortcut/global_shortcut_listener.cc
    +++ b/src/api/shortcut/global_shortcut_listener.cc
    @@ -35,7 +35,6 @@ GlobalShortcutListener::GlobalShortcutListener()
     
     GlobalShortcutListener::~GlobalShortcutListener() {
       CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
    -  DCHECK(accelerator_map_.empty());  // Make sure we've cleaned up.
     }
     
     bool GlobalShortcutListener::RegisterAccelerator(
    @@ -70,8 +69,8 @@ void GlobalShortcutListener::UnregisterAccelerator(
         return;
     
       AcceleratorMap::iterator it = accelerator_map_.find(accelerator);
    -  // We should never get asked to unregister something that we didn't register.
    -  DCHECK(it != accelerator_map_.end());
    +  if (it == accelerator_map_.end())
    +    return;
       // The caller should call this function with the right observer.
       DCHECK(it->second == observer);
     
    
    From ddb61d69ecf6be599e448d045d896e6db089556d Mon Sep 17 00:00:00 2001
    From: Haojian Wu 
    Date: Fri, 28 Mar 2014 16:18:04 +0800
    Subject: [PATCH 095/492] [API] Finish register global desktop keyboard
     shortcut on OSX.
    
    ---
     AUTHORS                                       |  3 +-
     nw.gypi                                       |  2 ++
     .../shortcut/global_shortcut_listener_mac.h   | 12 ++++----
     .../shortcut/global_shortcut_listener_mac.mm  | 28 ++++++++++++-------
     tests/manual_tests/global_hotkey/index.html   | 18 +++++++++++-
     5 files changed, 45 insertions(+), 18 deletions(-)
    
    diff --git a/AUTHORS b/AUTHORS
    index c34ff377b7..13ca024d2d 100644
    --- a/AUTHORS
    +++ b/AUTHORS
    @@ -25,4 +25,5 @@ Fabrice Weinberg 
     Lv Kaiyang 
     Lukas Benes 
     Lithare Emileit 
    -Jefry Tedjokusumo 
    \ No newline at end of file
    +Jefry Tedjokusumo 
    +Wu Haojian 
    diff --git a/nw.gypi b/nw.gypi
    index ef48bfe984..6c65e81e3f 100644
    --- a/nw.gypi
    +++ b/nw.gypi
    @@ -161,6 +161,8 @@
             'src/api/shell/shell.h',
             'src/api/shortcut/global_shortcut_listener.cc',
             'src/api/shortcut/global_shortcut_listener.h',
    +        'src/api/shortcut/global_shortcut_listener_mac.h',
    +        'src/api/shortcut/global_shortcut_listener_mac.mm',
             'src/api/shortcut/global_shortcut_listener_x11.cc',
             'src/api/shortcut/global_shortcut_listener_x11.h',
             'src/api/shortcut/global_shortcut_listener_win.cc',
    diff --git a/src/api/shortcut/global_shortcut_listener_mac.h b/src/api/shortcut/global_shortcut_listener_mac.h
    index d1ed0d6354..2f1f336df5 100644
    --- a/src/api/shortcut/global_shortcut_listener_mac.h
    +++ b/src/api/shortcut/global_shortcut_listener_mac.h
    @@ -18,10 +18,10 @@
     // 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 CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_
    -#define CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_
    +#ifndef CONTENT_NW_SRC_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_MAC_H_
    +#define CONTENT_NW_SRC_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_MAC_H_
     
    -#include "chrome/browser/extensions/global_shortcut_listener.h"
    +#include "content/nw/src/api/shortcut/global_shortcut_listener.h"
     
     #include 
     #include 
    @@ -30,7 +30,7 @@
     
     #include "base/mac/scoped_nsobject.h"
     
    -namespace extensions {
    +namespace nwapi {
     
     // Mac-specific implementation of the GlobalShortcutListener class that
     // listens for global shortcuts. Handles basic keyboard intercepting and
    @@ -117,6 +117,6 @@ class GlobalShortcutListenerMac : public GlobalShortcutListener {
       DISALLOW_COPY_AND_ASSIGN(GlobalShortcutListenerMac);
     };
     
    -}  // namespace extensions
    +}  // namespace nwapi
     
    -#endif  // CHROME_BROWSER_EXTENSIONS_GLOBAL_SHORTCUT_LISTENER_MAC_H_
    +#endif  // CONTENT_NW_SRC_API_SHORTCUT_GLOBAL_SHORTCUT_LISTENER_MAC_H_
    diff --git a/src/api/shortcut/global_shortcut_listener_mac.mm b/src/api/shortcut/global_shortcut_listener_mac.mm
    index b7052fe0b3..43132af46f 100644
    --- a/src/api/shortcut/global_shortcut_listener_mac.mm
    +++ b/src/api/shortcut/global_shortcut_listener_mac.mm
    @@ -18,21 +18,20 @@
     // 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 "chrome/browser/extensions/global_shortcut_listener_mac.h"
    +#include "content/nw/src/api/shortcut/global_shortcut_listener_mac.h"
     
     #include 
     #import 
     #include 
     
     #import "base/mac/foundation_util.h"
    -#include "chrome/common/extensions/command.h"
     #include "content/public/browser/browser_thread.h"
     #include "ui/base/accelerators/accelerator.h"
     #include "ui/events/event.h"
     #import "ui/events/keycodes/keyboard_code_conversion_mac.h"
     
     using content::BrowserThread;
    -using extensions::GlobalShortcutListenerMac;
    +using nwapi::GlobalShortcutListenerMac;
     
     namespace {
     
    @@ -54,9 +53,18 @@
       return ui::VKEY_UNKNOWN;
     }
     
    +bool IsMediaKey(const ui::Accelerator& accelerator) {
    +  if (accelerator.modifiers() != 0)
    +    return false;
    +  return (accelerator.key_code() == ui::VKEY_MEDIA_NEXT_TRACK ||
    +          accelerator.key_code() == ui::VKEY_MEDIA_PREV_TRACK ||
    +          accelerator.key_code() == ui::VKEY_MEDIA_PLAY_PAUSE ||
    +          accelerator.key_code() == ui::VKEY_MEDIA_STOP);
    +}
    +
     }  // namespace
     
    -namespace extensions {
    +namespace nwapi {
     
     // static
     GlobalShortcutListener* GlobalShortcutListener::GetInstance() {
    @@ -141,7 +149,7 @@
       CHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
       DCHECK(accelerator_ids_.find(accelerator) == accelerator_ids_.end());
     
    -  if (Command::IsMediaKey(accelerator)) {
    +  if (IsMediaKey(accelerator)) {
         if (!IsAnyMediaKeyRegistered()) {
           // If this is the first media key registered, start the event tap.
           StartWatchingMediaKeys();
    @@ -169,7 +177,7 @@
       DCHECK(accelerator_ids_.find(accelerator) != accelerator_ids_.end());
     
       // Unregister the hot_key if it's a keyboard shortcut.
    -  if (!Command::IsMediaKey(accelerator))
    +  if (!IsMediaKey(accelerator))
         UnregisterHotKey(accelerator);
     
       // Remove hot_key from the mappings.
    @@ -177,7 +185,7 @@
       id_accelerators_.erase(key_id);
       accelerator_ids_.erase(accelerator);
     
    -  if (Command::IsMediaKey(accelerator)) {
    +  if (IsMediaKey(accelerator)) {
         // If we unregistered a media key, and now no media keys are registered,
         // stop the media key tap.
         if (!IsAnyMediaKeyRegistered())
    @@ -299,7 +307,7 @@
       // Iterate through registered accelerators, looking for media keys.
       AcceleratorIdMap::iterator it;
       for (it = accelerator_ids_.begin(); it != accelerator_ids_.end(); ++it) {
    -    if (Command::IsMediaKey(it->first))
    +    if (IsMediaKey(it->first))
           return true;
       }
       return false;
    @@ -308,7 +316,7 @@
     bool GlobalShortcutListenerMac::IsAnyHotKeyRegistered() {
       AcceleratorIdMap::iterator it;
       for (it = accelerator_ids_.begin(); it != accelerator_ids_.end(); ++it) {
    -    if (!Command::IsMediaKey(it->first))
    +    if (!IsMediaKey(it->first))
           return true;
       }
       return false;
    @@ -388,4 +396,4 @@
       return noErr;
     }
     
    -}  // namespace extensions
    +}  // namespace nwapi
    diff --git a/tests/manual_tests/global_hotkey/index.html b/tests/manual_tests/global_hotkey/index.html
    index 213b9e2456..b13ad25b0e 100644
    --- a/tests/manual_tests/global_hotkey/index.html
    +++ b/tests/manual_tests/global_hotkey/index.html
    @@ -30,10 +30,26 @@
           option.key = "Ctrl+Alt+C";
           var shortcut4 = new gui.Shortcut(option);
     
    +      option.key = "MediaPrevTrack";
    +      var shortcut5 = new gui.Shortcut(option);
    +
    +      option.key = "MediaNextTrack";
    +      var shortcut6 = new gui.Shortcut(option);
    +
    +      option.key = "MediaPlayPause";
    +      var shortcut7 = new gui.Shortcut(option);
    +
    +      option.key = "MediaStop";
    +      var shortcut8 = new gui.Shortcut(option);
    +
           gui.App.registerGlobalHotKey(shortcut1)
           gui.App.registerGlobalHotKey(shortcut2);
           gui.App.registerGlobalHotKey(shortcut3);
           gui.App.registerGlobalHotKey(shortcut4);
    +      gui.App.registerGlobalHotKey(shortcut5);
    +      gui.App.registerGlobalHotKey(shortcut6);
    +      gui.App.registerGlobalHotKey(shortcut7);
    +      gui.App.registerGlobalHotKey(shortcut8);
     
           function unregister() {
             gui.App.unregisterGlobalHotKey(shortcut2);
    @@ -44,7 +60,7 @@
       
     
       
    -    
    Now you can try to press 'Alt+Shit+A', 'Ctrl+K', 'Alt+B', 'Ctrl+Alt+C'.
    +
    Now you can try to press 'Alt+Shit+A', 'Ctrl+K', 'Alt+B', 'Ctrl+Alt+C', 'MediaPrevTrack', 'MediaNextTrack', 'MediaPlayPause', 'MediaStop'.
    
       
    
    From 546af85deac63cf2db768869eefae7c2650c9a38 Mon Sep 17 00:00:00 2001
    From: "Chaobin,Zhang" 
    Date: Thu, 3 Apr 2014 11:28:01 +0800
    Subject: [PATCH 096/492] Improvement: |key| of |Shortcut| should be
     case-insensitive.
    
    ---
     src/api/shortcut/shortcut.cc           | 14 ++++++---
     src/api/shortcut/shortcut_constants.cc | 43 +++++++++++++-------------
     src/api/shortcut/shortcut_constants.h  |  1 -
     3 files changed, 30 insertions(+), 28 deletions(-)
    
    diff --git a/src/api/shortcut/shortcut.cc b/src/api/shortcut/shortcut.cc
    index a93b8aa540..dc5b0b2229 100644
    --- a/src/api/shortcut/shortcut.cc
    +++ b/src/api/shortcut/shortcut.cc
    @@ -24,6 +24,7 @@
     
     #include "base/compiler_specific.h"
     #include "base/strings/string_split.h"
    +#include "base/strings/string_util.h"
     #include "base/values.h"
     #include "content/nw/src/api/dispatcher_host.h"
     #include "content/nw/src/api/shortcut/shortcut_constants.h"
    @@ -31,11 +32,14 @@
     namespace nwapi {
     
     ui::Accelerator Parse(const std::string& shortcut) {
    +  // Convert to lower case, see
    +  // https://github.com/rogerwang/node-webkit/pull/1735.
    +  std::string lower_shortcut = StringToLowerASCII(shortcut);
    +
       std::vector tokens;
    -  base::SplitString(shortcut, '+', &tokens);
    -  if (tokens.size() == 0) {
    +  base::SplitString(lower_shortcut, '+', &tokens);
    +  if (tokens.size() == 0)
         return ui::Accelerator();
    -  }
     
       int modifiers = ui::EF_NONE;
       ui::KeyboardCode key = ui::VKEY_UNKNOWN;
    @@ -109,8 +113,8 @@ ui::Accelerator Parse(const std::string& shortcut) {
           } else if (tokens[i] == kKeyMediaStop) {
             key = ui::VKEY_MEDIA_STOP;
           } else if (tokens[i].size() == 1 &&
    -                 tokens[i][0] >= 'A' && tokens[i][0] <= 'Z') {
    -        key = static_cast(ui::VKEY_A + (tokens[i][0] - 'A'));
    +                 tokens[i][0] >= 'a' && tokens[i][0] <= 'z') {
    +        key = static_cast(ui::VKEY_A + (tokens[i][0] - 'a'));
           } else if (tokens[i].size() == 1 &&
                      tokens[i][0] >= '0' && tokens[i][0] <= '9') {
             key = static_cast(ui::VKEY_0 + (tokens[i][0] - '0'));
    diff --git a/src/api/shortcut/shortcut_constants.cc b/src/api/shortcut/shortcut_constants.cc
    index f2fc2d373d..6d404f9eea 100644
    --- a/src/api/shortcut/shortcut_constants.cc
    +++ b/src/api/shortcut/shortcut_constants.cc
    @@ -22,28 +22,27 @@
     
     namespace nwapi {
     
    -const char kKeyAlt[] = "Alt";
    -const char kKeyComma[] = "Comma";
    -const char kKeyCommand[] = "Command";
    -const char kKeyCtrl[] = "Ctrl";
    -const char kKeyDel[] = "Delete";
    -const char kKeyDown[] = "Down";
    -const char kKeyEnd[] = "End";
    -const char kKeyHome[] = "Home";
    -const char kKeyIns[] = "Insert";
    -const char kKeyLeft[] = "Left";
    -const char kKeyMacCtrl[] = "MacCtrl";
    -const char kKeyMediaNextTrack[] = "MediaNextTrack";
    -const char kKeyMediaPlayPause[] = "MediaPlayPause";
    -const char kKeyMediaPrevTrack[] = "MediaPrevTrack";
    -const char kKeyMediaStop[] = "MediaStop";
    -const char kKeyPgDwn[] = "PageDown";
    -const char kKeyPgUp[] = "PageUp";
    -const char kKeyPeriod[] = "Period";
    -const char kKeyRight[] = "Right";
    +const char kKeyAlt[] = "alt";
    +const char kKeyComma[] = "comma";
    +const char kKeyCommand[] = "command";
    +const char kKeyCtrl[] = "ctrl";
    +const char kKeyDel[] = "delete";
    +const char kKeyDown[] = "down";
    +const char kKeyEnd[] = "end";
    +const char kKeyHome[] = "home";
    +const char kKeyIns[] = "insert";
    +const char kKeyLeft[] = "left";
    +const char kKeyMediaNextTrack[] = "medianexttrack";
    +const char kKeyMediaPlayPause[] = "mediaplaypause";
    +const char kKeyMediaPrevTrack[] = "mediaprevtrack";
    +const char kKeyMediaStop[] = "mediastop";
    +const char kKeyPgDwn[] = "pagedown";
    +const char kKeyPgUp[] = "pageup";
    +const char kKeyPeriod[] = "period";
    +const char kKeyRight[] = "right";
     const char kKeySeparator[] = "+";
    -const char kKeyShift[] = "Shift";
    -const char kKeyTab[] = "Tab";
    -const char kKeyUp[] = "Up";
    +const char kKeyShift[] = "shift";
    +const char kKeyTab[] = "tab";
    +const char kKeyUp[] = "up";
     
     }  // namespace nwapi
    diff --git a/src/api/shortcut/shortcut_constants.h b/src/api/shortcut/shortcut_constants.h
    index 8459851e16..f0f0b88021 100644
    --- a/src/api/shortcut/shortcut_constants.h
    +++ b/src/api/shortcut/shortcut_constants.h
    @@ -33,7 +33,6 @@ extern const char kKeyEnd[];
     extern const char kKeyHome[];
     extern const char kKeyIns[];
     extern const char kKeyLeft[];
    -extern const char kKeyMacCtrl[];
     extern const char kKeyMediaNextTrack[];
     extern const char kKeyMediaPlayPause[];
     extern const char kKeyMediaPrevTrack[];
    
    From 14b2e22e8efe18e04816a46591e3c91fd95806f3 Mon Sep 17 00:00:00 2001
    From: Chaobin Zhang 
    Date: Thu, 3 Apr 2014 15:51:31 +0800
    Subject: [PATCH 097/492] Address comment: change {un}registerGlobalHotKey to
     sync method.
    
    ---
     src/api/app/app.cc | 36 ++++++++++++++++++++----------------
     src/api/app/app.js |  6 ++++--
     2 files changed, 24 insertions(+), 18 deletions(-)
    
    diff --git a/src/api/app/app.cc b/src/api/app/app.cc
    index a46de388dc..60567617d2 100644
    --- a/src/api/app/app.cc
    +++ b/src/api/app/app.cc
    @@ -84,22 +84,6 @@ void App::Call(const std::string& method,
       } else if (method == "CrashBrowser") {
         int* ptr = NULL;
         *ptr = 1;
    -  } else if (method == "RegisterGlobalHotKey") {
    -    int object_id = -1;
    -    arguments.GetInteger(0, &object_id);
    -    Shortcut* shortcut =
    -        static_cast(DispatcherHost::GetApiObject(object_id));
    -    bool success = GlobalShortcutListener::GetInstance()->RegisterAccelerator(
    -                       shortcut->GetAccelerator(), shortcut);
    -    if (!success)
    -      shortcut->OnFailed("Register global desktop keyboard shortcut failed.");
    -  } else if (method == "UnregisterGlobalHotKey") {
    -    int object_id = -1;
    -    arguments.GetInteger(0, &object_id);
    -    Shortcut* shortcut =
    -        static_cast(DispatcherHost::GetApiObject(object_id));
    -    GlobalShortcutListener::GetInstance()->UnregisterAccelerator(
    -        shortcut->GetAccelerator(), shortcut);
       } else {
         NOTREACHED() << "Calling unknown method " << method << " of App.";
       }
    @@ -144,6 +128,26 @@ void App::Call(Shell* shell,
         arguments.GetString(0, &path);
         result->AppendBoolean(SetCrashDumpPath(path.c_str()));
         return;
    +  } else if (method == "RegisterGlobalHotKey") {
    +    int object_id = -1;
    +    arguments.GetInteger(0, &object_id);
    +    Shortcut* shortcut =
    +        static_cast(DispatcherHost::GetApiObject(object_id));
    +    bool success = GlobalShortcutListener::GetInstance()->RegisterAccelerator(
    +                       shortcut->GetAccelerator(), shortcut);
    +    if (!success)
    +      shortcut->OnFailed("Register global desktop keyboard shortcut failed.");
    +
    +    result->AppendBoolean(success);
    +    return;
    +  } else if (method == "UnregisterGlobalHotKey") {
    +    int object_id = -1;
    +    arguments.GetInteger(0, &object_id);
    +    Shortcut* shortcut =
    +        static_cast(DispatcherHost::GetApiObject(object_id));
    +    GlobalShortcutListener::GetInstance()->UnregisterAccelerator(
    +        shortcut->GetAccelerator(), shortcut);
    +    return;
       }
     
       NOTREACHED() << "Calling unknown sync method " << method << " of App";
    diff --git a/src/api/app/app.js b/src/api/app/app.js
    index 8fa4d03640..b52e8dc697 100644
    --- a/src/api/app/app.js
    +++ b/src/api/app/app.js
    @@ -73,14 +73,16 @@ App.prototype.registerGlobalHotKey = function(shortcut) {
       if (v8_util.getConstructorName(shortcut) != "Shortcut")
         throw new TypeError("Invaild parameter, need Shortcut object.");
     
    -  nw.callStaticMethod('App', 'RegisterGlobalHotKey', [ shortcut.id ]);
    +  return nw.callStaticMethodSync('App',
    +                                 'RegisterGlobalHotKey',
    +                                 [ shortcut.id ])[0];
     }
     
     App.prototype.unregisterGlobalHotKey = function(shortcut) {
       if (v8_util.getConstructorName(shortcut) != "Shortcut")
         throw new TypeError("Invaild parameter, need Shortcut object.");
     
    -  nw.callStaticMethod('App', 'UnregisterGlobalHotKey', [ shortcut.id ]);
    +  nw.callStaticMethodSync('App', 'UnregisterGlobalHotKey', [ shortcut.id ]);
     }
     
     App.prototype.__defineGetter__('argv', function() {
    
    From cd354a22887d81eaaf6c90b774601a68a45042e0 Mon Sep 17 00:00:00 2001
    From: gitchs 
    Date: Fri, 27 Jun 2014 17:19:39 +0800
    Subject: [PATCH 098/492] Add nwfaketop test case
    
    ---
     tests/automatic_tests/nwfaketop/index.html    | 47 +++++++++++++++++++
     tests/automatic_tests/nwfaketop/mocha_test.js | 45 ++++++++++++++++++
     tests/automatic_tests/nwfaketop/package.json  | 11 +++++
     3 files changed, 103 insertions(+)
     create mode 100644 tests/automatic_tests/nwfaketop/index.html
     create mode 100644 tests/automatic_tests/nwfaketop/mocha_test.js
     create mode 100644 tests/automatic_tests/nwfaketop/package.json
    
    diff --git a/tests/automatic_tests/nwfaketop/index.html b/tests/automatic_tests/nwfaketop/index.html
    new file mode 100644
    index 0000000000..f897497957
    --- /dev/null
    +++ b/tests/automatic_tests/nwfaketop/index.html
    @@ -0,0 +1,47 @@
    +
    +
    +  
    +    
    +    test
    +  
    +  
    +    
    +    
    +    
    +  
    +
    +    
    \ No newline at end of file
    diff --git a/tests/automatic_tests/nwfaketop/mocha_test.js b/tests/automatic_tests/nwfaketop/mocha_test.js
    new file mode 100644
    index 0000000000..c58cfefbbf
    --- /dev/null
    +++ b/tests/automatic_tests/nwfaketop/mocha_test.js
    @@ -0,0 +1,45 @@
    +var path = require('path');
    +var assert = require('assert');
    +var spawn = require('child_process').spawn;
    +var server = global.server;
    +var server_port = global.port;
    +
    +
    +describe('nwfaketop',function(){
    +
    +	var results = [];
    +	var connection_handler_callback = undefined;
    +	var connection_handler = function(socket){
    +		socket.on('data',function(data){
    +			results = JSON.parse(data+"");
    +			connection_handler_callback();
    +		});
    +	};
    +	var child = undefined;
    +
    +	before(function(done){
    +		this.timeout(0);
    +		server.on('connection',connection_handler);
    +		var app_path = path.join(global.tests_dir,'nwfaketop');
    +		var exec_argv = [app_path,server_port];
    +		child = spawn(process.execPath,exec_argv);
    +		connection_handler_callback = done;
    +	});
    +
    +	after(function(done){
    +		server.removeListener('connection',connection_handler);
    +		child.kill();
    +		done();
    +	});
    +
    +	it("nwfaketop attribute set",function(done){
    +		assert(results[0],true);
    +		done();
    +	});
    +	it("nwfaketop attribute default",function(done){
    +		assert(results[1],true);
    +		done();
    +	});
    +
    +
    +});
    \ No newline at end of file
    diff --git a/tests/automatic_tests/nwfaketop/package.json b/tests/automatic_tests/nwfaketop/package.json
    new file mode 100644
    index 0000000000..b2bc1566ae
    --- /dev/null
    +++ b/tests/automatic_tests/nwfaketop/package.json
    @@ -0,0 +1,11 @@
    +{
    +  "name": "nwfaketop",
    +  "main": "index.html",
    +  "window": {
    +    "width": 600,
    +    "height": 400,
    +    "position": "center",
    +    "toolbar": true,
    +    "resizable": true
    +  }
    +}
    \ No newline at end of file
    
    From ba5e65c65c6b763204337f1c3c3fd5839cc4683d Mon Sep 17 00:00:00 2001
    From: Chaobin Zhang 
    Date: Fri, 27 Jun 2014 17:26:12 +0800
    Subject: [PATCH 099/492] Fix build error of missing parameter: isolate.
    
    ---
     src/api/dispatcher_bindings.cc | 2 +-
     1 file changed, 1 insertion(+), 1 deletion(-)
    
    diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc
    index 10987a574c..c68a26fef9 100644
    --- a/src/api/dispatcher_bindings.cc
    +++ b/src/api/dispatcher_bindings.cc
    @@ -215,7 +215,7 @@ DispatcherBindings::RequireNwGui(const v8::FunctionCallbackInfo& args
       RequireFromResource(args.This(),
                           NwGui, global, v8::String::NewFromUtf8(isolate, "app.js"), IDR_NW_API_APP_JS);
       RequireFromResource(args.This(),
    -                      NwGui, global, v8::String::NewFromUtf8("shortcut.js"), IDR_NW_API_SHORTCUT_JS);
    +                      NwGui, global, v8::String::NewFromUtf8(isolate, "shortcut.js"), IDR_NW_API_SHORTCUT_JS);
     
       g_context->Exit();
       args.GetReturnValue().Set(handle_scope.Escape(NwGui));
    
    From d56cc8ff7b93722587ec65494e142008043f8905 Mon Sep 17 00:00:00 2001
    From: Chaobin Zhang 
    Date: Wed, 2 Jul 2014 13:56:57 +0800
    Subject: [PATCH 100/492] X11ErrorTracker has been moved "ui/gfx/x/".
    
    ---
     src/api/shortcut/global_shortcut_listener_x11.cc | 4 ++--
     1 file changed, 2 insertions(+), 2 deletions(-)
    
    diff --git a/src/api/shortcut/global_shortcut_listener_x11.cc b/src/api/shortcut/global_shortcut_listener_x11.cc
    index 1d1d087df2..4064d389e1 100644
    --- a/src/api/shortcut/global_shortcut_listener_x11.cc
    +++ b/src/api/shortcut/global_shortcut_listener_x11.cc
    @@ -20,10 +20,10 @@
     
     #include "content/nw/src/api/shortcut/global_shortcut_listener_x11.h"
     
    -#include "base/x11/x11_error_tracker.h"
     #include "content/public/browser/browser_thread.h"
     #include "ui/base/accelerators/accelerator.h"
     #include "ui/events/keycodes/keyboard_code_conversion_x.h"
    +#include "ui/gfx/x/x11_error_tracker.h"
     #include "ui/gfx/x/x11_types.h"
     
     #if defined(TOOLKIT_GTK)
    @@ -131,7 +131,7 @@ bool GlobalShortcutListenerX11::RegisterAcceleratorImpl(
       int modifiers = GetNativeModifiers(accelerator);
       KeyCode keycode = XKeysymToKeycode(x_display_,
           XKeysymForWindowsKeyCode(accelerator.key_code(), false));
    -  base::X11ErrorTracker err_tracker;
    +  gfx::X11ErrorTracker err_tracker;
     
       // Because XGrabKey only works on the exact modifiers mask, we should register
       // our hot keys with modifiers that we want to ignore, including Num lock,
    
    From 10ca8ebae63d0c4de1ae2ea3d101126debd6239f Mon Sep 17 00:00:00 2001
    From: gitchs 
    Date: Wed, 2 Jul 2014 14:26:59 +0800
    Subject: [PATCH 101/492] Append reference xhr in node context test case
    
    ---
     .../reference_xhr_in_node_context/index.html  | 26 +++++++++++
     .../mocha_test.js                             | 44 +++++++++++++++++++
     .../package.json                              |  5 +++
     .../reference_xhr_in_node_context/test.js     | 11 +++++
     4 files changed, 86 insertions(+)
     create mode 100644 tests/automatic_tests/reference_xhr_in_node_context/index.html
     create mode 100644 tests/automatic_tests/reference_xhr_in_node_context/mocha_test.js
     create mode 100644 tests/automatic_tests/reference_xhr_in_node_context/package.json
     create mode 100644 tests/automatic_tests/reference_xhr_in_node_context/test.js
    
    diff --git a/tests/automatic_tests/reference_xhr_in_node_context/index.html b/tests/automatic_tests/reference_xhr_in_node_context/index.html
    new file mode 100644
    index 0000000000..375615a360
    --- /dev/null
    +++ b/tests/automatic_tests/reference_xhr_in_node_context/index.html
    @@ -0,0 +1,26 @@
    +
    +
    +  
    +    
    +    test
    +  
    +  
    +	  

    it works!

    + + + + \ No newline at end of file diff --git a/tests/automatic_tests/reference_xhr_in_node_context/mocha_test.js b/tests/automatic_tests/reference_xhr_in_node_context/mocha_test.js new file mode 100644 index 0000000000..eee8682f48 --- /dev/null +++ b/tests/automatic_tests/reference_xhr_in_node_context/mocha_test.js @@ -0,0 +1,44 @@ +var path = require('path'); +var assert = require('assert'); +var spawn = require('child_process').spawn; +var server = global.server; +var port = global.port||13013; + +describe('reference xhr from node context',function(){ + + var crash = true; + var child = undefined; + var connection_handler_callback = undefined; + var connection_handler = function(socket){ + socket.on('data',function(data){ + crash = false; + connection_handler_callback(); + }); + }; + + + before(function(done){ + this.timeout(0); + server.on('connection',connection_handler); + var exec_path = path.join(global.tests_dir,'reference_xhr_in_node_context'); + var exec_argv = [exec_path,port] + child = spawn(process.execPath,exec_argv); + connection_handler_callback = done; + child.on('exit',function(){ + if (crash){ + done(); + } + }); + }); + + after(function(done){ + server.removeListener('connection',connection_handler); + child.kill(); + done(); + }); + + it("reference xhr from node context should not crash",function(done){ + assert.equal(crash,false); + done(); + }); +}); \ No newline at end of file diff --git a/tests/automatic_tests/reference_xhr_in_node_context/package.json b/tests/automatic_tests/reference_xhr_in_node_context/package.json new file mode 100644 index 0000000000..1f456a50f6 --- /dev/null +++ b/tests/automatic_tests/reference_xhr_in_node_context/package.json @@ -0,0 +1,5 @@ +{ + "name":"nw_1404278514", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file diff --git a/tests/automatic_tests/reference_xhr_in_node_context/test.js b/tests/automatic_tests/reference_xhr_in_node_context/test.js new file mode 100644 index 0000000000..e935f938c6 --- /dev/null +++ b/tests/automatic_tests/reference_xhr_in_node_context/test.js @@ -0,0 +1,11 @@ +exports.xhr = function () { + global.xhr.onreadystatechange = function() { + if (global.xhr.readyState === 4 && global.xhr.status === 200) { + } + } + global.xhr.onload = function(e) { + var uInt8Array = new Uint8Array(this.response); // this.response == uInt8Array.buffer + // var byte3 = uInt8Array[4]; // byte at offset 4 + }; + +} \ No newline at end of file From 753cfd5a7057597f2487e0728c2c34a91fb3e1bd Mon Sep 17 00:00:00 2001 From: gitchs Date: Fri, 4 Jul 2014 13:34:10 +0800 Subject: [PATCH 102/492] Fix menu_shortcut test case on Windows --- tests/manual_tests/menu_shortcut/index.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/manual_tests/menu_shortcut/index.html b/tests/manual_tests/menu_shortcut/index.html index 83cf3c44cd..ecd349e91e 100644 --- a/tests/manual_tests/menu_shortcut/index.html +++ b/tests/manual_tests/menu_shortcut/index.html @@ -16,12 +16,10 @@

    var gui = require('nw.gui'); var win = gui.Window.get(); var menubar = new gui.Menu({ type: 'menubar' }); - win.menu = menubar; var menubar_file = new gui.MenuItem({"label":"File"}); menubar.append(menubar_file); var file_menu = new gui.Menu(); - menubar_file.submenu = file_menu; var file_quit_item = new gui.MenuItem({ "label":"Quit", "click":function(){ @@ -51,6 +49,9 @@

    }); file_menu.insert(file_about_item,0); + menubar_file.submenu = file_menu; + win.menu = menubar; + From ad9eefd2fd4c56bec33b21232111df45f80f3a8a Mon Sep 17 00:00:00 2001 From: David Gomes Date: Sat, 5 Jul 2014 17:48:35 +0100 Subject: [PATCH 103/492] Fixes typo. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 836650f5db..aa571adf9c 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ It's created and developed in the Intel Open Source Technology Center. * Complete support for [Node.js APIs](http://nodejs.org/api/) and all its [third party modules](https://npmjs.org). * Good performance: Node and WebKit runs in the same thread: Function calls are made straightforward; objects are in the same heap and can just reference each other; * Easy to package and distribute apps. -* Available on Linux, Mac OSX and Windows +* Available on Linux, Mac OS X and Windows ## Downloads [v0.9.2 release notes](https://groups.google.com/d/msg/node-webkit/qpBhcWr-hSc/caGjhtl8cEgJ) From 0ea2185df08167959fb562d19cc6551eaee6c561 Mon Sep 17 00:00:00 2001 From: libm Date: Fri, 4 Jul 2014 12:22:09 +0800 Subject: [PATCH 104/492] Check URL before navigation Fixed an error when an invalid url is given in the address bar. --- src/nw_shell.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/nw_shell.cc b/src/nw_shell.cc index afd90634ef..6bc6e62025 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -323,6 +323,10 @@ nw::Package* Shell::GetPackage() { } void Shell::LoadURL(const GURL& url) { + if (url.is_empty() || !url.is_valid()) { + LOG(ERROR) << "Unable to load URL: " << url; + return; + } NavigationController::LoadURLParams params(url); params.transition_type = PageTransitionFromInt( PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR); From 8096bd852b97d17dd72ae418abfd13a087e4be88 Mon Sep 17 00:00:00 2001 From: gitchs Date: Tue, 8 Jul 2014 14:08:11 +0800 Subject: [PATCH 105/492] Append http proxy auth test case. --- tests/manual_tests/http_proxy_auth/index.html | 41 +++++++++++++++++++ .../manual_tests/http_proxy_auth/package.json | 5 +++ .../http_proxy_auth/users.htpasswd | 1 + tests/package.json | 2 + tools/build_native_modules.py | 17 ++++++++ 5 files changed, 66 insertions(+) create mode 100644 tests/manual_tests/http_proxy_auth/index.html create mode 100644 tests/manual_tests/http_proxy_auth/package.json create mode 100644 tests/manual_tests/http_proxy_auth/users.htpasswd diff --git a/tests/manual_tests/http_proxy_auth/index.html b/tests/manual_tests/http_proxy_auth/index.html new file mode 100644 index 0000000000..6551a06818 --- /dev/null +++ b/tests/manual_tests/http_proxy_auth/index.html @@ -0,0 +1,41 @@ + + + + + test + + +

    Username: nw

    +

    Password: nw

    +

    If you get no error message in new window, it works fine!

    + + + + \ No newline at end of file diff --git a/tests/manual_tests/http_proxy_auth/package.json b/tests/manual_tests/http_proxy_auth/package.json new file mode 100644 index 0000000000..9c42efd736 --- /dev/null +++ b/tests/manual_tests/http_proxy_auth/package.json @@ -0,0 +1,5 @@ +{ + "name":"nw_1404797845", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file diff --git a/tests/manual_tests/http_proxy_auth/users.htpasswd b/tests/manual_tests/http_proxy_auth/users.htpasswd new file mode 100644 index 0000000000..6c8aa1dd6f --- /dev/null +++ b/tests/manual_tests/http_proxy_auth/users.htpasswd @@ -0,0 +1 @@ +nw:nw \ No newline at end of file diff --git a/tests/package.json b/tests/package.json index 6c0e164aff..dc6b5c490d 100644 --- a/tests/package.json +++ b/tests/package.json @@ -7,6 +7,8 @@ "show": false }, "dependencies": { + "http-auth":"2.1.8", + "http-proxy":"1.1.4", "tar": "*", "commander": "0.6.1", "growl": "1.6.x", diff --git a/tools/build_native_modules.py b/tools/build_native_modules.py index 8b83060806..f480f46cc6 100755 --- a/tools/build_native_modules.py +++ b/tools/build_native_modules.py @@ -52,6 +52,22 @@ win = sys.platform in ('win32', 'cygwin') + +#We need to rebuild a submodule in http-auth +apache_crypt_path = os.path.join( + script_dir, + "..", + "tests", + "node_modules", + "http-auth", + "node_modules", + "htpasswd", + "node_modules", + "apache-crypt") +os.chdir(apache_crypt_path) +subprocess.call(exec_args) + + for dir in native_modules: if dir == 'bignum' and win: @@ -64,4 +80,5 @@ #os.execl(node_gyp_script, '', 'build') + os.chdir(cur_dir) From e437a499a1b1a1296be2501cf60b0e04dae515d0 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Sun, 13 Jul 2014 02:00:27 +0800 Subject: [PATCH 106/492] Update CHANGELOG.md Fix #1984 --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 09d3ada90f..a8b160c189 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,4 @@ -0.9.0-rc1 / 06-22-2014 +0.10.0-rc1 / 06-22-2014 ====================== - Chromium is updated to 35.0.1916.113 From f245fcd47147f9f1c6096547635ef080cff63ee4 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Mon, 14 Jul 2014 00:17:09 +0800 Subject: [PATCH 107/492] [OSX] Fix #1996: resize with flash on 10.9 This is upstream bug #385120 --- nw.gypi | 4 ++++ src/browser/native_window_mac.mm | 2 ++ 2 files changed, 6 insertions(+) diff --git a/nw.gypi b/nw.gypi index 6c65e81e3f..9d20e64864 100644 --- a/nw.gypi +++ b/nw.gypi @@ -391,6 +391,10 @@ 'sources!': [ '<(DEPTH)/chrome/common/child_process_logging_posix.cc', ], + 'sources': [ + '<(DEPTH)/chrome/browser/ui/cocoa/nsview_additions.h', + '<(DEPTH)/chrome/browser/ui/cocoa/nsview_additions.mm', + ], 'dependencies': [ '<(DEPTH)/breakpad/breakpad.gyp:breakpad', '<(DEPTH)/components/components.gyp:breakpad_component', diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index 2afb7a095f..4a20b86a14 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -24,6 +24,7 @@ #include "base/strings/sys_string_conversions.h" #include "base/values.h" #import "chrome/browser/ui/cocoa/custom_frame_view.h" +#import "chrome/browser/ui/cocoa/nsview_additions.h" #include "content/nw/src/api/menu/menu.h" #include "content/nw/src/api/app/app.h" #include "content/nw/src/browser/chrome_event_processing_window.h" @@ -351,6 +352,7 @@ - (NSRect)contentRectForFrameRect:(NSRect)frameRect { } window_ = shell_window; [shell_window setShell:shell]; + [[window() contentView] cr_setWantsLayer:YES]; [window() setDelegate:[[NativeWindowDelegate alloc] initWithShell:shell]]; // Disable fullscreen button when 'fullscreen' is specified to false. From f386b2d6f5af73d1e85793206298b9677d127a81 Mon Sep 17 00:00:00 2001 From: gitchs Date: Mon, 14 Jul 2014 11:46:51 +0800 Subject: [PATCH 108/492] Fix should.js usage error --- tests/automatic_tests/shortcut/mocha_test.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/automatic_tests/shortcut/mocha_test.js b/tests/automatic_tests/shortcut/mocha_test.js index 16eed5174d..57b1a6aa53 100644 --- a/tests/automatic_tests/shortcut/mocha_test.js +++ b/tests/automatic_tests/shortcut/mocha_test.js @@ -18,7 +18,7 @@ describe('Shortcut', function() { shortcut = new gui.Shortcut({"key": "Alt+Shift+S"}); } catch (err) {} - shortcut.should.be.a('object'); + shortcut.should.be.a.Object; assert.equal(shortcut.key, "Alt+Shift+S"); }); }); @@ -37,7 +37,7 @@ describe('Shortcut', function() { var onActive = function() {}; var shortcut = new gui.Shortcut({key: 'Alt+Shift+S', active: onActive}); - shortcut.should.be.a('object'); + shortcut.should.be.a.Object; assert.equal(shortcut.active, onActive); }); }); @@ -56,7 +56,7 @@ describe('Shortcut', function() { var onFailed = function() {}; var shortcut = new gui.Shortcut({key: 'Alt+Shift+S', failed: onFailed}); - shortcut.should.be.a('object'); + shortcut.should.be.a.Object; assert.equal(shortcut.failed, onFailed); }); }); From 95c6554cd33909d66b2565d092ae807e4db33945 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 15 Jul 2014 12:57:21 +0800 Subject: [PATCH 109/492] Fix auth dialog for 0.10 --- src/browser/shell_login_dialog.cc | 7 ++++++- src/browser/shell_login_dialog.h | 3 +++ src/browser/shell_login_dialog_gtk.cc | 12 ++---------- src/shell_browser_context.cc | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/browser/shell_login_dialog.cc b/src/browser/shell_login_dialog.cc index b531b659a9..f832eb670b 100644 --- a/src/browser/shell_login_dialog.cc +++ b/src/browser/shell_login_dialog.cc @@ -2,13 +2,14 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/shell/browser/shell_login_dialog.h" +#include "content/nw/src/browser/shell_login_dialog.h" #include "base/bind.h" #include "base/logging.h" #include "base/strings/utf_string_conversions.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/resource_dispatcher_host.h" +#include "content/public/browser/resource_request_info.h" #include "net/base/auth.h" #include "net/url_request/url_request.h" #include "ui/gfx/text_elider.h" @@ -20,6 +21,10 @@ ShellLoginDialog::ShellLoginDialog( net::URLRequest* request) : auth_info_(auth_info), request_(request) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderFrame( + &render_process_id_, &render_frame_id_)) { + NOTREACHED(); + } BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&ShellLoginDialog::PrepDialog, this, diff --git a/src/browser/shell_login_dialog.h b/src/browser/shell_login_dialog.h index 75450339e5..0e5a3f0965 100644 --- a/src/browser/shell_login_dialog.h +++ b/src/browser/shell_login_dialog.h @@ -51,6 +51,9 @@ class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate { // Threading: any virtual ~ShellLoginDialog(); + int render_process_id_; + int render_frame_id_; + private: // All the methods that begin with Platform need to be implemented by the // platform specific LoginDialog implementation. diff --git a/src/browser/shell_login_dialog_gtk.cc b/src/browser/shell_login_dialog_gtk.cc index 7ac1f583a0..4d779ffeee 100644 --- a/src/browser/shell_login_dialog_gtk.cc +++ b/src/browser/shell_login_dialog_gtk.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/shell/browser/shell_login_dialog.h" +#include "content/nw/src/browser/shell_login_dialog.h" #include @@ -12,7 +12,6 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_frame_host.h" #include "content/public/browser/resource_dispatcher_host.h" -#include "content/public/browser/resource_request_info.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_view.h" #include "ui/base/gtk/gtk_hig_constants.h" @@ -22,16 +21,9 @@ namespace content { void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - int render_process_id; - int render_frame_id; - if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderFrame( - &render_process_id, &render_frame_id)) { - NOTREACHED(); - } - WebContents* web_contents = NULL; RenderFrameHost* render_frame_host = - RenderFrameHost::FromID(render_process_id, render_frame_id); + RenderFrameHost::FromID(render_process_id_, render_frame_id_); web_contents = WebContents::FromRenderFrameHost(render_frame_host); DCHECK(web_contents); diff --git a/src/shell_browser_context.cc b/src/shell_browser_context.cc index b807feef2e..7b82bf3919 100644 --- a/src/shell_browser_context.cc +++ b/src/shell_browser_context.cc @@ -178,7 +178,7 @@ net::URLRequestContextGetter* ShellBrowserContext::CreateRequestContext( cmd_line->GetSwitchValueASCII(switches::kAuthSchemes); if (auth_schemes.empty()) - auth_schemes = "digest,ntlm,negotiate"; + auth_schemes = "basic,digest,ntlm,negotiate"; url_request_getter_ = new ShellURLRequestContextGetter( ignore_certificate_errors_, From 266aee3ae1c7916f896fee8652ca768122f85689 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 16 Jul 2014 09:56:54 +0800 Subject: [PATCH 110/492] implement auth dialog with views framework; dialog ref counting --- nw.gypi | 7 +- src/browser/login_view.cc | 90 +++++++++++++ src/browser/login_view.h | 47 +++++++ src/browser/native_window.h | 15 +++ src/browser/native_window_win.cc | 27 ++++ src/browser/native_window_win.h | 7 +- src/browser/shell_login_dialog.cc | 21 +-- src/browser/shell_login_dialog.h | 33 ++++- src/browser/shell_login_dialog_gtk.cc | 10 ++ src/browser/shell_login_dialog_win.cc | 179 +++++++++++++++----------- src/nw_shell.cc | 20 +++ src/nw_shell.h | 11 ++ 12 files changed, 376 insertions(+), 91 deletions(-) create mode 100644 src/browser/login_view.cc create mode 100644 src/browser/login_view.h diff --git a/nw.gypi b/nw.gypi index 9d20e64864..d88bd9e989 100644 --- a/nw.gypi +++ b/nw.gypi @@ -250,7 +250,7 @@ 'src/browser/shell_javascript_dialog.h', 'src/browser/shell_login_dialog_gtk.cc', 'src/browser/shell_login_dialog_mac.mm', - #FIXME 'src/browser/shell_login_dialog_win.cc', + 'src/browser/shell_login_dialog_win.cc', 'src/browser/shell_login_dialog.cc', 'src/browser/shell_login_dialog.h', 'src/browser/shell_resource_dispatcher_host_delegate.cc', @@ -364,15 +364,20 @@ }], ['OS=="win"', { 'sources': [ + '<(DEPTH)/chrome/browser/ui/views/constrained_window_views.cc', + '<(DEPTH)/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc', 'src/browser/autofill_popup_base_view.cc', 'src/browser/autofill_popup_base_view.h', 'src/browser/autofill_popup_view_views.cc', 'src/browser/autofill_popup_view_views.h', + 'src/browser/login_view.cc', + 'src/browser/login_view.h', ], 'dependencies': [ '<(DEPTH)/breakpad/breakpad.gyp:breakpad_handler', '<(DEPTH)/breakpad/breakpad.gyp:breakpad_sender', '<(DEPTH)/components/components.gyp:breakpad_component', + '<(DEPTH)/components/components.gyp:web_modal', ], }], ['os_posix==1 and OS != "mac" and OS != "ios"', { diff --git a/src/browser/login_view.cc b/src/browser/login_view.cc new file mode 100644 index 0000000000..5220882397 --- /dev/null +++ b/src/browser/login_view.cc @@ -0,0 +1,90 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "login_view.h" + +#include "base/strings/utf_string_conversions.h" +#include "grit/generated_resources.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/views/controls/label.h" +#include "ui/views/controls/textfield/textfield.h" +#include "ui/views/layout/grid_layout.h" +#include "ui/views/layout/layout_constants.h" + +static const int kMessageWidth = 320; +static const int kTextfieldStackHorizontalSpacing = 30; + +using views::GridLayout; + +/////////////////////////////////////////////////////////////////////////////// +// LoginView, public: + +LoginView::LoginView(const base::string16& explanation) + : username_field_(new views::Textfield()), + password_field_(new views::Textfield()), + username_label_(new views::Label(base::ASCIIToUTF16("Username"))), + password_label_(new views::Label(base::ASCIIToUTF16("Password"))), + message_label_(new views::Label(explanation)) { + password_field_->SetTextInputType(ui::TEXT_INPUT_TYPE_PASSWORD); + message_label_->SetMultiLine(true); + message_label_->SetHorizontalAlignment(gfx::ALIGN_LEFT); + message_label_->SetAllowCharacterBreak(true); + + // Initialize the Grid Layout Manager used for this dialog box. + GridLayout* layout = GridLayout::CreatePanel(this); + SetLayoutManager(layout); + + // Add the column set for the information message at the top of the dialog + // box. + const int single_column_view_set_id = 0; + views::ColumnSet* column_set = + layout->AddColumnSet(single_column_view_set_id); + column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1, + GridLayout::FIXED, kMessageWidth, 0); + + // Add the column set for the user name and password fields and labels. + const int labels_column_set_id = 1; + column_set = layout->AddColumnSet(labels_column_set_id); + column_set->AddPaddingColumn(0, kTextfieldStackHorizontalSpacing); + column_set->AddColumn(GridLayout::LEADING, GridLayout::CENTER, 0, + GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, views::kRelatedControlHorizontalSpacing); + column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1, + GridLayout::USE_PREF, 0, 0); + column_set->AddPaddingColumn(0, kTextfieldStackHorizontalSpacing); + + layout->StartRow(0, single_column_view_set_id); + layout->AddView(message_label_); + + layout->AddPaddingRow(0, views::kUnrelatedControlLargeVerticalSpacing); + + layout->StartRow(0, labels_column_set_id); + layout->AddView(username_label_); + layout->AddView(username_field_); + + layout->AddPaddingRow(0, views::kRelatedControlVerticalSpacing); + + layout->StartRow(0, labels_column_set_id); + layout->AddView(password_label_); + layout->AddView(password_field_); + + layout->AddPaddingRow(0, views::kUnrelatedControlVerticalSpacing); + +} + +LoginView::~LoginView() { +} + +const base::string16& LoginView::GetUsername() const { + return username_field_->text(); +} + +const base::string16& LoginView::GetPassword() const { + return password_field_->text(); +} + +views::View* LoginView::GetInitiallyFocusedView() { + return username_field_; +} + diff --git a/src/browser/login_view.h b/src/browser/login_view.h new file mode 100644 index 0000000000..b254f1e5ee --- /dev/null +++ b/src/browser/login_view.h @@ -0,0 +1,47 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_VIEWS_LOGIN_VIEW_H_ +#define CHROME_BROWSER_UI_VIEWS_LOGIN_VIEW_H_ + +#include "base/compiler_specific.h" +#include "ui/views/view.h" + +namespace views { +class Label; +class Textfield; +} + +// This class is responsible for displaying the contents of a login window +// for HTTP/FTP authentication. +class LoginView : public views::View { + public: + // |model| is observed for the entire lifetime of the LoginView. + // Therefore |model| should not be destroyed before the LoginView object. + LoginView(const base::string16& explanation); + virtual ~LoginView(); + + // Access the data in the username/password text fields. + const base::string16& GetUsername() const; + const base::string16& GetPassword() const; + + // Used by LoginHandlerWin to set the initial focus. + views::View* GetInitiallyFocusedView(); + + private: + // Non-owning refs to the input text fields. + views::Textfield* username_field_; + views::Textfield* password_field_; + + // Button labels + views::Label* username_label_; + views::Label* password_label_; + + // Authentication message. + views::Label* message_label_; + + DISALLOW_COPY_AND_ASSIGN(LoginView); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_LOGIN_VIEW_H_ diff --git a/src/browser/native_window.h b/src/browser/native_window.h index fff9e11347..6cd8236ef6 100644 --- a/src/browser/native_window.h +++ b/src/browser/native_window.h @@ -34,6 +34,10 @@ #include "ui/gfx/point.h" #include "ui/gfx/size.h" +#if defined(OS_WIN) +#include "components/web_modal/web_contents_modal_dialog_host.h" +#endif + namespace nwapi { class Menu; } @@ -60,7 +64,11 @@ namespace nw { class CapturePageHelper; +#if defined(OS_WIN) +class NativeWindow : public web_modal::WebContentsModalDialogHost { +#else class NativeWindow { +#endif public: virtual ~NativeWindow(); @@ -119,6 +127,13 @@ class NativeWindow { virtual void HandleKeyboardEvent( const content::NativeWebKeyboardEvent& event) = 0; +#if defined(OS_WIN) + virtual gfx::NativeView GetHostView() const OVERRIDE = 0; + virtual gfx::Point GetDialogPosition(const gfx::Size& size) OVERRIDE = 0; + virtual void AddObserver(web_modal::ModalDialogHostObserver* observer) OVERRIDE = 0; + virtual void RemoveObserver(web_modal::ModalDialogHostObserver* observer) OVERRIDE = 0; + virtual gfx::Size GetMaximumDialogSize() OVERRIDE = 0; +#endif content::Shell* shell() const { return shell_.get(); } content::WebContents* web_contents() const; bool has_frame() const { return has_frame_; } diff --git a/src/browser/native_window_win.cc b/src/browser/native_window_win.cc index c9c733b315..68d5cc2d34 100644 --- a/src/browser/native_window_win.cc +++ b/src/browser/native_window_win.cc @@ -306,6 +306,9 @@ NativeWindowWin::NativeWindowWin(const base::WeakPtr& shell, } NativeWindowWin::~NativeWindowWin() { + FOR_EACH_OBSERVER(web_modal::ModalDialogHostObserver, + observer_list_, + OnHostDestroying()); views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); } @@ -864,4 +867,28 @@ bool NativeWindowWin::ShouldDescendIntoChildForEventHandling( return true; } + +gfx::NativeView NativeWindowWin::GetHostView() const { + return window_->GetNativeView(); +} + +gfx::Size NativeWindowWin::GetMaximumDialogSize() { + return window_->GetWindowBoundsInScreen().size(); +} + +gfx::Point NativeWindowWin::GetDialogPosition(const gfx::Size& size) { + gfx::Size app_window_size = window_->GetWindowBoundsInScreen().size(); + return gfx::Point(app_window_size.width() / 2 - size.width() / 2, + app_window_size.height() / 2 - size.height() / 2); +} + +void NativeWindowWin::AddObserver(web_modal::ModalDialogHostObserver* observer) { + if (observer && !observer_list_.HasObserver(observer)) + observer_list_.AddObserver(observer); +} + +void NativeWindowWin::RemoveObserver(web_modal::ModalDialogHostObserver* observer) { + observer_list_.RemoveObserver(observer); +} + } // namespace nw diff --git a/src/browser/native_window_win.h b/src/browser/native_window_win.h index 186025ecff..ba528c7ffe 100644 --- a/src/browser/native_window_win.h +++ b/src/browser/native_window_win.h @@ -126,6 +126,11 @@ class NativeWindowWin : public NativeWindow, virtual bool CanHandleAccelerators() const OVERRIDE{ return true; } + virtual gfx::NativeView GetHostView() const OVERRIDE; + virtual gfx::Point GetDialogPosition(const gfx::Size& size) OVERRIDE; + virtual void AddObserver(web_modal::ModalDialogHostObserver* observer) OVERRIDE; + virtual void RemoveObserver(web_modal::ModalDialogHostObserver* observer) OVERRIDE; + virtual gfx::Size GetMaximumDialogSize() OVERRIDE; protected: // NativeWindow implementation. @@ -184,7 +189,7 @@ class NativeWindowWin : public NativeWindow, bool super_down_; bool meta_down_; - + ObserverList observer_list_; DISALLOW_COPY_AND_ASSIGN(NativeWindowWin); }; diff --git a/src/browser/shell_login_dialog.cc b/src/browser/shell_login_dialog.cc index f832eb670b..1dfb826d1b 100644 --- a/src/browser/shell_login_dialog.cc +++ b/src/browser/shell_login_dialog.cc @@ -20,6 +20,14 @@ ShellLoginDialog::ShellLoginDialog( net::AuthChallengeInfo* auth_info, net::URLRequest* request) : auth_info_(auth_info), request_(request) { +#if !defined(OS_MACOSX) + AddRef(); +#endif + +#if defined(OS_WIN) + dialog_ = NULL; +#endif + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); if (!ResourceRequestInfo::ForRequest(request_)->GetAssociatedRenderFrame( &render_process_id_, &render_frame_id_)) { @@ -64,15 +72,6 @@ ShellLoginDialog::~ShellLoginDialog() { // referenced/dereferenced. } -#if !defined(OS_MACOSX) && !defined(TOOLKIT_GTK) -// Bogus implementations for linking. They are never called because -// ResourceDispatcherHostDelegate::CreateLoginDelegate returns NULL. -// TODO: implement ShellLoginDialog for other platforms, drop this #if -void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) {} -void ShellLoginDialog::PlatformCleanUp() {} -void ShellLoginDialog::PlatformRequestCancelled() {} -#endif - void ShellLoginDialog::PrepDialog(const base::string16& host, const base::string16& realm) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); @@ -109,4 +108,8 @@ void ShellLoginDialog::SendAuthToRequester(bool success, base::Bind(&ShellLoginDialog::PlatformCleanUp, this)); } +void ShellLoginDialog::ReleaseSoon() { + BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this); +} + } // namespace content diff --git a/src/browser/shell_login_dialog.h b/src/browser/shell_login_dialog.h index 0e5a3f0965..10a0181d3f 100644 --- a/src/browser/shell_login_dialog.h +++ b/src/browser/shell_login_dialog.h @@ -13,6 +13,11 @@ #include "ui/base/gtk/gtk_signal.h" #endif +#if defined(OS_WIN) +#include "ui/views/window/dialog_delegate.h" +#include "login_view.h" +#endif + #if defined(OS_MACOSX) #if __OBJC__ @class ShellLoginDialogHelper; @@ -30,7 +35,11 @@ namespace content { // This class provides a dialog box to ask the user for credentials. Useful in // ResourceDispatcherHostDelegate::CreateLoginDelegate. +#if defined(OS_WIN) +class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate, public views::DialogDelegate { +#else class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate { +#endif public: // Threading: IO thread. ShellLoginDialog(net::AuthChallengeInfo* auth_info, net::URLRequest* request); @@ -47,9 +56,25 @@ class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate { const base::string16& password); void UserCancelledAuth(); +#if defined(OS_WIN) + // views::DialogDelegate methods: + virtual base::string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE; + virtual base::string16 GetWindowTitle() const OVERRIDE; + virtual void WindowClosing() OVERRIDE; + virtual void DeleteDelegate() OVERRIDE; + virtual ui::ModalType GetModalType() const OVERRIDE; + virtual bool Cancel() OVERRIDE; + virtual bool Accept() OVERRIDE; + virtual views::View* GetInitiallyFocusedView() OVERRIDE; + virtual views::View* GetContentsView() OVERRIDE; + virtual views::Widget* GetWidget() OVERRIDE; + virtual const views::Widget* GetWidget() const OVERRIDE; +#endif + protected: // Threading: any virtual ~ShellLoginDialog(); + void ReleaseSoon(); int render_process_id_; int render_frame_id_; @@ -93,11 +118,11 @@ class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate { GtkWidget* password_entry_; GtkWidget* root_; CHROMEGTK_CALLBACK_1(ShellLoginDialog, void, OnResponse, int); + CHROMEGTK_CALLBACK_0(ShellLoginDialog, void, OnDestroy); #elif defined(OS_WIN) -INT_PTR CALLBACK DialogProc(HWND dialog, - UINT message, - WPARAM wparam, - LPARAM lparam); + LoginView* login_view_; + + views::Widget* dialog_; #endif }; diff --git a/src/browser/shell_login_dialog_gtk.cc b/src/browser/shell_login_dialog_gtk.cc index 4d779ffeee..d8239351ff 100644 --- a/src/browser/shell_login_dialog_gtk.cc +++ b/src/browser/shell_login_dialog_gtk.cc @@ -69,6 +69,8 @@ void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) { gtk_box_pack_start(GTK_BOX(content_area), table, FALSE, FALSE, 0); g_signal_connect(root_, "response", G_CALLBACK(OnResponseThunk), this); + g_signal_connect(root_, "destroy", G_CALLBACK(OnDestroyThunk), this); + gtk_widget_grab_focus(username_entry_); gtk_widget_show_all(GTK_WIDGET(root_)); } @@ -99,4 +101,12 @@ void ShellLoginDialog::OnResponse(GtkWidget* sender, int response_id) { gtk_widget_destroy(root_); } +void ShellLoginDialog::OnDestroy(GtkWidget* widget) { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + root_ = NULL; + + ReleaseSoon(); +} + } // namespace content diff --git a/src/browser/shell_login_dialog_win.cc b/src/browser/shell_login_dialog_win.cc index 2787067ff6..156d3af07f 100644 --- a/src/browser/shell_login_dialog_win.cc +++ b/src/browser/shell_login_dialog_win.cc @@ -23,107 +23,134 @@ #include "base/logging.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" +#include "components/web_modal/web_contents_modal_dialog_host.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" +#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" #include "content/nw/src/resource.h" #include "content/public/browser/browser_thread.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/resource_dispatcher_host.h" #include "content/public/browser/resource_request_info.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_view.h" +#include "ui/base/l10n/l10n_util.h" +#include "ui/views/widget/widget.h" -namespace content { +using web_modal::WebContentsModalDialogManager; +using web_modal::WebContentsModalDialogManagerDelegate; -INT_PTR CALLBACK ShellLoginDialog::DialogProc(HWND dialog, - UINT message, - WPARAM wparam, - LPARAM lparam) { - switch (message) { - case WM_INITDIALOG: { - SetWindowLongPtr(dialog, DWL_USER, static_cast(lparam)); - ShellLoginDialog* owner = reinterpret_cast(lparam); - owner->dialog_win_ = dialog; - SetDlgItemText(dialog, - IDC_DIALOG_MESSAGETEXT, - owner->message_text_.c_str()); - break; - } - case WM_CLOSE: { - ShellLoginDialog* owner = reinterpret_cast( - GetWindowLongPtr(dialog, DWL_USER)); - owner->UserCancelledAuth(); - DestroyWindow(owner->dialog_win_); - break; - } - case WM_DESTROY: { - ShellLoginDialog* owner = reinterpret_cast( - GetWindowLongPtr(dialog, DWL_USER)); - owner->dialog_win_ = NULL; - owner->ReleaseSoon(); - break; - } - case WM_COMMAND: { - ShellLoginDialog* owner = reinterpret_cast( - GetWindowLongPtr(dialog, DWL_USER)); - if (LOWORD(wparam) == IDOK) { - base::string16 username; - base::string16 password; - size_t length = - GetWindowTextLength(GetDlgItem(dialog, IDC_USERNAMEEDIT)) + 1; - GetDlgItemText(dialog, IDC_USERNAMEEDIT, - WriteInto(&username, length), length); - length = GetWindowTextLength(GetDlgItem(dialog, IDC_PASSWORDEDIT)) + 1; - GetDlgItemText(dialog, IDC_PASSWORDEDIT, - WriteInto(&password, length), length); - owner->UserAcceptedAuth(username, password); - } else if (LOWORD(wparam) == IDCANCEL) { - owner->UserCancelledAuth(); - } else { - DLOG(INFO) << "wparam is " << LOWORD(wparam); - // NOTREACHED(); - } - - break; - } - default: - return DefWindowProc(dialog, message, wparam, lparam); - } - - return 0; -} +namespace content { void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - WebContents* web_contents = NULL; - RenderViewHost* render_view_host = - RenderViewHost::FromID(render_process_id_, render_view_id_); - if (render_view_host) - web_contents = WebContents::FromRenderViewHost(render_view_host); - DCHECK(web_contents); - - gfx::NativeWindow parent_window = - web_contents->GetView()->GetTopLevelNativeWindow(); - message_text_ = message; - dialog_win_ = CreateDialogParam(GetModuleHandle(0), - MAKEINTRESOURCE(IDD_LOGIN), parent_window, - DialogProc, reinterpret_cast(this)); + login_view_ = new LoginView(message); + + // Scary thread safety note: This can potentially be called *after* SetAuth + // or CancelAuth (say, if the request was cancelled before the UI thread got + // control). However, that's OK since any UI interaction in those functions + // will occur via an InvokeLater on the UI thread, which is guaranteed + // to happen after this is called (since this was InvokeLater'd first). + content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( + render_process_id_, render_frame_id_); + + WebContents* requesting_contents = WebContents::FromRenderFrameHost(rfh); + WebContentsModalDialogManager* web_contents_modal_dialog_manager = + WebContentsModalDialogManager::FromWebContents(requesting_contents); + WebContentsModalDialogManagerDelegate* modal_delegate = + web_contents_modal_dialog_manager->delegate(); + CHECK(modal_delegate); + dialog_ = views::Widget::CreateWindowAsFramelessChild( + this, modal_delegate->GetWebContentsModalDialogHost()->GetHostView()); + web_contents_modal_dialog_manager->ShowDialog(dialog_->GetNativeView()); + } +#if 0 void ShellLoginDialog::PlatformShowDialog() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - ShowWindow(dialog_win_, SW_SHOWNORMAL); } +#endif void ShellLoginDialog::PlatformCleanUp() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - if (dialog_win_) { - DestroyWindow(dialog_win_); - dialog_win_ = NULL; - } + if (dialog_) + dialog_->Close(); } void ShellLoginDialog::PlatformRequestCancelled() { DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); } + +base::string16 ShellLoginDialog::GetDialogButtonLabel( + ui::DialogButton button) const { + if (button == ui::DIALOG_BUTTON_OK) + return base::ASCIIToUTF16("Log In"); + return DialogDelegate::GetDialogButtonLabel(button); +} + +base::string16 ShellLoginDialog::GetWindowTitle() const { + return base::ASCIIToUTF16("Authentication Required"); +} + +void ShellLoginDialog::WindowClosing() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + content::RenderFrameHost* rfh = content::RenderFrameHost::FromID( + render_process_id_, render_frame_id_); + + WebContents* tab = WebContents::FromRenderFrameHost(rfh); + + if (tab) + tab->GetRenderViewHost()->SetIgnoreInputEvents(false); + + // Reference is no longer valid. + dialog_ = NULL; + + // UserCancelledAuth(); +} + +void ShellLoginDialog::DeleteDelegate() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + // The widget is going to delete itself; clear our pointer. + dialog_ = NULL; + + ReleaseSoon(); +} + +ui::ModalType ShellLoginDialog::GetModalType() const { + return views::WidgetDelegate::GetModalType(); +} + +bool ShellLoginDialog::Cancel() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + UserCancelledAuth(); + return true; +} + +bool ShellLoginDialog::Accept() { + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + + UserAcceptedAuth(login_view_->GetUsername(), login_view_->GetPassword()); + return true; +} + +views::View* ShellLoginDialog::GetInitiallyFocusedView() { + return login_view_->GetInitiallyFocusedView(); +} + +views::View* ShellLoginDialog::GetContentsView() { + return login_view_; +} +views::Widget* ShellLoginDialog::GetWidget() { + return login_view_->GetWidget(); +} +const views::Widget* ShellLoginDialog::GetWidget() const { + return login_view_->GetWidget(); +} + } // namespace content diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 6bc6e62025..b93ae4f698 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -67,6 +67,7 @@ #include "components/autofill/content/browser/content_autofill_driver.h" #include "components/autofill/core/browser/autofill_manager.h" +#include "components/web_modal/web_contents_modal_dialog_manager.h" #if defined(OS_WIN) @@ -201,6 +202,10 @@ Shell::Shell(WebContents* web_contents, base::DictionaryValue* manifest) // NativeWindow requires the window_ to be non-NULL. window_->InitFromManifest(manifest); +#if defined(OS_WIN) + web_modal::WebContentsModalDialogManager::CreateForWebContents(web_contents); + web_modal::WebContentsModalDialogManager::FromWebContents(web_contents)->SetDelegate(this); +#endif autofill::TabAutofillManagerDelegate::CreateForWebContents(web_contents); autofill::ContentAutofillDriver::CreateForWebContentsAndDelegate( web_contents, @@ -587,6 +592,14 @@ void Shell::WebContentsCreated(WebContents* source_contents, // should be handled here new nwapi::DispatcherHost(new_contents->GetRenderViewHost()); +#if defined(ENABLE_PRINTING) + printing::PrintViewManager::CreateForWebContents(new_contents); +#endif + +#if defined(OS_WIN) + web_modal::WebContentsModalDialogManager::CreateForWebContents(new_contents); + web_modal::WebContentsModalDialogManager::FromWebContents(new_contents)->SetDelegate(this); +#endif autofill::TabAutofillManagerDelegate::CreateForWebContents(new_contents); autofill::ContentAutofillDriver::CreateForWebContentsAndDelegate( new_contents, @@ -693,4 +706,11 @@ void Shell::RenderViewCreated(RenderViewHost* render_view_host) { new nwapi::DispatcherHost(render_view_host); } +#if defined(OS_WIN) +bool Shell::IsWebContentsVisible(content::WebContents* web_contents) { + //FIXME + return true; +} +#endif + } // namespace content diff --git a/src/nw_shell.h b/src/nw_shell.h index a2b80adb79..b364293e6f 100644 --- a/src/nw_shell.h +++ b/src/nw_shell.h @@ -30,6 +30,9 @@ #include "content/public/browser/notification_observer.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" +#if defined(OS_WIN) +#include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" +#endif #include "ipc/ipc_channel.h" namespace base { @@ -61,6 +64,9 @@ using base::FilePath; // 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, +#if defined(OS_WIN) + public web_modal::WebContentsModalDialogManagerDelegate, +#endif public content::WebContentsObserver, public NotificationObserver { public: @@ -134,6 +140,11 @@ class Shell : public WebContentsDelegate, int id() const { return id_; } virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE; +#if defined(OS_WIN) + virtual void SetWebContentsBlocked(content::WebContents* web_contents, bool) OVERRIDE {} + virtual bool IsWebContentsVisible(content::WebContents* web_contents); + virtual web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost() OVERRIDE{ return (web_modal::WebContentsModalDialogHost*)window(); } +#endif protected: // content::WebContentsObserver implementation. From 8932fba79293df8d1d978624d5f52626ae881106 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Wed, 16 Jul 2014 15:42:18 +0800 Subject: [PATCH 111/492] [README] better downloads list --- README.md | 35 +++++++++++++++-------------------- 1 file changed, 15 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index aa571adf9c..8e1ceae4e6 100644 --- a/README.md +++ b/README.md @@ -20,32 +20,27 @@ It's created and developed in the Intel Open Source Technology Center. * Available on Linux, Mac OS X and Windows ## Downloads -[v0.9.2 release notes](https://groups.google.com/d/msg/node-webkit/qpBhcWr-hSc/caGjhtl8cEgJ) +* **0.9.2:** (Feb 20, 2014, based off of Node v0.11.9, Chrome 32.0.1700.107): [release notes](https://groups.google.com/d/msg/node-webkit/qpBhcWr-hSc/caGjhtl8cEgJ) + * Linux: [32bit](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-linux-x64.tar.gz) + * Windows: [win32](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-win-ia32.zip) + * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-osx-ia32.zip) -Prebuilt binaries (v0.9.2 - Feb 20, 2014, based off of Node v0.11.9, Chrome 32.0.1700.107): +* **v0.10.0-rc1:** (Jun 22, 2014, based off of Node v0.11.13, Chromium 35.0.1916.113): [release notes](https://groups.google.com/d/msg/node-webkit/zysKp3n37_4/Bs-QWWgsNIEJ) -* Linux: [32bit](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-linux-ia32.tar.gz) / [64bit] (http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-linux-x64.tar.gz) -* Windows: [win32](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-win-ia32.zip) -* Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-osx-ia32.zip) + * Linux: [32bit](http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-linux-x64.tar.gz) + * Windows: [win32](http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-win-ia32.zip) + * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-osx-ia32.zip) -[v0.10.0-rc1 release notes](https://groups.google.com/d/msg/node-webkit/zysKp3n37_4/Bs-QWWgsNIEJ) +* **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** +[release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) -Prebuilt binaries (v0.10.0-rc1 - Jun 22, 2014, based off of Node v0.11.13, Chromium 35.0.1916.113): + * Linux: [32bit](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-linux-x64.tar.gz) + * Windows: [win32](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-win-ia32.zip) + * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-osx-ia32.zip) -* Linux: [32bit](http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-linux-ia32.tar.gz) / [64bit] (http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-linux-x64.tar.gz) -* Windows: [win32](http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-win-ia32.zip) -* Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-osx-ia32.zip) +* **latest live build**: git tip version; build triggered from every git commit: http://dl.node-webkit.org/live-build/ -**If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** -[v0.8.6 release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) - -Prebuilt binaries (v0.8.6 - Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66): - -* Linux: [32bit](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-linux-ia32.tar.gz) / [64bit] (http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-linux-x64.tar.gz) -* Windows: [win32](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-win-ia32.zip) -* Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.8.6/node-webkit-v0.8.6-osx-ia32.zip) - -[Looking for older versions?](https://github.com/rogerwang/node-webkit/wiki/Downloads-of-old-versions) +* [Previous versions](https://github.com/rogerwang/node-webkit/wiki/Downloads-of-old-versions) ###Demos and real apps You may also be interested in [our demos repository](https://github.com/zcbenz/nw-sample-apps) and the [List of apps and companies using node-webkit](https://github.com/rogerwang/node-webkit/wiki/List-of-apps-and-companies-using-node-webkit). From 18afdf385edf598f9bfee6b179b53addba53f996 Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 17 Jul 2014 14:43:23 +0800 Subject: [PATCH 112/492] Revert "[nw10] disable nwsnapshot for now" This reverts commit eff1e977c46a77aecb7b789519ba448b3b5ea583. Conflicts: tools/package_binaries.py --- nw.gypi | 4 ++-- tools/package_binaries.py | 8 +++----- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/nw.gypi b/nw.gypi index d88bd9e989..f6bfe28ee4 100644 --- a/nw.gypi +++ b/nw.gypi @@ -708,7 +708,7 @@ { 'action_name': 'strip_nw_binaries', 'inputs': [ -# '<(PRODUCT_DIR)/nwsnapshot', + '<(PRODUCT_DIR)/nwsnapshot', '<(PRODUCT_DIR)/chromedriver', ], 'outputs': [ @@ -720,7 +720,7 @@ }, ], 'dependencies': [ -# '<(DEPTH)/v8/tools/gyp/v8.gyp:nwsnapshot', + '<(DEPTH)/v8/tools/gyp/v8.gyp:nwsnapshot', '<(DEPTH)/chrome/chrome.gyp:chromedriver', ], }], diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 0a14028b2c..3035f6e587 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -105,7 +105,7 @@ def generate_target_nw(platform_name, arch, version): 'credits.html', 'libffmpegsumo.so', 'nw.pak', -# 'nwsnapshot', + 'nwsnapshot', 'nw', 'icudtl.dat', ] @@ -117,15 +117,13 @@ def generate_target_nw(platform_name, arch, version): 'libGLESv2.dll', 'nw.exe', 'nw.pak', -# 'nw.exp', -# 'nw.lib', -# 'nwsnapshot.exe', + 'nwsnapshot.exe', 'credits.html', ] elif platform_name == 'osx': target['input'] = [ 'node-webkit.app', -# 'nwsnapshot', + 'nwsnapshot', 'credits.html', ] else: From 97812bfe4e5844b125f342f29d831d44598e5837 Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 17 Jul 2014 14:51:07 +0800 Subject: [PATCH 113/492] bump version to 0.10.0-rc2 --- src/nw_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nw_version.h b/src/nw_version.h index 6c449f0b66..b30a4d42ab 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -38,7 +38,7 @@ #else # define NW_VERSION_STRING NW_STRINGIFY(NW_MAJOR_VERSION) "." \ NW_STRINGIFY(NW_MINOR_VERSION) "." \ - NW_STRINGIFY(NW_PATCH_VERSION) "-rc1" + NW_STRINGIFY(NW_PATCH_VERSION) "-rc2" #endif #define NW_VERSION "v" NW_VERSION_STRING From 7643c2d93c21b2fd5bb057ddeb9c234abd5cccbe Mon Sep 17 00:00:00 2001 From: gitchs Date: Fri, 18 Jul 2014 15:14:06 +0800 Subject: [PATCH 114/492] Fix copy hardcode file name --- tests/automatic_tests/start_app/script.js | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/tests/automatic_tests/start_app/script.js b/tests/automatic_tests/start_app/script.js index 497bb9b9ef..da2c09376d 100644 --- a/tests/automatic_tests/start_app/script.js +++ b/tests/automatic_tests/start_app/script.js @@ -5,20 +5,9 @@ var cp = require('child_process'); var exec = cp.exec; var sqawn = cp.sqawn; -var required_file_win = [ - 'ffmpegsumo.dll', - 'icudt.dll', - 'libEGL.dll', - 'libGLESv2.dll', - 'nw.exe', - 'nw.pak' -]; - -var required_file_linux = [ - 'nw', - 'nw.pak', - 'libffmpegsumo.so' -]; +var required_file_win_linux = fs.readdirSync(path.dirname(process.execPath)); +var required_file_win = required_file_win_linux; +var required_file_linux = required_file_win_linux; var required_file_macox = [ 'node-webkit.app' From 1df8fa2e130da75500250782800befdd2b91fb2f Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 18 Jul 2014 23:03:42 +0800 Subject: [PATCH 115/492] [CHANGELOG] update for v0.10.0-rc2 --- CHANGELOG.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8b160c189..5488f7a33d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,17 @@ +0.10.0-rc2 / 07-18-2014 +======================= + +- [API] Implement register/unregister global desktop keyboard shortcut. (#1735, thanks to Chaobin Zhang and Haojian Wu) +- support for nwsnapshot is back +- Fix: authentication dialog +- check invalid URL on navigation +- [OSX] Fix #1996: resize with flash on 10.9 (upstream #385120) +- Fix regression: node-main +- Fix regression: [WIN] resize and drag frameless window +- Fix: crash on Win XP (#1985) + 0.10.0-rc1 / 06-22-2014 -====================== +======================= - Chromium is updated to 35.0.1916.113 - Node.js is updated to 0.11.13 From 718dcadd627ca7f0cfe9104fc801bae437f144fd Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 18 Jul 2014 23:11:47 +0800 Subject: [PATCH 116/492] [README] update for v0.10.0-rc2 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8e1ceae4e6..fc7b728589 100644 --- a/README.md +++ b/README.md @@ -25,11 +25,11 @@ It's created and developed in the Intel Open Source Technology Center. * Windows: [win32](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-win-ia32.zip) * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-osx-ia32.zip) -* **v0.10.0-rc1:** (Jun 22, 2014, based off of Node v0.11.13, Chromium 35.0.1916.113): [release notes](https://groups.google.com/d/msg/node-webkit/zysKp3n37_4/Bs-QWWgsNIEJ) +* **v0.10.0-rc2:** (Jul 18, 2014, based off of Node v0.11.13, Chromium 35.0.1916.113): [release notes](https://groups.google.com/d/msg/node-webkit/mdfF9rS38oQ/0QzIVqytGIoJ) - * Linux: [32bit](http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-linux-x64.tar.gz) - * Windows: [win32](http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-win-ia32.zip) - * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.10.0-rc1/node-webkit-v0.10.0-rc1-osx-ia32.zip) + * Linux: [32bit](http://dl.node-webkit.org/v0.10.0-rc2/node-webkit-v0.10.0-rc2-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.0-rc2/node-webkit-v0.10.0-rc2-linux-x64.tar.gz) + * Windows: [win32](http://dl.node-webkit.org/v0.10.0-rc2/node-webkit-v0.10.0-rc2-win-ia32.zip) + * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.10.0-rc2/node-webkit-v0.10.0-rc2-osx-ia32.zip) * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From 5511f62aa9c7f630a80f7c7ddf62fdf9634ec381 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Tue, 22 Jul 2014 00:46:19 +0800 Subject: [PATCH 117/492] [WIN] update menuitems properties with UpdateStates of top menu Fix #1132 --- src/api/menu/menu.h | 11 ++++++++++- src/api/menu/menu_win.cc | 21 +++++++++++++++++++++ src/api/menuitem/menuitem.h | 1 + src/api/menuitem/menuitem_win.cc | 9 +++++++++ src/browser/native_window_win.cc | 1 + src/browser/native_window_win.h | 6 ++++++ 6 files changed, 48 insertions(+), 1 deletion(-) diff --git a/src/api/menu/menu.h b/src/api/menu/menu.h index fb319c6c1f..e3384d8be7 100644 --- a/src/api/menu/menu.h +++ b/src/api/menu/menu.h @@ -53,6 +53,10 @@ namespace nw { class NativeWindowWin; } +namespace nwapi { +class Menu; +} + namespace ui { // A derived class to override |HasIcons| to prevent the |NativeMenuWin| from @@ -65,6 +69,9 @@ class NwMenuModel : public SimpleMenuModel { // Overridden from MenuModel: virtual bool HasIcons() const OVERRIDE; + +protected: + friend class nwapi::Menu; }; } // namespace ui @@ -124,12 +131,14 @@ class Menu : public Base { friend class nw::NativeWindowWin; void Rebuild(const HMENU *parent_menu = NULL); + void UpdateStates(); + void SetWindow(nw::NativeWindowWin* win); //**Never Try to free this pointer** //We get it from top widget views::FocusManager *focus_manager_; std::vector menu_items_; - + nw::NativeWindowWin* window_; // Flag to indicate the menu has been modified since last show, so we should // rebuild the menu before next show. bool is_menu_modified_; diff --git a/src/api/menu/menu_win.cc b/src/api/menu/menu_win.cc index 508ba61c84..9d67e93d5a 100644 --- a/src/api/menu/menu_win.cc +++ b/src/api/menu/menu_win.cc @@ -88,6 +88,7 @@ void Menu::Create(const base::DictionaryValue& option) { menu_.reset(new views::NativeMenuWin(menu_model_.get(), NULL)); focus_manager_ = NULL; + window_ = NULL; std::string type; if (option.GetString("type", &type) && type == "menubar") @@ -114,6 +115,7 @@ void Menu::Append(MenuItem* menu_item) { is_menu_modified_ = true; menu_items_.push_back(menu_item); + menu_item->menu_ = this; } void Menu::Insert(MenuItem* menu_item, int pos) { @@ -128,11 +130,14 @@ void Menu::Insert(MenuItem* menu_item, int pos) { menu_model_->InsertSeparatorAt(pos, ui::NORMAL_SEPARATOR); is_menu_modified_ = true; + menu_item->menu_ = this; + } void Menu::Remove(MenuItem* menu_item, int pos) { menu_model_->RemoveItemAt(pos); is_menu_modified_ = true; + menu_item->menu_ = NULL; } void Menu::Popup(int x, int y, content::Shell* shell) { @@ -205,6 +210,22 @@ void Menu::UpdateKeys(views::FocusManager *focus_manager){ } } +void Menu::UpdateStates() { + if (window_) + window_->menu_->menu_->UpdateStates(); +} +void Menu::SetWindow(nw::NativeWindowWin* win) { + window_ = win; + for (int model_index = 0; + model_index < menu_model_->GetItemCount(); + ++model_index) { + int command_id = menu_model_->GetCommandIdAt(model_index); + MenuItem* item = dispatcher_host()->GetApiObject(command_id); + if (item != NULL && item->submenu_) { + item->submenu_->SetWindow(win); + } + } +} } // namespace nwapi diff --git a/src/api/menuitem/menuitem.h b/src/api/menuitem/menuitem.h index 9302401ef1..f80af28b91 100644 --- a/src/api/menuitem/menuitem.h +++ b/src/api/menuitem/menuitem.h @@ -132,6 +132,7 @@ class MenuItem : public Base { #elif defined(OS_WIN) friend class MenuDelegate; + Menu* menu_; //**Never Try to free this pointer** //We get it from top widget views::FocusManager *focus_manager_; diff --git a/src/api/menuitem/menuitem_win.cc b/src/api/menuitem/menuitem_win.cc index 9fac6a48ce..c28dc5b25b 100644 --- a/src/api/menuitem/menuitem_win.cc +++ b/src/api/menuitem/menuitem_win.cc @@ -46,6 +46,7 @@ void MenuItem::Create(const base::DictionaryValue& option) { meta_down_flag_ = false; focus_manager_ = NULL; + menu_ = NULL; option.GetString("type", &type_); option.GetString("label", &label_); @@ -113,6 +114,8 @@ void MenuItem::OnClick() { void MenuItem::SetLabel(const std::string& label) { is_modified_ = true; label_ = base::UTF8ToUTF16(label); + if (menu_) + menu_->UpdateStates(); } void MenuItem::SetIcon(const std::string& icon) { @@ -130,14 +133,20 @@ void MenuItem::SetIcon(const std::string& icon) { void MenuItem::SetTooltip(const std::string& tooltip) { tooltip_ = base::UTF8ToUTF16(tooltip); + if (menu_) + menu_->UpdateStates(); } void MenuItem::SetEnabled(bool enabled) { is_enabled_ = enabled; + if (menu_) + menu_->UpdateStates(); } void MenuItem::SetChecked(bool checked) { is_checked_ = checked; + if (menu_) + menu_->UpdateStates(); } void MenuItem::SetSubmenu(Menu* menu) { diff --git a/src/browser/native_window_win.cc b/src/browser/native_window_win.cc index 68d5cc2d34..003c366133 100644 --- a/src/browser/native_window_win.cc +++ b/src/browser/native_window_win.cc @@ -544,6 +544,7 @@ void NativeWindowWin::SetMenu(nwapi::Menu* menu) { // The menu is lazily built. menu->Rebuild(); + menu->SetWindow(this); // menu is nwapi::Menu, menu->menu_ is NativeMenuWin, ::SetMenu(views::HWNDForWidget(window_), menu->menu_->GetNativeMenu()); diff --git a/src/browser/native_window_win.h b/src/browser/native_window_win.h index ba528c7ffe..c85bc0c2e6 100644 --- a/src/browser/native_window_win.h +++ b/src/browser/native_window_win.h @@ -40,6 +40,10 @@ namespace views { class WebView; } +namespace nwapi { +class Menu; +} + namespace nw { class NativeWindowToolbarWin; @@ -159,6 +163,8 @@ class NativeWindowWin : public NativeWindow, const gfx::Point& location) OVERRIDE; private: friend class content::Shell; + friend class nwapi::Menu; + void OnViewWasResized(); void InstallEasyResizeTargeterOnContainer(); From 924298d833e9f857d201ea8c09251584b1a9e2eb Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Tue, 22 Jul 2014 00:52:00 +0800 Subject: [PATCH 118/492] bump version to v0.10.0 --- src/nw_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nw_version.h b/src/nw_version.h index b30a4d42ab..6800afa8b8 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -24,7 +24,7 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 10 #define NW_PATCH_VERSION 0 -#define NW_VERSION_IS_RELEASE 0 +#define NW_VERSION_IS_RELEASE 1 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) From 18b574a44b131b20e459cbb37269035f76cbeab1 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 22 Jul 2014 09:04:59 +0800 Subject: [PATCH 119/492] [WIN] fix download dialog --- src/browser/shell_download_manager_delegate_win.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/browser/shell_download_manager_delegate_win.cc b/src/browser/shell_download_manager_delegate_win.cc index e993b29062..168d4957a0 100644 --- a/src/browser/shell_download_manager_delegate_win.cc +++ b/src/browser/shell_download_manager_delegate_win.cc @@ -37,6 +37,9 @@ #include "content/public/browser/web_contents_view.h" #include "net/base/net_util.h" +#include "ui/aura/window.h" +#include "ui/aura/window_tree_host.h" + namespace content { void ShellDownloadManagerDelegate::ChooseDownloadPath( @@ -56,7 +59,8 @@ void ShellDownloadManagerDelegate::ChooseDownloadPath( OPENFILENAME save_as; ZeroMemory(&save_as, sizeof(save_as)); save_as.lStructSize = sizeof(OPENFILENAME); - save_as.hwndOwner = (HWND)item->GetWebContents()->GetView()->GetNativeView(); + save_as.hwndOwner = (HWND)item->GetWebContents()->GetView()->GetNativeView()-> + GetHost()->GetAcceleratedWidget(); save_as.lpstrFile = file_name; save_as.nMaxFile = arraysize(file_name); From e7d43be37c5b7899ffe63527ea11f5eae9699499 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 22 Jul 2014 09:58:49 +0800 Subject: [PATCH 120/492] [CHANGELOG] update for v0.10.0 --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5488f7a33d..5b6ac27662 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +0.10.0 / 07-22-2014 +======================= +- Fix: [WIN] download dialog +- Fix: [WIN] MenuItem.enabled and other properties needs to be called twice to work (#1132) + 0.10.0-rc2 / 07-18-2014 ======================= From d3afdb8d7b92350f64b8fdf7c83e78d6db43b934 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 22 Jul 2014 12:42:27 +0800 Subject: [PATCH 121/492] [README] update for v0.10.0 --- README.md | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index fc7b728589..567f55764a 100644 --- a/README.md +++ b/README.md @@ -20,16 +20,11 @@ It's created and developed in the Intel Open Source Technology Center. * Available on Linux, Mac OS X and Windows ## Downloads -* **0.9.2:** (Feb 20, 2014, based off of Node v0.11.9, Chrome 32.0.1700.107): [release notes](https://groups.google.com/d/msg/node-webkit/qpBhcWr-hSc/caGjhtl8cEgJ) - * Linux: [32bit](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-linux-x64.tar.gz) - * Windows: [win32](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-win-ia32.zip) - * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.9.2/node-webkit-v0.9.2-osx-ia32.zip) +* **v0.10.0:** (Jul 22, 2014, based off of Node v0.11.13, Chromium 35.0.1916.113): [release notes](https://groups.google.com/d/msg/node-webkit/x7kYuDO0Cj8/cIxoJ6RFiLsJ) -* **v0.10.0-rc2:** (Jul 18, 2014, based off of Node v0.11.13, Chromium 35.0.1916.113): [release notes](https://groups.google.com/d/msg/node-webkit/mdfF9rS38oQ/0QzIVqytGIoJ) - - * Linux: [32bit](http://dl.node-webkit.org/v0.10.0-rc2/node-webkit-v0.10.0-rc2-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.0-rc2/node-webkit-v0.10.0-rc2-linux-x64.tar.gz) - * Windows: [win32](http://dl.node-webkit.org/v0.10.0-rc2/node-webkit-v0.10.0-rc2-win-ia32.zip) - * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.10.0-rc2/node-webkit-v0.10.0-rc2-osx-ia32.zip) + * Linux: [32bit](http://dl.node-webkit.org/v0.10.0/node-webkit-v0.10.0-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.0/node-webkit-v0.10.0-linux-x64.tar.gz) + * Windows: [win32](http://dl.node-webkit.org/v0.10.0/node-webkit-v0.10.0-win-ia32.zip) + * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.10.0/node-webkit-v0.10.0-osx-ia32.zip) * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From 0f90c9b00378ae30e252ed19a623b010f147521f Mon Sep 17 00:00:00 2001 From: Eric Newport Date: Tue, 22 Jul 2014 00:25:54 -0700 Subject: [PATCH 122/492] Option to hide "Edit" and "Window" OS X menus MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds the option to hide the “Edit” and “Window” menus when invoking `createMacBuiltin` like so: ```js nativeMenuBar.createMacBuiltin('My App', { hideEdit: true, hideWindow: true }); ``` --- src/api/menu/menu.js | 133 ++++++++++++++++++++++--------------------- 1 file changed, 69 insertions(+), 64 deletions(-) diff --git a/src/api/menu/menu.js b/src/api/menu/menu.js index c20a98033f..38d505e3a3 100644 --- a/src/api/menu/menu.js +++ b/src/api/menu/menu.js @@ -70,8 +70,9 @@ Menu.prototype.popup = function(x, y) { } if (require('os').platform() === 'darwin'){ - Menu.prototype.createMacBuiltin = function (app_name) { - var appleMenu = new Menu(); + Menu.prototype.createMacBuiltin = function (app_name, options) { + var appleMenu = new Menu(), + options = options || {}; appleMenu.append(new exports.MenuItem({ label: nw.getNSStringFWithFixup("IDS_ABOUT_MAC", app_name), selector: "orderFrontStandardAboutPanel:" @@ -104,69 +105,73 @@ if (require('os').platform() === 'darwin'){ })); this.append(new exports.MenuItem({ label:'', submenu: appleMenu})); - var editMenu = new Menu(); - editMenu.append(new exports.MenuItem({ - label: nw.getNSStringWithFixup("IDS_EDIT_UNDO_MAC"), - selector: "undo:", - key: "z" - })); - editMenu.append(new exports.MenuItem({ - label: nw.getNSStringWithFixup("IDS_EDIT_REDO_MAC"), - selector: "redo:", - key: "z", - modifiers: "cmd-shift" - })); - editMenu.append(new exports.MenuItem({ - type: "separator" - })); - editMenu.append(new exports.MenuItem({ - label: nw.getNSStringWithFixup("IDS_CUT_MAC"), - selector: "cut:", - key: "x" - })); - editMenu.append(new exports.MenuItem({ - label: nw.getNSStringWithFixup("IDS_COPY_MAC"), - selector: "copy:", - key: "c" - })); - editMenu.append(new exports.MenuItem({ - label: nw.getNSStringWithFixup("IDS_PASTE_MAC"), - selector: "paste:", - key: "v" - })); - editMenu.append(new exports.MenuItem({ - label: nw.getNSStringWithFixup("IDS_EDIT_DELETE_MAC"), - selector: "delete:", - key: "" - })); - editMenu.append(new exports.MenuItem({ - label: nw.getNSStringWithFixup("IDS_EDIT_SELECT_ALL_MAC"), - selector: "selectAll:", - key: "a" - })); - this.append(new exports.MenuItem({ label: nw.getNSStringWithFixup("IDS_EDIT_MENU_MAC"), - submenu: editMenu})); + if (!options.hideEdit) { + var editMenu = new Menu(); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_EDIT_UNDO_MAC"), + selector: "undo:", + key: "z" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_EDIT_REDO_MAC"), + selector: "redo:", + key: "z", + modifiers: "cmd-shift" + })); + editMenu.append(new exports.MenuItem({ + type: "separator" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_CUT_MAC"), + selector: "cut:", + key: "x" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_COPY_MAC"), + selector: "copy:", + key: "c" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_PASTE_MAC"), + selector: "paste:", + key: "v" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_EDIT_DELETE_MAC"), + selector: "delete:", + key: "" + })); + editMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_EDIT_SELECT_ALL_MAC"), + selector: "selectAll:", + key: "a" + })); + this.append(new exports.MenuItem({ label: nw.getNSStringWithFixup("IDS_EDIT_MENU_MAC"), + submenu: editMenu})); + } - var winMenu = new Menu(); - winMenu.append(new exports.MenuItem({ - label: nw.getNSStringWithFixup("IDS_MINIMIZE_WINDOW_MAC"), - selector: "performMiniaturize:", - key: "m" - })); - winMenu.append(new exports.MenuItem({ - label: nw.getNSStringWithFixup("IDS_CLOSE_WINDOW_MAC"), - selector: "performClose:", - key: "w" - })); - winMenu.append(new exports.MenuItem({ - type: "separator" - })); - winMenu.append(new exports.MenuItem({ - label: nw.getNSStringWithFixup("IDS_ALL_WINDOWS_FRONT_MAC"), - selector: "arrangeInFront:", - })); - this.append(new exports.MenuItem({ label: nw.getNSStringWithFixup("IDS_WINDOW_MENU_MAC"), - submenu: winMenu})); + if (!options.hideWindow) { + var winMenu = new Menu(); + winMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_MINIMIZE_WINDOW_MAC"), + selector: "performMiniaturize:", + key: "m" + })); + winMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_CLOSE_WINDOW_MAC"), + selector: "performClose:", + key: "w" + })); + winMenu.append(new exports.MenuItem({ + type: "separator" + })); + winMenu.append(new exports.MenuItem({ + label: nw.getNSStringWithFixup("IDS_ALL_WINDOWS_FRONT_MAC"), + selector: "arrangeInFront:", + })); + this.append(new exports.MenuItem({ label: nw.getNSStringWithFixup("IDS_WINDOW_MENU_MAC"), + submenu: winMenu})); + } } } exports.Menu = Menu; From e5630a3b542643dd404e7841c4078a97682de3e5 Mon Sep 17 00:00:00 2001 From: Bas Wegh Date: Tue, 22 Jul 2014 14:37:55 +0200 Subject: [PATCH 123/492] Update shortcut.cc --- src/api/shortcut/shortcut.cc | 72 ++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) diff --git a/src/api/shortcut/shortcut.cc b/src/api/shortcut/shortcut.cc index dc5b0b2229..63ef73d9b8 100644 --- a/src/api/shortcut/shortcut.cc +++ b/src/api/shortcut/shortcut.cc @@ -68,6 +68,30 @@ ui::Accelerator Parse(const std::string& shortcut) { tokens[i] == kKeyPgUp || tokens[i] == kKeyPgDwn || tokens[i] == kKeyTab || + tokens[i] == kKeyF1 || + tokens[i] == kKeyF2 || + tokens[i] == kKeyF3 || + tokens[i] == kKeyF4 || + tokens[i] == kKeyF5 || + tokens[i] == kKeyF6 || + tokens[i] == kKeyF7 || + tokens[i] == kKeyF8 || + tokens[i] == kKeyF9 || + tokens[i] == kKeyF10 || + tokens[i] == kKeyF11 || + tokens[i] == kKeyF12 || + tokens[i] == kKeyF13 || + tokens[i] == kKeyF14 || + tokens[i] == kKeyF15 || + tokens[i] == kKeyF16 || + tokens[i] == kKeyF17 || + tokens[i] == kKeyF18 || + tokens[i] == kKeyF19 || + tokens[i] == kKeyF20 || + tokens[i] == kKeyF21 || + tokens[i] == kKeyF22 || + tokens[i] == kKeyF23 || + tokens[i] == kKeyF24 || tokens[i] == kKeyMediaNextTrack || tokens[i] == kKeyMediaPlayPause || tokens[i] == kKeyMediaPrevTrack || @@ -104,6 +128,54 @@ ui::Accelerator Parse(const std::string& shortcut) { key = ui::VKEY_NEXT; } else if (tokens[i] == kKeyTab) { key = ui::VKEY_TAB; + } else if (tokens[i] == kKeyF1) { + key = ui::VKEY_F1; + } else if (tokens[i] == kKeyF2) { + key = ui::VKEY_F2; + } else if (tokens[i] == kKeyF3) { + key = ui::VKEY_F3; + } else if (tokens[i] == kKeyF4) { + key = ui::VKEY_F4; + } else if (tokens[i] == kKeyF5) { + key = ui::VKEY_F5; + } else if (tokens[i] == kKeyF6) { + key = ui::VKEY_F6; + } else if (tokens[i] == kKeyF7) { + key = ui::VKEY_F7; + } else if (tokens[i] == kKeyF8) { + key = ui::VKEY_F8; + } else if (tokens[i] == kKeyF9) { + key = ui::VKEY_F9; + } else if (tokens[i] == kKeyF10) { + key = ui::VKEY_F10; + } else if (tokens[i] == kKeyF11) { + key = ui::VKEY_F11; + } else if (tokens[i] == kKeyF12) { + key = ui::VKEY_F12; + } else if (tokens[i] == kKeyF13) { + key = ui::VKEY_F13; + } else if (tokens[i] == kKeyF14) { + key = ui::VKEY_F14; + } else if (tokens[i] == kKeyF15) { + key = ui::VKEY_F15; + } else if (tokens[i] == kKeyF16) { + key = ui::VKEY_F16; + } else if (tokens[i] == kKeyF17) { + key = ui::VKEY_F17; + } else if (tokens[i] == kKeyF18) { + key = ui::VKEY_F18; + } else if (tokens[i] == kKeyF19) { + key = ui::VKEY_F19; + } else if (tokens[i] == kKeyF20) { + key = ui::VKEY_F20; + } else if (tokens[i] == kKeyF21) { + key = ui::VKEY_F21; + } else if (tokens[i] == kKeyF22) { + key = ui::VKEY_F22; + } else if (tokens[i] == kKeyF23) { + key = ui::VKEY_F23; + } else if (tokens[i] == kKeyF24) { + key = ui::VKEY_F24; } else if (tokens[i] == kKeyMediaNextTrack) { key = ui::VKEY_MEDIA_NEXT_TRACK; } else if (tokens[i] == kKeyMediaPlayPause) { From 194462dffcf399f6d797d2885ed731020e0c7c76 Mon Sep 17 00:00:00 2001 From: Bas Wegh Date: Tue, 22 Jul 2014 14:39:38 +0200 Subject: [PATCH 124/492] Add support for F-keys --- src/api/shortcut/shortcut_constants.h | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/api/shortcut/shortcut_constants.h b/src/api/shortcut/shortcut_constants.h index f0f0b88021..db6f0f6ebb 100644 --- a/src/api/shortcut/shortcut_constants.h +++ b/src/api/shortcut/shortcut_constants.h @@ -45,6 +45,31 @@ extern const char kKeySeparator[]; extern const char kKeyShift[]; extern const char kKeyTab[]; extern const char kKeyUp[]; +extern const char kKeyF1[]; +extern const char kKeyF2[]; +extern const char kKeyF3[]; +extern const char kKeyF4[]; +extern const char kKeyF5[]; +extern const char kKeyF6[]; +extern const char kKeyF7[]; +extern const char kKeyF8[]; +extern const char kKeyF9[]; +extern const char kKeyF10[]; +extern const char kKeyF11[]; +extern const char kKeyF12[]; +extern const char kKeyF13[]; +extern const char kKeyF14[]; +extern const char kKeyF15[]; +extern const char kKeyF16[]; +extern const char kKeyF17[]; +extern const char kKeyF18[]; +extern const char kKeyF19[]; +extern const char kKeyF20[]; +extern const char kKeyF21[]; +extern const char kKeyF22[]; +extern const char kKeyF23[]; +extern const char kKeyF24[]; + } // namespace nwapi From c1bb17eb47125af81061ccc842a91ecccc6530b1 Mon Sep 17 00:00:00 2001 From: Bas Wegh Date: Tue, 22 Jul 2014 14:42:04 +0200 Subject: [PATCH 125/492] Add support for F-Keys --- src/api/shortcut/shortcut_constants.cc | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/api/shortcut/shortcut_constants.cc b/src/api/shortcut/shortcut_constants.cc index 6d404f9eea..0759889822 100644 --- a/src/api/shortcut/shortcut_constants.cc +++ b/src/api/shortcut/shortcut_constants.cc @@ -44,5 +44,29 @@ const char kKeySeparator[] = "+"; const char kKeyShift[] = "shift"; const char kKeyTab[] = "tab"; const char kKeyUp[] = "up"; +const char kKeyF1[] = "f1"; +const char kKeyF2[] = "f2"; +const char kKeyF3[] = "f3"; +const char kKeyF4[] = "f4"; +const char kKeyF5[] = "f5"; +const char kKeyF6[] = "f6"; +const char kKeyF7[] = "f7"; +const char kKeyF8[] = "f8"; +const char kKeyF9[] = "f9"; +const char kKeyF10[] = "f10"; +const char kKeyF11[] = "f11"; +const char kKeyF12[] = "f12"; +const char kKeyF13[] = "f13"; +const char kKeyF14[] = "f14"; +const char kKeyF15[] = "f15"; +const char kKeyF16[] = "f16"; +const char kKeyF17[] = "f17"; +const char kKeyF18[] = "f18"; +const char kKeyF19[] = "f19"; +const char kKeyF20[] = "f20"; +const char kKeyF21[] = "f21"; +const char kKeyF22[] = "f22"; +const char kKeyF23[] = "f23"; +const char kKeyF24[] = "f24"; } // namespace nwapi From d82a3821dea6603af03104e9b03c75ad13681c2a Mon Sep 17 00:00:00 2001 From: Mithgol Date: Thu, 24 Jul 2014 16:03:23 +0400 Subject: [PATCH 126/492] =?UTF-8?q?fix=20the=C2=A0hyperlink=20to=C2=A0eFou?= =?UTF-8?q?nders=20in=C2=A0the=C2=A0=E2=80=9CSponsors=E2=80=9D=C2=A0sectio?= =?UTF-8?q?n=20of=C2=A0README.md?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 567f55764a..b8be9ecae3 100644 --- a/README.md +++ b/README.md @@ -116,4 +116,4 @@ You can chat with us on IRC in the ##node-webkit channel on irc.freenode.net The work is being sponsored by: * [Intel](http://www.intel.com) * [Gnor Tech](http://gnor.net) -* [eFounders](http://efounder.co) +* [eFounders](http://efounders.co) From ff50e2553401d71d08f3b6c7d019f7e28ef7576a Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 25 Jul 2014 14:55:04 +0800 Subject: [PATCH 127/492] Support fullscreen API Fix part of #55 --- src/nw_shell.cc | 5 +++++ src/nw_shell.h | 2 ++ 2 files changed, 7 insertions(+) diff --git a/src/nw_shell.cc b/src/nw_shell.cc index b93ae4f698..d72190b514 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -713,4 +713,9 @@ bool Shell::IsWebContentsVisible(content::WebContents* web_contents) { } #endif +void Shell::ToggleFullscreenModeForTab(WebContents* web_contents, + bool enter_fullscreen) { + window()->SetFullscreen(enter_fullscreen); +} + } // namespace content diff --git a/src/nw_shell.h b/src/nw_shell.h index b364293e6f..c38144214b 100644 --- a/src/nw_shell.h +++ b/src/nw_shell.h @@ -165,6 +165,8 @@ class Shell : public WebContentsDelegate, const base::string16& frame_name, const GURL& target_url, WebContents* new_contents) OVERRIDE; + virtual void ToggleFullscreenModeForTab(WebContents* web_contents, + bool enter_fullscreen) OVERRIDE; #if defined(OS_WIN) virtual void WebContentsFocused(WebContents* contents) OVERRIDE; #endif From d4d7f14efd1e6bbb527ed45a51a1e0d5cc07249b Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 25 Jul 2014 14:56:20 +0800 Subject: [PATCH 128/492] bump version to v0.10.1-pre --- src/mac/app-Info.plist | 2 +- src/nw_version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mac/app-Info.plist b/src/mac/app-Info.plist index 269b46ee9e..726cee5584 100644 --- a/src/mac/app-Info.plist +++ b/src/mac/app-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.10.0 + 0.10.1 NSPrincipalClass NSApplication LSMinimumSystemVersion diff --git a/src/nw_version.h b/src/nw_version.h index 6800afa8b8..a09902adf8 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -23,8 +23,8 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 10 -#define NW_PATCH_VERSION 0 -#define NW_VERSION_IS_RELEASE 1 +#define NW_PATCH_VERSION 1 +#define NW_VERSION_IS_RELEASE 0 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) @@ -38,7 +38,7 @@ #else # define NW_VERSION_STRING NW_STRINGIFY(NW_MAJOR_VERSION) "." \ NW_STRINGIFY(NW_MINOR_VERSION) "." \ - NW_STRINGIFY(NW_PATCH_VERSION) "-rc2" + NW_STRINGIFY(NW_PATCH_VERSION) "-pre" #endif #define NW_VERSION "v" NW_VERSION_STRING From a3a537bb354f709172e71e7c985d4ac6b8ee1d48 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 25 Jul 2014 16:18:06 +0800 Subject: [PATCH 129/492] Fix #55: Support (video) element fullscreen --- src/nw_shell.cc | 4 ++++ src/nw_shell.h | 4 +++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/nw_shell.cc b/src/nw_shell.cc index d72190b514..ef9a8032d6 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -718,4 +718,8 @@ void Shell::ToggleFullscreenModeForTab(WebContents* web_contents, window()->SetFullscreen(enter_fullscreen); } +bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const { + return window()->IsFullscreen(); +} + } // namespace content diff --git a/src/nw_shell.h b/src/nw_shell.h index c38144214b..be01017f46 100644 --- a/src/nw_shell.h +++ b/src/nw_shell.h @@ -130,7 +130,7 @@ class Shell : public WebContentsDelegate, static int exit_code() { return exit_code_; } WebContents* web_contents() const { return web_contents_.get(); } - nw::NativeWindow* window() { return window_.get(); } + nw::NativeWindow* window() const { return window_.get(); } void set_force_close(bool force) { force_close_ = force; } bool is_devtools() const { return is_devtools_; } @@ -167,6 +167,8 @@ class Shell : public WebContentsDelegate, WebContents* new_contents) OVERRIDE; virtual void ToggleFullscreenModeForTab(WebContents* web_contents, bool enter_fullscreen) OVERRIDE; + virtual bool IsFullscreenForTabOrPending( + const WebContents* web_contents) const OVERRIDE; #if defined(OS_WIN) virtual void WebContentsFocused(WebContents* contents) OVERRIDE; #endif From 0338b93f629dfb75f497fc480baf033375320c4a Mon Sep 17 00:00:00 2001 From: Jefry Date: Mon, 26 May 2014 16:02:04 +0800 Subject: [PATCH 130/492] [Notification] update copyright notice (+1 squashed commit) Squashed commits: [b3c450f] [Notification] handle empty body on windows (+1 squashed commits) Squashed commits: [ca3f634] [Notification] fix compiler error. missing base:: (+1 squashed commits) Squashed commits: [af8b22b] [Notification]fix compile error on linux (+1 squashed commit) Squashed commits: [32bc400] compile error fix (+1 squashed commit) Squashed commits: [2955c46] [linux] notification implementation (+1 squashed commit) Squashed commits: [edb7e83] [WIN] make the StatusTray a singleton, check for the StatusIcon if it has been created before, handle the destruction of StatusIcon and StatusObserver properly (+1 squashed commit) Squashed commits: [3a1f53b] [Linux] add placeholder for the desktop notification (+7 squashed commits) Squashed commits: [f784e4a] indentation and formatting fix [c5ef03d] fix the indentation [d1662e7] [MAC] add version check for the notification image, since it only supported by Mavericks [18b2d38] [WIN] fix notification manager compile warnings (missing OVERRIDE) [00177bb] [MAC] implement loading / showing image from url for desktop notification [e8b8cce] fix compile warning for undefined constructor [a3d73b2] Move notification image download callback to the parent class, preparation for MAC notification custom icon implementation (+1 squashed commit) Squashed commits: [ee010e2] [WIN] implement the icon image display from URL (+8 squashed commits) Squashed commits: [4844475] [MAC] implement desktop notification, display event dispatcher [4c5f445] Remove unnecessary comments [af4bd7e] Implement notification events dispatcher (close, display, error) [d6662bc] [WIN] implement windows balloon tray notification, with application icon as the tray icon [19c8965] [WIN] AddDesktopNotification, CancelDesktopNotification function prototype adjustment with NotificationManager [29816f5] [WIN] implement windows notification [7191831] [MACOSX] implement desktop notification event handler (send the click back to java script) implement "CancelDesktopNotification" [c5b359d] add notification manager (nw_notification_manager) for desktop notification implement MacOS notification manager --- nw.gypi | 13 ++ src/api/tray/tray_win.cc | 2 +- src/nw_notification_manager.cc | 105 +++++++++++++++ src/nw_notification_manager.h | 67 ++++++++++ src/nw_notification_manager_linux.cc | 134 +++++++++++++++++++ src/nw_notification_manager_linux.h | 49 +++++++ src/nw_notification_manager_mac.h | 44 +++++++ src/nw_notification_manager_mac.mm | 156 ++++++++++++++++++++++ src/nw_notification_manager_win.cc | 190 +++++++++++++++++++++++++++ src/nw_notification_manager_win.h | 78 +++++++++++ src/shell_content_browser_client.cc | 35 +++++ src/shell_content_browser_client.h | 12 ++ 12 files changed, 884 insertions(+), 1 deletion(-) create mode 100644 src/nw_notification_manager.cc create mode 100644 src/nw_notification_manager.h create mode 100644 src/nw_notification_manager_linux.cc create mode 100644 src/nw_notification_manager_linux.h create mode 100644 src/nw_notification_manager_mac.h create mode 100644 src/nw_notification_manager_mac.mm create mode 100644 src/nw_notification_manager_win.cc create mode 100644 src/nw_notification_manager_win.h diff --git a/nw.gypi b/nw.gypi index f6bfe28ee4..a8c20c7c7c 100644 --- a/nw.gypi +++ b/nw.gypi @@ -315,6 +315,14 @@ 'src/renderer/shell_render_process_observer.h', 'src/nw_shell.cc', 'src/nw_shell.h', + 'src/nw_notification_manager.h', + 'src/nw_notification_manager.cc', + 'src/nw_notification_manager_win.h', + 'src/nw_notification_manager_win.cc', + 'src/nw_notification_manager_mac.h', + 'src/nw_notification_manager_mac.mm', + 'src/nw_notification_manager_linux.h', + 'src/nw_notification_manager_linux.cc', 'src/shell_browser_context.cc', 'src/shell_browser_context.h', 'src/shell_browser_main.cc', @@ -833,6 +841,11 @@ '<(DEPTH)/build/linux/system.gyp:gtk', ], }], # toolkit_uses_gtk + ['OS=="linux"', { + 'dependencies': [ + '<(DEPTH)/build/linux/system.gyp:notify', + ], + }], # OS=="linux" ['OS=="mac"', { 'product_name': '<(nw_product_name)', 'dependencies!': [ diff --git a/src/api/tray/tray_win.cc b/src/api/tray/tray_win.cc index a90e65bb83..4c0c677da1 100644 --- a/src/api/tray/tray_win.cc +++ b/src/api/tray/tray_win.cc @@ -56,7 +56,7 @@ class TrayObserver : public StatusIconObserver { void Tray::Create(const base::DictionaryValue& option) { if (!status_tray_) - status_tray_ = StatusTray::Create(); + status_tray_ = StatusTray::GetSingleton(); status_icon_ = status_tray_->CreateStatusIcon(StatusTray::NOTIFICATION_TRAY_ICON, gfx::ImageSkia(), base::string16()); diff --git a/src/nw_notification_manager.cc b/src/nw_notification_manager.cc new file mode 100644 index 0000000000..8698186522 --- /dev/null +++ b/src/nw_notification_manager.cc @@ -0,0 +1,105 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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 "ui/gfx/image/image.h" +#include "content/public/browser/render_view_host.h" + +#include "content/nw/src/nw_notification_manager.h" +#if defined(OS_MACOSX) +#include "content/nw/src/nw_notification_manager_mac.h" +#elif defined(OS_WIN) +#include "content/nw/src/nw_notification_manager_win.h" +#elif defined(OS_LINUX) +#include "content/nw/src/nw_notification_manager_linux.h" +#endif + +namespace nw +{ +NotificationManager* NotificationManager::singleton_ = NULL; + +NotificationManager::NotificationManager() { +} + +NotificationManager::~NotificationManager() { + singleton_ = NULL; +} + +NotificationManager* NotificationManager::getSingleton() { + if (singleton_ == NULL) { +#if defined(OS_MACOSX) + singleton_ = new NotificationManagerMac(); +#elif defined(OS_WIN) + singleton_ = new NotificationManagerWin(); +#elif defined(OS_LINUX) + singleton_ = new NotificationManagerLinux(); +#endif + } + return singleton_; +} + + +void NotificationManager::ImageDownloadCallback(int id, int http_status, const GURL& image_url, const std::vector& bitmaps, const std::vector& size) { + NotificationManager *singleton = getSingleton(); + DesktopNotificationParams params = singleton->desktop_notification_params_[id]; + singleton->AddDesktopNotification(params.params_, params.render_process_id_, params.render_view_id_, params.worker_, &bitmaps); + singleton->desktop_notification_params_.erase(id); +} + +bool NotificationManager::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) { + NOTIMPLEMENTED(); + return false; +} + +bool NotificationManager::DesktopNotificationPostClick(int render_process_id, int render_view_id, int notification_id) { + content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); + if (host == NULL) + return false; + + host->DesktopNotificationPostClick(notification_id); + return true; +} + +bool NotificationManager::DesktopNotificationPostClose(int render_process_id, int render_view_id, int notification_id, bool by_user) { + content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); + if (host == NULL) + return false; + + host->DesktopNotificationPostClose(notification_id, by_user); + return true; +} + +bool NotificationManager::DesktopNotificationPostDisplay(int render_process_id, int render_view_id, int notification_id) { + content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); + if (host == NULL) + return false; + + host->DesktopNotificationPostDisplay(notification_id); + return true; +} + +bool NotificationManager::DesktopNotificationPostError(int render_process_id, int render_view_id, int notification_id, const base::string16& message) { + content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); + if (host == NULL) + return false; + + host->DesktopNotificationPostError(notification_id, message); + return true; +} +} // namespace nw diff --git a/src/nw_notification_manager.h b/src/nw_notification_manager.h new file mode 100644 index 0000000000..fcc25b98ac --- /dev/null +++ b/src/nw_notification_manager.h @@ -0,0 +1,67 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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_NOTIFICATION_MANAGER_H_ +#define CONTENT_NW_NOTIFICATION_MANAGER_H_ + +#include "base/basictypes.h" +#include "content/public/common/show_desktop_notification_params.h" + +namespace nw { + +class NotificationManager{ +private: + static NotificationManager *singleton_; + +protected: + explicit NotificationManager(); + + // icon image download callback + static void ImageDownloadCallback(int id, int http_status, const GURL& image_url, const std::vector& bitmaps, const std::vector& size); + struct DesktopNotificationParams { + content::ShowDesktopNotificationHostMsgParams params_; + int render_process_id_; + int render_view_id_; + bool worker_; + }; + + // map used to stored desktop notification params used by ImageDownloadCallback + std::map desktop_notification_params_; + + // internal function for AddDesktopNotification + virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps); + +public: + virtual ~NotificationManager(); + static NotificationManager* getSingleton(); + virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker) = 0; + virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) = 0; + + bool DesktopNotificationPostClick(int render_process_id, int render_view_id, int notification_id); + bool DesktopNotificationPostClose(int render_process_id, int render_view_id, int notification_id, bool by_user); + bool DesktopNotificationPostDisplay(int render_process_id, int render_view_id, int notification_id); + bool DesktopNotificationPostError(int render_process_id, int render_view_id, int notification_id, const base::string16& message); + +}; + +} // namespace nw + +#endif // CONTENT_NW_NOTIFICATION_MANAGER_H_ diff --git a/src/nw_notification_manager_linux.cc b/src/nw_notification_manager_linux.cc new file mode 100644 index 0000000000..253d3808af --- /dev/null +++ b/src/nw_notification_manager_linux.cc @@ -0,0 +1,134 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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 "chrome/browser/status_icons/status_icon.h" + +#include "content/public/browser/web_contents.h" +#include "content/public/browser/render_view_host.h" +#include "content/nw/src/browser/native_window.h" +#include "content/nw/src/nw_package.h" +#include "content/nw/src/nw_shell.h" + +#include "ui/gfx/image/image.h" +#include "base/strings/utf_string_conversions.h" + +#include "content/nw/src/nw_notification_manager_linux.h" + +#include "ui/gfx/gtk_util.h" + +//#define GET_NOTIFICATION(id) mNotificationIDmap.find(id) +//Ubuntu notify-osd can only show 1 notification, this is the "hack" to do that +#define GET_NOTIFICATION(id) mNotificationIDmap.begin() + +namespace nw { + +NotificationManagerLinux::NotificationManagerLinux() { + notify_init (content::Shell::GetPackage()->GetName().c_str()); +} + +NotificationManagerLinux::~NotificationManagerLinux() { + notify_uninit(); +} + +void NotificationManagerLinux::onClose(NotifyNotification *notif) +{ + NotificationManagerLinux* singleton = static_cast(NotificationManagerLinux::getSingleton()); + std::map::iterator i; + for (i = singleton->mNotificationIDmap.begin(); i!=singleton->mNotificationIDmap.end(); i++) { + if (i->second == notif) + break; + } + singleton->mNotificationIDmap.erase(i); + g_object_unref(G_OBJECT(notif)); +}; + +bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) { + + content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); + if (host == NULL) + return false; + + content::Shell* shell = content::Shell::FromRenderViewHost(host); + + if (bitmaps == NULL) { + // called from public function, save the params + DesktopNotificationParams desktop_notification_params; + desktop_notification_params.params_ = params; + desktop_notification_params.render_process_id_ = render_process_id; + desktop_notification_params.render_view_id_ = render_view_id; + + // download the icon image first + content::WebContents::ImageDownloadCallback imageDownloadCallback = base::Bind(&NotificationManager::ImageDownloadCallback); + int id = shell->web_contents()->DownloadImage(params.icon_url, true, 0, imageDownloadCallback); + desktop_notification_params_[id] = desktop_notification_params; + + // wait for the image download callback + return true; + } + + // if we reach here, it means the function is called from image download callback + + SkBitmap bitmap; + // try to get the notification icon image given by image download callback + if (bitmaps->size()) + bitmap = bitmaps->at(0); + else { + // set the default notification icon as the app icon + bitmap = shell->window()->app_icon().AsBitmap(); + } + + NotifyNotification * notif; + std::map::iterator i = GET_NOTIFICATION(params.notification_id); + if (i==mNotificationIDmap.end()) { + notif = notify_notification_new ( + base::UTF16ToUTF8(params.title).c_str(), base::UTF16ToUTF8(params.body).c_str(), NULL); + mNotificationIDmap[params.notification_id] = notif; + } + else { + notif = i->second; + notify_notification_update(notif, base::UTF16ToUTF8(params.title).c_str(), + base::UTF16ToUTF8(params.body).c_str(), NULL); + } + + GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap); + notify_notification_set_image_from_pixbuf(notif, pixbuf); + g_object_unref(pixbuf); + + NOTIFY_NOTIFICATION_GET_CLASS(notif)->closed = onClose; + + GError* error = NULL; + if (notify_notification_show (notif, &error)) { + DesktopNotificationPostDisplay(render_process_id, render_view_id, params.notification_id); + } + else { + base::string16 errorMsg = base::UTF8ToUTF16(error->message); + DesktopNotificationPostError(render_process_id, render_view_id, params.notification_id, errorMsg); + } + return error==NULL; +} + +bool NotificationManagerLinux::CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) { + std::map::const_iterator i = GET_NOTIFICATION(notification_id); + if (i!=mNotificationIDmap.end()) { + return notify_notification_close(i->second, NULL); + } + return false; +} +} // namespace nw diff --git a/src/nw_notification_manager_linux.h b/src/nw_notification_manager_linux.h new file mode 100644 index 0000000000..10f18c4eba --- /dev/null +++ b/src/nw_notification_manager_linux.h @@ -0,0 +1,49 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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_NOTIFICATION_MANAGER_LINUX_H_ +#define CONTENT_NW_NOTIFICATION_MANAGER_LINUX_H_ + +#include "content/nw/src/nw_notification_manager.h" +#include + +namespace nw { +class NotificationManagerLinux : public NotificationManager { + + std::map mNotificationIDmap; + static void onClose(NotifyNotification *notif); + + + // internal function for AddDesktopNotification + virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) OVERRIDE; + +public: + explicit NotificationManagerLinux(); + virtual ~NotificationManagerLinux(); + virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker) OVERRIDE { + return AddDesktopNotification(params, render_process_id, render_view_id, worker, NULL); + } + virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) OVERRIDE; +}; + +} // namespace nw + +#endif // CONTENT_NW_NOTIFICATION_MANAGER_LINUX_H_ diff --git a/src/nw_notification_manager_mac.h b/src/nw_notification_manager_mac.h new file mode 100644 index 0000000000..48635bf10e --- /dev/null +++ b/src/nw_notification_manager_mac.h @@ -0,0 +1,44 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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_NOTIFICATION_MANAGER_MAC_H_ +#define CONTENT_NW_NOTIFICATION_MANAGER_MAC_H_ + +#include "content/nw/src/nw_notification_manager.h" + +namespace nw { + +class NotificationManagerMac : public NotificationManager { + + // internal function for AddDesktopNotification + virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) OVERRIDE; + +public: + explicit NotificationManagerMac(); + virtual ~NotificationManagerMac(){} + virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker) OVERRIDE; + virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) OVERRIDE; + +}; + +} // namespace nw + +#endif // CONTENT_NW_NOTIFICATION_MANAGER_MAC_H_ diff --git a/src/nw_notification_manager_mac.mm b/src/nw_notification_manager_mac.mm new file mode 100644 index 0000000000..251bf72a6a --- /dev/null +++ b/src/nw_notification_manager_mac.mm @@ -0,0 +1,156 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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. + +#import +#include "base/mac/mac_util.h" +#include "base/strings/sys_string_conversions.h" + +#include "content/public/browser/web_contents.h" +#include "content/public/browser/render_view_host.h" +#include "content/nw/src/browser/native_window.h" +#include "content/nw/src/nw_package.h" +#include "content/nw/src/nw_shell.h" + +#include "content/nw/src/nw_notification_manager_mac.h" + +#if !defined(MAC_OS_X_VERSION_10_8) || \ + MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_8 +@interface NSUserNotificationCenter : NSObject +@end +@interface NSUserNotification : NSObject +@end +@implementation NSUserNotification +@end +#endif + +@interface NWUserNotificationCenterDelegate : NSObject { +} +@end +@implementation NWUserNotificationCenterDelegate + +static NWUserNotificationCenterDelegate *singleton_ = nil; + ++(NWUserNotificationCenterDelegate *)defaultNWUserNotificationCenterDelegate{ + @synchronized(self) { + if (singleton_ == nil) + singleton_ = [[self alloc] init]; + } + return singleton_; +} + +-(BOOL)userNotificationCenter:(NSUserNotificationCenter *)center + shouldPresentNotification : (NSUserNotification *)notification { + + NSNumber *render_process_id = [notification.userInfo objectForKey : @"render_process_id"]; + NSNumber *render_view_id = [notification.userInfo objectForKey : @"render_view_id"]; + NSNumber *notification_id = [notification.userInfo objectForKey : @"notification_id"]; + + nw::NotificationManager::getSingleton()->DesktopNotificationPostDisplay(render_process_id.intValue, + render_view_id.intValue, + notification_id.intValue); + return YES; +} + +-(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification : (NSUserNotification *)notification { + NSNumber *render_process_id = [notification.userInfo objectForKey : @"render_process_id"]; + NSNumber *render_view_id = [notification.userInfo objectForKey : @"render_view_id"]; + NSNumber *notification_id = [notification.userInfo objectForKey : @"notification_id"]; + + nw::NotificationManager::getSingleton()->DesktopNotificationPostClick(render_process_id.intValue, + render_view_id.intValue, + notification_id.intValue); +} +@end + +namespace nw { +NotificationManagerMac::NotificationManagerMac() { +} + +bool NotificationManagerMac::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams ¶ms, const int render_process_id, const int render_view_id, const bool worker) { + return AddDesktopNotification(params, render_process_id, render_view_id, worker, NULL); +} + +bool NotificationManagerMac::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) { + + content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); + if (host == nullptr) + return false; + content::Shell* shell = content::Shell::FromRenderViewHost(host); + + static const bool downloadImage = base::mac::IsOSMavericksOrLater(); + + if (bitmaps == NULL && downloadImage) { + // called from public function, save the params + DesktopNotificationParams desktop_notification_params; + desktop_notification_params.params_ = params; + desktop_notification_params.render_process_id_ = render_process_id; + desktop_notification_params.render_view_id_ = render_view_id; + + // download the icon image first + content::WebContents::ImageDownloadCallback imageDownloadCallback = base::Bind(&NotificationManager::ImageDownloadCallback); + int id = shell->web_contents()->DownloadImage(params.icon_url, true, 0, imageDownloadCallback); + desktop_notification_params_[id] = desktop_notification_params; + + // wait for the image download callback + return true; + } + + // if we reach here, it means the function is called from image download callback + + NSUserNotification *notification = [[NSUserNotification alloc] init]; + [notification setTitle : base::SysUTF16ToNSString(params.title)]; + [notification setInformativeText : base::SysUTF16ToNSString(params.body)]; + notification.hasActionButton = YES; + + if (bitmaps && bitmaps->size()) { + // try to get the notification icon image given by image download callback + gfx::Image icon = gfx::Image::CreateFrom1xBitmap(bitmaps->at(0)); + + // this function only runs on Mavericks or later + [notification setContentImage : icon.ToNSImage()]; + } + + notification.userInfo = @{ @"render_process_id" :[NSNumber numberWithInt : render_process_id], + @"render_view_id" :[NSNumber numberWithInt : render_view_id], + @"notification_id" :[NSNumber numberWithInt : params.notification_id], + }; + + [notification setSoundName : @"NSUserNotificationDefaultSoundName"]; + + [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:[NWUserNotificationCenterDelegate defaultNWUserNotificationCenterDelegate]]; + + [[NSUserNotificationCenter defaultUserNotificationCenter] deliverNotification:notification]; + + [notification release]; + + return true; +} + +bool NotificationManagerMac::CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id){ + for (NSUserNotification *notification in[[NSUserNotificationCenter defaultUserNotificationCenter] deliveredNotifications]) { + NSNumber *current_notification_id = [notification.userInfo objectForKey : @"notification_id"]; + if (current_notification_id.intValue == notification_id){ + [[NSUserNotificationCenter defaultUserNotificationCenter] removeDeliveredNotification:notification]; + return true; + } + } + return false; +} +} // namespace nw diff --git a/src/nw_notification_manager_win.cc b/src/nw_notification_manager_win.cc new file mode 100644 index 0000000000..8f4ac41296 --- /dev/null +++ b/src/nw_notification_manager_win.cc @@ -0,0 +1,190 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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 "chrome/browser/status_icons/status_icon.h" +#include "chrome/browser/status_icons/status_icon_observer.h" +#include "chrome/browser/ui/views/status_icons/status_tray_win.h" + +#include "content/public/browser/web_contents.h" +#include "content/public/browser/render_view_host.h" +#include "content/nw/src/browser/native_window.h" +#include "content/nw/src/nw_package.h" +#include "content/nw/src/nw_shell.h" + +#include "ui/gfx/image/image.h" +#include "base/strings/utf_string_conversions.h" + +#include "content/nw/src/nw_notification_manager_win.h" + +namespace nw { +class TrayObserver : public StatusIconObserver { +public: + TrayObserver(NotificationManagerWin* tray) + : tray_(tray) { + } + + virtual ~TrayObserver() { + } + + virtual void OnStatusIconClicked() OVERRIDE { + } + + virtual void OnBalloonEvent(int event) OVERRIDE { + switch (event) { + case NIN_BALLOONHIDE: + tray_->DesktopNotificationPostClose(true); + tray_->ReleaseNotification(); + break; + case NIN_BALLOONTIMEOUT: + tray_->DesktopNotificationPostClose(false); + tray_->ReleaseNotification(); + break; + case NIN_BALLOONSHOW: + tray_->DesktopNotificationPostDisplay(); + break; + } + } + + virtual void OnBalloonClicked() OVERRIDE { + tray_->DesktopNotificationPostClick(); + tray_->ReleaseNotification(); + } +private: + NotificationManagerWin* tray_; +}; + +NotificationManagerWin::NotificationManagerWin() : status_icon_(NULL) { + status_tray_ = static_cast(StatusTray::GetSingleton()); + + // check if status icon is already created + StatusIcon* status_icon = status_tray_->GetStatusIcon(); + + // if status icon already created, set the notification count to 1 and add the observer + notification_count_ = status_icon ? 1 : 0; + if (status_icon) { + status_observer_ = new TrayObserver(this); + status_icon->AddObserver(status_observer_); + } +} + +bool NotificationManagerWin::ReleaseNotification() { + if (notification_count_ > 0) { + if (notification_count_ == 1) { + // if I create the status_icon_ I am responsible to delete it + if (status_icon_) { + status_icon_->RemoveObserver(status_observer_); + status_tray_->RemoveStatusIcon(status_icon_); + status_icon_ = NULL; + } + + delete status_observer_; + status_observer_ = NULL; + } + notification_count_--; + return true; + } + return false; +} + + +NotificationManagerWin::~NotificationManagerWin() { + ReleaseNotification(); + + // this is to clean up status_observer_ if it is created by the constructor + if (status_observer_) { + StatusIcon* status_icon = status_tray_->GetStatusIcon(); + if (status_icon) + status_icon->RemoveObserver(status_observer_); + + delete status_observer_; + status_observer_ = NULL; + } +} + +bool NotificationManagerWin::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) { + + content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); + if (host == NULL) + return false; + + content::Shell* shell = content::Shell::FromRenderViewHost(host); + + if (bitmaps == NULL) { + // called from public function, save the params + DesktopNotificationParams desktop_notification_params; + desktop_notification_params.params_ = params; + desktop_notification_params.render_process_id_ = render_process_id; + desktop_notification_params.render_view_id_ = render_view_id; + + // download the icon image first + content::WebContents::ImageDownloadCallback imageDownloadCallback = base::Bind(&NotificationManager::ImageDownloadCallback); + int id = shell->web_contents()->DownloadImage(params.icon_url, true, 0, imageDownloadCallback); + desktop_notification_params_[id] = desktop_notification_params; + + // wait for the image download callback + return true; + } + + // if we reach here, it means the function is called from image download callback + render_process_id_ = render_process_id; + render_view_id_ = render_view_id; + notification_id_ = params.notification_id; + + // set the default notification icon as the app icon + gfx::Image icon = shell->window()->app_icon(); + + // always check if status icon is exist or not + StatusIcon* status_icon = status_tray_->GetStatusIcon(); + + // status_icon_ is null, it means we need to create and adds it to the tray + if (status_icon == NULL) { + nw::Package* package = shell->GetPackage(); + status_icon_ = status_tray_->CreateStatusIcon(StatusTray::NOTIFICATION_TRAY_ICON, + *(shell->window()->app_icon().ToImageSkia()), base::UTF8ToUTF16(package->GetName())); + status_icon = status_icon_; + status_observer_ = new TrayObserver(this); + status_icon->AddObserver(status_observer_); + } + + // add the counter + notification_count_++; + // try to get the notification icon image given by image download callback + if (bitmaps->size()) + icon = gfx::Image::CreateFrom1xBitmap(bitmaps->at(0)); + + //if body is empty string, the baloon won't shown + base::string16 body = params.body; + if (body.empty()) body = L" "; + + //show the baloon + bool result = status_icon->DisplayBalloon(icon.IsEmpty() ? gfx::ImageSkia() : *icon.ToImageSkia(), params.title, body); + if (!result) { + DesktopNotificationPostError(L"DisplayBalloon fail"); + ReleaseNotification(); + } + + return result; +} + +bool NotificationManagerWin::CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) { + //windows can only have 1 notification, cannot delete existing notification + return true; +} +} // namespace nw diff --git a/src/nw_notification_manager_win.h b/src/nw_notification_manager_win.h new file mode 100644 index 0000000000..ca40f1edee --- /dev/null +++ b/src/nw_notification_manager_win.h @@ -0,0 +1,78 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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_NOTIFICATION_MANAGER_WIN_H_ +#define CONTENT_NW_NOTIFICATION_MANAGER_WIN_H_ + +#include "content/nw/src/nw_notification_manager.h" +class StatusTrayWin; +class StatusIcon; + +namespace nw { +class NotificationManagerWin : public NotificationManager{ + // The global presentation of system tray. + StatusTrayWin* status_tray_; + + // StatusIcon pointer created by ME + StatusIcon* status_icon_; + + // number of notification in the queue + int notification_count_; + + // decrement the status_icon_count_, if the value is 0 remove the status_icon_ from the tray + bool ReleaseNotification(); + + // Click observer. + friend class TrayObserver; + TrayObserver* status_observer_; + + // variable to store the latest notification data, windows can only show 1 notification + int render_process_id_, render_view_id_, notification_id_; + + // dispatch the events from the latest notification + bool DesktopNotificationPostClick() { + return NotificationManager::DesktopNotificationPostClick(render_process_id_, render_view_id_, notification_id_); + } + bool DesktopNotificationPostClose(bool by_user) { + return NotificationManager::DesktopNotificationPostClose(render_process_id_, render_view_id_, notification_id_, by_user); + } + bool DesktopNotificationPostDisplay() { + return NotificationManager::DesktopNotificationPostDisplay(render_process_id_, render_view_id_, notification_id_); + } + bool DesktopNotificationPostError(const base::string16& message) { + return NotificationManager::DesktopNotificationPostError(render_process_id_, render_view_id_, notification_id_, message); + } + + // internal function for AddDesktopNotification + virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) OVERRIDE; + +public: + explicit NotificationManagerWin(); + virtual ~NotificationManagerWin(); + virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker) OVERRIDE{ + return AddDesktopNotification(params, render_process_id, render_view_id, worker, NULL); + } + virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) OVERRIDE; +}; + +} // namespace nw + +#endif // CONTENT_NW_NOTIFICATION_MANAGER_WIN_H_ diff --git a/src/shell_content_browser_client.cc b/src/shell_content_browser_client.cc index dee937bf31..d7cf1c17b5 100644 --- a/src/shell_content_browser_client.cc +++ b/src/shell_content_browser_client.cc @@ -57,6 +57,7 @@ #include "content/nw/src/media/media_internals.h" #include "content/nw/src/nw_package.h" #include "content/nw/src/nw_shell.h" +#include "content/nw/src/nw_notification_manager.h" #include "content/nw/src/nw_version.h" #include "content/nw/src/shell_browser_context.h" #include "content/nw/src/shell_browser_main_parts.h" @@ -449,4 +450,38 @@ ShellContentBrowserClient::CreateQuotaPermissionContext() { return new ShellQuotaPermissionContext(); } +void ShellContentBrowserClient::ShowDesktopNotification( + const ShowDesktopNotificationHostMsgParams& params, + int render_process_id, + int render_view_id, + bool worker) { +#if defined(ENABLE_NOTIFICATIONS) + nw::NotificationManager *notificationManager = nw::NotificationManager::getSingleton(); + if (notificationManager == NULL) { + NOTIMPLEMENTED(); + return; + } + notificationManager->AddDesktopNotification(params, render_process_id, render_view_id, worker); +#else + NOTIMPLEMENTED(); +#endif + +} + +void ShellContentBrowserClient::CancelDesktopNotification( + int render_process_id, + int render_view_id, + int notification_id) { +#if defined(ENABLE_NOTIFICATIONS) + nw::NotificationManager *notificationManager = nw::NotificationManager::getSingleton(); + if (notificationManager == NULL) { + NOTIMPLEMENTED(); + return; + } + notificationManager->CancelDesktopNotification(render_process_id, render_view_id, notification_id); +#else + NOTIMPLEMENTED(); +#endif +} + } // namespace content diff --git a/src/shell_content_browser_client.h b/src/shell_content_browser_client.h index 2ae08193af..f8ad489382 100644 --- a/src/shell_content_browser_client.h +++ b/src/shell_content_browser_client.h @@ -93,6 +93,18 @@ class ShellContentBrowserClient : public ContentBrowserClient { #endif virtual QuotaPermissionContext* CreateQuotaPermissionContext() OVERRIDE; + //Notification + virtual void ShowDesktopNotification( + const ShowDesktopNotificationHostMsgParams& params, + int render_process_id, + int render_view_id, + bool worker) OVERRIDE; + + virtual void CancelDesktopNotification( + int render_process_id, + int render_view_id, + int notification_id) OVERRIDE; + private: ShellBrowserContext* ShellBrowserContextForBrowserContext( BrowserContext* content_browser_context); From f5e08afd3f90d4605c4ac4467f6e727f9012567b Mon Sep 17 00:00:00 2001 From: libm Date: Tue, 29 Jul 2014 12:14:45 +0800 Subject: [PATCH 131/492] new x64 support for mac build --- tools/package_binaries.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 3035f6e587..9ec6268125 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -68,9 +68,18 @@ print 'Unsupported arch: ' + _arch exit(-1) -if platform_name == 'win' or platform_name == 'osx': +if platform_name == 'win': arch = 'ia32' +if platform_name == 'osx': + # detect output arch + nw_bin = binaries_location + '/node-webkit.app/Contents/MacOS/node-webkit' + import subprocess + if 'i386' in subprocess.check_output(['file',nw_bin]): + arch = 'ia32' + else: # should be 'x86_64' + arch = 'x64' + nw_ver = getnwversion.nw_version if getnwisrelease.release == 0: nw_ver += getnwisrelease.postfix From c385bcf307a1526ab9bdcfebb851172a7a05b3b5 Mon Sep 17 00:00:00 2001 From: Bas Wegh Date: Tue, 29 Jul 2014 08:01:23 +0200 Subject: [PATCH 132/492] Added myself to contributers --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 13ca024d2d..f015be29b3 100644 --- a/AUTHORS +++ b/AUTHORS @@ -27,3 +27,4 @@ Lukas Benes Lithare Emileit Jefry Tedjokusumo Wu Haojian +Bas Wegh From d3d5136ade4e750e7686e97c781097616fc07bd8 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 30 Jul 2014 00:31:14 +0800 Subject: [PATCH 133/492] check window script context in will handle navigation callback --- src/api/dispatcher.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/api/dispatcher.cc b/src/api/dispatcher.cc index f664c4ade1..e1da914a59 100644 --- a/src/api/dispatcher.cc +++ b/src/api/dispatcher.cc @@ -215,7 +215,9 @@ void Dispatcher::willHandleNavigationPolicy( v8::Isolate* isolate = v8::Isolate::GetCurrent(); - v8::Handle id_val = nwapi::Dispatcher::GetWindowId(web_view->mainFrame()); + v8::Handle id_val; + if (web_view->mainFrame() && !web_view->mainFrame()->mainWorldScriptContext().IsEmpty()) + id_val = nwapi::Dispatcher::GetWindowId(web_view->mainFrame()); if (id_val.IsEmpty()) return; if (id_val->IsUndefined() || id_val->IsNull()) From 6a17131dd606517da7c1cefb057ba493e3bfac80 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 30 Jul 2014 10:54:52 +0800 Subject: [PATCH 134/492] Fix #2072: [WIN] context menu popup in wrong (screen) position --- src/api/menu/menu_win.cc | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/src/api/menu/menu_win.cc b/src/api/menu/menu_win.cc index 9d67e93d5a..6162138ba7 100644 --- a/src/api/menu/menu_win.cc +++ b/src/api/menu/menu_win.cc @@ -28,6 +28,9 @@ #include "content/public/browser/web_contents.h" #include "content/public/browser/web_contents_view.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/gfx/gdi_util.h" #include "ui/gfx/icon_util.h" #include "ui/views/controls/menu/menu_2.h" @@ -144,12 +147,20 @@ void Menu::Popup(int x, int y, content::Shell* shell) { Rebuild(); // Map point from document to screen. - POINT screen_point = { x, y }; - ClientToScreen((HWND)shell->web_contents()->GetView()->GetNativeView(), - &screen_point); - - menu_->RunMenuAt(gfx::Point(screen_point.x, screen_point.y), - views::Menu2::ALIGN_TOPLEFT); + 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* web_contents_window = + shell->web_contents()->GetView()->GetNativeView(); + aura::Window* root_window = web_contents_window->GetRootWindow(); + aura::client::ScreenPositionClient* screen_position_client = + aura::client::GetScreenPositionClient(root_window); + if (screen_position_client) { + screen_position_client->ConvertPointToScreen(web_contents_window, + &screen_point); + } + menu_->RunMenuAt(screen_point, views::Menu2::ALIGN_TOPLEFT); } void Menu::Rebuild(const HMENU *parent_menu) { From 518e9249fca9ab27dff65ea193d85e4d722e870b Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 30 Jul 2014 10:55:02 +0800 Subject: [PATCH 135/492] bump version to v0.10.1 --- src/nw_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nw_version.h b/src/nw_version.h index a09902adf8..0292ab9174 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -24,7 +24,7 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 10 #define NW_PATCH_VERSION 1 -#define NW_VERSION_IS_RELEASE 0 +#define NW_VERSION_IS_RELEASE 1 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) From 948fb600e4a14564aed2e2975adcbcd3e5542263 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 30 Jul 2014 18:38:53 +0800 Subject: [PATCH 136/492] [CHANGELOG] update for 0.10.1 --- CHANGELOG.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5b6ac27662..6ee35ef8c4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,18 @@ +0.10.1 / 07-30-2014 +=================== +- Support Desktop notification (#27 Thanks to Jefry Tedjokusumo) +- Support Fullscreen API (#55) +- Official 64bit binary for Mac OS X (#296) +- Support F-keys in global shortcut (Thanks to Bas Wegh) +- Option to hide "Edit" and "Window" OS X menus (Thanks to Eric Newport) +- Fix #2072: [WIN] context menu popup in wrong (screen) position +- Fix #2136: crash when popup new window in some cases +- Fix: Linux symbol files are incomplete in 0.10.0 +- Fix #1908: allows redirection to App protocol for OAuth usage +- Fix: new-win-policy is fired on each navigation + 0.10.0 / 07-22-2014 -======================= +=================== - Fix: [WIN] download dialog - Fix: [WIN] MenuItem.enabled and other properties needs to be called twice to work (#1132) From 4c6c0179ea2f7ea159e1bfa3b112f65745c76069 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 30 Jul 2014 18:43:57 +0800 Subject: [PATCH 137/492] [README] update for 0.10.1 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index b8be9ecae3..459c235c08 100644 --- a/README.md +++ b/README.md @@ -20,11 +20,11 @@ It's created and developed in the Intel Open Source Technology Center. * Available on Linux, Mac OS X and Windows ## Downloads -* **v0.10.0:** (Jul 22, 2014, based off of Node v0.11.13, Chromium 35.0.1916.113): [release notes](https://groups.google.com/d/msg/node-webkit/x7kYuDO0Cj8/cIxoJ6RFiLsJ) +* **v0.10.1:** (Jul 30, 2014, based off of Node v0.11.13, Chromium 35.0.1916.113): [release notes](https://groups.google.com/d/msg/node-webkit/7h2lIKrlqAk/weeURSPhfMgJ) - * Linux: [32bit](http://dl.node-webkit.org/v0.10.0/node-webkit-v0.10.0-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.0/node-webkit-v0.10.0-linux-x64.tar.gz) - * Windows: [win32](http://dl.node-webkit.org/v0.10.0/node-webkit-v0.10.0-win-ia32.zip) - * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.10.0/node-webkit-v0.10.0-osx-ia32.zip) + * Linux: [32bit](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-linux-x64.tar.gz) + * Windows: [win32](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-win-ia32.zip) + * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-osx-ia32.zip) * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From e5978aece51cf15242c02894591610d875d9f0eb Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 30 Jul 2014 19:02:07 +0800 Subject: [PATCH 138/492] [README] add 64bit OSX link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 459c235c08..7fb16feaff 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ It's created and developed in the Intel Open Source Technology Center. * Linux: [32bit](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-linux-x64.tar.gz) * Windows: [win32](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-win-ia32.zip) - * Mac: [32bit, 10.7+](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-osx-ia32.zip) + * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-osx-x64.zip) * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From f434eda1fefd6cfbc90789c4c1f9b21f6c79075b Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 1 Aug 2014 13:24:21 +0800 Subject: [PATCH 139/492] [README] link to essay; shorter quick start --- README.md | 25 +++++-------------------- 1 file changed, 5 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 7fb16feaff..514b648823 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,7 @@ It's created and developed in the Intel Open Source Technology Center. [Introduction to node-webkit (slides)](https://speakerdeck.com/u/zcbenz/p/node-webkit-app-runtime-based-on-chromium-and-node-dot-js) [Creating Desktop Applications With node-webkit](http://strongloop.com/strongblog/creating-desktop-applications-with-node-webkit/) [WebApp to DesktopApp with node-webkit (slides)](http://oldgeeksguide.github.io/presentations/html5devconf2013/wtod.html) +[Essay on the history and internals of the project](http://yedingding.com/2014/08/01/node-webkit-intro-en.html) ## Features @@ -66,28 +67,12 @@ Create `package.json`: } ``` -Compress `index.html` and `package.json` into a zip archive called `app.nw`: - -````bash -$ zip app.nw index.html package.json -```` - -This should create a structure like this: - +Run: +```bash +$ /path/to/nw . (suppose the current directory contains 'package.json') ``` -app.nw -|-- package.json -`-- index.html -``` - -Download the prebuilt binary for your platform and use it to open the -`app.nw` file: - -````bash -$ ./nw app.nw -```` -Note: on Windows, you can drag the `app.nw` to `nw.exe` to open it. +Note: on Windows, you can drag the folder containing `package.json` to `nw.exe` to open it. ## Documents From e45e623c3b98bb9d4fd10afccb394caa496a5462 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 1 Aug 2014 13:25:56 +0800 Subject: [PATCH 140/492] [README] adding line break --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 514b648823..180378a55d 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ It's created and developed in the Intel Open Source Technology Center. [Introduction to node-webkit (slides)](https://speakerdeck.com/u/zcbenz/p/node-webkit-app-runtime-based-on-chromium-and-node-dot-js) [Creating Desktop Applications With node-webkit](http://strongloop.com/strongblog/creating-desktop-applications-with-node-webkit/) -[WebApp to DesktopApp with node-webkit (slides)](http://oldgeeksguide.github.io/presentations/html5devconf2013/wtod.html) +[WebApp to DesktopApp with node-webkit (slides)](http://oldgeeksguide.github.io/presentations/html5devconf2013/wtod.html) [Essay on the history and internals of the project](http://yedingding.com/2014/08/01/node-webkit-intro-en.html) ## Features From 328ee9b0cca0eb57ddf9ce515d58ae24d60c60e5 Mon Sep 17 00:00:00 2001 From: Jefry Date: Tue, 3 Jun 2014 11:13:29 +0800 Subject: [PATCH 141/492] [FlashFrame] change NativeWindow::FlashFrame input parameter to int, the javascript boolean parameter true redirected as -1, false as 0 --- src/api/window/window.cc | 6 +++--- src/api/window_bindings.js | 5 ++++- src/browser/native_window.h | 2 +- src/browser/native_window_gtk.cc | 4 ++-- src/browser/native_window_gtk.h | 2 +- src/browser/native_window_mac.h | 2 +- src/browser/native_window_mac.mm | 6 +++--- src/browser/native_window_win.cc | 15 +++++++++++++-- src/browser/native_window_win.h | 2 +- 9 files changed, 29 insertions(+), 15 deletions(-) diff --git a/src/api/window/window.cc b/src/api/window/window.cc index 3d475b269f..535f1c8522 100644 --- a/src/api/window/window.cc +++ b/src/api/window/window.cc @@ -254,9 +254,9 @@ void Window::Call(const std::string& method, arguments.GetInteger(1, &y)) shell_->window()->SetPosition(gfx::Point(x, y)); } else if (method == "RequestAttention") { - bool flash; - if (arguments.GetBoolean(0, &flash)) - shell_->window()->FlashFrame(flash); + int count; + if (arguments.GetInteger(0, &count)) + shell_->window()->FlashFrame(count); } else if (method == "SetBadgeLabel") { std::string label; if (arguments.GetString(0, &label)) diff --git a/src/api/window_bindings.js b/src/api/window_bindings.js index 7d54bf2f10..9c317618ff 100644 --- a/src/api/window_bindings.js +++ b/src/api/window_bindings.js @@ -408,7 +408,10 @@ Window.prototype.setShowInTaskbar = function(flag) { } Window.prototype.requestAttention = function(flash) { - flash = Boolean(flash); + if (typeof flash == 'boolean') { + // boolean true is redirected as -1 value + flash = flash ? -1 : 0; + } CallObjectMethod(this, 'RequestAttention', [ flash ]); } diff --git a/src/browser/native_window.h b/src/browser/native_window.h index 6cd8236ef6..d54ddd503e 100644 --- a/src/browser/native_window.h +++ b/src/browser/native_window.h @@ -99,7 +99,7 @@ class NativeWindow { virtual void SetPosition(const gfx::Point& position) = 0; virtual gfx::Point GetPosition() = 0; virtual void SetTitle(const std::string& title) = 0; - virtual void FlashFrame(bool flash) = 0; + virtual void FlashFrame(int count) = 0; virtual void SetBadgeLabel(const std::string& badge) = 0; virtual void SetKiosk(bool kiosk) = 0; virtual bool IsKiosk() = 0; diff --git a/src/browser/native_window_gtk.cc b/src/browser/native_window_gtk.cc index 50d24b4bfd..ebcbbc1987 100644 --- a/src/browser/native_window_gtk.cc +++ b/src/browser/native_window_gtk.cc @@ -294,8 +294,8 @@ void NativeWindowGtk::SetTitle(const std::string& title) { gtk_window_set_title(GTK_WINDOW(window_), title.c_str()); } -void NativeWindowGtk::FlashFrame(bool flash) { - gtk_window_set_urgency_hint(window_, flash); +void NativeWindowGtk::FlashFrame(int count) { + gtk_window_set_urgency_hint(window_, count); } void NativeWindowGtk::SetBadgeLabel(const std::string& badge) { diff --git a/src/browser/native_window_gtk.h b/src/browser/native_window_gtk.h index ed1c89159e..e44edc85d6 100644 --- a/src/browser/native_window_gtk.h +++ b/src/browser/native_window_gtk.h @@ -59,7 +59,7 @@ class NativeWindowGtk : public NativeWindow { virtual void SetPosition(const gfx::Point& position) OVERRIDE; virtual gfx::Point GetPosition() OVERRIDE; virtual void SetTitle(const std::string& title) OVERRIDE; - virtual void FlashFrame(bool flash) OVERRIDE; + virtual void FlashFrame(int count) OVERRIDE; virtual void SetBadgeLabel(const std::string& badge) OVERRIDE; virtual void SetKiosk(bool kiosk) OVERRIDE; virtual bool IsKiosk() OVERRIDE; diff --git a/src/browser/native_window_mac.h b/src/browser/native_window_mac.h index b5a5817b63..e93f7823db 100644 --- a/src/browser/native_window_mac.h +++ b/src/browser/native_window_mac.h @@ -63,7 +63,7 @@ class NativeWindowCocoa : public NativeWindow { virtual void SetPosition(const gfx::Point& position) OVERRIDE; virtual gfx::Point GetPosition() OVERRIDE; virtual void SetTitle(const std::string& title) OVERRIDE; - virtual void FlashFrame(bool flash) OVERRIDE; + virtual void FlashFrame(int count) OVERRIDE; virtual void SetBadgeLabel(const std::string& badge) OVERRIDE; virtual void SetKiosk(bool kiosk) OVERRIDE; virtual bool IsKiosk() OVERRIDE; diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index 4a20b86a14..38641c45f9 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -636,9 +636,9 @@ - (NSRect)contentRectForFrameRect:(NSRect)frameRect { [window() setTitle:base::SysUTF8ToNSString(title)]; } -void NativeWindowCocoa::FlashFrame(bool flash) { - if (flash) { - attention_request_id_ = [NSApp requestUserAttention:NSInformationalRequest]; +void NativeWindowCocoa::FlashFrame(int count) { + if (count != 0) { + attention_request_id_ = count < 0 ? [NSApp requestUserAttention:NSInformationalRequest] : [NSApp requestUserAttention:NSCriticalRequest]; } else { [NSApp cancelUserAttentionRequest:attention_request_id_]; attention_request_id_ = 0; diff --git a/src/browser/native_window_win.cc b/src/browser/native_window_win.cc index 003c366133..8643f47e74 100644 --- a/src/browser/native_window_win.cc +++ b/src/browser/native_window_win.cc @@ -479,8 +479,19 @@ gfx::Point NativeWindowWin::GetPosition() { return window_->GetWindowBoundsInScreen().origin(); } -void NativeWindowWin::FlashFrame(bool flash) { - window_->FlashFrame(flash); +void NativeWindowWin::FlashFrame(int count) { + FLASHWINFO fwi; + fwi.cbSize = sizeof(fwi); + fwi.hwnd = views::HWNDForWidget(window_); + if (count != 0) { + fwi.dwFlags = FLASHW_ALL; + fwi.uCount = count < 0 ? 4 : count; + fwi.dwTimeout = 0; + } + else { + fwi.dwFlags = FLASHW_STOP; + } + FlashWindowEx(&fwi); } HICON createBadgeIcon(const HWND hWnd, const TCHAR *value, const int sizeX, const int sizeY) { diff --git a/src/browser/native_window_win.h b/src/browser/native_window_win.h index c85bc0c2e6..f174aa9ec6 100644 --- a/src/browser/native_window_win.h +++ b/src/browser/native_window_win.h @@ -84,7 +84,7 @@ class NativeWindowWin : public NativeWindow, virtual void SetPosition(const gfx::Point& position) OVERRIDE; virtual gfx::Point GetPosition() OVERRIDE; virtual void SetTitle(const std::string& title) OVERRIDE; - virtual void FlashFrame(bool flash) OVERRIDE; + virtual void FlashFrame(int count) OVERRIDE; virtual void SetKiosk(bool kiosk) OVERRIDE; virtual void SetBadgeLabel(const std::string& badge) OVERRIDE; virtual bool IsKiosk() OVERRIDE; From ed22df540b7b6a78574c66a612965f6b945ded66 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 4 Aug 2014 12:48:24 +0800 Subject: [PATCH 142/492] support asan build --- nw.gypi | 2 +- src/api/shortcut/shortcut.h | 2 +- src/api/window/window.cc | 2 ++ src/api/window/window.h | 3 +++ src/browser/printing/print_dialog_gtk.h | 2 +- src/media/media_capture_devices_dispatcher.h | 4 ++-- src/nw_notification_manager_linux.cc | 6 ++++++ src/nw_notification_manager_linux.h | 4 +--- 8 files changed, 17 insertions(+), 8 deletions(-) diff --git a/nw.gypi b/nw.gypi index a8c20c7c7c..efd69ca904 100644 --- a/nw.gypi +++ b/nw.gypi @@ -364,7 +364,7 @@ '<(DEPTH)/ui/views/controls/webview/webview.gyp:webview', ], }], - ['(os_posix==1 and OS != "mac" and linux_use_tcmalloc==1)', { + ['(os_posix==1 and OS != "mac" and linux_use_tcmalloc==1 and asan==0)', { 'dependencies': [ # This is needed by content/app/content_main_runner.cc '<(DEPTH)/base/allocator/allocator.gyp:allocator', diff --git a/src/api/shortcut/shortcut.h b/src/api/shortcut/shortcut.h index 9bff68602f..3da6a9f195 100644 --- a/src/api/shortcut/shortcut.h +++ b/src/api/shortcut/shortcut.h @@ -44,7 +44,7 @@ class Shortcut : public Base, public GlobalShortcutListener::Observer { void OnFailed(const std::string failed_msg); // GlobalShortcutListener::Observer implementation. - virtual void OnKeyPressed(const ui::Accelerator& accelerator); + virtual void OnKeyPressed(const ui::Accelerator& accelerator) OVERRIDE; private: ui::Accelerator accelerator_; diff --git a/src/api/window/window.cc b/src/api/window/window.cc index 3d475b269f..a94b0355be 100644 --- a/src/api/window/window.cc +++ b/src/api/window/window.cc @@ -161,6 +161,8 @@ PopulateCookieObject(const net::CanonicalCookie& canonical_cookie) { namespace nwapi { +CookieAPIContext::~CookieAPIContext() {} + Window::Window(int id, const base::WeakPtr& dispatcher_host, const base::DictionaryValue& option) diff --git a/src/api/window/window.h b/src/api/window/window.h index fa9295e834..6824547707 100644 --- a/src/api/window/window.h +++ b/src/api/window/window.h @@ -51,6 +51,9 @@ class CookieAPIContext : public base::RefCountedThreadSafe { GURL url_; int req_id_; bool success_; +private: + friend class base::RefCountedThreadSafe; + ~CookieAPIContext(); }; diff --git a/src/browser/printing/print_dialog_gtk.h b/src/browser/printing/print_dialog_gtk.h index 1eb385cc30..e6fe453e41 100644 --- a/src/browser/printing/print_dialog_gtk.h +++ b/src/browser/printing/print_dialog_gtk.h @@ -38,7 +38,7 @@ class PrintDialogGtk virtual void UseDefaultSettings() OVERRIDE; virtual bool UpdateSettings(const base::DictionaryValue& job_settings, const printing::PageRanges& ranges, - printing::PrintSettings* settings) OVERRIDE; + printing::PrintSettings* settings) ; //FIXME: override virtual void ShowDialog( gfx::NativeView parent_view, bool has_selection, diff --git a/src/media/media_capture_devices_dispatcher.h b/src/media/media_capture_devices_dispatcher.h index 2e707570a2..db4f6e53ff 100644 --- a/src/media/media_capture_devices_dispatcher.h +++ b/src/media/media_capture_devices_dispatcher.h @@ -52,7 +52,7 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver, // Overridden from content::MediaObserver: virtual void OnAudioCaptureDevicesChanged() OVERRIDE; virtual void OnVideoCaptureDevicesChanged() OVERRIDE; - void OnCreatingAudioStream(int render_process_id, + virtual void OnCreatingAudioStream(int render_process_id, int render_view_id) OVERRIDE; // content::NotificationObserver implementation. @@ -92,7 +92,7 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver, int page_request_id, const GURL& security_origin, const content::MediaStreamDevice& device, - content::MediaRequestState state) {} + content::MediaRequestState state) OVERRIDE {} // Returns the first available audio or video device, or NULL if no devices // are available. diff --git a/src/nw_notification_manager_linux.cc b/src/nw_notification_manager_linux.cc index 253d3808af..2b17433ebb 100644 --- a/src/nw_notification_manager_linux.cc +++ b/src/nw_notification_manager_linux.cc @@ -131,4 +131,10 @@ bool NotificationManagerLinux::CancelDesktopNotification(int render_process_id, } return false; } + +bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_view_id, const bool worker) { + return AddDesktopNotification(params, render_process_id, render_view_id, worker, NULL); +} + } // namespace nw diff --git a/src/nw_notification_manager_linux.h b/src/nw_notification_manager_linux.h index 10f18c4eba..f0851ded02 100644 --- a/src/nw_notification_manager_linux.h +++ b/src/nw_notification_manager_linux.h @@ -38,9 +38,7 @@ class NotificationManagerLinux : public NotificationManager { explicit NotificationManagerLinux(); virtual ~NotificationManagerLinux(); virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker) OVERRIDE { - return AddDesktopNotification(params, render_process_id, render_view_id, worker, NULL); - } + const int render_process_id, const int render_view_id, const bool worker) OVERRIDE; virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) OVERRIDE; }; From 646275d3acf6f2a5bb475993da6fc385679c1424 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 4 Aug 2014 14:39:34 +0200 Subject: [PATCH 143/492] Fixed support for screencapture media requests. This fixes issue #1994. --- nw.gypi | 1 + src/media/media_stream_devices_controller.cc | 28 +++++++++++++++++--- 2 files changed, 25 insertions(+), 4 deletions(-) diff --git a/nw.gypi b/nw.gypi index efd69ca904..4fe4ec9e5c 100644 --- a/nw.gypi +++ b/nw.gypi @@ -63,6 +63,7 @@ ], 'include_dirs': [ '<(DEPTH)', + '<(DEPTH)/third_party', '<(DEPTH)/third_party/WebKit/Source', '<(DEPTH)/third_party/WebKit/public/web', '<(DEPTH)/breakpad/src', diff --git a/src/media/media_stream_devices_controller.cc b/src/media/media_stream_devices_controller.cc index 29942a0300..032a659ce3 100644 --- a/src/media/media_stream_devices_controller.cc +++ b/src/media/media_stream_devices_controller.cc @@ -4,13 +4,17 @@ #include "content/nw/src/media/media_stream_devices_controller.h" +#include "base/command_line.h" #include "base/values.h" +#include "chrome/common/chrome_switches.h" #include "content/nw/src/media/media_capture_devices_dispatcher.h" #include "content/nw/src/media/media_internals.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/desktop_media_id.h" #include "content/public/common/media_stream_request.h" +#include "third_party/webrtc/modules/desktop_capture/desktop_capture_types.h" + using content::BrowserThread; namespace { @@ -230,10 +234,26 @@ void MediaStreamDevicesController::HandleTapMediaRequest() { content::MEDIA_TAB_AUDIO_CAPTURE, "", "")); } if (request_.video_type == content::MEDIA_DESKTOP_VIDEO_CAPTURE) { - content::DesktopMediaID media_id = - content::DesktopMediaID::Parse(request_.requested_video_device_id); - devices.push_back(content::MediaStreamDevice( - content::MEDIA_DESKTOP_VIDEO_CAPTURE, media_id.ToString(), "Screen")); + const bool screen_capture_enabled = + CommandLine::ForCurrentProcess()->HasSwitch( + switches::kEnableUserMediaScreenCapturing); + + if (screen_capture_enabled) { + content::DesktopMediaID media_id; + // If the device id wasn't specified then this is a screen capture request + // (i.e. chooseDesktopMedia() API wasn't used to generate device id). + if (request_.requested_video_device_id.empty()) { + media_id = + content::DesktopMediaID(content::DesktopMediaID::TYPE_SCREEN, + webrtc::kFullDesktopScreenId); + } else { + media_id = + content::DesktopMediaID::Parse(request_.requested_video_device_id); + } + + devices.push_back(content::MediaStreamDevice( + content::MEDIA_DESKTOP_VIDEO_CAPTURE, media_id.ToString(), "Screen")); + } } callback_.Run(devices, From 5661268f194cd369dbe9d101f95172312ac70511 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Tue, 5 Aug 2014 10:12:33 +0200 Subject: [PATCH 144/492] Added myself to contributors. --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index f015be29b3..fc3e010f66 100644 --- a/AUTHORS +++ b/AUTHORS @@ -28,3 +28,4 @@ Lithare Emileit Jefry Tedjokusumo Wu Haojian Bas Wegh +Joachim Bauch From 309579662c948906bed5397507905331c9450170 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Wed, 6 Aug 2014 09:29:36 +0800 Subject: [PATCH 145/492] [WIN] Fix build error --- src/browser/login_view.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/browser/login_view.cc b/src/browser/login_view.cc index 5220882397..75fb4ba1af 100644 --- a/src/browser/login_view.cc +++ b/src/browser/login_view.cc @@ -5,7 +5,6 @@ #include "login_view.h" #include "base/strings/utf_string_conversions.h" -#include "grit/generated_resources.h" #include "ui/base/l10n/l10n_util.h" #include "ui/views/controls/label.h" #include "ui/views/controls/textfield/textfield.h" From 18f2a1f0f1be74dac96f47336e223d58099294d2 Mon Sep 17 00:00:00 2001 From: Jefry Date: Fri, 6 Jun 2014 19:00:54 +0800 Subject: [PATCH 146/492] [ProgressBar] Linux implementation, currently only for Ubuntu using Unity api (+1 squashed commit) Squashed commits: [4d33a69] [ProgressBar] fix window compile error (+1 squashed commits) Squashed commits: [1738c18] [linux] placeholder for SetProgressBar (+1 squashed commit) Squashed commits: [8dd41ec] [WIN] implement SetProgressBar for windows platform (+1 squashed commit) Squashed commits: [79dca6e] [WIN] implement SetProgressBar for windows platform (+1 squashed commit) Squashed commits: [1be7893] [MAC] implements SetProgressBar with value 0 - 1, value > 1 means Indeterminate , value < 0 will turns of the progress bar. Currently still have problem with animating the Indeterminate state, and the progress bar color is fixed to blue --- nw.gypi | 2 + src/api/window/window.cc | 4 ++ src/api/window_bindings.js | 6 +++ src/browser/native_window.h | 1 + src/browser/native_window_gtk.cc | 21 +++++++- src/browser/native_window_gtk.h | 1 + src/browser/native_window_mac.h | 1 + src/browser/native_window_mac.mm | 89 ++++++++++++++++++++++++++++++++ src/browser/native_window_win.cc | 31 +++++++++++ src/browser/native_window_win.h | 1 + 10 files changed, 156 insertions(+), 1 deletion(-) diff --git a/nw.gypi b/nw.gypi index 4fe4ec9e5c..0f38f8bed1 100644 --- a/nw.gypi +++ b/nw.gypi @@ -104,6 +104,8 @@ '<(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/gtk/unity_service.cc', + '<(DEPTH)/chrome/browser/ui/gtk/unity_service.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', diff --git a/src/api/window/window.cc b/src/api/window/window.cc index d95fbcdab4..adfe934653 100644 --- a/src/api/window/window.cc +++ b/src/api/window/window.cc @@ -263,6 +263,10 @@ void Window::Call(const std::string& method, std::string label; if (arguments.GetString(0, &label)) shell_->window()->SetBadgeLabel(label); + } else if (method == "SetProgressBar") { + double progress; + if (arguments.GetDouble(0, &progress)) + shell_->window()->SetProgressBar(progress); } else if (method == "SetMenu") { int id; if (arguments.GetInteger(0, &id)) diff --git a/src/api/window_bindings.js b/src/api/window_bindings.js index 9c317618ff..570e8094c6 100644 --- a/src/api/window_bindings.js +++ b/src/api/window_bindings.js @@ -420,6 +420,12 @@ Window.prototype.setBadgeLabel = function(label) { CallObjectMethod(this, 'SetBadgeLabel', [ label ]); } +Window.prototype.setProgressBar = function(progress) { + if (typeof progress != "number") + throw new String('progress must be a number'); + CallObjectMethod(this, 'SetProgressBar', [ progress ]); +} + Window.prototype.setPosition = function(position) { if (position != 'center' && position != 'mouse') throw new String('Invalid postion'); diff --git a/src/browser/native_window.h b/src/browser/native_window.h index d54ddd503e..1a73dd2d23 100644 --- a/src/browser/native_window.h +++ b/src/browser/native_window.h @@ -101,6 +101,7 @@ class NativeWindow { virtual void SetTitle(const std::string& title) = 0; virtual void FlashFrame(int count) = 0; virtual void SetBadgeLabel(const std::string& badge) = 0; + virtual void SetProgressBar(double progress) = 0; virtual void SetKiosk(bool kiosk) = 0; virtual bool IsKiosk() = 0; virtual void SetMenu(nwapi::Menu* menu) = 0; diff --git a/src/browser/native_window_gtk.cc b/src/browser/native_window_gtk.cc index ebcbbc1987..e4bd5eae6a 100644 --- a/src/browser/native_window_gtk.cc +++ b/src/browser/native_window_gtk.cc @@ -23,7 +23,9 @@ #include #include "base/values.h" +#include "base/environment.h" #include "chrome/browser/ui/gtk/gtk_window_util.h" +#include "chrome/browser/ui/gtk/unity_service.h" #include "extensions/common/draggable_region.h" #include "content/nw/src/api/menu/menu.h" #include "content/nw/src/common/shell_switches.h" @@ -37,6 +39,15 @@ #include "ui/gfx/rect.h" #include "ui/gfx/skia_utils_gtk.h" +namespace ShellIntegrationLinux { +std::string GetDesktopName(base::Environment* env) { + std::string name; + if (env->GetVar("NW_DESKTOP", &name) && !name.empty()) + return name; + return "nw.desktop"; +} +} + namespace nw { namespace { @@ -299,7 +310,15 @@ void NativeWindowGtk::FlashFrame(int count) { } void NativeWindowGtk::SetBadgeLabel(const std::string& badge) { - // TODO + if (unity::IsRunning()) { + unity::SetDownloadCount(atoi(badge.c_str())); + } +} + +void NativeWindowGtk::SetProgressBar(double progress) { + if (unity::IsRunning()) { + unity::SetProgressFraction(progress); + } } void NativeWindowGtk::SetKiosk(bool kiosk) { diff --git a/src/browser/native_window_gtk.h b/src/browser/native_window_gtk.h index e44edc85d6..db7e247290 100644 --- a/src/browser/native_window_gtk.h +++ b/src/browser/native_window_gtk.h @@ -61,6 +61,7 @@ class NativeWindowGtk : public NativeWindow { virtual void SetTitle(const std::string& title) OVERRIDE; virtual void FlashFrame(int count) OVERRIDE; virtual void SetBadgeLabel(const std::string& badge) OVERRIDE; + virtual void SetProgressBar(double progress) OVERRIDE; virtual void SetKiosk(bool kiosk) OVERRIDE; virtual bool IsKiosk() OVERRIDE; virtual void SetMenu(nwapi::Menu* menu) OVERRIDE; diff --git a/src/browser/native_window_mac.h b/src/browser/native_window_mac.h index e93f7823db..28f05080e3 100644 --- a/src/browser/native_window_mac.h +++ b/src/browser/native_window_mac.h @@ -65,6 +65,7 @@ class NativeWindowCocoa : public NativeWindow { virtual void SetTitle(const std::string& title) OVERRIDE; virtual void FlashFrame(int count) OVERRIDE; virtual void SetBadgeLabel(const std::string& badge) OVERRIDE; + virtual void SetProgressBar(double progress) OVERRIDE; virtual void SetKiosk(bool kiosk) OVERRIDE; virtual bool IsKiosk() OVERRIDE; virtual void SetMenu(nwapi::Menu* menu) OVERRIDE; diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index 38641c45f9..1ebb6cd467 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -307,6 +307,41 @@ - (NSRect)contentRectForFrameRect:(NSRect)frameRect { @end +@interface NWProgressBar : NSProgressIndicator +@end + +@implementation NWProgressBar + +// override the drawing, so we can give color to the progress bar +- (void)drawRect:(NSRect)dirtyRect { + + [super drawRect:dirtyRect]; + + if(self.style != NSProgressIndicatorBarStyle) + return; + + NSRect sliceRect, remainderRect; + double progressFraction = ([self doubleValue] - [self minValue]) / + ([self maxValue] - [self minValue]); + + NSDivideRect(dirtyRect, &sliceRect, &remainderRect, + NSWidth(dirtyRect) * progressFraction, NSMinXEdge); + + const int kProgressBarCornerRadius = 3; + + if (progressFraction == 0.0) + return; + + NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:sliceRect + xRadius:kProgressBarCornerRadius + yRadius:kProgressBarCornerRadius]; + // blue color with alpha blend 0.5 + [[NSColor colorWithCalibratedRed:0 green:0 blue:1 alpha:0.5] set]; + [path fill]; +} +@end + + namespace nw { NativeWindowCocoa::NativeWindowCocoa( @@ -649,6 +684,60 @@ - (NSRect)contentRectForFrameRect:(NSRect)frameRect { [[NSApp dockTile] setBadgeLabel:base::SysUTF8ToNSString(badge)]; } + +void NativeWindowCocoa::SetProgressBar(double progress){ + NSDockTile *dockTile = [NSApp dockTile]; + NWProgressBar *progressIndicator = NULL; + + if (dockTile.contentView == NULL && progress >= 0) { + + // create image view to draw application icon + NSImageView *iv = [[NSImageView alloc] init]; + [iv setImage:[NSApp applicationIconImage]]; + + // set dockTile content view to app icon + [dockTile setContentView:iv]; + + progressIndicator = [[NWProgressBar alloc] + initWithFrame:NSMakeRect(0.0f, 0.0f, dockTile.size.width, 15.)]; + + [progressIndicator setStyle:NSProgressIndicatorBarStyle]; + + [progressIndicator setBezeled:YES]; + [progressIndicator setMinValue:0]; + [progressIndicator setMaxValue:1]; + [progressIndicator setHidden:NO]; + [progressIndicator setUsesThreadedAnimation:false]; + + // add progress indicator to image view + [iv addSubview:progressIndicator]; + } + + progressIndicator = (NWProgressBar*)[dockTile.contentView.subviews objectAtIndex:0]; + + if(progress >= 0) { + [progressIndicator setIndeterminate:progress > 1]; + if(progress > 1) { + // progress Indicator is indeterminate + // [progressIndicator startAnimation:window_]; + [progressIndicator setDoubleValue:1]; + } + else { + //[progressIndicator stopAnimation:window_]; + [progressIndicator setDoubleValue:progress]; + } + } + else { + // progress indicator < 0, destroy it + [[dockTile.contentView.subviews objectAtIndex:0]release]; + [dockTile.contentView release]; + dockTile.contentView = NULL; + } + + [dockTile display]; + +} + void NativeWindowCocoa::SetKiosk(bool kiosk) { if (kiosk) { NSApplicationPresentationOptions options = diff --git a/src/browser/native_window_win.cc b/src/browser/native_window_win.cc index 8643f47e74..5bbe361c50 100644 --- a/src/browser/native_window_win.cc +++ b/src/browser/native_window_win.cc @@ -541,6 +541,37 @@ void NativeWindowWin::SetBadgeLabel(const std::string& badge) { DestroyIcon(icon); } +void NativeWindowWin::SetProgressBar(double progress) { + base::win::ScopedComPtr taskbar; + HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, + CLSCTX_INPROC_SERVER); + + if (FAILED(result)) { + VLOG(1) << "Failed creating a TaskbarList3 object: " << result; + return; + } + + result = taskbar->HrInit(); + if (FAILED(result)) { + LOG(ERROR) << "Failed initializing an ITaskbarList3 interface."; + return; + } + + HWND hWnd = views::HWNDForWidget(window_); + + TBPFLAG tbpFlag = TBPF_NOPROGRESS; + + if (progress > 1) { + tbpFlag = TBPF_INDETERMINATE; + } + else if (progress >= 0) { + tbpFlag = TBPF_NORMAL; + taskbar->SetProgressValue(hWnd, progress * 100, 100); + } + + taskbar->SetProgressState(hWnd, tbpFlag); +} + void NativeWindowWin::SetKiosk(bool kiosk) { SetFullscreen(kiosk); } diff --git a/src/browser/native_window_win.h b/src/browser/native_window_win.h index f174aa9ec6..33b27b2c5f 100644 --- a/src/browser/native_window_win.h +++ b/src/browser/native_window_win.h @@ -87,6 +87,7 @@ class NativeWindowWin : public NativeWindow, virtual void FlashFrame(int count) OVERRIDE; virtual void SetKiosk(bool kiosk) OVERRIDE; virtual void SetBadgeLabel(const std::string& badge) OVERRIDE; + virtual void SetProgressBar(double progress) OVERRIDE; virtual bool IsKiosk() OVERRIDE; virtual void SetMenu(nwapi::Menu* menu) OVERRIDE; virtual void SetToolbarButtonEnabled(TOOLBAR_BUTTON button, From b445a6e9d1b79d73920b1a7e0b5bd010c3a313e5 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 6 Aug 2014 15:24:37 +0800 Subject: [PATCH 147/492] Fix #2167: require works in wrong path in new-instance window the url we get from DOM is 'about:blank' in DidCreateScriptContext. check this later in willSetSecurityToken again and set it --- src/renderer/shell_content_renderer_client.cc | 56 +++++++++++-------- src/renderer/shell_content_renderer_client.h | 2 + 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index 43d5831f76..3e2eb1bbd0 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -256,6 +256,37 @@ bool ShellContentRendererClient::goodForNode(blink::WebFrame* frame) return use_node; } +void ShellContentRendererClient::SetupNodeUtil( + blink::WebFrame* frame, + v8::Handle context) { + RenderViewImpl* rv = RenderViewImpl::FromWebView(frame->view()); + v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope scope(isolate); + + std::string root_path = rv->renderer_preferences_.nw_app_root_path.AsUTF8Unsafe(); +#if defined(OS_WIN) + base::ReplaceChars(root_path, "\\", "\\\\", &root_path); +#endif + base::ReplaceChars(root_path, "'", "\\'", &root_path); + v8::Local script = v8::Script::Compile(v8::String::NewFromUtf8(isolate, ( + // Make node's relative modules work + "if (!process.mainModule.filename || process.mainModule.filename === 'blank') {" + " var root = '" + root_path + "';" +#if defined(OS_WIN) + "process.mainModule.filename = decodeURIComponent(window.location.pathname.substr(1));" +#else + "process.mainModule.filename = decodeURIComponent(window.location.pathname);" +#endif + "console.log('process.mainModule.filename: ' + process.mainModule.filename);" + "if (window.location.href.indexOf('app://') === 0) {process.mainModule.filename = root + '/' + process.mainModule.filename}" + "process.mainModule.paths = global.require('module')._nodeModulePaths(process.cwd());" + "process.mainModule.loaded = true;" + "}").c_str()), + v8::String::NewFromUtf8(isolate, "process_main")); + CHECK(*script); + script->Run(); +} + bool ShellContentRendererClient::WillSetSecurityToken( blink::WebFrame* frame, v8::Handle context) { @@ -274,7 +305,7 @@ bool ShellContentRendererClient::WillSetSecurityToken( int ret = 0; RenderViewImpl* rv = RenderViewImpl::FromWebView(frame->view()); rv->Send(new ViewHostMsg_GrantUniversalPermissions(rv->GetRoutingID(), &ret)); - + SetupNodeUtil(frame, context); return true; } @@ -348,28 +379,7 @@ void ShellContentRendererClient::InstallNodeSymbols( } if (use_node) { - RenderViewImpl* rv = RenderViewImpl::FromWebView(frame->view()); - std::string root_path = rv->renderer_preferences_.nw_app_root_path.AsUTF8Unsafe(); -#if defined(OS_WIN) - base::ReplaceChars(root_path, "\\", "\\\\", &root_path); -#endif - base::ReplaceChars(root_path, "'", "\\'", &root_path); - v8::Local script = v8::Script::Compile(v8::String::NewFromUtf8(isolate, ( - // Make node's relative modules work - "if (!process.mainModule.filename) {" - " var root = '" + root_path + "';" -#if defined(OS_WIN) - "process.mainModule.filename = decodeURIComponent(window.location.pathname.substr(1));" -#else - "process.mainModule.filename = decodeURIComponent(window.location.pathname);" -#endif - "if (window.location.href.indexOf('app://') === 0) {process.mainModule.filename = root + '/' + process.mainModule.filename}" - "process.mainModule.paths = global.require('module')._nodeModulePaths(process.cwd());" - "process.mainModule.loaded = true;" - "}").c_str()), - v8::String::NewFromUtf8(isolate, "process_main")); - CHECK(*script); - script->Run(); + SetupNodeUtil(frame, context); } if (use_node || is_nw_protocol) { diff --git a/src/renderer/shell_content_renderer_client.h b/src/renderer/shell_content_renderer_client.h index 9243ac3055..b815585491 100644 --- a/src/renderer/shell_content_renderer_client.h +++ b/src/renderer/shell_content_renderer_client.h @@ -71,6 +71,8 @@ class ShellContentRendererClient : public ContentRendererClient { v8::Handle context); bool goodForNode(blink::WebFrame* frame); + void SetupNodeUtil(blink::WebFrame* frame, v8::Handle context); + // Catch node uncaughtException. static void ReportException(const v8::FunctionCallbackInfo& args); From bbe36c88f54fb97df9ff0ca96daf30690d6f2c17 Mon Sep 17 00:00:00 2001 From: jtg-gg Date: Tue, 5 Aug 2014 17:34:27 +0800 Subject: [PATCH 148/492] [Notification] linux improvement, sent on close event (+1 squashed commit) Squashed commits: [50defb9] [Notification] windows improvement, now will display notification even the icon size < 32x32 (+1 squashed commits) Squashed commits: [b7d99ce] [Notification] improve linux notification for different notification server --- src/nw_notification_manager_linux.cc | 48 +++++++++++++++++++++------- src/nw_notification_manager_linux.h | 12 ++++++- src/nw_notification_manager_win.cc | 4 +-- 3 files changed, 50 insertions(+), 14 deletions(-) diff --git a/src/nw_notification_manager_linux.cc b/src/nw_notification_manager_linux.cc index 2b17433ebb..f5bf355f4c 100644 --- a/src/nw_notification_manager_linux.cc +++ b/src/nw_notification_manager_linux.cc @@ -32,28 +32,39 @@ #include "ui/gfx/gtk_util.h" -//#define GET_NOTIFICATION(id) mNotificationIDmap.find(id) -//Ubuntu notify-osd can only show 1 notification, this is the "hack" to do that -#define GET_NOTIFICATION(id) mNotificationIDmap.begin() - namespace nw { NotificationManagerLinux::NotificationManagerLinux() { notify_init (content::Shell::GetPackage()->GetName().c_str()); + char* info[4]; + notify_get_server_info(&info[0], &info[1], &info[2], &info[3]); + + //Ubuntu notify-osd can only show 1 notification, this is the "hack" to do that + mForceOneNotification = strcmp(info[0], "notify-osd") == 0; } NotificationManagerLinux::~NotificationManagerLinux() { notify_uninit(); } +NotificationManagerLinux::NotificationMap::iterator NotificationManagerLinux::getNotification(int id) { + if (mForceOneNotification) { + return mNotificationIDmap.begin(); + } + return mNotificationIDmap.find(id); +} + void NotificationManagerLinux::onClose(NotifyNotification *notif) { NotificationManagerLinux* singleton = static_cast(NotificationManagerLinux::getSingleton()); - std::map::iterator i; + NotificationMap::iterator i; for (i = singleton->mNotificationIDmap.begin(); i!=singleton->mNotificationIDmap.end(); i++) { - if (i->second == notif) + if (i->second.mNotification == notif) break; } + //int close_reason = notify_notification_get_closed_reason(notif); + //printf("close reason %d\n", close_reason); + singleton->DesktopNotificationPostClose(i->second.mRenderProcessId, i->second.mRenderViewId, i->first, false); singleton->mNotificationIDmap.erase(i); g_object_unref(G_OBJECT(notif)); }; @@ -95,16 +106,31 @@ bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktop } NotifyNotification * notif; - std::map::iterator i = GET_NOTIFICATION(params.notification_id); + NotificationMap::iterator i = getNotification(params.notification_id); if (i==mNotificationIDmap.end()) { notif = notify_notification_new ( base::UTF16ToUTF8(params.title).c_str(), base::UTF16ToUTF8(params.body).c_str(), NULL); - mNotificationIDmap[params.notification_id] = notif; + NotificationData data; + data.mNotification = notif; + data.mRenderProcessId = render_process_id; + data.mRenderViewId = render_view_id; + mNotificationIDmap[params.notification_id] = data; } else { - notif = i->second; + notif = i->second.mNotification; notify_notification_update(notif, base::UTF16ToUTF8(params.title).c_str(), base::UTF16ToUTF8(params.body).c_str(), NULL); + + // means this is the notify-osd hack + if (i->first != params.notification_id) { + NotificationData data; + data.mNotification = notif; + g_object_ref(G_OBJECT(notif)); + onClose(notif); + data.mRenderProcessId = render_process_id; + data.mRenderViewId = render_view_id; + mNotificationIDmap[params.notification_id] = data; + } } GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap); @@ -125,9 +151,9 @@ bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktop } bool NotificationManagerLinux::CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) { - std::map::const_iterator i = GET_NOTIFICATION(notification_id); + NotificationMap::const_iterator i = getNotification(notification_id); if (i!=mNotificationIDmap.end()) { - return notify_notification_close(i->second, NULL); + return notify_notification_close(i->second.mNotification, NULL); } return false; } diff --git a/src/nw_notification_manager_linux.h b/src/nw_notification_manager_linux.h index f0851ded02..834acb035a 100644 --- a/src/nw_notification_manager_linux.h +++ b/src/nw_notification_manager_linux.h @@ -26,9 +26,19 @@ namespace nw { class NotificationManagerLinux : public NotificationManager { - std::map mNotificationIDmap; + struct NotificationData { + NotifyNotification* mNotification; + int mRenderProcessId; + int mRenderViewId; + }; + + typedef std::map NotificationMap; + NotificationMap mNotificationIDmap; + static void onClose(NotifyNotification *notif); + bool mForceOneNotification; + NotificationMap::iterator getNotification(int id); // internal function for AddDesktopNotification virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, diff --git a/src/nw_notification_manager_win.cc b/src/nw_notification_manager_win.cc index 8f4ac41296..3696db5b14 100644 --- a/src/nw_notification_manager_win.cc +++ b/src/nw_notification_manager_win.cc @@ -173,8 +173,8 @@ bool NotificationManagerWin::AddDesktopNotification(const content::ShowDesktopNo base::string16 body = params.body; if (body.empty()) body = L" "; - //show the baloon - bool result = status_icon->DisplayBalloon(icon.IsEmpty() ? gfx::ImageSkia() : *icon.ToImageSkia(), params.title, body); + //show the baloon, this only works if iconsize >= 32x32 + bool result = status_icon->DisplayBalloon(icon.Width() < 32 || icon.Height() < 32 ? gfx::ImageSkia() : *icon.ToImageSkia(), params.title, body); if (!result) { DesktopNotificationPostError(L"DisplayBalloon fail"); ReleaseNotification(); From 62c52b3d98f9e24af495962bad71e9d11fe8b3ea Mon Sep 17 00:00:00 2001 From: Jefry Date: Thu, 12 Jun 2014 16:29:33 +0800 Subject: [PATCH 149/492] [Screen Geometry] fix run time error (+1 squashed commit) Squashed commits: [29ac0fd] fix wrong merging (+1 squashed commit) Squashed commits: [0a0d093] properly call Add/Remove ScreenChangeCallback native function, by counting the javascript listener number (+2 squashed commits) Squashed commits: [6e1c7c5] Change the screen geometry event handler to use node.js EventEmitter move Screen functions from App to seperate Screen class [23332bf] Implement "Generic" Event listener, with application on Screen Geometry events listener (+1 squashed commit) Squashed commits: [372c9bd] add App API to get screen(s) information --- nw.gypi | 4 + src/api/dispatcher_bindings.cc | 2 + src/api/dispatcher_host.cc | 7 ++ src/api/event/event.cc | 41 ++++++++++ src/api/event/event.h | 83 +++++++++++++++++++ src/api/screen/screen.cc | 141 +++++++++++++++++++++++++++++++++ src/api/screen/screen.h | 48 +++++++++++ src/api/screen/screen.js | 81 +++++++++++++++++++ src/resources/nw_resources.grd | 1 + 9 files changed, 408 insertions(+) create mode 100644 src/api/event/event.cc create mode 100644 src/api/event/event.h create mode 100644 src/api/screen/screen.cc create mode 100644 src/api/screen/screen.h create mode 100644 src/api/screen/screen.js diff --git a/nw.gypi b/nw.gypi index 4fe4ec9e5c..9ac1983949 100644 --- a/nw.gypi +++ b/nw.gypi @@ -142,6 +142,10 @@ 'src/api/dispatcher_bindings_mac.mm', 'src/api/dispatcher_host.cc', 'src/api/dispatcher_host.h', + 'src/api/event/event.h', + 'src/api/event/event.cc', + 'src/api/screen/screen.h', + 'src/api/screen/screen.cc', 'src/api/window_bindings.cc', 'src/api/window_bindings.h', 'src/api/menu/menu.cc', diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index c68a26fef9..3ec58b2889 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -216,6 +216,8 @@ DispatcherBindings::RequireNwGui(const v8::FunctionCallbackInfo& args NwGui, global, v8::String::NewFromUtf8(isolate, "app.js"), IDR_NW_API_APP_JS); RequireFromResource(args.This(), NwGui, global, v8::String::NewFromUtf8(isolate, "shortcut.js"), IDR_NW_API_SHORTCUT_JS); + RequireFromResource(args.This(), + NwGui, global, v8::String::NewFromUtf8(isolate, "screen.js"), IDR_NW_API_SCREEN_JS); g_context->Exit(); args.GetReturnValue().Set(handle_scope.Escape(NwGui)); diff --git a/src/api/dispatcher_host.cc b/src/api/dispatcher_host.cc index 350d4899ef..262a962f5e 100644 --- a/src/api/dispatcher_host.cc +++ b/src/api/dispatcher_host.cc @@ -29,8 +29,10 @@ #include "content/nw/src/api/app/app.h" #include "content/nw/src/api/base/base.h" #include "content/nw/src/api/clipboard/clipboard.h" +#include "content/nw/src/api/event/event.h" #include "content/nw/src/api/menu/menu.h" #include "content/nw/src/api/menuitem/menuitem.h" +#include "content/nw/src/api/screen/screen.h" #include "content/nw/src/api/shell/shell.h" #include "content/nw/src/api/shortcut/shortcut.h" #include "content/nw/src/api/tray/tray.h" @@ -157,6 +159,8 @@ void DispatcherHost::OnAllocateObject(int object_id, objects_registry_.AddWithID(new Window(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); } else if (type == "Shortcut") { objects_registry_.AddWithID(new Shortcut(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); + } else if (type == "Screen") { + objects_registry_.AddWithID(new EventListener(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); } else { LOG(ERROR) << "Allocate an object of unknown type: " << type; objects_registry_.AddWithID(new Base(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); @@ -247,6 +251,9 @@ void DispatcherHost::OnCallStaticMethodSync( content::Shell::FromRenderViewHost(render_view_host()); nwapi::App::Call(shell, method, arguments, result); return; + } else if (type == "Screen") { + nwapi::Screen::Call(this, method, arguments, result); + return; } NOTREACHED() << "Calling unknown method " << method << " of class " << type; diff --git a/src/api/event/event.cc b/src/api/event/event.cc new file mode 100644 index 0000000000..b42649314e --- /dev/null +++ b/src/api/event/event.cc @@ -0,0 +1,41 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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/event/event.h" +#include "base/values.h" +#include "content/nw/src/api/dispatcher_host.h" +#include "ui/gfx/screen.h" + + +namespace nwapi { + +EventListener::EventListener(int id, + const base::WeakPtr& dispatcher_host, + const base::DictionaryValue& option) : Base(id, dispatcher_host, option) { + +} + +EventListener::~EventListener() { + for (std::map::iterator i = listerners_.begin(); i != listerners_.end(); i++) { + delete i->second; + } +} + +} // namespace nwapi diff --git a/src/api/event/event.h b/src/api/event/event.h new file mode 100644 index 0000000000..55ce26da94 --- /dev/null +++ b/src/api/event/event.h @@ -0,0 +1,83 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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_API_EVENT_EVENT_H_ +#define CONTENT_NW_SRC_API_EVENT_EVENT_H_ + + +#include "base/basictypes.h" + +#include "content/nw/src/api/base/base.h" +#include "ui/gfx/display_observer.h" + +#include + +namespace nwapi { + +class BaseEvent { + friend class EventListener; + DISALLOW_COPY_AND_ASSIGN(BaseEvent); + +protected: + BaseEvent(){} + virtual ~BaseEvent(){} +}; + +class EventListener : public Base { + std::map listerners_; + +public: + EventListener(int id, + const base::WeakPtr& dispatcher_host, + const base::DictionaryValue& option); + + virtual ~EventListener(); + + static int getUID() { + static int id = 0; + return ++id; + } + + template T* AddListener() { + std::map::iterator i = listerners_.find(T::id); + if (i==listerners_.end()) { + T* listener_object = new T(this); + listerners_[T::id] = listener_object; + return listener_object; + } + return NULL; + } + + template bool RemoveListener() { + std::map::iterator i = listerners_.find(T::id); + if (i!=listerners_.end()) { + delete i->second; + listerners_.erase(i); + return true; + } + return false; + } +private: + DISALLOW_COPY_AND_ASSIGN(EventListener); +}; + +} // namespace nwapi + +#endif //CONTENT_NW_SRC_API_EVENT_EVENT_H_ diff --git a/src/api/screen/screen.cc b/src/api/screen/screen.cc new file mode 100644 index 0000000000..d009dac433 --- /dev/null +++ b/src/api/screen/screen.cc @@ -0,0 +1,141 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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 "base/values.h" +#include "content/nw/src/api/screen/screen.h" +#include "content/nw/src/api/dispatcher_host.h" +#include "content/nw/src/api/event/event.h" +#include "content/nw/src/nw_shell.h" +#include "ui/gfx/display_observer.h" +#include "ui/gfx/screen.h" + +namespace nwapi { +std::string DisplayToJSON(const gfx::Display& display) { + std::stringstream ret; + gfx::Rect rect = display.bounds(); + + ret << "{\"id\":" << display.id(); + + ret << ",\"bounds\":{\"x\":" << rect.x() + << ", \"y\":" << rect.y() + << ", \"width\":" << rect.width() + << ", \"height\":" << rect.height() << "}"; + + rect = display.work_area(); + ret << ",\"work_area\":{\"x\":" << rect.x() + << ", \"y\":" << rect.y() + << ", \"width\":" << rect.width() + << ", \"height\":" << rect.height() << "}"; + + ret << ",\"scaleFactor\":" << display.device_scale_factor(); + ret << ",\"isBuiltIn\":" << (display.IsInternal() ? "true" : "false"); + ret << "}"; + + return ret.str(); +} + +class JavaScriptDisplayObserver : BaseEvent, public gfx::DisplayObserver { + friend class EventListener; + EventListener* object_; + gfx::Screen* screen_; + + // Called when the |display|'s bound has changed. + virtual void OnDisplayBoundsChanged(const gfx::Display& display) OVERRIDE { + base::ListValue arguments; + arguments.AppendString(DisplayToJSON(display)); + object_->dispatcher_host()->SendEvent(object_, "displayBoundsChanged", arguments); + } + + // Called when |new_display| has been added. + virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE { + base::ListValue arguments; + arguments.AppendString(DisplayToJSON(new_display)); + object_->dispatcher_host()->SendEvent(object_, "displayAdded", arguments); + + } + + // Called when |old_display| has been removed. + virtual void OnDisplayRemoved(const gfx::Display& old_display) OVERRIDE { + base::ListValue arguments; + arguments.AppendString(DisplayToJSON(old_display)); + object_->dispatcher_host()->SendEvent(object_, "displayRemoved", arguments); + } + + static const int id; + + JavaScriptDisplayObserver(EventListener* object) : object_(object), screen_(NULL){ + } + + virtual ~JavaScriptDisplayObserver() { + if(screen_) + screen_->RemoveObserver(this); + } + +public: + void setScreen(gfx::Screen* screen) { + if(screen_) screen_->RemoveObserver(this); + screen_ = screen; + if(screen_) screen_->AddObserver(this); + } +}; + +const int JavaScriptDisplayObserver::id = EventListener::getUID(); + + // static +void Screen::Call(DispatcherHost* dispatcher_host, + const std::string& method, + const base::ListValue& arguments, + base::ListValue* result) { + + if (method == "GetScreens") { + std::stringstream ret; + const std::vector& displays = gfx::Screen::GetNativeScreen()->GetAllDisplays(); + + if (displays.size() == 0) { + result->AppendString("{}"); + return; + } + + for (size_t i=0; iAppendString("["+ret.str()+"]"); + return; + } else if (method == "AddScreenChangeCallback") { + int object_id = 0; + arguments.GetInteger(0, &object_id); + EventListener* event_listener = dispatcher_host->GetApiObject(object_id); + JavaScriptDisplayObserver* listener = event_listener->AddListener(); + if (listener) listener->setScreen(gfx::Screen::GetNativeScreen()); + result->AppendBoolean(listener != NULL); + return; + } else if (method == "RemoveScreenChangeCallback") { + int object_id = 0; + arguments.GetInteger(0, &object_id); + EventListener* event_listener = dispatcher_host->GetApiObject(object_id); + bool res = event_listener->RemoveListener(); + result->AppendBoolean(res); + return; + } + +} + +} // namespace nwapi diff --git a/src/api/screen/screen.h b/src/api/screen/screen.h new file mode 100644 index 0000000000..9499a8a7f5 --- /dev/null +++ b/src/api/screen/screen.h @@ -0,0 +1,48 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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_API_SCREEN_SCREEN_H_ +#define CONTENT_NW_SRC_API_SCREEN_SCREEN_H_ + +#include "base/basictypes.h" + +#include + +namespace nwapi { + +class DispatcherHost; +class Screen { +public: + + static void Call(DispatcherHost* dispatcher_host, + const std::string& method, + const base::ListValue& arguments, + base::ListValue* result); + +private: + Screen(); + DISALLOW_COPY_AND_ASSIGN(Screen); +}; + +} // namespace nwapi + + + +#endif //CONTENT_NW_SRC_API_SCREEN_SCREEN_H_ diff --git a/src/api/screen/screen.js b/src/api/screen/screen.js new file mode 100644 index 0000000000..e914fc24df --- /dev/null +++ b/src/api/screen/screen.js @@ -0,0 +1,81 @@ +// Copyright (c) 2012 Intel Corp +// Copyright (c) 2014 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. + +var screenInstance = null; + +function Screen() { + nw.allocateObject(this, {}); + this._numListener = 0; +} +require('util').inherits(Screen, exports.Base); + +// Override the addListener method. +Screen.prototype.on = Screen.prototype.addListener = function(ev, callback) { + if ( ev != "displayBoundsChanged" && ev != "displayAdded" && ev != "displayRemoved" ) + throw new String('only following event can be listened: displayBoundsChanged, displayAdded, displayRemoved'); + + var onRemoveListener = function (type, listener) { + if (this._numListener > 0) { + this._numListener--; + if (this._numListener == 0) { + process.EventEmitter.prototype.removeListener.apply(this, ["removeListener", onRemoveListener]); + nw.callStaticMethodSync('Screen', 'RemoveScreenChangeCallback', [ this.id ]); + } + } + }; + + if(this._numListener == 0) { + if (nw.callStaticMethodSync('Screen', 'AddScreenChangeCallback', [ this.id ]) == false ) { + throw new String('nw.callStaticMethodSync(Screen, AddScreenChangeCallback) fails'); + return; + } + process.EventEmitter.prototype.addListener.apply(this, ["removeListener", onRemoveListener]); + } + + // Call parent. + process.EventEmitter.prototype.addListener.apply(this, arguments); + this._numListener++; +} + +// Route events. +Screen.prototype.handleEvent = function(ev) { + arguments[1] = JSON.parse(arguments[1]); + // Call parent. + this.emit.apply(this, arguments); +} + +Screen.prototype.__defineGetter__('screens', function() { + return JSON.parse(nw.callStaticMethodSync('Screen', 'GetScreens', [ ])); +}); + + +// ======== Screen functions End ======== + +// Store App object in node's context. +exports.Screen = { +Init: function() { + if (screenInstance == null) { + screenInstance = new Screen(); + } + exports.Screen = screenInstance; + return screenInstance; +} +}; + diff --git a/src/resources/nw_resources.grd b/src/resources/nw_resources.grd index 98f18da3d4..30f4dff82d 100644 --- a/src/resources/nw_resources.grd +++ b/src/resources/nw_resources.grd @@ -49,6 +49,7 @@ + From f61a0064c8f9700e8eb0b66bb4160719d1ffe35e Mon Sep 17 00:00:00 2001 From: Roger Date: Sat, 9 Aug 2014 13:55:21 +0800 Subject: [PATCH 150/492] update Chromium to 35.0.1916.157 --- src/nw_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nw_version.h b/src/nw_version.h index 0292ab9174..93d5f984a3 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -43,7 +43,7 @@ #define NW_VERSION "v" NW_VERSION_STRING -#define CHROME_VERSION "35.0.1916.113" +#define CHROME_VERSION "35.0.1916.157" #define NW_VERSION_AT_LEAST(major, minor, patch) \ (( (major) < NW_MAJOR_VERSION) \ From e4a86aeb74cb8541efe9368ac8a5ca3fd3fe4446 Mon Sep 17 00:00:00 2001 From: gitchs Date: Mon, 11 Aug 2014 15:09:59 +0800 Subject: [PATCH 151/492] Fix shift modifier not working for window menu --- src/api/menuitem/menuitem_gtk.cc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/api/menuitem/menuitem_gtk.cc b/src/api/menuitem/menuitem_gtk.cc index f01651273f..b9b4f39e7f 100644 --- a/src/api/menuitem/menuitem_gtk.cc +++ b/src/api/menuitem/menuitem_gtk.cc @@ -82,6 +82,11 @@ void MenuItem::Create(const base::DictionaryValue& option) { if (modifiers.find("meta") != std::string::npos){ modifiers_mask = GdkModifierType(modifiers_mask|GDK_META_MASK); } + + if (modifiers.find("shift") != std::string::npos){ + modifiers_mask = GdkModifierType(modifiers_mask|GDK_SHIFT_MASK); + } + } keyval = gdk_keyval_from_name(key.c_str()); From 11443800e774d92e74e7bc8c7ccdc8ed30fb8821 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 12 Aug 2014 09:20:57 +0800 Subject: [PATCH 152/492] bump version to 0.10.2 --- src/mac/app-Info.plist | 2 +- src/nw_version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mac/app-Info.plist b/src/mac/app-Info.plist index 726cee5584..48192fb35e 100644 --- a/src/mac/app-Info.plist +++ b/src/mac/app-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.10.1 + 0.10.2 NSPrincipalClass NSApplication LSMinimumSystemVersion diff --git a/src/nw_version.h b/src/nw_version.h index 93d5f984a3..981ad861f4 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -23,7 +23,7 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 10 -#define NW_PATCH_VERSION 1 +#define NW_PATCH_VERSION 2 #define NW_VERSION_IS_RELEASE 1 #ifndef NW_STRINGIFY From 6a0bdad9439569bd5dc16010e936fbe9f899127e Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 12 Aug 2014 09:45:03 +0800 Subject: [PATCH 153/492] ship the locales folder to fix l10n Fix #2031 --- tools/package_binaries.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 9ec6268125..1d535a59b0 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -117,6 +117,7 @@ def generate_target_nw(platform_name, arch, version): 'nwsnapshot', 'nw', 'icudtl.dat', + 'locales', ] elif platform_name == 'win': target['input'] = [ @@ -126,6 +127,7 @@ def generate_target_nw(platform_name, arch, version): 'libGLESv2.dll', 'nw.exe', 'nw.pak', + 'locales', 'nwsnapshot.exe', 'credits.html', ] From a0c5b45bb5aa978502ba1f064eb41b1fe33d9b7d Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 12 Aug 2014 14:56:00 +0800 Subject: [PATCH 154/492] [README] update for v0.10.2 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 180378a55d..d0c649fe51 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ It's created and developed in the Intel Open Source Technology Center. * Available on Linux, Mac OS X and Windows ## Downloads -* **v0.10.1:** (Jul 30, 2014, based off of Node v0.11.13, Chromium 35.0.1916.113): [release notes](https://groups.google.com/d/msg/node-webkit/7h2lIKrlqAk/weeURSPhfMgJ) +* **v0.10.2:** (Aug 12, 2014, based off of Node v0.11.13, Chromium 35.0.1916.157): [release notes](https://groups.google.com/d/msg/node-webkit/JWp8ViL6_zc/ruYpmUWxhb4J) - * Linux: [32bit](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-linux-x64.tar.gz) - * Windows: [win32](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-win-ia32.zip) - * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.10.1/node-webkit-v0.10.1-osx-x64.zip) + * Linux: [32bit](http://dl.node-webkit.org/v0.10.2/node-webkit-v0.10.2-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.2/node-webkit-v0.10.2-linux-x64.tar.gz) + * Windows: [win32](http://dl.node-webkit.org/v0.10.2/node-webkit-v0.10.2-win-ia32.zip) + * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.10.2/node-webkit-v0.10.2-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.10.2/node-webkit-v0.10.2-osx-x64.zip) * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From 5e94e1f22b6260b836aea96e019bf508ce347b19 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 25 Aug 2014 16:39:20 +0800 Subject: [PATCH 155/492] make nw run as node Fix #213 --- src/shell_main_delegate.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/shell_main_delegate.cc b/src/shell_main_delegate.cc index eab8324cb7..2378273cad 100644 --- a/src/shell_main_delegate.cc +++ b/src/shell_main_delegate.cc @@ -39,7 +39,9 @@ #include "content/nw/src/shell_browser_main.h" #include "content/nw/src/shell_content_browser_client.h" #include "net/cookies/cookie_monster.h" +#include "third_party/node/src/node_webkit.h" #include "third_party/node/src/node_version.h" +#include "third_party/zlib/google/zip_reader.h" #include "ui/base/l10n/l10n_util.h" #if defined(OS_MACOSX) #include "ui/base/l10n/l10n_util_mac.h" @@ -124,6 +126,18 @@ ShellMainDelegate::~ShellMainDelegate() { } bool ShellMainDelegate::BasicStartupComplete(int* exit_code) { + CommandLine* command_line = CommandLine::ForCurrentProcess(); + const CommandLine::StringVector& args = command_line->GetArgs(); + if (args.size() > 0) { + zip::ZipReader reader; + FilePath fp(args[0]); + if (!command_line->HasSwitch(switches::kProcessType) && + PathExists(fp) && !DirectoryExists(fp) && !reader.Open(fp)) { + *exit_code = node::Start(command_line->argc0(), command_line->argv0()); + return true; + } + } + #if defined(OS_WIN) // Enable trace control and transport through event tracing for Windows. logging::LogEventProvider::Initialize(kContentShellProviderName); From 9a78a03dce9903bdbe3b06cea6e77793ea7bd2be Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 31 Aug 2014 21:05:32 +0800 Subject: [PATCH 156/492] bump version to 0.10.3 --- src/mac/app-Info.plist | 2 +- src/nw_version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mac/app-Info.plist b/src/mac/app-Info.plist index 48192fb35e..fd77d91851 100644 --- a/src/mac/app-Info.plist +++ b/src/mac/app-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.10.2 + 0.10.3 NSPrincipalClass NSApplication LSMinimumSystemVersion diff --git a/src/nw_version.h b/src/nw_version.h index 981ad861f4..885848f15e 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -23,7 +23,7 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 10 -#define NW_PATCH_VERSION 2 +#define NW_PATCH_VERSION 3 #define NW_VERSION_IS_RELEASE 1 #ifndef NW_STRINGIFY From 01e3b03da4e8e27c0a0725976efbb3a40cc35ecf Mon Sep 17 00:00:00 2001 From: Cong Liu Date: Sun, 31 Aug 2014 22:03:32 +0800 Subject: [PATCH 157/492] Fix #2167 on Windows --- src/renderer/shell_content_renderer_client.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index 3e2eb1bbd0..b7b47221c2 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -273,7 +273,7 @@ void ShellContentRendererClient::SetupNodeUtil( "if (!process.mainModule.filename || process.mainModule.filename === 'blank') {" " var root = '" + root_path + "';" #if defined(OS_WIN) - "process.mainModule.filename = decodeURIComponent(window.location.pathname.substr(1));" + "process.mainModule.filename = decodeURIComponent(window.location.pathname === 'blank' ? 'blank': window.location.pathname.substr(1));" #else "process.mainModule.filename = decodeURIComponent(window.location.pathname);" #endif @@ -282,7 +282,7 @@ void ShellContentRendererClient::SetupNodeUtil( "process.mainModule.paths = global.require('module')._nodeModulePaths(process.cwd());" "process.mainModule.loaded = true;" "}").c_str()), - v8::String::NewFromUtf8(isolate, "process_main")); + v8::String::NewFromUtf8(isolate, "process_main")); CHECK(*script); script->Run(); } From 62da87d61aed11e8384335f5c45f869d9a5632f5 Mon Sep 17 00:00:00 2001 From: Cong Liu Date: Mon, 1 Sep 2014 10:41:38 +0800 Subject: [PATCH 158/492] Updated AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index fc3e010f66..5e0acc2e17 100644 --- a/AUTHORS +++ b/AUTHORS @@ -29,3 +29,4 @@ Jefry Tedjokusumo Wu Haojian Bas Wegh Joachim Bauch +Cong Liu From 8cb53f3b013aa0b3201b96eeeb97acc8cdfe5cb9 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 1 Sep 2014 10:57:57 +0800 Subject: [PATCH 159/492] fix build warnings in clang --- src/net/app_protocol_handler.cc | 15 --------------- src/nw_package.cc | 5 ----- src/shell_devtools_frontend.cc | 22 ---------------------- 3 files changed, 42 deletions(-) diff --git a/src/net/app_protocol_handler.cc b/src/net/app_protocol_handler.cc index 2b61c4be16..ab0186e2ab 100644 --- a/src/net/app_protocol_handler.cc +++ b/src/net/app_protocol_handler.cc @@ -65,12 +65,6 @@ net::HttpResponseHeaders* BuildHttpHeaders( return new net::HttpResponseHeaders(raw_headers); } -void ReadMimeTypeFromFile(const base::FilePath& filename, - std::string* mime_type, - bool* result) { - *result = net::GetMimeTypeFromFile(filename, mime_type); -} - base::Time GetFileLastModifiedTime(const base::FilePath& filename) { if (base::PathExists(filename)) { base::File::Info info; @@ -80,15 +74,6 @@ base::Time GetFileLastModifiedTime(const base::FilePath& filename) { return base::Time(); } -base::Time GetFileCreationTime(const base::FilePath& filename) { - if (base::PathExists(filename)) { - base::File::Info info; - if (base::GetFileInfo(filename, &info)) - return info.creation_time; - } - return base::Time(); -} - void ReadResourceFilePathAndLastModifiedTime( const base::FilePath& file_path, base::Time* last_modified_time) { diff --git a/src/nw_package.cc b/src/nw_package.cc index 537ce0df7c..82c814902f 100644 --- a/src/nw_package.cc +++ b/src/nw_package.cc @@ -120,11 +120,6 @@ void RelativePathToURI(FilePath root, base::DictionaryValue* manifest) { std::string("file://") + main_path.AsUTF8Unsafe()); } -std::wstring ASCIIToWide(const std::string& ascii) { - DCHECK(IsStringASCII(ascii)) << ascii; - return std::wstring(ascii.begin(), ascii.end()); -} - } // namespace Package::Package() diff --git a/src/shell_devtools_frontend.cc b/src/shell_devtools_frontend.cc index 6d43077ac0..21517511f7 100644 --- a/src/shell_devtools_frontend.cc +++ b/src/shell_devtools_frontend.cc @@ -21,28 +21,6 @@ namespace content { -namespace { - -// DevTools frontend path for inspector LayoutTests. -GURL GetDevToolsPathAsURL() { - base::FilePath dir_exe; - if (!PathService::Get(base::DIR_EXE, &dir_exe)) { - NOTREACHED(); - return GURL(); - } -#if defined(OS_MACOSX) - // On Mac, the executable is in - // out/Release/Content Shell.app/Contents/MacOS/Content Shell. - // We need to go up 3 directories to get to out/Release. - dir_exe = dir_exe.AppendASCII("../../.."); -#endif - base::FilePath dev_tools_path = dir_exe.AppendASCII( - "resources/inspector/devtools.html"); - return net::FilePathToFileURL(dev_tools_path); -} - -} // namespace - #if 0 // static ShellDevToolsFrontend* ShellDevToolsFrontend::Show( From 4bcc82669dcabd04a94a4a4d06e5c0c3d272be6e Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 1 Sep 2014 13:38:28 +0800 Subject: [PATCH 160/492] [CHANGELOG] update for 0.10.3 and 0.10.2 --- CHANGELOG.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6ee35ef8c4..4b92c4f1eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,22 @@ +0.10.3 / 09-01-2014 +=================== +- Fix: child_process.fork() (#213) by making nw executable run as node +- Fix: [OSX] process.nextTick() blocked in some cases (#2170) + +0.10.2 / 08-12-2014 +=================== +- Support screen geometry API (#2178 Thanks to Jefry Tedjokusumo +- Support progress bar (#2175 Thanks to Jefry Tedjokusumo) +- Window.requestAttention() now accepts an integer parameter [4] +- Fix: JS source code snapshot is now working +- Fix: Linux: shift modifier not working for window menu +- Fix: Win: window.navigator.language is empty +- Fix: require works in wrong path in new-instance window (#2167) +- Fix: support for screencapture media requests (Thanks to Joachim Bauch) +- Fix: Win: cursor not loaded in some cases (#2150, #2152) +- Fix: crash on some cases (#2155, #2148) +- Fix: Large combo-box does not scroll properly and values overlaps on each other (#2161; upstream #357480) + 0.10.1 / 07-30-2014 =================== - Support Desktop notification (#27 Thanks to Jefry Tedjokusumo) From 14e7cb2359cc78037657719a6b612077bc7170d3 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 1 Sep 2014 13:49:57 +0800 Subject: [PATCH 161/492] [README] update for 0.10.3 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index d0c649fe51..99ef0f8f0d 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ It's created and developed in the Intel Open Source Technology Center. * Available on Linux, Mac OS X and Windows ## Downloads -* **v0.10.2:** (Aug 12, 2014, based off of Node v0.11.13, Chromium 35.0.1916.157): [release notes](https://groups.google.com/d/msg/node-webkit/JWp8ViL6_zc/ruYpmUWxhb4J) +* **v0.10.3:** (Sep 1, 2014, based off of Node v0.11.13, Chromium 35.0.1916.157): [release notes](https://groups.google.com/d/msg/node-webkit/UIh7RMNk9pQ/j5VjvIMv3icJ) - * Linux: [32bit](http://dl.node-webkit.org/v0.10.2/node-webkit-v0.10.2-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.2/node-webkit-v0.10.2-linux-x64.tar.gz) - * Windows: [win32](http://dl.node-webkit.org/v0.10.2/node-webkit-v0.10.2-win-ia32.zip) - * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.10.2/node-webkit-v0.10.2-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.10.2/node-webkit-v0.10.2-osx-x64.zip) + * Linux: [32bit](http://dl.node-webkit.org/v0.10.3/node-webkit-v0.10.3-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.3/node-webkit-v0.10.3-linux-x64.tar.gz) + * Windows: [win32](http://dl.node-webkit.org/v0.10.3/node-webkit-v0.10.3-win-ia32.zip) + * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.10.3/node-webkit-v0.10.3-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.10.3/node-webkit-v0.10.3-osx-x64.zip) * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From 222a43a4b6661df036329a14c44d4d066c9924cd Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 1 Sep 2014 13:55:30 +0800 Subject: [PATCH 162/492] [WIN] fix build error --- src/nw_package.cc | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/nw_package.cc b/src/nw_package.cc index 82c814902f..76a88eede8 100644 --- a/src/nw_package.cc +++ b/src/nw_package.cc @@ -120,6 +120,13 @@ void RelativePathToURI(FilePath root, base::DictionaryValue* manifest) { std::string("file://") + main_path.AsUTF8Unsafe()); } +#if defined(OS_WIN) +std::wstring ASCIIToWide(const std::string& ascii) { + DCHECK(IsStringASCII(ascii)) << ascii; + return std::wstring(ascii.begin(), ascii.end()); +} +#endif + } // namespace Package::Package() From 0db423c39b3d600a54dcb3b5e846a3c491fe5d31 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 1 Sep 2014 13:55:38 +0800 Subject: [PATCH 163/492] remove unused BRANDING file --- BRANDING | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 BRANDING diff --git a/BRANDING b/BRANDING deleted file mode 100644 index 4a97f5989f..0000000000 --- a/BRANDING +++ /dev/null @@ -1,7 +0,0 @@ -COMPANY_FULLNAME=node-webkit.org -COMPANY_SHORTNAME=node-webkit.org -PRODUCT_FULLNAME=node-webkit -PRODUCT_SHORTNAME=node-webkit -PRODUCT_INSTALLER_FULLNAME=Chromium Installer -PRODUCT_INSTALLER_SHORTNAME=Chromium Installer -COPYRIGHT=Copyright 2013 The Chromium Authors. All rights reserved. From 09736d392a99c1b526f6f3a9451a10ac0c699d42 Mon Sep 17 00:00:00 2001 From: Eric Newport Date: Tue, 2 Sep 2014 03:55:37 -0700 Subject: [PATCH 164/492] Updating AUTHORS This is by @rogerwang's request: https://github.com/rogerwang/node-webkit/pull/2102#issuecomment-50300037 --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 5e0acc2e17..8acd9abe90 100644 --- a/AUTHORS +++ b/AUTHORS @@ -30,3 +30,4 @@ Wu Haojian Bas Wegh Joachim Bauch Cong Liu +Eric Newport From 2a27c1f52d9584cdea4b26f248a59bfb888cbd6b Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 2 Sep 2014 22:25:49 +0800 Subject: [PATCH 165/492] remove unused files --- src/common/gpu_internals.cc | 446 ------------------------------------ src/common/gpu_internals.h | 27 --- 2 files changed, 473 deletions(-) delete mode 100644 src/common/gpu_internals.cc delete mode 100644 src/common/gpu_internals.h diff --git a/src/common/gpu_internals.cc b/src/common/gpu_internals.cc deleted file mode 100644 index bf67a32d91..0000000000 --- a/src/common/gpu_internals.cc +++ /dev/null @@ -1,446 +0,0 @@ -// 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/common/gpu_internals.h" - -#include "base/callback.h" -#include "base/command_line.h" -#include "base/logging.h" -#include "base/memory/scoped_ptr.h" -#include "base/string_number_conversions.h" -#include "base/stringprintf.h" -#include "base/sys_info.h" -#include "base/values.h" -#include "cc/switches.h" -#include "content/public/browser/compositor_util.h" -#include "content/public/browser/gpu_data_manager.h" -#include "content/public/browser/gpu_data_manager_observer.h" -#include "content/public/common/content_switches.h" -#include "content/public/common/gpu_info.h" -#include "third_party/angle/src/common/version.h" - -using content::GpuDataManager; -using content::GpuFeatureType; - -namespace { - -struct GpuFeatureInfo { - std::string name; - uint32 blocked; - bool disabled; - std::string disabled_description; - bool fallback_to_software; -}; - -DictionaryValue* NewDescriptionValuePair(const std::string& desc, - const std::string& value) { - DictionaryValue* dict = new DictionaryValue(); - dict->SetString("description", desc); - dict->SetString("value", value); - return dict; -} - -DictionaryValue* NewDescriptionValuePair(const std::string& desc, - Value* value) { - DictionaryValue* dict = new DictionaryValue(); - dict->SetString("description", desc); - dict->Set("value", value); - return dict; -} - -Value* NewStatusValue(const char* name, const char* status) { - DictionaryValue* value = new DictionaryValue(); - value->SetString("name", name); - value->SetString("status", status); - return value; -} - -#if defined(OS_WIN) -// Output DxDiagNode tree as nested array of {description,value} pairs -ListValue* DxDiagNodeToList(const content::DxDiagNode& node) { - ListValue* list = new ListValue(); - for (std::map::const_iterator it = - node.values.begin(); - it != node.values.end(); - ++it) { - list->Append(NewDescriptionValuePair(it->first, it->second)); - } - - for (std::map::const_iterator it = - node.children.begin(); - it != node.children.end(); - ++it) { - ListValue* sublist = DxDiagNodeToList(it->second); - list->Append(NewDescriptionValuePair(it->first, sublist)); - } - return list; -} -#endif - -std::string GPUDeviceToString(const content::GPUInfo::GPUDevice& gpu) { - std::string vendor = base::StringPrintf("0x%04x", gpu.vendor_id); - if (!gpu.vendor_string.empty()) - vendor += " [" + gpu.vendor_string + "]"; - std::string device = base::StringPrintf("0x%04x", gpu.device_id); - if (!gpu.device_string.empty()) - device += " [" + gpu.device_string + "]"; - return base::StringPrintf( - "VENDOR = %s, DEVICE= %s", vendor.c_str(), device.c_str()); -} - -DictionaryValue* GpuInfoAsDictionaryValue() { - content::GPUInfo gpu_info = GpuDataManager::GetInstance()->GetGPUInfo(); - ListValue* basic_info = new ListValue(); - basic_info->Append(NewDescriptionValuePair( - "Initialization time", - base::Int64ToString(gpu_info.initialization_time.InMilliseconds()))); - basic_info->Append(NewDescriptionValuePair( - "Sandboxed", - Value::CreateBooleanValue(gpu_info.sandboxed))); - basic_info->Append(NewDescriptionValuePair( - "GPU0", GPUDeviceToString(gpu_info.gpu))); - for (size_t i = 0; i < gpu_info.secondary_gpus.size(); ++i) { - basic_info->Append(NewDescriptionValuePair( - base::StringPrintf("GPU%d", static_cast(i + 1)), - GPUDeviceToString(gpu_info.secondary_gpus[i]))); - } - basic_info->Append(NewDescriptionValuePair( - "Optimus", Value::CreateBooleanValue(gpu_info.optimus))); - basic_info->Append(NewDescriptionValuePair( - "AMD switchable", Value::CreateBooleanValue(gpu_info.amd_switchable))); - basic_info->Append(NewDescriptionValuePair("Driver vendor", - gpu_info.driver_vendor)); - basic_info->Append(NewDescriptionValuePair("Driver version", - gpu_info.driver_version)); - basic_info->Append(NewDescriptionValuePair("Driver date", - gpu_info.driver_date)); - basic_info->Append(NewDescriptionValuePair("Pixel shader version", - gpu_info.pixel_shader_version)); - basic_info->Append(NewDescriptionValuePair("Vertex shader version", - gpu_info.vertex_shader_version)); - basic_info->Append(NewDescriptionValuePair("Machine model", - gpu_info.machine_model)); - basic_info->Append(NewDescriptionValuePair("GL version", - gpu_info.gl_version)); - basic_info->Append(NewDescriptionValuePair("GL_VENDOR", - gpu_info.gl_vendor)); - basic_info->Append(NewDescriptionValuePair("GL_RENDERER", - gpu_info.gl_renderer)); - basic_info->Append(NewDescriptionValuePair("GL_VERSION", - gpu_info.gl_version_string)); - basic_info->Append(NewDescriptionValuePair("GL_EXTENSIONS", - gpu_info.gl_extensions)); - - DictionaryValue* info = new DictionaryValue(); - info->Set("basic_info", basic_info); - -#if defined(OS_WIN) - ListValue* perf_info = new ListValue(); - perf_info->Append(NewDescriptionValuePair( - "Graphics", - base::StringPrintf("%.1f", gpu_info.performance_stats.graphics))); - perf_info->Append(NewDescriptionValuePair( - "Gaming", - base::StringPrintf("%.1f", gpu_info.performance_stats.gaming))); - perf_info->Append(NewDescriptionValuePair( - "Overall", - base::StringPrintf("%.1f", gpu_info.performance_stats.overall))); - info->Set("performance_info", perf_info); - - Value* dx_info; - if (gpu_info.dx_diagnostics.children.size()) - dx_info = DxDiagNodeToList(gpu_info.dx_diagnostics); - else - dx_info = Value::CreateNullValue(); - info->Set("diagnostics", dx_info); -#endif - - return info; -} - -// Determine if accelerated-2d-canvas is supported, which depends on whether -// lose_context could happen and whether skia is the backend. -bool SupportsAccelerated2dCanvas() { - if (GpuDataManager::GetInstance()->GetGPUInfo().can_lose_context) - return false; -#if defined(USE_SKIA) - return true; -#else - return false; -#endif -} - -Value* GetFeatureStatus() { - const CommandLine& command_line = *CommandLine::ForCurrentProcess(); - bool gpu_access_blocked = !GpuDataManager::GetInstance()->GpuAccessAllowed(); - - uint32 flags = GpuDataManager::GetInstance()->GetBlacklistedFeatures(); - DictionaryValue* status = new DictionaryValue(); - - const GpuFeatureInfo kGpuFeatureInfo[] = { - { - "2d_canvas", - flags & content::GPU_FEATURE_TYPE_ACCELERATED_2D_CANVAS, - command_line.HasSwitch(switches::kDisableAccelerated2dCanvas) || - !SupportsAccelerated2dCanvas(), - "Accelerated 2D canvas is unavailable: either disabled at the command" - " line or not supported by the current system.", - true - }, - { - "compositing", - flags & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING, - command_line.HasSwitch(switches::kDisableAcceleratedCompositing), - "Accelerated compositing has been disabled, either via about:flags or" - " command line. This adversely affects performance of all hardware" - " accelerated features.", - true - }, - { - "3d_css", - flags & (content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING | - content::GPU_FEATURE_TYPE_3D_CSS), - command_line.HasSwitch(switches::kDisableAcceleratedLayers), - "Accelerated layers have been disabled at the command line.", - false - }, - { - "css_animation", - flags & (content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING | - content::GPU_FEATURE_TYPE_3D_CSS), - command_line.HasSwitch(cc::switches::kDisableThreadedAnimation) || - command_line.HasSwitch(switches::kDisableAcceleratedCompositing) || - command_line.HasSwitch(switches::kDisableAcceleratedLayers), - "Accelerated CSS animation has been disabled at the command line.", - true - }, - { - "webgl", - flags & content::GPU_FEATURE_TYPE_WEBGL, -#if defined(OS_ANDROID) - !command_line.HasSwitch(switches::kEnableExperimentalWebGL), -#else - command_line.HasSwitch(switches::kDisableExperimentalWebGL), -#endif - "WebGL has been disabled, either via about:flags or command line.", - false - }, - { - "multisampling", - flags & content::GPU_FEATURE_TYPE_MULTISAMPLING, - command_line.HasSwitch(switches::kDisableGLMultisampling), - "Multisampling has been disabled, either via about:flags or command" - " line.", - false - }, - { - "flash_3d", - flags & content::GPU_FEATURE_TYPE_FLASH3D, - command_line.HasSwitch(switches::kDisableFlash3d), - "Using 3d in flash has been disabled, either via about:flags or" - " command line.", - false - }, - { - "flash_stage3d", - flags & content::GPU_FEATURE_TYPE_FLASH_STAGE3D, - command_line.HasSwitch(switches::kDisableFlashStage3d), - "Using Stage3d in Flash has been disabled, either via about:flags or" - " command line.", - false - }, - { - "texture_sharing", - flags & content::GPU_FEATURE_TYPE_TEXTURE_SHARING, - command_line.HasSwitch(switches::kDisableImageTransportSurface), - "Sharing textures between processes has been disabled, either via" - " about:flags or command line.", - false - }, - { - "video_decode", - flags & content::GPU_FEATURE_TYPE_ACCELERATED_VIDEO_DECODE, - command_line.HasSwitch(switches::kDisableAcceleratedVideoDecode), - "Accelerated video decode has been disabled, either via about:flags" - " or command line.", - true - }, - { - "video", - flags & content::GPU_FEATURE_TYPE_ACCELERATED_VIDEO, - command_line.HasSwitch(switches::kDisableAcceleratedVideo) || - command_line.HasSwitch(switches::kDisableAcceleratedCompositing), - "Accelerated video presentation has been disabled, either via" - " about:flags or command line.", - true - }, - { - "panel_fitting", - flags & content::GPU_FEATURE_TYPE_PANEL_FITTING, -#if defined(OS_CHROMEOS) - command_line.HasSwitch(ash::switches::kAshDisablePanelFitting), -#else - true, -#endif - "Panel fitting is unavailable, either disabled at the command" - " line or not supported by the current system.", - false - } - }; - const size_t kNumFeatures = sizeof(kGpuFeatureInfo) / sizeof(GpuFeatureInfo); - - // Build the feature_status field. - { - ListValue* feature_status_list = new ListValue(); - - for (size_t i = 0; i < kNumFeatures; ++i) { - std::string status; - if (kGpuFeatureInfo[i].disabled) { - status = "disabled"; - if (kGpuFeatureInfo[i].name == "css_animation") { - status += "_software_animated"; - } else { - if (kGpuFeatureInfo[i].fallback_to_software) - status += "_software"; - else - status += "_off"; - } - } else if (GpuDataManager::GetInstance()->ShouldUseSoftwareRendering()) { - status = "unavailable_software"; - } else if (kGpuFeatureInfo[i].blocked || - gpu_access_blocked) { - status = "unavailable"; - if (kGpuFeatureInfo[i].fallback_to_software) - status += "_software"; - else - status += "_off"; - } else { - status = "enabled"; - if (kGpuFeatureInfo[i].name == "webgl" && - (command_line.HasSwitch(switches::kDisableAcceleratedCompositing) || - (flags & content::GPU_FEATURE_TYPE_ACCELERATED_COMPOSITING))) - status += "_readback"; - bool has_thread = content::IsThreadedCompositingEnabled(); - if (kGpuFeatureInfo[i].name == "compositing") { - bool force_compositing = - content::IsForceCompositingModeEnabled(); - if (force_compositing) - status += "_force"; - if (has_thread) - status += "_threaded"; - } - if (kGpuFeatureInfo[i].name == "css_animation") { - if (has_thread) - status = "accelerated_threaded"; - else - status = "accelerated"; - } - } - feature_status_list->Append( - NewStatusValue(kGpuFeatureInfo[i].name.c_str(), status.c_str())); - } - content::GPUInfo gpu_info = GpuDataManager::GetInstance()->GetGPUInfo(); - if (gpu_info.secondary_gpus.size() > 0 || - gpu_info.optimus || gpu_info.amd_switchable) { - std::string gpu_switching; - switch (GpuDataManager::GetInstance()->GetGpuSwitchingOption()) { - case content::GPU_SWITCHING_OPTION_AUTOMATIC: - gpu_switching = "gpu_switching_automatic"; - break; - case content::GPU_SWITCHING_OPTION_FORCE_DISCRETE: - gpu_switching = "gpu_switching_force_discrete"; - break; - case content::GPU_SWITCHING_OPTION_FORCE_INTEGRATED: - gpu_switching = "gpu_switching_force_integrated"; - break; - default: - break; - } - feature_status_list->Append( - NewStatusValue("gpu_switching", gpu_switching.c_str())); - } - status->Set("featureStatus", feature_status_list); - } - - // Build the problems list. - { - ListValue* problem_list = - GpuDataManager::GetInstance()->GetBlacklistReasons(); - - if (gpu_access_blocked) { - DictionaryValue* problem = new DictionaryValue(); - problem->SetString("description", - "GPU process was unable to boot. Access to GPU disallowed."); - problem->Set("crBugs", new ListValue()); - problem->Set("webkitBugs", new ListValue()); - problem_list->Append(problem); - } - - for (size_t i = 0; i < kNumFeatures; ++i) { - if (kGpuFeatureInfo[i].disabled) { - DictionaryValue* problem = new DictionaryValue(); - problem->SetString( - "description", kGpuFeatureInfo[i].disabled_description); - problem->Set("crBugs", new ListValue()); - problem->Set("webkitBugs", new ListValue()); - problem_list->Append(problem); - } - } - - status->Set("problems", problem_list); - } - - return status; -} - -} // namespace - -void PrintGpuInfo() { - // Get GPU Info. - scoped_ptr gpu_info_val( - GpuInfoAsDictionaryValue()); - - // Add in blacklisting features - Value* feature_status = GetFeatureStatus(); - if (feature_status) - gpu_info_val->Set("featureStatus", feature_status); - - LOG(ERROR) << *gpu_info_val; -} - -void PrintClientInfo() { - DictionaryValue* dict = new DictionaryValue(); - - dict->SetString("operating_system", - base::SysInfo::OperatingSystemName() + " " + - base::SysInfo::OperatingSystemVersion()); - dict->SetString("angle_revision", base::UintToString(BUILD_REVISION)); -#if defined(USE_SKIA) - dict->SetString("graphics_backend", "Skia"); -#else - dict->SetString("graphics_backend", "Core Graphics"); -#endif - dict->SetString("blacklist_version", - GpuDataManager::GetInstance()->GetBlacklistVersion()); - - LOG(ERROR) << *dict; - - delete dict; -} diff --git a/src/common/gpu_internals.h b/src/common/gpu_internals.h deleted file mode 100644 index a8a1f27774..0000000000 --- a/src/common/gpu_internals.h +++ /dev/null @@ -1,27 +0,0 @@ -// 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_COMMON_GPU_INTERNALS_H_ -#define CONTENT_NW_SRC_COMMON_GPU_INTERNALS_H_ - -void PrintGpuInfo(); -void PrintClientInfo(); - -#endif // CONTENT_NW_SRC_COMMON_GPU_INTERNALS_H_ From 982168cb824a13dc321533923fc3d09aa646d5e6 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 2 Sep 2014 22:32:17 +0800 Subject: [PATCH 166/492] fix chrome://gpu --- nw.gypi | 1 + 1 file changed, 1 insertion(+) diff --git a/nw.gypi b/nw.gypi index 4c85fc874e..0c661777c7 100644 --- a/nw.gypi +++ b/nw.gypi @@ -612,6 +612,7 @@ '<(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_resources/webui_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/ui/ui_strings/ui_strings_en-US.pak', '<(SHARED_INTERMEDIATE_DIR)/webkit/devtools_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/webkit/blink_resources.pak', From 8292043a67e6c96798aa9f1fa84324870fe371d1 Mon Sep 17 00:00:00 2001 From: Jefry Date: Wed, 3 Sep 2014 09:25:00 +0800 Subject: [PATCH 167/492] [Notification] OSX, disable the default sound --- src/nw_notification_manager_mac.mm | 1 - 1 file changed, 1 deletion(-) diff --git a/src/nw_notification_manager_mac.mm b/src/nw_notification_manager_mac.mm index 251bf72a6a..e56682bd98 100644 --- a/src/nw_notification_manager_mac.mm +++ b/src/nw_notification_manager_mac.mm @@ -132,7 +132,6 @@ -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNoti @"notification_id" :[NSNumber numberWithInt : params.notification_id], }; - [notification setSoundName : @"NSUserNotificationDefaultSoundName"]; [[NSUserNotificationCenter defaultUserNotificationCenter] setDelegate:[NWUserNotificationCenterDelegate defaultNWUserNotificationCenterDelegate]]; From eaa97b083c0b21c0bb04baa8bb33eebb09ef6ade Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 5 Sep 2014 09:59:47 +0800 Subject: [PATCH 168/492] [OSX] Fix #2294: disable File Quarantine --- src/mac/app-Info.plist | 2 +- src/mac/helper-Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mac/app-Info.plist b/src/mac/app-Info.plist index fd77d91851..33da6da2d2 100644 --- a/src/mac/app-Info.plist +++ b/src/mac/app-Info.plist @@ -25,7 +25,7 @@ LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET}.0 LSFileQuarantineEnabled - + NSSupportsAutomaticGraphicsSwitching CFBundleDocumentTypes diff --git a/src/mac/helper-Info.plist b/src/mac/helper-Info.plist index a9e9ee3b23..9b9219e655 100644 --- a/src/mac/helper-Info.plist +++ b/src/mac/helper-Info.plist @@ -19,7 +19,7 @@ CFBundleSignature ???? LSFileQuarantineEnabled - + LSMinimumSystemVersion ${MACOSX_DEPLOYMENT_TARGET}.0 LSUIElement From 0eebc7c11f3fd656d5a0591bd5fb1a0648b7142c Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 5 Sep 2014 10:02:04 +0800 Subject: [PATCH 169/492] bump version to 0.10.4 --- src/mac/app-Info.plist | 2 +- src/nw_version.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/mac/app-Info.plist b/src/mac/app-Info.plist index 33da6da2d2..a1ceef8519 100644 --- a/src/mac/app-Info.plist +++ b/src/mac/app-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.10.3 + 0.10.4 NSPrincipalClass NSApplication LSMinimumSystemVersion diff --git a/src/nw_version.h b/src/nw_version.h index 885848f15e..e5477f4142 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -23,7 +23,7 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 10 -#define NW_PATCH_VERSION 3 +#define NW_PATCH_VERSION 4 #define NW_VERSION_IS_RELEASE 1 #ifndef NW_STRINGIFY From 4f50956aee9501a2a81dbcfe530ee26541d53d4e Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 5 Sep 2014 12:56:12 +0800 Subject: [PATCH 170/492] [README] update for 0.10.4 --- CHANGELOG.md | 5 +++++ README.md | 8 ++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b92c4f1eb..461e252829 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,8 @@ +0.10.4 / 09-05-2014 +=================== +- Fix: [WIN] child_process.fork() by making nw executable run as node +- Fix: [WIN] stalling for seconds under threaded composition on some hardware (#1991) + 0.10.3 / 09-01-2014 =================== - Fix: child_process.fork() (#213) by making nw executable run as node diff --git a/README.md b/README.md index 99ef0f8f0d..675e553291 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ It's created and developed in the Intel Open Source Technology Center. * Available on Linux, Mac OS X and Windows ## Downloads -* **v0.10.3:** (Sep 1, 2014, based off of Node v0.11.13, Chromium 35.0.1916.157): [release notes](https://groups.google.com/d/msg/node-webkit/UIh7RMNk9pQ/j5VjvIMv3icJ) +* **v0.10.4:** (Sep 5, 2014, based off of Node v0.11.13, Chromium 35.0.1916.157): [release notes](https://groups.google.com/d/msg/node-webkit/UfjTXuZzMlo/Lqk72r1Ps6kJ) - * Linux: [32bit](http://dl.node-webkit.org/v0.10.3/node-webkit-v0.10.3-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.3/node-webkit-v0.10.3-linux-x64.tar.gz) - * Windows: [win32](http://dl.node-webkit.org/v0.10.3/node-webkit-v0.10.3-win-ia32.zip) - * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.10.3/node-webkit-v0.10.3-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.10.3/node-webkit-v0.10.3-osx-x64.zip) + * Linux: [32bit](http://dl.node-webkit.org/v0.10.4/node-webkit-v0.10.4-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.4/node-webkit-v0.10.4-linux-x64.tar.gz) + * Windows: [win32](http://dl.node-webkit.org/v0.10.4/node-webkit-v0.10.4-win-ia32.zip) + * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.10.4/node-webkit-v0.10.4-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.10.4/node-webkit-v0.10.4-osx-x64.zip) * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From 9b75ea40e9cbbadd0a283a176fe0acc1e49ed046 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 5 Sep 2014 12:56:53 +0800 Subject: [PATCH 171/492] bump version to v0.10.5-pre --- src/mac/app-Info.plist | 2 +- src/nw_version.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mac/app-Info.plist b/src/mac/app-Info.plist index a1ceef8519..e8b855f370 100644 --- a/src/mac/app-Info.plist +++ b/src/mac/app-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.10.4 + 0.10.5 NSPrincipalClass NSApplication LSMinimumSystemVersion diff --git a/src/nw_version.h b/src/nw_version.h index e5477f4142..1abe7346b2 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -23,8 +23,8 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 10 -#define NW_PATCH_VERSION 4 -#define NW_VERSION_IS_RELEASE 1 +#define NW_PATCH_VERSION 5 +#define NW_VERSION_IS_RELEASE 0 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) From 4beeddfaeb9461a718a5dd60b60089a70dd9712c Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 5 Sep 2014 13:08:24 +0800 Subject: [PATCH 172/492] fix CHANGELOG --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 461e252829..f81c76bdfd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,9 @@ =================== - Fix: [WIN] child_process.fork() by making nw executable run as node - Fix: [WIN] stalling for seconds under threaded composition on some hardware (#1991) +- Fix: [OSX] disable File Quarantine (#2294) +- Fix: [OSX] disable sound for notification +- support 'chrome://gpu' diagnosic page 0.10.3 / 09-01-2014 =================== From e6908144218758c88a7f918e2d80344d756e32ab Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 8 Sep 2014 11:59:53 +0200 Subject: [PATCH 173/492] Initialize Package earlier to evaluate commandline args earlier (fixes #1743). On package initialization, flags from "chromium-args" are added to the Chromium commandline. Previously, the Package object was initialized in the "PreMainMessageLoopRun" step. As the GPU flags are already evaluated in the "BrowserThreadsStarted" step (which is before that), this was too late for flags like "--ignore-gpu-blacklist". --- src/shell_browser_main_parts.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/shell_browser_main_parts.cc b/src/shell_browser_main_parts.cc index bb1c46447e..f319b9b40e 100644 --- a/src/shell_browser_main_parts.cc +++ b/src/shell_browser_main_parts.cc @@ -160,6 +160,7 @@ int ShellBrowserMainParts::PreCreateThreads() { gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen()); #endif + package_.reset(new nw::Package()); return 0; } @@ -180,7 +181,6 @@ void ShellBrowserMainParts::ToolkitInitialized() { } void ShellBrowserMainParts::Init() { - package_.reset(new nw::Package()); CommandLine& command_line = *CommandLine::ForCurrentProcess(); browser_context_.reset(new ShellBrowserContext(false, package())); From 4a08e1015f875d65c18b089c0d41bb626fa6232f Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 10 Sep 2014 12:35:04 +0800 Subject: [PATCH 174/492] Fix #2171: crash when opening window --- src/renderer/shell_content_renderer_client.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index b7b47221c2..c16740bcea 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -99,7 +99,7 @@ RenderView* GetCurrentRenderView() { } // namespace ShellContentRendererClient::ShellContentRendererClient() - :creating_first_context_(true) { + :in_nav_cb_(false), creating_first_context_(true) { } ShellContentRendererClient::~ShellContentRendererClient() { From fb6f77656a5c54e81922e21e338d3ecb8b52fcd3 Mon Sep 17 00:00:00 2001 From: Cong Liu Date: Wed, 10 Sep 2014 16:25:03 +0800 Subject: [PATCH 175/492] Avoid failure on debug check of replacements "Hide Others" menu item doesn't accept any replacements. Providing replacements will fail the debug check and block the execution. --- src/api/menu/menu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/menu/menu.js b/src/api/menu/menu.js index 38d505e3a3..5e40cb2210 100644 --- a/src/api/menu/menu.js +++ b/src/api/menu/menu.js @@ -86,7 +86,7 @@ if (require('os').platform() === 'darwin'){ key: "h" })); appleMenu.append(new exports.MenuItem({ - label: nw.getNSStringFWithFixup("IDS_HIDE_OTHERS_MAC", app_name), + label: nw.getNSStringWithFixup("IDS_HIDE_OTHERS_MAC"), selector: "hideOtherApplications:", key: "h", modifiers: "cmd-alt" From afdc6a683e3ad5490045361ceee7ff8076da3ff8 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 12 Sep 2014 12:52:45 +0800 Subject: [PATCH 176/492] Fix #2326: Workaround before update to VS2013 update 2 This is upstream issue #348525 and #330658 --- nw.gypi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nw.gypi b/nw.gypi index 0c661777c7..2779eb05d2 100644 --- a/nw.gypi +++ b/nw.gypi @@ -377,6 +377,14 @@ '<(DEPTH)/base/allocator/allocator.gyp:allocator', ], }], + ['OS=="win" and target_arch=="ia32"', { + 'sources': [ + # TODO(scottmg): This is a workaround for + # http://crbug.com/348525 that affects VS2013 before Update 2. + # This should be removed once Update 2 is released. + '<(DEPTH)/build/win/ftol3.obj', + ], + }], ['OS=="win"', { 'sources': [ '<(DEPTH)/chrome/browser/ui/views/constrained_window_views.cc', From 42382d22e93c0c5662e0d56ff8daa49ea0bd1e18 Mon Sep 17 00:00:00 2001 From: Mikael Roos Date: Fri, 12 Sep 2014 12:08:46 +0300 Subject: [PATCH 177/492] win: Don't crash on invalid parameter error. libuv relies on suppressing the invalid parameter error in uv__get_osfhandle, and it could happen frequently. --- src/breakpad_win.cc | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/breakpad_win.cc b/src/breakpad_win.cc index 88c15f5d31..65ddf4016b 100644 --- a/src/breakpad_win.cc +++ b/src/breakpad_win.cc @@ -739,9 +739,11 @@ void InitCrashReporter() { else if (GetBreakpadClient()->GetShouldDumpLargerDumps(is_per_user_install)) dump_type = kLargerDumpType; + int handler_types = google_breakpad::ExceptionHandler::HANDLER_EXCEPTION | + google_breakpad::ExceptionHandler::HANDLER_PURECALL; g_breakpad = new google_breakpad::ExceptionHandler(temp_dir, &FilterCallback, callback, NULL, - google_breakpad::ExceptionHandler::HANDLER_ALL, + handler_types, dump_type, pipe_name.c_str(), custom_info); // Now initialize the non crash dump handler. From ac54a982f175774b9e98ec3d31a603fa90bbb90b Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 16 Sep 2014 12:26:55 +0800 Subject: [PATCH 178/492] Fix 6bd5911: allow io while doing Init --- src/shell_browser_main_parts.cc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/shell_browser_main_parts.cc b/src/shell_browser_main_parts.cc index f319b9b40e..d26727bae4 100644 --- a/src/shell_browser_main_parts.cc +++ b/src/shell_browser_main_parts.cc @@ -160,6 +160,7 @@ int ShellBrowserMainParts::PreCreateThreads() { gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen()); #endif + base::ThreadRestrictions::ScopedAllowIO allow_io; package_.reset(new nw::Package()); return 0; } @@ -181,6 +182,9 @@ void ShellBrowserMainParts::ToolkitInitialized() { } void ShellBrowserMainParts::Init() { + //this will be reset to false before entering the message loop + base::ThreadRestrictions::SetIOAllowed(true); + CommandLine& command_line = *CommandLine::ForCurrentProcess(); browser_context_.reset(new ShellBrowserContext(false, package())); From 90817c0bb3ba833d43d9de0cd321c899bf4a8dde Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 16 Sep 2014 13:29:42 +0800 Subject: [PATCH 179/492] bump version to 0.10.5 --- src/nw_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nw_version.h b/src/nw_version.h index 1abe7346b2..3bee5f4289 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -24,7 +24,7 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 10 #define NW_PATCH_VERSION 5 -#define NW_VERSION_IS_RELEASE 0 +#define NW_VERSION_IS_RELEASE 1 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) From 05e5db3fc812807ba75d83fef7bb8fa070f694a8 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 16 Sep 2014 14:32:16 +0800 Subject: [PATCH 180/492] [CHANGELOG] update for 0.10.5 --- CHANGELOG.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index f81c76bdfd..185c5fbc3b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +0.10.5 / 09-16-2014 +=================== +- Fix: support more Chromium command line args (#1743, Thanks to Joachim Bauch) +- Fix #2171: crash when opening window +- Fix #2326: some websites crashes NW in Windows (fixed with the same file as updating to VS2013 Update 2) +- Fix: win: crash on invalid parameter error (thanks to Mikael Roos) +- Fix #1991 in a better way: [WIN] stalling for seconds under threaded composition on some hardware (#1991) +- Fix: [WIN] single-instance crash +- Fix: autofill crash when filling number in input box (#2310) +- Fix: CSP is not effective (#1672) +- Fix: crash when calling console.log() with a cross-domain window object in some cases (#1573) +- Fix: crash when stepping into a breakpoint set in scripts loaded by require() (#2214) + 0.10.4 / 09-05-2014 =================== - Fix: [WIN] child_process.fork() by making nw executable run as node From 8864ccca9b0f1b002bbf1fae8818eec23827d2d3 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 16 Sep 2014 22:01:24 +0800 Subject: [PATCH 181/492] [README] update for 0.10.5 --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 675e553291..bfc8b7d934 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ It's created and developed in the Intel Open Source Technology Center. * Available on Linux, Mac OS X and Windows ## Downloads -* **v0.10.4:** (Sep 5, 2014, based off of Node v0.11.13, Chromium 35.0.1916.157): [release notes](https://groups.google.com/d/msg/node-webkit/UfjTXuZzMlo/Lqk72r1Ps6kJ) +* **v0.10.5:** (Sep 16, 2014, based off of Node v0.11.13, Chromium 35.0.1916.157): [release notes](https://groups.google.com/d/msg/node-webkit/l2PsW-0G5Oc/Fx19-UrS3ZoJ) - * Linux: [32bit](http://dl.node-webkit.org/v0.10.4/node-webkit-v0.10.4-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.4/node-webkit-v0.10.4-linux-x64.tar.gz) - * Windows: [win32](http://dl.node-webkit.org/v0.10.4/node-webkit-v0.10.4-win-ia32.zip) - * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.10.4/node-webkit-v0.10.4-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.10.4/node-webkit-v0.10.4-osx-x64.zip) + * Linux: [32bit](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-linux-x64.tar.gz) + * Windows: [win32](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-win-ia32.zip) + * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-osx-x64.zip) * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From 33c12555d6d67f75c393c7f4c9136c5bde13611d Mon Sep 17 00:00:00 2001 From: Marco Fabbri Date: Wed, 25 Jun 2014 19:09:05 +0200 Subject: [PATCH 182/492] Handle system application termination attempts Implements `applicationShouldTerminate` method inside the `AppController` (`NSApplicationDelegate`) to (catch and) handle all application termination requests (e.g `Quit` in OS X Dock). Application termination is delegated to per window `close`/`quit` event handlers (or default window behaviour) via `App::CloseAllWindows` (called with the `quit` flag set): application terminates when/if all window close. Without an `applicationShouldTerminate` implementation the application terminates immediately (e.g. with `Quit` in OS X Dock) without permitting an orderly shutdown and emitting any `close`/`quit` events. Fixes rogerwang/node-webkit#430 and also resolves rogerwang/node-webkit#924 --- src/browser/app_controller_mac.mm | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/browser/app_controller_mac.mm b/src/browser/app_controller_mac.mm index e774be4178..72fe63bf52 100644 --- a/src/browser/app_controller_mac.mm +++ b/src/browser/app_controller_mac.mm @@ -82,4 +82,14 @@ - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication return YES; } +- (NSApplicationTerminateReply)applicationShouldTerminate:(NSApplication*)app { + // The termination procedure is completely and gracefully handled by node-webkit + // (triggered by CloseAllWindows, app exits when last window closes) so we + // don't need Cocoa to terminate the application immediately (NSTerminateNow) + // neither run a special event loop (NSTerminateLater) waiting for a termination + // reply + nwapi::App::CloseAllWindows(false, true); + return NSTerminateCancel; +} + @end From d84eae213f4d5ea5b0d469bcb5fa229184193321 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 17 Sep 2014 14:55:29 +0800 Subject: [PATCH 183/492] adding AUTHORS for #2006 --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 8acd9abe90..e75a5d52bd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -31,3 +31,4 @@ Bas Wegh Joachim Bauch Cong Liu Eric Newport +Marco Fabbri From 1fd5919e5b60bbfdaf43759b20b8a138867fded8 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 17 Sep 2014 14:56:24 +0800 Subject: [PATCH 184/492] bump version to 0.10.6-pre --- src/mac/app-Info.plist | 2 +- src/nw_version.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mac/app-Info.plist b/src/mac/app-Info.plist index e8b855f370..4e007452c9 100644 --- a/src/mac/app-Info.plist +++ b/src/mac/app-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.10.5 + 0.10.6 NSPrincipalClass NSApplication LSMinimumSystemVersion diff --git a/src/nw_version.h b/src/nw_version.h index 3bee5f4289..c63f7ba74f 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -23,8 +23,8 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 10 -#define NW_PATCH_VERSION 5 -#define NW_VERSION_IS_RELEASE 1 +#define NW_PATCH_VERSION 6 +#define NW_VERSION_IS_RELEASE 0 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) From 4ab12b7cded8c5759698a3bbc9fd072015cdb0c3 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 17 Sep 2014 14:56:57 +0800 Subject: [PATCH 185/492] fix opening external protocol --- src/browser/shell_resource_dispatcher_host_delegate.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/shell_resource_dispatcher_host_delegate.cc b/src/browser/shell_resource_dispatcher_host_delegate.cc index a9cbc7eb81..69b7dd864e 100644 --- a/src/browser/shell_resource_dispatcher_host_delegate.cc +++ b/src/browser/shell_resource_dispatcher_host_delegate.cc @@ -54,7 +54,7 @@ bool ShellResourceDispatcherHostDelegate::HandleExternalProtocol( // Otherwise put this work on the file thread. On Windows ShellExecute may // block for a significant amount of time, and it shouldn't hurt on Linux. BrowserThread::PostTask( - BrowserThread::FILE, + BrowserThread::UI, FROM_HERE, base::Bind(&platform_util::OpenExternal2, url)); #endif From e03f0d06dc8e8db31dbcefd9cde7a00d32dd9fb5 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 19 Sep 2014 09:53:50 +0800 Subject: [PATCH 186/492] dlpath argument for aws_uploader --- tools/aws_uploader.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/tools/aws_uploader.py b/tools/aws_uploader.py index 872a332339..891edd1f72 100755 --- a/tools/aws_uploader.py +++ b/tools/aws_uploader.py @@ -21,6 +21,7 @@ parser.add_argument('-r','--revision', help='Commit revision',required=True) parser.add_argument('-n','--number', help='Build number', required=True) parser.add_argument('-t','--bucket', help='AWS bucket name', required=True) +parser.add_argument('-d','--dlpath', help='AWS bucket path', required=True) args = parser.parse_args() @@ -31,6 +32,7 @@ got_revision = args.revision build_number = args.number bucket_name = args.bucket +dlpath = args.dlpath date = datetime.date.today().strftime('%m-%d-%Y') # If the binaries location is not given, calculate it from script related dir. @@ -47,8 +49,9 @@ dist_dir = os.path.normpath(dist_dir) # it's for S3, so always use '/' here -upload_path = ''.join(['/' + date, - '/' + builder_name + '-build-' + build_number + '-' + got_revision]) +#upload_path = ''.join(['/' + date, +# '/' + builder_name + '-build-' + build_number + '-' + got_revision]) +upload_path = '/' + dlpath; file_list = os.listdir(dist_dir) if len(file_list) == 0: From cbdd2e672eb3fb1e0c2468e73c1354873f08a65d Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 19 Sep 2014 13:16:39 +0800 Subject: [PATCH 187/492] unify filenames in package --- tools/dump_mac_syms | 4 ++-- tools/package_binaries.py | 19 +++++++++---------- 2 files changed, 11 insertions(+), 12 deletions(-) diff --git a/tools/dump_mac_syms b/tools/dump_mac_syms index a0f3c25ef2..a593527a95 100755 --- a/tools/dump_mac_syms +++ b/tools/dump_mac_syms @@ -46,7 +46,7 @@ BREAKPAD_DUMP_SYMS="${BUILT_PRODUCTS_DIR}/dump_syms" #FULL_VERSION="${MAJOR}.${MINOR}.${BUILD}.${PATCH}" FULL_VERSION=$1 -DSYM_TAR_PATH="${BUILT_PRODUCTS_DIR}/${SRC_APP_NAME}.breakpad.tar.bz2" +DSYM_TAR_PATH="${BUILT_PRODUCTS_DIR}/${SRC_APP_NAME}.breakpad.tar" # Starting with an already-dumped symbol file at ${original_sym_path}, # transforms the MODULE line (which must be the first line) from referring to @@ -158,5 +158,5 @@ done if [ ! -e "${DSYM_TAR_PATH}" ] ; then # Change directory so that absolute paths aren't included in the archive. (cd "${BUILT_PRODUCTS_DIR}" && - tar -jcf "${DSYM_TAR_PATH}" "${DSYMS[@]}") + tar -cf "${DSYM_TAR_PATH}" "${DSYMS[@]}") fi diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 1d535a59b0..a92f034888 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -173,16 +173,15 @@ def generate_target_symbols(platform_name, arch, version): target['compress'] = 'tar.gz' target['input'] = ['nw.breakpad.' + arch] elif platform_name == 'win': - target['compress'] = 'zip' -# target['input'] = ['nw.exe.pdb'] - target['input'] = [] + target['input'] = ['nw.sym.7z'] + target['output'] = ''.join(['node-webkit-symbol-', + 'v', version, + '-', platform_name, + '-', arch, '.7z']) elif platform_name == 'osx': - target['compress'] = 'tar.gz' + target['compress'] = 'gz' target['input'] = [ -# 'node-webkit.app.dSYM', -# 'node-webkit Helper.app.dSYM', -# 'node-webkit Framework.framework.dSYM', -# 'ffmpegsumo.so.dSYM', + 'node-webkit.breakpad.tar' ] else: print 'Unsupported platform: ' + platform_name @@ -195,9 +194,9 @@ def generate_target_others(platform_name, arch, version): target['output'] = '' target['compress'] = None if platform_name == 'win': - target['input'] = ['nw.exp', 'nw.lib', 'nw.sym.7z'] + target['input'] = ['nw.exp', 'nw.lib'] elif platform_name == 'osx' : - target['input'] = ['node-webkit.breakpad.tar.bz2'] + target['input'] = [] else: target['input'] = [] return target From 7483e32a2a6784337353dbf2689f1e4a6b60f6da Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 19 Sep 2014 13:34:27 +0800 Subject: [PATCH 188/492] fix previous commit --- nw.gypi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nw.gypi b/nw.gypi index 2779eb05d2..c1880c400b 100644 --- a/nw.gypi +++ b/nw.gypi @@ -655,7 +655,7 @@ '<(PRODUCT_DIR)/dump_syms', ], 'outputs': [ - '<(PRODUCT_DIR)/node-webkit.breakpad.tar.bz2', + '<(PRODUCT_DIR)/node-webkit.breakpad.tar', ], 'action': ['<(DEPTH)/content/nw/tools/dump_mac_syms', ], From 9605c1202642bec33897eef58a8ac315689057e2 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 19 Sep 2014 13:51:26 +0800 Subject: [PATCH 189/492] fix OSX packaging --- tools/package_binaries.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index a92f034888..4261219a01 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -172,6 +172,7 @@ def generate_target_symbols(platform_name, arch, version): if platform_name == 'linux': target['compress'] = 'tar.gz' target['input'] = ['nw.breakpad.' + arch] + target['folder'] = True elif platform_name == 'win': target['input'] = ['nw.sym.7z'] target['output'] = ''.join(['node-webkit-symbol-', @@ -186,7 +187,6 @@ def generate_target_symbols(platform_name, arch, version): else: print 'Unsupported platform: ' + platform_name exit(-1) - target['folder'] = True return target def generate_target_others(platform_name, arch, version): From 59790ab6592aac72412f5ea3d06df889388f0b5d Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 19 Sep 2014 14:07:58 +0800 Subject: [PATCH 190/492] fix package names --- tools/package_binaries.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 4261219a01..4b64aca652 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -180,10 +180,11 @@ def generate_target_symbols(platform_name, arch, version): '-', platform_name, '-', arch, '.7z']) elif platform_name == 'osx': - target['compress'] = 'gz' + target['compress'] = 'zip' target['input'] = [ 'node-webkit.breakpad.tar' ] + target['folder'] = True else: print 'Unsupported platform: ' + platform_name exit(-1) @@ -262,11 +263,12 @@ def make_packages(targets): if len(t['input']) == 0: continue if t['compress'] == None: - if t['output'] != '': - os.mkdir(dist_dir + t['output']) for f in t['input']: src = os.path.join(binaries_location, f) - dest = os.path.join(dist_dir + t['output'], f) + if t['output'] != '': + dest = os.path.join(dist_dir, t['output']) + else: + dest = os.path.join(dist_dir, f) print "Copying " + f shutil.copy(src, dest) elif (t.has_key('folder') and t['folder'] == True) or len(t['input']) > 1: From cc27ae2395e890ec5c556d6b087e63682ab71c8e Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 19 Sep 2014 14:11:01 +0800 Subject: [PATCH 191/492] fix windows packaging --- tools/package_binaries.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 4b64aca652..4ca2f384e6 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -174,6 +174,7 @@ def generate_target_symbols(platform_name, arch, version): target['input'] = ['nw.breakpad.' + arch] target['folder'] = True elif platform_name == 'win': + target['compress'] = None target['input'] = ['nw.sym.7z'] target['output'] = ''.join(['node-webkit-symbol-', 'v', version, From d1dee800e65947fc0610943279a3976ff8c6962c Mon Sep 17 00:00:00 2001 From: Gnor Tech Date: Fri, 29 Aug 2014 15:41:26 +0800 Subject: [PATCH 192/492] rebase fix for nw11 --- nw.gypi | 118 ++++---- src/api/api_messages.h | 1 + src/api/app/app.cc | 2 +- src/api/bindings_common.cc | 5 +- src/api/dispatcher.cc | 24 +- src/api/dispatcher.h | 8 +- src/api/dispatcher_bindings.cc | 4 +- src/api/dispatcher_host.cc | 7 +- src/api/dispatcher_host.h | 5 +- src/api/menu/menu.h | 39 +-- ...{menu_delegate_win.cc => menu_delegate.cc} | 209 +++++++------- .../{menu_delegate_win.h => menu_delegate.h} | 116 ++++---- src/api/menu/menu_gtk.cc | 3 +- src/api/menu/{menu_win.cc => menu_views.cc} | 49 +++- src/api/menuitem/menuitem.h | 31 +-- .../{menuitem_win.cc => menuitem_views.cc} | 17 +- .../shortcut/global_shortcut_listener_x11.cc | 12 +- .../shortcut/global_shortcut_listener_x11.h | 8 +- src/api/shortcut/shortcut.cc | 2 +- src/api/tray/tray.h | 6 +- src/api/tray/tray_gtk.cc | 2 + src/api/window/window.cc | 10 +- src/api/window_bindings.cc | 18 +- src/breakpad_linux.cc | 26 +- src/browser/autofill_popup_controller_impl.cc | 13 +- src/browser/autofill_popup_controller_impl.h | 2 - src/browser/capture_page_helper.cc | 2 +- src/browser/color_chooser_gtk.cc | 4 +- src/browser/file_select_helper.cc | 5 +- src/browser/native_window.cc | 8 +- ...ve_window_win.cc => native_window_aura.cc} | 251 ++++++++++------- ...tive_window_win.h => native_window_aura.h} | 34 +-- src/browser/native_window_gtk.cc | 12 +- src/browser/native_window_gtk.h | 2 +- src/browser/native_window_toolbar_aura.cc | 254 ++++++++++++++++++ ...bar_win.h => native_window_toolbar_aura.h} | 16 +- src/browser/native_window_toolbar_win.cc | 26 +- src/browser/printing/print_job.cc | 4 +- src/browser/printing/print_job_worker.cc | 29 +- src/browser/printing/print_view_manager.cc | 5 +- .../printing/printing_message_filter.cc | 7 +- .../printing/printing_message_filter.h | 3 +- .../printing_ui_web_contents_observer.cc | 3 +- src/browser/shell_devtools_delegate.cc | 33 ++- .../shell_download_manager_delegate.cc | 2 +- .../shell_download_manager_delegate_gtk.cc | 7 +- .../shell_javascript_dialog_creator.cc | 1 - src/browser/shell_login_dialog.cc | 9 + ...shell_resource_dispatcher_host_delegate.cc | 1 + src/chrome_breakpad_client.cc | 6 +- src/chrome_breakpad_client.h | 1 - src/common/print_messages.cc | 11 + src/common/print_messages.h | 46 +++- src/common/shell_switches.cc | 1 + src/common/shell_switches.h | 3 + src/media/media_capture_devices_dispatcher.h | 12 +- src/media/media_internals.cc | 12 +- src/media/media_internals.h | 5 +- src/media/media_stream_devices_controller.cc | 6 +- src/net/app_protocol_handler.cc | 7 +- src/net/clear_on_exit_policy.cc | 4 +- src/net/shell_url_request_context_getter.cc | 17 +- src/nw_notification_manager.cc | 8 +- src/nw_notification_manager_linux.cc | 1 - src/nw_package.cc | 2 +- src/nw_shell.cc | 35 ++- src/renderer/common/render_messages.h | 4 + src/renderer/nw_render_view_observer.cc | 8 +- src/renderer/nw_render_view_observer.h | 4 +- .../printing/print_web_view_helper.cc | 123 +++++---- src/renderer/printing/print_web_view_helper.h | 26 +- .../printing/print_web_view_helper_linux.cc | 2 +- src/renderer/shell_content_renderer_client.cc | 5 +- src/shell_browser_context.cc | 42 +-- src/shell_browser_context.h | 36 +-- src/shell_browser_main_parts.cc | 11 +- src/shell_content_browser_client.cc | 130 ++++++--- src/shell_content_browser_client.h | 51 ++-- src/shell_devtools_frontend.cc | 73 ++++- src/shell_devtools_frontend.h | 22 +- src/shell_main_delegate.cc | 13 +- src/shell_quota_permission_context.cc | 5 +- src/shell_quota_permission_context.h | 5 +- 83 files changed, 1317 insertions(+), 875 deletions(-) rename src/api/menu/{menu_delegate_win.cc => menu_delegate.cc} (94%) rename src/api/menu/{menu_delegate_win.h => menu_delegate.h} (95%) rename src/api/menu/{menu_win.cc => menu_views.cc} (86%) rename src/api/menuitem/{menuitem_win.cc => menuitem_views.cc} (98%) rename src/browser/{native_window_win.cc => native_window_aura.cc} (81%) rename src/browser/{native_window_win.h => native_window_aura.h} (91%) create mode 100644 src/browser/native_window_toolbar_aura.cc rename src/browser/{native_window_toolbar_win.h => native_window_toolbar_aura.h} (87%) diff --git a/nw.gypi b/nw.gypi index c1880c400b..1dc86d1129 100644 --- a/nw.gypi +++ b/nw.gypi @@ -44,7 +44,7 @@ '<(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.gyp:content_worker', '<(DEPTH)/content/content_resources.gyp:content_resources', '<(DEPTH)/ipc/ipc.gyp:ipc', '<(DEPTH)/media/media.gyp:media', @@ -68,7 +68,7 @@ '<(DEPTH)/third_party/WebKit/public/web', '<(DEPTH)/breakpad/src', '<(SHARED_INTERMEDIATE_DIR)/blink', - '<(SHARED_INTERMEDIATE_DIR)/blink/bindings', + '<(SHARED_INTERMEDIATE_DIR)/blink/bindings/core/v8/', '<(SHARED_INTERMEDIATE_DIR)/chrome', ], 'cflags_cc': [ @@ -85,12 +85,12 @@ '<(DEPTH)/chrome/common/env_vars.cc', '<(DEPTH)/chrome/browser/crash_upload_list.cc', '<(DEPTH)/chrome/browser/upload_list.cc', - '<(DEPTH)/chrome/browser/platform_util_common_linux.cc', '<(DEPTH)/chrome/browser/platform_util_linux.cc', + '<(DEPTH)/chrome/browser/platform_util_aura.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_posix.cc', '<(DEPTH)/chrome/browser/process_singleton_mac.cc', '<(DEPTH)/chrome/browser/process_singleton_win.cc', '<(DEPTH)/chrome/browser/process_singleton.h', @@ -102,10 +102,6 @@ '<(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/gtk/unity_service.cc', - '<(DEPTH)/chrome/browser/ui/gtk/unity_service.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', @@ -116,17 +112,14 @@ '<(DEPTH)/chrome/common/chrome_switches.h', '<(DEPTH)/extensions/common/draggable_region.cc', '<(DEPTH)/extensions/common/draggable_region.h', + '<(DEPTH)/extensions/renderer/static_v8_external_ascii_string_resource.cc', + '<(DEPTH)/extensions/renderer/static_v8_external_ascii_string_resource.h', '<(DEPTH)/third_party/zlib/google/zip.cc', '<(DEPTH)/third_party/zlib/google/zip.h', '<(DEPTH)/third_party/zlib/google/zip_reader.cc', '<(DEPTH)/third_party/zlib/google/zip_reader.h', '<(DEPTH)/third_party/zlib/google/zip_internal.cc', '<(DEPTH)/third_party/zlib/google/zip_internal.h', - '<(DEPTH)/components/autofill/content/renderer/page_click_listener.h', - '<(DEPTH)/components/autofill/content/renderer/page_click_tracker.cc', - '<(DEPTH)/components/autofill/content/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', @@ -144,24 +137,22 @@ 'src/api/dispatcher_bindings_mac.mm', 'src/api/dispatcher_host.cc', 'src/api/dispatcher_host.h', - 'src/api/event/event.h', - 'src/api/event/event.cc', - 'src/api/screen/screen.h', - 'src/api/screen/screen.cc', +# 'src/api/event/event.h', +# 'src/api/event/event.cc', +# 'src/api/screen/screen.h', +# 'src/api/screen/screen.cc', '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_delegate.cc', + 'src/api/menu/menu_delegate.h', 'src/api/menu/menu_mac.mm', - 'src/api/menu/menu_win.cc', + 'src/api/menu/menu_views.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_views.cc', 'src/api/menuitem/menuitem_delegate_mac.h', 'src/api/menuitem/menuitem_delegate_mac.mm', 'src/api/shell/shell.cc', @@ -187,19 +178,17 @@ 'src/api/window/window.h', 'src/browser/app_controller_mac.h', 'src/browser/app_controller_mac.mm', - 'src/browser/autofill_popup_view_gtk.cc', - 'src/browser/autofill_popup_view_gtk.h', 'src/browser/autofill_popup_view_cocoa.h', 'src/browser/autofill_popup_view_cocoa.mm', 'src/browser/autofill_popup_view_bridge.h', 'src/browser/autofill_popup_view_bridge.mm', 'src/browser/autofill_popup_controller_impl.cc', 'src/browser/autofill_popup_controller_impl.h', - 'src/browser/tab_autofill_manager_delegate.cc', - 'src/browser/tab_autofill_manager_delegate.h', +# 'src/browser/tab_autofill_manager_delegate.cc', +# 'src/browser/tab_autofill_manager_delegate.h', 'src/browser/capture_page_helper.h', 'src/browser/capture_page_helper.cc', - 'src/browser/color_chooser_gtk.cc', +# 'src/browser/color_chooser_gtk.cc', 'src/browser/color_chooser_win.cc', 'src/browser/color_chooser_mac.mm', 'src/browser/chrome_event_processing_window.mm', @@ -208,23 +197,19 @@ '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/native_window_toolbar_aura.cc', + 'src/browser/native_window_toolbar_aura.h', + 'src/browser/native_window_aura.cc', + 'src/browser/native_window_aura.h', 'src/browser/net_disk_cache_remover.cc', 'src/browser/net_disk_cache_remover.h', 'src/browser/nw_form_database_service.cc', 'src/browser/nw_form_database_service.h', 'src/browser/popup_controller_common.cc', 'src/browser/popup_controller_common.h', - 'src/browser/printing/print_dialog_gtk.cc', - 'src/browser/printing/print_dialog_gtk.h', 'src/browser/printing/print_job.cc', 'src/browser/printing/print_job.h', 'src/browser/printing/print_job_manager.cc', @@ -251,11 +236,11 @@ 'src/browser/shell_download_manager_delegate_mac.mm', '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_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_gtk.cc', 'src/browser/shell_login_dialog_mac.mm', 'src/browser/shell_login_dialog_win.cc', 'src/browser/shell_login_dialog.cc', @@ -328,8 +313,8 @@ 'src/nw_notification_manager_win.cc', 'src/nw_notification_manager_mac.h', 'src/nw_notification_manager_mac.mm', - 'src/nw_notification_manager_linux.h', - 'src/nw_notification_manager_linux.cc', + # 'src/nw_notification_manager_linux.h', + # 'src/nw_notification_manager_linux.cc', 'src/shell_browser_context.cc', 'src/shell_browser_context.h', 'src/shell_browser_main.cc', @@ -364,14 +349,21 @@ '<(DEPTH)/base/allocator/allocator.gyp:allocator', ], }], + ['os_posix == 1 and OS != "mac" and android_webview_build != 1', { + 'dependencies': [ + '../components/components.gyp:breakpad_host', + ], + }], ['use_aura==1', { 'dependencies': [ + '<(DEPTH)/components/components.gyp:web_modal', + '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources', '<(DEPTH)/ui/views/views.gyp:views', '<(DEPTH)/ui/views/views.gyp:views_test_support', '<(DEPTH)/ui/views/controls/webview/webview.gyp:webview', ], }], - ['(os_posix==1 and OS != "mac" and linux_use_tcmalloc==1 and asan==0)', { + ['(os_posix==1 and OS != "mac" and use_allocator!="none")', { 'dependencies': [ # This is needed by content/app/content_main_runner.cc '<(DEPTH)/base/allocator/allocator.gyp:allocator', @@ -400,21 +392,21 @@ '<(DEPTH)/breakpad/breakpad.gyp:breakpad_handler', '<(DEPTH)/breakpad/breakpad.gyp:breakpad_sender', '<(DEPTH)/components/components.gyp:breakpad_component', - '<(DEPTH)/components/components.gyp:web_modal', ], }], ['os_posix==1 and OS != "mac" and OS != "ios"', { - 'sources': [ - 'src/breakpad_linux.cc', - 'src/breakpad_linux.h', - 'src/crash_handler_host_linux.cc', - 'src/crash_handler_host_linux.h', - ], 'dependencies': [ '<(DEPTH)/breakpad/breakpad.gyp:breakpad_client', '<(DEPTH)/components/components.gyp:breakpad_component', ], }], + ['OS=="linux"', { + 'dependencies': [ + '<(DEPTH)/chrome/browser/ui/libgtk2ui/libgtk2ui.gyp:gtk2ui', + '<(DEPTH)/build/linux/system.gyp:gio', + '<(DEPTH)/build/linux/system.gyp:gtk', + ], + }], ['OS == "mac"', { 'sources!': [ '<(DEPTH)/chrome/common/child_process_logging_posix.cc', @@ -433,14 +425,6 @@ ], }, }], - ['toolkit_uses_gtk == 1', { - 'dependencies': [ - # For FT_Init_FreeType and friends. - '../build/linux/system.gyp:freetype2', - '../build/linux/system.gyp:gtk', - '../build/linux/system.gyp:gtkprint', - ], - }], ['OS=="win"', { 'sources': [ 'src/browser/color_chooser_dialog.cc', @@ -450,7 +434,6 @@ '<(SHARED_INTERMEDIATE_DIR)/webkit', ], 'dependencies': [ - '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources', '<(DEPTH)/ui/views/controls/webview/webview.gyp:webview', '<(DEPTH)/ui/views/views.gyp:views', '<(DEPTH)/webkit/webkit_resources.gyp:webkit_resources', @@ -605,6 +588,10 @@ 'dependencies': [ '<(DEPTH)/content/browser/devtools/devtools_resources.gyp:devtools_resources', '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources', + '<(DEPTH)/net/net.gyp:net_resources', + '<(DEPTH)/third_party/WebKit/public/blink_resources.gyp:blink_resources', + '<(DEPTH)/ui/strings/ui_strings.gyp:ui_strings', + '<(DEPTH)/webkit/glue/resources/webkit_resources.gyp:webkit_resources', 'nw_resources', ], 'variables': { @@ -619,11 +606,11 @@ '<(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_resources/webui_resources.pak', - '<(SHARED_INTERMEDIATE_DIR)/ui/ui_strings/ui_strings_en-US.pak', + '<(SHARED_INTERMEDIATE_DIR)/ui/resources/ui_resources_100_percent.pak', + '<(SHARED_INTERMEDIATE_DIR)/ui/resources/webui_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/ui/strings/ui_strings_en-US.pak', '<(SHARED_INTERMEDIATE_DIR)/webkit/devtools_resources.pak', - '<(SHARED_INTERMEDIATE_DIR)/webkit/blink_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/blink/public/resources/blink_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_resources_100_percent.pak', '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_strings_en-US.pak', ], @@ -744,7 +731,7 @@ }, ], 'dependencies': [ - '<(DEPTH)/v8/tools/gyp/v8.gyp:nwsnapshot', + # '<(DEPTH)/v8/tools/gyp/v8.gyp:nwsnapshot', '<(DEPTH)/chrome/chrome.gyp:chromedriver', ], }], @@ -847,16 +834,11 @@ 'ldflags': [ '-Wl,--whole-archive', 'obj/third_party/node/libnode.a', '-Wl,--no-whole-archive' ], }], - ['OS == "win" or toolkit_uses_gtk == 1', { + ['OS == "win"', { '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=="linux"', { 'dependencies': [ '<(DEPTH)/build/linux/system.gyp:notify', diff --git a/src/api/api_messages.h b/src/api/api_messages.h index e649074172..a8e9658a14 100644 --- a/src/api/api_messages.h +++ b/src/api/api_messages.h @@ -25,6 +25,7 @@ #include "extensions/common/draggable_region.h" #include "content/public/common/common_param_traits.h" #include "ipc/ipc_message_macros.h" +#include "ui/gfx/ipc/gfx_param_traits.h" #define IPC_MESSAGE_START ShellMsgStart diff --git a/src/api/app/app.cc b/src/api/app/app.cc index 60567617d2..21d4bce983 100644 --- a/src/api/app/app.cc +++ b/src/api/app/app.cc @@ -126,7 +126,7 @@ void App::Call(Shell* shell, } else if (method == "SetCrashDumpDir") { std::string path; arguments.GetString(0, &path); - result->AppendBoolean(SetCrashDumpPath(path.c_str())); + //FIXME: result->AppendBoolean(SetCrashDumpPath(path.c_str())); return; } else if (method == "RegisterGlobalHotKey") { int object_id = -1; diff --git a/src/api/bindings_common.cc b/src/api/bindings_common.cc index 48db9777e7..638c184c67 100644 --- a/src/api/bindings_common.cc +++ b/src/api/bindings_common.cc @@ -27,18 +27,19 @@ #include "content/public/renderer/render_thread.h" #include "content/public/renderer/v8_value_converter.h" #include "third_party/WebKit/public/web/WebView.h" -#include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "ui/base/resource/resource_bundle.h" using content::RenderView; using content::RenderThread; using content::V8ValueConverter; using blink::WebFrame; +using blink::WebLocalFrame; using blink::WebView; namespace { RenderView* GetRenderView(v8::Handle ctx) { - WebFrame* frame = WebFrame::frameForContext(ctx); + WebLocalFrame* frame = WebLocalFrame::frameForContext(ctx); if (!frame) return NULL; diff --git a/src/api/dispatcher.cc b/src/api/dispatcher.cc index e1da914a59..44ca98d2b5 100644 --- a/src/api/dispatcher.cc +++ b/src/api/dispatcher.cc @@ -29,7 +29,7 @@ #undef CHECK #include "third_party/node/src/req_wrap.h" #include "third_party/WebKit/public/web/WebDocument.h" -#include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebView.h" #include "v8/include/v8.h" @@ -43,7 +43,7 @@ #endif #include "third_party/WebKit/Source/config.h" #include "third_party/WebKit/Source/core/frame/Frame.h" -#include "third_party/WebKit/Source/web/WebFrameImpl.h" +#include "third_party/WebKit/Source/web/WebLocalFrameImpl.h" #include "V8HTMLElement.h" namespace nwapi { @@ -136,6 +136,7 @@ v8::Handle Dispatcher::GetWindowId(blink::WebFrame* frame) { return val; } +#if 0 //FIXME void Dispatcher::ZoomLevelChanged() { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::HandleScope scope(isolate); @@ -160,16 +161,17 @@ void Dispatcher::ZoomLevelChanged() { node::MakeCallback(isolate, objects_registry, "handleEvent", 3, argv); } +#endif -void Dispatcher::DidCreateDocumentElement(blink::WebFrame* frame) { +void Dispatcher::DidCreateDocumentElement(blink::WebLocalFrame* frame) { documentCallback("document-start", frame); } -void Dispatcher::DidFinishDocumentLoad(blink::WebFrame* frame) { +void Dispatcher::DidFinishDocumentLoad(blink::WebLocalFrame* frame) { documentCallback("document-end", frame); } -void Dispatcher::documentCallback(const char* ev, blink::WebFrame* frame) { +void Dispatcher::documentCallback(const char* ev, blink::WebLocalFrame* frame) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); blink::WebView* web_view = render_view()->GetWebView(); v8::HandleScope scope(isolate); @@ -190,9 +192,9 @@ void Dispatcher::documentCallback(const char* ev, blink::WebFrame* frame) { v8::Local args = v8::Array::New(isolate); v8::Handle element = v8::Null(isolate); - WebCore::LocalFrame* core_frame = blink::toWebFrameImpl(frame)->frame(); - if (core_frame->ownerElement()) { - element = WebCore::toV8((WebCore::HTMLElement*)core_frame->ownerElement(), + blink::LocalFrame* core_frame = blink::toWebLocalFrameImpl(frame)->frame(); + if (core_frame->deprecatedLocalOwner()) { + element = blink::toV8((blink::HTMLElement*)core_frame->deprecatedLocalOwner(), frame->mainWorldScriptContext()->Global(), frame->mainWorldScriptContext()->GetIsolate()); } @@ -233,9 +235,9 @@ void Dispatcher::willHandleNavigationPolicy( v8::Handle element = v8::Null(isolate); v8::Handle policy_obj = v8::Object::New(isolate); - WebCore::LocalFrame* core_frame = blink::toWebFrameImpl(frame)->frame(); - if (core_frame->ownerElement()) { - element = WebCore::toV8((WebCore::HTMLElement*)core_frame->ownerElement(), + blink::LocalFrame* core_frame = blink::toWebLocalFrameImpl(frame)->frame(); + if (core_frame->deprecatedLocalOwner()) { + element = blink::toV8((blink::HTMLElement*)core_frame->deprecatedLocalOwner(), frame->mainWorldScriptContext()->Global(), frame->mainWorldScriptContext()->GetIsolate()); } diff --git a/src/api/dispatcher.h b/src/api/dispatcher.h index 51be736156..8649a8a605 100644 --- a/src/api/dispatcher.h +++ b/src/api/dispatcher.h @@ -58,11 +58,11 @@ class Dispatcher : public content::RenderViewObserver { // RenderViewObserver implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; virtual void DraggableRegionsChanged(blink::WebFrame* frame) OVERRIDE; - virtual void ZoomLevelChanged() OVERRIDE; - virtual void DidFinishDocumentLoad(blink::WebFrame* frame) OVERRIDE; - virtual void DidCreateDocumentElement(blink::WebFrame* frame) OVERRIDE; + //FIXME virtual void ZoomLevelChanged() OVERRIDE; + virtual void DidFinishDocumentLoad(blink::WebLocalFrame* frame) OVERRIDE; + virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) OVERRIDE; - void documentCallback(const char* ev, blink::WebFrame* frame); + void documentCallback(const char* ev, blink::WebLocalFrame* frame); void OnEvent(int object_id, std::string event, diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 3ec58b2889..5e01466c9b 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -25,13 +25,13 @@ #include "base/logging.h" #include "base/values.h" #include "base/command_line.h" -#include "chrome/renderer/static_v8_external_string_resource.h" #include "content/nw/src/breakpad_linux.h" #include "content/nw/src/api/api_messages.h" #include "content/nw/src/api/bindings_common.h" #include "content/public/renderer/render_view.h" #include "content/public/renderer/render_thread.h" #include "content/public/renderer/v8_value_converter.h" +#include "extensions/renderer/static_v8_external_ascii_string_resource.h" #include "grit/nw_resources.h" #include "third_party/node/src/node.h" #undef CHECK @@ -69,7 +69,7 @@ void RequireFromResource(v8::Handle root, v8::HandleScope handle_scope(isolate); v8::Handle source = v8::String::NewExternal(isolate, - new StaticV8ExternalAsciiStringResource( + new extensions::StaticV8ExternalAsciiStringResource( GetStringResource(resource_id))); v8::Handle wrapped_source = WrapSource(source); diff --git a/src/api/dispatcher_host.cc b/src/api/dispatcher_host.cc index 262a962f5e..361b1dbc99 100644 --- a/src/api/dispatcher_host.cc +++ b/src/api/dispatcher_host.cc @@ -103,7 +103,8 @@ bool DispatcherHost::Send(IPC::Message* message) { return render_view_host_->Send(message); } -bool DispatcherHost::OnMessageReceived(content::RenderViewHost* render_view_host, +bool DispatcherHost::OnMessageReceived( + content::RenderViewHost* render_view_host, const IPC::Message& message) { if (render_view_host != render_view_host_) return false; @@ -160,7 +161,7 @@ void DispatcherHost::OnAllocateObject(int object_id, } else if (type == "Shortcut") { objects_registry_.AddWithID(new Shortcut(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); } else if (type == "Screen") { - objects_registry_.AddWithID(new EventListener(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); + //FIXME: objects_registry_.AddWithID(new EventListener(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); } else { LOG(ERROR) << "Allocate an object of unknown type: " << type; objects_registry_.AddWithID(new Base(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); @@ -252,7 +253,7 @@ void DispatcherHost::OnCallStaticMethodSync( nwapi::App::Call(shell, method, arguments, result); return; } else if (type == "Screen") { - nwapi::Screen::Call(this, method, arguments, result); + //FIXME: nwapi::Screen::Call(this, method, arguments, result); return; } diff --git a/src/api/dispatcher_host.h b/src/api/dispatcher_host.h index e9384ca98e..5e92867ea3 100644 --- a/src/api/dispatcher_host.h +++ b/src/api/dispatcher_host.h @@ -90,7 +90,10 @@ class DispatcherHost : public content::WebContentsObserver { // RenderViewHostObserver implementation. // WebContentsObserver implementation: - virtual bool OnMessageReceived(content::RenderViewHost* render_view_host, const IPC::Message& message) OVERRIDE; + virtual bool OnMessageReceived( + content::RenderViewHost* render_view_host, + const IPC::Message& message) OVERRIDE; + void OnAllocateObject(int object_id, const std::string& type, diff --git a/src/api/menu/menu.h b/src/api/menu/menu.h index e3384d8be7..b965dc72d6 100644 --- a/src/api/menu/menu.h +++ b/src/api/menu/menu.h @@ -38,19 +38,14 @@ class NSMenu; namespace nw { class NativeWindowCocoa; } -#elif defined(TOOLKIT_GTK) -#include -namespace nw { -class NativeWindowGtk; -} -#elif defined(OS_WIN) -#include "content/nw/src/api/menu/menu_delegate_win.h" -#include "ui/views/controls/menu/native_menu_win.h" +#elif defined(OS_WIN) || defined(OS_LINUX) +#include "content/nw/src/api/menu/menu_delegate.h" +//#include "ui/views/controls/menu/native_menu_win.h" #include "chrome/browser/status_icons/status_icon_menu_model.h" #include "ui/views/focus/focus_manager.h" namespace nw { -class NativeWindowWin; +class NativeWindowAura; } namespace nwapi { @@ -69,7 +64,7 @@ class NwMenuModel : public SimpleMenuModel { // Overridden from MenuModel: virtual bool HasIcons() const OVERRIDE; - + protected: friend class nwapi::Menu; }; @@ -96,11 +91,7 @@ class Menu : public Base { virtual void Call(const std::string& method, const base::ListValue& arguments) OVERRIDE; -#if defined(OS_LINUX) - void UpdateKeys(GtkAccelGroup *gtk_accel_group); -#endif - -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) void UpdateKeys(views::FocusManager *focus_manager); #endif @@ -118,15 +109,25 @@ class Menu : public Base { #if defined(OS_LINUX) std::vector menu_items; - GtkAccelGroup *gtk_accel_group; #endif #if defined(OS_MACOSX) friend class nw::NativeWindowCocoa; NSMenu* menu_; -#elif defined(TOOLKIT_GTK) - friend class nw::NativeWindowGtk; - GtkWidget* menu_; +#elif defined(OS_LINUX) + friend class nw::NativeWindowAura; + + views::FocusManager *focus_manager_; + std::vector menu_items_; + nw::NativeWindowAura* window_; + // Flag to indicate the menu has been modified since last show, so we should + // rebuild the menu before next show. + bool is_menu_modified_; + + scoped_ptr menu_delegate_; + scoped_ptr menu_model_; + void UpdateStates(); + #elif defined(OS_WIN) friend class nw::NativeWindowWin; diff --git a/src/api/menu/menu_delegate_win.cc b/src/api/menu/menu_delegate.cc similarity index 94% rename from src/api/menu/menu_delegate_win.cc rename to src/api/menu/menu_delegate.cc index 37941590df..a094211020 100644 --- a/src/api/menu/menu_delegate_win.cc +++ b/src/api/menu/menu_delegate.cc @@ -1,102 +1,109 @@ -// 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_delegate_win.h" - -#include "base/logging.h" -#include "base/strings/string16.h" -#include "content/nw/src/api/dispatcher_host.h" -#include "content/nw/src/api/menuitem/menuitem.h" - -namespace nwapi { - -MenuDelegate::MenuDelegate(DispatcherHost* dispatcher_host) - : dispatcher_host_(dispatcher_host) { -} - -MenuDelegate::~MenuDelegate() { -} - -bool MenuDelegate::IsCommandIdChecked(int command_id) const { - if (command_id < 0) - return false; - - MenuItem* item = dispatcher_host_->GetApiObject(command_id); - return item->is_checked_; -} - -bool MenuDelegate::IsCommandIdEnabled(int command_id) const { - if (command_id < 0) - return false; - - MenuItem* item = dispatcher_host_->GetApiObject(command_id); - if (!item) - return false; - return item->is_enabled_; -} - -bool MenuDelegate::IsItemForCommandIdDynamic(int command_id) const { - if (command_id < 0) - return false; - - MenuItem* item = dispatcher_host_->GetApiObject(command_id); - if (!item) - return false; - return item->is_modified_; -} - +// 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_delegate.h" + +#include "base/logging.h" +#include "base/strings/string16.h" +#include "content/nw/src/api/dispatcher_host.h" +#include "content/nw/src/api/menuitem/menuitem.h" + +namespace nwapi { + +MenuDelegate::MenuDelegate(DispatcherHost* dispatcher_host) + : dispatcher_host_(dispatcher_host) { +} + +MenuDelegate::~MenuDelegate() { +} + +bool MenuDelegate::IsCommandIdChecked(int command_id) const { + if (command_id < 0) + return false; + + MenuItem* item = dispatcher_host_->GetApiObject(command_id); + return item->is_checked_; +} + +bool MenuDelegate::IsCommandIdEnabled(int command_id) const { + if (command_id < 0) + return false; + + MenuItem* item = dispatcher_host_->GetApiObject(command_id); + if (!item) + return false; + return item->is_enabled_; +} + +bool MenuDelegate::IsItemForCommandIdDynamic(int command_id) const { + if (command_id < 0) + return false; + + MenuItem* item = dispatcher_host_->GetApiObject(command_id); + if (!item) + return false; + return item->is_modified_; +} + base::string16 MenuDelegate::GetLabelForCommandId(int command_id) const { - MenuItem* item = dispatcher_host_->GetApiObject(command_id); - return item->label_; -} - -bool MenuDelegate::GetIconForCommandId(int command_id, - gfx::Image* icon) const { - MenuItem* item = dispatcher_host_->GetApiObject(command_id); - if (!item) - return false; - if (item->icon_.IsEmpty()) - return false; - - *icon = item->icon_; - return true; -} - -void MenuDelegate::ExecuteCommand(int command_id, int event_flags) { - if (command_id < 0) - return; - - MenuItem* item = dispatcher_host_->GetApiObject(command_id); - if (!item) - return; - item->OnClick(); -} - -bool MenuDelegate::HasIcon(int command_id) { - if (command_id < 0) - return false; - - MenuItem* item = dispatcher_host_->GetApiObject(command_id); - if (!item) - return false; - return !item->icon_.IsEmpty(); -} - -} // namespace nwapi + MenuItem* item = dispatcher_host_->GetApiObject(command_id); + return item->label_; +} + + +bool MenuDelegate::GetAcceleratorForCommandId( + int command_id, + ui::Accelerator* accelerator) { + return false; +} + +bool MenuDelegate::GetIconForCommandId(int command_id, + gfx::Image* icon) const { + MenuItem* item = dispatcher_host_->GetApiObject(command_id); + if (!item) + return false; + if (item->icon_.IsEmpty()) + return false; + + *icon = item->icon_; + return true; +} + +void MenuDelegate::ExecuteCommand(int command_id, int event_flags) { + if (command_id < 0) + return; + + MenuItem* item = dispatcher_host_->GetApiObject(command_id); + if (!item) + return; + item->OnClick(); +} + +bool MenuDelegate::HasIcon(int command_id) { + if (command_id < 0) + return false; + + MenuItem* item = dispatcher_host_->GetApiObject(command_id); + if (!item) + return false; + return !item->icon_.IsEmpty(); +} + +} // namespace nwapi diff --git a/src/api/menu/menu_delegate_win.h b/src/api/menu/menu_delegate.h similarity index 95% rename from src/api/menu/menu_delegate_win.h rename to src/api/menu/menu_delegate.h index bda6a80075..258a571d68 100644 --- a/src/api/menu/menu_delegate_win.h +++ b/src/api/menu/menu_delegate.h @@ -1,59 +1,59 @@ -// 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_API_MENU_MENU_DELEGATE_H_ -#define CONTENT_NW_SRC_API_MENU_MENU_DELEGATE_H_ - -#include "ui/base/models/simple_menu_model.h" - -namespace nwapi { - -class DispatcherHost; - -class MenuDelegate : public ui::SimpleMenuModel::Delegate { - public: - MenuDelegate(DispatcherHost* dispatcher_host); - virtual ~MenuDelegate(); - - virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; - virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; - - virtual bool GetAcceleratorForCommandId( - int command_id, - ui::Accelerator* accelerator) { return false; } - - virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE; +// 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_API_MENU_MENU_DELEGATE_H_ +#define CONTENT_NW_SRC_API_MENU_MENU_DELEGATE_H_ + +#include "ui/base/models/simple_menu_model.h" + +namespace nwapi { + +class DispatcherHost; + +class MenuDelegate : public ui::SimpleMenuModel::Delegate { + public: + MenuDelegate(DispatcherHost* dispatcher_host); + virtual ~MenuDelegate(); + + virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; + virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; + + virtual bool GetAcceleratorForCommandId( + int command_id, + ui::Accelerator* accelerator) OVERRIDE; + + virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE; virtual base::string16 GetLabelForCommandId(int command_id) const OVERRIDE; - virtual bool GetIconForCommandId(int command_id, - gfx::Image* icon) const OVERRIDE; - - virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; - - virtual bool HasIcon(int command_id) OVERRIDE; - - private: - DispatcherHost* dispatcher_host_; - - DISALLOW_COPY_AND_ASSIGN(MenuDelegate); -}; - -} // namespace nwapi - -#endif // CONTENT_NW_SRC_API_MENU_MENU_DELEGATE_H_ + virtual bool GetIconForCommandId(int command_id, + gfx::Image* icon) const OVERRIDE; + + virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; + + virtual bool HasIcon(int command_id) OVERRIDE; + + private: + DispatcherHost* dispatcher_host_; + + DISALLOW_COPY_AND_ASSIGN(MenuDelegate); +}; + +} // namespace nwapi + +#endif // CONTENT_NW_SRC_API_MENU_MENU_DELEGATE_H_ diff --git a/src/api/menu/menu_gtk.cc b/src/api/menu/menu_gtk.cc index 4adadc04e1..893c0ab45d 100644 --- a/src/api/menu/menu_gtk.cc +++ b/src/api/menu/menu_gtk.cc @@ -128,8 +128,7 @@ void Menu::Remove(MenuItem* menu_item, int pos) { } void Menu::Popup(int x, int y, content::Shell* shell) { - GdkEventButton* event = shell->web_contents()->GetRenderWidgetHostView()-> - GetLastMouseDown(); + GdkEventButton* event = NULL; //FIXME: shell->web_contents()->GetRenderWidgetHostView()->GetLastMouseDown(); uint32_t triggering_event_time = event ? event->time : GDK_CURRENT_TIME; gfx::Point point; if (!event) { diff --git a/src/api/menu/menu_win.cc b/src/api/menu/menu_views.cc similarity index 86% rename from src/api/menu/menu_win.cc rename to src/api/menu/menu_views.cc index 6162138ba7..88ebc86357 100644 --- a/src/api/menu/menu_win.cc +++ b/src/api/menu/menu_views.cc @@ -21,26 +21,28 @@ #include "content/nw/src/api/menu/menu.h" #include "base/values.h" +#include "base/strings/utf_string_conversions.h" #include "content/nw/src/api/dispatcher_host.h" #include "content/nw/src/api/menuitem/menuitem.h" -#include "content/nw/src/browser/native_window_win.h" +#include "content/nw/src/browser/native_window_aura.h" #include "content/nw/src/nw_shell.h" #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.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/gfx/gdi_util.h" -#include "ui/gfx/icon_util.h" -#include "ui/views/controls/menu/menu_2.h" +//#include "ui/gfx/gdi_util.h" +//#include "ui/gfx/icon_util.h" +//#include "ui/views/controls/menu/menu_2.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 { +#if defined(OS_WIN) + HBITMAP GetNativeBitmapFromSkBitmap(const SkBitmap& bitmap) { int width = bitmap.width(); int height = bitmap.height(); @@ -62,6 +64,7 @@ HBITMAP GetNativeBitmapFromSkBitmap(const SkBitmap& bitmap) { return native_bitmap; } +#endif } // namespace @@ -79,30 +82,34 @@ bool NwMenuModel::HasIcons() const { namespace nwapi { +#if defined(OS_WIN) // The width of the icon for the menuitem static const int kIconWidth = 16; // The height of the icon for the menuitem static const int kIconHeight = 16; +#endif void Menu::Create(const base::DictionaryValue& option) { is_menu_modified_ = true; menu_delegate_.reset(new MenuDelegate(dispatcher_host())); menu_model_.reset(new ui::NwMenuModel(menu_delegate_.get())); - menu_.reset(new views::NativeMenuWin(menu_model_.get(), NULL)); + //menu_.reset(new views::NativeMenuWin(menu_model_.get(), NULL)); focus_manager_ = NULL; window_ = NULL; std::string type; - if (option.GetString("type", &type) && type == "menubar") - menu_->set_is_popup_menu(false); + //if (option.GetString("type", &type) && type == "menubar") + // menu_->set_is_popup_menu(false); menu_items_.empty(); } void Menu::Destroy() { +#if defined(OS_WIN) for (size_t index = 0; index < icon_bitmaps_.size(); ++index) { ::DeleteObject(icon_bitmaps_[index]); } +#endif } void Menu::Append(MenuItem* menu_item) { @@ -134,7 +141,7 @@ void Menu::Insert(MenuItem* menu_item, int pos) { is_menu_modified_ = true; menu_item->menu_ = this; - + } void Menu::Remove(MenuItem* menu_item, int pos) { @@ -144,7 +151,7 @@ void Menu::Remove(MenuItem* menu_item, int pos) { } void Menu::Popup(int x, int y, content::Shell* shell) { - Rebuild(); + // Rebuild(); // Map point from document to screen. gfx::Point screen_point(x, y); @@ -152,7 +159,7 @@ void Menu::Popup(int x, int y, content::Shell* shell) { // Convert from content coordinates to window coordinates. // This code copied from chrome_web_contents_view_delegate_views.cc aura::Window* web_contents_window = - shell->web_contents()->GetView()->GetNativeView(); + shell->web_contents()->GetNativeView(); aura::Window* root_window = web_contents_window->GetRootWindow(); aura::client::ScreenPositionClient* screen_position_client = aura::client::GetScreenPositionClient(root_window); @@ -160,9 +167,18 @@ void Menu::Popup(int x, int y, content::Shell* shell) { screen_position_client->ConvertPointToScreen(web_contents_window, &screen_point); } - menu_->RunMenuAt(screen_point, views::Menu2::ALIGN_TOPLEFT); + views::MenuRunner runner(menu_model_.get(), views::MenuRunner::CONTEXT_MENU); + if (views::MenuRunner::MENU_DELETED == + runner.RunMenuAt(static_cast(shell->window())->window(), + NULL, + gfx::Rect(screen_point, gfx::Size()), + views::MENU_ANCHOR_TOPRIGHT, + ui::MENU_SOURCE_NONE)) + return; + // menu_->RunMenuAt(screen_point, views::Menu2::ALIGN_TOPLEFT); } +#if defined(OS_WIN) void Menu::Rebuild(const HMENU *parent_menu) { if (is_menu_modified_) { // Refresh menu before show. @@ -207,6 +223,7 @@ void Menu::Rebuild(const HMENU *parent_menu) { is_menu_modified_ = false; } } +#endif void Menu::UpdateKeys(views::FocusManager *focus_manager){ if (focus_manager == NULL){ @@ -222,11 +239,14 @@ void Menu::UpdateKeys(views::FocusManager *focus_manager){ } void Menu::UpdateStates() { +#if defined(OS_WIN) if (window_) window_->menu_->menu_->UpdateStates(); +#endif } -void Menu::SetWindow(nw::NativeWindowWin* win) { +#if defined(OS_WIN) +void Menu::SetWindow(nw::NativeWindowAura* win) { window_ = win; for (int model_index = 0; model_index < menu_model_->GetItemCount(); @@ -238,5 +258,6 @@ void Menu::SetWindow(nw::NativeWindowWin* win) { } } } +#endif } // namespace nwapi diff --git a/src/api/menuitem/menuitem.h b/src/api/menuitem/menuitem.h index f80af28b91..d6aed148ec 100644 --- a/src/api/menuitem/menuitem.h +++ b/src/api/menuitem/menuitem.h @@ -34,10 +34,7 @@ class NSMenuItem; class MenuItemDelegate; #endif // __OBJC__ -#elif defined(TOOLKIT_GTK) -#include -#include "ui/base/gtk/gtk_signal.h" -#elif defined(OS_WIN) +#elif defined(OS_WIN) || defined(OS_LINUX) #include "base/strings/string16.h" #include "ui/gfx/image/image.h" #include "ui/base/accelerators/accelerator.h" @@ -64,9 +61,9 @@ class MenuItem : public Base { const base::ListValue& arguments) OVERRIDE; #if defined(OS_LINUX) - void UpdateKeys(GtkAccelGroup *gtk_accel_group); + void UpdateKeys(views::FocusManager *focus_manager); #endif - + #if defined(OS_WIN) virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE{ if (super_down_flag_){ @@ -89,9 +86,7 @@ class MenuItem : public Base { void UpdateKeys(views::FocusManager *focus_manager); #endif -#if defined(OS_MACOSX) || defined(OS_WIN) void OnClick(); -#endif private: friend class Menu; @@ -107,36 +102,20 @@ class MenuItem : public Base { void SetChecked(bool checked); void SetSubmenu(Menu* sub_menu); -#if defined(OS_LINUX) - GtkAccelGroup *gtk_accel_group; - GdkModifierType modifiers_mask; - guint keyval; - bool enable_shortcut; - Menu* submenu_; - std::string label_; -#endif - #if defined(OS_MACOSX) std::string type_; NSMenuItem* menu_item_; MenuItemDelegate* delegate_; -#elif defined(TOOLKIT_GTK) - GtkWidget* menu_item_; - // Don't send click event on active. - bool block_active_; - - // Callback invoked when user left-clicks on the menu item. - CHROMEGTK_CALLBACK_0(MenuItem, void, OnClick); -#elif defined(OS_WIN) +#elif defined(OS_WIN) || defined(OS_LINUX) friend class MenuDelegate; Menu* menu_; //**Never Try to free this pointer** //We get it from top widget views::FocusManager *focus_manager_; - + ui::Accelerator accelerator_; // Flag to indicate we need refresh. diff --git a/src/api/menuitem/menuitem_win.cc b/src/api/menuitem/menuitem_views.cc similarity index 98% rename from src/api/menuitem/menuitem_win.cc rename to src/api/menuitem/menuitem_views.cc index c28dc5b25b..0d31af2fc8 100644 --- a/src/api/menuitem/menuitem_win.cc +++ b/src/api/menuitem/menuitem_views.cc @@ -1,16 +1,16 @@ // Copyright (c) 2012 Intel Corp // Copyright (c) 2012 The Chromium Authors -// -// Permission is hereby granted, free of charge, to any person obtaining a copy +// +// 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 @@ -96,7 +96,7 @@ void MenuItem::Create(const base::DictionaryValue& option) { int menu_id; if (option.GetInteger("submenu", &menu_id)) SetSubmenu(dispatcher_host()->GetApiObject(menu_id)); -} +} void MenuItem::Destroy() { } @@ -114,8 +114,11 @@ void MenuItem::OnClick() { void MenuItem::SetLabel(const std::string& label) { is_modified_ = true; label_ = base::UTF8ToUTF16(label); + +#if 0//FIXME if (menu_) menu_->UpdateStates(); +#endif } void MenuItem::SetIcon(const std::string& icon) { @@ -159,10 +162,12 @@ void MenuItem::UpdateKeys(views::FocusManager *focus_manager){ } else { focus_manager_ = focus_manager; if (enable_shortcut_){ +#if 0 //FIXME focus_manager->RegisterAccelerator( accelerator_, ui::AcceleratorManager::kHighPriority, - this); + this); +#endif } if (submenu_ != NULL){ submenu_->UpdateKeys(focus_manager); diff --git a/src/api/shortcut/global_shortcut_listener_x11.cc b/src/api/shortcut/global_shortcut_listener_x11.cc index 4064d389e1..11d514248e 100644 --- a/src/api/shortcut/global_shortcut_listener_x11.cc +++ b/src/api/shortcut/global_shortcut_listener_x11.cc @@ -26,10 +26,8 @@ #include "ui/gfx/x/x11_error_tracker.h" #include "ui/gfx/x/x11_types.h" -#if defined(TOOLKIT_GTK) +#if defined(OS_LINUX) #include -#else -#include "base/message_loop/message_pump_x11.h" #endif using content::BrowserThread; @@ -88,7 +86,7 @@ void GlobalShortcutListenerX11::StartListening() { DCHECK(!is_listening_); // Don't start twice. DCHECK(!registered_hot_keys_.empty()); // Also don't start if no hotkey is // registered. -#if defined(TOOLKIT_GTK) +#if defined(OS_LINUX) gdk_window_add_filter(gdk_get_default_root_window(), &GlobalShortcutListenerX11::OnXEventThunk, this); @@ -104,7 +102,7 @@ void GlobalShortcutListenerX11::StopListening() { DCHECK(registered_hot_keys_.empty()); // Make sure the set is clean before // ending. -#if defined(TOOLKIT_GTK) +#if defined(OS_LINUX) gdk_window_remove_filter(NULL, &GlobalShortcutListenerX11::OnXEventThunk, this); @@ -115,14 +113,12 @@ void GlobalShortcutListenerX11::StopListening() { is_listening_ = false; } -#if !defined(TOOLKIT_GTK) uint32_t GlobalShortcutListenerX11::Dispatch(const base::NativeEvent& event) { if (event->type == KeyPress) OnXKeyPressEvent(event); return POST_DISPATCH_NONE; } -#endif bool GlobalShortcutListenerX11::RegisterAcceleratorImpl( const ui::Accelerator& accelerator) { @@ -170,7 +166,7 @@ void GlobalShortcutListenerX11::UnregisterAcceleratorImpl( registered_hot_keys_.erase(accelerator); } -#if defined(TOOLKIT_GTK) +#if defined(OS_LINUX) GdkFilterReturn GlobalShortcutListenerX11::OnXEvent(GdkXEvent* gdk_x_event, GdkEvent* gdk_event) { XEvent* x_event = static_cast(gdk_x_event); diff --git a/src/api/shortcut/global_shortcut_listener_x11.h b/src/api/shortcut/global_shortcut_listener_x11.h index 72d16bc517..473edac78c 100644 --- a/src/api/shortcut/global_shortcut_listener_x11.h +++ b/src/api/shortcut/global_shortcut_listener_x11.h @@ -28,9 +28,9 @@ #include "base/message_loop/message_pump_dispatcher.h" #include "content/nw/src/api/shortcut/global_shortcut_listener.h" -#if defined(TOOLKIT_GTK) +#if defined(OS_LINUX) #include -#include "ui/base/gtk/gtk_signal.h" +#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" #endif // defined(TOOLKIT_GTK) namespace nwapi { @@ -48,10 +48,8 @@ class GlobalShortcutListenerX11 GlobalShortcutListenerX11(); virtual ~GlobalShortcutListenerX11(); -#if !defined(TOOLKIT_GTK) // base::MessagePumpDispatcher implementation. virtual uint32_t Dispatch(const base::NativeEvent& event) OVERRIDE; -#endif private: // GlobalShortcutListener implementation. @@ -62,7 +60,7 @@ class GlobalShortcutListenerX11 virtual void UnregisterAcceleratorImpl( const ui::Accelerator& accelerator) OVERRIDE; -#if defined(TOOLKIT_GTK) +#if defined(OS_LINUX) // Callback for XEvents of the default root window. CHROMEG_CALLBACK_1(GlobalShortcutListenerX11, GdkFilterReturn, OnXEvent, GdkXEvent*, GdkEvent*); diff --git a/src/api/shortcut/shortcut.cc b/src/api/shortcut/shortcut.cc index 63ef73d9b8..16dea75e38 100644 --- a/src/api/shortcut/shortcut.cc +++ b/src/api/shortcut/shortcut.cc @@ -34,7 +34,7 @@ namespace nwapi { ui::Accelerator Parse(const std::string& shortcut) { // Convert to lower case, see // https://github.com/rogerwang/node-webkit/pull/1735. - std::string lower_shortcut = StringToLowerASCII(shortcut); + std::string lower_shortcut = base::StringToLowerASCII(shortcut); std::vector tokens; base::SplitString(lower_shortcut, '+', &tokens); diff --git a/src/api/tray/tray.h b/src/api/tray/tray.h index a0303edb14..338c1a79d0 100644 --- a/src/api/tray/tray.h +++ b/src/api/tray/tray.h @@ -34,9 +34,9 @@ class NSStatusItem; class MacTrayObserver; #endif // __OBJC__ -#elif defined(TOOLKIT_GTK) +#elif defined(OS_LINUX) #include -#include "ui/base/gtk/gtk_signal.h" +#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" #elif defined(OS_WIN) class StatusIcon; class StatusTray; @@ -73,7 +73,7 @@ class Tray : public Base { #if defined(OS_MACOSX) __block NSStatusItem* status_item_; MacTrayObserver* status_observer_; -#elif defined(TOOLKIT_GTK) +#elif defined(OS_LINUX) GtkStatusIcon* status_item_; // Reference to the associated menu. diff --git a/src/api/tray/tray_gtk.cc b/src/api/tray/tray_gtk.cc index cc86c9f86b..33a9078e6d 100644 --- a/src/api/tray/tray_gtk.cc +++ b/src/api/tray/tray_gtk.cc @@ -71,11 +71,13 @@ void Tray::OnClick(GtkWidget* widget) { } void Tray::OnPopupMenu(GtkWidget* widget, guint button, guint time) { +#if 0//FIXME if (menu_) { gtk_menu_popup(GTK_MENU(menu_->menu_), NULL, NULL, gtk_status_icon_position_menu, status_item_, button, time); } +#endif } void Tray::SetAltIcon(const std::string& alticon_path) { diff --git a/src/api/window/window.cc b/src/api/window/window.cc index adfe934653..b0aa7f1def 100644 --- a/src/api/window/window.cc +++ b/src/api/window/window.cc @@ -47,10 +47,10 @@ namespace { const char kCauseKey[] = "cause"; const char kCookieKey[] = "cookie"; -const char kDomainKey[] = "domain"; -const char kIdKey[] = "id"; +//const char kDomainKey[] = "domain"; +//const char kIdKey[] = "id"; const char kRemovedKey[] = "removed"; -const char kTabIdsKey[] = "tabIds"; +//const char kTabIdsKey[] = "tabIds"; // Cause Constants const char kEvictedChangeCause[] = "evicted"; @@ -65,7 +65,7 @@ GURL GetURLFromCanonicalCookie(const net::CanonicalCookie& cookie) { cookie.IsSecure() ? "https" : "http"; const std::string host = domain_key.find('.') != 0 ? domain_key : domain_key.substr(1); - return GURL(scheme + content::kStandardSchemeSeparator + host + "/"); + return GURL(scheme + url::kStandardSchemeSeparator + host + "/"); } void GetCookieListFromStore( @@ -145,7 +145,7 @@ PopulateCookieObject(const net::CanonicalCookie& canonical_cookie) { result->SetBoolean("host_only", net::cookie_util::DomainIsHostOnly( canonical_cookie.Domain())); // A non-UTF8 path is invalid, so we just replace it with an empty string. - result->SetString("path", IsStringUTF8(canonical_cookie.Path()) ? canonical_cookie.Path() + result->SetString("path", base::IsStringUTF8(canonical_cookie.Path()) ? canonical_cookie.Path() : std::string()); result->SetBoolean("secure", canonical_cookie.IsSecure()); result->SetBoolean("http_only", canonical_cookie.IsHttpOnly()); diff --git a/src/api/window_bindings.cc b/src/api/window_bindings.cc index d6436623f1..f760c3cd00 100644 --- a/src/api/window_bindings.cc +++ b/src/api/window_bindings.cc @@ -18,6 +18,7 @@ // 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/window_bindings.h" #include "base/values.h" @@ -26,7 +27,7 @@ #include "content/renderer/render_view_impl.h" #include "grit/nw_resources.h" #undef LOG -using namespace WebCore; +using namespace blink; #if defined(OS_WIN) #define _USE_MATH_DEFINES #include @@ -36,9 +37,10 @@ using namespace WebCore; #include "third_party/WebKit/Source/config.h" #include "third_party/WebKit/Source/core/html/HTMLIFrameElement.h" +#include "third_party/WebKit/Source/core/frame/LocalFrame.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebView.h" -#include "third_party/WebKit/Source/web/WebFrameImpl.h" +#include "third_party/WebKit/Source/web/WebLocalFrameImpl.h" #include "third_party/WebKit/public/web/WebScriptSource.h" #undef CHECK @@ -127,8 +129,8 @@ WindowBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args if (frm->IsNull()) { web_frame = main_frame; }else{ - WebCore::HTMLIFrameElement* iframe = WebCore::V8HTMLIFrameElement::toNative(frm); - web_frame = blink::WebFrameImpl::fromFrame(iframe->contentFrame()); + blink::HTMLIFrameElement* iframe = blink::V8HTMLIFrameElement::toNative(frm); + web_frame = blink::WebFrame::fromFrame(iframe->contentFrame()); } #if defined(OS_WIN) base::string16 jscript((WCHAR*)*v8::String::Value(args[3])); @@ -145,8 +147,8 @@ WindowBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args if (frm->IsNull()) { main_frame->setDevtoolsJail(NULL); }else{ - WebCore::HTMLIFrameElement* iframe = WebCore::V8HTMLIFrameElement::toNative(frm); - main_frame->setDevtoolsJail(blink::WebFrameImpl::fromFrame(iframe->contentFrame())); + blink::HTMLIFrameElement* iframe = blink::V8HTMLIFrameElement::toNative(frm); + main_frame->setDevtoolsJail(blink::WebFrame::fromFrame(iframe->contentFrame())); } args.GetReturnValue().Set(v8::Undefined(isolate)); return; @@ -183,8 +185,8 @@ WindowBindings::CallObjectMethodSync(const v8::FunctionCallbackInfo& args.GetReturnValue().Set(scope.Escape(array)); return; }else if (method == "SetZoomLevel") { - double zoom_level = args[2]->ToNumber()->Value(); - render_view->OnSetZoomLevel(zoom_level); + // double zoom_level = args[2]->ToNumber()->Value(); + //FIXME: render_view->OnSetZoomLevel(zoom_level); args.GetReturnValue().Set(v8::Undefined(isolate)); return; } diff --git a/src/breakpad_linux.cc b/src/breakpad_linux.cc index d9d7a3e339..2f1d8fcb49 100644 --- a/src/breakpad_linux.cc +++ b/src/breakpad_linux.cc @@ -29,7 +29,6 @@ #include "base/files/file_path.h" #include "base/linux_util.h" #include "base/path_service.h" -#include "base/platform_file.h" #include "base/posix/eintr_wrapper.h" #include "base/posix/global_descriptors.h" #include "base/process/memory.h" @@ -197,27 +196,11 @@ size_t LengthWithoutTrailingSpaces(const char* str, size_t len) { return len; } -// Populates the passed in allocated string and its size with the distro of -// the crashing process. -// The passed string is expected to be at least kDistroSize bytes long. -void PopulateDistro(char* distro, size_t* distro_len_param) { - size_t distro_len = std::min(my_strlen(base::g_linux_distro), kDistroSize); - memcpy(distro, base::g_linux_distro, distro_len); - if (distro_len_param) - *distro_len_param = distro_len; -} - void SetClientIdFromCommandLine(const CommandLine& command_line) { // Get the guid and linux distro from the command line switch. std::string switch_value = command_line.GetSwitchValueASCII(switches::kEnableCrashReporter); - size_t separator = switch_value.find(","); - if (separator != std::string::npos) { - GetBreakpadClient()->SetClientID(switch_value.substr(0, separator)); - base::SetLinuxDistro(switch_value.substr(separator + 1)); - } else { - GetBreakpadClient()->SetClientID(switch_value); - } + GetBreakpadClient()->SetBreakpadClientIdFromGUID(switch_value); } // MIME substrings. @@ -690,11 +673,8 @@ bool CrashDoneInProcessNoUpload( // Start constructing the message to send to the browser. char guid[kGuidSize + 1] = {0}; char crash_url[kMaxActiveURLSize + 1] = {0}; - char distro[kDistroSize + 1] = {0}; size_t guid_length = 0; size_t crash_url_length = 0; - size_t distro_length = 0; - PopulateDistro(distro, &distro_length); BreakpadInfo info = {0}; info.filename = NULL; info.fd = descriptor.fd(); @@ -702,8 +682,8 @@ bool CrashDoneInProcessNoUpload( info.process_type_length = my_strlen(g_process_type); info.crash_url = crash_url; info.crash_url_length = crash_url_length; - info.distro = distro; - info.distro_length = distro_length; + info.distro = base::g_linux_distro; + info.distro_length = my_strlen(base::g_linux_distro); info.upload = false; info.process_start_time = g_process_start_time; HandleCrashDump(info); diff --git a/src/browser/autofill_popup_controller_impl.cc b/src/browser/autofill_popup_controller_impl.cc index c85210e31b..40bc8fab13 100644 --- a/src/browser/autofill_popup_controller_impl.cc +++ b/src/browser/autofill_popup_controller_impl.cc @@ -153,13 +153,13 @@ void AutofillPopupControllerImpl::Show( names_[i] = gfx::ElideText(names_[i], GetNameFontListForRow(i), name_size, - gfx::ELIDE_AT_END); + gfx::ELIDE_TAIL); int subtext_size = available_width * subtext_width / total_text_length; subtexts_[i] = gfx::ElideText(subtexts_[i], subtext_font_list(), subtext_size, - gfx::ELIDE_AT_END); + gfx::ELIDE_TAIL); } #endif @@ -320,15 +320,6 @@ void AutofillPopupControllerImpl::SelectionCleared() { SetSelectedLine(kNoSelection); } -bool AutofillPopupControllerImpl::ShouldRepostEvent( - const ui::MouseEvent& event) { - return delegate_->ShouldRepostEvent(event); -} - -bool AutofillPopupControllerImpl::ShouldHideOnOutsideClick() const { - return hide_on_outside_click_; -} - void AutofillPopupControllerImpl::AcceptSuggestion(size_t index) { delegate_->DidAcceptSuggestion(full_names_[index], identifiers_[index]); } diff --git a/src/browser/autofill_popup_controller_impl.h b/src/browser/autofill_popup_controller_impl.h index 899c50b145..ca4de53c81 100644 --- a/src/browser/autofill_popup_controller_impl.h +++ b/src/browser/autofill_popup_controller_impl.h @@ -77,8 +77,6 @@ class AutofillPopupControllerImpl : public AutofillPopupController { virtual void SetSelectionAtPoint(const gfx::Point& point) OVERRIDE; virtual bool AcceptSelectedLine() OVERRIDE; virtual void SelectionCleared() OVERRIDE; - virtual bool ShouldRepostEvent(const ui::MouseEvent& event) OVERRIDE; - virtual bool ShouldHideOnOutsideClick() const OVERRIDE; virtual void AcceptSuggestion(size_t index) OVERRIDE; virtual int GetIconResourceID( const base::string16& resource_name) const OVERRIDE; diff --git a/src/browser/capture_page_helper.cc b/src/browser/capture_page_helper.cc index a62634c1a1..8743582ae2 100644 --- a/src/browser/capture_page_helper.cc +++ b/src/browser/capture_page_helper.cc @@ -88,7 +88,7 @@ void CapturePageHelper::StartCapturePage(const std::string& image_format_str) { gfx::Rect(), view->GetViewBounds().size(), base::Bind(&CapturePageHelper::CopyFromBackingStoreComplete, - this), SkBitmap::kARGB_8888_Config); + this), kN32_SkColorType); } void CapturePageHelper::CopyFromBackingStoreComplete( diff --git a/src/browser/color_chooser_gtk.cc b/src/browser/color_chooser_gtk.cc index 9a33769d1e..131007d38c 100644 --- a/src/browser/color_chooser_gtk.cc +++ b/src/browser/color_chooser_gtk.cc @@ -7,9 +7,9 @@ #include "content/public/browser/color_chooser.h" #include "content/public/browser/web_contents.h" #include "grit/nw_resources.h" -#include "ui/base/gtk/gtk_signal.h" +//#include "ui/base/gtk/gtk_signal.h" #include "ui/base/l10n/l10n_util.h" -#include "ui/gfx/skia_utils_gtk.h" +//#include "ui/gfx/skia_utils_gtk.h" class ColorChooserGtk : public content::ColorChooser { public: diff --git a/src/browser/file_select_helper.cc b/src/browser/file_select_helper.cc index c41b131658..484859dd7e 100644 --- a/src/browser/file_select_helper.cc +++ b/src/browser/file_select_helper.cc @@ -24,7 +24,6 @@ #include "base/bind.h" #include "base/file_util.h" -#include "base/platform_file.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/strings/string_split.h" @@ -295,7 +294,7 @@ FileSelectHelper::GetFileTypesFromAcceptType( // dialog uses the first extension in the list to form the description, // like "EHTML Files". This is not what we want. if (valid_type_count > 1 || - (valid_type_count == 1 && !description_id == 0 && extensions->size() > 1)) + (valid_type_count == 1 && description_id == 0 && extensions->size() > 1)) description_id = IDS_CUSTOM_FILES; if (description_id) { @@ -478,7 +477,7 @@ bool FileSelectHelper::IsAcceptTypeValid(const std::string& accept_type) { // of an extension or a "/" in the case of a MIME type). std::string unused; if (accept_type.length() <= 1 || - StringToLowerASCII(accept_type) != accept_type || + base::StringToLowerASCII(accept_type) != accept_type || base::TrimWhitespaceASCII(accept_type, base::TRIM_ALL, &unused) != base::TRIM_NONE) { return false; } diff --git a/src/browser/native_window.cc b/src/browser/native_window.cc index 51f4ae5e8d..2fbc31214a 100644 --- a/src/browser/native_window.cc +++ b/src/browser/native_window.cc @@ -32,8 +32,8 @@ #if defined(OS_MACOSX) #include "content/nw/src/browser/native_window_helper_mac.h" -#elif defined(TOOLKIT_GTK) -#include "content/nw/src/browser/native_window_gtk.h" +#elif defined(OS_LINUX) +#include "content/nw/src/browser/native_window_aura.h" #elif defined(OS_WIN) #include "content/nw/src/browser/native_window_win.h" #endif @@ -52,8 +52,8 @@ NativeWindow* NativeWindow::Create(const base::WeakPtr& shell, // Create window. NativeWindow* window = -#if defined(TOOLKIT_GTK) - new NativeWindowGtk(shell, manifest); +#if defined(OS_LINUX) + new NativeWindowAura(shell, manifest); #elif defined(OS_MACOSX) CreateNativeWindowCocoa(shell, manifest); #elif defined(OS_WIN) diff --git a/src/browser/native_window_win.cc b/src/browser/native_window_aura.cc similarity index 81% rename from src/browser/native_window_win.cc rename to src/browser/native_window_aura.cc index 5bbe361c50..cb055ff2e8 100644 --- a/src/browser/native_window_win.cc +++ b/src/browser/native_window_aura.cc @@ -1,16 +1,16 @@ // Copyright (c) 2012 Intel Corp // Copyright (c) 2012 The Chromium Authors -// -// Permission is hereby granted, free of charge, to any person obtaining a copy +// +// 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 @@ -18,33 +18,41 @@ // 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_win.h" +#include "content/nw/src/browser/native_window_aura.h" +#if defined(OS_WIN) #include +#endif #include "base/strings/utf_string_conversions.h" #include "base/values.h" + +#if defined(OS_WIN) #include "base/win/scoped_comptr.h" #include "base/win/windows_version.h" #include "base/win/wrapped_window_proc.h" +#endif + #include "chrome/browser/platform_util.h" #include "content/nw/src/api/menu/menu.h" -#include "content/nw/src/browser/native_window_toolbar_win.h" +#include "content/nw/src/browser/native_window_toolbar_aura.h" #include "content/nw/src/common/shell_switches.h" #include "content/nw/src/nw_shell.h" #include "content/public/browser/native_web_keyboard_event.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 "content/public/browser/web_contents_view.h" #include "extensions/common/draggable_region.h" #include "third_party/skia/include/core/SkPaint.h" #include "ui/base/hit_test.h" #include "ui/gfx/native_widget_types.h" +#if defined(OS_WIN) #include "ui/gfx/win/hwnd_util.h" +#include "ui/gfx/icon_util.h" +#include "ui/views/win/hwnd_util.h" +#endif #include "ui/gfx/path.h" #include "ui/gfx/canvas.h" -#include "ui/gfx/icon_util.h" #include "ui/gfx/font_list.h" #include "ui/gfx/platform_font.h" #include "ui/gfx/image/image_skia_operations.h" @@ -53,7 +61,6 @@ #include "ui/views/views_delegate.h" #include "ui/views/widget/widget.h" #include "ui/views/window/native_frame_view.h" -#include "ui/views/win/hwnd_util.h" #include "ui/views/widget/native_widget_private.h" #include "ui/events/event_handler.h" #include "ui/wm/core/easy_resize_window_targeter.h" @@ -86,7 +93,7 @@ bool IsParent(gfx::NativeView child, gfx::NativeView possible_parent) { return true; #endif gfx::NativeView parent = child; - while ((parent = (gfx::NativeView)::GetParent((HWND)parent))) { + while ((parent = (gfx::NativeView)platform_util::GetParent(parent))) { if (possible_parent == parent) return true; } @@ -119,7 +126,7 @@ class NativeWindowFrameView : public views::NonClientFrameView { public: static const char kViewClassName[]; - explicit NativeWindowFrameView(NativeWindowWin* window); + explicit NativeWindowFrameView(NativeWindowAura* window); virtual ~NativeWindowFrameView(); void Init(views::Widget* frame); @@ -136,15 +143,15 @@ class NativeWindowFrameView : public views::NonClientFrameView { virtual void UpdateWindowTitle() OVERRIDE {} // views::View implementation. - virtual gfx::Size GetPreferredSize() OVERRIDE; + virtual gfx::Size GetPreferredSize() const OVERRIDE; virtual void Layout() OVERRIDE; virtual const char* GetClassName() const OVERRIDE; virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; - virtual gfx::Size GetMinimumSize() OVERRIDE; - virtual gfx::Size GetMaximumSize() OVERRIDE; + virtual gfx::Size GetMinimumSize() const OVERRIDE; + virtual gfx::Size GetMaximumSize() const OVERRIDE; private: - NativeWindowWin* window_; + NativeWindowAura* window_; views::Widget* frame_; DISALLOW_COPY_AND_ASSIGN(NativeWindowFrameView); @@ -153,7 +160,7 @@ class NativeWindowFrameView : public views::NonClientFrameView { const char NativeWindowFrameView::kViewClassName[] = "content/nw/src/browser/NativeWindowFrameView"; -NativeWindowFrameView::NativeWindowFrameView(NativeWindowWin* window) +NativeWindowFrameView::NativeWindowFrameView(NativeWindowAura* window) : window_(window), frame_(NULL) { } @@ -230,7 +237,7 @@ void NativeWindowFrameView::GetWindowMask(const gfx::Size& size, // We got nothing to say about no window mask. } -gfx::Size NativeWindowFrameView::GetPreferredSize() { +gfx::Size NativeWindowFrameView::GetPreferredSize() const { gfx::Size pref = frame_->client_view()->GetPreferredSize(); gfx::Rect bounds(0, 0, pref.width(), pref.height()); return frame_->non_client_view()->GetWindowBoundsForClientBounds( @@ -247,21 +254,21 @@ const char* NativeWindowFrameView::GetClassName() const { return kViewClassName; } -gfx::Size NativeWindowFrameView::GetMinimumSize() { +gfx::Size NativeWindowFrameView::GetMinimumSize() const { return frame_->client_view()->GetMinimumSize(); } -gfx::Size NativeWindowFrameView::GetMaximumSize() { +gfx::Size NativeWindowFrameView::GetMaximumSize() const { return frame_->client_view()->GetMaximumSize(); } } // namespace -NativeWindowWin::NativeWindowWin(const base::WeakPtr& shell, +NativeWindowAura::NativeWindowAura(const base::WeakPtr& shell, base::DictionaryValue* manifest) : NativeWindow(shell, manifest), - web_view_(NULL), toolbar_(NULL), + web_view_(NULL), is_fullscreen_(false), is_minimized_(false), is_maximized_(false), @@ -278,7 +285,6 @@ NativeWindowWin::NativeWindowWin(const base::WeakPtr& shell, window_ = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.delegate = this; - params.top_level = true; params.remove_standard_frame = !has_frame(); params.use_system_default_icon = true; window_->Init(params); @@ -290,7 +296,7 @@ NativeWindowWin::NativeWindowWin(const base::WeakPtr& shell, int width, height; manifest->GetInteger(switches::kmWidth, &width); manifest->GetInteger(switches::kmHeight, &height); - gfx::Rect window_bounds = + gfx::Rect window_bounds = window_->non_client_view()->GetWindowBoundsForClientBounds( gfx::Rect(width,height)); last_width_ = width; @@ -305,27 +311,29 @@ NativeWindowWin::NativeWindowWin(const base::WeakPtr& shell, window_->SetInitialFocus(ui::SHOW_STATE_NORMAL); } -NativeWindowWin::~NativeWindowWin() { +NativeWindowAura::~NativeWindowAura() { +#if defined(OS_WIN) FOR_EACH_OBSERVER(web_modal::ModalDialogHostObserver, observer_list_, OnHostDestroying()); +#endif views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); } -void NativeWindowWin::Close() { +void NativeWindowAura::Close() { window_->Close(); } -void NativeWindowWin::Move(const gfx::Rect& bounds) { +void NativeWindowAura::Move(const gfx::Rect& bounds) { window_->SetBounds(bounds); } -void NativeWindowWin::Focus(bool focus) { +void NativeWindowAura::Focus(bool focus) { window_->Activate(); } -void NativeWindowWin::Show() { - VLOG(1) << "NativeWindowWin::Show(); initial_focus = " << initial_focus_; +void NativeWindowAura::Show() { + VLOG(1) << "NativeWindowAura::Show(); initial_focus = " << initial_focus_; if (is_maximized_) window_->native_widget_private()->ShowWithWindowState(ui::SHOW_STATE_MAXIMIZED); else if (!initial_focus_) { @@ -335,27 +343,27 @@ void NativeWindowWin::Show() { window_->native_widget_private()->Show(); } -void NativeWindowWin::Hide() { +void NativeWindowAura::Hide() { window_->Hide(); } -void NativeWindowWin::Maximize() { +void NativeWindowAura::Maximize() { window_->Maximize(); } -void NativeWindowWin::Unmaximize() { +void NativeWindowAura::Unmaximize() { window_->Restore(); } -void NativeWindowWin::Minimize() { +void NativeWindowAura::Minimize() { window_->Minimize(); } -void NativeWindowWin::Restore() { +void NativeWindowAura::Restore() { window_->Restore(); } -void NativeWindowWin::SetFullscreen(bool fullscreen) { +void NativeWindowAura::SetFullscreen(bool fullscreen) { is_fullscreen_ = fullscreen; window_->SetFullscreen(fullscreen); if (shell()) { @@ -366,31 +374,32 @@ void NativeWindowWin::SetFullscreen(bool fullscreen) { } } -bool NativeWindowWin::IsFullscreen() { +bool NativeWindowAura::IsFullscreen() { return is_fullscreen_; } -void NativeWindowWin::SetSize(const gfx::Size& size) { +void NativeWindowAura::SetSize(const gfx::Size& size) { window_->SetSize(size); } -gfx::Size NativeWindowWin::GetSize() { +gfx::Size NativeWindowAura::GetSize() { return window_->GetWindowBoundsInScreen().size(); } -void NativeWindowWin::SetMinimumSize(int width, int height) { +void NativeWindowAura::SetMinimumSize(int width, int height) { minimum_size_.set_width(width); minimum_size_.set_height(height); } -void NativeWindowWin::SetMaximumSize(int width, int height) { +void NativeWindowAura::SetMaximumSize(int width, int height) { maximum_size_.set_width(width); maximum_size_.set_height(height); } -void NativeWindowWin::SetResizable(bool resizable) { +void NativeWindowAura::SetResizable(bool resizable) { resizable_ = resizable; +#if 0 //FIXME // Show/Hide the maximize button. DWORD style = ::GetWindowLong(views::HWNDForWidget(window_), GWL_STYLE); if (resizable) @@ -398,9 +407,11 @@ void NativeWindowWin::SetResizable(bool resizable) { else style &= ~WS_MAXIMIZEBOX; ::SetWindowLong(views::HWNDForWidget(window_), GWL_STYLE, style); +#endif } -void NativeWindowWin::SetShowInTaskbar(bool show) { +void NativeWindowAura::SetShowInTaskbar(bool show) { +#if defined(OS_WIN) if (show == false && base::win::GetVersion() < base::win::VERSION_VISTA) { // Change the owner of native window. Only needed on Windows XP. ::SetWindowLong(views::HWNDForWidget(window_), @@ -431,16 +442,17 @@ void NativeWindowWin::SetShowInTaskbar(bool show) { LOG(ERROR) << "Failed to change the show in taskbar attribute"; return; } +#endif } -void NativeWindowWin::SetAlwaysOnTop(bool top) { +void NativeWindowAura::SetAlwaysOnTop(bool top) { window_->StackAtTop(); // SetAlwaysOnTop should be called after StackAtTop because otherwise // the top-most flag will be removed. window_->SetAlwaysOnTop(top); } -void NativeWindowWin::OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) { +void NativeWindowAura::OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) { int w = new_bounds.width(); int h = new_bounds.height(); if (shell() && (w != last_width_ || h != last_height_)) { @@ -453,11 +465,12 @@ void NativeWindowWin::OnWidgetBoundsChanged(views::Widget* widget, const gfx::Re } } -void NativeWindowWin::SetPosition(const std::string& position) { +void NativeWindowAura::SetPosition(const std::string& position) { if (position == "center") { gfx::Rect bounds = window_->GetWindowBoundsInScreen(); window_->CenterWindow(gfx::Size(bounds.width(), bounds.height())); } else if (position == "mouse") { +#if defined(OS_WIN) //FIXME gfx::Rect bounds = window_->GetWindowBoundsInScreen(); POINT pt; if (::GetCursorPos(&pt)) { @@ -467,19 +480,21 @@ void NativeWindowWin::SetPosition(const std::string& position) { bounds.set_y(y > 0 ? y : 0); window_->SetBoundsConstrained(bounds); } +#endif } } -void NativeWindowWin::SetPosition(const gfx::Point& position) { +void NativeWindowAura::SetPosition(const gfx::Point& position) { gfx::Rect bounds = window_->GetWindowBoundsInScreen(); window_->SetBounds(gfx::Rect(position, bounds.size())); } -gfx::Point NativeWindowWin::GetPosition() { +gfx::Point NativeWindowAura::GetPosition() { return window_->GetWindowBoundsInScreen().origin(); } -void NativeWindowWin::FlashFrame(int count) { +void NativeWindowAura::FlashFrame(int count) { +#if defined(OS_WIN) //FIXME FLASHWINFO fwi; fwi.cbSize = sizeof(fwi); fwi.hwnd = views::HWNDForWidget(window_); @@ -492,8 +507,10 @@ void NativeWindowWin::FlashFrame(int count) { fwi.dwFlags = FLASHW_STOP; } FlashWindowEx(&fwi); +#endif } +#if defined(OS_WIN) HICON createBadgeIcon(const HWND hWnd, const TCHAR *value, const int sizeX, const int sizeY) { // canvas for the overlay icon gfx::Canvas canvas(gfx::Size(sizeX, sizeY), 1, false); @@ -515,8 +532,10 @@ HICON createBadgeIcon(const HWND hWnd, const TCHAR *value, const int sizeX, cons // return the canvas as windows native icon handle return IconUtil::CreateHICONFromSkBitmap(canvas.ExtractImageRep().sk_bitmap()); } +#endif -void NativeWindowWin::SetBadgeLabel(const std::string& badge) { +void NativeWindowAura::SetBadgeLabel(const std::string& badge) { +#if defined(OS_WIN) base::win::ScopedComPtr taskbar; HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER); @@ -539,28 +558,30 @@ void NativeWindowWin::SetBadgeLabel(const std::string& badge) { taskbar->SetOverlayIcon(hWnd, icon, L"Status"); DestroyIcon(icon); +#endif } -void NativeWindowWin::SetProgressBar(double progress) { +void NativeWindowAura::SetProgressBar(double progress) { +#if defined(OS_WIN) base::win::ScopedComPtr taskbar; HRESULT result = taskbar.CreateInstance(CLSID_TaskbarList, NULL, CLSCTX_INPROC_SERVER); - + if (FAILED(result)) { VLOG(1) << "Failed creating a TaskbarList3 object: " << result; return; } - + result = taskbar->HrInit(); if (FAILED(result)) { LOG(ERROR) << "Failed initializing an ITaskbarList3 interface."; return; } - + HWND hWnd = views::HWNDForWidget(window_); - + TBPFLAG tbpFlag = TBPF_NOPROGRESS; - + if (progress > 1) { tbpFlag = TBPF_INDETERMINATE; } @@ -568,23 +589,25 @@ void NativeWindowWin::SetProgressBar(double progress) { tbpFlag = TBPF_NORMAL; taskbar->SetProgressValue(hWnd, progress * 100, 100); } - + taskbar->SetProgressState(hWnd, tbpFlag); +#endif } -void NativeWindowWin::SetKiosk(bool kiosk) { +void NativeWindowAura::SetKiosk(bool kiosk) { SetFullscreen(kiosk); } -bool NativeWindowWin::IsKiosk() { +bool NativeWindowAura::IsKiosk() { return IsFullscreen(); } -void NativeWindowWin::SetMenu(nwapi::Menu* menu) { +void NativeWindowAura::SetMenu(nwapi::Menu* menu) { window_->set_has_menu_bar(true); menu_ = menu; // The menu is lazily built. +#if defined(OS_WIN) //FIXME menu->Rebuild(); menu->SetWindow(this); @@ -592,43 +615,44 @@ void NativeWindowWin::SetMenu(nwapi::Menu* menu) { ::SetMenu(views::HWNDForWidget(window_), menu->menu_->GetNativeMenu()); menu->UpdateKeys( window_->GetFocusManager() ); +#endif } -void NativeWindowWin::SetTitle(const std::string& title) { +void NativeWindowAura::SetTitle(const std::string& title) { title_ = title; window_->UpdateWindowTitle(); } -void NativeWindowWin::AddToolbar() { - toolbar_ = new NativeWindowToolbarWin(shell()); +void NativeWindowAura::AddToolbar() { + toolbar_ = new NativeWindowToolbarAura(shell()); AddChildViewAt(toolbar_, 0); } -void NativeWindowWin::SetToolbarButtonEnabled(TOOLBAR_BUTTON button, +void NativeWindowAura::SetToolbarButtonEnabled(TOOLBAR_BUTTON button, bool enabled) { if (toolbar_) toolbar_->SetButtonEnabled(button, enabled); } -void NativeWindowWin::SetToolbarUrlEntry(const std::string& url) { +void NativeWindowAura::SetToolbarUrlEntry(const std::string& url) { if (toolbar_) toolbar_->SetUrlEntry(url); } - -void NativeWindowWin::SetToolbarIsLoading(bool loading) { + +void NativeWindowAura::SetToolbarIsLoading(bool loading) { if (toolbar_) toolbar_->SetIsLoading(loading); } -views::View* NativeWindowWin::GetContentsView() { +views::View* NativeWindowAura::GetContentsView() { return this; } -views::ClientView* NativeWindowWin::CreateClientView(views::Widget* widget) { +views::ClientView* NativeWindowAura::CreateClientView(views::Widget* widget) { return new NativeWindowClientView(widget, GetContentsView(), shell_); } -views::NonClientFrameView* NativeWindowWin::CreateNonClientFrameView( +views::NonClientFrameView* NativeWindowAura::CreateNonClientFrameView( views::Widget* widget) { if (has_frame()) return new views::NativeFrameView(GetWidget()); @@ -638,7 +662,7 @@ views::NonClientFrameView* NativeWindowWin::CreateNonClientFrameView( return frame_view; } -void NativeWindowWin::OnWidgetMove() { +void NativeWindowAura::OnWidgetMove() { gfx::Point origin = GetPosition(); if (shell()) { base::ListValue args; @@ -648,39 +672,39 @@ void NativeWindowWin::OnWidgetMove() { } } -bool NativeWindowWin::CanResize() const { +bool NativeWindowAura::CanResize() const { return resizable_; } -bool NativeWindowWin::CanMaximize() const { +bool NativeWindowAura::CanMaximize() const { return resizable_; } -views::Widget* NativeWindowWin::GetWidget() { +views::Widget* NativeWindowAura::GetWidget() { return window_; } -const views::Widget* NativeWindowWin::GetWidget() const { +const views::Widget* NativeWindowAura::GetWidget() const { return window_; } -base::string16 NativeWindowWin::GetWindowTitle() const { +base::string16 NativeWindowAura::GetWindowTitle() const { return base::UTF8ToUTF16(title_); } -void NativeWindowWin::DeleteDelegate() { +void NativeWindowAura::DeleteDelegate() { OnNativeWindowDestory(); } -bool NativeWindowWin::ShouldShowWindowTitle() const { +bool NativeWindowAura::ShouldShowWindowTitle() const { return has_frame(); } -bool NativeWindowWin::ShouldHandleOnSize() const { +bool NativeWindowAura::ShouldHandleOnSize() const { return true; } -void NativeWindowWin::OnNativeFocusChange(gfx::NativeView focused_before, +void NativeWindowAura::OnNativeFocusChange(gfx::NativeView focused_before, gfx::NativeView focused_now) { gfx::NativeView this_window = GetWidget()->GetNativeView(); if (IsParent(focused_now, this_window) || @@ -700,7 +724,7 @@ void NativeWindowWin::OnNativeFocusChange(gfx::NativeView focused_before, } } -gfx::ImageSkia NativeWindowWin::GetWindowAppIcon() { +gfx::ImageSkia NativeWindowAura::GetWindowAppIcon() { gfx::Image icon = app_icon(); if (icon.IsEmpty()) return gfx::ImageSkia(); @@ -716,7 +740,7 @@ gfx::ImageSkia NativeWindowWin::GetWindowAppIcon() { #endif } -gfx::ImageSkia NativeWindowWin::GetWindowIcon() { +gfx::ImageSkia NativeWindowAura::GetWindowIcon() { gfx::Image icon = app_icon(); if (icon.IsEmpty()) return gfx::ImageSkia(); @@ -724,11 +748,11 @@ gfx::ImageSkia NativeWindowWin::GetWindowIcon() { return *icon.ToImageSkia(); } -views::View* NativeWindowWin::GetInitiallyFocusedView() { +views::View* NativeWindowAura::GetInitiallyFocusedView() { return web_view_; } -void NativeWindowWin::UpdateDraggableRegions( +void NativeWindowAura::UpdateDraggableRegions( const std::vector& regions) { // Draggable region is not supported for non-frameless window. if (has_frame()) @@ -754,7 +778,7 @@ void NativeWindowWin::UpdateDraggableRegions( OnViewWasResized(); } -void NativeWindowWin::HandleKeyboardEvent( +void NativeWindowAura::HandleKeyboardEvent( const content::NativeWebKeyboardEvent& event) { unhandled_keyboard_event_handler_.HandleKeyboardEvent(event, GetFocusManager()); @@ -765,7 +789,7 @@ void NativeWindowWin::HandleKeyboardEvent( // event.os_event.wParam, event.os_event.lParam); } -void NativeWindowWin::Layout() { +void NativeWindowAura::Layout() { DCHECK(web_view_); if (toolbar_) { toolbar_->SetBounds(0, 0, width(), 34); @@ -776,7 +800,7 @@ void NativeWindowWin::Layout() { OnViewWasResized(); } -void NativeWindowWin::ViewHierarchyChanged( +void NativeWindowAura::ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) { if (details.is_add && details.child == this) { views::BoxLayout* layout = new views::BoxLayout( @@ -789,23 +813,36 @@ void NativeWindowWin::ViewHierarchyChanged( } } -gfx::Size NativeWindowWin::GetMinimumSize() { +gfx::Size NativeWindowAura::GetMinimumSize() const { return minimum_size_; } -gfx::Size NativeWindowWin::GetMaximumSize() { +gfx::Size NativeWindowAura::GetMaximumSize() const { return maximum_size_; } -void NativeWindowWin::OnFocus() { +void NativeWindowAura::OnFocus() { web_view_->RequestFocus(); } -void NativeWindowWin::SetInitialFocus(bool initial_focus) { +bool NativeWindowAura::InitialFocus() { + return initial_focus_; +} + +bool NativeWindowAura::AcceleratorPressed(const ui::Accelerator& accelerator) { + return true; +} + +bool NativeWindowAura::CanHandleAccelerators() const { + return true; +} + +void NativeWindowAura::SetInitialFocus(bool initial_focus) { initial_focus_ = initial_focus; } -bool NativeWindowWin::ExecuteWindowsCommand(int command_id) { +bool NativeWindowAura::ExecuteWindowsCommand(int command_id) { +#if defined(OS_WIN) // Windows uses the 4 lower order bits of |command_id| for type-specific // information so we must exclude this when comparing. static const int sc_mask = 0xFFF0; @@ -823,10 +860,12 @@ bool NativeWindowWin::ExecuteWindowsCommand(int command_id) { if (shell()) shell()->SendEvent("unmaximize"); } +#endif return false; } -bool NativeWindowWin::HandleSize(unsigned int param, const gfx::Size& size) { +bool NativeWindowAura::HandleSize(unsigned int param, const gfx::Size& size) { +#if defined(OS_WIN) if (param == SIZE_MAXIMIZED) { is_maximized_ = true; if (shell()) @@ -836,25 +875,28 @@ bool NativeWindowWin::HandleSize(unsigned int param, const gfx::Size& size) { if (shell()) shell()->SendEvent("unmaximize"); } +#endif return false; } -bool NativeWindowWin::ExecuteAppCommand(int command_id) { +bool NativeWindowAura::ExecuteAppCommand(int command_id) { +#if defined(OS_WIN) if (menu_) { menu_->menu_delegate_->ExecuteCommand(command_id, 0); menu_->menu_->UpdateStates(); } - +#endif return false; } -void NativeWindowWin::SaveWindowPlacement(const gfx::Rect& bounds, +void NativeWindowAura::SaveWindowPlacement(const gfx::Rect& bounds, ui::WindowShowState show_state) { // views::WidgetDelegate::SaveWindowPlacement(bounds, show_state); } -void NativeWindowWin::OnViewWasResized() { +void NativeWindowAura::OnViewWasResized() { // Set the window shape of the RWHV. +#if defined(OS_WIN) DCHECK(window_); DCHECK(web_view_); gfx::Size sz = web_view_->size(); @@ -883,9 +925,10 @@ void NativeWindowWin::OnViewWasResized() { if (web_contents()->GetRenderViewHost()->GetView()) web_contents()->GetRenderViewHost()->GetView()->SetClickthroughRegion(rgn); #endif +#endif } -void NativeWindowWin::InstallEasyResizeTargeterOnContainer() { +void NativeWindowAura::InstallEasyResizeTargeterOnContainer() { aura::Window* window = window_->GetNativeWindow(); gfx::Insets inset(kResizeInsideBoundsSize, kResizeInsideBoundsSize, kResizeInsideBoundsSize, kResizeInsideBoundsSize); @@ -896,11 +939,11 @@ void NativeWindowWin::InstallEasyResizeTargeterOnContainer() { new wm::EasyResizeWindowTargeter(window, inset, inset))); } -bool NativeWindowWin::ShouldDescendIntoChildForEventHandling( +bool NativeWindowAura::ShouldDescendIntoChildForEventHandling( gfx::NativeView child, const gfx::Point& location) { #if defined(USE_AURA) - if (child->Contains(web_view_->web_contents()->GetView()->GetNativeView())) { + if (child->Contains(web_view_->web_contents()->GetNativeView())) { // App window should claim mouse events that fall within the draggable // region. return !draggable_region_.get() || @@ -911,26 +954,26 @@ bool NativeWindowWin::ShouldDescendIntoChildForEventHandling( return true; } -gfx::NativeView NativeWindowWin::GetHostView() const { +gfx::NativeView NativeWindowAura::GetHostView() const { return window_->GetNativeView(); } -gfx::Size NativeWindowWin::GetMaximumDialogSize() { +gfx::Size NativeWindowAura::GetMaximumDialogSize() { return window_->GetWindowBoundsInScreen().size(); } -gfx::Point NativeWindowWin::GetDialogPosition(const gfx::Size& size) { +gfx::Point NativeWindowAura::GetDialogPosition(const gfx::Size& size) { gfx::Size app_window_size = window_->GetWindowBoundsInScreen().size(); return gfx::Point(app_window_size.width() / 2 - size.width() / 2, app_window_size.height() / 2 - size.height() / 2); } -void NativeWindowWin::AddObserver(web_modal::ModalDialogHostObserver* observer) { +void NativeWindowAura::AddObserver(web_modal::ModalDialogHostObserver* observer) { if (observer && !observer_list_.HasObserver(observer)) observer_list_.AddObserver(observer); } -void NativeWindowWin::RemoveObserver(web_modal::ModalDialogHostObserver* observer) { +void NativeWindowAura::RemoveObserver(web_modal::ModalDialogHostObserver* observer) { observer_list_.RemoveObserver(observer); } diff --git a/src/browser/native_window_win.h b/src/browser/native_window_aura.h similarity index 91% rename from src/browser/native_window_win.h rename to src/browser/native_window_aura.h index 33b27b2c5f..7076d2167a 100644 --- a/src/browser/native_window_win.h +++ b/src/browser/native_window_aura.h @@ -23,8 +23,11 @@ #include "content/nw/src/browser/native_window.h" +#include "components/web_modal/web_contents_modal_dialog_host.h" #include "third_party/skia/include/core/SkRegion.h" +#if defined(OS_WIN) #include "ui/base/win/hidden_window.h" +#endif #include "ui/gfx/image/image_skia.h" #include "ui/gfx/rect.h" #include "ui/views/focus/widget_focus_manager.h" @@ -46,19 +49,20 @@ class Menu; namespace nw { -class NativeWindowToolbarWin; +class NativeWindowToolbarAura; -class NativeWindowWin : public NativeWindow, +class NativeWindowAura : public NativeWindow, + public web_modal::WebContentsModalDialogHost, public views::WidgetFocusChangeListener, public views::WidgetDelegateView , public views::WidgetObserver { public: - explicit NativeWindowWin(const base::WeakPtr& shell, + explicit NativeWindowAura(const base::WeakPtr& shell, base::DictionaryValue* manifest); - virtual ~NativeWindowWin(); + virtual ~NativeWindowAura(); SkRegion* draggable_region() { return draggable_region_.get(); } - NativeWindowToolbarWin* toolbar() { return toolbar_; } + NativeWindowToolbarAura* toolbar() { return toolbar_; } views::Widget* window() { return window_; } // NativeWindow implementation. @@ -95,7 +99,7 @@ class NativeWindowWin : public NativeWindow, virtual void SetToolbarUrlEntry(const std::string& url) OVERRIDE; virtual void SetToolbarIsLoading(bool loading) OVERRIDE; virtual void SetInitialFocus(bool initial_focus) OVERRIDE; - virtual bool InitialFocus() OVERRIDE { return initial_focus_; } + virtual bool InitialFocus() OVERRIDE; // WidgetDelegate implementation. virtual void OnWidgetMove() OVERRIDE; @@ -125,12 +129,10 @@ class NativeWindowWin : public NativeWindow, // WidgetObserver implementation virtual void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) OVERRIDE; - virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE{ - return true; - } - virtual bool CanHandleAccelerators() const OVERRIDE{ - return true; - } + virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; + + virtual bool CanHandleAccelerators() const OVERRIDE; + virtual gfx::NativeView GetHostView() const OVERRIDE; virtual gfx::Point GetDialogPosition(const gfx::Size& size) OVERRIDE; virtual void AddObserver(web_modal::ModalDialogHostObserver* observer) OVERRIDE; @@ -149,8 +151,8 @@ class NativeWindowWin : public NativeWindow, virtual void Layout() OVERRIDE; virtual void ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) OVERRIDE; - virtual gfx::Size GetMinimumSize() OVERRIDE; - virtual gfx::Size GetMaximumSize() OVERRIDE; + virtual gfx::Size GetMinimumSize() const OVERRIDE; + virtual gfx::Size GetMaximumSize() const OVERRIDE; virtual void OnFocus() OVERRIDE; // views::WidgetDelegate implementation. @@ -169,7 +171,7 @@ class NativeWindowWin : public NativeWindow, void OnViewWasResized(); void InstallEasyResizeTargeterOnContainer(); - NativeWindowToolbarWin* toolbar_; + NativeWindowToolbarAura* toolbar_; views::WebView* web_view_; views::Widget* window_; bool is_fullscreen_; @@ -197,7 +199,7 @@ class NativeWindowWin : public NativeWindow, bool super_down_; bool meta_down_; ObserverList observer_list_; - DISALLOW_COPY_AND_ASSIGN(NativeWindowWin); + DISALLOW_COPY_AND_ASSIGN(NativeWindowAura); }; } // namespace nw diff --git a/src/browser/native_window_gtk.cc b/src/browser/native_window_gtk.cc index e4bd5eae6a..08e93fa86a 100644 --- a/src/browser/native_window_gtk.cc +++ b/src/browser/native_window_gtk.cc @@ -24,20 +24,18 @@ #include "base/values.h" #include "base/environment.h" -#include "chrome/browser/ui/gtk/gtk_window_util.h" -#include "chrome/browser/ui/gtk/unity_service.h" +//#include "chrome/browser/ui/gtk/gtk_window_util.h" +//#include "chrome/browser/ui/gtk/unity_service.h" #include "extensions/common/draggable_region.h" #include "content/nw/src/api/menu/menu.h" #include "content/nw/src/common/shell_switches.h" #include "content/nw/src/nw_shell.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" #include "content/public/common/renderer_preferences.h" #include "ui/base/x/x11_util.h" -#include "ui/gfx/gtk_util.h" #include "ui/gfx/rect.h" -#include "ui/gfx/skia_utils_gtk.h" +//#include "ui/gfx/skia_utils_gtk.h" namespace ShellIntegrationLinux { std::string GetDesktopName(base::Environment* env) { @@ -78,10 +76,12 @@ NativeWindowGtk::NativeWindowGtk(const base::WeakPtr& shell, gtk_widget_show(vbox_); gtk_container_add(GTK_CONTAINER(window_), vbox_); +#if 0 //FIXME // Set window icon. gfx::Image icon = app_icon(); if (!icon.IsEmpty()) gtk_window_set_icon(window_, icon.ToGdkPixbuf()); +#endif // Always create toolbar since we need to create a url entry. CreateToolbar(); @@ -93,7 +93,7 @@ NativeWindowGtk::NativeWindowGtk(const base::WeakPtr& shell, gtk_box_pack_start(GTK_BOX(vbox_), toolbar_, FALSE, FALSE, 0); gfx::NativeView native_view = - web_contents()->GetView()->GetNativeView(); + web_contents()->GetNativeView(); gtk_widget_show(native_view); gtk_container_add(GTK_CONTAINER(vbox_), native_view); diff --git a/src/browser/native_window_gtk.h b/src/browser/native_window_gtk.h index db7e247290..f9265432e0 100644 --- a/src/browser/native_window_gtk.h +++ b/src/browser/native_window_gtk.h @@ -26,7 +26,7 @@ #include "content/nw/src/browser/native_window.h" #include "third_party/skia/include/core/SkRegion.h" -#include "ui/base/gtk/gtk_signal.h" +#include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" namespace nw { diff --git a/src/browser/native_window_toolbar_aura.cc b/src/browser/native_window_toolbar_aura.cc new file mode 100644 index 0000000000..cddc19b6f4 --- /dev/null +++ b/src/browser/native_window_toolbar_aura.cc @@ -0,0 +1,254 @@ +// 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_aura.h" + +#include "base/logging.h" +#include "base/strings/string16.h" +#include "base/strings/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; + +NativeWindowToolbarAura::NativeWindowToolbarAura(content::Shell* shell) + : shell_(shell) { +} + +NativeWindowToolbarAura::~NativeWindowToolbarAura() { +} + +views::View* NativeWindowToolbarAura::GetContentsView() { + return this; +} + +void NativeWindowToolbarAura::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 NativeWindowToolbarAura::ViewHierarchyChanged( + const ViewHierarchyChangedDetails& details) { + if (details.is_add && details.child == this) + InitToolbar(); +} + +void NativeWindowToolbarAura::ContentsChanged( + views::Textfield* sender, + const base::string16& new_contents) { +} + +bool NativeWindowToolbarAura::HandleKeyEvent(views::Textfield* sender, + const ui::KeyEvent& key_event) { + if (key_event.key_code() == ui::VKEY_RETURN) { + base::string16 url_string = url_entry_->text(); + if (!url_string.empty()) { + GURL url(url_string); + if (!url.has_scheme()) +#if defined(OS_WIN) + url = GURL(L"http://" + url_string); +#else + url = GURL(base::UTF8ToUTF16("http://") + url_string); +#endif + shell_->LoadURL(url); + } + } + + return false; +} + +void NativeWindowToolbarAura::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); + else + NOTREACHED() << "Click on unkown toolbar button."; +} + +void NativeWindowToolbarAura::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(base::UTF8ToUTF16("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(base::UTF8ToUTF16("Forward")); + AddChildView(forward_button_); + + stop_or_refresh_button_ = new views::ImageButton(this); + SetIsLoading(true); + AddChildView(stop_or_refresh_button_); + + url_entry_ = new views::Textfield(); + url_entry_->set_controller(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(base::UTF8ToUTF16("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(base::UTF8ToUTF16("Reload render process")); + AddChildView(dev_reload_button_); +} + +void NativeWindowToolbarAura::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 NativeWindowToolbarAura::SetUrlEntry(const std::string& url) { + url_entry_->SetText(base::UTF8ToUTF16(url)); +} + +void NativeWindowToolbarAura::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(base::UTF8ToUTF16("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(base::UTF8ToUTF16("Reload")); + } + + // Force refresh + stop_or_refresh_button_->SchedulePaint(); +} + +} // namespace nw diff --git a/src/browser/native_window_toolbar_win.h b/src/browser/native_window_toolbar_aura.h similarity index 87% rename from src/browser/native_window_toolbar_win.h rename to src/browser/native_window_toolbar_aura.h index a3358170f8..54ef8cfb95 100644 --- a/src/browser/native_window_toolbar_win.h +++ b/src/browser/native_window_toolbar_aura.h @@ -18,8 +18,8 @@ // 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_NATIVE_WINDOW_TOOLBAR_WIN_H_ -#define CONTENT_NW_SRC_BROWSER_NATIVE_WINDOW_TOOLBAR_WIN_H_ +#ifndef CONTENT_NW_SRC_BROWSER_NATIVE_WINDOW_TOOLBAR_AURA_H_ +#define CONTENT_NW_SRC_BROWSER_NATIVE_WINDOW_TOOLBAR_AURA_H_ #include "base/basictypes.h" #include "content/nw/src/browser/native_window.h" @@ -37,13 +37,13 @@ class Textfield; } namespace nw { - -class NativeWindowToolbarWin : public views::WidgetDelegateView, + +class NativeWindowToolbarAura : public views::WidgetDelegateView, public views::TextfieldController, public views::ButtonListener { public: - explicit NativeWindowToolbarWin(content::Shell* shell); - ~NativeWindowToolbarWin(); + explicit NativeWindowToolbarAura(content::Shell* shell); + virtual ~NativeWindowToolbarAura(); void SetButtonEnabled(NativeWindow::TOOLBAR_BUTTON button, bool enabled); @@ -81,9 +81,9 @@ class NativeWindowToolbarWin : public views::WidgetDelegateView, views::ImageButton* devtools_button_; views::ImageButton* dev_reload_button_; - DISALLOW_COPY_AND_ASSIGN(NativeWindowToolbarWin); + DISALLOW_COPY_AND_ASSIGN(NativeWindowToolbarAura); }; } // namespace nw -#endif // CONTENT_NW_SRC_BROWSER_NATIVE_WINDOW_TOOLBAR_WIN_H_ +#endif // CONTENT_NW_SRC_BROWSER_NATIVE_WINDOW_TOOLBAR_AURA_H_ diff --git a/src/browser/native_window_toolbar_win.cc b/src/browser/native_window_toolbar_win.cc index 985169a031..270f4ef466 100644 --- a/src/browser/native_window_toolbar_win.cc +++ b/src/browser/native_window_toolbar_win.cc @@ -18,7 +18,7 @@ // 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 "content/nw/src/browser/native_window_toolbar_aura.h" #include "base/logging.h" #include "base/strings/string16.h" @@ -36,18 +36,18 @@ namespace nw { const int kButtonMargin = 2; -NativeWindowToolbarWin::NativeWindowToolbarWin(content::Shell* shell) +NativeWindowToolbarAura::NativeWindowToolbarAura(content::Shell* shell) : shell_(shell) { } -NativeWindowToolbarWin::~NativeWindowToolbarWin() { +NativeWindowToolbarAura::~NativeWindowToolbarAura() { } -views::View* NativeWindowToolbarWin::GetContentsView() { +views::View* NativeWindowToolbarAura::GetContentsView() { return this; } -void NativeWindowToolbarWin::Layout() { +void NativeWindowToolbarAura::Layout() { int panel_width = width(); int x = kButtonMargin; @@ -87,18 +87,18 @@ void NativeWindowToolbarWin::Layout() { 24); } -void NativeWindowToolbarWin::ViewHierarchyChanged( +void NativeWindowToolbarAura::ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) { if (details.is_add && details.child == this) InitToolbar(); } -void NativeWindowToolbarWin::ContentsChanged( +void NativeWindowToolbarAura::ContentsChanged( views::Textfield* sender, const base::string16& new_contents) { } -bool NativeWindowToolbarWin::HandleKeyEvent(views::Textfield* sender, +bool NativeWindowToolbarAura::HandleKeyEvent(views::Textfield* sender, const ui::KeyEvent& key_event) { if (key_event.key_code() == ui::VKEY_RETURN) { base::string16 url_string = url_entry_->text(); @@ -113,7 +113,7 @@ bool NativeWindowToolbarWin::HandleKeyEvent(views::Textfield* sender, return false; } -void NativeWindowToolbarWin::ButtonPressed(views::Button* sender, +void NativeWindowToolbarAura::ButtonPressed(views::Button* sender, const ui::Event& event) { if (sender == back_button_) shell_->GoBackOrForward(-1); @@ -129,7 +129,7 @@ void NativeWindowToolbarWin::ButtonPressed(views::Button* sender, NOTREACHED() << "Click on unkown toolbar button."; } -void NativeWindowToolbarWin::InitToolbar() { +void NativeWindowToolbarAura::InitToolbar() { set_background(views::Background::CreateStandardPanelBackground()); views::BoxLayout* layout = new views::BoxLayout( @@ -192,7 +192,7 @@ void NativeWindowToolbarWin::InitToolbar() { AddChildView(dev_reload_button_); } -void NativeWindowToolbarWin::SetButtonEnabled( +void NativeWindowToolbarAura::SetButtonEnabled( NativeWindow::TOOLBAR_BUTTON button, bool enabled) { switch (button) { @@ -214,11 +214,11 @@ void NativeWindowToolbarWin::SetButtonEnabled( } } -void NativeWindowToolbarWin::SetUrlEntry(const std::string& url) { +void NativeWindowToolbarAura::SetUrlEntry(const std::string& url) { url_entry_->SetText(base::UTF8ToUTF16(url)); } -void NativeWindowToolbarWin::SetIsLoading(bool loading) { +void NativeWindowToolbarAura::SetIsLoading(bool loading) { ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance(); if (loading) { diff --git a/src/browser/printing/print_job.cc b/src/browser/printing/print_job.cc index d7dfbedc2d..7485983945 100644 --- a/src/browser/printing/print_job.cc +++ b/src/browser/printing/print_job.cc @@ -10,6 +10,7 @@ #include "base/threading/thread_restrictions.h" #include "base/threading/worker_pool.h" #include "base/timer/timer.h" +#include "content/public/browser/browser_thread.h" #include "content/nw/src/browser/printing/print_job_worker.h" #include "content/public/browser/notification_types.h" #include "content/public/browser/notification_service.h" @@ -70,7 +71,8 @@ void PrintJob::Initialize(PrintJobWorkerOwner* job, settings_ = job->settings(); PrintedDocument* new_doc = - new PrintedDocument(settings_, source_, job->cookie()); + new PrintedDocument(settings_, source_, job->cookie(), + content::BrowserThread::GetBlockingPool()); new_doc->set_page_count(page_count); UpdatePrintedDocument(new_doc); diff --git a/src/browser/printing/print_job_worker.cc b/src/browser/printing/print_job_worker.cc index 5e4ed1ed15..7da21ca269 100644 --- a/src/browser/printing/print_job_worker.cc +++ b/src/browser/printing/print_job_worker.cc @@ -130,31 +130,8 @@ void PrintJobWorker::SetSettings(const base::DictionaryValue* const new_settings void PrintJobWorker::UpdatePrintSettings( const base::DictionaryValue* const new_settings) { - // Create new PageRanges based on |new_settings|. - PageRanges new_ranges; - const base::ListValue* page_range_array; - if (new_settings->GetList(kSettingPageRange, &page_range_array)) { - for (size_t index = 0; index < page_range_array->GetSize(); ++index) { - const base::DictionaryValue* dict; - if (!page_range_array->GetDictionary(index, &dict)) - continue; - - PageRange range; - if (!dict->GetInteger(kSettingPageRangeFrom, &range.from) || - !dict->GetInteger(kSettingPageRangeTo, &range.to)) { - continue; - } - - // Page numbers are 1-based in the dictionary. - // Page numbers are 0-based for the printing context. - range.from--; - range.to--; - new_ranges.push_back(range); - } - } PrintingContext::Result result = - printing_context_->UpdatePrintSettings(*new_settings, new_ranges); - delete new_settings; + printing_context_->UpdatePrintSettings(*new_settings); GetSettingsDone(result); } @@ -274,8 +251,8 @@ void PrintJobWorker::OnNewPage() { while (true) { // Is the page available? - scoped_refptr page; - if (!document_->GetPage(page_number_.ToInt(), &page)) { + scoped_refptr page = document_->GetPage(page_number_.ToInt()); + if (!page) { // We need to wait for the page to be available. MessageLoop::current()->PostDelayedTask( FROM_HERE, diff --git a/src/browser/printing/print_view_manager.cc b/src/browser/printing/print_view_manager.cc index 836da15c00..76df2282c1 100644 --- a/src/browser/printing/print_view_manager.cc +++ b/src/browser/printing/print_view_manager.cc @@ -35,7 +35,6 @@ #include "content/public/browser/notification_source.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" #include "grit/nw_resources.h" #include "printing/metafile.h" #include "printing/metafile_impl.h" @@ -52,8 +51,10 @@ DEFINE_WEB_CONTENTS_USER_DATA_KEY(printing::PrintViewManager); namespace { +#if defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING) // Limits memory usage by raster to 64 MiB. const int kMaxRasterSizeInPixels = 16*1024*1024; +#endif } // namespace @@ -219,7 +220,9 @@ void PrintViewManager::OnDidPrintPage( // Update the rendered document. It will send notifications to the listener. document->SetPage(params.page_number, metafile.release(), +#if defined(OS_WIN) params.actual_shrink, +#endif params.page_size, params.content_area); diff --git a/src/browser/printing/printing_message_filter.cc b/src/browser/printing/printing_message_filter.cc index 08606ac886..b3ee115e96 100644 --- a/src/browser/printing/printing_message_filter.cc +++ b/src/browser/printing/printing_message_filter.cc @@ -14,7 +14,6 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" #include "content/public/common/content_client.h" #if defined(OS_CHROMEOS) @@ -98,10 +97,10 @@ void PrintingMessageFilter::OverrideThreadForMessage( #endif } -bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message, - bool* message_was_ok) { +bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) { + bool handled = true; - IPC_BEGIN_MESSAGE_MAP_EX(PrintingMessageFilter, message, *message_was_ok) + IPC_BEGIN_MESSAGE_MAP(PrintingMessageFilter, message) #if defined(OS_WIN) IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection) #endif diff --git a/src/browser/printing/printing_message_filter.h b/src/browser/printing/printing_message_filter.h index b74f7cdcab..b858505947 100644 --- a/src/browser/printing/printing_message_filter.h +++ b/src/browser/printing/printing_message_filter.h @@ -40,8 +40,7 @@ class PrintingMessageFilter : public content::BrowserMessageFilter { virtual void OverrideThreadForMessage( const IPC::Message& message, content::BrowserThread::ID* thread) OVERRIDE; - virtual bool OnMessageReceived(const IPC::Message& message, - bool* message_was_ok) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; private: virtual ~PrintingMessageFilter(); diff --git a/src/browser/printing/printing_ui_web_contents_observer.cc b/src/browser/printing/printing_ui_web_contents_observer.cc index 6353c5dccb..23be554307 100644 --- a/src/browser/printing/printing_ui_web_contents_observer.cc +++ b/src/browser/printing/printing_ui_web_contents_observer.cc @@ -6,7 +6,6 @@ #include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" PrintingUIWebContentsObserver::PrintingUIWebContentsObserver( content::WebContents* web_contents) @@ -16,5 +15,5 @@ PrintingUIWebContentsObserver::PrintingUIWebContentsObserver( gfx::NativeView PrintingUIWebContentsObserver::GetParentView() { DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI)); - return web_contents() ? web_contents()->GetView()->GetNativeView() : NULL; + return web_contents() ? web_contents()->GetNativeView() : NULL; } diff --git a/src/browser/shell_devtools_delegate.cc b/src/browser/shell_devtools_delegate.cc index bf58db0f0a..4f08cc67b6 100644 --- a/src/browser/shell_devtools_delegate.cc +++ b/src/browser/shell_devtools_delegate.cc @@ -40,7 +40,7 @@ ShellDevToolsDelegate::ShellDevToolsDelegate(BrowserContext* browser_context, devtools_http_handler_ = DevToolsHttpHandler::Start( new net::TCPListenSocketFactory("127.0.0.1", port), "", - this); + this, base::FilePath()); } ShellDevToolsDelegate::~ShellDevToolsDelegate() { @@ -82,11 +82,12 @@ class Target : public content::DevToolsTarget { explicit Target(WebContents* web_contents); virtual std::string GetId() const OVERRIDE { return id_; } + virtual std::string GetParentId() const OVERRIDE { return std::string(); } virtual std::string GetType() const OVERRIDE { return kTargetTypePage; } virtual std::string GetTitle() const OVERRIDE { return title_; } virtual std::string GetDescription() const OVERRIDE { return description_; } - virtual GURL GetUrl() const OVERRIDE { return url_; } - virtual GURL GetFaviconUrl() const OVERRIDE { return GURL(); } + virtual GURL GetURL() const OVERRIDE { return url_; } + virtual GURL GetFaviconURL() const OVERRIDE { return GURL(); } virtual base::TimeTicks GetLastActivityTime() const OVERRIDE { return last_activity_time_; } @@ -110,7 +111,7 @@ class Target : public content::DevToolsTarget { Target::Target(WebContents* web_contents) { agent_host_ = - DevToolsAgentHost::GetOrCreateFor(web_contents->GetRenderViewHost()); + DevToolsAgentHost::GetOrCreateFor(web_contents); id_ = agent_host_->GetId(); title_ = base::UTF16ToUTF8(web_contents->GetTitle()); url_ = web_contents->GetURL(); @@ -118,10 +119,7 @@ Target::Target(WebContents* web_contents) { } bool Target::Activate() const { - RenderViewHost* rvh = agent_host_->GetRenderViewHost(); - if (!rvh) - return false; - WebContents* web_contents = WebContents::FromRenderViewHost(rvh); + WebContents* web_contents = agent_host_->GetWebContents(); if (!web_contents) return false; web_contents->GetDelegate()->ActivateContents(web_contents); @@ -129,22 +127,21 @@ bool Target::Activate() const { } bool Target::Close() const { - RenderViewHost* rvh = agent_host_->GetRenderViewHost(); - if (!rvh) + WebContents* web_contents = agent_host_->GetWebContents(); + if (!web_contents) return false; - rvh->ClosePage(); + web_contents->GetRenderViewHost()->ClosePage(); return true; } void ShellDevToolsDelegate::EnumerateTargets(TargetCallback callback) { TargetList targets; - std::vector rvh_list = - content::DevToolsAgentHost::GetValidRenderViewHosts(); - for (std::vector::iterator it = rvh_list.begin(); - it != rvh_list.end(); ++it) { - WebContents* web_contents = WebContents::FromRenderViewHost(*it); - if (web_contents) - targets.push_back(new Target(web_contents)); + std::vector wc_list = + content::DevToolsAgentHost::GetInspectableWebContents(); + for (std::vector::iterator it = wc_list.begin(); + it != wc_list.end(); + ++it) { + targets.push_back(new Target(*it)); } callback.Run(targets); } diff --git a/src/browser/shell_download_manager_delegate.cc b/src/browser/shell_download_manager_delegate.cc index b40fd7924f..c3bdf09e88 100644 --- a/src/browser/shell_download_manager_delegate.cc +++ b/src/browser/shell_download_manager_delegate.cc @@ -38,7 +38,7 @@ #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/filename_util.h" #include "net/base/net_util.h" using base::FilePath; diff --git a/src/browser/shell_download_manager_delegate_gtk.cc b/src/browser/shell_download_manager_delegate_gtk.cc index 0e8d4fe50e..e502fb33e2 100644 --- a/src/browser/shell_download_manager_delegate_gtk.cc +++ b/src/browser/shell_download_manager_delegate_gtk.cc @@ -20,7 +20,7 @@ #include "content/nw/src/browser/shell_download_manager_delegate.h" -#if defined(TOOLKIT_GTK) +#if defined(OS_LINUX) #include #endif @@ -33,7 +33,6 @@ #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" using base::FilePath; @@ -54,9 +53,9 @@ void ShellDownloadManagerDelegate::ChooseDownloadPath( gfx::NativeWindow parent_window; std::string base_name = FilePath(suggested_path).BaseName().value(); - parent_window = item->GetWebContents()->GetView()->GetTopLevelNativeWindow(); + parent_window = item->GetWebContents()->GetTopLevelNativeWindow(); dialog = gtk_file_chooser_dialog_new("Save File", - parent_window, + NULL, GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT, diff --git a/src/browser/shell_javascript_dialog_creator.cc b/src/browser/shell_javascript_dialog_creator.cc index 4c176b2a1e..2d2e9dea0b 100644 --- a/src/browser/shell_javascript_dialog_creator.cc +++ b/src/browser/shell_javascript_dialog_creator.cc @@ -24,7 +24,6 @@ #include "base/logging.h" #include "base/strings/utf_string_conversions.h" #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" #include "content/nw/src/browser/shell_javascript_dialog.h" #include "content/nw/src/common/shell_switches.h" #include "net/base/net_util.h" diff --git a/src/browser/shell_login_dialog.cc b/src/browser/shell_login_dialog.cc index 1dfb826d1b..d5888030fe 100644 --- a/src/browser/shell_login_dialog.cc +++ b/src/browser/shell_login_dialog.cc @@ -112,4 +112,13 @@ void ShellLoginDialog::ReleaseSoon() { BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this); } +#if !defined(OS_MACOSX) //FIXME +// Bogus implementations for linking. They are never called because +// ResourceDispatcherHostDelegate::CreateLoginDelegate returns NULL. +// TODO: implement ShellLoginDialog for other platforms, drop this #if +void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) {} +void ShellLoginDialog::PlatformCleanUp() {} +void ShellLoginDialog::PlatformRequestCancelled() {} +#endif + } // namespace content diff --git a/src/browser/shell_resource_dispatcher_host_delegate.cc b/src/browser/shell_resource_dispatcher_host_delegate.cc index 69b7dd864e..2de9d40be1 100644 --- a/src/browser/shell_resource_dispatcher_host_delegate.cc +++ b/src/browser/shell_resource_dispatcher_host_delegate.cc @@ -23,6 +23,7 @@ #include "chrome/browser/platform_util.h" #include "content/nw/src/browser/shell_login_dialog.h" #include "content/public/browser/browser_thread.h" +#include "url/gurl.h" namespace content { diff --git a/src/chrome_breakpad_client.cc b/src/chrome_breakpad_client.cc index a41ff3e367..cc56fb7178 100644 --- a/src/chrome_breakpad_client.cc +++ b/src/chrome_breakpad_client.cc @@ -77,10 +77,10 @@ ChromeBreakpadClient::ChromeBreakpadClient() {} ChromeBreakpadClient::~ChromeBreakpadClient() {} -void ChromeBreakpadClient::SetClientID(const std::string& client_id) { - crash_keys::SetClientID(client_id); +void ChromeBreakpadClient::SetBreakpadClientIdFromGUID( + const std::string& client_guid) { + crash_keys::SetCrashClientIdFromGUID(client_guid); } - #if defined(OS_WIN) bool ChromeBreakpadClient::GetAlternativeCrashDumpLocation( base::FilePath* crash_dir) { diff --git a/src/chrome_breakpad_client.h b/src/chrome_breakpad_client.h index 489e8fe512..d056f23f95 100644 --- a/src/chrome_breakpad_client.h +++ b/src/chrome_breakpad_client.h @@ -17,7 +17,6 @@ class ChromeBreakpadClient : public breakpad::BreakpadClient { virtual ~ChromeBreakpadClient(); // breakpad::BreakpadClient implementation. - virtual void SetClientID(const std::string& client_id) OVERRIDE; #if defined(OS_WIN) virtual bool GetAlternativeCrashDumpLocation(base::FilePath* crash_dir) OVERRIDE; diff --git a/src/common/print_messages.cc b/src/common/print_messages.cc index f4fae5cc88..21a359412e 100644 --- a/src/common/print_messages.cc +++ b/src/common/print_messages.cc @@ -79,3 +79,14 @@ PrintHostMsg_RequestPrintPreview_Params:: PrintHostMsg_RequestPrintPreview_Params:: ~PrintHostMsg_RequestPrintPreview_Params() {} + +PrintHostMsg_SetOptionsFromDocument_Params:: + PrintHostMsg_SetOptionsFromDocument_Params() + : is_scaling_disabled(false), + copies(0), + duplex(printing::UNKNOWN_DUPLEX_MODE) { +} + +PrintHostMsg_SetOptionsFromDocument_Params:: + ~PrintHostMsg_SetOptionsFromDocument_Params() { +} diff --git a/src/common/print_messages.h b/src/common/print_messages.h index 4e3f99fab5..e638450da3 100644 --- a/src/common/print_messages.h +++ b/src/common/print_messages.h @@ -11,6 +11,7 @@ #include "base/memory/shared_memory.h" #include "base/values.h" #include "ipc/ipc_message_macros.h" +#include "printing/page_range.h" #include "printing/page_size_margins.h" #include "printing/print_job_constants.h" #include "third_party/WebKit/public/web/WebPrintScalingOption.h" @@ -70,12 +71,27 @@ struct PrintHostMsg_RequestPrintPreview_Params { bool selection_only; }; +struct PrintHostMsg_SetOptionsFromDocument_Params { + PrintHostMsg_SetOptionsFromDocument_Params(); + ~PrintHostMsg_SetOptionsFromDocument_Params(); + + bool is_scaling_disabled; + int copies; + printing::DuplexMode duplex; + printing::PageRanges page_ranges; +}; + #endif // CHROME_COMMON_PRINT_MESSAGES_H_ #define IPC_MESSAGE_START PrintMsgStart -IPC_ENUM_TRAITS(printing::MarginType) -IPC_ENUM_TRAITS(blink::WebPrintScalingOption) +IPC_ENUM_TRAITS_MAX_VALUE(printing::MarginType, + printing::MARGIN_TYPE_LAST) +IPC_ENUM_TRAITS_MAX_VALUE(blink::WebPrintScalingOption, + blink::WebPrintScalingOptionLast) +IPC_ENUM_TRAITS_MIN_MAX_VALUE(printing::DuplexMode, + printing::UNKNOWN_DUPLEX_MODE, + printing::SHORT_EDGE) // Parameters for a render request. IPC_STRUCT_TRAITS_BEGIN(PrintMsg_Print_Params) @@ -181,6 +197,25 @@ IPC_STRUCT_TRAITS_BEGIN(PrintMsg_PrintPages_Params) IPC_STRUCT_TRAITS_MEMBER(pages) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(printing::PageRange) + IPC_STRUCT_TRAITS_MEMBER(from) + IPC_STRUCT_TRAITS_MEMBER(to) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PrintHostMsg_SetOptionsFromDocument_Params) + // Specifies whether print scaling is enabled or not. + IPC_STRUCT_TRAITS_MEMBER(is_scaling_disabled) + + // Specifies number of copies to be printed. + IPC_STRUCT_TRAITS_MEMBER(copies) + + // Specifies paper handling option. + IPC_STRUCT_TRAITS_MEMBER(duplex) + + // Specifies page range to be printed. + IPC_STRUCT_TRAITS_MEMBER(page_ranges) +IPC_STRUCT_TRAITS_END() + // Parameters to describe a rendered document. IPC_STRUCT_BEGIN(PrintHostMsg_DidPreviewDocument_Params) // True when we can reuse existing preview data. |metafile_data_handle| and @@ -401,6 +436,9 @@ IPC_SYNC_MESSAGE_ROUTED2_1(PrintHostMsg_CheckForCancel, int /* request id */, bool /* print preview cancelled */) +// This is sent when there are invalid printer settings. +IPC_MESSAGE_ROUTED0(PrintHostMsg_ShowInvalidPrinterSettingsError) + // Sends back to the browser the complete rendered document (non-draft mode, // used for printing) that was requested by a PrintMsg_PrintPreview message. // The memory handle in this message is already valid in the browser process. @@ -437,3 +475,7 @@ IPC_MESSAGE_ROUTED0(PrintHostMsg_PrintPreviewScalingDisabled) // Check if printing is enabled. IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_IsPrintingEnabled, bool /* is_enabled */) + +// Notify the browser to set print presets based on source PDF document. +IPC_MESSAGE_ROUTED1(PrintHostMsg_SetOptionsFromDocument, + PrintHostMsg_SetOptionsFromDocument_Params /* params */) diff --git a/src/common/shell_switches.cc b/src/common/shell_switches.cc index 2d6065b224..be6bb8c1ed 100644 --- a/src/common/shell_switches.cc +++ b/src/common/shell_switches.cc @@ -110,4 +110,5 @@ const char kmInjectCSS[] = "inject-css"; const char kPrintRaster[] = "print-raster"; #endif +const char kCrashDumpsDir[] = "crash-dumps-dir"; } // namespace switches diff --git a/src/common/shell_switches.h b/src/common/shell_switches.h index 8b145858e1..79fe155eab 100644 --- a/src/common/shell_switches.h +++ b/src/common/shell_switches.h @@ -64,6 +64,9 @@ extern const char kmInjectCSS[]; #if defined(OS_WIN) extern const char kPrintRaster[]; #endif + +extern const char kCrashDumpsDir[]; + } // namespace switches #endif // CONTENT_NW_SRC_SHELL_SWITCHES_H_ diff --git a/src/media/media_capture_devices_dispatcher.h b/src/media/media_capture_devices_dispatcher.h index db4f6e53ff..9e834961c4 100644 --- a/src/media/media_capture_devices_dispatcher.h +++ b/src/media/media_capture_devices_dispatcher.h @@ -87,12 +87,12 @@ class MediaCaptureDevicesDispatcher : public content::MediaObserver, virtual void OnMediaRequestStateChanged( - int render_process_id, - int render_view_id, - int page_request_id, - const GURL& security_origin, - const content::MediaStreamDevice& device, - content::MediaRequestState state) OVERRIDE {} + int render_process_id, + int render_frame_id, + int page_request_id, + const GURL& security_origin, + content::MediaStreamType stream_type, + content::MediaRequestState state) OVERRIDE {} // Returns the first available audio or video device, or NULL if no devices // are available. diff --git a/src/media/media_internals.cc b/src/media/media_internals.cc index e8546ea141..22ddf30191 100644 --- a/src/media/media_internals.cc +++ b/src/media/media_internals.cc @@ -100,12 +100,12 @@ void MediaInternals::OnVideoCaptureDevicesChanged() { } void MediaInternals::OnMediaRequestStateChanged( - int render_process_id, - int render_view_id, - int page_request_id, - const GURL& security_origin, - const content::MediaStreamDevice& device, - content::MediaRequestState state) { + int render_process_id, + int render_frame_id, + int page_request_id, + const GURL& security_origin, + content::MediaStreamType stream_type, + content::MediaRequestState state) { } void MediaInternals::OnCreatingAudioStream( diff --git a/src/media/media_internals.h b/src/media/media_internals.h index 74254297b9..d90855214d 100644 --- a/src/media/media_internals.h +++ b/src/media/media_internals.h @@ -46,11 +46,12 @@ class MediaInternals : public content::MediaObserver { virtual void OnVideoCaptureDevicesChanged() OVERRIDE; virtual void OnMediaRequestStateChanged( int render_process_id, - int render_view_id, + int render_frame_id, int page_request_id, const GURL& security_origin, - const content::MediaStreamDevice& device, + content::MediaStreamType stream_type, content::MediaRequestState state) OVERRIDE; + virtual void OnCreatingAudioStream(int render_process_id, int render_view_id) OVERRIDE; diff --git a/src/media/media_stream_devices_controller.cc b/src/media/media_stream_devices_controller.cc index 032a659ce3..1522f034df 100644 --- a/src/media/media_stream_devices_controller.cc +++ b/src/media/media_stream_devices_controller.cc @@ -30,8 +30,8 @@ bool HasAnyAvailableDevice() { return !audio_devices.empty() || !video_devices.empty(); }; -const char kAudioKey[] = "audio"; -const char kVideoKey[] = "video"; +//const char kAudioKey[] = "audio"; +//const char kVideoKey[] = "video"; } // namespace @@ -41,7 +41,7 @@ MediaStreamDevicesController::MediaStreamDevicesController( : request_(request), callback_(callback), - has_audio_(content::IsAudioMediaType(request.audio_type) && + has_audio_(content::IsAudioInputMediaType(request.audio_type) && !IsAudioDeviceBlockedByPolicy()), has_video_(content::IsVideoMediaType(request.video_type) && !IsVideoDeviceBlockedByPolicy()) { diff --git a/src/net/app_protocol_handler.cc b/src/net/app_protocol_handler.cc index ab0186e2ab..3f7ec69b16 100644 --- a/src/net/app_protocol_handler.cc +++ b/src/net/app_protocol_handler.cc @@ -13,6 +13,7 @@ #include "base/strings/stringprintf.h" #include "base/threading/sequenced_worker_pool.h" #include "content/public/browser/browser_thread.h" +#include "net/base/filename_util.h" #include "net/base/mime_util.h" #include "net/base/net_errors.h" #include "net/base/net_util.h" @@ -146,12 +147,12 @@ URLRequestJob* AppProtocolHandler::MaybeCreateJob( URLRequest* request, NetworkDelegate* network_delegate) const { base::FilePath file_path; GURL url(request->url()); - url_canon::Replacements replacements; - replacements.SetScheme("file", url_parse::Component(0, 4)); + url::Replacements replacements; + replacements.SetScheme("file", url::Component(0, 4)); replacements.ClearHost(); url = url.ReplaceComponents(replacements); - const bool is_file = FileURLToFilePath(url, &file_path); + const bool is_file = net::FileURLToFilePath(url, &file_path); file_path = root_path_.Append(file_path); // Check file access permissions. diff --git a/src/net/clear_on_exit_policy.cc b/src/net/clear_on_exit_policy.cc index 667f47da3e..0457b4ab22 100644 --- a/src/net/clear_on_exit_policy.cc +++ b/src/net/clear_on_exit_policy.cc @@ -27,9 +27,9 @@ bool ClearOnExitPolicy::ShouldClearOriginOnExit(const std::string& domain, return false; std::string scheme = - scheme_is_secure ? content::kHttpsScheme : content::kHttpScheme; + scheme_is_secure ? url::kHttpsScheme : url::kHttpScheme; std::string host = domain[0] == '.' ? domain.substr(1) : domain; - GURL url(scheme + content::kStandardSchemeSeparator + host); + GURL url(scheme + url::kStandardSchemeSeparator + host); return special_storage_policy_->IsStorageSessionOnly(url); } diff --git a/src/net/shell_url_request_context_getter.cc b/src/net/shell_url_request_context_getter.cc index 0595186d07..04f2a7379c 100644 --- a/src/net/shell_url_request_context_getter.cc +++ b/src/net/shell_url_request_context_getter.cc @@ -37,10 +37,8 @@ #include "content/nw/src/nw_shell.h" #include "content/nw/src/shell_content_browser_client.h" #include "net/cert/cert_verifier.h" -#include "net/ssl/default_server_bound_cert_store.h" #include "net/dns/host_resolver.h" #include "net/dns/mapped_host_resolver.h" -#include "net/ssl/server_bound_cert_service.h" #include "net/ssl/ssl_config_service_defaults.h" #include "net/cookies/cookie_monster.h" #include "net/http/http_auth_filter.h" @@ -53,8 +51,9 @@ #include "net/proxy/proxy_script_fetcher_impl.h" #include "net/proxy/proxy_service.h" #include "net/proxy/proxy_service_v8.h" +#include "net/ssl/channel_id_service.h" +#include "net/ssl/default_channel_id_store.h" #include "net/url_request/file_protocol_handler.h" -#include "net/url_request/protocol_intercept_job_factory.h" #include "net/url_request/static_http_user_agent_settings.h" #include "net/url_request/url_request_context.h" #include "net/url_request/url_request_context_storage.h" @@ -99,6 +98,8 @@ class NWCookieMonsterDelegate : public net::CookieMonster::Delegate { base::Bind(&NWCookieMonsterDelegate::OnCookieChangedAsyncHelper, this, cookie, removed, cause)); } + virtual void OnLoaded() OVERRIDE { + } private: virtual ~NWCookieMonsterDelegate() {} @@ -187,8 +188,8 @@ net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() { const char* schemes[] = {"http", "https", "file", "app"}; cookie_store->GetCookieMonster()->SetCookieableSchemes(schemes, 4); - storage_->set_server_bound_cert_service(new net::ServerBoundCertService( - new net::DefaultServerBoundCertStore(NULL), + storage_->set_channel_id_service(new net::ChannelIDService( + new net::DefaultChannelIDStore(NULL), base::WorkerPool::GetTaskRunner(true))); std::string accept_lang = browser_client->GetApplicationLocale(); @@ -242,8 +243,8 @@ net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() { url_request_context_->cert_verifier(); network_session_params.transport_security_state = url_request_context_->transport_security_state(); - network_session_params.server_bound_cert_service = - url_request_context_->server_bound_cert_service(); + network_session_params.channel_id_service = + url_request_context_->channel_id_service(); network_session_params.proxy_service = url_request_context_->proxy_service(); network_session_params.ssl_config_service = @@ -270,7 +271,7 @@ net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() { new net::URLRequestJobFactoryImpl()); InstallProtocolHandlers(job_factory.get(), &protocol_handlers_); job_factory->SetProtocolHandler( - content::kFileScheme, + url::kFileScheme, new net::FileProtocolHandler( content::BrowserThread::GetBlockingPool()-> GetTaskRunnerWithShutdownBehavior( diff --git a/src/nw_notification_manager.cc b/src/nw_notification_manager.cc index 8698186522..5b7ab96a17 100644 --- a/src/nw_notification_manager.cc +++ b/src/nw_notification_manager.cc @@ -72,7 +72,7 @@ bool NotificationManager::DesktopNotificationPostClick(int render_process_id, in if (host == NULL) return false; - host->DesktopNotificationPostClick(notification_id); + // host->DesktopNotificationPostClick(notification_id); return true; } @@ -81,7 +81,7 @@ bool NotificationManager::DesktopNotificationPostClose(int render_process_id, in if (host == NULL) return false; - host->DesktopNotificationPostClose(notification_id, by_user); + // host->DesktopNotificationPostClose(notification_id, by_user); return true; } @@ -90,7 +90,7 @@ bool NotificationManager::DesktopNotificationPostDisplay(int render_process_id, if (host == NULL) return false; - host->DesktopNotificationPostDisplay(notification_id); + // host->DesktopNotificationPostDisplay(notification_id); return true; } @@ -99,7 +99,7 @@ bool NotificationManager::DesktopNotificationPostError(int render_process_id, in if (host == NULL) return false; - host->DesktopNotificationPostError(notification_id, message); + // host->DesktopNotificationPostError(notification_id, message); return true; } } // namespace nw diff --git a/src/nw_notification_manager_linux.cc b/src/nw_notification_manager_linux.cc index f5bf355f4c..fd62b61316 100644 --- a/src/nw_notification_manager_linux.cc +++ b/src/nw_notification_manager_linux.cc @@ -30,7 +30,6 @@ #include "content/nw/src/nw_notification_manager_linux.h" -#include "ui/gfx/gtk_util.h" namespace nw { diff --git a/src/nw_package.cc b/src/nw_package.cc index 76a88eede8..937809d57e 100644 --- a/src/nw_package.cc +++ b/src/nw_package.cc @@ -122,7 +122,7 @@ void RelativePathToURI(FilePath root, base::DictionaryValue* manifest) { #if defined(OS_WIN) std::wstring ASCIIToWide(const std::string& ascii) { - DCHECK(IsStringASCII(ascii)) << ascii; + DCHECK(base::IsStringASCII(ascii)) << ascii; return std::wstring(ascii.begin(), ascii.end()); } #endif diff --git a/src/nw_shell.cc b/src/nw_shell.cc index ef9a8032d6..17b78e3cd3 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -52,7 +52,7 @@ #include "content/nw/src/browser/native_window.h" #include "content/nw/src/browser/shell_devtools_delegate.h" #include "content/nw/src/browser/shell_javascript_dialog_creator.h" -#include "content/nw/src/browser/tab_autofill_manager_delegate.h" +//#include "content/nw/src/browser/tab_autofill_manager_delegate.h" #include "content/nw/src/common/shell_switches.h" #include "content/nw/src/media/media_stream_devices_controller.h" #include "content/nw/src/nw_package.h" @@ -206,12 +206,15 @@ Shell::Shell(WebContents* web_contents, base::DictionaryValue* manifest) web_modal::WebContentsModalDialogManager::CreateForWebContents(web_contents); web_modal::WebContentsModalDialogManager::FromWebContents(web_contents)->SetDelegate(this); #endif + +#if 0 //FIXME autofill::TabAutofillManagerDelegate::CreateForWebContents(web_contents); autofill::ContentAutofillDriver::CreateForWebContentsAndDelegate( web_contents, autofill::TabAutofillManagerDelegate::FromWebContents(web_contents), "", autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER); +#endif } Shell::~Shell() { @@ -341,13 +344,13 @@ void Shell::LoadURL(const GURL& url) { // Referrer(), // PAGE_TRANSITION_TYPED, // std::string()); - web_contents_->GetView()->Focus(); + web_contents_->Focus(); window()->SetToolbarButtonEnabled(nw::NativeWindow::BUTTON_FORWARD, false); } void Shell::GoBackOrForward(int offset) { web_contents_->GetController().GoToOffset(offset); - web_contents_->GetView()->Focus(); + web_contents_->Focus(); } void Shell::Reload(ReloadType type) { @@ -373,12 +376,12 @@ void Shell::Reload(ReloadType type) { break; } - web_contents_->GetView()->Focus(); + web_contents_->Focus(); } void Shell::Stop() { web_contents_->Stop(); - web_contents_->GetView()->Focus(); + web_contents_->Focus(); } void Shell::ReloadOrStop() { @@ -419,14 +422,14 @@ void Shell::ShowDevTools(const char* jail_id, bool headless) { return; } - RenderViewHost* inspected_rvh = web_contents()->GetRenderViewHost(); + // RenderViewHost* inspected_rvh = web_contents()->GetRenderViewHost(); if (nodejs()) { std::string jscript = std::string("require('nw.gui').Window.get().__setDevToolsJail('") + (jail_id ? jail_id : "(null)") + "');"; - inspected_rvh->ExecuteJavascriptInWebFrame(base::string16(), base::UTF8ToUTF16(jscript.c_str())); + web_contents()->GetMainFrame()->ExecuteJavaScript(base::UTF8ToUTF16(jscript.c_str())); } - scoped_refptr agent(DevToolsAgentHost::GetOrCreateFor(inspected_rvh)); + scoped_refptr agent(DevToolsAgentHost::GetOrCreateFor(web_contents())); DevToolsManager* manager = DevToolsManager::GetInstance(); if (agent->IsAttached()) { @@ -436,10 +439,12 @@ void Shell::ShowDevTools(const char* jail_id, bool headless) { ShellDevToolsDelegate* delegate = browser_client->shell_browser_main_parts()->devtools_delegate(); - GURL url = delegate->devtools_http_handler()->GetFrontendURL(); + GURL url = delegate->devtools_http_handler()->GetFrontendURL(agent.get()); + DevToolsHttpHandlerImpl* http_handler = static_cast(delegate->devtools_http_handler()); + http_handler->EnumerateTargets(); if (headless) { - DevToolsAgentHost* agent_host = DevToolsAgentHost::GetOrCreateFor(inspected_rvh).get(); + DevToolsAgentHost* agent_host = DevToolsAgentHost::GetOrCreateFor(web_contents()).get(); url = delegate->devtools_http_handler()->GetFrontendURL(agent_host); DevToolsHttpHandlerImpl* http_handler = static_cast(delegate->devtools_http_handler()); @@ -469,10 +474,10 @@ void Shell::ShowDevTools(const char* jail_id, bool headless) { new ShellDevToolsFrontend( shell, - DevToolsAgentHost::GetOrCreateFor(inspected_rvh).get()); + DevToolsAgentHost::GetOrCreateFor(web_contents_.get()).get()); int rh_id = shell->web_contents_->GetRenderProcessHost()->GetID(); - ChildProcessSecurityPolicyImpl::GetInstance()->GrantScheme(rh_id, content::kFileScheme); + ChildProcessSecurityPolicyImpl::GetInstance()->GrantScheme(rh_id, url::kFileScheme); ChildProcessSecurityPolicyImpl::GetInstance()->GrantScheme(rh_id, "app"); shell->is_devtools_ = true; shell->devtools_owner_ = weak_ptr_factory_.GetWeakPtr(); @@ -600,12 +605,15 @@ void Shell::WebContentsCreated(WebContents* source_contents, web_modal::WebContentsModalDialogManager::CreateForWebContents(new_contents); web_modal::WebContentsModalDialogManager::FromWebContents(new_contents)->SetDelegate(this); #endif + +#if 0 //FIXME autofill::TabAutofillManagerDelegate::CreateForWebContents(new_contents); autofill::ContentAutofillDriver::CreateForWebContentsAndDelegate( new_contents, autofill::TabAutofillManagerDelegate::FromWebContents(new_contents), "", autofill::AutofillManager::ENABLE_AUTOFILL_DOWNLOAD_MANAGER); +#endif } #if defined(OS_WIN) @@ -619,7 +627,8 @@ void Shell::WebContentsFocused(content::WebContents* web_contents) { content::ColorChooser* Shell::OpenColorChooser(content::WebContents* web_contents, SkColor color, const std::vector& suggestions) { - return nw::ShowColorChooser(web_contents, color); + //FIXME: return nw::ShowColorChooser(web_contents, color); + return NULL; } void Shell::RunFileChooser(WebContents* web_contents, diff --git a/src/renderer/common/render_messages.h b/src/renderer/common/render_messages.h index 7a1cfc2415..f5c657ca31 100644 --- a/src/renderer/common/render_messages.h +++ b/src/renderer/common/render_messages.h @@ -19,7 +19,11 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "content/public/common/common_param_traits.h" +#include "ipc/ipc_message.h" +#include "ipc/ipc_message_macros.h" +#include "ipc/ipc_param_traits.h" #include "third_party/skia/include/core/SkBitmap.h" +#include "ui/gfx/ipc/gfx_param_traits.h" // Singly-included section #ifndef CONTENT_NW_SRC_RENDERER_COMMON_RENDER_MESSAGES_H_ diff --git a/src/renderer/nw_render_view_observer.cc b/src/renderer/nw_render_view_observer.cc index 6e6b2d059a..297de10d31 100644 --- a/src/renderer/nw_render_view_observer.cc +++ b/src/renderer/nw_render_view_observer.cc @@ -30,7 +30,7 @@ #include "skia/ext/platform_canvas.h" #include "third_party/WebKit/public/platform/WebRect.h" #include "third_party/WebKit/public/platform/WebSize.h" -#include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebView.h" @@ -79,7 +79,7 @@ void NwRenderViewObserver::OnCaptureSnapshot() { Send(new NwViewHostMsg_Snapshot(routing_id(), snapshot)); } -void NwRenderViewObserver::DidFinishDocumentLoad(blink::WebFrame* frame) { +void NwRenderViewObserver::DidFinishDocumentLoad(blink::WebLocalFrame* frame) { RenderViewImpl* rv = RenderViewImpl::FromWebView(frame->view()); if (!rv) return; @@ -87,7 +87,7 @@ void NwRenderViewObserver::DidFinishDocumentLoad(blink::WebFrame* frame) { OnDocumentCallback(rv, js_fn, frame); } -void NwRenderViewObserver::DidCreateDocumentElement(blink::WebFrame* frame) { +void NwRenderViewObserver::DidCreateDocumentElement(blink::WebLocalFrame* frame) { RenderViewImpl* rv = RenderViewImpl::FromWebView(frame->view()); if (!rv) return; @@ -131,7 +131,7 @@ bool NwRenderViewObserver::CaptureSnapshot(blink::WebView* view, SkBaseDevice* device = skia::GetTopDevice(*canvas); const SkBitmap& bitmap = device->accessBitmap(false); - if (!bitmap.copyTo(snapshot, SkBitmapConfigToColorType(SkBitmap::kARGB_8888_Config))) + if (!bitmap.copyTo(snapshot, kN32_SkColorType)) return false; return true; diff --git a/src/renderer/nw_render_view_observer.h b/src/renderer/nw_render_view_observer.h index 0449c1db08..79a6002723 100644 --- a/src/renderer/nw_render_view_observer.h +++ b/src/renderer/nw_render_view_observer.h @@ -42,8 +42,8 @@ class NwRenderViewObserver : public content::RenderViewObserver { // RenderViewObserver implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void DidCreateDocumentElement(blink::WebFrame* frame) OVERRIDE; - virtual void DidFinishDocumentLoad(blink::WebFrame* frame) OVERRIDE; + virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) OVERRIDE; + virtual void DidFinishDocumentLoad(blink::WebLocalFrame* frame) OVERRIDE; private: diff --git a/src/renderer/printing/print_web_view_helper.cc b/src/renderer/printing/print_web_view_helper.cc index 8e5c18b3bc..ec0b517101 100644 --- a/src/renderer/printing/print_web_view_helper.cc +++ b/src/renderer/printing/print_web_view_helper.cc @@ -15,9 +15,9 @@ #include "base/strings/stringprintf.h" #include "base/strings/string_number_conversions.h" #include "base/strings/utf_string_conversions.h" -#include "content/public/renderer/web_preferences.h" +#include "content/public/common/web_preferences.h" #include "chrome/common/chrome_switches.h" -#include "chrome/common/print_messages.h" +#include "content/nw/src/common/print_messages.h" #include "chrome/common/render_messages.h" #include "chrome/renderer/prerender/prerender_helper.h" #include "content/public/renderer/render_thread.h" @@ -34,7 +34,7 @@ #include "third_party/WebKit/public/web/WebConsoleMessage.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebElement.h" -#include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebFrameClient.h" #include "third_party/WebKit/public/web/WebPlugin.h" #include "third_party/WebKit/public/web/WebPluginDocument.h" @@ -46,9 +46,9 @@ #include "third_party/WebKit/public/web/WebViewClient.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" -#include "webkit/common/webpreferences.h" using base::MessageLoop; +using content::WebPreferences; namespace printing { @@ -392,7 +392,7 @@ void PrintWebViewHelper::PrintHeaderAndFooter( blink::WebView* web_view = blink::WebView::create(NULL); web_view->settings()->setJavaScriptEnabled(true); - blink::WebFrame* frame = blink::WebFrame::create(NULL); + blink::WebLocalFrame* frame = blink::WebLocalFrame::create(NULL); web_view->setMainFrame(frame); base::StringValue html( @@ -453,7 +453,7 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient, public blink::WebFrameClient { public: PrepareFrameAndViewForPrint(const PrintMsg_Print_Params& params, - blink::WebFrame* frame, + blink::WebLocalFrame* frame, const blink::WebNode& node, bool ignore_css_margins); virtual ~PrepareFrameAndViewForPrint(); @@ -466,7 +466,7 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient, // Prepares frame for printing. void StartPrinting(); - blink::WebFrame* frame() const { + blink::WebLocalFrame* frame() const { return frame_; } @@ -500,7 +500,7 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient, base::WeakPtrFactory weak_ptr_factory_; - blink::WebFrame* frame_; + blink::WebLocalFrame* frame_; blink::WebNode node_to_print_; bool owns_web_view_; blink::WebPrintParams web_print_params_; @@ -517,7 +517,7 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient, PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint( const PrintMsg_Print_Params& params, - blink::WebFrame* frame, + blink::WebLocalFrame* frame, const blink::WebNode& node, bool ignore_css_margins) : weak_ptr_factory_(this), @@ -607,9 +607,9 @@ void PrepareFrameAndViewForPrint::CopySelection( blink::WebView* web_view = blink::WebView::create(this); owns_web_view_ = true; - content::ApplyWebPreferences(prefs, web_view); - web_view->setMainFrame(blink::WebFrame::create(this)); - frame_ = web_view->mainFrame(); + content::RenderView::ApplyWebPreferences(prefs, web_view); + web_view->setMainFrame(blink::WebLocalFrame::create(this)); + frame_ = web_view->mainFrame()->toWebLocalFrame(); node_to_print_.reset(); // When loading is done this will call didStopLoading() and that will do the @@ -701,7 +701,7 @@ bool PrintWebViewHelper::IsScriptInitiatedPrintAllowed( } // Prints |frame| which called window.print(). -void PrintWebViewHelper::PrintPage(blink::WebFrame* frame, +void PrintWebViewHelper::PrintPage(blink::WebLocalFrame* frame, bool user_initiated) { DCHECK(frame); @@ -757,12 +757,29 @@ void PrintWebViewHelper::OnPrintForPrintPreview( return; } + // The out-of-process plugin element is nested within a frame. + blink::WebLocalFrame* plugin_frame = pdf_element.document().frame(); + blink::WebElement plugin_element = pdf_element; + if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kOutOfProcessPdf)) { + if (!pdf_element.hasHTMLTagName("iframe")) { + NOTREACHED(); + return; + } + plugin_frame = blink::WebLocalFrame::fromFrameOwnerElement(pdf_element); + // with id="plugin" is created in + // chrome/browser/resources/pdf/pdf.js. + plugin_element = plugin_frame->document().getElementById("plugin"); + if (plugin_element.isNull()) { + NOTREACHED(); + return; + } + } + // Set |print_for_preview_| flag and autoreset it to back to original // on return. base::AutoReset set_printing_flag(&print_for_preview_, true); - blink::WebFrame* pdf_frame = pdf_element.document().frame(); - if (!UpdatePrintSettings(pdf_frame, pdf_element, job_settings)) { + if (!UpdatePrintSettings(plugin_frame, plugin_element, job_settings)) { LOG(ERROR) << "UpdatePrintSettings failed"; DidFinishPrinting(FAIL_PRINT); return; @@ -781,34 +798,37 @@ void PrintWebViewHelper::OnPrintForPrintPreview( print_params.printable_area = gfx::Rect(print_params.page_size); // Render Pages for printing. - if (!RenderPagesForPrint(pdf_frame, pdf_element)) { + if (!RenderPagesForPrint(plugin_frame, plugin_element)) { LOG(ERROR) << "RenderPagesForPrint failed"; DidFinishPrinting(FAIL_PRINT); } } -bool PrintWebViewHelper::GetPrintFrame(blink::WebFrame** frame) { +bool PrintWebViewHelper::GetPrintFrame(blink::WebLocalFrame** frame) { DCHECK(frame); - DCHECK(render_view()->GetWebView()); - if (!render_view()->GetWebView()) + blink::WebView* webView = render_view()->GetWebView(); + DCHECK(webView); + if (!webView) return false; // If the user has selected text in the currently focused frame we print // only that frame (this makes print selection work for multiple frames). - *frame = render_view()->GetWebView()->focusedFrame()->hasSelection() ? - render_view()->GetWebView()->focusedFrame() : - render_view()->GetWebView()->mainFrame(); + blink::WebLocalFrame* focusedFrame = + webView->focusedFrame()->toWebLocalFrame(); + *frame = focusedFrame->hasSelection() + ? focusedFrame + : webView->mainFrame()->toWebLocalFrame(); return true; } void PrintWebViewHelper::OnPrintPages() { - blink::WebFrame* frame; + blink::WebLocalFrame* frame; if (GetPrintFrame(&frame)) Print(frame, blink::WebNode()); } void PrintWebViewHelper::OnPrintForSystemDialog() { - blink::WebFrame* frame = print_preview_context_.source_frame(); + blink::WebLocalFrame* frame = print_preview_context_.source_frame(); if (!frame) { NOTREACHED(); return; @@ -887,13 +907,13 @@ void PrintWebViewHelper::OnPrintPreview(const base::DictionaryValue& settings) { return; } - // If we are previewing a pdf and the print scaling is disabled, send a + // Set the options from document if we are previewing a pdf and send a // message to browser. if (print_pages_params_->params.is_first_request && - !print_preview_context_.IsModifiable() && - print_preview_context_.source_frame()->isPrintScalingDisabledForPlugin( - print_preview_context_.source_node())) { - Send(new PrintHostMsg_PrintPreviewScalingDisabled(routing_id())); + !print_preview_context_.IsModifiable()) { + PrintHostMsg_SetOptionsFromDocument_Params params; + SetOptionsFromDocument(params); + Send(new PrintHostMsg_SetOptionsFromDocument(routing_id(), params)); } is_print_ready_metafile_sent_ = false; @@ -1064,7 +1084,7 @@ void PrintWebViewHelper::SetScriptedPrintBlocked(bool blocked) { void PrintWebViewHelper::OnInitiatePrintPreview(bool selection_only) { DCHECK(is_preview_enabled_); - blink::WebFrame* frame; + blink::WebLocalFrame* frame; if (GetPrintFrame(&frame)) { print_preview_context_.InitWithFrame(frame); RequestPrintPreview(selection_only ? @@ -1108,7 +1128,7 @@ void PrintWebViewHelper::PrintNode(const blink::WebNode& node) { print_node_in_progress_ = false; } -void PrintWebViewHelper::Print(blink::WebFrame* frame, +void PrintWebViewHelper::Print(blink::WebLocalFrame* frame, const blink::WebNode& node) { // If still not finished with earlier print request simply ignore. if (prep_frame_view_) @@ -1294,16 +1314,14 @@ bool PrintWebViewHelper::InitPrintSettings(bool fit_to_paper_size) { return result; } -bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebFrame* frame, +bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame, const blink::WebNode& node, int* number_of_pages) { DCHECK(frame); bool fit_to_paper_size = !(PrintingNodeOrPdfFrame(frame, node)); if (!InitPrintSettings(fit_to_paper_size)) { notify_browser_of_print_failure_ = false; - render_view()->RunModalAlertDialog( - frame, - l10n_util::GetStringUTF16(IDS_PRINT_PREVIEW_INVALID_PRINTER_SETTINGS)); + Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id())); return false; } @@ -1317,8 +1335,17 @@ bool PrintWebViewHelper::CalculateNumberOfPages(blink::WebFrame* frame, return true; } +void PrintWebViewHelper::SetOptionsFromDocument( + PrintHostMsg_SetOptionsFromDocument_Params& params) { + blink::WebLocalFrame* source_frame = print_preview_context_.source_frame(); + const blink::WebNode& source_node = print_preview_context_.source_node(); + + params.is_scaling_disabled = + source_frame->isPrintScalingDisabledForPlugin(source_node); +} + bool PrintWebViewHelper::UpdatePrintSettings( - blink::WebFrame* frame, + blink::WebLocalFrame* frame, const blink::WebNode& node, const base::DictionaryValue& passed_job_settings) { DCHECK(is_preview_enabled_); @@ -1358,19 +1385,9 @@ bool PrintWebViewHelper::UpdatePrintSettings( if (!PrintMsg_Print_Params_IsValid(settings.params)) { if (!print_for_preview_) { print_preview_context_.set_error(PREVIEW_ERROR_INVALID_PRINTER_SETTINGS); - } else { - // PrintForPrintPreview - blink::WebFrame* print_frame = NULL; - // This may not be the right frame, but the alert will be modal, - // therefore it works well enough. - GetPrintFrame(&print_frame); - if (print_frame) { - render_view()->RunModalAlertDialog( - print_frame, - l10n_util::GetStringUTF16( - IDS_PRINT_PREVIEW_INVALID_PRINTER_SETTINGS)); - } - } + } else + Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id())); + return false; } @@ -1452,7 +1469,7 @@ bool PrintWebViewHelper::GetPrintSettingsFromUser(blink::WebFrame* frame, return (print_settings.params.dpi && print_settings.params.document_cookie); } -bool PrintWebViewHelper::RenderPagesForPrint(blink::WebFrame* frame, +bool PrintWebViewHelper::RenderPagesForPrint(blink::WebLocalFrame* frame, const blink::WebNode& node) { if (prep_frame_view_) return false; @@ -1634,7 +1651,7 @@ PrintWebViewHelper::PrintPreviewContext::~PrintPreviewContext() { } void PrintWebViewHelper::PrintPreviewContext::InitWithFrame( - blink::WebFrame* web_frame) { + blink::WebLocalFrame* web_frame) { DCHECK(web_frame); DCHECK(!IsRendering()); state_ = INITIALIZED; @@ -1810,7 +1827,7 @@ void PrintWebViewHelper::PrintPreviewContext::set_error( error_ = error; } -blink::WebFrame* PrintWebViewHelper::PrintPreviewContext::source_frame() { +blink::WebLocalFrame* PrintWebViewHelper::PrintPreviewContext::source_frame() { // TODO(thestig) turn this back into a DCHECK when http://crbug.com/118303 is // resolved. CHECK(state_ != UNINITIALIZED); @@ -1823,7 +1840,7 @@ const blink::WebNode& return source_node_; } -blink::WebFrame* PrintWebViewHelper::PrintPreviewContext::prepared_frame() { +blink::WebLocalFrame* PrintWebViewHelper::PrintPreviewContext::prepared_frame() { // TODO(thestig) turn this back into a DCHECK when http://crbug.com/118303 is // resolved. CHECK(state_ != UNINITIALIZED); diff --git a/src/renderer/printing/print_web_view_helper.h b/src/renderer/printing/print_web_view_helper.h index 5298812be6..7087738655 100644 --- a/src/renderer/printing/print_web_view_helper.h +++ b/src/renderer/printing/print_web_view_helper.h @@ -23,6 +23,7 @@ struct PrintMsg_Print_Params; struct PrintMsg_PrintPage_Params; struct PrintMsg_PrintPages_Params; +struct PrintHostMsg_SetOptionsFromDocument_Params; namespace base { class DictionaryValue; @@ -92,7 +93,7 @@ class PrintWebViewHelper // RenderViewObserver implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void PrintPage(blink::WebFrame* frame, bool user_initiated) OVERRIDE; + virtual void PrintPage(blink::WebLocalFrame* frame, bool user_initiated) OVERRIDE; // Message handlers --------------------------------------------------------- @@ -169,7 +170,7 @@ class PrintWebViewHelper // Main printing code ------------------------------------------------------- - void Print(blink::WebFrame* frame, const blink::WebNode& node); + void Print(blink::WebLocalFrame* frame, const blink::WebNode& node); // Notification when printing is done - signal tear-down/free resources. void DidFinishPrinting(PrintingResult result); @@ -181,14 +182,17 @@ class PrintWebViewHelper bool InitPrintSettings(bool fit_to_paper_size); // Calculate number of pages in source document. - bool CalculateNumberOfPages(blink::WebFrame* frame, + bool CalculateNumberOfPages(blink::WebLocalFrame* frame, const blink::WebNode& node, int* number_of_pages); + // Set options for print preset from source PDF document. + void SetOptionsFromDocument( + PrintHostMsg_SetOptionsFromDocument_Params& params); // Update the current print settings with new |passed_job_settings|. // |passed_job_settings| dictionary contains print job details such as printer // name, number of copies, page range, etc. - bool UpdatePrintSettings(blink::WebFrame* frame, + bool UpdatePrintSettings(blink::WebLocalFrame* frame, const blink::WebNode& node, const base::DictionaryValue& passed_job_settings); @@ -209,7 +213,7 @@ class PrintWebViewHelper void FinishFramePrinting(); // Prints the page listed in |params|. -#if defined(USE_X11) +#if defined(OS_LINUX) void PrintPageInternal(const PrintMsg_PrintPage_Params& params, const gfx::Size& canvas_size, blink::WebFrame* frame, @@ -221,7 +225,7 @@ class PrintWebViewHelper #endif // Render the frame for printing. - bool RenderPagesForPrint(blink::WebFrame* frame, + bool RenderPagesForPrint(blink::WebLocalFrame* frame, const blink::WebNode& node); // Platform specific helper function for rendering page(s) to |metafile|. @@ -280,7 +284,7 @@ class PrintWebViewHelper const base::DictionaryValue& header_footer_info, const PrintMsg_Print_Params& params); - bool GetPrintFrame(blink::WebFrame** frame); + bool GetPrintFrame(blink::WebLocalFrame** frame); // This reports the current time - |start_time| as the time to render a page. void ReportPreviewPageRenderTime(base::TimeTicks start_time); @@ -353,7 +357,7 @@ class PrintWebViewHelper // Initializes the print preview context. Need to be called to set // the |web_frame| / |web_node| to generate the print preview for. - void InitWithFrame(blink::WebFrame* web_frame); + void InitWithFrame(blink::WebLocalFrame* web_frame); void InitWithNode(const blink::WebNode& web_node); // Does bookkeeping at the beginning of print preview. @@ -394,13 +398,13 @@ class PrintWebViewHelper // Getters // Original frame for which preview was requested. - blink::WebFrame* source_frame(); + blink::WebLocalFrame* source_frame(); // Original node for which preview was requested. const blink::WebNode& source_node() const; // Frame to be use to render preview. May be the same as source_frame(), or // generated from it, e.g. copy of selected block. - blink::WebFrame* prepared_frame(); + blink::WebLocalFrame* prepared_frame(); // Node to be use to render preview. May be the same as source_node(), or // generated from it, e.g. copy of selected block. const blink::WebNode& prepared_node() const; @@ -423,7 +427,7 @@ class PrintWebViewHelper void ClearContext(); // Specifies what to render for print preview. - blink::WebFrame* source_frame_; + blink::WebLocalFrame* source_frame_; blink::WebNode source_node_; scoped_ptr prep_frame_view_; diff --git a/src/renderer/printing/print_web_view_helper_linux.cc b/src/renderer/printing/print_web_view_helper_linux.cc index a55fd9d3d6..d56faee6b3 100644 --- a/src/renderer/printing/print_web_view_helper_linux.cc +++ b/src/renderer/printing/print_web_view_helper_linux.cc @@ -16,7 +16,7 @@ #include "printing/page_size_margins.h" #include "skia/ext/platform_device.h" #include "skia/ext/vector_canvas.h" -#include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" namespace printing { diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index c16740bcea..e7000ca27b 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -58,7 +58,7 @@ #include "third_party/node/src/node_internals.h" #include "third_party/node/src/req_wrap.h" #include "third_party/WebKit/public/web/WebDocument.h" -#include "third_party/WebKit/public/web/WebFrame.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebSecurityOrigin.h" #include "third_party/WebKit/public/web/WebSecurityPolicy.h" #include "third_party/WebKit/public/web/WebView.h" @@ -72,6 +72,7 @@ using autofill::PasswordAutofillAgent; using autofill::PasswordGenerationAgent; using net::ProxyBypassRules; using blink::WebFrame; +using blink::WebLocalFrame; using blink::WebView; using blink::WebString; using blink::WebSecurityPolicy; @@ -82,7 +83,7 @@ namespace content { namespace { RenderView* GetCurrentRenderView() { - WebFrame* frame = WebFrame::frameForCurrentContext(); + WebLocalFrame* frame = WebLocalFrame::frameForCurrentContext(); DCHECK(frame); if (!frame) return NULL; diff --git a/src/shell_browser_context.cc b/src/shell_browser_context.cc index 7b82bf3919..998384a07b 100644 --- a/src/shell_browser_context.cc +++ b/src/shell_browser_context.cc @@ -164,7 +164,7 @@ net::URLRequestContextGetter* ShellBrowserContext::GetRequestContext() { net::URLRequestContextGetter* ShellBrowserContext::CreateRequestContext( ProtocolHandlerMap* protocol_handlers, - ProtocolHandlerScopedVector protocol_interceptors) { + URLRequestInterceptorScopedVector protocol_interceptors) { DCHECK(!url_request_getter_); CommandLine* cmd_line = CommandLine::ForCurrentProcess(); @@ -198,7 +198,8 @@ net::URLRequestContextGetter* ShellBrowserContext::CreateRequestContextForStoragePartition( const base::FilePath& partition_path, bool in_memory, - ProtocolHandlerMap* protocol_handlers) { + ProtocolHandlerMap* protocol_handlers, + URLRequestInterceptorScopedVector request_interceptors) { return NULL; } @@ -230,45 +231,20 @@ ResourceContext* ShellBrowserContext::GetResourceContext() { return resource_context_.get(); } -GeolocationPermissionContext* - ShellBrowserContext::GetGeolocationPermissionContext() { - return NULL; -} - quota::SpecialStoragePolicy* ShellBrowserContext::GetSpecialStoragePolicy() { return NULL; } -void ShellBrowserContext::RequestMidiSysExPermission( - int render_process_id, - int render_view_id, - int bridge_id, - const GURL& requesting_frame, - bool user_gesture, - const MidiSysExPermissionCallback& callback) { - callback.Run(true); -} - -void ShellBrowserContext::CancelMidiSysExPermissionRequest( - int render_process_id, - int render_view_id, - int bridge_id, - const GURL& requesting_frame) { +BrowserPluginGuestManager* ShellBrowserContext::GetGuestManager() { + return NULL; } -void ShellBrowserContext::RequestProtectedMediaIdentifierPermission( - int render_process_id, - int render_view_id, - int bridge_id, - int group_id, - const GURL& requesting_frame, - const ProtectedMediaIdentifierPermissionCallback& callback) { - callback.Run(true); +PushMessagingService* ShellBrowserContext::GetPushMessagingService() { + return NULL; } -void ShellBrowserContext::CancelProtectedMediaIdentifierPermissionRequests( - int group_id) { +SSLHostStateDelegate* ShellBrowserContext::GetSSLHostStateDelegate() { + return NULL; } - } // namespace content diff --git a/src/shell_browser_context.h b/src/shell_browser_context.h index 7b8b05ef33..70ca6621a0 100644 --- a/src/shell_browser_context.h +++ b/src/shell_browser_context.h @@ -49,44 +49,24 @@ class ShellBrowserContext : public BrowserContext { const FilePath& partition_path, bool in_memory) OVERRIDE; virtual ResourceContext* GetResourceContext() OVERRIDE; - virtual GeolocationPermissionContext* - GetGeolocationPermissionContext() OVERRIDE; virtual quota::SpecialStoragePolicy* GetSpecialStoragePolicy() OVERRIDE; - - virtual void RequestMidiSysExPermission( - int render_process_id, - int render_view_id, - int bridge_id, - const GURL& requesting_frame, - bool user_gesture, - const MidiSysExPermissionCallback& callback) OVERRIDE; - virtual void CancelMidiSysExPermissionRequest( - int render_process_id, - int render_view_id, - int bridge_id, - const GURL& requesting_frame) OVERRIDE; - virtual void RequestProtectedMediaIdentifierPermission( - int render_process_id, - int render_view_id, - int bridge_id, - int group_id, - const GURL& requesting_frame, - const ProtectedMediaIdentifierPermissionCallback& callback) OVERRIDE; - virtual void CancelProtectedMediaIdentifierPermissionRequests( - int group_id) OVERRIDE; + virtual BrowserPluginGuestManager* GetGuestManager() OVERRIDE; + virtual PushMessagingService* GetPushMessagingService() OVERRIDE; + virtual SSLHostStateDelegate* GetSSLHostStateDelegate() OVERRIDE; nw::NwFormDatabaseService* GetFormDatabaseService(); // Maps to BrowserMainParts::PreMainMessageLoopRun. void PreMainMessageLoopRun(); - virtual net::URLRequestContextGetter* CreateRequestContext( + net::URLRequestContextGetter* CreateRequestContext( ProtocolHandlerMap* protocol_handlers, - ProtocolHandlerScopedVector protocol_interceptors); - virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition( + URLRequestInterceptorScopedVector request_interceptors); + net::URLRequestContextGetter* CreateRequestContextForStoragePartition( const base::FilePath& partition_path, bool in_memory, - ProtocolHandlerMap* protocol_handlers); + ProtocolHandlerMap* protocol_handlers, + URLRequestInterceptorScopedVector request_interceptors); bool pinning_renderer() { return !disable_pinning_renderer_; } void set_pinning_renderer(bool val) { disable_pinning_renderer_ = !val; } diff --git a/src/shell_browser_main_parts.cc b/src/shell_browser_main_parts.cc index d26727bae4..f7b2b3ac7b 100644 --- a/src/shell_browser_main_parts.cc +++ b/src/shell_browser_main_parts.cc @@ -42,6 +42,7 @@ #include "grit/net_resources.h" #include "net/base/net_module.h" #include "net/proxy/proxy_resolver_v8.h" +#include "ui/base/ime/input_method_initializer.h" #include "ui/base/resource/resource_bundle.h" #if !defined(OS_WIN) @@ -155,7 +156,7 @@ void ShellBrowserMainParts::PostMainMessageLoopStart() { } int ShellBrowserMainParts::PreCreateThreads() { - net::ProxyResolverV8::RememberDefaultIsolate(); + net::ProxyResolverV8::EnsureIsolateCreated(); #if defined(USE_AURA) gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, views::CreateDesktopScreen()); @@ -174,7 +175,7 @@ void ShellBrowserMainParts::PostDestroyThreads() { void ShellBrowserMainParts::ToolkitInitialized() { #if defined(USE_AURA) - aura::Env::CreateInstance(); + aura::Env::CreateInstance(true); DCHECK(!views::ViewsDelegate::views_delegate); new views::DesktopTestViewsDelegate; @@ -280,7 +281,7 @@ void ShellBrowserMainParts::PreEarlyInitialization() { // see chrome_browser_main_posix.cc CommandLine& command_line = *CommandLine::ForCurrentProcess(); const std::string fd_limit_string = - command_line.GetSwitchValueASCII(switches::kFileDescriptorLimit); + command_line.GetSwitchValueASCII("file-descriptor-limit"); int fd_limit = 0; if (!fd_limit_string.empty()) { base::StringToInt(fd_limit_string, &fd_limit); @@ -295,6 +296,10 @@ void ShellBrowserMainParts::PreEarlyInitialization() { if (fd_limit > 0) SetFileDescriptorLimit(fd_limit); #endif // !OS_WIN + +#if defined(OS_LINUX) + ui::InitializeInputMethodForTesting(); +#endif } } // namespace content diff --git a/src/shell_content_browser_client.cc b/src/shell_content_browser_client.cc index d7cf1c17b5..197783c148 100644 --- a/src/shell_content_browser_client.cc +++ b/src/shell_content_browser_client.cc @@ -46,8 +46,6 @@ #include "content/nw/src/api/dispatcher_host.h" #if defined(OS_MACOSX) #include "content/nw/src/breakpad_mac.h" -#elif defined(OS_POSIX) -#include "content/nw/src/breakpad_linux.h" #endif #include "content/nw/src/common/shell_switches.h" #include "content/nw/src/browser/printing/print_job_manager.h" @@ -66,14 +64,20 @@ #include "ui/base/l10n/l10n_util.h" #include "ui/base/ui_base_switches.h" #include "content/common/dom_storage/dom_storage_map.h" -#include "webkit/common/webpreferences.h" +#include "content/public/common/web_preferences.h" #include "content/public/common/user_agent.h" #include "content/common/plugin_list.h" #include "content/public/browser/plugin_service.h" #include "chrome/common/chrome_switches.h" #if defined(OS_LINUX) #include "base/linux_util.h" -#include "content/nw/src/crash_handler_host_linux.h" +#endif + +#if defined(OS_POSIX) && !defined(OS_MACOSX) +#include "base/debug/leak_annotations.h" +#include "components/breakpad/app/breakpad_linux.h" +#include "components/breakpad/browser/crash_handler_host_linux.h" +#include "content/public/common/content_descriptors.h" #endif using base::FileDescriptor; @@ -81,21 +85,55 @@ using base::FileDescriptor; namespace { #if defined(OS_POSIX) && !defined(OS_MACOSX) +breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost( + const std::string& process_type) { + base::FilePath dumps_path = + CommandLine::ForCurrentProcess()->GetSwitchValuePath( + switches::kCrashDumpsDir); + { + ANNOTATE_SCOPED_MEMORY_LEAK; + breakpad::CrashHandlerHostLinux* crash_handler = + new breakpad::CrashHandlerHostLinux( + process_type, dumps_path, false); + crash_handler->StartUploaderThread(); + return crash_handler; + } +} + int GetCrashSignalFD(const CommandLine& command_line) { + if (!breakpad::IsCrashReporterEnabled()) + return -1; + std::string process_type = command_line.GetSwitchValueASCII(switches::kProcessType); - if (process_type == switches::kRendererProcess) - return RendererCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket(); + if (process_type == switches::kRendererProcess) { + static breakpad::CrashHandlerHostLinux* crash_handler = NULL; + if (!crash_handler) + crash_handler = CreateCrashHandlerHost(process_type); + return crash_handler->GetDeathSignalSocket(); + } - if (process_type == switches::kPluginProcess) - return PluginCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket(); + if (process_type == switches::kPluginProcess) { + static breakpad::CrashHandlerHostLinux* crash_handler = NULL; + if (!crash_handler) + crash_handler = CreateCrashHandlerHost(process_type); + return crash_handler->GetDeathSignalSocket(); + } - if (process_type == switches::kPpapiPluginProcess) - return PpapiCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket(); + if (process_type == switches::kPpapiPluginProcess) { + static breakpad::CrashHandlerHostLinux* crash_handler = NULL; + if (!crash_handler) + crash_handler = CreateCrashHandlerHost(process_type); + return crash_handler->GetDeathSignalSocket(); + } - if (process_type == switches::kGpuProcess) - return GpuCrashHandlerHostLinux::GetInstance()->GetDeathSignalSocket(); + if (process_type == switches::kGpuProcess) { + static breakpad::CrashHandlerHostLinux* crash_handler = NULL; + if (!crash_handler) + crash_handler = CreateCrashHandlerHost(process_type); + return crash_handler->GetDeathSignalSocket(); + } return -1; } @@ -137,7 +175,7 @@ bool ShellContentBrowserClient::GetUserAgentManifest(std::string* agent) { return false; } -WebContentsViewPort* ShellContentBrowserClient::OverrideCreateWebContentsView( +void ShellContentBrowserClient::OverrideCreateWebContentsView( WebContents* web_contents, RenderViewHostDelegateView** render_view_host_delegate_view, const WebContents::CreateParams& params) { @@ -154,7 +192,6 @@ WebContentsViewPort* ShellContentBrowserClient::OverrideCreateWebContentsView( prefs->nw_inject_css_fn = params.nw_inject_css_fn; prefs->nw_inject_js_doc_start = params.nw_inject_js_doc_start; prefs->nw_inject_js_doc_end = params.nw_inject_js_doc_end; - return NULL; } std::string ShellContentBrowserClient::GetApplicationLocale() { @@ -185,8 +222,10 @@ void ShellContentBrowserClient::AppendExtraCommandLineSwitches( if (command_line->GetSwitchValueASCII("type") != "renderer") return; +#if 0 if (content::IsThreadedCompositingEnabled()) command_line->AppendSwitch(switches::kEnableThreadedCompositing); +#endif //FIXME std::string user_agent; if (!command_line->HasSwitch(switches::kUserAgent) && @@ -247,9 +286,11 @@ void ShellContentBrowserClient::AppendExtraCommandLineSwitches( // destory rph immediately. Then the channel error msg is caught by // SuicideOnChannelErrorFilter and the renderer is killed // immediately +#if 0 //FIXME #if defined(OS_POSIX) command_line->AppendSwitch(switches::kChildCleanExit); #endif +#endif } @@ -288,7 +329,7 @@ AccessTokenStore* ShellContentBrowserClient::CreateAccessTokenStore() { void ShellContentBrowserClient::OverrideWebkitPrefs( RenderViewHost* render_view_host, const GURL& url, - WebPreferences* prefs) { + content::WebPreferences* prefs) { nw::Package* package = shell_browser_main_parts()->package(); // Disable web security. @@ -335,10 +376,10 @@ bool ShellContentBrowserClient::IsSuitableHost(RenderProcessHost* process_host, net::URLRequestContextGetter* ShellContentBrowserClient::CreateRequestContext( BrowserContext* content_browser_context, ProtocolHandlerMap* protocol_handlers, - ProtocolHandlerScopedVector protocol_interceptors) { + URLRequestInterceptorScopedVector request_interceptors) { ShellBrowserContext* shell_browser_context = ShellBrowserContextForBrowserContext(content_browser_context); - return shell_browser_context->CreateRequestContext(protocol_handlers, protocol_interceptors.Pass()); + return shell_browser_context->CreateRequestContext(protocol_handlers, request_interceptors.Pass()); } net::URLRequestContextGetter* @@ -347,11 +388,11 @@ ShellContentBrowserClient::CreateRequestContextForStoragePartition( const base::FilePath& partition_path, bool in_memory, ProtocolHandlerMap* protocol_handlers, - ProtocolHandlerScopedVector protocol_interceptors) { + URLRequestInterceptorScopedVector request_interceptors) { ShellBrowserContext* shell_browser_context = ShellBrowserContextForBrowserContext(content_browser_context); return shell_browser_context->CreateRequestContextForStoragePartition( - partition_path, in_memory, protocol_handlers); + partition_path, in_memory, protocol_handlers, request_interceptors.Pass()); } @@ -376,7 +417,7 @@ void ShellContentBrowserClient::RenderProcessWillLaunch( // Grant file: scheme to the whole process, since we impose // per-view access checks. content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme( - host->GetID(), content::kFileScheme); + host->GetID(), "file"); content::ChildProcessSecurityPolicy::GetInstance()->GrantScheme( host->GetID(), "app"); @@ -388,12 +429,12 @@ void ShellContentBrowserClient::RenderProcessWillLaunch( bool ShellContentBrowserClient::IsHandledURL(const GURL& url) { if (!url.is_valid()) return false; - DCHECK_EQ(url.scheme(), StringToLowerASCII(url.scheme())); + DCHECK_EQ(url.scheme(), base::StringToLowerASCII(url.scheme())); // Keep in sync with ProtocolHandlers added by // ShellURLRequestContextGetter::GetURLRequestContext(). static const char* const kProtocolList[] = { - content::kFileSystemScheme, - content::kFileScheme, + url::kFileSystemScheme, + url::kFileScheme, "app", }; for (size_t i = 0; i < arraysize(kProtocolList); ++i) { @@ -403,17 +444,17 @@ bool ShellContentBrowserClient::IsHandledURL(const GURL& url) { return false; } -void ShellContentBrowserClient::AllowCertificateError( - int render_process_id, - int render_view_id, - int cert_error, - const net::SSLInfo& ssl_info, - const GURL& request_url, - ResourceType::Type resource_type, - bool overridable, - bool strict_enforcement, - const base::Callback& callback, - content::CertificateRequestResultType* result) { +void ShellContentBrowserClient::AllowCertificateError(int render_process_id, + int render_frame_id, + int cert_error, + const net::SSLInfo& ssl_info, + const GURL& request_url, + ResourceType resource_type, + bool overridable, + bool strict_enforcement, + bool expired_previous_decision, + const base::Callback& callback, + CertificateRequestResultType* result) { VLOG(1) << "AllowCertificateError: " << request_url; CommandLine* cmd_line = CommandLine::ForCurrentProcess(); if (cmd_line->HasSwitch(switches::kIgnoreCertificateErrors)) { @@ -450,6 +491,7 @@ ShellContentBrowserClient::CreateQuotaPermissionContext() { return new ShellQuotaPermissionContext(); } +#if 0 void ShellContentBrowserClient::ShowDesktopNotification( const ShowDesktopNotificationHostMsgParams& params, int render_process_id, @@ -484,4 +526,24 @@ void ShellContentBrowserClient::CancelDesktopNotification( #endif } +#endif + +void ShellContentBrowserClient::RequestMidiSysExPermission( + WebContents* web_contents, + int bridge_id, + const GURL& requesting_frame, + bool user_gesture, + base::Callback result_callback, + base::Closure* cancel_callback) { + result_callback.Run(true); +} + +void ShellContentBrowserClient::RequestProtectedMediaIdentifierPermission( + WebContents* web_contents, + const GURL& origin, + base::Callback result_callback, + base::Closure* cancel_callback) { + result_callback.Run(true); +} + } // namespace content diff --git a/src/shell_content_browser_client.h b/src/shell_content_browser_client.h index f8ad489382..bb92bb843c 100644 --- a/src/shell_content_browser_client.h +++ b/src/shell_content_browser_client.h @@ -11,7 +11,6 @@ #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" #include "content/public/browser/content_browser_client.h" -#include "content/public/browser/web_contents_view.h" namespace printing { class PrintJobManager; @@ -32,7 +31,7 @@ class ShellContentBrowserClient : public ContentBrowserClient { // ContentBrowserClient overrides. virtual BrowserMainParts* CreateBrowserMainParts( const MainFunctionParams& parameters) OVERRIDE; - virtual WebContentsViewPort* OverrideCreateWebContentsView( + virtual void OverrideCreateWebContentsView( WebContents* web_contents, RenderViewHostDelegateView** render_view_host_delegate_view, const WebContents::CreateParams& params) OVERRIDE; @@ -65,24 +64,24 @@ class ShellContentBrowserClient : public ContentBrowserClient { virtual void RenderProcessWillLaunch(RenderProcessHost* host) OVERRIDE; virtual net::URLRequestContextGetter* CreateRequestContext( BrowserContext* browser_context, - ProtocolHandlerMap* protocol_handlers, ProtocolHandlerScopedVector protocol_interceptors) OVERRIDE; + ProtocolHandlerMap* protocol_handlers, URLRequestInterceptorScopedVector request_interceptors) OVERRIDE; virtual net::URLRequestContextGetter* CreateRequestContextForStoragePartition( BrowserContext* browser_context, const base::FilePath& partition_path, bool in_memory, ProtocolHandlerMap* protocol_handlers, - ProtocolHandlerScopedVector protocol_interceptors) OVERRIDE; - virtual void AllowCertificateError( - int render_process_id, - int render_view_id, - int cert_error, - const net::SSLInfo& ssl_info, - const GURL& request_url, - ResourceType::Type resource_type, - bool overridable, - bool strict_enforcement, - const base::Callback& callback, - content::CertificateRequestResultType* result) OVERRIDE; + URLRequestInterceptorScopedVector request_interceptors) OVERRIDE; + virtual void AllowCertificateError(int render_process_id, + int render_frame_id, + int cert_error, + const net::SSLInfo& ssl_info, + const GURL& request_url, + ResourceType resource_type, + bool overridable, + bool strict_enforcement, + bool expired_previous_decision, + const base::Callback& callback, + CertificateRequestResultType* result) OVERRIDE; virtual void GetAdditionalAllowedSchemesForFileSystem( std::vector* additional_schemes) OVERRIDE; #if defined(OS_POSIX) && !defined(OS_MACOSX) @@ -93,17 +92,33 @@ class ShellContentBrowserClient : public ContentBrowserClient { #endif virtual QuotaPermissionContext* CreateQuotaPermissionContext() OVERRIDE; +#if 0 //Notification virtual void ShowDesktopNotification( const ShowDesktopNotificationHostMsgParams& params, int render_process_id, int render_view_id, - bool worker) OVERRIDE; - + bool worker) ; //FIXME + virtual void CancelDesktopNotification( int render_process_id, int render_view_id, - int notification_id) OVERRIDE; + int notification_id) ; //FIXME +#endif + + virtual void RequestMidiSysExPermission( + WebContents* web_contents, + int bridge_id, + const GURL& requesting_frame, + bool user_gesture, + base::Callback result_callback, + base::Closure* cancel_callback) OVERRIDE; + + virtual void RequestProtectedMediaIdentifierPermission( + WebContents* web_contents, + const GURL& origin, + base::Callback result_callback, + base::Closure* cancel_callback) OVERRIDE; private: ShellBrowserContext* ShellBrowserContextForBrowserContext( diff --git a/src/shell_devtools_frontend.cc b/src/shell_devtools_frontend.cc index 21517511f7..905758ca9f 100644 --- a/src/shell_devtools_frontend.cc +++ b/src/shell_devtools_frontend.cc @@ -5,11 +5,14 @@ #include "content/nw/src/shell_devtools_frontend.h" #include "base/command_line.h" +#include "base/json/json_reader.h" #include "base/path_service.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/utf_string_conversions.h" #include "content/public/browser/devtools_http_handler.h" #include "content/public/browser/devtools_manager.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" #include "content/public/common/content_client.h" #include "content/nw/src/nw_shell.h" #include "content/nw/src/shell_browser_context.h" @@ -18,6 +21,7 @@ #include "content/nw/src/browser/shell_devtools_delegate.h" #include "net/base/net_util.h" +#include "net/base/filename_util.h" namespace content { @@ -47,7 +51,7 @@ ShellDevToolsFrontend* ShellDevToolsFrontend::Show( #endif void ShellDevToolsFrontend::Focus() { - web_contents()->GetView()->Focus(); + web_contents()->Focus(); } void ShellDevToolsFrontend::Close() { @@ -58,8 +62,6 @@ ShellDevToolsFrontend::ShellDevToolsFrontend(Shell* frontend_shell, : WebContentsObserver(frontend_shell->web_contents()), frontend_shell_(frontend_shell), agent_host_(agent_host) { - frontend_host_.reset( - DevToolsClientHost::CreateDevToolsFrontendHost(web_contents(), this)); } ShellDevToolsFrontend::~ShellDevToolsFrontend() { @@ -67,19 +69,68 @@ ShellDevToolsFrontend::~ShellDevToolsFrontend() { void ShellDevToolsFrontend::RenderViewCreated( RenderViewHost* render_view_host) { - DevToolsClientHost::SetupDevToolsFrontendClient(render_view_host); - // web_contents()->GetRenderViewHost()); - DevToolsManager* manager = DevToolsManager::GetInstance(); - manager->RegisterDevToolsClientHostFor(agent_host_.get(), - frontend_host_.get()); +#if 0 + if (!frontend_host_) { + frontend_host_.reset(DevToolsFrontendHost::Create(render_view_host, this)); + DevToolsManager::GetInstance()->RegisterDevToolsClientHostFor( + agent_host_.get(), this); + } +#endif } -void ShellDevToolsFrontend::WebContentsDestroyed(WebContents* web_contents) { - DevToolsManager::GetInstance()->ClientHostClosing(frontend_host_.get()); +void ShellDevToolsFrontend::WebContentsDestroyed() { + DevToolsManager::GetInstance()->ClientHostClosing(this); delete this; } void ShellDevToolsFrontend::InspectedContentsClosing() { } +void ShellDevToolsFrontend::DispatchOnInspectorFrontend( + const std::string& message) { + std::string code = "InspectorFrontendAPI.dispatchMessage(" + message + ");"; + base::string16 javascript = base::UTF8ToUTF16(code); + web_contents()->GetMainFrame()->ExecuteJavaScript(javascript); +} + +void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontend( + const std::string& message) { + std::string method; + std::string browser_message; + int id = 0; + + base::ListValue* params = NULL; + base::DictionaryValue* dict = NULL; + scoped_ptr parsed_message(base::JSONReader::Read(message)); + if (!parsed_message || + !parsed_message->GetAsDictionary(&dict) || + !dict->GetString("method", &method) || + !dict->GetList("params", ¶ms)) { + return; + } + + if (method != "sendMessageToBrowser" || + params->GetSize() != 1 || + !params->GetString(0, &browser_message)) { + return; + } + dict->GetInteger("id", &id); + + DevToolsManager::GetInstance()->DispatchOnInspectorBackend( + this, browser_message); + + if (id) { + std::string code = "InspectorFrontendAPI.embedderMessageAck(" + + base::IntToString(id) + ",\"\");"; + base::string16 javascript = base::UTF8ToUTF16(code); + web_contents()->GetMainFrame()->ExecuteJavaScript(javascript); + } +} + +void ShellDevToolsFrontend::HandleMessageFromDevToolsFrontendToBackend( + const std::string& message) { + DevToolsManager::GetInstance()->DispatchOnInspectorBackend( + this, message); +} + } // namespace content diff --git a/src/shell_devtools_frontend.h b/src/shell_devtools_frontend.h index 78de5b0eae..fdba3b2c0e 100644 --- a/src/shell_devtools_frontend.h +++ b/src/shell_devtools_frontend.h @@ -11,7 +11,7 @@ #include "base/memory/scoped_ptr.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_client_host.h" -#include "content/public/browser/devtools_frontend_host_delegate.h" +#include "content/public/browser/devtools_frontend_host.h" #include "content/public/browser/web_contents_observer.h" namespace content { @@ -21,10 +21,11 @@ class Shell; class WebContents; class ShellDevToolsFrontend : public WebContentsObserver, - public DevToolsFrontendHostDelegate { + public DevToolsFrontendHost::Delegate, + public DevToolsClientHost { public: - // static ShellDevToolsFrontend* Show(WebContents* inspected_contents); + //static ShellDevToolsFrontend* Show(WebContents* inspected_contents); void Focus(); void Close(); @@ -36,15 +37,22 @@ class ShellDevToolsFrontend : public WebContentsObserver, // WebContentsObserver overrides virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE; - virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE; + virtual void WebContentsDestroyed() OVERRIDE; - // DevToolsFrontendHostDelegate implementation - virtual void DispatchOnEmbedder(const std::string& message) OVERRIDE {} + // content::DevToolsFrontendHost::Delegate implementation. + virtual void HandleMessageFromDevToolsFrontend( + const std::string& message) OVERRIDE; + virtual void HandleMessageFromDevToolsFrontendToBackend( + const std::string& message) OVERRIDE; + + // content::DevToolsClientHost implementation. + virtual void DispatchOnInspectorFrontend(const std::string& message) OVERRIDE; virtual void InspectedContentsClosing() OVERRIDE; + virtual void ReplacedWithAnotherClient() OVERRIDE {} Shell* frontend_shell_; scoped_refptr agent_host_; - scoped_ptr frontend_host_; + scoped_ptr frontend_host_; DISALLOW_COPY_AND_ASSIGN(ShellDevToolsFrontend); }; diff --git a/src/shell_main_delegate.cc b/src/shell_main_delegate.cc index 2378273cad..32e2690136 100644 --- a/src/shell_main_delegate.cc +++ b/src/shell_main_delegate.cc @@ -31,7 +31,7 @@ #include "content/public/browser/render_process_host.h" #include "content/public/common/content_switches.h" #include "content/public/common/url_constants.h" -#include "content/nw/src/breakpad_linux.h" +//#include "content/nw/src/breakpad_linux.h" #include "content/nw/src/chrome_breakpad_client.h" #include "content/nw/src/common/shell_switches.h" #include "content/nw/src/nw_version.h" @@ -64,6 +64,10 @@ using base::FilePath; #include "content/nw/src/breakpad_win.h" #endif +#if defined(OS_POSIX) && !defined(OS_MACOSX) +#include "components/breakpad/app/breakpad_linux.h" +#endif + #include "ipc/ipc_message.h" // For IPC_MESSAGE_LOG_ENABLED. #if defined(IPC_MESSAGE_LOG_ENABLED) @@ -173,7 +177,7 @@ void ShellMainDelegate::PreSandboxStartup() { command_line->GetSwitchValueASCII(switches::kProcessType); if (process_type != switches::kZygoteProcess) - breakpad::InitCrashReporter(); + breakpad::InitCrashReporter(process_type); // Just prevent sandbox. command_line->AppendSwitch(switches::kNoSandbox); @@ -237,7 +241,10 @@ ContentRendererClient* ShellMainDelegate::CreateContentRendererClient() { void ShellMainDelegate::ZygoteForked() { // Needs to be called after we have chrome::DIR_USER_DATA. BrowserMain sets // this up for the browser process in a different manner. - breakpad::InitCrashReporter(); + const CommandLine* command_line = CommandLine::ForCurrentProcess(); + std::string process_type = + command_line->GetSwitchValueASCII(switches::kProcessType); + breakpad::InitCrashReporter(process_type); } #endif diff --git a/src/shell_quota_permission_context.cc b/src/shell_quota_permission_context.cc index 2a78e40b16..1387a5ca5d 100644 --- a/src/shell_quota_permission_context.cc +++ b/src/shell_quota_permission_context.cc @@ -11,11 +11,8 @@ namespace content { ShellQuotaPermissionContext::ShellQuotaPermissionContext() {} void ShellQuotaPermissionContext::RequestQuotaPermission( - const GURL& origin_url, - quota::StorageType type, - int64 requested_quota, + const StorageQuotaParams& params, int render_process_id, - int render_view_id, const PermissionCallback& callback) { callback.Run(QUOTA_PERMISSION_RESPONSE_ALLOW); } diff --git a/src/shell_quota_permission_context.h b/src/shell_quota_permission_context.h index ad095f58c3..f4c246c1eb 100644 --- a/src/shell_quota_permission_context.h +++ b/src/shell_quota_permission_context.h @@ -16,11 +16,8 @@ class ShellQuotaPermissionContext : public QuotaPermissionContext { // The callback will be dispatched on the IO thread. virtual void RequestQuotaPermission( - const GURL& origin_url, - quota::StorageType type, - int64 new_quota, + const StorageQuotaParams& params, int render_process_id, - int render_view_id, const PermissionCallback& callback) OVERRIDE; private: From f84e721097d5d71b2bedb0cc1903243d2de054d5 Mon Sep 17 00:00:00 2001 From: Gnor Tech Date: Wed, 24 Sep 2014 15:42:13 +0800 Subject: [PATCH 193/492] support linux menu --- nw.gypi | 6 +- src/api/menu/menu.h | 1 + src/browser/browser_view_layout.cc | 74 ++++++++++++++++++ src/browser/browser_view_layout.h | 49 ++++++++++++ src/browser/menubar_view.cc | 118 +++++++++++++++++++++++++++++ src/browser/menubar_view.h | 63 +++++++++++++++ src/browser/native_window_aura.cc | 20 ++++- src/browser/native_window_aura.h | 7 +- src/common/shell_switches.h | 5 ++ 9 files changed, 338 insertions(+), 5 deletions(-) create mode 100644 src/browser/browser_view_layout.cc create mode 100644 src/browser/browser_view_layout.h create mode 100644 src/browser/menubar_view.cc create mode 100644 src/browser/menubar_view.h diff --git a/nw.gypi b/nw.gypi index 1dc86d1129..b03ba280ab 100644 --- a/nw.gypi +++ b/nw.gypi @@ -184,6 +184,8 @@ 'src/browser/autofill_popup_view_bridge.mm', 'src/browser/autofill_popup_controller_impl.cc', 'src/browser/autofill_popup_controller_impl.h', + 'src/browser/browser_view_layout.cc', + 'src/browser/browser_view_layout.h', # 'src/browser/tab_autofill_manager_delegate.cc', # 'src/browser/tab_autofill_manager_delegate.h', 'src/browser/capture_page_helper.h', @@ -195,6 +197,8 @@ 'src/browser/chrome_event_processing_window.h', 'src/browser/file_select_helper.cc', 'src/browser/file_select_helper.h', + 'src/browser/menubar_view.cc', + 'src/browser/menubar_view.h', 'src/browser/native_window.cc', 'src/browser/native_window.h', 'src/browser/native_window_helper_mac.h', @@ -612,7 +616,7 @@ '<(SHARED_INTERMEDIATE_DIR)/webkit/devtools_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/blink/public/resources/blink_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_resources_100_percent.pak', - '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_strings_en-US.pak', + '<(SHARED_INTERMEDIATE_DIR)/content/app/strings/content_strings_en-US.pak', ], }, 'inputs': [ diff --git a/src/api/menu/menu.h b/src/api/menu/menu.h index b965dc72d6..2c30ff8a22 100644 --- a/src/api/menu/menu.h +++ b/src/api/menu/menu.h @@ -93,6 +93,7 @@ class Menu : public Base { #if defined(OS_WIN) || defined(OS_LINUX) void UpdateKeys(views::FocusManager *focus_manager); + ui::NwMenuModel* model() { return menu_model_.get(); } #endif private: diff --git a/src/browser/browser_view_layout.cc b/src/browser/browser_view_layout.cc new file mode 100644 index 0000000000..d30d49f22e --- /dev/null +++ b/src/browser/browser_view_layout.cc @@ -0,0 +1,74 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/browser_view_layout.h" +#include "content/nw/src/common/shell_switches.h" + +#include "base/logging.h" + +using views::View; + +namespace nw { + +BrowserViewLayout::BrowserViewLayout() + : menu_bar_(NULL), web_view_(NULL), tool_bar_(NULL) +{ +} + +BrowserViewLayout::~BrowserViewLayout() {} + +void BrowserViewLayout::Layout(View* host) { + if (!host->has_children()) + return; + + int y = 0; + gfx::Size host_size = host->GetContentsBounds().size(); + + if (menu_bar_) { + menu_bar_->SetBounds(0, y, host_size.width(), kMenuHeight); + y += kMenuHeight; + } + + if (tool_bar_) { + int height = tool_bar_->GetPreferredSize().height(); + tool_bar_->SetBounds(0, y, host_size.width(), height); + y += height; + } + + web_view_->SetBounds(0, y, host_size.width(), host_size.height() - y); +} + +gfx::Size BrowserViewLayout::GetPreferredSize(const View* host) const { + if (!host->has_children()) + return gfx::Size(); + + gfx::Rect rect(web_view_->GetPreferredSize()); + rect.Inset(-host->GetInsets()); + if (menu_bar_) + rect.Inset(0, 0, 0, -kMenuHeight); + + if (tool_bar_) + rect.Inset(0, 0, 0, -tool_bar_->GetPreferredSize().height()); + + return rect.size(); +} + +int BrowserViewLayout::GetPreferredHeightForWidth(const View* host, int width) const { + if (!host->has_children()) + return 0; + + const gfx::Insets insets = host->GetInsets(); + int ret = web_view_->GetHeightForWidth(width - insets.width()) + + insets.height(); + + if (menu_bar_) + ret += kMenuHeight; + + if (tool_bar_) + ret += tool_bar_->GetHeightForWidth(width - insets.width()); + + return ret; +} + +} // namespace views diff --git a/src/browser/browser_view_layout.h b/src/browser/browser_view_layout.h new file mode 100644 index 0000000000..7854d06de4 --- /dev/null +++ b/src/browser/browser_view_layout.h @@ -0,0 +1,49 @@ +// Copyright (c) 2011 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NW_BROWSER_VIEW_LAYOUT_H_ +#define NW_BROWSER_VIEW_LAYOUT_H_ + +#include "base/compiler_specific.h" +#include "ui/views/layout/layout_manager.h" +#include "ui/views/view.h" + +namespace nw { + +/////////////////////////////////////////////////////////////////////////////// +// +// copied from ui/views/layout/FillLayout +// +/////////////////////////////////////////////////////////////////////////////// +class BrowserViewLayout : public views::LayoutManager { + public: + BrowserViewLayout(); + virtual ~BrowserViewLayout(); + + // Overridden from LayoutManager: + virtual void Layout(views::View* host) OVERRIDE; + virtual gfx::Size GetPreferredSize(const views::View* host) const OVERRIDE; + virtual int GetPreferredHeightForWidth(const views::View* host, + int width) const OVERRIDE; + + void set_menu_bar(views::View* menu_bar) { menu_bar_ = menu_bar; } + views::View* menu_bar() { return menu_bar_; } + + void set_web_view(views::View* web_view) { web_view_ = web_view; } + views::View* web_view() { return web_view_; } + + void set_tool_bar(views::View* tool_bar) { tool_bar_ = tool_bar; } + views::View* tool_bar() { return tool_bar_; } + + private: + views::View* menu_bar_; + views::View* web_view_; + views::View* tool_bar_; + + DISALLOW_COPY_AND_ASSIGN(BrowserViewLayout); +}; + +} // namespace nw + +#endif // NW_BROWSER_VIEW_LAYOUT_H_ diff --git a/src/browser/menubar_view.cc b/src/browser/menubar_view.cc new file mode 100644 index 0000000000..b4c103aa81 --- /dev/null +++ b/src/browser/menubar_view.cc @@ -0,0 +1,118 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/menubar_view.h" +#include "ui/base/models/menu_model.h" +#include "ui/base/window_open_disposition.h" +#include "ui/gfx/text_elider.h" +#include "ui/views/controls/button/menu_button.h" +#include "ui/views/controls/menu/menu_runner.h" +#include "ui/views/layout/box_layout.h" +#include "ui/views/widget/widget.h" + +using views::MenuRunner; + +#if !defined(OS_WIN) +static const gfx::ElideBehavior kElideBehavior = gfx::FADE_TAIL; +#else +// Windows fade eliding causes text to darken; see http://crbug.com/388084 +static const gfx::ElideBehavior kElideBehavior = gfx::ELIDE_TAIL; +#endif + +namespace nw { + +const char MenuBarView::kViewClassName[] = "BookmarkBarView"; + +// MenuBarButton ------------------------------------------------------- + +// Buttons used on the menu bar. Copied from BookmarkFolderButton + +class MenuBarButton : public views::MenuButton { + public: + MenuBarButton(views::ButtonListener* listener, + const base::string16& title, + views::MenuButtonListener* menu_button_listener, + bool show_menu_marker) + : MenuButton(listener, title, menu_button_listener, show_menu_marker) { + SetElideBehavior(kElideBehavior); + } + + virtual bool GetTooltipText(const gfx::Point& p, + base::string16* tooltip) const OVERRIDE { + if (label()->GetPreferredSize().width() > label()->size().width()) + *tooltip = GetText(); + return !tooltip->empty(); + } + + virtual bool IsTriggerableEvent(const ui::Event& e) OVERRIDE { + // Left clicks and taps should show the menu contents and right clicks + // should show the context menu. They should not trigger the opening of + // underlying urls. + if (e.type() == ui::ET_GESTURE_TAP || + (e.IsMouseEvent() && (e.flags() & + (ui::EF_LEFT_MOUSE_BUTTON | ui::EF_RIGHT_MOUSE_BUTTON)))) + return false; + + if (e.IsMouseEvent()) + return ui::DispositionFromEventFlags(e.flags()) != CURRENT_TAB; + return false; + } + + private: + + DISALLOW_COPY_AND_ASSIGN(MenuBarButton); +}; + +MenuBarView::MenuBarView() { + SetLayoutManager(new views::BoxLayout(views::BoxLayout::kHorizontal, 0, 0, 0)); +} + +MenuBarView::~MenuBarView() { +} + +void MenuBarView::UpdateMenu(ui::MenuModel* model) { + RemoveAllChildViews(true); + InitView(model); + Layout(); + PreferredSizeChanged(); + SchedulePaint(); +} + +void MenuBarView::InitView(ui::MenuModel* model) { + model_ = model; + for (int i = 0; i < model_->GetItemCount(); i++) { + AddChildView(new MenuBarButton(this, model_->GetLabelAt(i), this, false)); + } +} + +void MenuBarView::OnMenuButtonClicked(views::View* view, + const gfx::Point& point) { + int button_index = GetIndexOf(view); + DCHECK_NE(-1, button_index); + ui::MenuModel::ItemType type = model_->GetTypeAt(button_index); + if (type == ui::MenuModel::TYPE_SUBMENU) { + menu_runner_.reset(new MenuRunner(model_->GetSubmenuModelAt(button_index), + MenuRunner::HAS_MNEMONICS)); + + if (menu_runner_->RunMenuAt(GetWidget()->GetTopLevelWidget(), + NULL, + gfx::Rect(point, gfx::Size()), + views::MENU_ANCHOR_TOPRIGHT, + ui::MENU_SOURCE_NONE) == + MenuRunner::MENU_DELETED) { + return; + } + } +} + +void MenuBarView::ButtonPressed(views::Button* sender, + const ui::Event& event) { +} + +void MenuBarView::OnNativeThemeChanged(const ui::NativeTheme* theme) { + set_background(views::Background::CreateSolidBackground(GetNativeTheme()-> + GetSystemColor(ui::NativeTheme::kColorId_MenuBackgroundColor))); +} + +} //namespace nw diff --git a/src/browser/menubar_view.h b/src/browser/menubar_view.h new file mode 100644 index 0000000000..f3fa24b837 --- /dev/null +++ b/src/browser/menubar_view.h @@ -0,0 +1,63 @@ +// 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. + +#ifndef NW_BROWSER_MENUBAR_VIEWS_H_ +#define NW_BROWSER_MENUBAR_VIEWS_H_ + +#include "base/strings/string16.h" +#include "ui/views/accessible_pane_view.h" +#include "ui/views/controls/button/button.h" +#include "ui/views/controls/button/menu_button_listener.h" + +namespace views { + class MenuRunner; +} + +namespace ui { + class MenuModel; +} + +namespace nw { + +/////////////////////////////////////////////////////////////////////////////// +// +// copied from chrome/browser/ui/views/bookmarks/bookmark_bar_view.h +// +/////////////////////////////////////////////////////////////////////////////// + +class MenuBarView : + public views::AccessiblePaneView, + public views::MenuButtonListener, + public views::ButtonListener { + + public: + // The internal view class name. + static const char kViewClassName[]; + + // Maximum size of buttons + static const int kMaxButtonWidth; + + // |browser_view| can be NULL during tests. + MenuBarView(); + virtual ~MenuBarView(); + + void UpdateMenu(ui::MenuModel* model); + void InitView(ui::MenuModel* model); + + // views::MenuButtonListener: + virtual void OnMenuButtonClicked(views::View* view, + const gfx::Point& point) OVERRIDE; + + // views::ButtonListener: + virtual void ButtonPressed(views::Button* sender, + const ui::Event& event) OVERRIDE; + virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE; + + private: + ui::MenuModel* model_; + scoped_ptr menu_runner_; + DISALLOW_COPY_AND_ASSIGN(MenuBarView); +}; +} //namespace nw +#endif diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index cb055ff2e8..2608d9de17 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -35,6 +35,8 @@ #include "chrome/browser/platform_util.h" #include "content/nw/src/api/menu/menu.h" +#include "content/nw/src/browser/browser_view_layout.h" +#include "content/nw/src/browser/menubar_view.h" #include "content/nw/src/browser/native_window_toolbar_aura.h" #include "content/nw/src/common/shell_switches.h" #include "content/nw/src/nw_shell.h" @@ -606,6 +608,13 @@ void NativeWindowAura::SetMenu(nwapi::Menu* menu) { window_->set_has_menu_bar(true); menu_ = menu; + MenuBarView* menubar = new MenuBarView(); + GetBrowserViewLayout()->set_menu_bar(menubar); + AddChildView(menubar); + menubar->UpdateMenu(menu->model()); + Layout(); + SchedulePaint(); + // The menu is lazily built. #if defined(OS_WIN) //FIXME menu->Rebuild(); @@ -618,6 +627,10 @@ void NativeWindowAura::SetMenu(nwapi::Menu* menu) { #endif } +BrowserViewLayout* NativeWindowAura::GetBrowserViewLayout() const { + return static_cast(GetLayoutManager()); +} + void NativeWindowAura::SetTitle(const std::string& title) { title_ = title; window_->UpdateWindowTitle(); @@ -625,6 +638,7 @@ void NativeWindowAura::SetTitle(const std::string& title) { void NativeWindowAura::AddToolbar() { toolbar_ = new NativeWindowToolbarAura(shell()); + GetBrowserViewLayout()->set_tool_bar(toolbar_); AddChildViewAt(toolbar_, 0); } @@ -789,6 +803,7 @@ void NativeWindowAura::HandleKeyboardEvent( // event.os_event.wParam, event.os_event.lParam); } +#if 0 void NativeWindowAura::Layout() { DCHECK(web_view_); if (toolbar_) { @@ -799,16 +814,17 @@ void NativeWindowAura::Layout() { } OnViewWasResized(); } +#endif void NativeWindowAura::ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) { if (details.is_add && details.child == this) { - views::BoxLayout* layout = new views::BoxLayout( - views::BoxLayout::kVertical, 0, 0, 0); + BrowserViewLayout* layout = new BrowserViewLayout(); SetLayoutManager(layout); web_view_ = new views::WebView(NULL); web_view_->SetWebContents(web_contents()); + layout->set_web_view(web_view_); AddChildView(web_view_); } } diff --git a/src/browser/native_window_aura.h b/src/browser/native_window_aura.h index 7076d2167a..1fc0129767 100644 --- a/src/browser/native_window_aura.h +++ b/src/browser/native_window_aura.h @@ -49,12 +49,13 @@ class Menu; namespace nw { +class BrowserViewLayout; class NativeWindowToolbarAura; class NativeWindowAura : public NativeWindow, public web_modal::WebContentsModalDialogHost, public views::WidgetFocusChangeListener, - public views::WidgetDelegateView , + public views::WidgetDelegateView, public views::WidgetObserver { public: explicit NativeWindowAura(const base::WeakPtr& shell, @@ -65,6 +66,8 @@ class NativeWindowAura : public NativeWindow, NativeWindowToolbarAura* toolbar() { return toolbar_; } views::Widget* window() { return window_; } + BrowserViewLayout* GetBrowserViewLayout() const; + // NativeWindow implementation. virtual void Close() OVERRIDE; virtual void Move(const gfx::Rect& pos) OVERRIDE; @@ -148,7 +151,7 @@ class NativeWindowAura : public NativeWindow, const content::NativeWebKeyboardEvent& event) OVERRIDE; // views::View implementation. - virtual void Layout() OVERRIDE; + // virtual void Layout() OVERRIDE; virtual void ViewHierarchyChanged( const ViewHierarchyChangedDetails& details) OVERRIDE; virtual gfx::Size GetMinimumSize() const OVERRIDE; diff --git a/src/common/shell_switches.h b/src/common/shell_switches.h index 79fe155eab..2eaf0d2814 100644 --- a/src/common/shell_switches.h +++ b/src/common/shell_switches.h @@ -7,6 +7,11 @@ #ifndef CONTENT_NW_SRC_SHELL_SWITCHES_H_ #define CONTENT_NW_SRC_SHELL_SWITCHES_H_ +namespace nw { + const int kMenuHeight = 25; + const int kToolbarHeight = 34; +} + namespace switches { extern const char kContentShellDataPath[]; From c3ca61b1dbcc802d217b7decfa66c8429ed24f8b Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Sun, 5 Oct 2014 15:46:05 +0800 Subject: [PATCH 194/492] rebase fix for windows --- nw.gypi | 28 +- src/api/dispatcher_bindings.cc | 4 +- src/api/menu/menu.h | 11 +- src/api/menu/menu_views.cc | 9 +- src/browser/autofill_popup_base_view.cc | 71 ++--- src/browser/autofill_popup_base_view.h | 29 +- src/browser/native_window.cc | 6 +- src/browser/native_window_aura.cc | 4 +- src/browser/native_window_aura.h | 1 - src/browser/printing/print_view_manager.cc | 2 +- .../shell_download_manager_delegate_win.cc | 3 +- .../shell_javascript_dialog_creator.cc | 4 +- src/browser/shell_login_dialog.cc | 2 +- src/browser/shell_login_dialog_win.cc | 29 +- src/nw_notification_manager_win.cc | 1 - src/nw_notification_manager_win.h | 10 +- src/nw_shell.cc | 6 +- .../printing/print_web_view_helper.cc | 5 +- src/renderer/printing/print_web_view_helper.h | 8 +- .../printing/print_web_view_helper_pdf_win.cc | 247 ++++++++++++++++++ src/shell_main_delegate.cc | 2 +- 21 files changed, 366 insertions(+), 116 deletions(-) create mode 100644 src/renderer/printing/print_web_view_helper_pdf_win.cc diff --git a/nw.gypi b/nw.gypi index b03ba280ab..5b91ae84d1 100644 --- a/nw.gypi +++ b/nw.gypi @@ -104,6 +104,8 @@ '<(DEPTH)/chrome/browser/ui/base_window.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_state_changer_win.cc', + '<(DEPTH)/chrome/browser/ui/views/status_icons/status_tray_state_changer_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', @@ -171,7 +173,6 @@ 'src/api/shortcut/shortcut_constants.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', @@ -236,7 +237,6 @@ 'src/browser/shell_download_manager_delegate.cc', 'src/browser/shell_download_manager_delegate.h', 'src/browser/shell_download_manager_delegate_win.cc', - 'src/browser/shell_download_manager_delegate_gtk.cc', 'src/browser/shell_download_manager_delegate_mac.mm', 'src/browser/shell_javascript_dialog_creator.cc', 'src/browser/shell_javascript_dialog_creator.h', @@ -265,8 +265,6 @@ 'src/breakpad_linux_impl.h', 'src/breakpad_mac.mm', 'src/breakpad_mac.h', - 'src/breakpad_win.cc', - 'src/breakpad_win.h', 'src/hard_error_handler_win.cc', 'src/hard_error_handler_win.h', 'src/geolocation/shell_access_token_store.cc', @@ -302,7 +300,6 @@ 'src/renderer/printing/print_web_view_helper.h', 'src/renderer/printing/print_web_view_helper_linux.cc', 'src/renderer/printing/print_web_view_helper_mac.mm', - 'src/renderer/printing/print_web_view_helper_win.cc', 'src/renderer/nw_render_view_observer.cc', 'src/renderer/nw_render_view_observer.h', 'src/renderer/shell_content_renderer_client.cc', @@ -381,6 +378,15 @@ '<(DEPTH)/build/win/ftol3.obj', ], }], + ['win_pdf_metafile_for_printing==1', { + 'sources': [ + 'src/renderer/printing/print_web_view_helper_pdf_win.cc', + ], + }, { + 'sources': [ + 'src/renderer/printing/print_web_view_helper_win.cc', + ], + }], ['OS=="win"', { 'sources': [ '<(DEPTH)/chrome/browser/ui/views/constrained_window_views.cc', @@ -440,8 +446,7 @@ 'dependencies': [ '<(DEPTH)/ui/views/controls/webview/webview.gyp:webview', '<(DEPTH)/ui/views/views.gyp:views', - '<(DEPTH)/webkit/webkit_resources.gyp:webkit_resources', - '<(DEPTH)/webkit/webkit_resources.gyp:webkit_strings', + #'<(DEPTH)/webkit/webkit_resources.gyp:webkit_strings', ], 'configurations': { 'Debug_Base': { @@ -452,7 +457,7 @@ }, }, }, - 'msvs_disabled_warnings': [ 4800 ], + 'msvs_disabled_warnings': [ 4800, 4819 ], }], # OS=="win" ], }, @@ -609,9 +614,9 @@ '<(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/resources/ui_resources_100_percent.pak', '<(SHARED_INTERMEDIATE_DIR)/ui/resources/webui_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/ui/strings/app_locale_settings_en-US.pak', '<(SHARED_INTERMEDIATE_DIR)/ui/strings/ui_strings_en-US.pak', '<(SHARED_INTERMEDIATE_DIR)/webkit/devtools_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/blink/public/resources/blink_resources.pak', @@ -820,9 +825,12 @@ ], }], ['OS=="win"', { + 'dependencies': [ + '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources', + ], 'sources': [ 'src/shell.rc', - '<(SHARED_INTERMEDIATE_DIR)/ui/ui_resources/ui_unscaled_resources.rc', + '<(SHARED_INTERMEDIATE_DIR)/ui/resources/ui_unscaled_resources.rc', ], 'configurations': { 'Debug_Base': { diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 5e01466c9b..36fbdf1c90 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -461,8 +461,8 @@ void DispatcherBindings::CrashRenderer( void DispatcherBindings::SetCrashDumpDir( const v8::FunctionCallbackInfo& args) { #if defined(OS_WIN) || defined(OS_MACOSX) - std::string path = *v8::String::Utf8Value(args[0]); - SetCrashDumpPath(path.c_str()); + //std::string path = *v8::String::Utf8Value(args[0]); + //FIXME: SetCrashDumpPath(path.c_str()); #endif } diff --git a/src/api/menu/menu.h b/src/api/menu/menu.h index 2c30ff8a22..70db2361ee 100644 --- a/src/api/menu/menu.h +++ b/src/api/menu/menu.h @@ -28,6 +28,10 @@ #include #include +#if defined(OS_WIN) +#include "ui/views/controls/menu/native_menu_win.h" +#endif + #if defined(OS_MACOSX) #if __OBJC__ @class NSMenu; @@ -41,7 +45,6 @@ class NativeWindowCocoa; #elif defined(OS_WIN) || defined(OS_LINUX) #include "content/nw/src/api/menu/menu_delegate.h" -//#include "ui/views/controls/menu/native_menu_win.h" #include "chrome/browser/status_icons/status_icon_menu_model.h" #include "ui/views/focus/focus_manager.h" namespace nw { @@ -130,17 +133,17 @@ class Menu : public Base { void UpdateStates(); #elif defined(OS_WIN) - friend class nw::NativeWindowWin; + friend class nw::NativeWindowAura; void Rebuild(const HMENU *parent_menu = NULL); void UpdateStates(); - void SetWindow(nw::NativeWindowWin* win); + void SetWindow(nw::NativeWindowAura* win); //**Never Try to free this pointer** //We get it from top widget views::FocusManager *focus_manager_; std::vector menu_items_; - nw::NativeWindowWin* window_; + nw::NativeWindowAura* window_; // Flag to indicate the menu has been modified since last show, so we should // rebuild the menu before next show. bool is_menu_modified_; diff --git a/src/api/menu/menu_views.cc b/src/api/menu/menu_views.cc index 88ebc86357..192a87f04f 100644 --- a/src/api/menu/menu_views.cc +++ b/src/api/menu/menu_views.cc @@ -31,14 +31,17 @@ #include "ui/aura/client/screen_position_client.h" #include "ui/aura/window.h" #include "ui/aura/window_tree_host.h" -//#include "ui/gfx/gdi_util.h" -//#include "ui/gfx/icon_util.h" -//#include "ui/views/controls/menu/menu_2.h" #include "ui/views/controls/menu/menu_runner.h" #include "ui/views/widget/widget.h" #include "ui/views/focus/focus_manager.h" #include "vector" +#if defined(OS_WIN) +#include "ui/gfx/gdi_util.h" +#include "ui/gfx/icon_util.h" +#include "ui/views/controls/menu/menu_2.h" +#endif + namespace { #if defined(OS_WIN) diff --git a/src/browser/autofill_popup_base_view.cc b/src/browser/autofill_popup_base_view.cc index ef87bcb065..31a1335956 100644 --- a/src/browser/autofill_popup_base_view.cc +++ b/src/browser/autofill_popup_base_view.cc @@ -8,15 +8,9 @@ #include "base/location.h" #include "base/message_loop/message_loop.h" #include "chrome/browser/ui/autofill/popup_constants.h" -#include "ui/gfx/point.h" -#include "ui/gfx/screen.h" #include "ui/views/border.h" -#include "ui/views/event_utils.h" #include "ui/views/widget/widget.h" - -#if defined(USE_AURA) #include "ui/wm/core/window_animations.h" -#endif namespace autofill { @@ -49,7 +43,8 @@ AutofillPopupBaseView::~AutofillPopupBaseView() { } void AutofillPopupBaseView::DoShow() { - if (!GetWidget()) { + const bool initialize_widget = !GetWidget(); + if (initialize_widget) { observing_widget_->AddObserver(this); views::FocusManager* focus_manager = observing_widget_->GetFocusManager(); @@ -71,11 +66,10 @@ void AutofillPopupBaseView::DoShow() { params.parent = container_view(); widget->Init(params); widget->SetContentsView(this); -#if defined(USE_AURA) + // No animation for popup appearance (too distracting). wm::SetWindowVisibilityAnimationTransition( widget->GetNativeView(), wm::ANIMATE_HIDE); -#endif } SetBorder(views::Border::CreateSolidBorder(kPopupBorderThickness, @@ -84,8 +78,10 @@ void AutofillPopupBaseView::DoShow() { DoUpdateBoundsAndRedrawPopup(); GetWidget()->Show(); - if (ShouldHideOnOutsideClick()) - GetWidget()->SetCapture(this); + // Showing the widget can change native focus (which would result in an + // immediate hiding of the popup). Only start observing after shown. + if (initialize_widget) + views::WidgetFocusManager::GetInstance()->AddFocusChangeListener(this); } void AutofillPopupBaseView::DoHide() { @@ -108,6 +104,7 @@ void AutofillPopupBaseView::DoHide() { void AutofillPopupBaseView::RemoveObserver() { observing_widget_->GetFocusManager()->UnregisterAccelerators(this); observing_widget_->RemoveObserver(this); + views::WidgetFocusManager::GetInstance()->RemoveFocusChangeListener(this); } void AutofillPopupBaseView::DoUpdateBoundsAndRedrawPopup() { @@ -115,6 +112,13 @@ void AutofillPopupBaseView::DoUpdateBoundsAndRedrawPopup() { SchedulePaint(); } +void AutofillPopupBaseView::OnNativeFocusChange( + gfx::NativeView focused_before, + gfx::NativeView focused_now) { + if (GetWidget() && GetWidget()->GetNativeView() != focused_now) + HideController(); +} + void AutofillPopupBaseView::OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) { DCHECK_EQ(widget, observing_widget_); @@ -157,39 +161,10 @@ void AutofillPopupBaseView::OnMouseMoved(const ui::MouseEvent& event) { } bool AutofillPopupBaseView::OnMousePressed(const ui::MouseEvent& event) { - if (HitTestPoint(event.location())) - return true; - - if (ShouldHideOnOutsideClick()) { - GetWidget()->ReleaseCapture(); - - gfx::Point screen_loc = event.location(); - views::View::ConvertPointToScreen(this, &screen_loc); - - ui::MouseEvent mouse_event = event; - mouse_event.set_location(screen_loc); - - if (ShouldRepostEvent(mouse_event)) { - gfx::NativeView native_view = GetWidget()->GetNativeView(); - gfx::Screen* screen = gfx::Screen::GetScreenFor(native_view); - gfx::NativeWindow window = screen->GetWindowAtScreenPoint(screen_loc); - views::RepostLocatedEvent(window, mouse_event); - } - - HideController(); - // |this| is now deleted. - } - - return false; + return event.GetClickCount() == 1; } void AutofillPopupBaseView::OnMouseReleased(const ui::MouseEvent& event) { - // Because this view can can be shown in response to a mouse press, it can - // receive an OnMouseReleased event just after showing. This breaks the mouse - // capture, so restart capturing here. - if (ShouldHideOnOutsideClick() && GetWidget()) - GetWidget()->SetCapture(this); - // We only care about the left click. if (event.IsOnlyLeftMouseButton() && HitTestPoint(event.location())) AcceptSelection(event.location()); @@ -256,27 +231,13 @@ void AutofillPopupBaseView::ClearSelection() { delegate_->SelectionCleared(); } -bool AutofillPopupBaseView::ShouldHideOnOutsideClick() { - if (delegate_) - return delegate_->ShouldHideOnOutsideClick(); - - // |this| instance should be in the process of being destroyed, so the return - // value shouldn't matter. - return false; -} - void AutofillPopupBaseView::HideController() { if (delegate_) delegate_->Hide(); } -bool AutofillPopupBaseView::ShouldRepostEvent(const ui::MouseEvent& event) { - return delegate_->ShouldRepostEvent(event); -} - gfx::NativeView AutofillPopupBaseView::container_view() { return delegate_->container_view(); } - } // namespace autofill diff --git a/src/browser/autofill_popup_base_view.h b/src/browser/autofill_popup_base_view.h index e379f3d98b..72c4162952 100644 --- a/src/browser/autofill_popup_base_view.h +++ b/src/browser/autofill_popup_base_view.h @@ -6,7 +6,8 @@ #define CHROME_BROWSER_UI_VIEWS_AUTOFILL_AUTOFILL_POPUP_BASE_VIEW_H_ #include "base/memory/weak_ptr.h" -#include "content/nw/src/browser/autofill_popup_view_delegate.h" +#include "chrome/browser/ui/autofill/autofill_popup_view_delegate.h" +#include "ui/views/focus/widget_focus_manager.h" #include "ui/views/widget/widget_delegate.h" #include "ui/views/widget/widget_observer.h" @@ -23,7 +24,16 @@ namespace autofill { // Class that deals with the event handling for Autofill-style popups. This // class should only be instantiated by sub-classes. class AutofillPopupBaseView : public views::WidgetDelegateView, + public views::WidgetFocusChangeListener, public views::WidgetObserver { + public: + static const SkColor kBorderColor; + static const SkColor kHoveredBackgroundColor; + static const SkColor kItemTextColor; + static const SkColor kPopupBackground; + static const SkColor kValueTextColor; + static const SkColor kWarningTextColor; + protected: explicit AutofillPopupBaseView(AutofillPopupViewDelegate* delegate, views::Widget* observing_widget); @@ -38,13 +48,6 @@ class AutofillPopupBaseView : public views::WidgetDelegateView, // Update size of popup and paint. void DoUpdateBoundsAndRedrawPopup(); - static const SkColor kBorderColor; - static const SkColor kHoveredBackgroundColor; - static const SkColor kItemTextColor; - static const SkColor kPopupBackground; - static const SkColor kValueTextColor; - static const SkColor kWarningTextColor; - private: friend class AutofillPopupBaseViewTest; @@ -58,6 +61,10 @@ class AutofillPopupBaseView : public views::WidgetDelegateView, virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; + // views::WidgetFocusChangeListener implementation. + virtual void OnNativeFocusChange(gfx::NativeView focused_before, + gfx::NativeView focused_now) OVERRIDE; + // views::WidgetObserver implementation. virtual void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) OVERRIDE; @@ -69,16 +76,10 @@ class AutofillPopupBaseView : public views::WidgetDelegateView, void AcceptSelection(const gfx::Point& point); void ClearSelection(); - // If the popup should be hidden if the user clicks outside it's bounds. - bool ShouldHideOnOutsideClick(); - // Hide the controller of this view. This assumes that doing so will // eventually hide this view in the process. void HideController(); - // Returns true if this event should be passed along. - bool ShouldRepostEvent(const ui::MouseEvent& event); - // Must return the container view for this popup. gfx::NativeView container_view(); diff --git a/src/browser/native_window.cc b/src/browser/native_window.cc index 2fbc31214a..548e2c763b 100644 --- a/src/browser/native_window.cc +++ b/src/browser/native_window.cc @@ -35,7 +35,7 @@ #elif defined(OS_LINUX) #include "content/nw/src/browser/native_window_aura.h" #elif defined(OS_WIN) -#include "content/nw/src/browser/native_window_win.h" +#include "content/nw/src/browser/native_window_aura.h" #endif @@ -57,7 +57,7 @@ NativeWindow* NativeWindow::Create(const base::WeakPtr& shell, #elif defined(OS_MACOSX) CreateNativeWindowCocoa(shell, manifest); #elif defined(OS_WIN) - new NativeWindowWin(shell, manifest); + new NativeWindowAura(shell, manifest); #else NULL; NOTREACHED() << "Cannot create native window on unsupported platform."; @@ -85,7 +85,7 @@ content::WebContents* NativeWindow::web_contents() const { void NativeWindow::InitFromManifest(base::DictionaryValue* manifest) { // Setup window from manifest. - int x, y; + int x, y = 0; std::string position; if (manifest->GetInteger(switches::kmX, &x) && manifest->GetInteger(switches::kmY, &y)) { diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index 2608d9de17..00d2dcd4cc 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -95,7 +95,7 @@ bool IsParent(gfx::NativeView child, gfx::NativeView possible_parent) { return true; #endif gfx::NativeView parent = child; - while ((parent = (gfx::NativeView)platform_util::GetParent(parent))) { + while ((parent = (gfx::NativeView)platform_util::GetParent(parent)) != NULL) { if (possible_parent == parent) return true; } @@ -919,7 +919,7 @@ void NativeWindowAura::OnViewWasResized() { int height = sz.height(), width = sz.width(); gfx::Path path; path.addRect(0, 0, width, height); - SetWindowRgn((HWND)web_contents()->GetView()->GetNativeView(), + SetWindowRgn((HWND)web_contents()->GetNativeView(), (HRGN)path.CreateNativeRegion(), 1); diff --git a/src/browser/native_window_aura.h b/src/browser/native_window_aura.h index 1fc0129767..f24ee6adb6 100644 --- a/src/browser/native_window_aura.h +++ b/src/browser/native_window_aura.h @@ -53,7 +53,6 @@ class BrowserViewLayout; class NativeWindowToolbarAura; class NativeWindowAura : public NativeWindow, - public web_modal::WebContentsModalDialogHost, public views::WidgetFocusChangeListener, public views::WidgetDelegateView, public views::WidgetObserver { diff --git a/src/browser/printing/print_view_manager.cc b/src/browser/printing/print_view_manager.cc index 76df2282c1..60a7c451fb 100644 --- a/src/browser/printing/print_view_manager.cc +++ b/src/browser/printing/print_view_manager.cc @@ -197,7 +197,7 @@ void PrintViewManager::OnDidPrintPage( } } -#if defined(OS_WIN) +#if defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING) bool big_emf = (params.data_size && params.data_size >= kMetafileMaxSize); const CommandLine* cmdline = CommandLine::ForCurrentProcess(); int raster_size = std::min(params.page_size.GetArea(), diff --git a/src/browser/shell_download_manager_delegate_win.cc b/src/browser/shell_download_manager_delegate_win.cc index 168d4957a0..9004a2af0c 100644 --- a/src/browser/shell_download_manager_delegate_win.cc +++ b/src/browser/shell_download_manager_delegate_win.cc @@ -34,7 +34,6 @@ #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" #include "ui/aura/window.h" @@ -59,7 +58,7 @@ void ShellDownloadManagerDelegate::ChooseDownloadPath( OPENFILENAME save_as; ZeroMemory(&save_as, sizeof(save_as)); save_as.lStructSize = sizeof(OPENFILENAME); - save_as.hwndOwner = (HWND)item->GetWebContents()->GetView()->GetNativeView()-> + save_as.hwndOwner = (HWND)item->GetWebContents()->GetNativeView()-> GetHost()->GetAcceleratedWidget(); save_as.lpstrFile = file_name; save_as.nMaxFile = arraysize(file_name); diff --git a/src/browser/shell_javascript_dialog_creator.cc b/src/browser/shell_javascript_dialog_creator.cc index 2d2e9dea0b..8b4b8a649c 100644 --- a/src/browser/shell_javascript_dialog_creator.cc +++ b/src/browser/shell_javascript_dialog_creator.cc @@ -62,7 +62,7 @@ void ShellJavaScriptDialogCreator::RunJavaScriptDialog( } gfx::NativeWindow parent_window = - web_contents->GetView()->GetTopLevelNativeWindow(); + web_contents->GetTopLevelNativeWindow(); dialog_.reset(new ShellJavaScriptDialog(this, parent_window, @@ -101,7 +101,7 @@ void ShellJavaScriptDialogCreator::RunBeforeUnloadDialog( base::ASCIIToUTF16("\n\nIs it OK to leave/reload this page?"); gfx::NativeWindow parent_window = - web_contents->GetView()->GetTopLevelNativeWindow(); + web_contents->GetTopLevelNativeWindow(); dialog_.reset(new ShellJavaScriptDialog(this, parent_window, diff --git a/src/browser/shell_login_dialog.cc b/src/browser/shell_login_dialog.cc index d5888030fe..78eb02c768 100644 --- a/src/browser/shell_login_dialog.cc +++ b/src/browser/shell_login_dialog.cc @@ -112,7 +112,7 @@ void ShellLoginDialog::ReleaseSoon() { BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this); } -#if !defined(OS_MACOSX) //FIXME +#if defined(OS_LINUX) //FIXME // Bogus implementations for linking. They are never called because // ResourceDispatcherHostDelegate::CreateLoginDelegate returns NULL. // TODO: implement ShellLoginDialog for other platforms, drop this #if diff --git a/src/browser/shell_login_dialog_win.cc b/src/browser/shell_login_dialog_win.cc index 156d3af07f..113b25f256 100644 --- a/src/browser/shell_login_dialog_win.cc +++ b/src/browser/shell_login_dialog_win.cc @@ -23,6 +23,7 @@ #include "base/logging.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" +#include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_host.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" @@ -33,13 +34,33 @@ #include "content/public/browser/resource_dispatcher_host.h" #include "content/public/browser/resource_request_info.h" #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" #include "ui/base/l10n/l10n_util.h" #include "ui/views/widget/widget.h" using web_modal::WebContentsModalDialogManager; using web_modal::WebContentsModalDialogManagerDelegate; +namespace { + +// The captive portal dialog is system-modal, but uses the web-content-modal +// dialog manager (odd) and requires this atypical dialog widget initialization. +views::Widget* CreateWindowAsFramelessChild(views::WidgetDelegate* delegate, + gfx::NativeView parent) { + views::Widget* widget = new views::Widget; + + views::Widget::InitParams params; + params.delegate = delegate; + params.child = true; + params.parent = parent; + params.remove_standard_frame = true; + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + + widget->Init(params); + return widget; +} + +} // namespace + namespace content { void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) { @@ -61,9 +82,11 @@ void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) { WebContentsModalDialogManagerDelegate* modal_delegate = web_contents_modal_dialog_manager->delegate(); CHECK(modal_delegate); - dialog_ = views::Widget::CreateWindowAsFramelessChild( + dialog_ = CreateWindowAsFramelessChild( this, modal_delegate->GetWebContentsModalDialogHost()->GetHostView()); - web_contents_modal_dialog_manager->ShowDialog(dialog_->GetNativeView()); + web_modal::PopupManager* popup_manager = + web_modal::PopupManager::FromWebContents(requesting_contents); + popup_manager->ShowModalDialog(dialog_->GetNativeView(), requesting_contents); } diff --git a/src/nw_notification_manager_win.cc b/src/nw_notification_manager_win.cc index 3696db5b14..aa7f09eea9 100644 --- a/src/nw_notification_manager_win.cc +++ b/src/nw_notification_manager_win.cc @@ -145,7 +145,6 @@ bool NotificationManagerWin::AddDesktopNotification(const content::ShowDesktopNo // if we reach here, it means the function is called from image download callback render_process_id_ = render_process_id; render_view_id_ = render_view_id; - notification_id_ = params.notification_id; // set the default notification icon as the app icon gfx::Image icon = shell->window()->app_icon(); diff --git a/src/nw_notification_manager_win.h b/src/nw_notification_manager_win.h index ca40f1edee..f4a5d95a87 100644 --- a/src/nw_notification_manager_win.h +++ b/src/nw_notification_manager_win.h @@ -43,20 +43,20 @@ class NotificationManagerWin : public NotificationManager{ TrayObserver* status_observer_; // variable to store the latest notification data, windows can only show 1 notification - int render_process_id_, render_view_id_, notification_id_; + int render_process_id_, render_view_id_; // dispatch the events from the latest notification bool DesktopNotificationPostClick() { - return NotificationManager::DesktopNotificationPostClick(render_process_id_, render_view_id_, notification_id_); + return NotificationManager::DesktopNotificationPostClick(render_process_id_, render_view_id_, 0); } bool DesktopNotificationPostClose(bool by_user) { - return NotificationManager::DesktopNotificationPostClose(render_process_id_, render_view_id_, notification_id_, by_user); + return NotificationManager::DesktopNotificationPostClose(render_process_id_, render_view_id_, 0, by_user); } bool DesktopNotificationPostDisplay() { - return NotificationManager::DesktopNotificationPostDisplay(render_process_id_, render_view_id_, notification_id_); + return NotificationManager::DesktopNotificationPostDisplay(render_process_id_, render_view_id_, 0); } bool DesktopNotificationPostError(const base::string16& message) { - return NotificationManager::DesktopNotificationPostError(render_process_id_, render_view_id_, notification_id_, message); + return NotificationManager::DesktopNotificationPostError(render_process_id_, render_view_id_, 0, message); } // internal function for AddDesktopNotification diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 17b78e3cd3..879e5999fa 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -71,9 +71,9 @@ #if defined(OS_WIN) -#include "content/nw/src/browser/native_window_win.h" +#include "content/nw/src/browser/native_window_aura.h" #include "ui/views/controls/webview/webview.h" -using nw::NativeWindowWin; +using nw::NativeWindowAura; #endif #include "content/nw/src/browser/printing/print_view_manager.h" @@ -618,7 +618,7 @@ void Shell::WebContentsCreated(WebContents* source_contents, #if defined(OS_WIN) void Shell::WebContentsFocused(content::WebContents* web_contents) { - NativeWindowWin* win = static_cast(window_.get()); + NativeWindowAura* win = static_cast(window_.get()); if (win) // on aura this function is called in the middle of window creation win->web_view_->OnWebContentsFocused(web_contents); } diff --git a/src/renderer/printing/print_web_view_helper.cc b/src/renderer/printing/print_web_view_helper.cc index ec0b517101..0a3e84fa3f 100644 --- a/src/renderer/printing/print_web_view_helper.cc +++ b/src/renderer/printing/print_web_view_helper.cc @@ -1226,7 +1226,7 @@ void PrintWebViewHelper::PrintPages() { } #endif // !defined(OS_CHROMEOS) - if (!PrintPagesNative(prep_frame_view_->frame(), prep_frame_view_->node(), + if (!PrintPagesNative(prep_frame_view_->frame(), page_count, prep_frame_view_->GetPrintCanvasSize())) { LOG(ERROR) << "Printing failed."; return DidFinishPrinting(FAIL_PRINT); @@ -1237,7 +1237,8 @@ void PrintWebViewHelper::FinishFramePrinting() { prep_frame_view_.reset(); } -#if defined(OS_MACOSX) || defined(OS_WIN) +#if defined(OS_MACOSX) || \ + (defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING)) bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, const blink::WebNode& node, int page_count, diff --git a/src/renderer/printing/print_web_view_helper.h b/src/renderer/printing/print_web_view_helper.h index 7087738655..1da8b0787a 100644 --- a/src/renderer/printing/print_web_view_helper.h +++ b/src/renderer/printing/print_web_view_helper.h @@ -207,7 +207,6 @@ class PrintWebViewHelper void OnFramePreparedForPrintPages(); void PrintPages(); bool PrintPagesNative(blink::WebFrame* frame, - const blink::WebNode& node, int page_count, const gfx::Size& canvas_size); void FinishFramePrinting(); @@ -218,6 +217,13 @@ class PrintWebViewHelper const gfx::Size& canvas_size, blink::WebFrame* frame, Metafile* metafile); +#elif defined(WIN_PDF_METAFILE_FOR_PRINTING) + void PrintPageInternal(const PrintMsg_PrintPage_Params& params, + const gfx::Size& canvas_size, + blink::WebFrame* frame, + Metafile* metafile, + gfx::Size* page_size_in_dpi, + gfx::Rect* content_area_in_dpi); #else void PrintPageInternal(const PrintMsg_PrintPage_Params& params, const gfx::Size& canvas_size, diff --git a/src/renderer/printing/print_web_view_helper_pdf_win.cc b/src/renderer/printing/print_web_view_helper_pdf_win.cc new file mode 100644 index 0000000000..b7aa4a51a7 --- /dev/null +++ b/src/renderer/printing/print_web_view_helper_pdf_win.cc @@ -0,0 +1,247 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/renderer/printing/print_web_view_helper.h" + +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/process/process_handle.h" +#include "chrome/common/print_messages.h" +#include "content/public/renderer/render_thread.h" +#include "printing/metafile.h" +#include "printing/metafile_impl.h" +#include "printing/metafile_skia_wrapper.h" +#include "printing/page_size_margins.h" +#include "printing/units.h" +#include "skia/ext/platform_device.h" +#include "skia/ext/vector_canvas.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" + + +namespace printing { + +using blink::WebFrame; + +bool PrintWebViewHelper::RenderPreviewPage( + int page_number, + const PrintMsg_Print_Params& print_params) { + PrintMsg_PrintPage_Params page_params; + page_params.params = print_params; + page_params.page_number = page_number; + scoped_ptr draft_metafile; + Metafile* initial_render_metafile = print_preview_context_.metafile(); + if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) { + draft_metafile.reset(new PreviewMetafile); + initial_render_metafile = draft_metafile.get(); + } + + base::TimeTicks begin_time = base::TimeTicks::Now(); + PrintPageInternal(page_params, + print_preview_context_.GetPrintCanvasSize(), + print_preview_context_.prepared_frame(), + initial_render_metafile, + NULL, + NULL); + print_preview_context_.RenderedPreviewPage( + base::TimeTicks::Now() - begin_time); + if (draft_metafile.get()) { + draft_metafile->FinishDocument(); + } else if (print_preview_context_.IsModifiable() && + print_preview_context_.generate_draft_pages()) { + DCHECK(!draft_metafile.get()); + draft_metafile.reset( + print_preview_context_.metafile()->GetMetafileForCurrentPage()); + } + return PreviewPageRendered(page_number, draft_metafile.get()); +} + +bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, + int page_count, + const gfx::Size& canvas_size) { + NativeMetafile metafile; + if (!metafile.Init()) + return false; + + const PrintMsg_PrintPages_Params& params = *print_pages_params_; + std::vector printed_pages; + if (params.pages.empty()) { + for (int i = 0; i < page_count; ++i) { + printed_pages.push_back(i); + } + } else { + // TODO(vitalybuka): redesign to make more code cross platform. + for (size_t i = 0; i < params.pages.size(); ++i) { + if (params.pages[i] >= 0 && params.pages[i] < page_count) { + printed_pages.push_back(params.pages[i]); + } + } + } + if (printed_pages.empty()) + return false; + + std::vector page_size_in_dpi(printed_pages.size()); + std::vector content_area_in_dpi(printed_pages.size()); + + PrintMsg_PrintPage_Params page_params; + page_params.params = params.params; + for (size_t i = 0; i < printed_pages.size(); ++i) { + page_params.page_number = printed_pages[i]; + PrintPageInternal(page_params, + canvas_size, + frame, + &metafile, + &page_size_in_dpi[i], + &content_area_in_dpi[i]); + } + + // blink::printEnd() for PDF should be called before metafile is closed. + FinishFramePrinting(); + + metafile.FinishDocument(); + + // Get the size of the resulting metafile. + uint32 buf_size = metafile.GetDataSize(); + DCHECK_GT(buf_size, 0u); + + PrintHostMsg_DidPrintPage_Params printed_page_params; + printed_page_params.data_size = 0; + printed_page_params.document_cookie = params.params.document_cookie; + printed_page_params.page_size = params.params.page_size; + printed_page_params.content_area = params.params.printable_area; + + { + base::SharedMemory shared_buf; + // Allocate a shared memory buffer to hold the generated metafile data. + if (!shared_buf.CreateAndMapAnonymous(buf_size)) { + NOTREACHED() << "Buffer allocation failed"; + return false; + } + + // Copy the bits into shared memory. + if (!metafile.GetData(shared_buf.memory(), buf_size)) { + NOTREACHED() << "GetData() failed"; + shared_buf.Unmap(); + return false; + } + shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), + &printed_page_params.metafile_data_handle); + shared_buf.Unmap(); + + printed_page_params.data_size = buf_size; + Send(new PrintHostMsg_DuplicateSection( + routing_id(), + printed_page_params.metafile_data_handle, + &printed_page_params.metafile_data_handle)); + } + + for (size_t i = 0; i < printed_pages.size(); ++i) { + printed_page_params.page_number = printed_pages[i]; + printed_page_params.page_size = page_size_in_dpi[i]; + printed_page_params.content_area = content_area_in_dpi[i]; + Send(new PrintHostMsg_DidPrintPage(routing_id(), printed_page_params)); + printed_page_params.metafile_data_handle = INVALID_HANDLE_VALUE; + } + return true; +} + +void PrintWebViewHelper::PrintPageInternal( + const PrintMsg_PrintPage_Params& params, + const gfx::Size& canvas_size, + WebFrame* frame, + Metafile* metafile, + gfx::Size* page_size_in_dpi, + gfx::Rect* content_area_in_dpi) { + PageSizeMargins page_layout_in_points; + double css_scale_factor = 1.0f; + ComputePageLayoutInPointsForCss(frame, params.page_number, params.params, + ignore_css_margins_, &css_scale_factor, + &page_layout_in_points); + gfx::Size page_size; + gfx::Rect content_area; + GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size, + &content_area); + int dpi = static_cast(params.params.dpi); + // Calculate the actual page size and content area in dpi. + if (page_size_in_dpi) { + *page_size_in_dpi = + gfx::Size(static_cast(ConvertUnitDouble( + page_size.width(), kPointsPerInch, dpi)), + static_cast(ConvertUnitDouble( + page_size.height(), kPointsPerInch, dpi))); + } + + if (content_area_in_dpi) { + // Output PDF matches paper size and should be printer edge to edge. + *content_area_in_dpi = + gfx::Rect(0, 0, page_size_in_dpi->width(), page_size_in_dpi->height()); + } + + gfx::Rect canvas_area = + params.params.display_header_footer ? gfx::Rect(page_size) : content_area; + + float webkit_page_shrink_factor = + frame->getPrintPageShrink(params.page_number); + float scale_factor = css_scale_factor * webkit_page_shrink_factor; + + SkBaseDevice* device = metafile->StartPageForVectorCanvas(page_size, + canvas_area, + scale_factor); + if (!device) + return; + + // The printPage method take a reference to the canvas we pass down, so it + // can't be a stack object. + skia::RefPtr canvas = + skia::AdoptRef(new skia::VectorCanvas(device)); + MetafileSkiaWrapper::SetMetafileOnCanvas(*canvas, metafile); + skia::SetIsDraftMode(*canvas, is_print_ready_metafile_sent_); + + if (params.params.display_header_footer) { + // |page_number| is 0-based, so 1 is added. + PrintHeaderAndFooter(canvas.get(), + params.page_number + 1, + print_preview_context_.total_page_count(), + scale_factor, + page_layout_in_points, + *header_footer_info_, + params.params); + } + + float webkit_scale_factor = RenderPageContent(frame, + params.page_number, + canvas_area, + content_area, + scale_factor, + canvas.get()); + DCHECK_GT(webkit_scale_factor, 0.0f); + // Done printing. Close the device context to retrieve the compiled metafile. + if (!metafile->FinishPage()) + NOTREACHED() << "metafile failed"; +} + +bool PrintWebViewHelper::CopyMetafileDataToSharedMem( + Metafile* metafile, base::SharedMemoryHandle* shared_mem_handle) { + uint32 buf_size = metafile->GetDataSize(); + base::SharedMemory shared_buf; + // Allocate a shared memory buffer to hold the generated metafile data. + if (!shared_buf.CreateAndMapAnonymous(buf_size)) { + NOTREACHED() << "Buffer allocation failed"; + return false; + } + + // Copy the bits into shared memory. + if (!metafile->GetData(shared_buf.memory(), buf_size)) { + NOTREACHED() << "GetData() failed"; + shared_buf.Unmap(); + return false; + } + shared_buf.GiveToProcess(base::GetCurrentProcessHandle(), shared_mem_handle); + shared_buf.Unmap(); + + Send(new PrintHostMsg_DuplicateSection(routing_id(), *shared_mem_handle, + shared_mem_handle)); + return true; +} + +} // namespace printing diff --git a/src/shell_main_delegate.cc b/src/shell_main_delegate.cc index 32e2690136..e04dddca1b 100644 --- a/src/shell_main_delegate.cc +++ b/src/shell_main_delegate.cc @@ -61,7 +61,7 @@ using base::FilePath; #if defined(OS_WIN) #include "base/logging_win.h" #include -#include "content/nw/src/breakpad_win.h" +#include "components/breakpad/app/breakpad_win.h" #endif #if defined(OS_POSIX) && !defined(OS_MACOSX) From 022ac6022b1849eaf5ae96e99d64b48664a9d6a1 Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 5 Oct 2014 16:17:49 +0800 Subject: [PATCH 195/492] fix for tray --- nw.gypi | 9 ++- src/api/menu/menu_delegate.h | 2 +- src/api/tray/tray.h | 8 +-- src/api/tray/tray_win.cc | 110 ----------------------------- src/browser/menubar_view.cc | 29 +++++++- src/browser/menubar_view.h | 3 + src/shell_browser_main_parts.cc | 17 ++++- tests/manual_tests/menu/index.html | 2 +- 8 files changed, 58 insertions(+), 122 deletions(-) delete mode 100644 src/api/tray/tray_win.cc diff --git a/nw.gypi b/nw.gypi index b03ba280ab..c7a0d9bfe2 100644 --- a/nw.gypi +++ b/nw.gypi @@ -102,8 +102,12 @@ '<(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/views/status_icons/status_icon_linux_wrapper.cc', + '<(DEPTH)/chrome/browser/ui/views/status_icons/status_icon_linux_wrapper.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_linux.cc', + '<(DEPTH)/chrome/browser/ui/views/status_icons/status_tray_linux.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', @@ -171,9 +175,8 @@ 'src/api/shortcut/shortcut_constants.h', 'src/api/tray/tray.cc', 'src/api/tray/tray.h', - 'src/api/tray/tray_gtk.cc', + 'src/api/tray/tray_aura.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', @@ -197,6 +200,8 @@ 'src/browser/chrome_event_processing_window.h', 'src/browser/file_select_helper.cc', 'src/browser/file_select_helper.h', + 'src/browser/menubar_controller.cc', + 'src/browser/menubar_controller.h', 'src/browser/menubar_view.cc', 'src/browser/menubar_view.h', 'src/browser/native_window.cc', diff --git a/src/api/menu/menu_delegate.h b/src/api/menu/menu_delegate.h index 258a571d68..376323fa1c 100644 --- a/src/api/menu/menu_delegate.h +++ b/src/api/menu/menu_delegate.h @@ -24,7 +24,7 @@ #include "ui/base/models/simple_menu_model.h" namespace nwapi { - + class DispatcherHost; class MenuDelegate : public ui::SimpleMenuModel::Delegate { diff --git a/src/api/tray/tray.h b/src/api/tray/tray.h index 338c1a79d0..8f54eccb99 100644 --- a/src/api/tray/tray.h +++ b/src/api/tray/tray.h @@ -34,10 +34,10 @@ class NSStatusItem; class MacTrayObserver; #endif // __OBJC__ -#elif defined(OS_LINUX) +#elif 0 #include #include "chrome/browser/ui/libgtk2ui/gtk2_signal.h" -#elif defined(OS_WIN) +#elif defined(OS_WIN) || defined(OS_LINUX) class StatusIcon; class StatusTray; #endif // defined(OS_MACOSX) @@ -73,7 +73,7 @@ class Tray : public Base { #if defined(OS_MACOSX) __block NSStatusItem* status_item_; MacTrayObserver* status_observer_; -#elif defined(OS_LINUX) +#elif 0 GtkStatusIcon* status_item_; // Reference to the associated menu. @@ -83,7 +83,7 @@ class Tray : public Base { CHROMEGTK_CALLBACK_0(Tray, void, OnClick); // Callback invoked when user right-clicks on the status icon. CHROMEGTK_CALLBACK_2(Tray, void, OnPopupMenu, guint, guint); -#elif defined(OS_WIN) +#elif defined(OS_WIN) || defined(OS_LINUX) // The global presentation of system tray. static StatusTray* status_tray_; diff --git a/src/api/tray/tray_win.cc b/src/api/tray/tray_win.cc deleted file mode 100644 index 4c0c677da1..0000000000 --- a/src/api/tray/tray_win.cc +++ /dev/null @@ -1,110 +0,0 @@ -// 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/tray/tray.h" - -#include "base/files/file_path.h" -#include "base/strings/utf_string_conversions.h" -#include "base/values.h" -#include "chrome/browser/status_icons/status_icon.h" -#include "chrome/browser/status_icons/status_icon_observer.h" -#include "chrome/browser/status_icons/status_tray.h" -#include "content/nw/src/api/dispatcher_host.h" -#include "content/nw/src/api/menu/menu.h" -#include "content/nw/src/nw_package.h" -#include "content/nw/src/nw_shell.h" -#include "ui/gfx/image/image.h" - -namespace nwapi { - -StatusTray* Tray::status_tray_ = NULL; - -class TrayObserver : public StatusIconObserver { - public: - TrayObserver(Tray* tray) - : tray_(tray) { - } - - virtual ~TrayObserver() { - } - - virtual void OnStatusIconClicked() OVERRIDE { - base::ListValue args; - tray_->dispatcher_host()->SendEvent(tray_, "click", args); - } - - private: - Tray* tray_; -}; - -void Tray::Create(const base::DictionaryValue& option) { - if (!status_tray_) - status_tray_ = StatusTray::GetSingleton(); - - status_icon_ = status_tray_->CreateStatusIcon(StatusTray::NOTIFICATION_TRAY_ICON, - gfx::ImageSkia(), base::string16()); - status_observer_ = new TrayObserver(this); - status_icon_->AddObserver(status_observer_); -} - -void Tray::ShowAfterCreate() { -} - -void Tray::Destroy() { - if (status_icon_) - Remove(); -} - -void Tray::SetTitle(const std::string& title) { -} - -void Tray::SetIcon(const std::string& path) { - gfx::Image icon; - content::Shell* shell = content::Shell::FromRenderViewHost( - dispatcher_host()->render_view_host()); - nw::Package* package = shell->GetPackage(); - package->GetImage(base::FilePath::FromUTF8Unsafe(path), &icon); - - if (!icon.IsEmpty()) - status_icon_->SetImage(*icon.ToImageSkia()); -} - -void Tray::SetTooltip(const std::string& tooltip) { - status_icon_->SetToolTip(base::UTF8ToUTF16(tooltip)); -} - -void Tray::SetMenu(Menu* menu) { - status_icon_->UpdatePlatformContextMenu(menu->menu_model_.get()); -} - -void Tray::Remove() { - if (status_icon_) { - status_icon_->RemoveObserver(status_observer_); - delete status_observer_; - - status_tray_->RemoveStatusIcon(status_icon_); - status_icon_ = NULL; - } -} - -void Tray::SetAltIcon(const std::string& alticon_path) { -} - -} // namespace nwapi diff --git a/src/browser/menubar_view.cc b/src/browser/menubar_view.cc index b4c103aa81..03e253a4b8 100644 --- a/src/browser/menubar_view.cc +++ b/src/browser/menubar_view.cc @@ -3,6 +3,9 @@ // found in the LICENSE file. #include "content/nw/src/browser/menubar_view.h" + + +#include "content/nw/src/browser/menubar_controller.h" #include "ui/base/models/menu_model.h" #include "ui/base/window_open_disposition.h" #include "ui/gfx/text_elider.h" @@ -86,17 +89,37 @@ void MenuBarView::InitView(ui::MenuModel* model) { } } +bool MenuBarView::GetMenuButtonAtLocation(const gfx::Point& loc, ui::MenuModel** model, views::MenuButton** button) { + if (!model_) + return false; + if (loc.x() < 0 || loc.x() >= width() || loc.y() < 0 || loc.y() >= height()) + return false; + for (int i = 0; i < model_->GetItemCount(); i++) { + views::View* child = child_at(i); + if (child->bounds().Contains(loc) && + (model_->GetTypeAt(i) == ui::MenuModel::TYPE_SUBMENU)) { + *model = model_->GetSubmenuModelAt(i); + *button = static_cast(child); + return true; + } + } + return false; +} + void MenuBarView::OnMenuButtonClicked(views::View* view, const gfx::Point& point) { int button_index = GetIndexOf(view); DCHECK_NE(-1, button_index); ui::MenuModel::ItemType type = model_->GetTypeAt(button_index); if (type == ui::MenuModel::TYPE_SUBMENU) { - menu_runner_.reset(new MenuRunner(model_->GetSubmenuModelAt(button_index), - MenuRunner::HAS_MNEMONICS)); + views::MenuItemView* menu = MenuBarController::CreateMenu(this, model_->GetSubmenuModelAt(button_index)); + menu_runner_.reset(new MenuRunner(menu, MenuRunner::HAS_MNEMONICS)); + + // menu_runner_.reset(new MenuRunner(model_->GetSubmenuModelAt(button_index), + // MenuRunner::HAS_MNEMONICS)); if (menu_runner_->RunMenuAt(GetWidget()->GetTopLevelWidget(), - NULL, + static_cast(view), gfx::Rect(point, gfx::Size()), views::MENU_ANCHOR_TOPRIGHT, ui::MENU_SOURCE_NONE) == diff --git a/src/browser/menubar_view.h b/src/browser/menubar_view.h index f3fa24b837..74e9330145 100644 --- a/src/browser/menubar_view.h +++ b/src/browser/menubar_view.h @@ -12,6 +12,7 @@ namespace views { class MenuRunner; + class MenuButton; } namespace ui { @@ -45,6 +46,8 @@ class MenuBarView : void UpdateMenu(ui::MenuModel* model); void InitView(ui::MenuModel* model); + bool GetMenuButtonAtLocation(const gfx::Point& loc, ui::MenuModel** model, views::MenuButton** button); + // views::MenuButtonListener: virtual void OnMenuButtonClicked(views::View* view, const gfx::Point& point) OVERRIDE; diff --git a/src/shell_browser_main_parts.cc b/src/shell_browser_main_parts.cc index f7b2b3ac7b..e9f5f58eb7 100644 --- a/src/shell_browser_main_parts.cc +++ b/src/shell_browser_main_parts.cc @@ -60,6 +60,14 @@ #include "ui/views/widget/desktop_aura/desktop_screen.h" #endif // defined(USE_AURA) +#if defined(OS_LINUX) +#include "chrome/browser/ui/libgtk2ui/gtk2_ui.h" +#include "ui/aura/window.h" +#include "ui/base/ime/input_method_initializer.h" +#include "ui/native_theme/native_theme_aura.h" +#include "ui/views/linux_ui/linux_ui.h" +#endif + using base::MessageLoop; namespace { @@ -180,6 +188,10 @@ void ShellBrowserMainParts::ToolkitInitialized() { DCHECK(!views::ViewsDelegate::views_delegate); new views::DesktopTestViewsDelegate; #endif + +#if defined(OS_LINUX) + views::LinuxUI::instance()->Initialize(); +#endif } void ShellBrowserMainParts::Init() { @@ -298,7 +310,10 @@ void ShellBrowserMainParts::PreEarlyInitialization() { #endif // !OS_WIN #if defined(OS_LINUX) - ui::InitializeInputMethodForTesting(); + views::LinuxUI* gtk2_ui = BuildGtk2UI(); + // gtk2_ui->SetNativeThemeOverride(base::Bind(&GetNativeThemeForWindow)); + views::LinuxUI::SetInstance(gtk2_ui); + // ui::InitializeInputMethodForTesting(); #endif } diff --git a/tests/manual_tests/menu/index.html b/tests/manual_tests/menu/index.html index e1e772fa4b..d67823ac98 100644 --- a/tests/manual_tests/menu/index.html +++ b/tests/manual_tests/menu/index.html @@ -193,7 +193,7 @@ } })); menubar.append(new gui.MenuItem({ label: 'Sub1', submenu: sub1})); - menubar.append(new gui.MenuItem({ label: 'Sub2', submenu: sub2})); + //menubar.append(new gui.MenuItem({ label: 'Sub2', submenu: sub2})); win.menu = menubar; From 526f2f8a7e3f5926e9d5dc6d601de684a80a23c4 Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 5 Oct 2014 16:28:45 +0800 Subject: [PATCH 196/492] add lost files for tray --- src/api/tray/tray_aura.cc | 110 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 src/api/tray/tray_aura.cc diff --git a/src/api/tray/tray_aura.cc b/src/api/tray/tray_aura.cc new file mode 100644 index 0000000000..4c0c677da1 --- /dev/null +++ b/src/api/tray/tray_aura.cc @@ -0,0 +1,110 @@ +// 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/tray/tray.h" + +#include "base/files/file_path.h" +#include "base/strings/utf_string_conversions.h" +#include "base/values.h" +#include "chrome/browser/status_icons/status_icon.h" +#include "chrome/browser/status_icons/status_icon_observer.h" +#include "chrome/browser/status_icons/status_tray.h" +#include "content/nw/src/api/dispatcher_host.h" +#include "content/nw/src/api/menu/menu.h" +#include "content/nw/src/nw_package.h" +#include "content/nw/src/nw_shell.h" +#include "ui/gfx/image/image.h" + +namespace nwapi { + +StatusTray* Tray::status_tray_ = NULL; + +class TrayObserver : public StatusIconObserver { + public: + TrayObserver(Tray* tray) + : tray_(tray) { + } + + virtual ~TrayObserver() { + } + + virtual void OnStatusIconClicked() OVERRIDE { + base::ListValue args; + tray_->dispatcher_host()->SendEvent(tray_, "click", args); + } + + private: + Tray* tray_; +}; + +void Tray::Create(const base::DictionaryValue& option) { + if (!status_tray_) + status_tray_ = StatusTray::GetSingleton(); + + status_icon_ = status_tray_->CreateStatusIcon(StatusTray::NOTIFICATION_TRAY_ICON, + gfx::ImageSkia(), base::string16()); + status_observer_ = new TrayObserver(this); + status_icon_->AddObserver(status_observer_); +} + +void Tray::ShowAfterCreate() { +} + +void Tray::Destroy() { + if (status_icon_) + Remove(); +} + +void Tray::SetTitle(const std::string& title) { +} + +void Tray::SetIcon(const std::string& path) { + gfx::Image icon; + content::Shell* shell = content::Shell::FromRenderViewHost( + dispatcher_host()->render_view_host()); + nw::Package* package = shell->GetPackage(); + package->GetImage(base::FilePath::FromUTF8Unsafe(path), &icon); + + if (!icon.IsEmpty()) + status_icon_->SetImage(*icon.ToImageSkia()); +} + +void Tray::SetTooltip(const std::string& tooltip) { + status_icon_->SetToolTip(base::UTF8ToUTF16(tooltip)); +} + +void Tray::SetMenu(Menu* menu) { + status_icon_->UpdatePlatformContextMenu(menu->menu_model_.get()); +} + +void Tray::Remove() { + if (status_icon_) { + status_icon_->RemoveObserver(status_observer_); + delete status_observer_; + + status_tray_->RemoveStatusIcon(status_icon_); + status_icon_ = NULL; + } +} + +void Tray::SetAltIcon(const std::string& alticon_path) { +} + +} // namespace nwapi From 41a41b42f0d9ca84d7cd8f6341c896972ab5d1c7 Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 5 Oct 2014 16:41:54 +0800 Subject: [PATCH 197/492] merge Linux and Windows fixes --- nw.gypi | 1 + src/browser/native_window.h | 4 ++-- src/browser/native_window_aura.h | 1 - src/renderer/printing/print_web_view_helper_linux.cc | 1 - 4 files changed, 3 insertions(+), 4 deletions(-) diff --git a/nw.gypi b/nw.gypi index 9b9c2908c7..c825c2669d 100644 --- a/nw.gypi +++ b/nw.gypi @@ -242,6 +242,7 @@ 'src/browser/shell_devtools_delegate.h', 'src/browser/shell_download_manager_delegate.cc', 'src/browser/shell_download_manager_delegate.h', + 'src/browser/shell_download_manager_delegate_gtk.cc', 'src/browser/shell_download_manager_delegate_win.cc', 'src/browser/shell_download_manager_delegate_mac.mm', 'src/browser/shell_javascript_dialog_creator.cc', diff --git a/src/browser/native_window.h b/src/browser/native_window.h index 1a73dd2d23..b01a830a23 100644 --- a/src/browser/native_window.h +++ b/src/browser/native_window.h @@ -34,7 +34,7 @@ #include "ui/gfx/point.h" #include "ui/gfx/size.h" -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) #include "components/web_modal/web_contents_modal_dialog_host.h" #endif @@ -64,7 +64,7 @@ namespace nw { class CapturePageHelper; -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) class NativeWindow : public web_modal::WebContentsModalDialogHost { #else class NativeWindow { diff --git a/src/browser/native_window_aura.h b/src/browser/native_window_aura.h index f24ee6adb6..b3d7585ca2 100644 --- a/src/browser/native_window_aura.h +++ b/src/browser/native_window_aura.h @@ -23,7 +23,6 @@ #include "content/nw/src/browser/native_window.h" -#include "components/web_modal/web_contents_modal_dialog_host.h" #include "third_party/skia/include/core/SkRegion.h" #if defined(OS_WIN) #include "ui/base/win/hidden_window.h" diff --git a/src/renderer/printing/print_web_view_helper_linux.cc b/src/renderer/printing/print_web_view_helper_linux.cc index d56faee6b3..dc9def314a 100644 --- a/src/renderer/printing/print_web_view_helper_linux.cc +++ b/src/renderer/printing/print_web_view_helper_linux.cc @@ -55,7 +55,6 @@ bool PrintWebViewHelper::RenderPreviewPage( } bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, - const blink::WebNode& node, int page_count, const gfx::Size& canvas_size) { NativeMetafile metafile; From 7e29171eceea7db0c4ba1930932b69f7807f0e15 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 6 Oct 2014 09:20:59 +0800 Subject: [PATCH 198/492] add missing files for menubar_controller --- src/browser/menubar_controller.cc | 48 +++++++++++++++++++++++++++++++ src/browser/menubar_controller.h | 39 +++++++++++++++++++++++++ 2 files changed, 87 insertions(+) create mode 100644 src/browser/menubar_controller.cc create mode 100644 src/browser/menubar_controller.h diff --git a/src/browser/menubar_controller.cc b/src/browser/menubar_controller.cc new file mode 100644 index 0000000000..f70c78149d --- /dev/null +++ b/src/browser/menubar_controller.cc @@ -0,0 +1,48 @@ +#include "content/nw/src/browser/menubar_controller.h" + +#include "content/nw/src/browser/menubar_view.h" +#include "ui/views/controls/menu/menu_item_view.h" + +namespace nw { + +MenuBarController::ModelToMenuMap MenuBarController::model_to_menu_map_; + +MenuBarController::MenuBarController(MenuBarView* menubar, ui::MenuModel* menu_model) + :MenuModelAdapter(menu_model), menubar_(menubar) { +} + +MenuBarController::~MenuBarController() { +} + +views::MenuItemView* MenuBarController::GetSiblingMenu( + views::MenuItemView* menu, + const gfx::Point& screen_point, + views::MenuAnchorPosition* anchor, + bool* has_mnemonics, + views::MenuButton** button) { + if (!menubar_) + return NULL; + gfx::Point menubar_loc(screen_point); + views::View::ConvertPointFromScreen(menubar_, &menubar_loc); + ui::MenuModel* model; + if (!menubar_->GetMenuButtonAtLocation(menubar_loc, &model, button)) + return NULL; + + *has_mnemonics = false; + *anchor = views::MENU_ANCHOR_TOPLEFT; + if (!model_to_menu_map_[model]) + CreateMenu(menubar_, model); + + return model_to_menu_map_[model]; +} + +views::MenuItemView* MenuBarController::CreateMenu(MenuBarView* menubar, ui::MenuModel* model) { + MenuBarController* controller = new MenuBarController(menubar, model); + views::MenuItemView* menu = new views::MenuItemView(controller); + controller->BuildMenu(menu); + model_to_menu_map_[model] = menu; + + return menu; +} + +} //namespace nw diff --git a/src/browser/menubar_controller.h b/src/browser/menubar_controller.h new file mode 100644 index 0000000000..09f2e4284e --- /dev/null +++ b/src/browser/menubar_controller.h @@ -0,0 +1,39 @@ +#ifndef NW_BROWSER_MENUBAR_CONTROLLER_H +#define NW_BROWSER_MENUBAR_CONTROLLER_H + +#include "ui/views/controls/menu/menu_model_adapter.h" + +#include + +namespace ui { +class MenuModel; +} + +namespace nw { +class MenuBarView; + +class MenuBarController : public views::MenuModelAdapter { + public: + MenuBarController(MenuBarView* menubar, ui::MenuModel* menu_model); + virtual ~MenuBarController(); + + static views::MenuItemView* CreateMenu(MenuBarView* menubar, ui::MenuModel* model); + + virtual views::MenuItemView* GetSiblingMenu( + views::MenuItemView* menu, + const gfx::Point& screen_point, + views::MenuAnchorPosition* anchor, + bool* has_mnemonics, + views::MenuButton** button) OVERRIDE; + + private: + typedef std::map ModelToMenuMap; + + MenuBarView* menubar_; + static ModelToMenuMap model_to_menu_map_; + + DISALLOW_COPY_AND_ASSIGN(MenuBarController); +}; + +} //namespace nw +#endif From 0b88c8e024234fabd1a73522dce0430f605fef0b Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 6 Oct 2014 11:15:20 +0800 Subject: [PATCH 199/492] fix nw.gypi for linux compiling --- nw.gypi | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/nw.gypi b/nw.gypi index c825c2669d..48ab14a177 100644 --- a/nw.gypi +++ b/nw.gypi @@ -242,7 +242,6 @@ 'src/browser/shell_devtools_delegate.h', 'src/browser/shell_download_manager_delegate.cc', 'src/browser/shell_download_manager_delegate.h', - 'src/browser/shell_download_manager_delegate_gtk.cc', 'src/browser/shell_download_manager_delegate_win.cc', 'src/browser/shell_download_manager_delegate_mac.mm', 'src/browser/shell_javascript_dialog_creator.cc', @@ -423,6 +422,9 @@ '<(DEPTH)/build/linux/system.gyp:gio', '<(DEPTH)/build/linux/system.gyp:gtk', ], + 'sources': [ + 'src/browser/shell_download_manager_delegate_gtk.cc', + ], }], ['OS == "mac"', { 'sources!': [ From 86573f91ef05efd0881d28f14f459d4fb7c185d9 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Mon, 6 Oct 2014 18:11:44 +0800 Subject: [PATCH 200/492] menu fix for windows --- src/api/menu/menu_views.cc | 11 ++++++++--- src/browser/native_window_aura.cc | 4 ++-- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/api/menu/menu_views.cc b/src/api/menu/menu_views.cc index 192a87f04f..11d8d9ae97 100644 --- a/src/api/menu/menu_views.cc +++ b/src/api/menu/menu_views.cc @@ -96,14 +96,19 @@ void Menu::Create(const base::DictionaryValue& option) { is_menu_modified_ = true; menu_delegate_.reset(new MenuDelegate(dispatcher_host())); menu_model_.reset(new ui::NwMenuModel(menu_delegate_.get())); - //menu_.reset(new views::NativeMenuWin(menu_model_.get(), NULL)); +#if defined(OS_WIN) + menu_.reset(new views::NativeMenuWin(menu_model_.get(), NULL)); +#endif focus_manager_ = NULL; window_ = NULL; std::string type; - //if (option.GetString("type", &type) && type == "menubar") - // menu_->set_is_popup_menu(false); + +#if defined(OS_WIN) + if (option.GetString("type", &type) && type == "menubar") + menu_->set_is_popup_menu(false); +#endif menu_items_.empty(); } diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index 00d2dcd4cc..b1254f317b 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -607,14 +607,14 @@ bool NativeWindowAura::IsKiosk() { void NativeWindowAura::SetMenu(nwapi::Menu* menu) { window_->set_has_menu_bar(true); menu_ = menu; - +#if defined(OS_LINUX) MenuBarView* menubar = new MenuBarView(); GetBrowserViewLayout()->set_menu_bar(menubar); AddChildView(menubar); menubar->UpdateMenu(menu->model()); Layout(); SchedulePaint(); - +#endif // The menu is lazily built. #if defined(OS_WIN) //FIXME menu->Rebuild(); From f8e7867ee99f89bceeee8a8a1412b44d573dfe52 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Mon, 6 Oct 2014 22:29:40 +0800 Subject: [PATCH 201/492] [test] fix menu shortcut case --- tests/manual_tests/menu_shortcut/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/manual_tests/menu_shortcut/index.html b/tests/manual_tests/menu_shortcut/index.html index ecd349e91e..fdb1f05426 100644 --- a/tests/manual_tests/menu_shortcut/index.html +++ b/tests/manual_tests/menu_shortcut/index.html @@ -18,7 +18,6 @@

    var menubar = new gui.Menu({ type: 'menubar' }); var menubar_file = new gui.MenuItem({"label":"File"}); - menubar.append(menubar_file); var file_menu = new gui.Menu(); var file_quit_item = new gui.MenuItem({ "label":"Quit", @@ -50,9 +49,10 @@

    file_menu.insert(file_about_item,0); menubar_file.submenu = file_menu; + menubar.append(menubar_file); win.menu = menubar; - \ No newline at end of file + From 81cfec63bd94abc2dce33af454317e8cd580a3ea Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 6 Oct 2014 22:34:55 +0800 Subject: [PATCH 202/492] menu shortcut fix for linux --- src/api/menuitem/menuitem.h | 30 +++++------------------------- src/api/menuitem/menuitem_views.cc | 27 +++++++++++++++++++++++++-- src/browser/native_window_aura.cc | 2 +- 3 files changed, 31 insertions(+), 28 deletions(-) diff --git a/src/api/menuitem/menuitem.h b/src/api/menuitem/menuitem.h index d6aed148ec..b1a5bc7e8e 100644 --- a/src/api/menuitem/menuitem.h +++ b/src/api/menuitem/menuitem.h @@ -45,8 +45,8 @@ namespace nwapi { class Menu; -#if defined(OS_WIN) -class MenuItem : public Base , +#if defined(OS_WIN) || defined(OS_LINUX) +class MenuItem : public Base , public ui::AcceleratorTarget { #else class MenuItem : public Base { @@ -60,29 +60,9 @@ class MenuItem : public Base { virtual void Call(const std::string& method, const base::ListValue& arguments) OVERRIDE; -#if defined(OS_LINUX) - void UpdateKeys(views::FocusManager *focus_manager); -#endif - -#if defined(OS_WIN) - virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE{ - if (super_down_flag_){ - if ( ( (::GetKeyState(VK_LWIN) & 0x8000) != 0x8000) - || ( (::GetKeyState(VK_LWIN) & 0x8000) != 0x8000) ){ - return true; - } - } - if (meta_down_flag_){ - if ( (::GetKeyState(VK_APPS) & 0x8000) != 0x8000 ){ - return true; - } - } - OnClick(); - return true; - } - virtual bool CanHandleAccelerators() const OVERRIDE { - return true; - } +#if defined(OS_WIN) || defined(OS_LINUX) + virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; + virtual bool CanHandleAccelerators() const OVERRIDE; void UpdateKeys(views::FocusManager *focus_manager); #endif diff --git a/src/api/menuitem/menuitem_views.cc b/src/api/menuitem/menuitem_views.cc index 0d31af2fc8..20dcc4b6ee 100644 --- a/src/api/menuitem/menuitem_views.cc +++ b/src/api/menuitem/menuitem_views.cc @@ -162,12 +162,10 @@ void MenuItem::UpdateKeys(views::FocusManager *focus_manager){ } else { focus_manager_ = focus_manager; if (enable_shortcut_){ -#if 0 //FIXME focus_manager->RegisterAccelerator( accelerator_, ui::AcceleratorManager::kHighPriority, this); -#endif } if (submenu_ != NULL){ submenu_->UpdateKeys(focus_manager); @@ -175,6 +173,31 @@ void MenuItem::UpdateKeys(views::FocusManager *focus_manager){ } } +#if defined(OS_WIN) || defined(OS_LINUX) +bool MenuItem::AcceleratorPressed(const ui::Accelerator& accelerator) { + +#if defined(OS_WIN) + if (super_down_flag_){ + if ( ( (::GetKeyState(VK_LWIN) & 0x8000) != 0x8000) + || ( (::GetKeyState(VK_LWIN) & 0x8000) != 0x8000) ){ + return true; + } + } + if (meta_down_flag_){ + if ( (::GetKeyState(VK_APPS) & 0x8000) != 0x8000 ){ + return true; + } + } +#endif + OnClick(); + return true; +} + +bool MenuItem::CanHandleAccelerators() const { + return true; +} + +#endif } // namespace nwapi diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index b1254f317b..0a79eb58ec 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -623,8 +623,8 @@ void NativeWindowAura::SetMenu(nwapi::Menu* menu) { // menu is nwapi::Menu, menu->menu_ is NativeMenuWin, ::SetMenu(views::HWNDForWidget(window_), menu->menu_->GetNativeMenu()); - menu->UpdateKeys( window_->GetFocusManager() ); #endif + menu->UpdateKeys( window_->GetFocusManager() ); } BrowserViewLayout* NativeWindowAura::GetBrowserViewLayout() const { From c1a25cafa5844be786c6650b0b90ffe12c858f0b Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Wed, 8 Oct 2014 06:40:31 +0800 Subject: [PATCH 203/492] [nw11] rebase fix for mac --- nw.gypi | 5 ++--- src/api/dispatcher_bindings_mac.mm | 1 + src/api/menu/menu_mac.mm | 3 +-- src/browser/native_window_mac.mm | 15 +++++++-------- .../shell_download_manager_delegate_mac.mm | 1 - src/nw_notification_manager_mac.mm | 11 ++++------- src/renderer/printing/print_web_view_helper.cc | 1 - .../printing/print_web_view_helper_mac.mm | 2 +- src/shell_main_delegate.cc | 1 + 9 files changed, 17 insertions(+), 23 deletions(-) diff --git a/nw.gypi b/nw.gypi index 48ab14a177..cd7b8a773a 100644 --- a/nw.gypi +++ b/nw.gypi @@ -91,7 +91,6 @@ '<(DEPTH)/chrome/browser/platform_util_win.cc', '<(DEPTH)/chrome/browser/platform_util.h', '<(DEPTH)/chrome/browser/process_singleton_posix.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', @@ -269,8 +268,6 @@ 'src/common/shell_switches.cc', 'src/common/shell_switches.h', 'src/breakpad_linux_impl.h', - 'src/breakpad_mac.mm', - 'src/breakpad_mac.h', 'src/hard_error_handler_win.cc', 'src/hard_error_handler_win.h', 'src/geolocation/shell_access_token_store.cc', @@ -429,6 +426,8 @@ ['OS == "mac"', { 'sources!': [ '<(DEPTH)/chrome/common/child_process_logging_posix.cc', + 'src/api/menu/menu_delegate.cc', + 'src/api/menu/menu_delegate.h', ], 'sources': [ '<(DEPTH)/chrome/browser/ui/cocoa/nsview_additions.h', diff --git a/src/api/dispatcher_bindings_mac.mm b/src/api/dispatcher_bindings_mac.mm index 0cedab54e4..e77be987fe 100644 --- a/src/api/dispatcher_bindings_mac.mm +++ b/src/api/dispatcher_bindings_mac.mm @@ -2,6 +2,7 @@ #include +#include "base/containers/hash_tables.h" #include "grit/nw_strings.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/l10n/l10n_util_mac.h" diff --git a/src/api/menu/menu_mac.mm b/src/api/menu/menu_mac.mm index 1274bad0c0..2ff0a652fd 100644 --- a/src/api/menu/menu_mac.mm +++ b/src/api/menu/menu_mac.mm @@ -25,7 +25,6 @@ #include "base/values.h" #import #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" #include "content/nw/src/api/menuitem/menuitem.h" #include "content/nw/src/browser/native_window_mac.h" #include "content/nw/src/nw_shell.h" @@ -58,7 +57,7 @@ NSWindow* window = static_cast(shell->window())->window(); NSEvent* currentEvent = [NSApp currentEvent]; - NSView* web_view = shell->web_contents()->GetView()->GetNativeView(); + NSView* web_view = shell->web_contents()->GetNativeView(); NSPoint position = { x, web_view.bounds.size.height - y }; NSTimeInterval eventTime = [currentEvent timestamp]; NSEvent* clickEvent = [NSEvent mouseEventWithType:NSRightMouseDown diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index 1ebb6cd467..7a8aa06ac4 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -37,7 +37,6 @@ #include "content/public/browser/native_web_keyboard_event.h" #include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/web_contents.h" -#include "content/public/browser/web_contents_view.h" #include "extensions/common/draggable_region.h" #include "third_party/skia/include/core/SkRegion.h" #import "ui/base/cocoa/underlay_opengl_hosting_window.h" @@ -120,7 +119,7 @@ - (void)windowWillExitFullScreen:(NSNotification*)notification { - (void)windowDidBecomeKey:(NSNotification *)notification { if (shell_) { - shell_->web_contents()->GetView()->Focus(); + shell_->web_contents()->Focus(); shell_->SendEvent("focus"); } } @@ -408,7 +407,7 @@ - (void)drawRect:(NSRect)dirtyRect { [window() respondsToSelector:@selector(setBottomCornerRounded:)]) [window() setBottomCornerRounded:NO]; - NSView* view = web_contents()->GetView()->GetNativeView(); + NSView* view = web_contents()->GetNativeView(); [view setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; // By default, the whole frameless window is not draggable. @@ -425,7 +424,7 @@ - (void)drawRect:(NSRect)dirtyRect { } void NativeWindowCocoa::InstallView() { - NSView* view = web_contents()->GetView()->GetNativeView(); + NSView* view = web_contents()->GetNativeView(); if (has_frame_) { [view setFrame:[[window() contentView] bounds]]; [[window() contentView] addSubview:view]; @@ -450,7 +449,7 @@ - (void)drawRect:(NSRect)dirtyRect { } void NativeWindowCocoa::UninstallView() { - NSView* view = web_contents()->GetView()->GetNativeView(); + NSView* view = web_contents()->GetNativeView(); [view removeFromSuperview]; } @@ -901,7 +900,7 @@ - (void)drawRect:(NSRect)dirtyRect { void NativeWindowCocoa::UpdateDraggableRegionsForSystemDrag( const std::vector& regions, const extensions::DraggableRegion* draggable_area) { - NSView* web_view = web_contents()->GetView()->GetNativeView(); + NSView* web_view = web_contents()->GetNativeView(); NSInteger web_view_width = NSWidth([web_view bounds]); NSInteger web_view_height = NSHeight([web_view bounds]); @@ -971,7 +970,7 @@ - (void)drawRect:(NSRect)dirtyRect { const std::vector& regions) { // We still need one ControlRegionView to cover the whole window such that // mouse events could be captured. - NSView* web_view = web_contents()->GetView()->GetNativeView(); + NSView* web_view = web_contents()->GetNativeView(); gfx::Rect window_bounds( 0, 0, NSWidth([web_view bounds]), NSHeight([web_view bounds])); system_drag_exclude_areas_.clear(); @@ -1001,7 +1000,7 @@ - (void)drawRect:(NSRect)dirtyRect { // All ControlRegionViews should be added as children of the WebContentsView, // because WebContentsView will be removed and re-added when entering and // leaving fullscreen mode. - NSView* webView = web_contents()->GetView()->GetNativeView(); + NSView* webView = web_contents()->GetNativeView(); NSInteger webViewHeight = NSHeight([webView bounds]); // Remove all ControlRegionViews that are added last time. diff --git a/src/browser/shell_download_manager_delegate_mac.mm b/src/browser/shell_download_manager_delegate_mac.mm index 195b568fbe..232633ed56 100644 --- a/src/browser/shell_download_manager_delegate_mac.mm +++ b/src/browser/shell_download_manager_delegate_mac.mm @@ -33,7 +33,6 @@ #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" using base::FilePath; diff --git a/src/nw_notification_manager_mac.mm b/src/nw_notification_manager_mac.mm index e56682bd98..2a23464886 100644 --- a/src/nw_notification_manager_mac.mm +++ b/src/nw_notification_manager_mac.mm @@ -59,22 +59,20 @@ -(BOOL)userNotificationCenter:(NSUserNotificationCenter *)center NSNumber *render_process_id = [notification.userInfo objectForKey : @"render_process_id"]; NSNumber *render_view_id = [notification.userInfo objectForKey : @"render_view_id"]; - NSNumber *notification_id = [notification.userInfo objectForKey : @"notification_id"]; nw::NotificationManager::getSingleton()->DesktopNotificationPostDisplay(render_process_id.intValue, render_view_id.intValue, - notification_id.intValue); + 0); return YES; } -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification : (NSUserNotification *)notification { NSNumber *render_process_id = [notification.userInfo objectForKey : @"render_process_id"]; NSNumber *render_view_id = [notification.userInfo objectForKey : @"render_view_id"]; - NSNumber *notification_id = [notification.userInfo objectForKey : @"notification_id"]; nw::NotificationManager::getSingleton()->DesktopNotificationPostClick(render_process_id.intValue, render_view_id.intValue, - notification_id.intValue); + 0); } @end @@ -129,7 +127,6 @@ -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNoti notification.userInfo = @{ @"render_process_id" :[NSNumber numberWithInt : render_process_id], @"render_view_id" :[NSNumber numberWithInt : render_view_id], - @"notification_id" :[NSNumber numberWithInt : params.notification_id], }; @@ -145,10 +142,10 @@ -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNoti bool NotificationManagerMac::CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id){ for (NSUserNotification *notification in[[NSUserNotificationCenter defaultUserNotificationCenter] deliveredNotifications]) { NSNumber *current_notification_id = [notification.userInfo objectForKey : @"notification_id"]; - if (current_notification_id.intValue == notification_id){ + //FIXME: if (current_notification_id.intValue == notification_id){ [[NSUserNotificationCenter defaultUserNotificationCenter] removeDeliveredNotification:notification]; return true; - } + //} } return false; } diff --git a/src/renderer/printing/print_web_view_helper.cc b/src/renderer/printing/print_web_view_helper.cc index 0a3e84fa3f..8ebfa58af0 100644 --- a/src/renderer/printing/print_web_view_helper.cc +++ b/src/renderer/printing/print_web_view_helper.cc @@ -1240,7 +1240,6 @@ void PrintWebViewHelper::FinishFramePrinting() { #if defined(OS_MACOSX) || \ (defined(OS_WIN) && !defined(WIN_PDF_METAFILE_FOR_PRINTING)) bool PrintWebViewHelper::PrintPagesNative(blink::WebFrame* frame, - const blink::WebNode& node, int page_count, const gfx::Size& canvas_size) { const PrintMsg_PrintPages_Params& params = *print_pages_params_; diff --git a/src/renderer/printing/print_web_view_helper_mac.mm b/src/renderer/printing/print_web_view_helper_mac.mm index 4904ed787c..05c5e43f93 100644 --- a/src/renderer/printing/print_web_view_helper_mac.mm +++ b/src/renderer/printing/print_web_view_helper_mac.mm @@ -77,7 +77,7 @@ base::TimeTicks begin_time = base::TimeTicks::Now(); gfx::Size page_size; - RenderPage(printParams, page_number, print_preview_context_.prepared_frame(), + RenderPage(printParams, page_number, (blink::WebFrame*)print_preview_context_.prepared_frame(), true, initial_render_metafile, &page_size, NULL); print_preview_context_.RenderedPreviewPage( base::TimeTicks::Now() - begin_time); diff --git a/src/shell_main_delegate.cc b/src/shell_main_delegate.cc index e04dddca1b..7f149aec77 100644 --- a/src/shell_main_delegate.cc +++ b/src/shell_main_delegate.cc @@ -55,6 +55,7 @@ using base::FilePath; #if defined(OS_MACOSX) +#include "components/breakpad/app/breakpad_mac.h" #include "content/nw/src/paths_mac.h" #endif // OS_MACOSX From c388fa5ca196be1207d22a7581def667ad7c1247 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 8 Oct 2014 16:13:16 +0800 Subject: [PATCH 204/492] [linux] autofill and notification fix --- nw.gypi | 18 +++-- ...ager_delegate.cc => nw_autofill_client.cc} | 79 +++++++++---------- ...anager_delegate.h => nw_autofill_client.h} | 68 +++++++++------- src/nw_notification_manager.cc | 8 +- src/nw_notification_manager.h | 12 ++- src/nw_notification_manager_linux.cc | 31 +++++--- src/nw_notification_manager_linux.h | 11 ++- src/nw_shell.cc | 8 +- src/shell_content_browser_client.cc | 34 +++----- src/shell_content_browser_client.h | 15 +--- 10 files changed, 151 insertions(+), 133 deletions(-) rename src/browser/{tab_autofill_manager_delegate.cc => nw_autofill_client.cc} (56%) rename src/browser/{tab_autofill_manager_delegate.h => nw_autofill_client.h} (56%) diff --git a/nw.gypi b/nw.gypi index cd7b8a773a..e3bcdf955d 100644 --- a/nw.gypi +++ b/nw.gypi @@ -190,8 +190,8 @@ 'src/browser/autofill_popup_controller_impl.h', 'src/browser/browser_view_layout.cc', 'src/browser/browser_view_layout.h', -# 'src/browser/tab_autofill_manager_delegate.cc', -# 'src/browser/tab_autofill_manager_delegate.h', + 'src/browser/nw_autofill_client.cc', + 'src/browser/nw_autofill_client.h', 'src/browser/capture_page_helper.h', 'src/browser/capture_page_helper.cc', # 'src/browser/color_chooser_gtk.cc', @@ -317,8 +317,8 @@ 'src/nw_notification_manager_win.cc', 'src/nw_notification_manager_mac.h', 'src/nw_notification_manager_mac.mm', - # 'src/nw_notification_manager_linux.h', - # 'src/nw_notification_manager_linux.cc', + 'src/nw_notification_manager_linux.h', + 'src/nw_notification_manager_linux.cc', 'src/shell_browser_context.cc', 'src/shell_browser_context.h', 'src/shell_browser_main.cc', @@ -390,14 +390,18 @@ 'src/renderer/printing/print_web_view_helper_win.cc', ], }], - ['OS=="win"', { + ['OS=="win" or OS=="linux"', { 'sources': [ - '<(DEPTH)/chrome/browser/ui/views/constrained_window_views.cc', - '<(DEPTH)/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc', 'src/browser/autofill_popup_base_view.cc', 'src/browser/autofill_popup_base_view.h', 'src/browser/autofill_popup_view_views.cc', 'src/browser/autofill_popup_view_views.h', + ], + }], + ['OS=="win"', { + 'sources': [ + '<(DEPTH)/chrome/browser/ui/views/constrained_window_views.cc', + '<(DEPTH)/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc', 'src/browser/login_view.cc', 'src/browser/login_view.h', ], diff --git a/src/browser/tab_autofill_manager_delegate.cc b/src/browser/nw_autofill_client.cc similarity index 56% rename from src/browser/tab_autofill_manager_delegate.cc rename to src/browser/nw_autofill_client.cc index 143e79f729..de2716ca7a 100644 --- a/src/browser/tab_autofill_manager_delegate.cc +++ b/src/browser/nw_autofill_client.cc @@ -1,81 +1,83 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "chrome/browser/ui/autofill/tab_autofill_manager_delegate.h" +#include "content/nw/src/browser/nw_autofill_client.h" #include "base/logging.h" #include "base/prefs/pref_service.h" -#include "chrome/browser/ui/autofill/autofill_popup_controller_impl.h" #include "components/autofill/content/browser/content_autofill_driver.h" #include "components/autofill/content/common/autofill_messages.h" #include "components/autofill/core/common/autofill_pref_names.h" -#include "content/public/browser/render_view_host.h" -#include "content/public/browser/web_contents_view.h" -#include "content/nw/src/shell_browser_context.h" +#include "content/nw/src/browser/autofill_popup_controller_impl.h" #include "content/nw/src/browser/nw_form_database_service.h" +#include "content/nw/src/shell_browser_context.h" +#include "content/public/browser/render_view_host.h" #include "ui/gfx/rect.h" #if defined(OS_ANDROID) #include "chrome/browser/ui/android/autofill/autofill_logger_android.h" #endif -DEFINE_WEB_CONTENTS_USER_DATA_KEY(autofill::TabAutofillManagerDelegate); +DEFINE_WEB_CONTENTS_USER_DATA_KEY(autofill::NWAutofillClient); namespace autofill { -TabAutofillManagerDelegate::TabAutofillManagerDelegate( - content::WebContents* web_contents) - : content::WebContentsObserver(web_contents), - web_contents_(web_contents) { +NWAutofillClient::NWAutofillClient(content::WebContents* web_contents) + : content::WebContentsObserver(web_contents), web_contents_(web_contents) { DCHECK(web_contents); +#if defined(OS_MACOSX) && !defined(OS_IOS) + RegisterForKeystoneNotifications(); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) } -TabAutofillManagerDelegate::~TabAutofillManagerDelegate() { +NWAutofillClient::~NWAutofillClient() { // NOTE: It is too late to clean up the autofill popup; that cleanup process // requires that the WebContents instance still be valid and it is not at // this point (in particular, the WebContentsImpl destructor has already // finished running and we are now in the base class destructor). DCHECK(!popup_controller_); +#if defined(OS_MACOSX) && !defined(OS_IOS) + UnregisterFromKeystoneNotifications(); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) } -void TabAutofillManagerDelegate::TabActivated() { +void NWAutofillClient::TabActivated() { } -PersonalDataManager* TabAutofillManagerDelegate::GetPersonalDataManager() { +PersonalDataManager* NWAutofillClient::GetPersonalDataManager() { return NULL; } -scoped_refptr - TabAutofillManagerDelegate::GetDatabase() { +scoped_refptr NWAutofillClient::GetDatabase() { nw::NwFormDatabaseService* service = static_cast( web_contents_->GetBrowserContext())->GetFormDatabaseService(); return service->get_autofill_webdata_service(); } -PrefService* TabAutofillManagerDelegate::GetPrefs() { +PrefService* NWAutofillClient::GetPrefs() { return NULL; } -void TabAutofillManagerDelegate::ShowAutofillSettings() { +void NWAutofillClient::ShowAutofillSettings() { NOTIMPLEMENTED(); } -void TabAutofillManagerDelegate::ConfirmSaveCreditCard( +void NWAutofillClient::ConfirmSaveCreditCard( const AutofillMetrics& metric_logger, const base::Closure& save_card_callback) { NOTIMPLEMENTED(); } -void TabAutofillManagerDelegate::ShowRequestAutocompleteDialog( +void NWAutofillClient::ShowRequestAutocompleteDialog( const FormData& form, const GURL& source_url, - const base::Callback& callback) { + const ResultCallback& callback) { NOTIMPLEMENTED(); } -void TabAutofillManagerDelegate::ShowAutofillPopup( +void NWAutofillClient::ShowAutofillPopup( const gfx::RectF& element_bounds, base::i18n::TextDirection text_direction, const std::vector& values, @@ -84,55 +86,52 @@ void TabAutofillManagerDelegate::ShowAutofillPopup( const std::vector& identifiers, base::WeakPtr delegate) { // Convert element_bounds to be in screen space. - gfx::Rect client_area; - web_contents_->GetView()->GetContainerBounds(&client_area); + gfx::Rect client_area = web_contents_->GetContainerBounds(); gfx::RectF element_bounds_in_screen_space = element_bounds + client_area.OffsetFromOrigin(); // Will delete or reuse the old |popup_controller_|. - popup_controller_ = AutofillPopupControllerImpl::GetOrCreate( - popup_controller_, - delegate, - web_contents(), - web_contents()->GetView()->GetNativeView(), - element_bounds_in_screen_space, - text_direction); + popup_controller_ = + AutofillPopupControllerImpl::GetOrCreate(popup_controller_, + delegate, + web_contents(), + web_contents()->GetNativeView(), + element_bounds_in_screen_space, + text_direction); popup_controller_->Show(values, labels, icons, identifiers); } -void TabAutofillManagerDelegate::UpdateAutofillPopupDataListValues( +void NWAutofillClient::UpdateAutofillPopupDataListValues( const std::vector& values, const std::vector& labels) { if (popup_controller_.get()) popup_controller_->UpdateDataListValues(values, labels); } -void TabAutofillManagerDelegate::HideAutofillPopup() { +void NWAutofillClient::HideAutofillPopup() { if (popup_controller_.get()) popup_controller_->Hide(); - } -bool TabAutofillManagerDelegate::IsAutocompleteEnabled() { +bool NWAutofillClient::IsAutocompleteEnabled() { return true; } -void TabAutofillManagerDelegate::HideRequestAutocompleteDialog() { +void NWAutofillClient::HideRequestAutocompleteDialog() { NOTIMPLEMENTED(); } -void TabAutofillManagerDelegate::WebContentsDestroyed( - content::WebContents* web_contents) { +void NWAutofillClient::WebContentsDestroyed() { HideAutofillPopup(); } -void TabAutofillManagerDelegate::DetectAccountCreationForms( +void NWAutofillClient::DetectAccountCreationForms( const std::vector& forms) { NOTIMPLEMENTED(); } -void TabAutofillManagerDelegate::DidFillOrPreviewField( +void NWAutofillClient::DidFillOrPreviewField( const base::string16& autofilled_value, const base::string16& profile_full_name) { } diff --git a/src/browser/tab_autofill_manager_delegate.h b/src/browser/nw_autofill_client.h similarity index 56% rename from src/browser/tab_autofill_manager_delegate.h rename to src/browser/nw_autofill_client.h index 6830858bbd..372a6226c3 100644 --- a/src/browser/tab_autofill_manager_delegate.h +++ b/src/browser/nw_autofill_client.h @@ -1,15 +1,15 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Copyright 2014 The Chromium Authors. All rights reserved. // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_AUTOFILL_TAB_AUTOFILL_MANAGER_DELEGATE_H_ -#define CHROME_BROWSER_UI_AUTOFILL_TAB_AUTOFILL_MANAGER_DELEGATE_H_ +#ifndef NW_BROWSER_UI_AUTOFILL_CHROME_AUTOFILL_CLIENT_H_ +#define NW_BROWSER_UI_AUTOFILL_CHROME_AUTOFILL_CLIENT_H_ #include "base/callback.h" #include "base/compiler_specific.h" #include "base/i18n/rtl.h" #include "base/memory/weak_ptr.h" -#include "components/autofill/core/browser/autofill_manager_delegate.h" +#include "components/autofill/core/browser/autofill_client.h" #include "content/public/browser/web_contents_observer.h" #include "content/public/browser/web_contents_user_data.h" @@ -22,24 +22,24 @@ class WebContents; namespace autofill { class AutofillDialogController; +class AutofillKeystoneBridgeWrapper; class AutofillPopupControllerImpl; struct FormData; -// Chrome implementation of AutofillManagerDelegate. -class TabAutofillManagerDelegate - : public AutofillManagerDelegate, - public content::WebContentsUserData, +// Chrome implementation of AutofillClient. +class NWAutofillClient + : public AutofillClient, + public content::WebContentsUserData, public content::WebContentsObserver { public: - virtual ~TabAutofillManagerDelegate(); + virtual ~NWAutofillClient(); // Called when the tab corresponding to |this| instance is activated. void TabActivated(); - // AutofillManagerDelegate implementation. + // AutofillClient: virtual PersonalDataManager* GetPersonalDataManager() OVERRIDE; - virtual scoped_refptr - GetDatabase() OVERRIDE; + virtual scoped_refptr GetDatabase() OVERRIDE; virtual PrefService* GetPrefs() OVERRIDE; virtual void HideRequestAutocompleteDialog() OVERRIDE; virtual void ShowAutofillSettings() OVERRIDE; @@ -49,7 +49,7 @@ class TabAutofillManagerDelegate virtual void ShowRequestAutocompleteDialog( const FormData& form, const GURL& source_url, - const base::Callback& callback) OVERRIDE; + const ResultCallback& callback) OVERRIDE; virtual void ShowAutofillPopup( const gfx::RectF& element_bounds, base::i18n::TextDirection text_direction, @@ -70,29 +70,39 @@ class TabAutofillManagerDelegate const base::string16& profile_full_name) OVERRIDE; // content::WebContentsObserver implementation. - virtual void WebContentsDestroyed( - content::WebContents* web_contents) OVERRIDE; - - // Exposed for testing. - AutofillDialogController* GetDialogControllerForTesting() { - return dialog_controller_.get(); - } - void SetDialogControllerForTesting( - const base::WeakPtr& dialog_controller) { - dialog_controller_ = dialog_controller; - } + virtual void WebContentsDestroyed() OVERRIDE; private: - explicit TabAutofillManagerDelegate(content::WebContents* web_contents); - friend class content::WebContentsUserData; +#if defined(OS_MACOSX) && !defined(OS_IOS) + // Creates |bridge_wrapper_|, which is responsible for dealing with Keystone + // notifications. + void RegisterForKeystoneNotifications(); + + // Deletes |bridge_wrapper_|. + void UnregisterFromKeystoneNotifications(); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + + explicit NWAutofillClient(content::WebContents* web_contents); + friend class content::WebContentsUserData; content::WebContents* const web_contents_; - base::WeakPtr dialog_controller_; + // base::WeakPtr dialog_controller_; base::WeakPtr popup_controller_; - DISALLOW_COPY_AND_ASSIGN(TabAutofillManagerDelegate); +#if defined(OS_MACOSX) && !defined(OS_IOS) + // Listens to Keystone notifications and passes relevant ones on to the + // PersonalDataManager. + // + // The class of this member must remain a forward declaration, even in the + // .cc implementation file, since the class is defined in a Mac-only + // implementation file. This means that the pointer cannot be wrapped in a + // scoped_ptr. + AutofillKeystoneBridgeWrapper* bridge_wrapper_; +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + + DISALLOW_COPY_AND_ASSIGN(NWAutofillClient); }; } // namespace autofill -#endif // CHROME_BROWSER_UI_AUTOFILL_TAB_AUTOFILL_MANAGER_DELEGATE_H_ +#endif // CHROME_BROWSER_UI_AUTOFILL_CHROME_AUTOFILL_CLIENT_H_ diff --git a/src/nw_notification_manager.cc b/src/nw_notification_manager.cc index 5b7ab96a17..cd9eb778e3 100644 --- a/src/nw_notification_manager.cc +++ b/src/nw_notification_manager.cc @@ -57,12 +57,16 @@ NotificationManager* NotificationManager::getSingleton() { void NotificationManager::ImageDownloadCallback(int id, int http_status, const GURL& image_url, const std::vector& bitmaps, const std::vector& size) { NotificationManager *singleton = getSingleton(); DesktopNotificationParams params = singleton->desktop_notification_params_[id]; - singleton->AddDesktopNotification(params.params_, params.render_process_id_, params.render_view_id_, params.worker_, &bitmaps); + singleton->AddDesktopNotification(params.params_, params.render_process_id_, params.render_view_id_, id, params.worker_, &bitmaps); singleton->desktop_notification_params_.erase(id); } bool NotificationManager::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) { + const int render_process_id, + const int render_view_id, + const int notification_id, + const bool worker, + const std::vector* bitmaps) { NOTIMPLEMENTED(); return false; } diff --git a/src/nw_notification_manager.h b/src/nw_notification_manager.h index fcc25b98ac..d999c52ad5 100644 --- a/src/nw_notification_manager.h +++ b/src/nw_notification_manager.h @@ -46,13 +46,19 @@ class NotificationManager{ // internal function for AddDesktopNotification virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps); + const int render_process_id, const int render_view_id, + const int notification_id, const bool worker, + const std::vector* bitmaps); public: virtual ~NotificationManager(); static NotificationManager* getSingleton(); - virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker) = 0; + virtual bool AddDesktopNotification( + const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, + const int render_view_id, + const int notification_id, + const bool worker) = 0; virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) = 0; bool DesktopNotificationPostClick(int render_process_id, int render_view_id, int notification_id); diff --git a/src/nw_notification_manager_linux.cc b/src/nw_notification_manager_linux.cc index fd62b61316..cd90d5d1f1 100644 --- a/src/nw_notification_manager_linux.cc +++ b/src/nw_notification_manager_linux.cc @@ -18,8 +18,10 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "chrome/browser/status_icons/status_icon.h" +#include "chrome/browser/ui/libgtk2ui/skia_utils_gtk2.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" #include "content/nw/src/browser/native_window.h" #include "content/nw/src/nw_package.h" @@ -69,9 +71,13 @@ void NotificationManagerLinux::onClose(NotifyNotification *notif) }; bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) { + const int render_process_id, + const int render_view_id, + const int notification_id, + const bool worker, + const std::vector* bitmaps) { - content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); + content::RenderViewHost* host = content::RenderFrameHost::FromID(render_process_id, render_view_id)->GetRenderViewHost(); if (host == NULL) return false; @@ -105,7 +111,7 @@ bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktop } NotifyNotification * notif; - NotificationMap::iterator i = getNotification(params.notification_id); + NotificationMap::iterator i = getNotification(notification_id); if (i==mNotificationIDmap.end()) { notif = notify_notification_new ( base::UTF16ToUTF8(params.title).c_str(), base::UTF16ToUTF8(params.body).c_str(), NULL); @@ -113,7 +119,7 @@ bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktop data.mNotification = notif; data.mRenderProcessId = render_process_id; data.mRenderViewId = render_view_id; - mNotificationIDmap[params.notification_id] = data; + mNotificationIDmap[notification_id] = data; } else { notif = i->second.mNotification; @@ -121,18 +127,18 @@ bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktop base::UTF16ToUTF8(params.body).c_str(), NULL); // means this is the notify-osd hack - if (i->first != params.notification_id) { + if (i->first != notification_id) { NotificationData data; data.mNotification = notif; g_object_ref(G_OBJECT(notif)); onClose(notif); data.mRenderProcessId = render_process_id; data.mRenderViewId = render_view_id; - mNotificationIDmap[params.notification_id] = data; + mNotificationIDmap[notification_id] = data; } } - GdkPixbuf* pixbuf = gfx::GdkPixbufFromSkBitmap(bitmap); + GdkPixbuf* pixbuf = libgtk2ui::GdkPixbufFromSkBitmap(bitmap); notify_notification_set_image_from_pixbuf(notif, pixbuf); g_object_unref(pixbuf); @@ -140,11 +146,11 @@ bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktop GError* error = NULL; if (notify_notification_show (notif, &error)) { - DesktopNotificationPostDisplay(render_process_id, render_view_id, params.notification_id); + DesktopNotificationPostDisplay(render_process_id, render_view_id, notification_id); } else { base::string16 errorMsg = base::UTF8ToUTF16(error->message); - DesktopNotificationPostError(render_process_id, render_view_id, params.notification_id, errorMsg); + DesktopNotificationPostError(render_process_id, render_view_id, notification_id, errorMsg); } return error==NULL; } @@ -158,8 +164,11 @@ bool NotificationManagerLinux::CancelDesktopNotification(int render_process_id, } bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker) { - return AddDesktopNotification(params, render_process_id, render_view_id, worker, NULL); + const int render_process_id, + const int render_view_id, + const int notification_id, + const bool worker) { + return AddDesktopNotification(params, render_process_id, render_view_id, notification_id, worker, NULL); } } // namespace nw diff --git a/src/nw_notification_manager_linux.h b/src/nw_notification_manager_linux.h index 834acb035a..4da49b5ba4 100644 --- a/src/nw_notification_manager_linux.h +++ b/src/nw_notification_manager_linux.h @@ -42,13 +42,20 @@ class NotificationManagerLinux : public NotificationManager { // internal function for AddDesktopNotification virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) OVERRIDE; + const int render_process_id, + const int render_view_id, + const int notification_id, + const bool worker, + const std::vector* bitmaps) OVERRIDE; public: explicit NotificationManagerLinux(); virtual ~NotificationManagerLinux(); virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker) OVERRIDE; + const int render_process_id, + const int render_view_id, + const int notification_id, + const bool worker) OVERRIDE; virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) OVERRIDE; }; diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 879e5999fa..af015f1c0d 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -52,7 +52,7 @@ #include "content/nw/src/browser/native_window.h" #include "content/nw/src/browser/shell_devtools_delegate.h" #include "content/nw/src/browser/shell_javascript_dialog_creator.h" -//#include "content/nw/src/browser/tab_autofill_manager_delegate.h" +#include "content/nw/src/browser/nw_autofill_client.h" #include "content/nw/src/common/shell_switches.h" #include "content/nw/src/media/media_stream_devices_controller.h" #include "content/nw/src/nw_package.h" @@ -207,14 +207,12 @@ Shell::Shell(WebContents* web_contents, base::DictionaryValue* manifest) web_modal::WebContentsModalDialogManager::FromWebContents(web_contents)->SetDelegate(this); #endif -#if 0 //FIXME - autofill::TabAutofillManagerDelegate::CreateForWebContents(web_contents); + autofill::NWAutofillClient::CreateForWebContents(web_contents); autofill::ContentAutofillDriver::CreateForWebContentsAndDelegate( web_contents, - autofill::TabAutofillManagerDelegate::FromWebContents(web_contents), + autofill::NWAutofillClient::FromWebContents(web_contents), "", autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER); -#endif } Shell::~Shell() { diff --git a/src/shell_content_browser_client.cc b/src/shell_content_browser_client.cc index 197783c148..5c452faa74 100644 --- a/src/shell_content_browser_client.cc +++ b/src/shell_content_browser_client.cc @@ -34,6 +34,7 @@ #include "content/browser/gpu/compositor_util.h" #include "content/nw/src/browser/printing/printing_message_filter.h" #include "content/public/browser/browser_url_handler.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_process_host.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/render_widget_host_iterator.h" @@ -491,42 +492,29 @@ ShellContentBrowserClient::CreateQuotaPermissionContext() { return new ShellQuotaPermissionContext(); } -#if 0 void ShellContentBrowserClient::ShowDesktopNotification( - const ShowDesktopNotificationHostMsgParams& params, - int render_process_id, - int render_view_id, - bool worker) { + const ShowDesktopNotificationHostMsgParams& params, + RenderFrameHost* render_frame_host, + scoped_ptr delegate, + base::Closure* cancel_callback) { #if defined(ENABLE_NOTIFICATIONS) nw::NotificationManager *notificationManager = nw::NotificationManager::getSingleton(); if (notificationManager == NULL) { NOTIMPLEMENTED(); return; } - notificationManager->AddDesktopNotification(params, render_process_id, render_view_id, worker); + content::RenderProcessHost* process = render_frame_host->GetProcess(); + notificationManager->AddDesktopNotification(params, process->GetID(), + render_frame_host->GetRoutingID(), + delegate->notification_id(), + false); #else NOTIMPLEMENTED(); #endif } -void ShellContentBrowserClient::CancelDesktopNotification( - int render_process_id, - int render_view_id, - int notification_id) { -#if defined(ENABLE_NOTIFICATIONS) - nw::NotificationManager *notificationManager = nw::NotificationManager::getSingleton(); - if (notificationManager == NULL) { - NOTIMPLEMENTED(); - return; - } - notificationManager->CancelDesktopNotification(render_process_id, render_view_id, notification_id); -#else - NOTIMPLEMENTED(); -#endif -} - -#endif +// FIXME: cancel desktop notification void ShellContentBrowserClient::RequestMidiSysExPermission( WebContents* web_contents, diff --git a/src/shell_content_browser_client.h b/src/shell_content_browser_client.h index bb92bb843c..dc82cdea6d 100644 --- a/src/shell_content_browser_client.h +++ b/src/shell_content_browser_client.h @@ -92,19 +92,12 @@ class ShellContentBrowserClient : public ContentBrowserClient { #endif virtual QuotaPermissionContext* CreateQuotaPermissionContext() OVERRIDE; -#if 0 //Notification virtual void ShowDesktopNotification( - const ShowDesktopNotificationHostMsgParams& params, - int render_process_id, - int render_view_id, - bool worker) ; //FIXME - - virtual void CancelDesktopNotification( - int render_process_id, - int render_view_id, - int notification_id) ; //FIXME -#endif + const ShowDesktopNotificationHostMsgParams& params, + RenderFrameHost* render_frame_host, + scoped_ptr delegate, + base::Closure* cancel_callback) OVERRIDE; virtual void RequestMidiSysExPermission( WebContents* web_contents, From c6489287530252fa55ed00ba597fc082fc47b468 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Thu, 9 Oct 2014 00:00:23 +0800 Subject: [PATCH 205/492] fix notification for windows --- src/nw_notification_manager_win.cc | 6 ++++-- src/nw_notification_manager_win.h | 8 +++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/nw_notification_manager_win.cc b/src/nw_notification_manager_win.cc index aa7f09eea9..02cfc4a8f5 100644 --- a/src/nw_notification_manager_win.cc +++ b/src/nw_notification_manager_win.cc @@ -22,6 +22,7 @@ #include "chrome/browser/ui/views/status_icons/status_tray_win.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" #include "content/nw/src/browser/native_window.h" #include "content/nw/src/nw_package.h" @@ -118,9 +119,10 @@ NotificationManagerWin::~NotificationManagerWin() { } bool NotificationManagerWin::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) { + const int render_process_id, const int render_view_id, const int notification_id, + const bool worker, const std::vector* bitmaps) { - content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); + content::RenderViewHost* host = content::RenderFrameHost::FromID(render_process_id, render_view_id)->GetRenderViewHost(); if (host == NULL) return false; diff --git a/src/nw_notification_manager_win.h b/src/nw_notification_manager_win.h index f4a5d95a87..5d2c8e2bbd 100644 --- a/src/nw_notification_manager_win.h +++ b/src/nw_notification_manager_win.h @@ -61,14 +61,16 @@ class NotificationManagerWin : public NotificationManager{ // internal function for AddDesktopNotification virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) OVERRIDE; + const int render_process_id, const int render_view_id, const int notification_id, + const bool worker, const std::vector* bitmaps) OVERRIDE; public: explicit NotificationManagerWin(); virtual ~NotificationManagerWin(); virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker) OVERRIDE{ - return AddDesktopNotification(params, render_process_id, render_view_id, worker, NULL); + const int render_process_id, const int render_view_id, const int notification_id, + const bool worker) OVERRIDE{ + return AddDesktopNotification(params, render_process_id, render_view_id, notification_id, worker, NULL); } virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) OVERRIDE; }; From dc5f005dc07532c36a2a5441282825d5e9d95723 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Thu, 9 Oct 2014 10:21:51 +0800 Subject: [PATCH 206/492] rebase fix for mac --- src/browser/native_window_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index 7a8aa06ac4..0839d8ecde 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -386,7 +386,7 @@ - (void)drawRect:(NSRect)dirtyRect { } window_ = shell_window; [shell_window setShell:shell]; - [[window() contentView] cr_setWantsLayer:YES]; + [[window() contentView] setWantsLayer:YES]; [window() setDelegate:[[NativeWindowDelegate alloc] initWithShell:shell]]; // Disable fullscreen button when 'fullscreen' is specified to false. From 30b336e331243e80399de41e11e3020bfac1b46d Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Thu, 9 Oct 2014 14:35:58 +0800 Subject: [PATCH 207/492] [OSX] fix notification --- nw.gypi | 1 + src/browser/nw_autofill_client.h | 2 +- src/browser/nw_autofill_client_mac.mm | 21 +++++++++++++++++++++ src/nw_notification_manager_mac.h | 8 ++++++-- src/nw_notification_manager_mac.mm | 9 +++++---- 5 files changed, 34 insertions(+), 7 deletions(-) create mode 100644 src/browser/nw_autofill_client_mac.mm diff --git a/nw.gypi b/nw.gypi index e3bcdf955d..d4198a06d0 100644 --- a/nw.gypi +++ b/nw.gypi @@ -192,6 +192,7 @@ 'src/browser/browser_view_layout.h', 'src/browser/nw_autofill_client.cc', 'src/browser/nw_autofill_client.h', + 'src/browser/nw_autofill_client_mac.mm', 'src/browser/capture_page_helper.h', 'src/browser/capture_page_helper.cc', # 'src/browser/color_chooser_gtk.cc', diff --git a/src/browser/nw_autofill_client.h b/src/browser/nw_autofill_client.h index 372a6226c3..d4c02a1d12 100644 --- a/src/browser/nw_autofill_client.h +++ b/src/browser/nw_autofill_client.h @@ -97,7 +97,7 @@ class NWAutofillClient // .cc implementation file, since the class is defined in a Mac-only // implementation file. This means that the pointer cannot be wrapped in a // scoped_ptr. - AutofillKeystoneBridgeWrapper* bridge_wrapper_; + // AutofillKeystoneBridgeWrapper* bridge_wrapper_; #endif // defined(OS_MACOSX) && !defined(OS_IOS) DISALLOW_COPY_AND_ASSIGN(NWAutofillClient); diff --git a/src/browser/nw_autofill_client_mac.mm b/src/browser/nw_autofill_client_mac.mm new file mode 100644 index 0000000000..783572495b --- /dev/null +++ b/src/browser/nw_autofill_client_mac.mm @@ -0,0 +1,21 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/nw_autofill_client.h" + +#import + +#include "base/logging.h" +#include "base/mac/scoped_nsobject.h" +#include "components/autofill/core/browser/personal_data_manager.h" + +namespace autofill { + +void NWAutofillClient::RegisterForKeystoneNotifications() { +} + +void NWAutofillClient::UnregisterFromKeystoneNotifications() { +} + +} // namespace autofill diff --git a/src/nw_notification_manager_mac.h b/src/nw_notification_manager_mac.h index 48635bf10e..8c3ddb942d 100644 --- a/src/nw_notification_manager_mac.h +++ b/src/nw_notification_manager_mac.h @@ -28,13 +28,17 @@ class NotificationManagerMac : public NotificationManager { // internal function for AddDesktopNotification virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) OVERRIDE; + const int render_process_id, const int render_view_id, + const int notification_id, + const bool worker, const std::vector* bitmaps) OVERRIDE; public: explicit NotificationManagerMac(); virtual ~NotificationManagerMac(){} virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker) OVERRIDE; + const int render_process_id, const int render_view_id, + const int notification_id, + const bool worker) OVERRIDE; virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) OVERRIDE; }; diff --git a/src/nw_notification_manager_mac.mm b/src/nw_notification_manager_mac.mm index 2a23464886..2654745368 100644 --- a/src/nw_notification_manager_mac.mm +++ b/src/nw_notification_manager_mac.mm @@ -22,6 +22,7 @@ #include "base/strings/sys_string_conversions.h" #include "content/public/browser/web_contents.h" +#include "content/public/browser/render_frame_host.h" #include "content/public/browser/render_view_host.h" #include "content/nw/src/browser/native_window.h" #include "content/nw/src/nw_package.h" @@ -80,14 +81,14 @@ -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNoti NotificationManagerMac::NotificationManagerMac() { } -bool NotificationManagerMac::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams ¶ms, const int render_process_id, const int render_view_id, const bool worker) { - return AddDesktopNotification(params, render_process_id, render_view_id, worker, NULL); +bool NotificationManagerMac::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams ¶ms, const int render_process_id, const int render_view_id, const int notification_id, const bool worker) { + return AddDesktopNotification(params, render_process_id, render_view_id, notification_id, worker, NULL); } bool NotificationManagerMac::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const bool worker, const std::vector* bitmaps) { + const int render_process_id, const int render_view_id, const int notification_id, const bool worker, const std::vector* bitmaps) { - content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); + content::RenderViewHost* host = content::RenderFrameHost::FromID(render_process_id, render_view_id)->GetRenderViewHost(); if (host == nullptr) return false; content::Shell* shell = content::Shell::FromRenderViewHost(host); From 6289cfab7db5d7edad1b3e4e40a160ed19023419 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 10 Oct 2014 23:17:54 +0800 Subject: [PATCH 208/492] bump version to v0.11.0-pre --- src/mac/app-Info.plist | 2 +- src/nw_version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mac/app-Info.plist b/src/mac/app-Info.plist index 4e007452c9..9ca35ff029 100644 --- a/src/mac/app-Info.plist +++ b/src/mac/app-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.10.6 + 0.11.0 NSPrincipalClass NSApplication LSMinimumSystemVersion diff --git a/src/nw_version.h b/src/nw_version.h index c63f7ba74f..e06da8148c 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -22,8 +22,8 @@ #define NW_VERSION_H #define NW_MAJOR_VERSION 0 -#define NW_MINOR_VERSION 10 -#define NW_PATCH_VERSION 6 +#define NW_MINOR_VERSION 11 +#define NW_PATCH_VERSION 0 #define NW_VERSION_IS_RELEASE 0 #ifndef NW_STRINGIFY @@ -43,7 +43,7 @@ #define NW_VERSION "v" NW_VERSION_STRING -#define CHROME_VERSION "35.0.1916.157" +#define CHROME_VERSION "38.0.2125.104" #define NW_VERSION_AT_LEAST(major, minor, patch) \ (( (major) < NW_MAJOR_VERSION) \ From 3f795f4b0131583f1128ed25ab88c7265f6bceaa Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 12 Oct 2014 11:20:07 +0800 Subject: [PATCH 209/492] disable nwsnapshot for now --- nw.gypi | 2 +- tools/package_binaries.py | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/nw.gypi b/nw.gypi index d4198a06d0..b648fe1d78 100644 --- a/nw.gypi +++ b/nw.gypi @@ -741,7 +741,7 @@ { 'action_name': 'strip_nw_binaries', 'inputs': [ - '<(PRODUCT_DIR)/nwsnapshot', + #'<(PRODUCT_DIR)/nwsnapshot', '<(PRODUCT_DIR)/chromedriver', ], 'outputs': [ diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 4ca2f384e6..a6d7812492 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -114,7 +114,7 @@ def generate_target_nw(platform_name, arch, version): 'credits.html', 'libffmpegsumo.so', 'nw.pak', - 'nwsnapshot', + #'nwsnapshot', 'nw', 'icudtl.dat', 'locales', @@ -128,13 +128,13 @@ def generate_target_nw(platform_name, arch, version): 'nw.exe', 'nw.pak', 'locales', - 'nwsnapshot.exe', + #'nwsnapshot.exe', 'credits.html', ] elif platform_name == 'osx': target['input'] = [ 'node-webkit.app', - 'nwsnapshot', + #'nwsnapshot', 'credits.html', ] else: From 920fc1b5e54f9b7fa44332728c7ff6f5e4169ac5 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Sun, 12 Oct 2014 23:25:27 +0800 Subject: [PATCH 210/492] [WIN] fix for 64bit build --- nw.gypi | 2 +- src/api/dispatcher_bindings.cc | 2 +- src/browser/native_window_aura.cc | 2 +- src/browser/shell_javascript_dialog_win.cc | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/nw.gypi b/nw.gypi index b648fe1d78..fcd8351ad2 100644 --- a/nw.gypi +++ b/nw.gypi @@ -470,7 +470,7 @@ }, }, }, - 'msvs_disabled_warnings': [ 4800, 4819 ], + 'msvs_disabled_warnings': [ 4267, 4800, 4819 ], }], # OS=="win" ], }, diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 36fbdf1c90..359c47e57a 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -117,7 +117,7 @@ DispatcherBindings::DispatcherBindings() IDR_NW_API_DISPATCHER_BINDINGS_JS).data(), 0, // num dependencies. NULL, // dependencies array. - GetStringResource( + (int)GetStringResource( IDR_NW_API_DISPATCHER_BINDINGS_JS).size()) { #if defined(OS_MACOSX) InitMsgIDMap(); diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index 0a79eb58ec..da75d20d90 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -417,7 +417,7 @@ void NativeWindowAura::SetShowInTaskbar(bool show) { if (show == false && base::win::GetVersion() < base::win::VERSION_VISTA) { // Change the owner of native window. Only needed on Windows XP. ::SetWindowLong(views::HWNDForWidget(window_), - GWL_HWNDPARENT, + GWLP_HWNDPARENT, (LONG)ui::GetHiddenWindow()); } diff --git a/src/browser/shell_javascript_dialog_win.cc b/src/browser/shell_javascript_dialog_win.cc index 3611e3fd5a..636bf3028e 100644 --- a/src/browser/shell_javascript_dialog_win.cc +++ b/src/browser/shell_javascript_dialog_win.cc @@ -35,7 +35,7 @@ INT_PTR CALLBACK ShellJavaScriptDialog::DialogProc(HWND dialog, LPARAM lparam) { switch (message) { case WM_INITDIALOG: { - SetWindowLongPtr(dialog, DWL_USER, static_cast(lparam)); + SetWindowLongPtr(dialog, DWLP_USER, static_cast(lparam)); ShellJavaScriptDialog* owner = reinterpret_cast(lparam); owner->dialog_win_ = dialog; @@ -47,7 +47,7 @@ INT_PTR CALLBACK ShellJavaScriptDialog::DialogProc(HWND dialog, } case WM_DESTROY: { ShellJavaScriptDialog* owner = reinterpret_cast( - GetWindowLongPtr(dialog, DWL_USER)); + GetWindowLongPtr(dialog, DWLP_USER)); if (owner->dialog_win_) { owner->dialog_win_ = 0; owner->callback_.Run(false, base::string16()); @@ -57,7 +57,7 @@ INT_PTR CALLBACK ShellJavaScriptDialog::DialogProc(HWND dialog, } case WM_COMMAND: { ShellJavaScriptDialog* owner = reinterpret_cast( - GetWindowLongPtr(dialog, DWL_USER)); + GetWindowLongPtr(dialog, DWLP_USER)); base::string16 user_input; bool finish = false; bool result; From 883af3641fe984cf0ceb9ad41d2297e53715d460 Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 12 Oct 2014 11:36:30 +0800 Subject: [PATCH 211/492] fix color chooser for linux --- nw.gypi | 3 +- src/browser/color_chooser_aura.cc | 68 +++++++++++++++ src/browser/color_chooser_aura.h | 58 +++++++++++++ src/browser/color_chooser_gtk.cc | 134 ------------------------------ src/nw_shell.cc | 3 +- 5 files changed, 129 insertions(+), 137 deletions(-) create mode 100644 src/browser/color_chooser_aura.cc create mode 100644 src/browser/color_chooser_aura.h delete mode 100644 src/browser/color_chooser_gtk.cc diff --git a/nw.gypi b/nw.gypi index fcd8351ad2..0d26329f39 100644 --- a/nw.gypi +++ b/nw.gypi @@ -195,7 +195,8 @@ 'src/browser/nw_autofill_client_mac.mm', 'src/browser/capture_page_helper.h', 'src/browser/capture_page_helper.cc', -# 'src/browser/color_chooser_gtk.cc', + 'src/browser/color_chooser_aura.cc', + 'src/browser/color_chooser_aura.h', 'src/browser/color_chooser_win.cc', 'src/browser/color_chooser_mac.mm', 'src/browser/chrome_event_processing_window.mm', diff --git a/src/browser/color_chooser_aura.cc b/src/browser/color_chooser_aura.cc new file mode 100644 index 0000000000..1c4c5012c3 --- /dev/null +++ b/src/browser/color_chooser_aura.cc @@ -0,0 +1,68 @@ +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/color_chooser_aura.h" + +#include "content/public/browser/web_contents.h" +#include "ui/views/color_chooser/color_chooser_view.h" +#include "ui/views/widget/widget.h" + +ColorChooserAura::ColorChooserAura(content::WebContents* web_contents, + SkColor initial_color) + : web_contents_(web_contents) { + view_ = new views::ColorChooserView(this, initial_color); + widget_ = views::Widget::CreateWindowWithParent( + view_, web_contents->GetTopLevelNativeWindow()); + widget_->Show(); +} + +void ColorChooserAura::OnColorChosen(SkColor color) { + if (web_contents_) + web_contents_->DidChooseColorInColorChooser(color); +} + +void ColorChooserAura::OnColorChooserDialogClosed() { + view_ = NULL; + widget_ = NULL; + DidEndColorChooser(); +} + +void ColorChooserAura::End() { + if (widget_) { + view_->set_listener(NULL); + widget_->Close(); + view_ = NULL; + widget_ = NULL; + // DidEndColorChooser will invoke Browser::DidEndColorChooser, which deletes + // this. Take care of the call order. + DidEndColorChooser(); + } +} + +void ColorChooserAura::DidEndColorChooser() { + if (web_contents_) + web_contents_->DidEndColorChooser(); +} + +void ColorChooserAura::SetSelectedColor(SkColor color) { + if (view_) + view_->OnColorChanged(color); +} + +// static +ColorChooserAura* ColorChooserAura::Open( + content::WebContents* web_contents, SkColor initial_color) { + return new ColorChooserAura(web_contents, initial_color); +} + +#if !defined(OS_WIN) +namespace nw { + +content::ColorChooser* ShowColorChooser(content::WebContents* web_contents, + SkColor initial_color) { + return ColorChooserAura::Open(web_contents, initial_color); +} + +} // namespace nw +#endif // OS_WIN diff --git a/src/browser/color_chooser_aura.h b/src/browser/color_chooser_aura.h new file mode 100644 index 0000000000..e625550891 --- /dev/null +++ b/src/browser/color_chooser_aura.h @@ -0,0 +1,58 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NW_BROWSER_UI_VIEWS_COLOR_CHOOSER_AURA_H_ +#define NW_BROWSER_UI_VIEWS_COLOR_CHOOSER_AURA_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "content/public/browser/color_chooser.h" +#include "ui/views/color_chooser/color_chooser_listener.h" + +namespace content { +class WebContents; +} + +namespace views { +class ColorChooserView; +class Widget; +} + +// TODO(mukai): rename this as -Ash and move to c/b/ui/ash after Linux-aura +// switches to its native color chooser. +class ColorChooserAura : public content::ColorChooser, + public views::ColorChooserListener { + public: + static ColorChooserAura* Open(content::WebContents* web_contents, + SkColor initial_color); + + private: + ColorChooserAura(content::WebContents* web_contents, SkColor initial_color); + + // content::ColorChooser overrides: + virtual void End() OVERRIDE; + virtual void SetSelectedColor(SkColor color) OVERRIDE; + + // views::ColorChooserListener overrides: + virtual void OnColorChosen(SkColor color) OVERRIDE; + virtual void OnColorChooserDialogClosed() OVERRIDE; + + void DidEndColorChooser(); + + // The actual view of the color chooser. No ownership because its parent + // view will take care of its lifetime. + views::ColorChooserView* view_; + + // The widget for the color chooser. No ownership because it's released + // automatically when closed. + views::Widget* widget_; + + // The web contents invoking the color chooser. No ownership because it will + // outlive this class. + content::WebContents* web_contents_; + + DISALLOW_COPY_AND_ASSIGN(ColorChooserAura); +}; + +#endif // CHROME_BROWSER_UI_VIEWS_COLOR_CHOOSER_AURA_H_ diff --git a/src/browser/color_chooser_gtk.cc b/src/browser/color_chooser_gtk.cc deleted file mode 100644 index 131007d38c..0000000000 --- a/src/browser/color_chooser_gtk.cc +++ /dev/null @@ -1,134 +0,0 @@ -// Copyright (c) 2012 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#include - -#include "content/public/browser/color_chooser.h" -#include "content/public/browser/web_contents.h" -#include "grit/nw_resources.h" -//#include "ui/base/gtk/gtk_signal.h" -#include "ui/base/l10n/l10n_util.h" -//#include "ui/gfx/skia_utils_gtk.h" - -class ColorChooserGtk : public content::ColorChooser { - public: - static ColorChooserGtk* Open(content::WebContents* web_contents, - SkColor initial_color); - - ColorChooserGtk(content::WebContents* web_contents, SkColor initial_color); - virtual ~ColorChooserGtk(); - - virtual void End() OVERRIDE; - virtual void SetSelectedColor(SkColor color) OVERRIDE; - - private: - static ColorChooserGtk* current_color_chooser_; - - CHROMEGTK_CALLBACK_0(ColorChooserGtk, void, OnColorChooserOk); - CHROMEGTK_CALLBACK_0(ColorChooserGtk, void, OnColorChooserCancel); - CHROMEGTK_CALLBACK_0(ColorChooserGtk, void, OnColorChooserDestroy); - - // The web contents invoking the color chooser. No ownership because it will - // outlive this class. - content::WebContents* web_contents_; - GtkWidget* color_selection_dialog_; -}; - -ColorChooserGtk* ColorChooserGtk::current_color_chooser_ = NULL; - -ColorChooserGtk* ColorChooserGtk::Open(content::WebContents* web_contents, - SkColor initial_color) { - if (current_color_chooser_) - current_color_chooser_->End(); - DCHECK(!current_color_chooser_); - current_color_chooser_ = new ColorChooserGtk(web_contents, initial_color); - return current_color_chooser_; -} - -ColorChooserGtk::ColorChooserGtk(content::WebContents* web_contents, - SkColor initial_color) - : web_contents_(web_contents) { - color_selection_dialog_ = gtk_color_selection_dialog_new( - l10n_util::GetStringUTF8(IDS_SELECT_COLOR_DIALOG_TITLE).c_str()); - GtkWidget* cancel_button; - GtkColorSelection* color_selection; - GtkWidget* ok_button; - g_object_get(color_selection_dialog_, - "cancel-button", &cancel_button, - "color-selection", &color_selection, - "ok-button", &ok_button, - NULL); - gtk_color_selection_set_has_opacity_control(color_selection, FALSE); - g_signal_connect(ok_button, "clicked", - G_CALLBACK(OnColorChooserOkThunk), this); - g_signal_connect(cancel_button, "clicked", - G_CALLBACK(OnColorChooserCancelThunk), this); - g_signal_connect(color_selection_dialog_, "destroy", - G_CALLBACK(OnColorChooserDestroyThunk), this); - GdkColor gdk_color = gfx::SkColorToGdkColor(initial_color); - gtk_color_selection_set_previous_color(color_selection, &gdk_color); - gtk_color_selection_set_current_color(color_selection, &gdk_color); - gtk_window_present(GTK_WINDOW(color_selection_dialog_)); - g_object_unref(cancel_button); - g_object_unref(color_selection); - g_object_unref(ok_button); -} - -ColorChooserGtk::~ColorChooserGtk() { - // Always call End() before destroying. - DCHECK(!color_selection_dialog_); -} - -void ColorChooserGtk::OnColorChooserOk(GtkWidget* widget) { - GdkColor color; - GtkColorSelection* color_selection; - g_object_get(color_selection_dialog_, - "color-selection", &color_selection, NULL); - gtk_color_selection_get_current_color(color_selection, &color); - if (web_contents_) - web_contents_->DidChooseColorInColorChooser(gfx::GdkColorToSkColor(color)); - g_object_unref(color_selection); - gtk_widget_destroy(color_selection_dialog_); -} - -void ColorChooserGtk::OnColorChooserCancel(GtkWidget* widget) { - gtk_widget_destroy(color_selection_dialog_); -} - -void ColorChooserGtk::OnColorChooserDestroy(GtkWidget* widget) { - color_selection_dialog_ = NULL; - DCHECK(current_color_chooser_ == this); - current_color_chooser_ = NULL; - if (web_contents_) - web_contents_->DidEndColorChooser(); -} - -void ColorChooserGtk::End() { - if (!color_selection_dialog_) - return; - - gtk_widget_destroy(color_selection_dialog_); -} - -void ColorChooserGtk::SetSelectedColor(SkColor color) { - if (!color_selection_dialog_) - return; - - GdkColor gdk_color = gfx::SkColorToGdkColor(color); - GtkColorSelection* color_selection; - g_object_get(color_selection_dialog_, - "color-selection", &color_selection, NULL); - gtk_color_selection_set_previous_color(color_selection, &gdk_color); - gtk_color_selection_set_current_color(color_selection, &gdk_color); - g_object_unref(color_selection); -} - -namespace nw { - -content::ColorChooser* ShowColorChooser(content::WebContents* web_contents, - SkColor initial_color) { - return ColorChooserGtk::Open(web_contents, initial_color); -} - -} // namespace chrome diff --git a/src/nw_shell.cc b/src/nw_shell.cc index af015f1c0d..602f92382e 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -625,8 +625,7 @@ void Shell::WebContentsFocused(content::WebContents* web_contents) { content::ColorChooser* Shell::OpenColorChooser(content::WebContents* web_contents, SkColor color, const std::vector& suggestions) { - //FIXME: return nw::ShowColorChooser(web_contents, color); - return NULL; + return nw::ShowColorChooser(web_contents, color); } void Shell::RunFileChooser(WebContents* web_contents, From 1c0ff87e1d93577fa5a40abc87563aee363af442 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 13 Oct 2014 23:23:50 +0800 Subject: [PATCH 212/492] [WIN] fix popup manager --- src/browser/shell_login_dialog_win.cc | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/browser/shell_login_dialog_win.cc b/src/browser/shell_login_dialog_win.cc index 113b25f256..b75744261a 100644 --- a/src/browser/shell_login_dialog_win.cc +++ b/src/browser/shell_login_dialog_win.cc @@ -23,7 +23,6 @@ #include "base/logging.h" #include "base/strings/string16.h" #include "base/strings/utf_string_conversions.h" -#include "components/web_modal/popup_manager.h" #include "components/web_modal/web_contents_modal_dialog_host.h" #include "components/web_modal/web_contents_modal_dialog_manager.h" #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" @@ -82,12 +81,10 @@ void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) { WebContentsModalDialogManagerDelegate* modal_delegate = web_contents_modal_dialog_manager->delegate(); CHECK(modal_delegate); - dialog_ = CreateWindowAsFramelessChild( - this, modal_delegate->GetWebContentsModalDialogHost()->GetHostView()); - web_modal::PopupManager* popup_manager = - web_modal::PopupManager::FromWebContents(requesting_contents); - popup_manager->ShowModalDialog(dialog_->GetNativeView(), requesting_contents); - + dialog_ = views::DialogDelegate::CreateDialogWidget( + this, NULL, modal_delegate->GetWebContentsModalDialogHost()->GetHostView()); + web_modal::WebContentsModalDialogManager::FromWebContents(requesting_contents)-> + ShowModalDialog(dialog_->GetNativeWindow()); } #if 0 From 06cf6cb4d6102382743b073cba5cbd099d8e12e0 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 14 Oct 2014 06:46:04 +0800 Subject: [PATCH 213/492] specify product dir when package --- nw.gypi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nw.gypi b/nw.gypi index 0d26329f39..8f047d0527 100644 --- a/nw.gypi +++ b/nw.gypi @@ -775,7 +775,7 @@ 'outputs':[ '<(PRODUCT_DIR)/new_package.re', ], - 'action': ['python', '<(package_script)'], + 'action': ['python', '<(package_script)', '-p', '<(PRODUCT_DIR)'], }, ], 'dependencies': [ From 92262c961b75346f3c104ad178415721c7b205ff Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 14 Oct 2014 07:02:34 +0800 Subject: [PATCH 214/492] specify target_arch from nw.gypi for package --- nw.gypi | 2 +- tools/package_binaries.py | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/nw.gypi b/nw.gypi index 8f047d0527..284346ba4e 100644 --- a/nw.gypi +++ b/nw.gypi @@ -775,7 +775,7 @@ 'outputs':[ '<(PRODUCT_DIR)/new_package.re', ], - 'action': ['python', '<(package_script)', '-p', '<(PRODUCT_DIR)'], + 'action': ['python', '<(package_script)', '-p', '<(PRODUCT_DIR)', '-a', '<(target_arch)'], }, ], 'dependencies': [ diff --git a/tools/package_binaries.py b/tools/package_binaries.py index a6d7812492..2d62a3bee4 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -15,6 +15,7 @@ # Parse command line args parser = argparse.ArgumentParser(description='Package nw binaries.') parser.add_argument('-p','--path', help='Where to find the binaries, like out/Release', required=False) +parser.add_argument('-a','--arch', help='target arch', required=False) group = parser.add_mutually_exclusive_group() group.add_argument('-s','--step', choices=steps, help='Execute specified step.', required=False) group.add_argument('-n','--skip', choices=steps, help='Skip specified step.', required=False) @@ -80,6 +81,9 @@ else: # should be 'x86_64' arch = 'x64' +if args.arch != None: + arch = args.arch + nw_ver = getnwversion.nw_version if getnwisrelease.release == 0: nw_ver += getnwisrelease.postfix From 8a4ee77c8cdb1a0736005747c8760a66c20b1e1e Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 14 Oct 2014 13:08:26 +0800 Subject: [PATCH 215/492] tweak path argument of aws_uploader --- tools/aws_uploader.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tools/aws_uploader.py b/tools/aws_uploader.py index 891edd1f72..de9044ac12 100755 --- a/tools/aws_uploader.py +++ b/tools/aws_uploader.py @@ -38,7 +38,9 @@ # If the binaries location is not given, calculate it from script related dir. if dist_dir == None: dist_dir = os.path.join(os.path.dirname(__file__), - os.pardir, os.pardir, os.pardir, 'out', 'Release', 'dist') + os.pardir, os.pardir, os.pardir, 'out', 'Release') + +dist_dir = os.path.join(dist_dir, 'dist') if not os.path.isabs(dist_dir): dist_dir = os.path.join(os.getcwd(), dist_dir) From 7267ee3cb006261e6946542ee532db234a754b0f Mon Sep 17 00:00:00 2001 From: WolfspiritM Date: Fri, 17 Oct 2014 12:37:08 +0200 Subject: [PATCH 216/492] Fix #2469: Changed Window.open to ignore slashes in parameters. --- src/api/window/window.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/window/window.js b/src/api/window/window.js index 73d050a316..5124d90530 100644 --- a/src/api/window/window.js +++ b/src/api/window/window.js @@ -48,7 +48,7 @@ exports.Window = { // Conver relative url to full url. var protocol = url.match(/^[a-z]+:\/\//i); if (protocol == null || protocol.length == 0) { - var href = window.location.href; + var href = window.location.href.split(/\?|#/)[0]; url = href.substring(0, href.lastIndexOf('/') + 1) + url; } From 6d4254d3c0942390989fd759fe94ac8dda12c558 Mon Sep 17 00:00:00 2001 From: Chase Willden Date: Fri, 17 Oct 2014 09:08:18 -0600 Subject: [PATCH 217/492] Fixed bug #2307 --- src/api/window/window.cc | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/api/window/window.cc b/src/api/window/window.cc index adfe934653..c5c93dbeea 100644 --- a/src/api/window/window.cc +++ b/src/api/window/window.cc @@ -223,7 +223,12 @@ void Window::Call(const std::string& method, shell_->window()->SetKiosk(!shell_->window()->IsKiosk()); } else if (method == "CloseDevTools") { shell_->CloseDevTools(); - }else if (method == "ResizeTo") { + } else if (method == "SetPosition") { + std::string position; + if (arguments.GetString(0, &position)){ + shell_->window()->SetPosition(position); + } + } else if (method == "ResizeTo") { int width, height; if (arguments.GetInteger(0, &width) && arguments.GetInteger(1, &height)) From 7440c58fd72232dcb922406340e2617c72abd23c Mon Sep 17 00:00:00 2001 From: Nathan Dinsmore Date: Sun, 19 Oct 2014 17:31:19 -0400 Subject: [PATCH 218/492] Fix typo in breakpad_mac.mm --- src/breakpad_mac.mm | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/breakpad_mac.mm b/src/breakpad_mac.mm index 48dc09e729..25b0282831 100644 --- a/src/breakpad_mac.mm +++ b/src/breakpad_mac.mm @@ -195,7 +195,7 @@ void InitCrashReporter() { [resource_path stringByAppendingPathComponent:@"crash_report_sender.app"]; NSString *reporter_location = [[NSBundle bundleWithPath:reporter_bundle_location] executablePath]; -#endif +#endif VLOG(1) << "resource_path: " << [resource_path UTF8String]; VLOG(1) << "inspector_location: " << [inspector_location UTF8String]; @@ -235,7 +235,7 @@ void InitCrashReporter() { // Initialize Breakpad. gBreakpadRef = BreakpadCreate(breakpad_config); if (!gBreakpadRef) { - LOG_IF(ERROR, base::mac::AmIBundled()) << "Breakpad initializaiton failed"; + LOG_IF(ERROR, base::mac::AmIBundled()) << "Breakpad initialization failed"; return; } From 17f2aa21b1b7a4b05c4f805e365d64d6d4163b6c Mon Sep 17 00:00:00 2001 From: Cong Liu Date: Wed, 10 Sep 2014 16:25:03 +0800 Subject: [PATCH 219/492] Avoid failure on debug check of replacements "Hide Others" menu item doesn't accept any replacements. Providing replacements will fail the debug check and block the execution. --- src/api/menu/menu.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/menu/menu.js b/src/api/menu/menu.js index 38d505e3a3..5e40cb2210 100644 --- a/src/api/menu/menu.js +++ b/src/api/menu/menu.js @@ -86,7 +86,7 @@ if (require('os').platform() === 'darwin'){ key: "h" })); appleMenu.append(new exports.MenuItem({ - label: nw.getNSStringFWithFixup("IDS_HIDE_OTHERS_MAC", app_name), + label: nw.getNSStringWithFixup("IDS_HIDE_OTHERS_MAC"), selector: "hideOtherApplications:", key: "h", modifiers: "cmd-alt" From fc251cdc0a26facff7c0476653e3cc4bb2d9e5e7 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 20 Oct 2014 14:04:17 +0800 Subject: [PATCH 220/492] Remove workaround for vs2013 update 2 revert afdc6a683e3ad5490045361ceee7ff8076da3ff8 --- nw.gypi | 8 -------- 1 file changed, 8 deletions(-) diff --git a/nw.gypi b/nw.gypi index 284346ba4e..3d491d3681 100644 --- a/nw.gypi +++ b/nw.gypi @@ -375,14 +375,6 @@ '<(DEPTH)/base/allocator/allocator.gyp:allocator', ], }], - ['OS=="win" and target_arch=="ia32"', { - 'sources': [ - # TODO(scottmg): This is a workaround for - # http://crbug.com/348525 that affects VS2013 before Update 2. - # This should be removed once Update 2 is released. - '<(DEPTH)/build/win/ftol3.obj', - ], - }], ['win_pdf_metafile_for_printing==1', { 'sources': [ 'src/renderer/printing/print_web_view_helper_pdf_win.cc', From f7e0b6dc50346d336beb736db6dff1dd76a62616 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 20 Oct 2014 19:42:15 +0800 Subject: [PATCH 221/492] remove unused variable --- src/browser/shell_download_manager_delegate_gtk.cc | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/browser/shell_download_manager_delegate_gtk.cc b/src/browser/shell_download_manager_delegate_gtk.cc index e502fb33e2..5fd7b4dbaf 100644 --- a/src/browser/shell_download_manager_delegate_gtk.cc +++ b/src/browser/shell_download_manager_delegate_gtk.cc @@ -50,10 +50,8 @@ void ShellDownloadManagerDelegate::ChooseDownloadPath( FilePath result; GtkWidget *dialog; - gfx::NativeWindow parent_window; std::string base_name = FilePath(suggested_path).BaseName().value(); - parent_window = item->GetWebContents()->GetTopLevelNativeWindow(); dialog = gtk_file_chooser_dialog_new("Save File", NULL, GTK_FILE_CHOOSER_ACTION_SAVE, From 6ddf9db563fc484d0770992a202765182203b128 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 20 Oct 2014 19:43:41 +0800 Subject: [PATCH 222/492] bump version to v0.11.0-rc1 --- src/nw_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nw_version.h b/src/nw_version.h index e06da8148c..a22b3164c1 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -38,7 +38,7 @@ #else # define NW_VERSION_STRING NW_STRINGIFY(NW_MAJOR_VERSION) "." \ NW_STRINGIFY(NW_MINOR_VERSION) "." \ - NW_STRINGIFY(NW_PATCH_VERSION) "-pre" + NW_STRINGIFY(NW_PATCH_VERSION) "-rc1" #endif #define NW_VERSION "v" NW_VERSION_STRING From fe6c14373edaac5416821cb16c1f691e0bb9a28c Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 21 Oct 2014 15:30:41 +0800 Subject: [PATCH 223/492] fix download manager for nw11 --- src/browser/shell_download_manager_delegate.cc | 12 ++++++++++++ src/browser/shell_download_manager_delegate.h | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/src/browser/shell_download_manager_delegate.cc b/src/browser/shell_download_manager_delegate.cc index c3bdf09e88..133220ed46 100644 --- a/src/browser/shell_download_manager_delegate.cc +++ b/src/browser/shell_download_manager_delegate.cc @@ -102,6 +102,12 @@ bool ShellDownloadManagerDelegate::DetermineDownloadTarget( return true; } +bool ShellDownloadManagerDelegate::ShouldOpenDownload( + DownloadItem* item, + const DownloadOpenDelayedCallback& callback) { + return true; +} + void ShellDownloadManagerDelegate::GenerateFilename( int32 download_id, const DownloadTargetCallback& callback, @@ -142,4 +148,10 @@ void ShellDownloadManagerDelegate::SetDownloadBehaviorForTesting( suppress_prompting_ = true; } +void ShellDownloadManagerDelegate::GetNextId( + const DownloadIdCallback& callback) { + static uint32 next_id = DownloadItem::kInvalidId + 1; + callback.Run(next_id++); +} + } // namespace content diff --git a/src/browser/shell_download_manager_delegate.h b/src/browser/shell_download_manager_delegate.h index f9649e0e0f..4688eb433e 100644 --- a/src/browser/shell_download_manager_delegate.h +++ b/src/browser/shell_download_manager_delegate.h @@ -41,6 +41,10 @@ class ShellDownloadManagerDelegate virtual bool DetermineDownloadTarget( DownloadItem* download, const DownloadTargetCallback& callback) OVERRIDE; + virtual bool ShouldOpenDownload( + DownloadItem* item, + const DownloadOpenDelayedCallback& callback) OVERRIDE; + virtual void GetNextId(const DownloadIdCallback& callback) OVERRIDE; // Inhibits prompting and sets the default download path. void SetDownloadBehaviorForTesting( @@ -53,6 +57,8 @@ class ShellDownloadManagerDelegate private: friend class base::RefCountedThreadSafe; + typedef base::Callback + FilenameDeterminedCallback; void GenerateFilename(int32 download_id, const DownloadTargetCallback& callback, From 153ccd8997ad3de018f0036b0b82013b28d000e1 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 22 Oct 2014 12:36:24 +0800 Subject: [PATCH 224/492] fix fullscreen in Aura --- src/browser/native_window_aura.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index da75d20d90..196210d958 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -283,13 +283,18 @@ NativeWindowAura::NativeWindowAura(const base::WeakPtr& shell, initial_focus_(true), last_width_(-1), last_height_(-1) { manifest->GetBoolean("focus", &initial_focus_); + manifest->GetBoolean("fullscreen", &is_fullscreen_); window_ = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); params.delegate = this; params.remove_standard_frame = !has_frame(); params.use_system_default_icon = true; + if (is_fullscreen_) + params.show_state = ui::SHOW_STATE_FULLSCREEN; + window_->Init(params); + if (!has_frame()) InstallEasyResizeTargeterOnContainer(); @@ -304,6 +309,7 @@ NativeWindowAura::NativeWindowAura(const base::WeakPtr& shell, last_width_ = width; last_height_ = height; window_->AddObserver(this); + window_->SetSize(window_bounds.size()); window_->CenterWindow(window_bounds.size()); @@ -341,6 +347,8 @@ void NativeWindowAura::Show() { else if (!initial_focus_) { window_->set_focus_on_creation(false); window_->native_widget_private()->ShowWithWindowState(ui::SHOW_STATE_INACTIVE); + } else if (is_fullscreen_) { + window_->native_widget_private()->ShowWithWindowState(ui::SHOW_STATE_FULLSCREEN); } else window_->native_widget_private()->Show(); } From e3767a2d765ce4309da25485892f8a8b02719e96 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 22 Oct 2014 14:22:51 +0800 Subject: [PATCH 225/492] fix crash in window.open() Fix #2485 --- src/renderer/shell_content_renderer_client.cc | 10 ++++++++-- src/renderer/shell_content_renderer_client.h | 2 ++ 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index e7000ca27b..8ac12de0ef 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -502,9 +502,15 @@ void ShellContentRendererClient::willHandleNavigationPolicy( const blink::WebURLRequest& request, blink::WebNavigationPolicy* policy) { - in_nav_cb_ = true; - in_nav_url_ = request.url().string().utf8(); nwapi::Dispatcher::willHandleNavigationPolicy(rv, frame, request, policy); +} + +void ShellContentRendererClient::windowOpenBegin(const blink::WebURL& url) { + in_nav_cb_ = true; + in_nav_url_ =url.string().utf8(); +} + +void ShellContentRendererClient::windowOpenEnd() { in_nav_cb_ = false; } diff --git a/src/renderer/shell_content_renderer_client.h b/src/renderer/shell_content_renderer_client.h index b815585491..cd7a85e938 100644 --- a/src/renderer/shell_content_renderer_client.h +++ b/src/renderer/shell_content_renderer_client.h @@ -56,6 +56,8 @@ class ShellContentRendererClient : public ContentRendererClient { const blink::WebURLRequest& request, blink::WebNavigationPolicy* policy) OVERRIDE; + virtual void windowOpenBegin(const blink::WebURL& url) OVERRIDE; + virtual void windowOpenEnd() OVERRIDE; private: scoped_ptr shell_observer_; scoped_ptr window_bindings_; From 7585bf434229c67813f6f93ef7c583edf16dda67 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 22 Oct 2014 16:06:45 +0800 Subject: [PATCH 226/492] [linux] fix #2493: urlbar focus issue based on d699ce8cafc0066e4174a1d282d73ad68d432566 --- src/nw_shell.cc | 4 ++-- src/nw_shell.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 602f92382e..806837c937 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -70,7 +70,7 @@ #include "components/web_modal/web_contents_modal_dialog_manager.h" -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) #include "content/nw/src/browser/native_window_aura.h" #include "ui/views/controls/webview/webview.h" using nw::NativeWindowAura; @@ -614,7 +614,7 @@ void Shell::WebContentsCreated(WebContents* source_contents, #endif } -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) void Shell::WebContentsFocused(content::WebContents* web_contents) { NativeWindowAura* win = static_cast(window_.get()); if (win) // on aura this function is called in the middle of window creation diff --git a/src/nw_shell.h b/src/nw_shell.h index be01017f46..b802945c41 100644 --- a/src/nw_shell.h +++ b/src/nw_shell.h @@ -169,7 +169,7 @@ class Shell : public WebContentsDelegate, bool enter_fullscreen) OVERRIDE; virtual bool IsFullscreenForTabOrPending( const WebContents* web_contents) const OVERRIDE; -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) virtual void WebContentsFocused(WebContents* contents) OVERRIDE; #endif virtual content::ColorChooser* OpenColorChooser( From 44b26b1a9f65d61a33d774d197a849f3b08a02a2 Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 23 Oct 2014 12:51:25 +0800 Subject: [PATCH 227/492] [linux] fix crash dump Part of #2489 --- src/shell_content_browser_client.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/shell_content_browser_client.cc b/src/shell_content_browser_client.cc index 5c452faa74..9a12ea7ee1 100644 --- a/src/shell_content_browser_client.cc +++ b/src/shell_content_browser_client.cc @@ -24,6 +24,7 @@ #include "base/command_line.h" #include "base/files/file_path.h" #include "base/file_util.h" +#include "base/path_service.h" #include "base/strings/string_util.h" #include "base/strings/string_number_conversions.h" #include "base/threading/thread_restrictions.h" @@ -91,6 +92,8 @@ breakpad::CrashHandlerHostLinux* CreateCrashHandlerHost( base::FilePath dumps_path = CommandLine::ForCurrentProcess()->GetSwitchValuePath( switches::kCrashDumpsDir); + if (dumps_path.value().empty()) + PathService::Get(base::DIR_TEMP, &dumps_path); { ANNOTATE_SCOPED_MEMORY_LEAK; breakpad::CrashHandlerHostLinux* crash_handler = From 56e0242cd085f1feaa48b88b9a089effe11438cc Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 23 Oct 2014 23:52:37 +0800 Subject: [PATCH 228/492] fix linux login view and focus issue Fix #2502 --- nw.gypi | 14 +++++++------- src/browser/shell_login_dialog.cc | 9 --------- src/browser/shell_login_dialog.h | 8 ++++---- ...n_dialog_win.cc => shell_login_dialog_views.cc} | 4 +++- src/nw_shell.cc | 10 +++++++--- src/nw_shell.h | 10 +++++----- 6 files changed, 26 insertions(+), 29 deletions(-) rename src/browser/{shell_login_dialog_win.cc => shell_login_dialog_views.cc} (99%) diff --git a/nw.gypi b/nw.gypi index 3d491d3681..cb4ef3b38a 100644 --- a/nw.gypi +++ b/nw.gypi @@ -253,7 +253,7 @@ '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_views.cc', 'src/browser/shell_login_dialog.cc', 'src/browser/shell_login_dialog.h', 'src/browser/shell_resource_dispatcher_host_delegate.cc', @@ -361,6 +361,12 @@ ], }], ['use_aura==1', { + 'sources': [ + '<(DEPTH)/chrome/browser/ui/views/constrained_window_views.cc', + '<(DEPTH)/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc', + 'src/browser/login_view.cc', + 'src/browser/login_view.h', + ], 'dependencies': [ '<(DEPTH)/components/components.gyp:web_modal', '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources', @@ -393,12 +399,6 @@ ], }], ['OS=="win"', { - 'sources': [ - '<(DEPTH)/chrome/browser/ui/views/constrained_window_views.cc', - '<(DEPTH)/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc', - 'src/browser/login_view.cc', - 'src/browser/login_view.h', - ], 'dependencies': [ '<(DEPTH)/breakpad/breakpad.gyp:breakpad_handler', '<(DEPTH)/breakpad/breakpad.gyp:breakpad_sender', diff --git a/src/browser/shell_login_dialog.cc b/src/browser/shell_login_dialog.cc index 78eb02c768..1dfb826d1b 100644 --- a/src/browser/shell_login_dialog.cc +++ b/src/browser/shell_login_dialog.cc @@ -112,13 +112,4 @@ void ShellLoginDialog::ReleaseSoon() { BrowserThread::ReleaseSoon(BrowserThread::IO, FROM_HERE, this); } -#if defined(OS_LINUX) //FIXME -// Bogus implementations for linking. They are never called because -// ResourceDispatcherHostDelegate::CreateLoginDelegate returns NULL. -// TODO: implement ShellLoginDialog for other platforms, drop this #if -void ShellLoginDialog::PlatformCreateDialog(const base::string16& message) {} -void ShellLoginDialog::PlatformCleanUp() {} -void ShellLoginDialog::PlatformRequestCancelled() {} -#endif - } // namespace content diff --git a/src/browser/shell_login_dialog.h b/src/browser/shell_login_dialog.h index 10a0181d3f..55c39d34eb 100644 --- a/src/browser/shell_login_dialog.h +++ b/src/browser/shell_login_dialog.h @@ -13,7 +13,7 @@ #include "ui/base/gtk/gtk_signal.h" #endif -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) #include "ui/views/window/dialog_delegate.h" #include "login_view.h" #endif @@ -35,7 +35,7 @@ namespace content { // This class provides a dialog box to ask the user for credentials. Useful in // ResourceDispatcherHostDelegate::CreateLoginDelegate. -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate, public views::DialogDelegate { #else class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate { @@ -56,7 +56,7 @@ class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate { const base::string16& password); void UserCancelledAuth(); -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) // views::DialogDelegate methods: virtual base::string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE; virtual base::string16 GetWindowTitle() const OVERRIDE; @@ -119,7 +119,7 @@ class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate { GtkWidget* root_; CHROMEGTK_CALLBACK_1(ShellLoginDialog, void, OnResponse, int); CHROMEGTK_CALLBACK_0(ShellLoginDialog, void, OnDestroy); -#elif defined(OS_WIN) +#elif defined(OS_WIN) || defined(OS_LINUX) LoginView* login_view_; views::Widget* dialog_; diff --git a/src/browser/shell_login_dialog_win.cc b/src/browser/shell_login_dialog_views.cc similarity index 99% rename from src/browser/shell_login_dialog_win.cc rename to src/browser/shell_login_dialog_views.cc index b75744261a..b6c2376ea1 100644 --- a/src/browser/shell_login_dialog_win.cc +++ b/src/browser/shell_login_dialog_views.cc @@ -39,6 +39,7 @@ using web_modal::WebContentsModalDialogManager; using web_modal::WebContentsModalDialogManagerDelegate; +#if 0 namespace { // The captive portal dialog is system-modal, but uses the web-content-modal @@ -59,6 +60,7 @@ views::Widget* CreateWindowAsFramelessChild(views::WidgetDelegate* delegate, } } // namespace +#endif namespace content { @@ -142,7 +144,7 @@ void ShellLoginDialog::DeleteDelegate() { } ui::ModalType ShellLoginDialog::GetModalType() const { - return views::WidgetDelegate::GetModalType(); + return ui::MODAL_TYPE_CHILD; } bool ShellLoginDialog::Cancel() { diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 806837c937..36267cc813 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -202,7 +202,7 @@ Shell::Shell(WebContents* web_contents, base::DictionaryValue* manifest) // NativeWindow requires the window_ to be non-NULL. window_->InitFromManifest(manifest); -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) web_modal::WebContentsModalDialogManager::CreateForWebContents(web_contents); web_modal::WebContentsModalDialogManager::FromWebContents(web_contents)->SetDelegate(this); #endif @@ -599,7 +599,7 @@ void Shell::WebContentsCreated(WebContents* source_contents, printing::PrintViewManager::CreateForWebContents(new_contents); #endif -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) web_modal::WebContentsModalDialogManager::CreateForWebContents(new_contents); web_modal::WebContentsModalDialogManager::FromWebContents(new_contents)->SetDelegate(this); #endif @@ -712,7 +712,7 @@ void Shell::RenderViewCreated(RenderViewHost* render_view_host) { new nwapi::DispatcherHost(render_view_host); } -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) bool Shell::IsWebContentsVisible(content::WebContents* web_contents) { //FIXME return true; @@ -728,4 +728,8 @@ bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const { return window()->IsFullscreen(); } +web_modal::WebContentsModalDialogHost* Shell::GetWebContentsModalDialogHost() { + return (web_modal::WebContentsModalDialogHost*)window(); +} + } // namespace content diff --git a/src/nw_shell.h b/src/nw_shell.h index b802945c41..9823f99e89 100644 --- a/src/nw_shell.h +++ b/src/nw_shell.h @@ -30,7 +30,7 @@ #include "content/public/browser/notification_observer.h" #include "content/public/browser/web_contents_delegate.h" #include "content/public/browser/web_contents_observer.h" -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) #include "components/web_modal/web_contents_modal_dialog_manager_delegate.h" #endif #include "ipc/ipc_channel.h" @@ -64,7 +64,7 @@ using base::FilePath; // 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, -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) public web_modal::WebContentsModalDialogManagerDelegate, #endif public content::WebContentsObserver, @@ -140,10 +140,10 @@ class Shell : public WebContentsDelegate, int id() const { return id_; } virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE; -#if defined(OS_WIN) +#if defined(OS_WIN) || defined(OS_LINUX) virtual void SetWebContentsBlocked(content::WebContents* web_contents, bool) OVERRIDE {} - virtual bool IsWebContentsVisible(content::WebContents* web_contents); - virtual web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost() OVERRIDE{ return (web_modal::WebContentsModalDialogHost*)window(); } + virtual bool IsWebContentsVisible(content::WebContents* web_contents) OVERRIDE; + virtual web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost() OVERRIDE; #endif protected: From bf0a6f22c09648d70fb7d57faed9c75ee28cc196 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 24 Oct 2014 00:02:09 +0800 Subject: [PATCH 229/492] guard handle scope in navigation Part of #2489 v8::HandleScope::CreateHandle() blink::ScopedPersistent<>::newLocal() blink::ScriptState::context() blink::WindowProxy::context() blink::toV8Context() blink::WebLocalFrameImpl::mainWorldScriptContext() nwapi::Dispatcher::willHandleNavigationPolicy() --- src/api/dispatcher.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/api/dispatcher.cc b/src/api/dispatcher.cc index 44ca98d2b5..9fa708394c 100644 --- a/src/api/dispatcher.cc +++ b/src/api/dispatcher.cc @@ -216,6 +216,7 @@ void Dispatcher::willHandleNavigationPolicy( return; v8::Isolate* isolate = v8::Isolate::GetCurrent(); + v8::HandleScope handleScope(isolate); v8::Handle id_val; if (web_view->mainFrame() && !web_view->mainFrame()->mainWorldScriptContext().IsEmpty()) From 29b67e826b52fac153e04548ef59e5431d61b4ea Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 24 Oct 2014 00:07:06 +0800 Subject: [PATCH 230/492] fix build error for Mac --- src/nw_shell.cc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 36267cc813..f4fee0a880 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -728,8 +728,10 @@ bool Shell::IsFullscreenForTabOrPending(const WebContents* web_contents) const { return window()->IsFullscreen(); } +#if defined(OS_WIN) || defined(OS_LINUX) web_modal::WebContentsModalDialogHost* Shell::GetWebContentsModalDialogHost() { return (web_modal::WebContentsModalDialogHost*)window(); } +#endif } // namespace content From 9b4645e890a671336a85668b3e902a2425058cee Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 24 Oct 2014 10:24:49 +0800 Subject: [PATCH 231/492] support commit id and expose it in version page and crash report --- nw.gypi | 52 +++++++++++++++++++ src/chrome_breakpad_client.cc | 17 ++---- src/renderer/shell_content_renderer_client.cc | 3 ++ src/resources/pages/nw_version.html | 1 + tools/commit_id.py | 43 +++++++++++++++ 5 files changed, 104 insertions(+), 12 deletions(-) create mode 100644 tools/commit_id.py diff --git a/nw.gypi b/nw.gypi index cb4ef3b38a..16408f0ce2 100644 --- a/nw.gypi +++ b/nw.gypi @@ -6,6 +6,12 @@ 'variables': { 'nw_product_name': 'node-webkit', 'mac_strip_release': 1, + 'nw_gen_path': '<(SHARED_INTERMEDIATE_DIR)/nw', + 'nw_id_script_base': 'commit_id.py', + 'nw_id_script': '<(nw_gen_path)/<(nw_id_script_base)', + 'nw_id_header_base': 'commit.h', + 'nw_id_header': '<(nw_gen_path)/id/<(nw_id_header_base)', + 'nw_use_commit_id%': ' @@ -266,19 +268,10 @@ void ChromeBreakpadClient::GetProductNameAndVersion(std::string* product_name, std::string* version) { DCHECK(product_name); DCHECK(version); -#if defined(OS_ANDROID) - *product_name = "Chrome_Android"; -#elif defined(OS_CHROMEOS) - *product_name = "Chrome_ChromeOS"; -#else // OS_LINUX -#if !defined(ADDRESS_SANITIZER) - *product_name = "Chrome_Linux"; -#else - *product_name = "Chrome_Linux_ASan"; -#endif -#endif - *version = NW_VERSION_STRING; + *product_name = "node-webkit"; + + *version = NW_VERSION_STRING " " NW_COMMIT_HASH; } base::FilePath ChromeBreakpadClient::GetReporterLogFilename() { diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index 8ac12de0ef..a97a9a476a 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -65,6 +65,8 @@ //#include "third_party/WebKit/Source/WebKit/chromium/public/platform/WebString.h" #include "content/common/dom_storage/dom_storage_map.h" +#include "id/commit.h" + using content::RenderView; using content::RenderViewImpl; using autofill::AutofillAgent; @@ -397,6 +399,7 @@ void ShellContentRendererClient::InstallNodeSymbols( // Save node-webkit version "process.versions['node-webkit'] = '" NW_VERSION_STRING "';" + "process.versions['nw-commit-id'] = '" NW_COMMIT_HASH "';" "process.versions['chromium'] = '" CHROME_VERSION "';" )); script->Run(); diff --git a/src/resources/pages/nw_version.html b/src/resources/pages/nw_version.html index 46a46268cf..fc8c74030a 100644 --- a/src/resources/pages/nw_version.html +++ b/src/resources/pages/nw_version.html @@ -7,5 +7,6 @@ node-webkit v
    node.js v
    Chromium
    + commit hash:
    diff --git a/tools/commit_id.py b/tools/commit_id.py new file mode 100644 index 0000000000..40aebce038 --- /dev/null +++ b/tools/commit_id.py @@ -0,0 +1,43 @@ +import subprocess as sp +import sys +import os + +# Usage: commit_id.py check (checks if git is present) +# Usage: commit_id.py gen (generates commit id) + +def grab_output(command, cwd): + return sp.Popen(command, stdout=sp.PIPE, shell=True, cwd=cwd).communicate()[0].strip() + +operation = sys.argv[1] +cwd = sys.argv[2] +repos = ['content/nw', '.', 'third_party/WebKit', 'v8', 'third_party/node', 'breakpad/src' ] + +if operation == 'check': + for repo in repos: + index_path = os.path.join(cwd, repo, '.git', 'index') + if not os.path.exists(index_path): + print("0") + sys.exit(0) + print("1") + sys.exit(0) + +output_file = sys.argv[3] +commit_id_size = 7 +final_hash = '' + +for repo in repos: + try: + repo_path = os.path.join(cwd, repo) + final_hash += grab_output('git rev-parse --short=%d HEAD' % commit_id_size, repo_path) + final_hash += '-' + except: + final_hash = 'invalid-hash' + break + +final_hash = final_hash.rstrip('-') +hfile = open(output_file, 'w') + +hfile.write('#define NW_COMMIT_HASH "%s"\n' % final_hash) +hfile.write('#define NW_COMMIT_HASH_SIZE %d\n' % len(final_hash)) + +hfile.close() From 140972bb41a43374b66cd5025645b8db08cea85d Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Sat, 25 Oct 2014 22:56:51 +0800 Subject: [PATCH 232/492] clean up shells on exit This will prevent the assertion in GpuProcessTransportFactory on renderer crash --- src/nw_shell.cc | 7 +++++++ src/nw_shell.h | 1 + src/shell_browser_main.cc | 2 ++ 3 files changed, 10 insertions(+) diff --git a/src/nw_shell.cc b/src/nw_shell.cc index f4fee0a880..61c88671cf 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -734,4 +734,11 @@ web_modal::WebContentsModalDialogHost* Shell::GetWebContentsModalDialogHost() { } #endif +void Shell::Cleanup() { + std::vector list = windows(); + for (size_t i = 0; i < list.size(); ++i) { + delete list[i]; + } +} + } // namespace content diff --git a/src/nw_shell.h b/src/nw_shell.h index 9823f99e89..d206e06704 100644 --- a/src/nw_shell.h +++ b/src/nw_shell.h @@ -97,6 +97,7 @@ class Shell : public WebContentsDelegate, // Returns the Shell object corresponding to the given RenderViewHost. static Shell* FromRenderViewHost(RenderViewHost* rvh); + static void Cleanup(); void LoadURL(const GURL& url); void GoBackOrForward(int offset); diff --git a/src/shell_browser_main.cc b/src/shell_browser_main.cc index e1735de934..58db9a0c0c 100644 --- a/src/shell_browser_main.cc +++ b/src/shell_browser_main.cc @@ -44,6 +44,8 @@ int ShellBrowserMain(const content::MainFunctionParams& parameters) { main_runner_->Run(); + content::Shell::Cleanup(); + main_runner_->Shutdown(); return content::Shell::exit_code(); From 4cedbd2f5219ba18f7f3519c48c7b7531122c0bc Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 26 Oct 2014 19:28:01 +0800 Subject: [PATCH 233/492] remove console logging of process_main --- src/renderer/shell_content_renderer_client.cc | 1 - 1 file changed, 1 deletion(-) diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index a97a9a476a..9107d67329 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -280,7 +280,6 @@ void ShellContentRendererClient::SetupNodeUtil( #else "process.mainModule.filename = decodeURIComponent(window.location.pathname);" #endif - "console.log('process.mainModule.filename: ' + process.mainModule.filename);" "if (window.location.href.indexOf('app://') === 0) {process.mainModule.filename = root + '/' + process.mainModule.filename}" "process.mainModule.paths = global.require('module')._nodeModulePaths(process.cwd());" "process.mainModule.loaded = true;" From 1a53ba442bec3260aa5707cd29465dfde4b7c0b4 Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 26 Oct 2014 19:28:32 +0800 Subject: [PATCH 234/492] nw headers: replace abs path in more files --- tools/make-nw-headers.sh | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/tools/make-nw-headers.sh b/tools/make-nw-headers.sh index 48944b3100..8d2a86ab12 100644 --- a/tools/make-nw-headers.sh +++ b/tools/make-nw-headers.sh @@ -10,8 +10,10 @@ rm -rf $tmpdir/node/deps/v8/test rm -rf $tmpdir/node/deps/v8/out rm -rf $tmpdir/node/deps/npm/node_modules -cat $tmpdir/node/src/node.h | sed -e 's|third_party/node/deps/uv/include/uv.h|uv.h|' > tmp_node.h && mv tmp_node.h $tmpdir/node/src/node.h +for h in env.h env-inl.h node.h; do +cat $tmpdir/node/src/$h | sed -e 's|third_party/node/deps/uv/include/uv.h|uv.h|' > tmp_$h && mv tmp_$h $tmpdir/node/src/$h +done pushd tmp -tar czf ../nw-headers-v0.6.1.tar.gz node +tar czf ../nw-headers-v0.11.0-rc1.tar.gz node popd From 9af4024062a15a41676808891dbd53195729e904 Mon Sep 17 00:00:00 2001 From: Roger Date: Sun, 26 Oct 2014 22:32:42 +0800 Subject: [PATCH 235/492] Revert "Append uncaughtException listener to process to avoid crash." This reverts commit 33f393e5d931ff3d995dfa29799c77106dc3db05. Conflicts: tests/automatic_tests/node-main/mocha_test.js --- tests/automatic_tests/app/index.html | 3 +- tests/automatic_tests/app/mocha_test.js | 13 +- .../calls_across_window/mocha_test.js | 1 + .../chromedriver2_server_test.py | 41 +- .../chromedriver2_server/mocha_test.js | 4 +- .../chromium-args/mocha_test.js | 54 +- tests/automatic_tests/cookies_api/index.html | 258 +- .../automatic_tests/cookies_api/mocha_test.js | 166 +- .../document_cookies/mocha_test.js | 110 +- .../loaded_event/mocha_test.js | 6 +- tests/automatic_tests/node-main/mocha_test.js | 15 +- .../automatic_tests/node-remote/mocha_test.js | 2 +- tests/automatic_tests/process/exit/index.html | 4 +- tests/automatic_tests/process/mocha_test.js | 36 +- .../reload_application/mocha_test.js | 2 + tests/automatic_tests/snapshot/mocha_test.js | 192 +- tests/automatic_tests/start_app/mocha_test.js | 13 +- tests/automatic_tests/start_app/script.js | 7 +- .../user-agent-app/mocha_test.js | 37 +- tests/automatic_tests/website/mocha_test.js | 25 +- tests/automatic_tests/window/index.html | 9 - tests/index.html | 46 +- tests/mocha/Readme.md | 172 - tests/mocha/bin/_mocha | 467 -- tests/mocha/bin/mocha | 51 - tests/mocha/images/error.png | Bin 412 -> 0 bytes tests/mocha/images/ok.png | Bin 388 -> 0 bytes tests/mocha/index.js | 4 - tests/mocha/lib/browser/debug.js | 5 - tests/mocha/lib/browser/diff.js | 354 - tests/mocha/lib/browser/events.js | 178 - tests/mocha/lib/browser/fs.js | 0 tests/mocha/lib/browser/path.js | 0 tests/mocha/lib/browser/progress.js | 125 - tests/mocha/lib/browser/tty.js | 13 - tests/mocha/lib/context.js | 69 - tests/mocha/lib/hook.js | 49 - tests/mocha/lib/interfaces/bdd.js | 137 - tests/mocha/lib/interfaces/exports.js | 60 - tests/mocha/lib/interfaces/index.js | 5 - tests/mocha/lib/interfaces/qunit.js | 122 - tests/mocha/lib/interfaces/tdd.js | 138 - tests/mocha/lib/mocha.js | 370 -- tests/mocha/lib/ms.js | 109 - tests/mocha/lib/reporters/base.js | 507 -- tests/mocha/lib/reporters/doc.js | 56 - tests/mocha/lib/reporters/dot.js | 62 - tests/mocha/lib/reporters/html-cov.js | 51 - tests/mocha/lib/reporters/html.js | 273 - tests/mocha/lib/reporters/index.js | 18 - tests/mocha/lib/reporters/json-cov.js | 153 - tests/mocha/lib/reporters/json-stream.js | 61 - tests/mocha/lib/reporters/json.js | 70 - tests/mocha/lib/reporters/landing.js | 97 - tests/mocha/lib/reporters/list.js | 64 - tests/mocha/lib/reporters/markdown.js | 91 - tests/mocha/lib/reporters/min.js | 38 - tests/mocha/lib/reporters/nyan.js | 260 - tests/mocha/lib/reporters/progress.js | 86 - tests/mocha/lib/reporters/spec.js | 83 - tests/mocha/lib/reporters/tap.js | 73 - .../lib/reporters/templates/coverage.jade | 50 - tests/mocha/lib/reporters/templates/menu.jade | 13 - .../mocha/lib/reporters/templates/script.html | 34 - .../mocha/lib/reporters/templates/style.html | 320 - tests/mocha/lib/reporters/xunit.js | 119 - tests/mocha/lib/runnable.js | 231 - tests/mocha/lib/runner.js | 661 -- tests/mocha/lib/suite.js | 320 - tests/mocha/lib/template.html | 18 - tests/mocha/lib/test.js | 32 - tests/mocha/lib/utils.js | 299 - tests/mocha/mocha.css | 270 - tests/mocha/mocha.js | 5848 ----------------- tests/mocha/node_modules/commander/History.md | 179 - tests/mocha/node_modules/commander/Readme.md | 195 - tests/mocha/node_modules/commander/index.js | 847 --- .../mocha/node_modules/commander/package.json | 38 - tests/mocha/node_modules/diff/README.md | 101 - tests/mocha/node_modules/diff/diff.js | 354 - tests/mocha/node_modules/diff/package.json | 51 - tests/mocha/node_modules/glob/.npmignore | 2 - tests/mocha/node_modules/glob/.travis.yml | 3 - tests/mocha/node_modules/glob/LICENSE | 27 - tests/mocha/node_modules/glob/README.md | 250 - tests/mocha/node_modules/glob/examples/g.js | 9 - .../node_modules/glob/examples/usr-local.js | 9 - tests/mocha/node_modules/glob/glob.js | 675 -- .../glob/node_modules/graceful-fs/.npmignore | 1 - .../glob/node_modules/graceful-fs/LICENSE | 27 - .../glob/node_modules/graceful-fs/README.md | 26 - .../node_modules/graceful-fs/graceful-fs.js | 160 - .../node_modules/graceful-fs/package.json | 49 - .../node_modules/graceful-fs/polyfills.js | 228 - .../node_modules/graceful-fs/test/open.js | 39 - .../graceful-fs/test/readdir-sort.js | 21 - .../glob/node_modules/inherits/LICENSE | 16 - .../glob/node_modules/inherits/README.md | 42 - .../glob/node_modules/inherits/inherits.js | 1 - .../node_modules/inherits/inherits_browser.js | 23 - .../glob/node_modules/inherits/package.json | 33 - .../glob/node_modules/inherits/test.js | 25 - .../glob/node_modules/minimatch/.npmignore | 1 - .../glob/node_modules/minimatch/LICENSE | 23 - .../glob/node_modules/minimatch/README.md | 218 - .../glob/node_modules/minimatch/minimatch.js | 1055 --- .../node_modules/lru-cache/.npmignore | 1 - .../node_modules/lru-cache/CONTRIBUTORS | 14 - .../minimatch/node_modules/lru-cache/LICENSE | 23 - .../node_modules/lru-cache/README.md | 97 - .../node_modules/lru-cache/lib/lru-cache.js | 252 - .../node_modules/lru-cache/package.json | 33 - .../node_modules/lru-cache/test/basic.js | 369 -- .../node_modules/lru-cache/test/foreach.js | 52 - .../lru-cache/test/memory-leak.js | 50 - .../minimatch/node_modules/sigmund/LICENSE | 27 - .../minimatch/node_modules/sigmund/README.md | 53 - .../minimatch/node_modules/sigmund/bench.js | 283 - .../node_modules/sigmund/package.json | 42 - .../minimatch/node_modules/sigmund/sigmund.js | 39 - .../node_modules/sigmund/test/basic.js | 24 - .../glob/node_modules/minimatch/package.json | 40 - .../glob/node_modules/minimatch/test/basic.js | 399 -- .../minimatch/test/brace-expand.js | 33 - .../node_modules/minimatch/test/caching.js | 14 - .../node_modules/minimatch/test/defaults.js | 274 - .../test/extglob-ending-with-state-char.js | 8 - tests/mocha/node_modules/glob/package.json | 40 - .../mocha/node_modules/glob/test/00-setup.js | 176 - .../node_modules/glob/test/bash-comparison.js | 63 - .../node_modules/glob/test/bash-results.json | 350 - .../mocha/node_modules/glob/test/cwd-test.js | 55 - .../node_modules/glob/test/globstar-match.js | 19 - tests/mocha/node_modules/glob/test/mark.js | 74 - .../node_modules/glob/test/nocase-nomagic.js | 113 - .../node_modules/glob/test/pause-resume.js | 73 - .../node_modules/glob/test/root-nomount.js | 39 - tests/mocha/node_modules/glob/test/root.js | 46 - tests/mocha/node_modules/glob/test/stat.js | 32 - .../node_modules/glob/test/zz-cleanup.js | 11 - tests/mocha/node_modules/growl/History.md | 63 - tests/mocha/node_modules/growl/Readme.md | 99 - tests/mocha/node_modules/growl/lib/growl.js | 234 - tests/mocha/node_modules/growl/package.json | 14 - tests/mocha/node_modules/growl/test.js | 20 - tests/mocha/node_modules/mkdirp/.npmignore | 2 - tests/mocha/node_modules/mkdirp/.travis.yml | 5 - tests/mocha/node_modules/mkdirp/LICENSE | 21 - .../mocha/node_modules/mkdirp/examples/pow.js | 6 - tests/mocha/node_modules/mkdirp/index.js | 82 - tests/mocha/node_modules/mkdirp/package.json | 34 - .../mocha/node_modules/mkdirp/readme.markdown | 63 - tests/mocha/node_modules/mkdirp/test/chmod.js | 38 - .../mocha/node_modules/mkdirp/test/clobber.js | 37 - .../mocha/node_modules/mkdirp/test/mkdirp.js | 28 - tests/mocha/node_modules/mkdirp/test/perm.js | 32 - .../node_modules/mkdirp/test/perm_sync.js | 39 - tests/mocha/node_modules/mkdirp/test/race.js | 41 - tests/mocha/node_modules/mkdirp/test/rel.js | 32 - .../mocha/node_modules/mkdirp/test/return.js | 25 - .../node_modules/mkdirp/test/return_sync.js | 24 - tests/mocha/node_modules/mkdirp/test/root.js | 18 - tests/mocha/node_modules/mkdirp/test/sync.js | 32 - tests/mocha/node_modules/mkdirp/test/umask.js | 28 - .../node_modules/mkdirp/test/umask_sync.js | 32 - tests/mocha/package.json | 60 - tests/package.json | 1 + tests/server/cookie_server.js | 71 - tests/server/server.js | 3 - 169 files changed, 462 insertions(+), 22398 deletions(-) delete mode 100644 tests/mocha/Readme.md delete mode 100755 tests/mocha/bin/_mocha delete mode 100755 tests/mocha/bin/mocha delete mode 100644 tests/mocha/images/error.png delete mode 100644 tests/mocha/images/ok.png delete mode 100644 tests/mocha/index.js delete mode 100644 tests/mocha/lib/browser/debug.js delete mode 100644 tests/mocha/lib/browser/diff.js delete mode 100644 tests/mocha/lib/browser/events.js delete mode 100644 tests/mocha/lib/browser/fs.js delete mode 100644 tests/mocha/lib/browser/path.js delete mode 100644 tests/mocha/lib/browser/progress.js delete mode 100644 tests/mocha/lib/browser/tty.js delete mode 100644 tests/mocha/lib/context.js delete mode 100644 tests/mocha/lib/hook.js delete mode 100644 tests/mocha/lib/interfaces/bdd.js delete mode 100644 tests/mocha/lib/interfaces/exports.js delete mode 100644 tests/mocha/lib/interfaces/index.js delete mode 100644 tests/mocha/lib/interfaces/qunit.js delete mode 100644 tests/mocha/lib/interfaces/tdd.js delete mode 100644 tests/mocha/lib/mocha.js delete mode 100644 tests/mocha/lib/ms.js delete mode 100644 tests/mocha/lib/reporters/base.js delete mode 100644 tests/mocha/lib/reporters/doc.js delete mode 100644 tests/mocha/lib/reporters/dot.js delete mode 100644 tests/mocha/lib/reporters/html-cov.js delete mode 100644 tests/mocha/lib/reporters/html.js delete mode 100644 tests/mocha/lib/reporters/index.js delete mode 100644 tests/mocha/lib/reporters/json-cov.js delete mode 100644 tests/mocha/lib/reporters/json-stream.js delete mode 100644 tests/mocha/lib/reporters/json.js delete mode 100644 tests/mocha/lib/reporters/landing.js delete mode 100644 tests/mocha/lib/reporters/list.js delete mode 100644 tests/mocha/lib/reporters/markdown.js delete mode 100644 tests/mocha/lib/reporters/min.js delete mode 100644 tests/mocha/lib/reporters/nyan.js delete mode 100644 tests/mocha/lib/reporters/progress.js delete mode 100644 tests/mocha/lib/reporters/spec.js delete mode 100644 tests/mocha/lib/reporters/tap.js delete mode 100644 tests/mocha/lib/reporters/templates/coverage.jade delete mode 100644 tests/mocha/lib/reporters/templates/menu.jade delete mode 100644 tests/mocha/lib/reporters/templates/script.html delete mode 100644 tests/mocha/lib/reporters/templates/style.html delete mode 100644 tests/mocha/lib/reporters/xunit.js delete mode 100644 tests/mocha/lib/runnable.js delete mode 100644 tests/mocha/lib/runner.js delete mode 100644 tests/mocha/lib/suite.js delete mode 100644 tests/mocha/lib/template.html delete mode 100644 tests/mocha/lib/test.js delete mode 100644 tests/mocha/lib/utils.js delete mode 100644 tests/mocha/mocha.css delete mode 100644 tests/mocha/mocha.js delete mode 100644 tests/mocha/node_modules/commander/History.md delete mode 100644 tests/mocha/node_modules/commander/Readme.md delete mode 100644 tests/mocha/node_modules/commander/index.js delete mode 100644 tests/mocha/node_modules/commander/package.json delete mode 100644 tests/mocha/node_modules/diff/README.md delete mode 100644 tests/mocha/node_modules/diff/diff.js delete mode 100644 tests/mocha/node_modules/diff/package.json delete mode 100644 tests/mocha/node_modules/glob/.npmignore delete mode 100644 tests/mocha/node_modules/glob/.travis.yml delete mode 100644 tests/mocha/node_modules/glob/LICENSE delete mode 100644 tests/mocha/node_modules/glob/README.md delete mode 100644 tests/mocha/node_modules/glob/examples/g.js delete mode 100644 tests/mocha/node_modules/glob/examples/usr-local.js delete mode 100644 tests/mocha/node_modules/glob/glob.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/.npmignore delete mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/LICENSE delete mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/README.md delete mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/graceful-fs.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/package.json delete mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/polyfills.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/test/open.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/graceful-fs/test/readdir-sort.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/LICENSE delete mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/README.md delete mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/inherits.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/inherits_browser.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/package.json delete mode 100644 tests/mocha/node_modules/glob/node_modules/inherits/test.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/.npmignore delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/LICENSE delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/README.md delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/minimatch.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/.npmignore delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/CONTRIBUTORS delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/LICENSE delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/README.md delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/package.json delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/basic.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/foreach.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/LICENSE delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/README.md delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/bench.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/package.json delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/sigmund.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/test/basic.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/package.json delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/test/basic.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/test/brace-expand.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/test/caching.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/test/defaults.js delete mode 100644 tests/mocha/node_modules/glob/node_modules/minimatch/test/extglob-ending-with-state-char.js delete mode 100644 tests/mocha/node_modules/glob/package.json delete mode 100644 tests/mocha/node_modules/glob/test/00-setup.js delete mode 100644 tests/mocha/node_modules/glob/test/bash-comparison.js delete mode 100644 tests/mocha/node_modules/glob/test/bash-results.json delete mode 100644 tests/mocha/node_modules/glob/test/cwd-test.js delete mode 100644 tests/mocha/node_modules/glob/test/globstar-match.js delete mode 100644 tests/mocha/node_modules/glob/test/mark.js delete mode 100644 tests/mocha/node_modules/glob/test/nocase-nomagic.js delete mode 100644 tests/mocha/node_modules/glob/test/pause-resume.js delete mode 100644 tests/mocha/node_modules/glob/test/root-nomount.js delete mode 100644 tests/mocha/node_modules/glob/test/root.js delete mode 100644 tests/mocha/node_modules/glob/test/stat.js delete mode 100644 tests/mocha/node_modules/glob/test/zz-cleanup.js delete mode 100644 tests/mocha/node_modules/growl/History.md delete mode 100644 tests/mocha/node_modules/growl/Readme.md delete mode 100644 tests/mocha/node_modules/growl/lib/growl.js delete mode 100644 tests/mocha/node_modules/growl/package.json delete mode 100644 tests/mocha/node_modules/growl/test.js delete mode 100644 tests/mocha/node_modules/mkdirp/.npmignore delete mode 100644 tests/mocha/node_modules/mkdirp/.travis.yml delete mode 100644 tests/mocha/node_modules/mkdirp/LICENSE delete mode 100644 tests/mocha/node_modules/mkdirp/examples/pow.js delete mode 100644 tests/mocha/node_modules/mkdirp/index.js delete mode 100644 tests/mocha/node_modules/mkdirp/package.json delete mode 100644 tests/mocha/node_modules/mkdirp/readme.markdown delete mode 100644 tests/mocha/node_modules/mkdirp/test/chmod.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/clobber.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/mkdirp.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/perm.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/perm_sync.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/race.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/rel.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/return.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/return_sync.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/root.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/sync.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/umask.js delete mode 100644 tests/mocha/node_modules/mkdirp/test/umask_sync.js delete mode 100644 tests/mocha/package.json delete mode 100644 tests/server/cookie_server.js diff --git a/tests/automatic_tests/app/index.html b/tests/automatic_tests/app/index.html index 65a091fbbf..f12e02f867 100644 --- a/tests/automatic_tests/app/index.html +++ b/tests/automatic_tests/app/index.html @@ -21,11 +21,10 @@ if (self.name == 2) gui.App.clearCache(); else if (self.name == 3) { - gui.App.clearCache(); var client = require('../../nw_test_app').createClient({ argv: gui.App.argv, data: {} - }); + }); } location.reload(); } diff --git a/tests/automatic_tests/app/mocha_test.js b/tests/automatic_tests/app/mocha_test.js index 3f32b62f9f..6ae0862b28 100644 --- a/tests/automatic_tests/app/mocha_test.js +++ b/tests/automatic_tests/app/mocha_test.js @@ -37,20 +37,11 @@ describe('gui.App', function() { describe('clearCache()', function(done) { it('should clear the HTTP cache in memory and the one on disk', function() { var res_save = global.local_server.res_save; - //request 4 time - //1. 200 request image from remote server - //2. 304 load image from cache - //3. 304 load image from cache, but we call clearCache API this time - //4. 200 clear cache, request image from remote server - assert.equal(res_save.length,4); - assert.equal(res_save[0].status, 200); - assert.equal(res_save[0].pathname, 'img.jpg'); + assert.equal(res_save[1].status, 304); assert.equal(res_save[1].pathname, 'img.jpg'); - assert.equal(res_save[2].status, 304); + assert.equal(res_save[2].status, 200); assert.equal(res_save[2].pathname, 'img.jpg'); - assert.equal(res_save[3].status, 200); - assert.equal(res_save[3].pathname, 'img.jpg'); }); }); }) diff --git a/tests/automatic_tests/calls_across_window/mocha_test.js b/tests/automatic_tests/calls_across_window/mocha_test.js index ceaa1d3864..3ecb13696d 100644 --- a/tests/automatic_tests/calls_across_window/mocha_test.js +++ b/tests/automatic_tests/calls_across_window/mocha_test.js @@ -7,6 +7,7 @@ var cb; describe('AppTest', function(){ describe('call across window', function(){ + var app; var exec_argv; var socket; diff --git a/tests/automatic_tests/chromedriver2_server/chromedriver2_server_test.py b/tests/automatic_tests/chromedriver2_server/chromedriver2_server_test.py index 1d1fac779e..52eeb0be29 100644 --- a/tests/automatic_tests/chromedriver2_server/chromedriver2_server_test.py +++ b/tests/automatic_tests/chromedriver2_server/chromedriver2_server_test.py @@ -2,35 +2,11 @@ import time import os from selenium import webdriver -from platform import platform #path = os.getcwd(); #path = os.path.join(path, 'tmp-nw', 'chromedriver2_server'); -path = os.path.join(os.path.abspath(__file__),"../../../tmp-nw/chromedriver2_server") -path = os.path.abspath(path) +path = '/home/owen-cloud/Desktop/kevin/node-webkit/tests/tmp-nw/chromedriver2_server'; -def kill_process_tree(pid): - machine_type = platform() - if "Linux" in machine_type or "Darwin" in machine_type: - import psutil - parent = psutil.Process(spid) - for child in parent.get_children(recursive=True): - child.kill() - parent.kill() - return - elif 'Windows' in machine_type: - import subprocess - dev_null = open(os.devnull,"wb") - subprocess.Popen(['taskkill', '/F', '/T', '/PID', str(pid)],stdout=dev_null,stderr=dev_null) - return - else: - # print "Unknow OS type" - return - - - - -driver = None try: driver = webdriver.Chrome(path); driver.get('http://www.google.com'); @@ -40,18 +16,11 @@ def kill_process_tree(pid): search_box = driver.find_element_by_name('q') search_box.send_keys('ChromeDriver') search_box.submit() - time.sleep(5); - title = str(driver.title[0:12]) - assert title == 'ChromeDriver' + time.sleep(5) # Let the user actually see something! + assert driver.title[0:12] == 'ChromeDriver' + driver.quit() except: + driver.quit(); traceback.print_exc() else: print 'pass' - - -# Now driver.quit() will not quit normal, it is selenium's bug -# we kill process recursive, if the API works, uncomment next line and delete last 2 lines -# driver.quit() -spid = driver.service.process.pid -kill_process_tree(spid) -exit(0) diff --git a/tests/automatic_tests/chromedriver2_server/mocha_test.js b/tests/automatic_tests/chromedriver2_server/mocha_test.js index ed666c6cfe..f1a22bcfde 100644 --- a/tests/automatic_tests/chromedriver2_server/mocha_test.js +++ b/tests/automatic_tests/chromedriver2_server/mocha_test.js @@ -47,9 +47,7 @@ describe('chromedriver2_server', function() { done("chromedrier2_server does not exist"); else { assert.equal(result[0], null); - if (result[1] != 'pass\n' && result[1] != 'pass\r\n'){ - done(result[1]); - } + assert.equal(result[1], 'pass\n'); assert.equal(result[2], ''); done(); } diff --git a/tests/automatic_tests/chromium-args/mocha_test.js b/tests/automatic_tests/chromium-args/mocha_test.js index 8a6481ca1e..c0bc77a0a0 100644 --- a/tests/automatic_tests/chromium-args/mocha_test.js +++ b/tests/automatic_tests/chromium-args/mocha_test.js @@ -31,34 +31,34 @@ describe('chromium-args', function() { }); }); - // describe('--app=url', function() { - // var result2 = false; - // before(function(done) { - // this.timeout(0); - // fs_extra.copy(path.join(app_path, 'package2.json'), path.join(app_path, 'package.json'), function (err) { - // if (err) { - // throw err; - // } - // var child = app_test.createChildProcess({ - // execPath: exec_path, - // appPath: app_path, - // end: function(data, app) { - // result2 = data; - // app.kill(); - // done() - // } - // }); - // }); - // }); + describe('--app=url', function() { + var result2 = false; + before(function(done) { + this.timeout(0); + fs_extra.copy(path.join(app_path, 'package2.json'), path.join(app_path, 'package.json'), function (err) { + if (err) { + throw err; + } + var child = app_test.createChildProcess({ + execPath: exec_path, + appPath: app_path, + end: function(data, app) { + result2 = data; + app.kill(); + done() + } + }); + }); + }); - // it('website should be the url', function() { - // assert.equal(result2, true); - // }); + it('website should be the url', function() { + assert.equal(result2, true); + }); - // after(function() { - // fs.unlink(path.join(app_path, 'package.json'), function(err) {if(err && err.code !== 'ENOENT') throw err}); - // fs.unlink(path.join(app_path, 'hi'), function(err) {if(err && err.code !== 'ENOENT') throw err}); - // }); - // }); + after(function() { + fs.unlink(path.join(app_path, 'package.json'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + fs.unlink(path.join(app_path, 'hi'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + }); + }); }); diff --git a/tests/automatic_tests/cookies_api/index.html b/tests/automatic_tests/cookies_api/index.html index 08a3dd72ae..10f426bfc4 100644 --- a/tests/automatic_tests/cookies_api/index.html +++ b/tests/automatic_tests/cookies_api/index.html @@ -1,145 +1,129 @@ + + TEST CASE FOR COOKIES API + + +

    Hello World!

    + We are using node.js + - - - + + + diff --git a/tests/automatic_tests/cookies_api/mocha_test.js b/tests/automatic_tests/cookies_api/mocha_test.js index c0f75be3ee..4f662d15e3 100644 --- a/tests/automatic_tests/cookies_api/mocha_test.js +++ b/tests/automatic_tests/cookies_api/mocha_test.js @@ -4,99 +4,99 @@ var assert = require('assert'); var results; var changed; describe('Window.cookies', function() { + describe("get, getAll", function() { - before(function(done) { - this.timeout(0); - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'cookies_api'), - args: [1], - end: function(data, app) { - results = data; - app.kill(); - done(); - } - }); - }); - it('should get cookies', function(done) { - assert.equal(results[0], true); - assert.equal(results[1], true); - done(); - }) + before(function(done) { + this.timeout(0); + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'cookies_api'), + args: [1], + end: function(data, app) { + results = data; + app.kill(); + console.log("1"); + done(); + } + }); + }); + it('should get cookies', function() { + assert.equal(results[0], true); + assert.equal(results[1], true); + }) }) describe("set", function() { - describe("set lang en", function() { - before(function(done) { - this.timeout(0); - var first = false; - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'cookies_api'), - args: [2], - end: function(data, app) { - results = data; - changed = results[1]; - app.kill(); - done(); - } - }); - }); - it('should get cookies', function(done) { - assert.equal(results[0], true); - done(); - }) - }); + describe("set lang en", function() { + before(function(done) { + this.timeout(0); + var first = false; + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'cookies_api'), + args: [2], + end: function(data, app) { + results = data; + changed = results[1]; + app.kill(); + console.log("2"); + done(); + } + }); + }); + it('should get cookies', function() { + assert.equal(results[0], true); + }) + }); - describe("set lang zh", function() { - before(function(done) { - this.timeout(0); - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'cookies_api'), - args: [3], - end: function(data, app) { - results = data; - done(); - app.kill(); - } - }); - }); + describe("set lang zh", function() { + before(function(done) { + this.timeout(0); + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'cookies_api'), + args: [3], + end: function(data, app) { + console.log("3"); + results = data; + done(); + app.kill(); + } + }); + }); - it('should get cookies', function(done) { - assert.equal(results[0], true); - done(); - }) - }); + it('should get cookies', function() { + assert.equal(results[0], true); + }) + }); }); - + describe('remove', function() { - before(function(done) { - this.timeout(0); - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'cookies_api'), - args: [4], - end: function(data, app) { - results = data; - changed = results[0]; - app.kill(); - done(); - } - }); - }); + before(function(done) { + this.timeout(0); + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'cookies_api'), + args: [4], + end: function(data, app) { + console.log("4"); + results = data; + app.kill(); + done(); + } + }); + }); - it('should remove lang', function(done) { - assert.equal(results[1], false); - done(); - }); + it('should remove lang', function() { + assert.equal(results[1], false); + }); }); - + describe('onChanged', function() { - it('should be called when changed', function(done) { - assert.equal(changed, true); - done(); - }) + it('should be called when changed', function() { + assert.equal(changed, true); + }) }); -}); \ No newline at end of file +}); + diff --git a/tests/automatic_tests/document_cookies/mocha_test.js b/tests/automatic_tests/document_cookies/mocha_test.js index bed1986203..c06b748823 100644 --- a/tests/automatic_tests/document_cookies/mocha_test.js +++ b/tests/automatic_tests/document_cookies/mocha_test.js @@ -4,70 +4,60 @@ var assert = require('assert'); var gui = require('nw.gui'); var results = new Array(); describe('document.cookies', function() { -//this case could be very slow on OS X -//leave child process enough time to finish its job - this.timeout(10000); - describe('http', function() { - before(function(done) { - this.timeout(0); - var url = "http://127.0.0.1:8123/document_cookies.html"; - var win = gui.Window.open(url); - win.on("loaded", function() { - results.push(win.window.msg.textContent); - done(); - win.window.close(); - }); - }); - it('should be set', function() { - assert.equal(results[0], '123'); - }); + describe('http', function() { + before(function(done) { + this.timeout(0); + var url = "http://127.0.0.1:8123/document_cookies.html"; + var win = gui.Window.open(url); + + setTimeout(function() { + results.push(win.window.msg.textContent); + done(); + win.window.close(); + }, 1000); + }); + it('should be set', function() { + assert.equal(results[0], '123'); }); + }); - describe('file', function() { - before(function(done) { - this.timeout(0); - var crontab = undefined; - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'document_cookies', 'file'), - end: function(data, app) { - if (crontab !== undefined){ - clearTimeout(crontab); - } - results.push(data); - app.kill(); - done(); - } - }); - crontab = setTimeout(done, 10000); - }); - it('should be set', function() { - assert.equal(results[1], '123'); - }); + describe('file', function() { + before(function(done) { + this.timeout(0); + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'document_cookies', 'file'), + end: function(data, app) { + results.push(data); + app.kill(); + done(); + } + }); + setTimeout(done, 3000); }); + it ('should be set', function() { + assert.equal(results[1], '123'); + }); + }); - describe('app', function() { - before(function(done) { - this.timeout(0); - var crontab = undefined; - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'document_cookies', 'app'), - end: function(data, app) { - if (crontab !== undefined){ - clearTimeout(crontab); - } - results.push(data); - app.kill(); - done(); - } - }); - crontab = setTimeout(done, 10000); - }); - it('should be set', function() { - assert.equal(results[2], '123'); - }); + describe('app', function() { + before(function(done) { + this.timeout(0); + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'document_cookies', 'app'), + end: function(data, app) { + results.push(data); + app.kill(); + done(); + } + }); + setTimeout(done, 3000); + }); + it ('should be set', function() { + assert.equal(results[2], '123'); }); + }); -}); \ No newline at end of file +}); diff --git a/tests/automatic_tests/loaded_event/mocha_test.js b/tests/automatic_tests/loaded_event/mocha_test.js index b4a9d6f52a..ec416b4b38 100644 --- a/tests/automatic_tests/loaded_event/mocha_test.js +++ b/tests/automatic_tests/loaded_event/mocha_test.js @@ -8,15 +8,11 @@ describe('loaded event', function() { function(done) { this.timeout(0); var result = false; - var crontab = undefined; var child = app_test.createChildProcess({ execPath: process.execPath, appPath: path.join(global.tests_dir, 'loaded_event'), end: function(data, app) { - if (crontab !== undefined){ - clearTimeout(crontab); - } result = true; done(); app.kill(); @@ -24,7 +20,7 @@ describe('loaded event', function() { }); - crontab = setTimeout(function(){ + setTimeout(function(){ if (!result) { child.close(); //child.app.kill(); diff --git a/tests/automatic_tests/node-main/mocha_test.js b/tests/automatic_tests/node-main/mocha_test.js index 101d0daded..dacc98477e 100644 --- a/tests/automatic_tests/node-main/mocha_test.js +++ b/tests/automatic_tests/node-main/mocha_test.js @@ -5,29 +5,26 @@ var assert = require('assert'); describe('node-main', function() { describe('create http server in node-main', function() { it('nw should not close by itself after show devtool', - function(done) { + function(done) { this.timeout(0); var result = false; - var crontab = undefined; - var child = app_test.createChildProcess({ execPath: process.execPath, appPath: path.join(global.tests_dir, - 'show_devtool_after_http_server_created_in_node_main'), + 'show_devtool_after_http_server_created_in_node_main'), end: function(data, app) { - clearTimeout(crontab); app.kill(); if (data.success) { done(); } else { done('erro'); - } + } result = true; } }); - crontab = setTimeout(function() { + setTimeout(function(){ if (!result) { done('nw close by itself') } @@ -38,7 +35,7 @@ describe('node-main', function() { }); describe('call require() in app', function() { - it('nw should can require modules', function(done) { + it('nw should can require modules', function(done){ this.timeout(0); var child = app_test.createChildProcess({ @@ -50,7 +47,7 @@ describe('node-main', function() { done(); } else { done(data.error); - } + } } }); }) diff --git a/tests/automatic_tests/node-remote/mocha_test.js b/tests/automatic_tests/node-remote/mocha_test.js index 56672bfccc..737c129899 100644 --- a/tests/automatic_tests/node-remote/mocha_test.js +++ b/tests/automatic_tests/node-remote/mocha_test.js @@ -62,7 +62,7 @@ describe('node-remote', function() { } else { done(); } - socket.end(); + }); socket.write('8124'); }) diff --git a/tests/automatic_tests/process/exit/index.html b/tests/automatic_tests/process/exit/index.html index b33afd4e6d..15aed33954 100644 --- a/tests/automatic_tests/process/exit/index.html +++ b/tests/automatic_tests/process/exit/index.html @@ -11,10 +11,8 @@ fs.openSync('a.txt', 'w'); }); - - process.exit(); - // gui.Window.get().close(true); + gui.Window.get().close(true); sdew diff --git a/tests/automatic_tests/process/mocha_test.js b/tests/automatic_tests/process/mocha_test.js index 3fb3d72140..cc0b6b8c4c 100644 --- a/tests/automatic_tests/process/mocha_test.js +++ b/tests/automatic_tests/process/mocha_test.js @@ -4,33 +4,29 @@ var fs = require('fs-extra'); describe('process', function() { - describe('exit', function() { + describe('exit', function(){ it('event process.exit should be fired after calling win.close(true)', function(done) { - var crontab = undefined; + + var child = app_test.createChildProcess({ execPath: process.execPath, appPath: path.join(global.tests_dir, 'process', 'exit'), - no_connect: true, + no_connect: true }); - child.app.on('exit',function(){ - fs.exists(path.join(global.tests_dir, 'process', 'exit', 'a.txt'), function(exists) { - if (crontab){ - clearTimeout(crontab); - } - if (exists) { - fs.unlink(path.join(global.tests_dir, 'process', 'exit', 'a.txt'), done); - } else { - done('the event `exit` does not been called.'); - } - }); - }); + setTimeout(function() { + fs.exists(path.join(global.tests_dir, 'process', 'exit', 'a.txt'), function (exists) { + if (exists) { + fs.unlink(path.join(global.tests_dir, 'process', 'exit', 'a.txt'), done); + } else { + done('the event `exit` does not been called.'); + } + }); + + }, 1500); + - crontab = setTimeout(function() { - console.log("CHILD PROCESS FAIL TO EXIT"); - done('the event `exit` does not been called.'); - }, 5000); }) }) -}) \ No newline at end of file +}) diff --git a/tests/automatic_tests/reload_application/mocha_test.js b/tests/automatic_tests/reload_application/mocha_test.js index 80c945498d..f41181b8ab 100644 --- a/tests/automatic_tests/reload_application/mocha_test.js +++ b/tests/automatic_tests/reload_application/mocha_test.js @@ -8,6 +8,8 @@ var cb; describe('AppTest', function(){ describe('reload app (long-to-run)', function(){ + + var exec_argv = [path.join(global.tests_dir, 'reload_application'), '--port', global.port, diff --git a/tests/automatic_tests/snapshot/mocha_test.js b/tests/automatic_tests/snapshot/mocha_test.js index f60084d184..5a9e5eac6c 100644 --- a/tests/automatic_tests/snapshot/mocha_test.js +++ b/tests/automatic_tests/snapshot/mocha_test.js @@ -7,116 +7,98 @@ var snapshotPath; describe('snapshot', function() { - describe('demo should work fine', function() { - before(function(done) { - var snapshotExec; - if (os.platform() == 'darwin') { - snapshotExec = '../../../../../../nwsnapshot'; + describe('demo should work fine', function() { + before(function(done) { + var snapshotExec; + if (os.platform() == 'darwin') { + snapshotExec = '../../../../../../nwsnapshot'; + } + if (os.platform() == 'linux') { + snapshotExec = 'nwsnapshot'; + } + if (os.platform() == 'win32') { + snapshotExec = 'nwsnapshot.exe'; + } + + snapshotPath = path.join(process.execPath, '..', snapshotExec); + console.log("snapshotPath: " + snapshotPath); + + cp.execFile(snapshotPath, + ['--extra_code', 'mytest.js', 'mytest.bin'], + {cwd:'./' + global.tests_dir + '/snapshot/'}, + function (error, stdout, stderr) { + done(); } - if (os.platform() == 'linux') { - snapshotExec = 'nwsnapshot'; - } - if (os.platform() == 'win32') { - snapshotExec = 'nwsnapshot.exe'; - } - - snapshotPath = path.join(process.execPath, '..', snapshotExec); - console.log("snapshotPath: " + snapshotPath); - - cp.execFile(snapshotPath, ['--extra_code', 'mytest.js', 'mytest.bin'], { - cwd: './' + global.tests_dir + '/snapshot/' - }, - function(error, stdout, stderr) { - done(); - } - - ); - }) - - after(function() { - fs.unlink(path.join(global.tests_dir, 'snapshot', 'mytest.bin'), function(err) { - if (err && err.code !== 'ENOENT') throw err - }); - fs.unlink(path.join(global.tests_dir, 'snapshot', 'v8.log'), function(err) { - if (err && err.code !== 'ENOENT') throw err - }); - }) - it('the native code could be exectuted', - function(done) { - this.timeout(0); - var result = false; - - var checkBinExists = function() { - var binPath = path.join(global.tests_dir, 'snapshot', 'mytest.bin'); - console.log(binPath); - if (fs.existsSync(binPath) == false) { - setTimeout(checkBinExists, 500); - } else { - var child = app_test.createChildProcess({ - execPath: process.execPath, - appPath: path.join(global.tests_dir, 'snapshot'), - end: function(data, app) { - done(); - app.kill(); - result = true; - } - }); - - setTimeout(function() { - if (!result) { - done('the native code does not been executed'); - child.close(); - //child.removeConnection(); - //child.app.kill(); - } - }, 10000); - //child.app.stderr.on('data', function(d){ console.log ('app' + d);}); - } - }; - - checkBinExists(); - }) + ); }) - describe('1266-snapshot-crash-start', function() { - before(function(done) { - cp.execFile(snapshotPath, ['--extra_code', 'file_to_snapshot_to_app.bin.js', 'app.bin'], { - cwd: './' + global.tests_dir + '/snapshot/1266-snapshot-crash-start/' - }, - function(error, stdout, stderr) { - done(); - } - - ); - }) - - after(function() { - fs.unlink(path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start', 'app.bin'), function(err) { - if (err && err.code !== 'ENOENT') throw err - }); - fs.unlink(path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start', 'v8.log'), function(err) { - if (err && err.code !== 'ENOENT') throw err - }); - fs.unlink(path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start', 'tmp'), function(err) { - if (err && err.code !== 'ENOENT') throw err - }); - }) + after(function() { + fs.unlink(path.join(global.tests_dir, 'snapshot', 'mytest.bin'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + fs.unlink(path.join(global.tests_dir, 'snapshot', 'v8.log'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + }) - it('another demo should close nomally', function(done) { - this.timeout(0); - var ppath = process.execPath + " " + path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start'); - cp.exec(ppath, function(err, stdout, stderr) {}); - setTimeout(function() { - fs.exists(path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start', 'tmp'), function(exists) { - if (exists) - done(); - else - done('another demo fails'); - }); - }, 3000); + it('the native code could be exectuted', + function(done) { + this.timeout(0); + var result = false; + + var child = app_test.createChildProcess({ + execPath: process.execPath, + appPath: path.join(global.tests_dir, 'snapshot'), + end: function(data, app) { + done(); + app.kill(); + result = true; + } + }); + + setTimeout(function(){ + if (!result) { + done('the native code does not been executed'); + child.close(); + //child.removeConnection(); + //child.app.kill(); + } + }, 3000); + //child.app.stderr.on('data', function(d){ console.log ('app' + d);}); + + }) + }) + + describe('1266-snapshot-crash-start', function() { + before(function(done) { + cp.execFile(snapshotPath, + ['--extra_code', 'file_to_snapshot_to_app.bin.js', 'app.bin'], + {cwd:'./' + global.tests_dir + '/snapshot/1266-snapshot-crash-start/'}, + function (error, stdout, stderr) { + done(); + } + + ); + }) + + after(function() { + fs.unlink(path.join(global.tests_dir, 'snapshot','1266-snapshot-crash-start', 'app.bin'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + fs.unlink(path.join(global.tests_dir, 'snapshot','1266-snapshot-crash-start', 'v8.log'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + fs.unlink(path.join(global.tests_dir, 'snapshot','1266-snapshot-crash-start','tmp'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + }) + + it('another demo should close nomally', function(done) { + this.timeout(0); + var ppath = process.execPath + " " + path.join(global.tests_dir, 'snapshot', '1266-snapshot-crash-start'); + cp.exec(ppath, function(err, stdout, stderr) { + }); + setTimeout(function(){ + fs.exists(path.join(global.tests_dir, 'snapshot','1266-snapshot-crash-start', 'tmp'), function(exists) { + if (exists) + done(); + else + done('another demo fails'); }); - }); + }, 3000); + }); + }); -}) \ No newline at end of file +}) diff --git a/tests/automatic_tests/start_app/mocha_test.js b/tests/automatic_tests/start_app/mocha_test.js index 2735c5b4c3..6afa1b2fc7 100644 --- a/tests/automatic_tests/start_app/mocha_test.js +++ b/tests/automatic_tests/start_app/mocha_test.js @@ -12,7 +12,9 @@ var execPath = func.getExecPath(); describe('Startup', function() { describe('different method of starting app (long-to-run)', function() { var temp_root = 'tmp-nw'; + before(function(done){ + this.timeout(10000); func.copyExecFiles(function() { func.copySourceFiles(); func.zipSourceFiles(function() { @@ -20,16 +22,15 @@ describe('different method of starting app (long-to-run)', function() { done(); }); }); - setTimeout(function(){ - done("ERROR") - },10000); }) after(function() { - fs.removeSync('tmp-nw', function (er) { - if (er) throw er; - }) + setTimeout(function() { + fs.remove('tmp-nw', function (er) { + if (er) throw er; + }) + }, 1000); }) it('start from nw that package.json in the same folder', function(done) { diff --git a/tests/automatic_tests/start_app/script.js b/tests/automatic_tests/start_app/script.js index da2c09376d..93f2a649d5 100644 --- a/tests/automatic_tests/start_app/script.js +++ b/tests/automatic_tests/start_app/script.js @@ -73,11 +73,8 @@ exports.copySourceFiles = function(folder) { } exports.zipSourceFiles = function(callback) { - exec('python automatic_tests/start_app/zip.py',function(){ - if (typeof callback === 'function'){ - callback(); - } - }); + exec('python automatic_tests/start_app/zip.py'); + setTimeout(callback, 2000); } exports.makeExecuableFile = function() { diff --git a/tests/automatic_tests/user-agent-app/mocha_test.js b/tests/automatic_tests/user-agent-app/mocha_test.js index a03849f7ac..418475a433 100644 --- a/tests/automatic_tests/user-agent-app/mocha_test.js +++ b/tests/automatic_tests/user-agent-app/mocha_test.js @@ -7,30 +7,27 @@ describe('user-agent-app', function() { function(done) { this.timeout(0); var result = false; - var crontab = undefined; var child = app_test.createChildProcess({ execPath: process.execPath, appPath: path.join(global.tests_dir, 'user-agent-app'), end: function(data, app) { - if (crontab != undefined){ - clearTimeout(crontab); - } - result = true; - var package_info = JSON.parse(fs.readFileSync('automatic_tests/user-agent-app/package.json', 'utf8')); - app.kill(); - if (data == package_info.name) { - done(); - } else { - done('the user agent has changed'); - } + result = true; + var package_info = JSON.parse(fs.readFileSync('automatic_tests/user-agent-app/package.json', 'utf8')); + app.kill(); + if (data == package_info.name) { + done(); + } + else{ + done('the user agent has changed'); + } } }); - crontab = setTimeout(function() { - if (!result) { - child.close(); - done('loaded event does not been fired'); - } - }, 10000); - }) -}) \ No newline at end of file + setTimeout(function(){ + if (!result) { + child.close(); + done('loaded event does not been fired'); + } + }, 10000); + }) +}) diff --git a/tests/automatic_tests/website/mocha_test.js b/tests/automatic_tests/website/mocha_test.js index 9caeec32ba..7547c91eca 100644 --- a/tests/automatic_tests/website/mocha_test.js +++ b/tests/automatic_tests/website/mocha_test.js @@ -6,32 +6,31 @@ describe('website', function() { it('html5test.com should score high (long-to-run)', function(done) { this.timeout(0); - var win = gui.Window.open('http://html5test.com', { show: true }); + var win = gui.Window.open('http://html5test.com', { show: false }); win.on('loaded', function() { - //do not read data immediately, it is a RESTful site. - //wait 4 seconds - setTimeout(function(){ - var results = win.window.document.querySelectorAll('div.pointsPanel strong'); - if (results.length === 0){ - done('Can not connect to the web'); - return; - } - - var score = parseInt(results[0].innerHTML); + var results = win.window.document.getElementById('results'); + if (results == null){ + done('Can not connect to the web'); + win.close(); + return; + } + try { + var score = results.childNodes[0].childNodes[1].innerHTML;; if (score >= 445) { done(); } else { done('have a low score'); } win.close(); - },4000); + } catch (e) { + } }); }); it('should support WebGL at get.webgl.org', function(done) { this.timeout(0); - var win = gui.Window.open('http://get.webgl.org', { show: true }); + var win = gui.Window.open('http://get.webgl.org', { show: false }); win.on('loaded', function() { var results = win.window.document.getElementById('webgl-yes'); if (results.classList.contains('webgl-hidden')) { diff --git a/tests/automatic_tests/window/index.html b/tests/automatic_tests/window/index.html index 4afe3dd08a..3ebd01f650 100644 --- a/tests/automatic_tests/window/index.html +++ b/tests/automatic_tests/window/index.html @@ -4,18 +4,11 @@ Test Case for 'Window.focus' + +
    diff --git a/tests/mocha/lib/reporters/templates/style.html b/tests/mocha/lib/reporters/templates/style.html deleted file mode 100644 index 643c0ab7b8..0000000000 --- a/tests/mocha/lib/reporters/templates/style.html +++ /dev/null @@ -1,320 +0,0 @@ - \ No newline at end of file diff --git a/tests/mocha/lib/reporters/xunit.js b/tests/mocha/lib/reporters/xunit.js deleted file mode 100644 index e956380d8e..0000000000 --- a/tests/mocha/lib/reporters/xunit.js +++ /dev/null @@ -1,119 +0,0 @@ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils') - , escape = utils.escape; - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Expose `XUnit`. - */ - -exports = module.exports = XUnit; - -/** - * Initialize a new `XUnit` reporter. - * - * @param {Runner} runner - * @api public - */ - -function XUnit(runner) { - Base.call(this, runner); - var stats = this.stats - , tests = [] - , self = this; - - runner.on('pending', function(test){ - tests.push(test); - }); - - runner.on('pass', function(test){ - tests.push(test); - }); - - runner.on('fail', function(test){ - tests.push(test); - }); - - runner.on('end', function(){ - console.log(tag('testsuite', { - name: 'Mocha Tests' - , tests: stats.tests - , failures: stats.failures - , errors: stats.failures - , skipped: stats.tests - stats.failures - stats.passes - , timestamp: (new Date).toUTCString() - , time: (stats.duration / 1000) || 0 - }, false)); - - tests.forEach(test); - console.log(''); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -XUnit.prototype.__proto__ = Base.prototype; - -/** - * Output tag for the given `test.` - */ - -function test(test) { - var attrs = { - classname: test.parent.fullTitle() - , name: test.title - , time: (test.duration / 1000) || 0 - }; - - if ('failed' == test.state) { - var err = test.err; - attrs.message = escape(err.message); - console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); - } else if (test.pending) { - console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); - } else { - console.log(tag('testcase', attrs, true) ); - } -} - -/** - * HTML tag helper. - */ - -function tag(name, attrs, close, content) { - var end = close ? '/>' : '>' - , pairs = [] - , tag; - - for (var key in attrs) { - pairs.push(key + '="' + escape(attrs[key]) + '"'); - } - - tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; - if (content) tag += content + ''; -} diff --git a/tests/mocha/lib/runnable.js b/tests/mocha/lib/runnable.js deleted file mode 100644 index 6940bb77d3..0000000000 --- a/tests/mocha/lib/runnable.js +++ /dev/null @@ -1,231 +0,0 @@ - -/** - * Module dependencies. - */ - -var EventEmitter = require('events').EventEmitter - , debug = require('debug')('mocha:runnable') - , milliseconds = require('./ms'); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Object#toString(). - */ - -var toString = Object.prototype.toString; - -/** - * Expose `Runnable`. - */ - -module.exports = Runnable; - -/** - * Initialize a new `Runnable` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Runnable(title, fn) { - this.title = title; - this.fn = fn; - this.async = fn && fn.length; - this.sync = ! this.async; - this._timeout = 2000; - this._slow = 75; - this.timedOut = false; -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -Runnable.prototype.__proto__ = EventEmitter.prototype; - -/** - * Set & get timeout `ms`. - * - * @param {Number|String} ms - * @return {Runnable|Number} ms or self - * @api private - */ - -Runnable.prototype.timeout = function(ms){ - if (0 == arguments.length) return this._timeout; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._timeout = ms; - if (this.timer) this.resetTimeout(); - return this; -}; - -/** - * Set & get slow `ms`. - * - * @param {Number|String} ms - * @return {Runnable|Number} ms or self - * @api private - */ - -Runnable.prototype.slow = function(ms){ - if (0 === arguments.length) return this._slow; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._slow = ms; - return this; -}; - -/** - * Return the full title generated by recursively - * concatenating the parent's full title. - * - * @return {String} - * @api public - */ - -Runnable.prototype.fullTitle = function(){ - return this.parent.fullTitle() + ' ' + this.title; -}; - -/** - * Clear the timeout. - * - * @api private - */ - -Runnable.prototype.clearTimeout = function(){ - clearTimeout(this.timer); -}; - -/** - * Inspect the runnable void of private properties. - * - * @return {String} - * @api private - */ - -Runnable.prototype.inspect = function(){ - return JSON.stringify(this, function(key, val){ - if ('_' == key[0]) return; - if ('parent' == key) return '#'; - if ('ctx' == key) return '#'; - return val; - }, 2); -}; - -/** - * Reset the timeout. - * - * @api private - */ - -Runnable.prototype.resetTimeout = function(){ - var self = this; - var ms = this.timeout() || 1e9; - - this.clearTimeout(); - this.timer = setTimeout(function(){ - self.callback(new Error('timeout of ' + ms + 'ms exceeded')); - self.timedOut = true; - }, ms); -}; - -/** - * Whitelist these globals for this test run - * - * @api private - */ -Runnable.prototype.globals = function(arr){ - var self = this; - this._allowedGlobals = arr; -}; - -/** - * Run the test and invoke `fn(err)`. - * - * @param {Function} fn - * @api private - */ - -Runnable.prototype.run = function(fn){ - var self = this - , ms = this.timeout() - , start = new Date - , ctx = this.ctx - , finished - , emitted; - - if (ctx) ctx.runnable(this); - - // called multiple times - function multiple(err) { - if (emitted) return; - emitted = true; - self.emit('error', err || new Error('done() called multiple times')); - } - - // finished - function done(err) { - if (self.timedOut) return; - if (finished) return multiple(err); - self.clearTimeout(); - self.duration = new Date - start; - finished = true; - fn(err); - } - - // for .resetTimeout() - this.callback = done; - - // explicit async with `done` argument - if (this.async) { - this.resetTimeout(); - - try { - this.fn.call(ctx, function(err){ - if (err instanceof Error || toString.call(err) === "[object Error]") return done(err); - if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); - done(); - }); - } catch (err) { - done(err); - } - return; - } - - if (this.asyncOnly) { - return done(new Error('--async-only option in use without declaring `done()`')); - } - - // sync or promise-returning - try { - if (this.pending) { - done(); - } else { - callFn(this.fn); - } - } catch (err) { - done(err); - } - - function callFn(fn) { - var result = fn.call(ctx); - if (result && typeof result.then === 'function') { - self.resetTimeout(); - result.then(function(){ done() }, done); - } else { - done(); - } - } -}; diff --git a/tests/mocha/lib/runner.js b/tests/mocha/lib/runner.js deleted file mode 100644 index deb442e145..0000000000 --- a/tests/mocha/lib/runner.js +++ /dev/null @@ -1,661 +0,0 @@ -/** - * Module dependencies. - */ - -var EventEmitter = require('events').EventEmitter - , debug = require('debug')('mocha:runner') - , Test = require('./test') - , utils = require('./utils') - , filter = utils.filter - , keys = utils.keys; - -/** - * Non-enumerable globals. - */ - -var globals = [ - 'setTimeout', - 'clearTimeout', - 'setInterval', - 'clearInterval', - 'XMLHttpRequest', - 'Date' -]; - -/** - * Expose `Runner`. - */ - -module.exports = Runner; - -/** - * Initialize a `Runner` for the given `suite`. - * - * Events: - * - * - `start` execution started - * - `end` execution complete - * - `suite` (suite) test suite execution started - * - `suite end` (suite) all tests (and sub-suites) have finished - * - `test` (test) test execution started - * - `test end` (test) test completed - * - `hook` (hook) hook execution started - * - `hook end` (hook) hook complete - * - `pass` (test) test passed - * - `fail` (test, err) test failed - * - `pending` (test) test pending - * - * @api public - */ - -function Runner(suite) { - var self = this; - this._globals = []; - this._abort = false; - this.suite = suite; - this.total = suite.total(); - this.failures = 0; - this.on('test end', function(test){ self.checkGlobals(test); }); - this.on('hook end', function(hook){ self.checkGlobals(hook); }); - this.grep(/.*/); - this.globals(this.globalProps().concat(extraGlobals())); -} - -/** - * Wrapper for setImmediate, process.nextTick, or browser polyfill. - * - * @param {Function} fn - * @api private - */ - -Runner.immediately = global.setImmediate || process.nextTick; - -/** - * Inherit from `EventEmitter.prototype`. - */ - -Runner.prototype.__proto__ = EventEmitter.prototype; - -/** - * Run tests with full titles matching `re`. Updates runner.total - * with number of tests matched. - * - * @param {RegExp} re - * @param {Boolean} invert - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.grep = function(re, invert){ - debug('grep %s', re); - this._grep = re; - this._invert = invert; - this.total = this.grepTotal(this.suite); - return this; -}; - -/** - * Returns the number of tests matching the grep search for the - * given suite. - * - * @param {Suite} suite - * @return {Number} - * @api public - */ - -Runner.prototype.grepTotal = function(suite) { - var self = this; - var total = 0; - - suite.eachTest(function(test){ - var match = self._grep.test(test.fullTitle()); - if (self._invert) match = !match; - if (match) total++; - }); - - return total; -}; - -/** - * Return a list of global properties. - * - * @return {Array} - * @api private - */ - -Runner.prototype.globalProps = function() { - var props = utils.keys(global); - - // non-enumerables - for (var i = 0; i < globals.length; ++i) { - if (~utils.indexOf(props, globals[i])) continue; - props.push(globals[i]); - } - - return props; -}; - -/** - * Allow the given `arr` of globals. - * - * @param {Array} arr - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.globals = function(arr){ - if (0 == arguments.length) return this._globals; - debug('globals %j', arr); - this._globals = this._globals.concat(arr); - return this; -}; - -/** - * Check for global variable leaks. - * - * @api private - */ - -Runner.prototype.checkGlobals = function(test){ - if (this.ignoreLeaks) return; - var ok = this._globals; - - var globals = this.globalProps(); - var isNode = process.kill; - var leaks; - - if (test) { - ok = ok.concat(test._allowedGlobals || []); - } - - if(this.prevGlobalsLength == globals.length) return; - this.prevGlobalsLength = globals.length; - - leaks = filterLeaks(ok, globals); - this._globals = this._globals.concat(leaks); - - if (leaks.length > 1) { - this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); - } else if (leaks.length) { - this.fail(test, new Error('global leak detected: ' + leaks[0])); - } -}; - -/** - * Fail the given `test`. - * - * @param {Test} test - * @param {Error} err - * @api private - */ - -Runner.prototype.fail = function(test, err){ - ++this.failures; - test.state = 'failed'; - - if ('string' == typeof err) { - err = new Error('the string "' + err + '" was thrown, throw an Error :)'); - } - - this.emit('fail', test, err); -}; - -/** - * Fail the given `hook` with `err`. - * - * Hook failures work in the following pattern: - * - If bail, then exit - * - Failed `before` hook skips all tests in a suite and subsuites, - * but jumps to corresponding `after` hook - * - Failed `before each` hook skips remaining tests in a - * suite and jumps to corresponding `after each` hook, - * which is run only once - * - Failed `after` hook does not alter - * execution order - * - Failed `after each` hook skips remaining tests in a - * suite and subsuites, but executes other `after each` - * hooks - * - * @param {Hook} hook - * @param {Error} err - * @api private - */ - -Runner.prototype.failHook = function(hook, err){ - this.fail(hook, err); - if (this.suite.bail()) { - this.emit('end'); - } -}; - -/** - * Run hook `name` callbacks and then invoke `fn()`. - * - * @param {String} name - * @param {Function} function - * @api private - */ - -Runner.prototype.hook = function(name, fn){ - var suite = this.suite - , hooks = suite['_' + name] - , self = this - , timer; - - function next(i) { - var hook = hooks[i]; - if (!hook) return fn(); - if (self.failures && suite.bail()) return fn(); - self.currentRunnable = hook; - - hook.ctx.currentTest = self.test; - - self.emit('hook', hook); - - hook.on('error', function(err){ - self.failHook(hook, err); - }); - - hook.run(function(err){ - hook.removeAllListeners('error'); - var testError = hook.error(); - if (testError) self.fail(self.test, testError); - if (err) { - self.failHook(hook, err); - - // stop executing hooks, notify callee of hook err - return fn(err); - } - self.emit('hook end', hook); - delete hook.ctx.currentTest; - next(++i); - }); - } - - Runner.immediately(function(){ - next(0); - }); -}; - -/** - * Run hook `name` for the given array of `suites` - * in order, and callback `fn(err, errSuite)`. - * - * @param {String} name - * @param {Array} suites - * @param {Function} fn - * @api private - */ - -Runner.prototype.hooks = function(name, suites, fn){ - var self = this - , orig = this.suite; - - function next(suite) { - self.suite = suite; - - if (!suite) { - self.suite = orig; - return fn(); - } - - self.hook(name, function(err){ - if (err) { - var errSuite = self.suite; - self.suite = orig; - return fn(err, errSuite); - } - - next(suites.pop()); - }); - } - - next(suites.pop()); -}; - -/** - * Run hooks from the top level down. - * - * @param {String} name - * @param {Function} fn - * @api private - */ - -Runner.prototype.hookUp = function(name, fn){ - var suites = [this.suite].concat(this.parents()).reverse(); - this.hooks(name, suites, fn); -}; - -/** - * Run hooks from the bottom up. - * - * @param {String} name - * @param {Function} fn - * @api private - */ - -Runner.prototype.hookDown = function(name, fn){ - var suites = [this.suite].concat(this.parents()); - this.hooks(name, suites, fn); -}; - -/** - * Return an array of parent Suites from - * closest to furthest. - * - * @return {Array} - * @api private - */ - -Runner.prototype.parents = function(){ - var suite = this.suite - , suites = []; - while (suite = suite.parent) suites.push(suite); - return suites; -}; - -/** - * Run the current test and callback `fn(err)`. - * - * @param {Function} fn - * @api private - */ - -Runner.prototype.runTest = function(fn){ - var test = this.test - , self = this; - - if (this.asyncOnly) test.asyncOnly = true; - - try { - test.on('error', function(err){ - self.fail(test, err); - }); - test.run(fn); - } catch (err) { - fn(err); - } -}; - -/** - * Run tests in the given `suite` and invoke - * the callback `fn()` when complete. - * - * @param {Suite} suite - * @param {Function} fn - * @api private - */ - -Runner.prototype.runTests = function(suite, fn){ - var self = this - , tests = suite.tests.slice() - , test; - - - function hookErr(err, errSuite, after) { - // before/after Each hook for errSuite failed: - var orig = self.suite; - - // for failed 'after each' hook start from errSuite parent, - // otherwise start from errSuite itself - self.suite = after ? errSuite.parent : errSuite; - - if (self.suite) { - // call hookUp afterEach - self.hookUp('afterEach', function(err2, errSuite2) { - self.suite = orig; - // some hooks may fail even now - if (err2) return hookErr(err2, errSuite2, true); - // report error suite - fn(errSuite); - }); - } else { - // there is no need calling other 'after each' hooks - self.suite = orig; - fn(errSuite); - } - } - - function next(err, errSuite) { - // if we bail after first err - if (self.failures && suite._bail) return fn(); - - if (self._abort) return fn(); - - if (err) return hookErr(err, errSuite, true); - - // next test - test = tests.shift(); - - // all done - if (!test) return fn(); - - // grep - var match = self._grep.test(test.fullTitle()); - if (self._invert) match = !match; - if (!match) return next(); - - // pending - if (test.pending) { - self.emit('pending', test); - self.emit('test end', test); - return next(); - } - - // execute test and hook(s) - self.emit('test', self.test = test); - self.hookDown('beforeEach', function(err, errSuite){ - - if (err) return hookErr(err, errSuite, false); - - self.currentRunnable = self.test; - self.runTest(function(err){ - test = self.test; - - if (err) { - self.fail(test, err); - self.emit('test end', test); - return self.hookUp('afterEach', next); - } - - test.state = 'passed'; - self.emit('pass', test); - self.emit('test end', test); - self.hookUp('afterEach', next); - }); - }); - } - - this.next = next; - next(); -}; - -/** - * Run the given `suite` and invoke the - * callback `fn()` when complete. - * - * @param {Suite} suite - * @param {Function} fn - * @api private - */ - -Runner.prototype.runSuite = function(suite, fn){ - var total = this.grepTotal(suite) - , self = this - , i = 0; - - debug('run suite %s', suite.fullTitle()); - - if (!total) return fn(); - - this.emit('suite', this.suite = suite); - - function next(errSuite) { - if (errSuite) { - // current suite failed on a hook from errSuite - if (errSuite == suite) { - // if errSuite is current suite - // continue to the next sibling suite - return done(); - } else { - // errSuite is among the parents of current suite - // stop execution of errSuite and all sub-suites - return done(errSuite); - } - } - - if (self._abort) return done(); - - var curr = suite.suites[i++]; - if (!curr) return done(); - self.runSuite(curr, next); - } - - function done(errSuite) { - self.suite = suite; - self.hook('afterAll', function(){ - self.emit('suite end', suite); - fn(errSuite); - }); - } - - this.hook('beforeAll', function(err){ - if (err) return done(); - self.runTests(suite, next); - }); -}; - -/** - * Handle uncaught exceptions. - * - * @param {Error} err - * @api private - */ - -Runner.prototype.uncaught = function(err){ - debug('uncaught exception %s', err.message); - var runnable = this.currentRunnable; - if (!runnable || 'failed' == runnable.state) return; - runnable.clearTimeout(); - err.uncaught = true; - this.fail(runnable, err); - - // recover from test - if ('test' == runnable.type) { - this.emit('test end', runnable); - this.hookUp('afterEach', this.next); - return; - } - - // bail on hooks - this.emit('end'); -}; - -/** - * Run the root suite and invoke `fn(failures)` - * on completion. - * - * @param {Function} fn - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.run = function(fn){ - var self = this - , fn = fn || function(){}; - - function uncaught(err){ - self.uncaught(err); - } - - debug('start'); - - // callback - this.on('end', function(){ - debug('end'); - process.removeListener('uncaughtException', uncaught); - fn(self.failures); - }); - - // run suites - this.emit('start'); - this.runSuite(this.suite, function(){ - debug('finished running'); - self.emit('end'); - }); - - // uncaught exception - process.on('uncaughtException', uncaught); - - return this; -}; - -/** - * Cleanly abort execution - * - * @return {Runner} for chaining - * @api public - */ -Runner.prototype.abort = function(){ - debug('aborting'); - this._abort = true; -} - -/** - * Filter leaks with the given globals flagged as `ok`. - * - * @param {Array} ok - * @param {Array} globals - * @return {Array} - * @api private - */ - -function filterLeaks(ok, globals) { - return filter(globals, function(key){ - // Firefox and Chrome exposes iframes as index inside the window object - if (/^d+/.test(key)) return false; - - // in firefox - // if runner runs in an iframe, this iframe's window.getInterface method not init at first - // it is assigned in some seconds - if (global.navigator && /^getInterface/.test(key)) return false; - - // an iframe could be approached by window[iframeIndex] - // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak - if (global.navigator && /^\d+/.test(key)) return false; - - // Opera and IE expose global variables for HTML element IDs (issue #243) - if (/^mocha-/.test(key)) return false; - - var matched = filter(ok, function(ok){ - if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); - return key == ok; - }); - return matched.length == 0 && (!global.navigator || 'onerror' !== key); - }); -} - -/** - * Array of globals dependent on the environment. - * - * @return {Array} - * @api private - */ - - function extraGlobals() { - if (typeof(process) === 'object' && - typeof(process.version) === 'string') { - - var nodeVersion = process.version.split('.').reduce(function(a, v) { - return a << 8 | v; - }); - - // 'errno' was renamed to process._errno in v0.9.11. - - if (nodeVersion < 0x00090B) { - return ['errno']; - } - } - - return []; - } diff --git a/tests/mocha/lib/suite.js b/tests/mocha/lib/suite.js deleted file mode 100644 index d403a83f38..0000000000 --- a/tests/mocha/lib/suite.js +++ /dev/null @@ -1,320 +0,0 @@ - -/** - * Module dependencies. - */ - -var EventEmitter = require('events').EventEmitter - , debug = require('debug')('mocha:suite') - , milliseconds = require('./ms') - , utils = require('./utils') - , Hook = require('./hook'); - -/** - * Expose `Suite`. - */ - -exports = module.exports = Suite; - -/** - * Create a new `Suite` with the given `title` - * and parent `Suite`. When a suite with the - * same title is already present, that suite - * is returned to provide nicer reporter - * and more flexible meta-testing. - * - * @param {Suite} parent - * @param {String} title - * @return {Suite} - * @api public - */ - -exports.create = function(parent, title){ - var suite = new Suite(title, parent.ctx); - suite.parent = parent; - if (parent.pending) suite.pending = true; - title = suite.fullTitle(); - parent.addSuite(suite); - return suite; -}; - -/** - * Initialize a new `Suite` with the given - * `title` and `ctx`. - * - * @param {String} title - * @param {Context} ctx - * @api private - */ - -function Suite(title, ctx) { - this.title = title; - this.ctx = ctx; - this.suites = []; - this.tests = []; - this.pending = false; - this._beforeEach = []; - this._beforeAll = []; - this._afterEach = []; - this._afterAll = []; - this.root = !title; - this._timeout = 2000; - this._slow = 75; - this._bail = false; -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -Suite.prototype.__proto__ = EventEmitter.prototype; - -/** - * Return a clone of this `Suite`. - * - * @return {Suite} - * @api private - */ - -Suite.prototype.clone = function(){ - var suite = new Suite(this.title); - debug('clone'); - suite.ctx = this.ctx; - suite.timeout(this.timeout()); - suite.slow(this.slow()); - suite.bail(this.bail()); - return suite; -}; - -/** - * Set timeout `ms` or short-hand such as "2s". - * - * @param {Number|String} ms - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.timeout = function(ms){ - if (0 == arguments.length) return this._timeout; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._timeout = parseInt(ms, 10); - return this; -}; - -/** - * Set slow `ms` or short-hand such as "2s". - * - * @param {Number|String} ms - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.slow = function(ms){ - if (0 === arguments.length) return this._slow; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('slow %d', ms); - this._slow = ms; - return this; -}; - -/** - * Sets whether to bail after first error. - * - * @parma {Boolean} bail - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.bail = function(bail){ - if (0 == arguments.length) return this._bail; - debug('bail %s', bail); - this._bail = bail; - return this; -}; - -/** - * Run `fn(test[, done])` before running tests. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.beforeAll = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"before all" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeAll.push(hook); - this.emit('beforeAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after running tests. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.afterAll = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"after all" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterAll.push(hook); - this.emit('afterAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` before each test case. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.beforeEach = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"before each" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeEach.push(hook); - this.emit('beforeEach', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after each test case. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.afterEach = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"after each" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterEach.push(hook); - this.emit('afterEach', hook); - return this; -}; - -/** - * Add a test `suite`. - * - * @param {Suite} suite - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.addSuite = function(suite){ - suite.parent = this; - suite.timeout(this.timeout()); - suite.slow(this.slow()); - suite.bail(this.bail()); - this.suites.push(suite); - this.emit('suite', suite); - return this; -}; - -/** - * Add a `test` to this suite. - * - * @param {Test} test - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.addTest = function(test){ - test.parent = this; - test.timeout(this.timeout()); - test.slow(this.slow()); - test.ctx = this.ctx; - this.tests.push(test); - this.emit('test', test); - return this; -}; - -/** - * Return the full title generated by recursively - * concatenating the parent's full title. - * - * @return {String} - * @api public - */ - -Suite.prototype.fullTitle = function(){ - if (this.parent) { - var full = this.parent.fullTitle(); - if (full) return full + ' ' + this.title; - } - return this.title; -}; - -/** - * Return the total number of tests. - * - * @return {Number} - * @api public - */ - -Suite.prototype.total = function(){ - return utils.reduce(this.suites, function(sum, suite){ - return sum + suite.total(); - }, 0) + this.tests.length; -}; - -/** - * Iterates through each suite recursively to find - * all tests. Applies a function in the format - * `fn(test)`. - * - * @param {Function} fn - * @return {Suite} - * @api private - */ - -Suite.prototype.eachTest = function(fn){ - utils.forEach(this.tests, fn); - utils.forEach(this.suites, function(suite){ - suite.eachTest(fn); - }); - return this; -}; diff --git a/tests/mocha/lib/template.html b/tests/mocha/lib/template.html deleted file mode 100644 index 0590d4aac2..0000000000 --- a/tests/mocha/lib/template.html +++ /dev/null @@ -1,18 +0,0 @@ - - - - Mocha - - - - - -
    - - - - - - diff --git a/tests/mocha/lib/test.js b/tests/mocha/lib/test.js deleted file mode 100644 index 11773e0cc9..0000000000 --- a/tests/mocha/lib/test.js +++ /dev/null @@ -1,32 +0,0 @@ - -/** - * Module dependencies. - */ - -var Runnable = require('./runnable'); - -/** - * Expose `Test`. - */ - -module.exports = Test; - -/** - * Initialize a new `Test` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Test(title, fn) { - Runnable.call(this, title, fn); - this.pending = !fn; - this.type = 'test'; -} - -/** - * Inherit from `Runnable.prototype`. - */ - -Test.prototype.__proto__ = Runnable.prototype; diff --git a/tests/mocha/lib/utils.js b/tests/mocha/lib/utils.js deleted file mode 100644 index 37fd5d7e1b..0000000000 --- a/tests/mocha/lib/utils.js +++ /dev/null @@ -1,299 +0,0 @@ -/** - * Module dependencies. - */ - -var fs = require('fs') - , path = require('path') - , join = path.join - , debug = require('debug')('mocha:watch'); - -/** - * Ignored directories. - */ - -var ignore = ['node_modules', '.git']; - -/** - * Escape special characters in the given string of html. - * - * @param {String} html - * @return {String} - * @api private - */ - -exports.escape = function(html){ - return String(html) - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(//g, '>'); -}; - -/** - * Array#forEach (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} scope - * @api private - */ - -exports.forEach = function(arr, fn, scope){ - for (var i = 0, l = arr.length; i < l; i++) - fn.call(scope, arr[i], i); -}; - -/** - * Array#map (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} scope - * @api private - */ - -exports.map = function(arr, fn, scope){ - var result = []; - for (var i = 0, l = arr.length; i < l; i++) - result.push(fn.call(scope, arr[i], i)); - return result; -}; - -/** - * Array#indexOf (<=IE8) - * - * @parma {Array} arr - * @param {Object} obj to find index of - * @param {Number} start - * @api private - */ - -exports.indexOf = function(arr, obj, start){ - for (var i = start || 0, l = arr.length; i < l; i++) { - if (arr[i] === obj) - return i; - } - return -1; -}; - -/** - * Array#reduce (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} initial value - * @api private - */ - -exports.reduce = function(arr, fn, val){ - var rval = val; - - for (var i = 0, l = arr.length; i < l; i++) { - rval = fn(rval, arr[i], i, arr); - } - - return rval; -}; - -/** - * Array#filter (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @api private - */ - -exports.filter = function(arr, fn){ - var ret = []; - - for (var i = 0, l = arr.length; i < l; i++) { - var val = arr[i]; - if (fn(val, i, arr)) ret.push(val); - } - - return ret; -}; - -/** - * Object.keys (<=IE8) - * - * @param {Object} obj - * @return {Array} keys - * @api private - */ - -exports.keys = Object.keys || function(obj) { - var keys = [] - , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 - - for (var key in obj) { - if (has.call(obj, key)) { - keys.push(key); - } - } - - return keys; -}; - -/** - * Watch the given `files` for changes - * and invoke `fn(file)` on modification. - * - * @param {Array} files - * @param {Function} fn - * @api private - */ - -exports.watch = function(files, fn){ - var options = { interval: 100 }; - files.forEach(function(file){ - debug('file %s', file); - fs.watchFile(file, options, function(curr, prev){ - if (prev.mtime < curr.mtime) fn(file); - }); - }); -}; - -/** - * Ignored files. - */ - -function ignored(path){ - return !~ignore.indexOf(path); -} - -/** - * Lookup files in the given `dir`. - * - * @return {Array} - * @api private - */ - -exports.files = function(dir, ret){ - ret = ret || []; - - fs.readdirSync(dir) - .filter(ignored) - .forEach(function(path){ - path = join(dir, path); - if (fs.statSync(path).isDirectory()) { - exports.files(path, ret); - } else if (path.match(/\.(js|coffee|litcoffee|coffee.md)$/)) { - ret.push(path); - } - }); - - return ret; -}; - -/** - * Compute a slug from the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.slug = function(str){ - return str - .toLowerCase() - .replace(/ +/g, '-') - .replace(/[^-\w]/g, ''); -}; - -/** - * Strip the function definition from `str`, - * and re-indent for pre whitespace. - */ - -exports.clean = function(str) { - str = str - .replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '') - .replace(/^function *\(.*\) *{/, '') - .replace(/\s+\}$/, ''); - - var spaces = str.match(/^\n?( *)/)[1].length - , tabs = str.match(/^\n?(\t*)/)[1].length - , re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm'); - - str = str.replace(re, ''); - - return exports.trim(str); -}; - -/** - * Escape regular expression characters in `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.escapeRegexp = function(str){ - return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); -}; - -/** - * Trim the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.trim = function(str){ - return str.replace(/^\s+|\s+$/g, ''); -}; - -/** - * Parse the given `qs`. - * - * @param {String} qs - * @return {Object} - * @api private - */ - -exports.parseQuery = function(qs){ - return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){ - var i = pair.indexOf('=') - , key = pair.slice(0, i) - , val = pair.slice(++i); - - obj[key] = decodeURIComponent(val); - return obj; - }, {}); -}; - -/** - * Highlight the given string of `js`. - * - * @param {String} js - * @return {String} - * @api private - */ - -function highlight(js) { - return js - .replace(//g, '>') - .replace(/\/\/(.*)/gm, '//$1') - .replace(/('.*?')/gm, '$1') - .replace(/(\d+\.\d+)/gm, '$1') - .replace(/(\d+)/gm, '$1') - .replace(/\bnew *(\w+)/gm, 'new $1') - .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') -} - -/** - * Highlight the contents of tag `name`. - * - * @param {String} name - * @api private - */ - -exports.highlightTags = function(name) { - var code = document.getElementsByTagName(name); - for (var i = 0, len = code.length; i < len; ++i) { - code[i].innerHTML = highlight(code[i].innerHTML); - } -}; diff --git a/tests/mocha/mocha.css b/tests/mocha/mocha.css deleted file mode 100644 index 42b9798fa4..0000000000 --- a/tests/mocha/mocha.css +++ /dev/null @@ -1,270 +0,0 @@ -@charset "utf-8"; - -body { - margin:0; -} - -#mocha { - font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; - margin: 60px 50px; -} - -#mocha ul, -#mocha li { - margin: 0; - padding: 0; -} - -#mocha ul { - list-style: none; -} - -#mocha h1, -#mocha h2 { - margin: 0; -} - -#mocha h1 { - margin-top: 15px; - font-size: 1em; - font-weight: 200; -} - -#mocha h1 a { - text-decoration: none; - color: inherit; -} - -#mocha h1 a:hover { - text-decoration: underline; -} - -#mocha .suite .suite h1 { - margin-top: 0; - font-size: .8em; -} - -#mocha .hidden { - display: none; -} - -#mocha h2 { - font-size: 12px; - font-weight: normal; - cursor: pointer; -} - -#mocha .suite { - margin-left: 15px; -} - -#mocha .test { - margin-left: 15px; - overflow: hidden; -} - -#mocha .test.pending:hover h2::after { - content: '(pending)'; - font-family: arial, sans-serif; -} - -#mocha .test.pass.medium .duration { - background: #c09853; -} - -#mocha .test.pass.slow .duration { - background: #b94a48; -} - -#mocha .test.pass::before { - content: '✓'; - font-size: 12px; - display: block; - float: left; - margin-right: 5px; - color: #00d6b2; -} - -#mocha .test.pass .duration { - font-size: 9px; - margin-left: 5px; - padding: 2px 5px; - color: #fff; - -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - box-shadow: inset 0 1px 1px rgba(0,0,0,.2); - -webkit-border-radius: 5px; - -moz-border-radius: 5px; - -ms-border-radius: 5px; - -o-border-radius: 5px; - border-radius: 5px; -} - -#mocha .test.pass.fast .duration { - display: none; -} - -#mocha .test.pending { - color: #0b97c4; -} - -#mocha .test.pending::before { - content: '◦'; - color: #0b97c4; -} - -#mocha .test.fail { - color: #c00; -} - -#mocha .test.fail pre { - color: black; -} - -#mocha .test.fail::before { - content: '✖'; - font-size: 12px; - display: block; - float: left; - margin-right: 5px; - color: #c00; -} - -#mocha .test pre.error { - color: #c00; - max-height: 300px; - overflow: auto; -} - -/** - * (1): approximate for browsers not supporting calc - * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) - * ^^ seriously - */ -#mocha .test pre { - display: block; - float: left; - clear: left; - font: 12px/1.5 monaco, monospace; - margin: 5px; - padding: 15px; - border: 1px solid #eee; - max-width: 85%; /*(1)*/ - max-width: calc(100% - 42px); /*(2)*/ - word-wrap: break-word; - border-bottom-color: #ddd; - -webkit-border-radius: 3px; - -webkit-box-shadow: 0 1px 3px #eee; - -moz-border-radius: 3px; - -moz-box-shadow: 0 1px 3px #eee; - border-radius: 3px; -} - -#mocha .test h2 { - position: relative; -} - -#mocha .test a.replay { - position: absolute; - top: 3px; - right: 0; - text-decoration: none; - vertical-align: middle; - display: block; - width: 15px; - height: 15px; - line-height: 15px; - text-align: center; - background: #eee; - font-size: 15px; - -moz-border-radius: 15px; - border-radius: 15px; - -webkit-transition: opacity 200ms; - -moz-transition: opacity 200ms; - transition: opacity 200ms; - opacity: 0.3; - color: #888; -} - -#mocha .test:hover a.replay { - opacity: 1; -} - -#mocha-report.pass .test.fail { - display: none; -} - -#mocha-report.fail .test.pass { - display: none; -} - -#mocha-report.pending .test.pass, -#mocha-report.pending .test.fail { - display: none; -} -#mocha-report.pending .test.pass.pending { - display: block; -} - -#mocha-error { - color: #c00; - font-size: 1.5em; - font-weight: 100; - letter-spacing: 1px; -} - -#mocha-stats { - position: fixed; - top: 15px; - right: 10px; - font-size: 12px; - margin: 0; - color: #888; - z-index: 1; -} - -#mocha-stats .progress { - float: right; - padding-top: 0; -} - -#mocha-stats em { - color: black; -} - -#mocha-stats a { - text-decoration: none; - color: inherit; -} - -#mocha-stats a:hover { - border-bottom: 1px solid #eee; -} - -#mocha-stats li { - display: inline-block; - margin: 0 5px; - list-style: none; - padding-top: 11px; -} - -#mocha-stats canvas { - width: 40px; - height: 40px; -} - -#mocha code .comment { color: #ddd; } -#mocha code .init { color: #2f6fad; } -#mocha code .string { color: #5890ad; } -#mocha code .keyword { color: #8a6343; } -#mocha code .number { color: #2f6fad; } - -@media screen and (max-device-width: 480px) { - #mocha { - margin: 60px 0px; - } - - #mocha #stats { - position: absolute; - } -} diff --git a/tests/mocha/mocha.js b/tests/mocha/mocha.js deleted file mode 100644 index 6eb96ae6ff..0000000000 --- a/tests/mocha/mocha.js +++ /dev/null @@ -1,5848 +0,0 @@ -;(function(global){;(function(){ - -// CommonJS require() - -function require(p){ - var path = require.resolve(p) - , mod = require.modules[path]; - if (!mod) throw new Error('failed to require "' + p + '"'); - if (!mod.exports) { - mod.exports = {}; - mod.call(mod.exports, mod, mod.exports, require.relative(path)); - } - return mod.exports; - } - -require.modules = {}; - -require.resolve = function (path){ - var orig = path - , reg = path + '.js' - , index = path + '/index.js'; - return require.modules[reg] && reg - || require.modules[index] && index - || orig; - }; - -require.register = function (path, fn){ - require.modules[path] = fn; - }; - -require.relative = function (parent) { - return function(p){ - if ('.' != p.charAt(0)) return require(p); - - var path = parent.split('/') - , segs = p.split('/'); - path.pop(); - - for (var i = 0; i < segs.length; i++) { - var seg = segs[i]; - if ('..' == seg) path.pop(); - else if ('.' != seg) path.push(seg); - } - - return require(path.join('/')); - }; - }; - - -require.register("browser/debug.js", function(module, exports, require){ - -module.exports = function(type){ - return function(){ - } -}; - -}); // module: browser/debug.js - -require.register("browser/diff.js", function(module, exports, require){ -/* See LICENSE file for terms of use */ - -/* - * Text diff implementation. - * - * This library supports the following APIS: - * JsDiff.diffChars: Character by character diff - * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace - * JsDiff.diffLines: Line based diff - * - * JsDiff.diffCss: Diff targeted at CSS content - * - * These methods are based on the implementation proposed in - * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). - * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 - */ -var JsDiff = (function() { - /*jshint maxparams: 5*/ - function clonePath(path) { - return { newPos: path.newPos, components: path.components.slice(0) }; - } - function removeEmpty(array) { - var ret = []; - for (var i = 0; i < array.length; i++) { - if (array[i]) { - ret.push(array[i]); - } - } - return ret; - } - function escapeHTML(s) { - var n = s; - n = n.replace(/&/g, '&'); - n = n.replace(//g, '>'); - n = n.replace(/"/g, '"'); - - return n; - } - - var Diff = function(ignoreWhitespace) { - this.ignoreWhitespace = ignoreWhitespace; - }; - Diff.prototype = { - diff: function(oldString, newString) { - // Handle the identity case (this is due to unrolling editLength == 0 - if (newString === oldString) { - return [{ value: newString }]; - } - if (!newString) { - return [{ value: oldString, removed: true }]; - } - if (!oldString) { - return [{ value: newString, added: true }]; - } - - newString = this.tokenize(newString); - oldString = this.tokenize(oldString); - - var newLen = newString.length, oldLen = oldString.length; - var maxEditLength = newLen + oldLen; - var bestPath = [{ newPos: -1, components: [] }]; - - // Seed editLength = 0 - var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); - if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) { - return bestPath[0].components; - } - - for (var editLength = 1; editLength <= maxEditLength; editLength++) { - for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) { - var basePath; - var addPath = bestPath[diagonalPath-1], - removePath = bestPath[diagonalPath+1]; - oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; - if (addPath) { - // No one else is going to attempt to use this value, clear it - bestPath[diagonalPath-1] = undefined; - } - - var canAdd = addPath && addPath.newPos+1 < newLen; - var canRemove = removePath && 0 <= oldPos && oldPos < oldLen; - if (!canAdd && !canRemove) { - bestPath[diagonalPath] = undefined; - continue; - } - - // Select the diagonal that we want to branch from. We select the prior - // path whose position in the new string is the farthest from the origin - // and does not pass the bounds of the diff graph - if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { - basePath = clonePath(removePath); - this.pushComponent(basePath.components, oldString[oldPos], undefined, true); - } else { - basePath = clonePath(addPath); - basePath.newPos++; - this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined); - } - - var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath); - - if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) { - return basePath.components; - } else { - bestPath[diagonalPath] = basePath; - } - } - } - }, - - pushComponent: function(components, value, added, removed) { - var last = components[components.length-1]; - if (last && last.added === added && last.removed === removed) { - // We need to clone here as the component clone operation is just - // as shallow array clone - components[components.length-1] = - {value: this.join(last.value, value), added: added, removed: removed }; - } else { - components.push({value: value, added: added, removed: removed }); - } - }, - extractCommon: function(basePath, newString, oldString, diagonalPath) { - var newLen = newString.length, - oldLen = oldString.length, - newPos = basePath.newPos, - oldPos = newPos - diagonalPath; - while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) { - newPos++; - oldPos++; - - this.pushComponent(basePath.components, newString[newPos], undefined, undefined); - } - basePath.newPos = newPos; - return oldPos; - }, - - equals: function(left, right) { - var reWhitespace = /\S/; - if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) { - return true; - } else { - return left === right; - } - }, - join: function(left, right) { - return left + right; - }, - tokenize: function(value) { - return value; - } - }; - - var CharDiff = new Diff(); - - var WordDiff = new Diff(true); - var WordWithSpaceDiff = new Diff(); - WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\s+|\b)/)); - }; - - var CssDiff = new Diff(true); - CssDiff.tokenize = function(value) { - return removeEmpty(value.split(/([{}:;,]|\s+)/)); - }; - - var LineDiff = new Diff(); - LineDiff.tokenize = function(value) { - return value.split(/^/m); - }; - - return { - Diff: Diff, - - diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); }, - diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); }, - diffWordsWithSpace: function(oldStr, newStr) { return WordWithSpaceDiff.diff(oldStr, newStr); }, - diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); }, - - diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); }, - - createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { - var ret = []; - - ret.push('Index: ' + fileName); - ret.push('==================================================================='); - ret.push('--- ' + fileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); - ret.push('+++ ' + fileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); - - var diff = LineDiff.diff(oldStr, newStr); - if (!diff[diff.length-1].value) { - diff.pop(); // Remove trailing newline add - } - diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier - - function contextLines(lines) { - return lines.map(function(entry) { return ' ' + entry; }); - } - function eofNL(curRange, i, current) { - var last = diff[diff.length-2], - isLast = i === diff.length-2, - isLastOfType = i === diff.length-3 && (current.added !== last.added || current.removed !== last.removed); - - // Figure out if this is the last line for the given file and missing NL - if (!/\n$/.test(current.value) && (isLast || isLastOfType)) { - curRange.push('\\ No newline at end of file'); - } - } - - var oldRangeStart = 0, newRangeStart = 0, curRange = [], - oldLine = 1, newLine = 1; - for (var i = 0; i < diff.length; i++) { - var current = diff[i], - lines = current.lines || current.value.replace(/\n$/, '').split('\n'); - current.lines = lines; - - if (current.added || current.removed) { - if (!oldRangeStart) { - var prev = diff[i-1]; - oldRangeStart = oldLine; - newRangeStart = newLine; - - if (prev) { - curRange = contextLines(prev.lines.slice(-4)); - oldRangeStart -= curRange.length; - newRangeStart -= curRange.length; - } - } - curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?'+':'-') + entry; })); - eofNL(curRange, i, current); - - if (current.added) { - newLine += lines.length; - } else { - oldLine += lines.length; - } - } else { - if (oldRangeStart) { - // Close out any changes that have been output (or join overlapping) - if (lines.length <= 8 && i < diff.length-2) { - // Overlapping - curRange.push.apply(curRange, contextLines(lines)); - } else { - // end the range and output - var contextSize = Math.min(lines.length, 4); - ret.push( - '@@ -' + oldRangeStart + ',' + (oldLine-oldRangeStart+contextSize) - + ' +' + newRangeStart + ',' + (newLine-newRangeStart+contextSize) - + ' @@'); - ret.push.apply(ret, curRange); - ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); - if (lines.length <= 4) { - eofNL(ret, i, current); - } - - oldRangeStart = 0; newRangeStart = 0; curRange = []; - } - } - oldLine += lines.length; - newLine += lines.length; - } - } - - return ret.join('\n') + '\n'; - }, - - applyPatch: function(oldStr, uniDiff) { - var diffstr = uniDiff.split('\n'); - var diff = []; - var remEOFNL = false, - addEOFNL = false; - - for (var i = (diffstr[0][0]==='I'?4:0); i < diffstr.length; i++) { - if(diffstr[i][0] === '@') { - var meh = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); - diff.unshift({ - start:meh[3], - oldlength:meh[2], - oldlines:[], - newlength:meh[4], - newlines:[] - }); - } else if(diffstr[i][0] === '+') { - diff[0].newlines.push(diffstr[i].substr(1)); - } else if(diffstr[i][0] === '-') { - diff[0].oldlines.push(diffstr[i].substr(1)); - } else if(diffstr[i][0] === ' ') { - diff[0].newlines.push(diffstr[i].substr(1)); - diff[0].oldlines.push(diffstr[i].substr(1)); - } else if(diffstr[i][0] === '\\') { - if (diffstr[i-1][0] === '+') { - remEOFNL = true; - } else if(diffstr[i-1][0] === '-') { - addEOFNL = true; - } - } - } - - var str = oldStr.split('\n'); - for (var i = diff.length - 1; i >= 0; i--) { - var d = diff[i]; - for (var j = 0; j < d.oldlength; j++) { - if(str[d.start-1+j] !== d.oldlines[j]) { - return false; - } - } - Array.prototype.splice.apply(str,[d.start-1,+d.oldlength].concat(d.newlines)); - } - - if (remEOFNL) { - while (!str[str.length-1]) { - str.pop(); - } - } else if (addEOFNL) { - str.push(''); - } - return str.join('\n'); - }, - - convertChangesToXML: function(changes){ - var ret = []; - for ( var i = 0; i < changes.length; i++) { - var change = changes[i]; - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } - - ret.push(escapeHTML(change.value)); - - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } - } - return ret.join(''); - }, - - // See: http://code.google.com/p/google-diff-match-patch/wiki/API - convertChangesToDMP: function(changes){ - var ret = [], change; - for ( var i = 0; i < changes.length; i++) { - change = changes[i]; - ret.push([(change.added ? 1 : change.removed ? -1 : 0), change.value]); - } - return ret; - } - }; -})(); - -if (typeof module !== 'undefined') { - module.exports = JsDiff; -} - -}); // module: browser/diff.js - -require.register("browser/events.js", function(module, exports, require){ - -/** - * Module exports. - */ - -exports.EventEmitter = EventEmitter; - -/** - * Check if `obj` is an array. - */ - -function isArray(obj) { - return '[object Array]' == {}.toString.call(obj); -} - -/** - * Event emitter constructor. - * - * @api public - */ - -function EventEmitter(){}; - -/** - * Adds a listener. - * - * @api public - */ - -EventEmitter.prototype.on = function (name, fn) { - if (!this.$events) { - this.$events = {}; - } - - if (!this.$events[name]) { - this.$events[name] = fn; - } else if (isArray(this.$events[name])) { - this.$events[name].push(fn); - } else { - this.$events[name] = [this.$events[name], fn]; - } - - return this; -}; - -EventEmitter.prototype.addListener = EventEmitter.prototype.on; - -/** - * Adds a volatile listener. - * - * @api public - */ - -EventEmitter.prototype.once = function (name, fn) { - var self = this; - - function on () { - self.removeListener(name, on); - fn.apply(this, arguments); - }; - - on.listener = fn; - this.on(name, on); - - return this; -}; - -/** - * Removes a listener. - * - * @api public - */ - -EventEmitter.prototype.removeListener = function (name, fn) { - if (this.$events && this.$events[name]) { - var list = this.$events[name]; - - if (isArray(list)) { - var pos = -1; - - for (var i = 0, l = list.length; i < l; i++) { - if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { - pos = i; - break; - } - } - - if (pos < 0) { - return this; - } - - list.splice(pos, 1); - - if (!list.length) { - delete this.$events[name]; - } - } else if (list === fn || (list.listener && list.listener === fn)) { - delete this.$events[name]; - } - } - - return this; -}; - -/** - * Removes all listeners for an event. - * - * @api public - */ - -EventEmitter.prototype.removeAllListeners = function (name) { - if (name === undefined) { - this.$events = {}; - return this; - } - - if (this.$events && this.$events[name]) { - this.$events[name] = null; - } - - return this; -}; - -/** - * Gets all listeners for a certain event. - * - * @api public - */ - -EventEmitter.prototype.listeners = function (name) { - if (!this.$events) { - this.$events = {}; - } - - if (!this.$events[name]) { - this.$events[name] = []; - } - - if (!isArray(this.$events[name])) { - this.$events[name] = [this.$events[name]]; - } - - return this.$events[name]; -}; - -/** - * Emits an event. - * - * @api public - */ - -EventEmitter.prototype.emit = function (name) { - if (!this.$events) { - return false; - } - - var handler = this.$events[name]; - - if (!handler) { - return false; - } - - var args = [].slice.call(arguments, 1); - - if ('function' == typeof handler) { - handler.apply(this, args); - } else if (isArray(handler)) { - var listeners = handler.slice(); - - for (var i = 0, l = listeners.length; i < l; i++) { - listeners[i].apply(this, args); - } - } else { - return false; - } - - return true; -}; -}); // module: browser/events.js - -require.register("browser/fs.js", function(module, exports, require){ - -}); // module: browser/fs.js - -require.register("browser/path.js", function(module, exports, require){ - -}); // module: browser/path.js - -require.register("browser/progress.js", function(module, exports, require){ -/** - * Expose `Progress`. - */ - -module.exports = Progress; - -/** - * Initialize a new `Progress` indicator. - */ - -function Progress() { - this.percent = 0; - this.size(0); - this.fontSize(11); - this.font('helvetica, arial, sans-serif'); -} - -/** - * Set progress size to `n`. - * - * @param {Number} n - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.size = function(n){ - this._size = n; - return this; -}; - -/** - * Set text to `str`. - * - * @param {String} str - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.text = function(str){ - this._text = str; - return this; -}; - -/** - * Set font size to `n`. - * - * @param {Number} n - * @return {Progress} for chaining - * @api public - */ - -Progress.prototype.fontSize = function(n){ - this._fontSize = n; - return this; -}; - -/** - * Set font `family`. - * - * @param {String} family - * @return {Progress} for chaining - */ - -Progress.prototype.font = function(family){ - this._font = family; - return this; -}; - -/** - * Update percentage to `n`. - * - * @param {Number} n - * @return {Progress} for chaining - */ - -Progress.prototype.update = function(n){ - this.percent = n; - return this; -}; - -/** - * Draw on `ctx`. - * - * @param {CanvasRenderingContext2d} ctx - * @return {Progress} for chaining - */ - -Progress.prototype.draw = function(ctx){ - try { - var percent = Math.min(this.percent, 100) - , size = this._size - , half = size / 2 - , x = half - , y = half - , rad = half - 1 - , fontSize = this._fontSize; - - ctx.font = fontSize + 'px ' + this._font; - - var angle = Math.PI * 2 * (percent / 100); - ctx.clearRect(0, 0, size, size); - - // outer circle - ctx.strokeStyle = '#9f9f9f'; - ctx.beginPath(); - ctx.arc(x, y, rad, 0, angle, false); - ctx.stroke(); - - // inner circle - ctx.strokeStyle = '#eee'; - ctx.beginPath(); - ctx.arc(x, y, rad - 1, 0, angle, true); - ctx.stroke(); - - // text - var text = this._text || (percent | 0) + '%' - , w = ctx.measureText(text).width; - - ctx.fillText( - text - , x - w / 2 + 1 - , y + fontSize / 2 - 1); - } catch (ex) {} //don't fail if we can't render progress - return this; -}; - -}); // module: browser/progress.js - -require.register("browser/tty.js", function(module, exports, require){ - -exports.isatty = function(){ - return true; -}; - -exports.getWindowSize = function(){ - if ('innerHeight' in global) { - return [global.innerHeight, global.innerWidth]; - } else { - // In a Web Worker, the DOM Window is not available. - return [640, 480]; - } -}; - -}); // module: browser/tty.js - -require.register("context.js", function(module, exports, require){ - -/** - * Expose `Context`. - */ - -module.exports = Context; - -/** - * Initialize a new `Context`. - * - * @api private - */ - -function Context(){} - -/** - * Set or get the context `Runnable` to `runnable`. - * - * @param {Runnable} runnable - * @return {Context} - * @api private - */ - -Context.prototype.runnable = function(runnable){ - if (0 == arguments.length) return this._runnable; - this.test = this._runnable = runnable; - return this; -}; - -/** - * Set test timeout `ms`. - * - * @param {Number} ms - * @return {Context} self - * @api private - */ - -Context.prototype.timeout = function(ms){ - this.runnable().timeout(ms); - return this; -}; - -/** - * Set test slowness threshold `ms`. - * - * @param {Number} ms - * @return {Context} self - * @api private - */ - -Context.prototype.slow = function(ms){ - this.runnable().slow(ms); - return this; -}; - -/** - * Inspect the context void of `._runnable`. - * - * @return {String} - * @api private - */ - -Context.prototype.inspect = function(){ - return JSON.stringify(this, function(key, val){ - if ('_runnable' == key) return; - if ('test' == key) return; - return val; - }, 2); -}; - -}); // module: context.js - -require.register("hook.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Runnable = require('./runnable'); - -/** - * Expose `Hook`. - */ - -module.exports = Hook; - -/** - * Initialize a new `Hook` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Hook(title, fn) { - Runnable.call(this, title, fn); - this.type = 'hook'; -} - -/** - * Inherit from `Runnable.prototype`. - */ - -function F(){}; -F.prototype = Runnable.prototype; -Hook.prototype = new F; -Hook.prototype.constructor = Hook; - - -/** - * Get or set the test `err`. - * - * @param {Error} err - * @return {Error} - * @api public - */ - -Hook.prototype.error = function(err){ - if (0 == arguments.length) { - var err = this._error; - this._error = null; - return err; - } - - this._error = err; -}; - -}); // module: hook.js - -require.register("interfaces/bdd.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test') - , utils = require('../utils'); - -/** - * BDD-style interface: - * - * describe('Array', function(){ - * describe('#indexOf()', function(){ - * it('should return -1 when not present', function(){ - * - * }); - * - * it('should return the index when present', function(){ - * - * }); - * }); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context, file, mocha){ - - /** - * Execute before running tests. - */ - - context.before = function(name, fn){ - suites[0].beforeAll(name, fn); - }; - - /** - * Execute after running tests. - */ - - context.after = function(name, fn){ - suites[0].afterAll(name, fn); - }; - - /** - * Execute before each test case. - */ - - context.beforeEach = function(name, fn){ - suites[0].beforeEach(name, fn); - }; - - /** - * Execute after each test case. - */ - - context.afterEach = function(name, fn){ - suites[0].afterEach(name, fn); - }; - - /** - * Describe a "suite" with the given `title` - * and callback `fn` containing nested suites - * and/or tests. - */ - - context.describe = context.context = function(title, fn){ - var suite = Suite.create(suites[0], title); - suites.unshift(suite); - fn.call(suite); - suites.shift(); - return suite; - }; - - /** - * Pending describe. - */ - - context.xdescribe = - context.xcontext = - context.describe.skip = function(title, fn){ - var suite = Suite.create(suites[0], title); - suite.pending = true; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - }; - - /** - * Exclusive suite. - */ - - context.describe.only = function(title, fn){ - var suite = context.describe(title, fn); - mocha.grep(suite.fullTitle()); - return suite; - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.it = context.specify = function(title, fn){ - var suite = suites[0]; - if (suite.pending) var fn = null; - var test = new Test(title, fn); - suite.addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.it.only = function(title, fn){ - var test = context.it(title, fn); - var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); - return test; - }; - - /** - * Pending test case. - */ - - context.xit = - context.xspecify = - context.it.skip = function(title){ - context.it(title); - }; - }); -}; - -}); // module: interfaces/bdd.js - -require.register("interfaces/exports.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test'); - -/** - * TDD-style interface: - * - * exports.Array = { - * '#indexOf()': { - * 'should return -1 when the value is not present': function(){ - * - * }, - * - * 'should return the correct index when the value is present': function(){ - * - * } - * } - * }; - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('require', visit); - - function visit(obj) { - var suite; - for (var key in obj) { - if ('function' == typeof obj[key]) { - var fn = obj[key]; - switch (key) { - case 'before': - suites[0].beforeAll(fn); - break; - case 'after': - suites[0].afterAll(fn); - break; - case 'beforeEach': - suites[0].beforeEach(fn); - break; - case 'afterEach': - suites[0].afterEach(fn); - break; - default: - suites[0].addTest(new Test(key, fn)); - } - } else { - var suite = Suite.create(suites[0], key); - suites.unshift(suite); - visit(obj[key]); - suites.shift(); - } - } - } -}; - -}); // module: interfaces/exports.js - -require.register("interfaces/index.js", function(module, exports, require){ - -exports.bdd = require('./bdd'); -exports.tdd = require('./tdd'); -exports.qunit = require('./qunit'); -exports.exports = require('./exports'); - -}); // module: interfaces/index.js - -require.register("interfaces/qunit.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test') - , utils = require('../utils'); - -/** - * QUnit-style interface: - * - * suite('Array'); - * - * test('#length', function(){ - * var arr = [1,2,3]; - * ok(arr.length == 3); - * }); - * - * test('#indexOf()', function(){ - * var arr = [1,2,3]; - * ok(arr.indexOf(1) == 0); - * ok(arr.indexOf(2) == 1); - * ok(arr.indexOf(3) == 2); - * }); - * - * suite('String'); - * - * test('#length', function(){ - * ok('foo'.length == 3); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context, file, mocha){ - - /** - * Execute before running tests. - */ - - context.before = function(name, fn){ - suites[0].beforeAll(name, fn); - }; - - /** - * Execute after running tests. - */ - - context.after = function(name, fn){ - suites[0].afterAll(name, fn); - }; - - /** - * Execute before each test case. - */ - - context.beforeEach = function(name, fn){ - suites[0].beforeEach(name, fn); - }; - - /** - * Execute after each test case. - */ - - context.afterEach = function(name, fn){ - suites[0].afterEach(name, fn); - }; - - /** - * Describe a "suite" with the given `title`. - */ - - context.suite = function(title){ - if (suites.length > 1) suites.shift(); - var suite = Suite.create(suites[0], title); - suites.unshift(suite); - return suite; - }; - - /** - * Exclusive test-case. - */ - - context.suite.only = function(title, fn){ - var suite = context.suite(title, fn); - mocha.grep(suite.fullTitle()); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.test = function(title, fn){ - var test = new Test(title, fn); - suites[0].addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.test.only = function(title, fn){ - var test = context.test(title, fn); - var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); - }; - - /** - * Pending test case. - */ - - context.test.skip = function(title){ - context.test(title); - }; - }); -}; - -}); // module: interfaces/qunit.js - -require.register("interfaces/tdd.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Suite = require('../suite') - , Test = require('../test') - , utils = require('../utils');; - -/** - * TDD-style interface: - * - * suite('Array', function(){ - * suite('#indexOf()', function(){ - * suiteSetup(function(){ - * - * }); - * - * test('should return -1 when not present', function(){ - * - * }); - * - * test('should return the index when present', function(){ - * - * }); - * - * suiteTeardown(function(){ - * - * }); - * }); - * }); - * - */ - -module.exports = function(suite){ - var suites = [suite]; - - suite.on('pre-require', function(context, file, mocha){ - - /** - * Execute before each test case. - */ - - context.setup = function(name, fn){ - suites[0].beforeEach(name, fn); - }; - - /** - * Execute after each test case. - */ - - context.teardown = function(name, fn){ - suites[0].afterEach(name, fn); - }; - - /** - * Execute before the suite. - */ - - context.suiteSetup = function(name, fn){ - suites[0].beforeAll(name, fn); - }; - - /** - * Execute after the suite. - */ - - context.suiteTeardown = function(name, fn){ - suites[0].afterAll(name, fn); - }; - - /** - * Describe a "suite" with the given `title` - * and callback `fn` containing nested suites - * and/or tests. - */ - - context.suite = function(title, fn){ - var suite = Suite.create(suites[0], title); - suites.unshift(suite); - fn.call(suite); - suites.shift(); - return suite; - }; - - /** - * Pending suite. - */ - context.suite.skip = function(title, fn) { - var suite = Suite.create(suites[0], title); - suite.pending = true; - suites.unshift(suite); - fn.call(suite); - suites.shift(); - }; - - /** - * Exclusive test-case. - */ - - context.suite.only = function(title, fn){ - var suite = context.suite(title, fn); - mocha.grep(suite.fullTitle()); - }; - - /** - * Describe a specification or test-case - * with the given `title` and callback `fn` - * acting as a thunk. - */ - - context.test = function(title, fn){ - var suite = suites[0]; - if (suite.pending) var fn = null; - var test = new Test(title, fn); - suite.addTest(test); - return test; - }; - - /** - * Exclusive test-case. - */ - - context.test.only = function(title, fn){ - var test = context.test(title, fn); - var reString = '^' + utils.escapeRegexp(test.fullTitle()) + '$'; - mocha.grep(new RegExp(reString)); - }; - - /** - * Pending test case. - */ - - context.test.skip = function(title){ - context.test(title); - }; - }); -}; - -}); // module: interfaces/tdd.js - -require.register("mocha.js", function(module, exports, require){ -/*! - * mocha - * Copyright(c) 2011 TJ Holowaychuk - * MIT Licensed - */ - -/** - * Module dependencies. - */ - -var path = require('browser/path') - , utils = require('./utils'); - -/** - * Expose `Mocha`. - */ - -exports = module.exports = Mocha; - -/** - * Expose internals. - */ - -exports.utils = utils; -exports.interfaces = require('./interfaces'); -exports.reporters = require('./reporters'); -exports.Runnable = require('./runnable'); -exports.Context = require('./context'); -exports.Runner = require('./runner'); -exports.Suite = require('./suite'); -exports.Hook = require('./hook'); -exports.Test = require('./test'); - -/** - * Return image `name` path. - * - * @param {String} name - * @return {String} - * @api private - */ - -function image(name) { - return __dirname + '/../images/' + name + '.png'; -} - -/** - * Setup mocha with `options`. - * - * Options: - * - * - `ui` name "bdd", "tdd", "exports" etc - * - `reporter` reporter instance, defaults to `mocha.reporters.Dot` - * - `globals` array of accepted globals - * - `timeout` timeout in milliseconds - * - `bail` bail on the first test failure - * - `slow` milliseconds to wait before considering a test slow - * - `ignoreLeaks` ignore global leaks - * - `grep` string or regexp to filter tests with - * - * @param {Object} options - * @api public - */ - -function Mocha(options) { - options = options || {}; - this.files = []; - this.options = options; - this.grep(options.grep); - this.suite = new exports.Suite('', new exports.Context); - this.ui(options.ui); - this.bail(options.bail); - this.reporter(options.reporter); - if (null != options.timeout) this.timeout(options.timeout); - this.useColors(options.useColors) - if (options.slow) this.slow(options.slow); - - this.suite.on('pre-require', function (context) { - exports.afterEach = context.afterEach || context.teardown; - exports.after = context.after || context.suiteTeardown; - exports.beforeEach = context.beforeEach || context.setup; - exports.before = context.before || context.suiteSetup; - exports.describe = context.describe || context.suite; - exports.it = context.it || context.test; - exports.setup = context.setup || context.beforeEach; - exports.suiteSetup = context.suiteSetup || context.before; - exports.suiteTeardown = context.suiteTeardown || context.after; - exports.suite = context.suite || context.describe; - exports.teardown = context.teardown || context.afterEach; - exports.test = context.test || context.it; - }); -} - -/** - * Enable or disable bailing on the first failure. - * - * @param {Boolean} [bail] - * @api public - */ - -Mocha.prototype.bail = function(bail){ - if (0 == arguments.length) bail = true; - this.suite.bail(bail); - return this; -}; - -/** - * Add test `file`. - * - * @param {String} file - * @api public - */ - -Mocha.prototype.addFile = function(file){ - this.files.push(file); - return this; -}; - -/** - * Set reporter to `reporter`, defaults to "dot". - * - * @param {String|Function} reporter name or constructor - * @api public - */ - -Mocha.prototype.reporter = function(reporter){ - if ('function' == typeof reporter) { - this._reporter = reporter; - } else { - reporter = reporter || 'dot'; - var _reporter; - try { _reporter = require('./reporters/' + reporter); } catch (err) {}; - if (!_reporter) try { _reporter = require(reporter); } catch (err) {}; - if (!_reporter && reporter === 'teamcity') - console.warn('The Teamcity reporter was moved to a package named ' + - 'mocha-teamcity-reporter ' + - '(https://npmjs.org/package/mocha-teamcity-reporter).'); - if (!_reporter) throw new Error('invalid reporter "' + reporter + '"'); - this._reporter = _reporter; - } - return this; -}; - -/** - * Set test UI `name`, defaults to "bdd". - * - * @param {String} bdd - * @api public - */ - -Mocha.prototype.ui = function(name){ - name = name || 'bdd'; - this._ui = exports.interfaces[name]; - if (!this._ui) try { this._ui = require(name); } catch (err) {}; - if (!this._ui) throw new Error('invalid interface "' + name + '"'); - this._ui = this._ui(this.suite); - return this; -}; - -/** - * Load registered files. - * - * @api private - */ - -Mocha.prototype.loadFiles = function(fn){ - var self = this; - var suite = this.suite; - var pending = this.files.length; - this.files.forEach(function(file){ - file = path.resolve(file); - suite.emit('pre-require', global, file, self); - suite.emit('require', require(file), file, self); - suite.emit('post-require', global, file, self); - --pending || (fn && fn()); - }); -}; - -/** - * Enable growl support. - * - * @api private - */ - -Mocha.prototype._growl = function(runner, reporter) { - var notify = require('growl'); - - runner.on('end', function(){ - var stats = reporter.stats; - if (stats.failures) { - var msg = stats.failures + ' of ' + runner.total + ' tests failed'; - notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); - } else { - notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { - name: 'mocha' - , title: 'Passed' - , image: image('ok') - }); - } - }); -}; - -/** - * Add regexp to grep, if `re` is a string it is escaped. - * - * @param {RegExp|String} re - * @return {Mocha} - * @api public - */ - -Mocha.prototype.grep = function(re){ - this.options.grep = 'string' == typeof re - ? new RegExp(utils.escapeRegexp(re)) - : re; - return this; -}; - -/** - * Invert `.grep()` matches. - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.invert = function(){ - this.options.invert = true; - return this; -}; - -/** - * Ignore global leaks. - * - * @param {Boolean} ignore - * @return {Mocha} - * @api public - */ - -Mocha.prototype.ignoreLeaks = function(ignore){ - this.options.ignoreLeaks = !!ignore; - return this; -}; - -/** - * Enable global leak checking. - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.checkLeaks = function(){ - this.options.ignoreLeaks = false; - return this; -}; - -/** - * Enable growl support. - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.growl = function(){ - this.options.growl = true; - return this; -}; - -/** - * Ignore `globals` array or string. - * - * @param {Array|String} globals - * @return {Mocha} - * @api public - */ - -Mocha.prototype.globals = function(globals){ - this.options.globals = (this.options.globals || []).concat(globals); - return this; -}; - -/** - * Emit color output. - * - * @param {Boolean} colors - * @return {Mocha} - * @api public - */ - -Mocha.prototype.useColors = function(colors){ - this.options.useColors = arguments.length && colors != undefined - ? colors - : true; - return this; -}; - -/** - * Use inline diffs rather than +/-. - * - * @param {Boolean} inlineDiffs - * @return {Mocha} - * @api public - */ - -Mocha.prototype.useInlineDiffs = function(inlineDiffs) { - this.options.useInlineDiffs = arguments.length && inlineDiffs != undefined - ? inlineDiffs - : false; - return this; -}; - -/** - * Set the timeout in milliseconds. - * - * @param {Number} timeout - * @return {Mocha} - * @api public - */ - -Mocha.prototype.timeout = function(timeout){ - this.suite.timeout(timeout); - return this; -}; - -/** - * Set slowness threshold in milliseconds. - * - * @param {Number} slow - * @return {Mocha} - * @api public - */ - -Mocha.prototype.slow = function(slow){ - this.suite.slow(slow); - return this; -}; - -/** - * Makes all tests async (accepting a callback) - * - * @return {Mocha} - * @api public - */ - -Mocha.prototype.asyncOnly = function(){ - this.options.asyncOnly = true; - return this; -}; - -/** - * Run tests and invoke `fn()` when complete. - * - * @param {Function} fn - * @return {Runner} - * @api public - */ - -Mocha.prototype.run = function(fn){ - if (this.files.length) this.loadFiles(); - var suite = this.suite; - var options = this.options; - options.files = this.files; - var runner = new exports.Runner(suite); - var reporter = new this._reporter(runner, options); - runner.ignoreLeaks = false !== options.ignoreLeaks; - runner.asyncOnly = options.asyncOnly; - if (options.grep) runner.grep(options.grep, options.invert); - if (options.globals) runner.globals(options.globals); - if (options.growl) this._growl(runner, reporter); - exports.reporters.Base.useColors = options.useColors; - exports.reporters.Base.inlineDiffs = options.useInlineDiffs; - return runner.run(fn); -}; - -}); // module: mocha.js - -require.register("ms.js", function(module, exports, require){ -/** - * Helpers. - */ - -var s = 1000; -var m = s * 60; -var h = m * 60; -var d = h * 24; -var y = d * 365.25; - -/** - * Parse or format the given `val`. - * - * Options: - * - * - `long` verbose formatting [false] - * - * @param {String|Number} val - * @param {Object} options - * @return {String|Number} - * @api public - */ - -module.exports = function(val, options){ - options = options || {}; - if ('string' == typeof val) return parse(val); - return options.long ? longFormat(val) : shortFormat(val); -}; - -/** - * Parse the given `str` and return milliseconds. - * - * @param {String} str - * @return {Number} - * @api private - */ - -function parse(str) { - var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str); - if (!match) return; - var n = parseFloat(match[1]); - var type = (match[2] || 'ms').toLowerCase(); - switch (type) { - case 'years': - case 'year': - case 'y': - return n * y; - case 'days': - case 'day': - case 'd': - return n * d; - case 'hours': - case 'hour': - case 'h': - return n * h; - case 'minutes': - case 'minute': - case 'm': - return n * m; - case 'seconds': - case 'second': - case 's': - return n * s; - case 'ms': - return n; - } -} - -/** - * Short format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function shortFormat(ms) { - if (ms >= d) return Math.round(ms / d) + 'd'; - if (ms >= h) return Math.round(ms / h) + 'h'; - if (ms >= m) return Math.round(ms / m) + 'm'; - if (ms >= s) return Math.round(ms / s) + 's'; - return ms + 'ms'; -} - -/** - * Long format for `ms`. - * - * @param {Number} ms - * @return {String} - * @api private - */ - -function longFormat(ms) { - return plural(ms, d, 'day') - || plural(ms, h, 'hour') - || plural(ms, m, 'minute') - || plural(ms, s, 'second') - || ms + ' ms'; -} - -/** - * Pluralization helper. - */ - -function plural(ms, n, name) { - if (ms < n) return; - if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name; - return Math.ceil(ms / n) + ' ' + name + 's'; -} - -}); // module: ms.js - -require.register("reporters/base.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var tty = require('browser/tty') - , diff = require('browser/diff') - , ms = require('../ms') - , utils = require('../utils'); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Check if both stdio streams are associated with a tty. - */ - -var isatty = tty.isatty(1) && tty.isatty(2); - -/** - * Expose `Base`. - */ - -exports = module.exports = Base; - -/** - * Enable coloring by default. - */ - -exports.useColors = isatty || (process.env.MOCHA_COLORS !== undefined); - -/** - * Inline diffs instead of +/- - */ - -exports.inlineDiffs = false; - -/** - * Default color map. - */ - -exports.colors = { - 'pass': 90 - , 'fail': 31 - , 'bright pass': 92 - , 'bright fail': 91 - , 'bright yellow': 93 - , 'pending': 36 - , 'suite': 0 - , 'error title': 0 - , 'error message': 31 - , 'error stack': 90 - , 'checkmark': 32 - , 'fast': 90 - , 'medium': 33 - , 'slow': 31 - , 'green': 32 - , 'light': 90 - , 'diff gutter': 90 - , 'diff added': 42 - , 'diff removed': 41 -}; - -/** - * Default symbol map. - */ - -exports.symbols = { - ok: '✓', - err: '✖', - dot: '․' -}; - -// With node.js on Windows: use symbols available in terminal default fonts -if ('win32' == process.platform) { - exports.symbols.ok = '\u221A'; - exports.symbols.err = '\u00D7'; - exports.symbols.dot = '.'; -} - -/** - * Color `str` with the given `type`, - * allowing colors to be disabled, - * as well as user-defined color - * schemes. - * - * @param {String} type - * @param {String} str - * @return {String} - * @api private - */ - -var color = exports.color = function(type, str) { - if (!exports.useColors) return str; - return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; -}; - -/** - * Expose term window size, with some - * defaults for when stderr is not a tty. - */ - -exports.window = { - width: isatty - ? process.stdout.getWindowSize - ? process.stdout.getWindowSize(1)[0] - : tty.getWindowSize()[1] - : 75 -}; - -/** - * Expose some basic cursor interactions - * that are common among reporters. - */ - -exports.cursor = { - hide: function(){ - isatty && process.stdout.write('\u001b[?25l'); - }, - - show: function(){ - isatty && process.stdout.write('\u001b[?25h'); - }, - - deleteLine: function(){ - isatty && process.stdout.write('\u001b[2K'); - }, - - beginningOfLine: function(){ - isatty && process.stdout.write('\u001b[0G'); - }, - - CR: function(){ - if (isatty) { - exports.cursor.deleteLine(); - exports.cursor.beginningOfLine(); - } else { - process.stdout.write('\r'); - } - } -}; - -/** - * Outut the given `failures` as a list. - * - * @param {Array} failures - * @api public - */ - -exports.list = function(failures){ - console.error(); - failures.forEach(function(test, i){ - // format - var fmt = color('error title', ' %s) %s:\n') - + color('error message', ' %s') - + color('error stack', '\n%s\n'); - - // msg - var err = test.err - , message = err.message || '' - , stack = err.stack || message - , index = stack.indexOf(message) + message.length - , msg = stack.slice(0, index) - , actual = err.actual - , expected = err.expected - , escape = true; - - // uncaught - if (err.uncaught) { - msg = 'Uncaught ' + msg; - } - - // explicitly show diff - if (err.showDiff && sameType(actual, expected)) { - escape = false; - err.actual = actual = stringify(canonicalize(actual)); - err.expected = expected = stringify(canonicalize(expected)); - } - - // actual / expected diff - if ('string' == typeof actual && 'string' == typeof expected) { - fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); - var match = message.match(/^([^:]+): expected/); - msg = '\n ' + color('error message', match ? match[1] : msg); - - if (exports.inlineDiffs) { - msg += inlineDiff(err, escape); - } else { - msg += unifiedDiff(err, escape); - } - } - - // indent stack trace without msg - stack = stack.slice(index ? index + 1 : index) - .replace(/^/gm, ' '); - - console.error(fmt, (i + 1), test.fullTitle(), msg, stack); - }); -}; - -/** - * Initialize a new `Base` reporter. - * - * All other reporters generally - * inherit from this reporter, providing - * stats such as test duration, number - * of tests passed / failed etc. - * - * @param {Runner} runner - * @api public - */ - -function Base(runner) { - var self = this - , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } - , failures = this.failures = []; - - if (!runner) return; - this.runner = runner; - - runner.stats = stats; - - runner.on('start', function(){ - stats.start = new Date; - }); - - runner.on('suite', function(suite){ - stats.suites = stats.suites || 0; - suite.root || stats.suites++; - }); - - runner.on('test end', function(test){ - stats.tests = stats.tests || 0; - stats.tests++; - }); - - runner.on('pass', function(test){ - stats.passes = stats.passes || 0; - - var medium = test.slow() / 2; - test.speed = test.duration > test.slow() - ? 'slow' - : test.duration > medium - ? 'medium' - : 'fast'; - - stats.passes++; - }); - - runner.on('fail', function(test, err){ - stats.failures = stats.failures || 0; - stats.failures++; - test.err = err; - failures.push(test); - }); - - runner.on('end', function(){ - stats.end = new Date; - stats.duration = new Date - stats.start; - }); - - runner.on('pending', function(){ - stats.pending++; - }); -} - -/** - * Output common epilogue used by many of - * the bundled reporters. - * - * @api public - */ - -Base.prototype.epilogue = function(){ - var stats = this.stats; - var tests; - var fmt; - - console.log(); - - // passes - fmt = color('bright pass', ' ') - + color('green', ' %d passing') - + color('light', ' (%s)'); - - console.log(fmt, - stats.passes || 0, - ms(stats.duration)); - - // pending - if (stats.pending) { - fmt = color('pending', ' ') - + color('pending', ' %d pending'); - - console.log(fmt, stats.pending); - } - - // failures - if (stats.failures) { - fmt = color('fail', ' %d failing'); - - console.error(fmt, - stats.failures); - - Base.list(this.failures); - console.error(); - } - - console.log(); -}; - -/** - * Pad the given `str` to `len`. - * - * @param {String} str - * @param {String} len - * @return {String} - * @api private - */ - -function pad(str, len) { - str = String(str); - return Array(len - str.length + 1).join(' ') + str; -} - - -/** - * Returns an inline diff between 2 strings with coloured ANSI output - * - * @param {Error} Error with actual/expected - * @return {String} Diff - * @api private - */ - -function inlineDiff(err, escape) { - var msg = errorDiff(err, 'WordsWithSpace', escape); - - // linenos - var lines = msg.split('\n'); - if (lines.length > 4) { - var width = String(lines.length).length; - msg = lines.map(function(str, i){ - return pad(++i, width) + ' |' + ' ' + str; - }).join('\n'); - } - - // legend - msg = '\n' - + color('diff removed', 'actual') - + ' ' - + color('diff added', 'expected') - + '\n\n' - + msg - + '\n'; - - // indent - msg = msg.replace(/^/gm, ' '); - return msg; -} - -/** - * Returns a unified diff between 2 strings - * - * @param {Error} Error with actual/expected - * @return {String} Diff - * @api private - */ - -function unifiedDiff(err, escape) { - var indent = ' '; - function cleanUp(line) { - if (escape) { - line = escapeInvisibles(line); - } - if (line[0] === '+') return indent + colorLines('diff added', line); - if (line[0] === '-') return indent + colorLines('diff removed', line); - if (line.match(/\@\@/)) return null; - if (line.match(/\\ No newline/)) return null; - else return indent + line; - } - function notBlank(line) { - return line != null; - } - msg = diff.createPatch('string', err.actual, err.expected); - var lines = msg.split('\n').splice(4); - return '\n ' - + colorLines('diff added', '+ expected') + ' ' - + colorLines('diff removed', '- actual') - + '\n\n' - + lines.map(cleanUp).filter(notBlank).join('\n'); -} - -/** - * Return a character diff for `err`. - * - * @param {Error} err - * @return {String} - * @api private - */ - -function errorDiff(err, type, escape) { - var actual = escape ? escapeInvisibles(err.actual) : err.actual; - var expected = escape ? escapeInvisibles(err.expected) : err.expected; - return diff['diff' + type](actual, expected).map(function(str){ - if (str.added) return colorLines('diff added', str.value); - if (str.removed) return colorLines('diff removed', str.value); - return str.value; - }).join(''); -} - -/** - * Returns a string with all invisible characters in plain text - * - * @param {String} line - * @return {String} - * @api private - */ -function escapeInvisibles(line) { - return line.replace(/\t/g, '') - .replace(/\r/g, '') - .replace(/\n/g, '\n'); -} - -/** - * Color lines for `str`, using the color `name`. - * - * @param {String} name - * @param {String} str - * @return {String} - * @api private - */ - -function colorLines(name, str) { - return str.split('\n').map(function(str){ - return color(name, str); - }).join('\n'); -} - -/** - * Stringify `obj`. - * - * @param {Object} obj - * @return {String} - * @api private - */ - -function stringify(obj) { - if (obj instanceof RegExp) return obj.toString(); - return JSON.stringify(obj, null, 2); -} - -/** - * Return a new object that has the keys in sorted order. - * @param {Object} obj - * @return {Object} - * @api private - */ - - function canonicalize(obj, stack) { - stack = stack || []; - - if (utils.indexOf(stack, obj) !== -1) return obj; - - var canonicalizedObj; - - if ('[object Array]' == {}.toString.call(obj)) { - stack.push(obj); - canonicalizedObj = utils.map(obj, function(item) { - return canonicalize(item, stack); - }); - stack.pop(); - } else if (typeof obj === 'object' && obj !== null) { - stack.push(obj); - canonicalizedObj = {}; - utils.forEach(utils.keys(obj).sort(), function(key) { - canonicalizedObj[key] = canonicalize(obj[key], stack); - }); - stack.pop(); - } else { - canonicalizedObj = obj; - } - - return canonicalizedObj; - } - -/** - * Check that a / b have the same type. - * - * @param {Object} a - * @param {Object} b - * @return {Boolean} - * @api private - */ - -function sameType(a, b) { - a = Object.prototype.toString.call(a); - b = Object.prototype.toString.call(b); - return a == b; -} - - -}); // module: reporters/base.js - -require.register("reporters/doc.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils'); - -/** - * Expose `Doc`. - */ - -exports = module.exports = Doc; - -/** - * Initialize a new `Doc` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Doc(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total - , indents = 2; - - function indent() { - return Array(indents).join(' '); - } - - runner.on('suite', function(suite){ - if (suite.root) return; - ++indents; - console.log('%s
    ', indent()); - ++indents; - console.log('%s

    %s

    ', indent(), utils.escape(suite.title)); - console.log('%s
    ', indent()); - }); - - runner.on('suite end', function(suite){ - if (suite.root) return; - console.log('%s
    ', indent()); - --indents; - console.log('%s
    ', indent()); - --indents; - }); - - runner.on('pass', function(test){ - console.log('%s
    %s
    ', indent(), utils.escape(test.title)); - var code = utils.escape(utils.clean(test.fn.toString())); - console.log('%s
    %s
    ', indent(), code); - }); -} - -}); // module: reporters/doc.js - -require.register("reporters/dot.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , color = Base.color; - -/** - * Expose `Dot`. - */ - -exports = module.exports = Dot; - -/** - * Initialize a new `Dot` matrix test reporter. - * - * @param {Runner} runner - * @api public - */ - -function Dot(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , n = 0; - - runner.on('start', function(){ - process.stdout.write('\n '); - }); - - runner.on('pending', function(test){ - process.stdout.write(color('pending', Base.symbols.dot)); - }); - - runner.on('pass', function(test){ - if (++n % width == 0) process.stdout.write('\n '); - if ('slow' == test.speed) { - process.stdout.write(color('bright yellow', Base.symbols.dot)); - } else { - process.stdout.write(color(test.speed, Base.symbols.dot)); - } - }); - - runner.on('fail', function(test, err){ - if (++n % width == 0) process.stdout.write('\n '); - process.stdout.write(color('fail', Base.symbols.dot)); - }); - - runner.on('end', function(){ - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -Dot.prototype = new F; -Dot.prototype.constructor = Dot; - -}); // module: reporters/dot.js - -require.register("reporters/html-cov.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var JSONCov = require('./json-cov') - , fs = require('browser/fs'); - -/** - * Expose `HTMLCov`. - */ - -exports = module.exports = HTMLCov; - -/** - * Initialize a new `JsCoverage` reporter. - * - * @param {Runner} runner - * @api public - */ - -function HTMLCov(runner) { - var jade = require('jade') - , file = __dirname + '/templates/coverage.jade' - , str = fs.readFileSync(file, 'utf8') - , fn = jade.compile(str, { filename: file }) - , self = this; - - JSONCov.call(this, runner, false); - - runner.on('end', function(){ - process.stdout.write(fn({ - cov: self.cov - , coverageClass: coverageClass - })); - }); -} - -/** - * Return coverage class for `n`. - * - * @return {String} - * @api private - */ - -function coverageClass(n) { - if (n >= 75) return 'high'; - if (n >= 50) return 'medium'; - if (n >= 25) return 'low'; - return 'terrible'; -} -}); // module: reporters/html-cov.js - -require.register("reporters/html.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils') - , Progress = require('../browser/progress') - , escape = utils.escape; - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Expose `HTML`. - */ - -exports = module.exports = HTML; - -/** - * Stats template. - */ - -var statsTemplate = ''; - -/** - * Initialize a new `HTML` reporter. - * - * @param {Runner} runner - * @api public - */ - -function HTML(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total - , stat = fragment(statsTemplate) - , items = stat.getElementsByTagName('li') - , passes = items[1].getElementsByTagName('em')[0] - , passesLink = items[1].getElementsByTagName('a')[0] - , failures = items[2].getElementsByTagName('em')[0] - , failuresLink = items[2].getElementsByTagName('a')[0] - , duration = items[3].getElementsByTagName('em')[0] - , canvas = stat.getElementsByTagName('canvas')[0] - , report = fragment('
      ') - , stack = [report] - , progress - , ctx - , root = document.getElementById('mocha'); - - if (canvas.getContext) { - var ratio = window.devicePixelRatio || 1; - canvas.style.width = canvas.width; - canvas.style.height = canvas.height; - canvas.width *= ratio; - canvas.height *= ratio; - ctx = canvas.getContext('2d'); - ctx.scale(ratio, ratio); - progress = new Progress; - } - - if (!root) return error('#mocha div missing, add it to your document'); - - // pass toggle - on(passesLink, 'click', function(){ - unhide(); - var name = /pass/.test(report.className) ? '' : ' pass'; - report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) hideSuitesWithout('test pass'); - }); - - // failure toggle - on(failuresLink, 'click', function(){ - unhide(); - var name = /fail/.test(report.className) ? '' : ' fail'; - report.className = report.className.replace(/fail|pass/g, '') + name; - if (report.className.trim()) hideSuitesWithout('test fail'); - }); - - root.appendChild(stat); - root.appendChild(report); - - if (progress) progress.size(40); - - runner.on('suite', function(suite){ - if (suite.root) return; - - // suite - var url = self.suiteURL(suite); - var el = fragment('
    • %s

    • ', url, escape(suite.title)); - - // container - stack[0].appendChild(el); - stack.unshift(document.createElement('ul')); - el.appendChild(stack[0]); - }); - - runner.on('suite end', function(suite){ - if (suite.root) return; - stack.shift(); - }); - - runner.on('fail', function(test, err){ - if ('hook' == test.type) runner.emit('test end', test); - }); - - runner.on('test end', function(test){ - // TODO: add to stats - var percent = stats.tests / this.total * 100 | 0; - if (progress) progress.update(percent).draw(ctx); - - // update stats - var ms = new Date - stats.start; - text(passes, stats.passes); - text(failures, stats.failures); - text(duration, (ms / 1000).toFixed(2)); - - // test - if ('passed' == test.state) { - var url = self.testURL(test); - var el = fragment('
    • %e%ems

    • ', test.speed, test.title, test.duration, url); - } else if (test.pending) { - var el = fragment('
    • %e

    • ', test.title); - } else { - var el = fragment('
    • %e

    • ', test.title, encodeURIComponent(test.fullTitle())); - var str = test.err.stack || test.err.toString(); - - // FF / Opera do not add the message - if (!~str.indexOf(test.err.message)) { - str = test.err.message + '\n' + str; - } - - // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we - // check for the result of the stringifying. - if ('[object Error]' == str) str = test.err.message; - - // Safari doesn't give you a stack. Let's at least provide a source line. - if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { - str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; - } - - el.appendChild(fragment('
      %e
      ', str)); - } - - // toggle code - // TODO: defer - if (!test.pending) { - var h2 = el.getElementsByTagName('h2')[0]; - - on(h2, 'click', function(){ - pre.style.display = 'none' == pre.style.display - ? 'block' - : 'none'; - }); - - var pre = fragment('
      %e
      ', utils.clean(test.fn.toString())); - el.appendChild(pre); - pre.style.display = 'none'; - } - - // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. - if (stack[0]) stack[0].appendChild(el); - }); -} - -/** - * Provide suite URL - * - * @param {Object} [suite] - */ - -HTML.prototype.suiteURL = function(suite){ - return '?grep=' + encodeURIComponent(suite.fullTitle()); -}; - -/** - * Provide test URL - * - * @param {Object} [test] - */ - -HTML.prototype.testURL = function(test){ - return '?grep=' + encodeURIComponent(test.fullTitle()); -}; - -/** - * Display error `msg`. - */ - -function error(msg) { - document.body.appendChild(fragment('
      %s
      ', msg)); -} - -/** - * Return a DOM fragment from `html`. - */ - -function fragment(html) { - var args = arguments - , div = document.createElement('div') - , i = 1; - - div.innerHTML = html.replace(/%([se])/g, function(_, type){ - switch (type) { - case 's': return String(args[i++]); - case 'e': return escape(args[i++]); - } - }); - - return div.firstChild; -} - -/** - * Check for suites that do not have elements - * with `classname`, and hide them. - */ - -function hideSuitesWithout(classname) { - var suites = document.getElementsByClassName('suite'); - for (var i = 0; i < suites.length; i++) { - var els = suites[i].getElementsByClassName(classname); - if (0 == els.length) suites[i].className += ' hidden'; - } -} - -/** - * Unhide .hidden suites. - */ - -function unhide() { - var els = document.getElementsByClassName('suite hidden'); - for (var i = 0; i < els.length; ++i) { - els[i].className = els[i].className.replace('suite hidden', 'suite'); - } -} - -/** - * Set `el` text to `str`. - */ - -function text(el, str) { - if (el.textContent) { - el.textContent = str; - } else { - el.innerText = str; - } -} - -/** - * Listen on `event` with callback `fn`. - */ - -function on(el, event, fn) { - if (el.addEventListener) { - el.addEventListener(event, fn, false); - } else { - el.attachEvent('on' + event, fn); - } -} - -}); // module: reporters/html.js - -require.register("reporters/index.js", function(module, exports, require){ - -exports.Base = require('./base'); -exports.Dot = require('./dot'); -exports.Doc = require('./doc'); -exports.TAP = require('./tap'); -exports.JSON = require('./json'); -exports.HTML = require('./html'); -exports.List = require('./list'); -exports.Min = require('./min'); -exports.Spec = require('./spec'); -exports.Nyan = require('./nyan'); -exports.XUnit = require('./xunit'); -exports.Markdown = require('./markdown'); -exports.Progress = require('./progress'); -exports.Landing = require('./landing'); -exports.JSONCov = require('./json-cov'); -exports.HTMLCov = require('./html-cov'); -exports.JSONStream = require('./json-stream'); - -}); // module: reporters/index.js - -require.register("reporters/json-cov.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `JSONCov`. - */ - -exports = module.exports = JSONCov; - -/** - * Initialize a new `JsCoverage` reporter. - * - * @param {Runner} runner - * @param {Boolean} output - * @api public - */ - -function JSONCov(runner, output) { - var self = this - , output = 1 == arguments.length ? true : output; - - Base.call(this, runner); - - var tests = [] - , failures = [] - , passes = []; - - runner.on('test end', function(test){ - tests.push(test); - }); - - runner.on('pass', function(test){ - passes.push(test); - }); - - runner.on('fail', function(test){ - failures.push(test); - }); - - runner.on('end', function(){ - var cov = global._$jscoverage || {}; - var result = self.cov = map(cov); - result.stats = self.stats; - result.tests = tests.map(clean); - result.failures = failures.map(clean); - result.passes = passes.map(clean); - if (!output) return; - process.stdout.write(JSON.stringify(result, null, 2 )); - }); -} - -/** - * Map jscoverage data to a JSON structure - * suitable for reporting. - * - * @param {Object} cov - * @return {Object} - * @api private - */ - -function map(cov) { - var ret = { - instrumentation: 'node-jscoverage' - , sloc: 0 - , hits: 0 - , misses: 0 - , coverage: 0 - , files: [] - }; - - for (var filename in cov) { - var data = coverage(filename, cov[filename]); - ret.files.push(data); - ret.hits += data.hits; - ret.misses += data.misses; - ret.sloc += data.sloc; - } - - ret.files.sort(function(a, b) { - return a.filename.localeCompare(b.filename); - }); - - if (ret.sloc > 0) { - ret.coverage = (ret.hits / ret.sloc) * 100; - } - - return ret; -}; - -/** - * Map jscoverage data for a single source file - * to a JSON structure suitable for reporting. - * - * @param {String} filename name of the source file - * @param {Object} data jscoverage coverage data - * @return {Object} - * @api private - */ - -function coverage(filename, data) { - var ret = { - filename: filename, - coverage: 0, - hits: 0, - misses: 0, - sloc: 0, - source: {} - }; - - data.source.forEach(function(line, num){ - num++; - - if (data[num] === 0) { - ret.misses++; - ret.sloc++; - } else if (data[num] !== undefined) { - ret.hits++; - ret.sloc++; - } - - ret.source[num] = { - source: line - , coverage: data[num] === undefined - ? '' - : data[num] - }; - }); - - ret.coverage = ret.hits / ret.sloc * 100; - - return ret; -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } -} - -}); // module: reporters/json-cov.js - -require.register("reporters/json-stream.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , color = Base.color; - -/** - * Expose `List`. - */ - -exports = module.exports = List; - -/** - * Initialize a new `List` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function List(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , total = runner.total; - - runner.on('start', function(){ - console.log(JSON.stringify(['start', { total: total }])); - }); - - runner.on('pass', function(test){ - console.log(JSON.stringify(['pass', clean(test)])); - }); - - runner.on('fail', function(test, err){ - console.log(JSON.stringify(['fail', clean(test)])); - }); - - runner.on('end', function(){ - process.stdout.write(JSON.stringify(['end', self.stats])); - }); -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } -} -}); // module: reporters/json-stream.js - -require.register("reporters/json.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `JSON`. - */ - -exports = module.exports = JSONReporter; - -/** - * Initialize a new `JSON` reporter. - * - * @param {Runner} runner - * @api public - */ - -function JSONReporter(runner) { - var self = this; - Base.call(this, runner); - - var tests = [] - , failures = [] - , passes = []; - - runner.on('test end', function(test){ - tests.push(test); - }); - - runner.on('pass', function(test){ - passes.push(test); - }); - - runner.on('fail', function(test){ - failures.push(test); - }); - - runner.on('end', function(){ - var obj = { - stats: self.stats - , tests: tests.map(clean) - , failures: failures.map(clean) - , passes: passes.map(clean) - }; - - process.stdout.write(JSON.stringify(obj, null, 2)); - }); -} - -/** - * Return a plain-object representation of `test` - * free of cyclic properties etc. - * - * @param {Object} test - * @return {Object} - * @api private - */ - -function clean(test) { - return { - title: test.title - , fullTitle: test.fullTitle() - , duration: test.duration - } -} -}); // module: reporters/json.js - -require.register("reporters/landing.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `Landing`. - */ - -exports = module.exports = Landing; - -/** - * Airplane color. - */ - -Base.colors.plane = 0; - -/** - * Airplane crash color. - */ - -Base.colors['plane crash'] = 31; - -/** - * Runway color. - */ - -Base.colors.runway = 90; - -/** - * Initialize a new `Landing` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Landing(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , total = runner.total - , stream = process.stdout - , plane = color('plane', '✈') - , crashed = -1 - , n = 0; - - function runway() { - var buf = Array(width).join('-'); - return ' ' + color('runway', buf); - } - - runner.on('start', function(){ - stream.write('\n '); - cursor.hide(); - }); - - runner.on('test end', function(test){ - // check if the plane crashed - var col = -1 == crashed - ? width * ++n / total | 0 - : crashed; - - // show the crash - if ('failed' == test.state) { - plane = color('plane crash', '✈'); - crashed = col; - } - - // render landing strip - stream.write('\u001b[4F\n\n'); - stream.write(runway()); - stream.write('\n '); - stream.write(color('runway', Array(col).join('⋅'))); - stream.write(plane) - stream.write(color('runway', Array(width - col).join('⋅') + '\n')); - stream.write(runway()); - stream.write('\u001b[0m'); - }); - - runner.on('end', function(){ - cursor.show(); - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -Landing.prototype = new F; -Landing.prototype.constructor = Landing; - -}); // module: reporters/landing.js - -require.register("reporters/list.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `List`. - */ - -exports = module.exports = List; - -/** - * Initialize a new `List` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function List(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , n = 0; - - runner.on('start', function(){ - console.log(); - }); - - runner.on('test', function(test){ - process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); - }); - - runner.on('pending', function(test){ - var fmt = color('checkmark', ' -') - + color('pending', ' %s'); - console.log(fmt, test.fullTitle()); - }); - - runner.on('pass', function(test){ - var fmt = color('checkmark', ' '+Base.symbols.dot) - + color('pass', ' %s: ') - + color(test.speed, '%dms'); - cursor.CR(); - console.log(fmt, test.fullTitle(), test.duration); - }); - - runner.on('fail', function(test, err){ - cursor.CR(); - console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); - }); - - runner.on('end', self.epilogue.bind(self)); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -List.prototype = new F; -List.prototype.constructor = List; - - -}); // module: reporters/list.js - -require.register("reporters/markdown.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils'); - -/** - * Expose `Markdown`. - */ - -exports = module.exports = Markdown; - -/** - * Initialize a new `Markdown` reporter. - * - * @param {Runner} runner - * @api public - */ - -function Markdown(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , level = 0 - , buf = ''; - - function title(str) { - return Array(level).join('#') + ' ' + str; - } - - function indent() { - return Array(level).join(' '); - } - - function mapTOC(suite, obj) { - var ret = obj; - obj = obj[suite.title] = obj[suite.title] || { suite: suite }; - suite.suites.forEach(function(suite){ - mapTOC(suite, obj); - }); - return ret; - } - - function stringifyTOC(obj, level) { - ++level; - var buf = ''; - var link; - for (var key in obj) { - if ('suite' == key) continue; - if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; - if (key) buf += Array(level).join(' ') + link; - buf += stringifyTOC(obj[key], level); - } - --level; - return buf; - } - - function generateTOC(suite) { - var obj = mapTOC(suite, {}); - return stringifyTOC(obj, 0); - } - - generateTOC(runner.suite); - - runner.on('suite', function(suite){ - ++level; - var slug = utils.slug(suite.fullTitle()); - buf += '' + '\n'; - buf += title(suite.title) + '\n'; - }); - - runner.on('suite end', function(suite){ - --level; - }); - - runner.on('pass', function(test){ - var code = utils.clean(test.fn.toString()); - buf += test.title + '.\n'; - buf += '\n```js\n'; - buf += code + '\n'; - buf += '```\n\n'; - }); - - runner.on('end', function(){ - process.stdout.write('# TOC\n'); - process.stdout.write(generateTOC(runner.suite)); - process.stdout.write(buf); - }); -} -}); // module: reporters/markdown.js - -require.register("reporters/min.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base'); - -/** - * Expose `Min`. - */ - -exports = module.exports = Min; - -/** - * Initialize a new `Min` minimal test reporter (best used with --watch). - * - * @param {Runner} runner - * @api public - */ - -function Min(runner) { - Base.call(this, runner); - - runner.on('start', function(){ - // clear screen - process.stdout.write('\u001b[2J'); - // set cursor position - process.stdout.write('\u001b[1;3H'); - }); - - runner.on('end', this.epilogue.bind(this)); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -Min.prototype = new F; -Min.prototype.constructor = Min; - - -}); // module: reporters/min.js - -require.register("reporters/nyan.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var Base = require('./base') - , color = Base.color; - -/** - * Expose `Dot`. - */ - -exports = module.exports = NyanCat; - -/** - * Initialize a new `Dot` matrix test reporter. - * - * @param {Runner} runner - * @api public - */ - -function NyanCat(runner) { - Base.call(this, runner); - var self = this - , stats = this.stats - , width = Base.window.width * .75 | 0 - , rainbowColors = this.rainbowColors = self.generateColors() - , colorIndex = this.colorIndex = 0 - , numerOfLines = this.numberOfLines = 4 - , trajectories = this.trajectories = [[], [], [], []] - , nyanCatWidth = this.nyanCatWidth = 11 - , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth) - , scoreboardWidth = this.scoreboardWidth = 5 - , tick = this.tick = 0 - , n = 0; - - runner.on('start', function(){ - Base.cursor.hide(); - self.draw(); - }); - - runner.on('pending', function(test){ - self.draw(); - }); - - runner.on('pass', function(test){ - self.draw(); - }); - - runner.on('fail', function(test, err){ - self.draw(); - }); - - runner.on('end', function(){ - Base.cursor.show(); - for (var i = 0; i < self.numberOfLines; i++) write('\n'); - self.epilogue(); - }); -} - -/** - * Draw the nyan cat - * - * @api private - */ - -NyanCat.prototype.draw = function(){ - this.appendRainbow(); - this.drawScoreboard(); - this.drawRainbow(); - this.drawNyanCat(); - this.tick = !this.tick; -}; - -/** - * Draw the "scoreboard" showing the number - * of passes, failures and pending tests. - * - * @api private - */ - -NyanCat.prototype.drawScoreboard = function(){ - var stats = this.stats; - var colors = Base.colors; - - function draw(color, n) { - write(' '); - write('\u001b[' + color + 'm' + n + '\u001b[0m'); - write('\n'); - } - - draw(colors.green, stats.passes); - draw(colors.fail, stats.failures); - draw(colors.pending, stats.pending); - write('\n'); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Append the rainbow. - * - * @api private - */ - -NyanCat.prototype.appendRainbow = function(){ - var segment = this.tick ? '_' : '-'; - var rainbowified = this.rainbowify(segment); - - for (var index = 0; index < this.numberOfLines; index++) { - var trajectory = this.trajectories[index]; - if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift(); - trajectory.push(rainbowified); - } -}; - -/** - * Draw the rainbow. - * - * @api private - */ - -NyanCat.prototype.drawRainbow = function(){ - var self = this; - - this.trajectories.forEach(function(line, index) { - write('\u001b[' + self.scoreboardWidth + 'C'); - write(line.join('')); - write('\n'); - }); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Draw the nyan cat - * - * @api private - */ - -NyanCat.prototype.drawNyanCat = function() { - var self = this; - var startWidth = this.scoreboardWidth + this.trajectories[0].length; - var color = '\u001b[' + startWidth + 'C'; - var padding = ''; - - write(color); - write('_,------,'); - write('\n'); - - write(color); - padding = self.tick ? ' ' : ' '; - write('_|' + padding + '/\\_/\\ '); - write('\n'); - - write(color); - padding = self.tick ? '_' : '__'; - var tail = self.tick ? '~' : '^'; - var face; - write(tail + '|' + padding + this.face() + ' '); - write('\n'); - - write(color); - padding = self.tick ? ' ' : ' '; - write(padding + '"" "" '); - write('\n'); - - this.cursorUp(this.numberOfLines); -}; - -/** - * Draw nyan cat face. - * - * @return {String} - * @api private - */ - -NyanCat.prototype.face = function() { - var stats = this.stats; - if (stats.failures) { - return '( x .x)'; - } else if (stats.pending) { - return '( o .o)'; - } else if(stats.passes) { - return '( ^ .^)'; - } else { - return '( - .-)'; - } -} - -/** - * Move cursor up `n`. - * - * @param {Number} n - * @api private - */ - -NyanCat.prototype.cursorUp = function(n) { - write('\u001b[' + n + 'A'); -}; - -/** - * Move cursor down `n`. - * - * @param {Number} n - * @api private - */ - -NyanCat.prototype.cursorDown = function(n) { - write('\u001b[' + n + 'B'); -}; - -/** - * Generate rainbow colors. - * - * @return {Array} - * @api private - */ - -NyanCat.prototype.generateColors = function(){ - var colors = []; - - for (var i = 0; i < (6 * 7); i++) { - var pi3 = Math.floor(Math.PI / 3); - var n = (i * (1.0 / 6)); - var r = Math.floor(3 * Math.sin(n) + 3); - var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); - var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); - colors.push(36 * r + 6 * g + b + 16); - } - - return colors; -}; - -/** - * Apply rainbow to the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -NyanCat.prototype.rainbowify = function(str){ - var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; - this.colorIndex += 1; - return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; -}; - -/** - * Stdout helper. - */ - -function write(string) { - process.stdout.write(string); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -NyanCat.prototype = new F; -NyanCat.prototype.constructor = NyanCat; - - -}); // module: reporters/nyan.js - -require.register("reporters/progress.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `Progress`. - */ - -exports = module.exports = Progress; - -/** - * General progress bar color. - */ - -Base.colors.progress = 90; - -/** - * Initialize a new `Progress` bar test reporter. - * - * @param {Runner} runner - * @param {Object} options - * @api public - */ - -function Progress(runner, options) { - Base.call(this, runner); - - var self = this - , options = options || {} - , stats = this.stats - , width = Base.window.width * .50 | 0 - , total = runner.total - , complete = 0 - , max = Math.max; - - // default chars - options.open = options.open || '['; - options.complete = options.complete || '▬'; - options.incomplete = options.incomplete || Base.symbols.dot; - options.close = options.close || ']'; - options.verbose = false; - - // tests started - runner.on('start', function(){ - console.log(); - cursor.hide(); - }); - - // tests complete - runner.on('test end', function(){ - complete++; - var incomplete = total - complete - , percent = complete / total - , n = width * percent | 0 - , i = width - n; - - cursor.CR(); - process.stdout.write('\u001b[J'); - process.stdout.write(color('progress', ' ' + options.open)); - process.stdout.write(Array(n).join(options.complete)); - process.stdout.write(Array(i).join(options.incomplete)); - process.stdout.write(color('progress', options.close)); - if (options.verbose) { - process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); - } - }); - - // tests are complete, output some stats - // and the failures if any - runner.on('end', function(){ - cursor.show(); - console.log(); - self.epilogue(); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -Progress.prototype = new F; -Progress.prototype.constructor = Progress; - - -}); // module: reporters/progress.js - -require.register("reporters/spec.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `Spec`. - */ - -exports = module.exports = Spec; - -/** - * Initialize a new `Spec` test reporter. - * - * @param {Runner} runner - * @api public - */ - -function Spec(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , indents = 0 - , n = 0; - - function indent() { - return Array(indents).join(' ') - } - - runner.on('start', function(){ - console.log(); - }); - - runner.on('suite', function(suite){ - ++indents; - console.log(color('suite', '%s%s'), indent(), suite.title); - }); - - runner.on('suite end', function(suite){ - --indents; - if (1 == indents) console.log(); - }); - - runner.on('pending', function(test){ - var fmt = indent() + color('pending', ' - %s'); - console.log(fmt, test.title); - }); - - runner.on('pass', function(test){ - if ('fast' == test.speed) { - var fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s '); - cursor.CR(); - console.log(fmt, test.title); - } else { - var fmt = indent() - + color('checkmark', ' ' + Base.symbols.ok) - + color('pass', ' %s ') - + color(test.speed, '(%dms)'); - cursor.CR(); - console.log(fmt, test.title, test.duration); - } - }); - - runner.on('fail', function(test, err){ - cursor.CR(); - console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); - }); - - runner.on('end', self.epilogue.bind(self)); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -Spec.prototype = new F; -Spec.prototype.constructor = Spec; - - -}); // module: reporters/spec.js - -require.register("reporters/tap.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , cursor = Base.cursor - , color = Base.color; - -/** - * Expose `TAP`. - */ - -exports = module.exports = TAP; - -/** - * Initialize a new `TAP` reporter. - * - * @param {Runner} runner - * @api public - */ - -function TAP(runner) { - Base.call(this, runner); - - var self = this - , stats = this.stats - , n = 1 - , passes = 0 - , failures = 0; - - runner.on('start', function(){ - var total = runner.grepTotal(runner.suite); - console.log('%d..%d', 1, total); - }); - - runner.on('test end', function(){ - ++n; - }); - - runner.on('pending', function(test){ - console.log('ok %d %s # SKIP -', n, title(test)); - }); - - runner.on('pass', function(test){ - passes++; - console.log('ok %d %s', n, title(test)); - }); - - runner.on('fail', function(test, err){ - failures++; - console.log('not ok %d %s', n, title(test)); - if (err.stack) console.log(err.stack.replace(/^/gm, ' ')); - }); - - runner.on('end', function(){ - console.log('# tests ' + (passes + failures)); - console.log('# pass ' + passes); - console.log('# fail ' + failures); - }); -} - -/** - * Return a TAP-safe title of `test` - * - * @param {Object} test - * @return {String} - * @api private - */ - -function title(test) { - return test.fullTitle().replace(/#/g, ''); -} - -}); // module: reporters/tap.js - -require.register("reporters/xunit.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Base = require('./base') - , utils = require('../utils') - , escape = utils.escape; - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Expose `XUnit`. - */ - -exports = module.exports = XUnit; - -/** - * Initialize a new `XUnit` reporter. - * - * @param {Runner} runner - * @api public - */ - -function XUnit(runner) { - Base.call(this, runner); - var stats = this.stats - , tests = [] - , self = this; - - runner.on('pending', function(test){ - tests.push(test); - }); - - runner.on('pass', function(test){ - tests.push(test); - }); - - runner.on('fail', function(test){ - tests.push(test); - }); - - runner.on('end', function(){ - console.log(tag('testsuite', { - name: 'Mocha Tests' - , tests: stats.tests - , failures: stats.failures - , errors: stats.failures - , skipped: stats.tests - stats.failures - stats.passes - , timestamp: (new Date).toUTCString() - , time: (stats.duration / 1000) || 0 - }, false)); - - tests.forEach(test); - console.log(''); - }); -} - -/** - * Inherit from `Base.prototype`. - */ - -function F(){}; -F.prototype = Base.prototype; -XUnit.prototype = new F; -XUnit.prototype.constructor = XUnit; - - -/** - * Output tag for the given `test.` - */ - -function test(test) { - var attrs = { - classname: test.parent.fullTitle() - , name: test.title - , time: (test.duration / 1000) || 0 - }; - - if ('failed' == test.state) { - var err = test.err; - attrs.message = escape(err.message); - console.log(tag('testcase', attrs, false, tag('failure', attrs, false, cdata(err.stack)))); - } else if (test.pending) { - console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); - } else { - console.log(tag('testcase', attrs, true) ); - } -} - -/** - * HTML tag helper. - */ - -function tag(name, attrs, close, content) { - var end = close ? '/>' : '>' - , pairs = [] - , tag; - - for (var key in attrs) { - pairs.push(key + '="' + escape(attrs[key]) + '"'); - } - - tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; - if (content) tag += content + ''; -} - -}); // module: reporters/xunit.js - -require.register("runnable.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('mocha:runnable') - , milliseconds = require('./ms'); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date - , setTimeout = global.setTimeout - , setInterval = global.setInterval - , clearTimeout = global.clearTimeout - , clearInterval = global.clearInterval; - -/** - * Object#toString(). - */ - -var toString = Object.prototype.toString; - -/** - * Expose `Runnable`. - */ - -module.exports = Runnable; - -/** - * Initialize a new `Runnable` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Runnable(title, fn) { - this.title = title; - this.fn = fn; - this.async = fn && fn.length; - this.sync = ! this.async; - this._timeout = 2000; - this._slow = 75; - this.timedOut = false; -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -function F(){}; -F.prototype = EventEmitter.prototype; -Runnable.prototype = new F; -Runnable.prototype.constructor = Runnable; - - -/** - * Set & get timeout `ms`. - * - * @param {Number|String} ms - * @return {Runnable|Number} ms or self - * @api private - */ - -Runnable.prototype.timeout = function(ms){ - if (0 == arguments.length) return this._timeout; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._timeout = ms; - if (this.timer) this.resetTimeout(); - return this; -}; - -/** - * Set & get slow `ms`. - * - * @param {Number|String} ms - * @return {Runnable|Number} ms or self - * @api private - */ - -Runnable.prototype.slow = function(ms){ - if (0 === arguments.length) return this._slow; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._slow = ms; - return this; -}; - -/** - * Return the full title generated by recursively - * concatenating the parent's full title. - * - * @return {String} - * @api public - */ - -Runnable.prototype.fullTitle = function(){ - return this.parent.fullTitle() + ' ' + this.title; -}; - -/** - * Clear the timeout. - * - * @api private - */ - -Runnable.prototype.clearTimeout = function(){ - clearTimeout(this.timer); -}; - -/** - * Inspect the runnable void of private properties. - * - * @return {String} - * @api private - */ - -Runnable.prototype.inspect = function(){ - return JSON.stringify(this, function(key, val){ - if ('_' == key[0]) return; - if ('parent' == key) return '#'; - if ('ctx' == key) return '#'; - return val; - }, 2); -}; - -/** - * Reset the timeout. - * - * @api private - */ - -Runnable.prototype.resetTimeout = function(){ - var self = this; - var max_timeout = 10000;//default 10s - if (window && window.__mocha_max_timeout){ - max_timeout = window.__mocha_max_timeout; - } - var ms = this.timeout() || max_timeout; - if (ms > max_timeout){ - ms = max_timeout; - } - - this.clearTimeout(); - this.timer = setTimeout(function(){ - self.callback(new Error('timeout of ' + ms + 'ms exceeded')); - self.timedOut = true; - }, ms); -}; - -/** - * Whitelist these globals for this test run - * - * @api private - */ -Runnable.prototype.globals = function(arr){ - var self = this; - this._allowedGlobals = arr; -}; - -/** - * Run the test and invoke `fn(err)`. - * - * @param {Function} fn - * @api private - */ - -Runnable.prototype.run = function(fn){ - var self = this - , ms = this.timeout() - , start = new Date - , ctx = this.ctx - , finished - , emitted; - - if (ctx) ctx.runnable(this); - - // called multiple times - function multiple(err) { - if (emitted) return; - emitted = true; - self.emit('error', err || new Error('done() called multiple times')); - } - - // finished - function done(err) { - if (self.timedOut) return; - if (finished) return multiple(err); - self.clearTimeout(); - self.duration = new Date - start; - finished = true; - fn(err); - } - - // for .resetTimeout() - this.callback = done; - - // explicit async with `done` argument - if (this.async) { - this.resetTimeout(); - - try { - this.fn.call(ctx, function(err){ - if (err instanceof Error || toString.call(err) === "[object Error]") return done(err); - if (null != err) return done(new Error('done() invoked with non-Error: ' + err)); - done(); - }); - } catch (err) { - done(err); - } - return; - } - - if (this.asyncOnly) { - return done(new Error('--async-only option in use without declaring `done()`')); - } - - // sync or promise-returning - try { - if (this.pending) { - done(); - } else { - callFn(this.fn); - } - } catch (err) { - done(err); - } - - function callFn(fn) { - var result = fn.call(ctx); - if (result && typeof result.then === 'function') { - self.resetTimeout(); - result.then(function(){ done() }, done); - } else { - done(); - } - } -}; - -}); // module: runnable.js - -require.register("runner.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('mocha:runner') - , Test = require('./test') - , utils = require('./utils') - , filter = utils.filter - , keys = utils.keys; - -/** - * Non-enumerable globals. - */ - -var globals = [ - 'setTimeout', - 'clearTimeout', - 'setInterval', - 'clearInterval', - 'XMLHttpRequest', - 'Date' -]; - -/** - * Expose `Runner`. - */ - -module.exports = Runner; - -/** - * Initialize a `Runner` for the given `suite`. - * - * Events: - * - * - `start` execution started - * - `end` execution complete - * - `suite` (suite) test suite execution started - * - `suite end` (suite) all tests (and sub-suites) have finished - * - `test` (test) test execution started - * - `test end` (test) test completed - * - `hook` (hook) hook execution started - * - `hook end` (hook) hook complete - * - `pass` (test) test passed - * - `fail` (test, err) test failed - * - `pending` (test) test pending - * - * @api public - */ - -function Runner(suite) { - var self = this; - this._globals = []; - this._abort = false; - this.suite = suite; - this.total = suite.total(); - this.failures = 0; - this.on('test end', function(test){ self.checkGlobals(test); }); - this.on('hook end', function(hook){ self.checkGlobals(hook); }); - this.grep(/.*/); - this.globals(this.globalProps().concat(extraGlobals())); -} - -/** - * Wrapper for setImmediate, process.nextTick, or browser polyfill. - * - * @param {Function} fn - * @api private - */ - -Runner.immediately = global.setImmediate || process.nextTick; - -/** - * Inherit from `EventEmitter.prototype`. - */ - -function F(){}; -F.prototype = EventEmitter.prototype; -Runner.prototype = new F; -Runner.prototype.constructor = Runner; - - -/** - * Run tests with full titles matching `re`. Updates runner.total - * with number of tests matched. - * - * @param {RegExp} re - * @param {Boolean} invert - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.grep = function(re, invert){ - debug('grep %s', re); - this._grep = re; - this._invert = invert; - this.total = this.grepTotal(this.suite); - return this; -}; - -/** - * Returns the number of tests matching the grep search for the - * given suite. - * - * @param {Suite} suite - * @return {Number} - * @api public - */ - -Runner.prototype.grepTotal = function(suite) { - var self = this; - var total = 0; - - suite.eachTest(function(test){ - var match = self._grep.test(test.fullTitle()); - if (self._invert) match = !match; - if (match) total++; - }); - - return total; -}; - -/** - * Return a list of global properties. - * - * @return {Array} - * @api private - */ - -Runner.prototype.globalProps = function() { - var props = utils.keys(global); - - // non-enumerables - for (var i = 0; i < globals.length; ++i) { - if (~utils.indexOf(props, globals[i])) continue; - props.push(globals[i]); - } - - return props; -}; - -/** - * Allow the given `arr` of globals. - * - * @param {Array} arr - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.globals = function(arr){ - if (0 == arguments.length) return this._globals; - debug('globals %j', arr); - this._globals = this._globals.concat(arr); - return this; -}; - -/** - * Check for global variable leaks. - * - * @api private - */ - -Runner.prototype.checkGlobals = function(test){ - if (this.ignoreLeaks) return; - var ok = this._globals; - - var globals = this.globalProps(); - var isNode = process.kill; - var leaks; - - if (test) { - ok = ok.concat(test._allowedGlobals || []); - } - - if(this.prevGlobalsLength == globals.length) return; - this.prevGlobalsLength = globals.length; - - leaks = filterLeaks(ok, globals); - this._globals = this._globals.concat(leaks); - - if (leaks.length > 1) { - this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); - } else if (leaks.length) { - this.fail(test, new Error('global leak detected: ' + leaks[0])); - } -}; - -/** - * Fail the given `test`. - * - * @param {Test} test - * @param {Error} err - * @api private - */ - -Runner.prototype.fail = function(test, err){ - ++this.failures; - test.state = 'failed'; - - if ('string' == typeof err) { - err = new Error('the string "' + err + '" was thrown, throw an Error :)'); - } - - this.emit('fail', test, err); -}; - -/** - * Fail the given `hook` with `err`. - * - * Hook failures work in the following pattern: - * - If bail, then exit - * - Failed `before` hook skips all tests in a suite and subsuites, - * but jumps to corresponding `after` hook - * - Failed `before each` hook skips remaining tests in a - * suite and jumps to corresponding `after each` hook, - * which is run only once - * - Failed `after` hook does not alter - * execution order - * - Failed `after each` hook skips remaining tests in a - * suite and subsuites, but executes other `after each` - * hooks - * - * @param {Hook} hook - * @param {Error} err - * @api private - */ - -Runner.prototype.failHook = function(hook, err){ - this.fail(hook, err); - if (this.suite.bail()) { - this.emit('end'); - } -}; - -/** - * Run hook `name` callbacks and then invoke `fn()`. - * - * @param {String} name - * @param {Function} function - * @api private - */ - -Runner.prototype.hook = function(name, fn){ - var suite = this.suite - , hooks = suite['_' + name] - , self = this - , timer; - - function next(i) { - var hook = hooks[i]; - if (!hook) return fn(); - if (self.failures && suite.bail()) return fn(); - self.currentRunnable = hook; - - hook.ctx.currentTest = self.test; - - self.emit('hook', hook); - - hook.on('error', function(err){ - self.failHook(hook, err); - }); - - hook.run(function(err){ - hook.removeAllListeners('error'); - var testError = hook.error(); - if (testError) self.fail(self.test, testError); - if (err) { - self.failHook(hook, err); - - // stop executing hooks, notify callee of hook err - return fn(err); - } - self.emit('hook end', hook); - delete hook.ctx.currentTest; - next(++i); - }); - } - - Runner.immediately(function(){ - next(0); - }); -}; - -/** - * Run hook `name` for the given array of `suites` - * in order, and callback `fn(err, errSuite)`. - * - * @param {String} name - * @param {Array} suites - * @param {Function} fn - * @api private - */ - -Runner.prototype.hooks = function(name, suites, fn){ - var self = this - , orig = this.suite; - - function next(suite) { - self.suite = suite; - - if (!suite) { - self.suite = orig; - return fn(); - } - - self.hook(name, function(err){ - if (err) { - var errSuite = self.suite; - self.suite = orig; - return fn(err, errSuite); - } - - next(suites.pop()); - }); - } - - next(suites.pop()); -}; - -/** - * Run hooks from the top level down. - * - * @param {String} name - * @param {Function} fn - * @api private - */ - -Runner.prototype.hookUp = function(name, fn){ - var suites = [this.suite].concat(this.parents()).reverse(); - this.hooks(name, suites, fn); -}; - -/** - * Run hooks from the bottom up. - * - * @param {String} name - * @param {Function} fn - * @api private - */ - -Runner.prototype.hookDown = function(name, fn){ - var suites = [this.suite].concat(this.parents()); - this.hooks(name, suites, fn); -}; - -/** - * Return an array of parent Suites from - * closest to furthest. - * - * @return {Array} - * @api private - */ - -Runner.prototype.parents = function(){ - var suite = this.suite - , suites = []; - while (suite = suite.parent) suites.push(suite); - return suites; -}; - -/** - * Run the current test and callback `fn(err)`. - * - * @param {Function} fn - * @api private - */ - -Runner.prototype.runTest = function(fn){ - var test = this.test - , self = this; - - if (this.asyncOnly) test.asyncOnly = true; - - try { - test.on('error', function(err){ - self.fail(test, err); - }); - test.run(fn); - } catch (err) { - fn(err); - } -}; - -/** - * Run tests in the given `suite` and invoke - * the callback `fn()` when complete. - * - * @param {Suite} suite - * @param {Function} fn - * @api private - */ - -Runner.prototype.runTests = function(suite, fn){ - var self = this - , tests = suite.tests.slice() - , test; - - - function hookErr(err, errSuite, after) { - // before/after Each hook for errSuite failed: - var orig = self.suite; - - // for failed 'after each' hook start from errSuite parent, - // otherwise start from errSuite itself - self.suite = after ? errSuite.parent : errSuite; - - if (self.suite) { - // call hookUp afterEach - self.hookUp('afterEach', function(err2, errSuite2) { - self.suite = orig; - // some hooks may fail even now - if (err2) return hookErr(err2, errSuite2, true); - // report error suite - fn(errSuite); - }); - } else { - // there is no need calling other 'after each' hooks - self.suite = orig; - fn(errSuite); - } - } - - function next(err, errSuite) { - // if we bail after first err - if (self.failures && suite._bail) return fn(); - - if (self._abort) return fn(); - - if (err) return hookErr(err, errSuite, true); - - // next test - test = tests.shift(); - - // all done - if (!test) return fn(); - - // grep - var match = self._grep.test(test.fullTitle()); - if (self._invert) match = !match; - if (!match) return next(); - - // pending - if (test.pending) { - self.emit('pending', test); - self.emit('test end', test); - return next(); - } - - // execute test and hook(s) - self.emit('test', self.test = test); - self.hookDown('beforeEach', function(err, errSuite){ - - if (err) return hookErr(err, errSuite, false); - - self.currentRunnable = self.test; - self.runTest(function(err){ - test = self.test; - - if (err) { - self.fail(test, err); - self.emit('test end', test); - return self.hookUp('afterEach', next); - } - - test.state = 'passed'; - self.emit('pass', test); - self.emit('test end', test); - self.hookUp('afterEach', next); - }); - }); - } - - this.next = next; - next(); -}; - -/** - * Run the given `suite` and invoke the - * callback `fn()` when complete. - * - * @param {Suite} suite - * @param {Function} fn - * @api private - */ - -Runner.prototype.runSuite = function(suite, fn){ - var total = this.grepTotal(suite) - , self = this - , i = 0; - - debug('run suite %s', suite.fullTitle()); - - if (!total) return fn(); - - this.emit('suite', this.suite = suite); - - function next(errSuite) { - if (errSuite) { - // current suite failed on a hook from errSuite - if (errSuite == suite) { - // if errSuite is current suite - // continue to the next sibling suite - return done(); - } else { - // errSuite is among the parents of current suite - // stop execution of errSuite and all sub-suites - return done(errSuite); - } - } - - if (self._abort) return done(); - - var curr = suite.suites[i++]; - if (!curr) return done(); - self.runSuite(curr, next); - } - - function done(errSuite) { - self.suite = suite; - self.hook('afterAll', function(){ - self.emit('suite end', suite); - fn(errSuite); - }); - } - - this.hook('beforeAll', function(err){ - if (err) return done(); - self.runTests(suite, next); - }); -}; - -/** - * Handle uncaught exceptions. - * - * @param {Error} err - * @api private - */ - -Runner.prototype.uncaught = function(err){ - debug('uncaught exception %s', err.message); - var runnable = this.currentRunnable; - if (!runnable || 'failed' == runnable.state) return; - runnable.clearTimeout(); - err.uncaught = true; - this.fail(runnable, err); - - // recover from test - if ('test' == runnable.type) { - this.emit('test end', runnable); - this.hookUp('afterEach', this.next); - return; - } - - // bail on hooks - this.emit('end'); -}; - -/** - * Run the root suite and invoke `fn(failures)` - * on completion. - * - * @param {Function} fn - * @return {Runner} for chaining - * @api public - */ - -Runner.prototype.run = function(fn){ - var self = this - , fn = fn || function(){}; - - function uncaught(err){ - self.uncaught(err); - } - - debug('start'); - - // callback - this.on('end', function(){ - debug('end'); - process.removeListener('uncaughtException', uncaught); - fn(self.failures); - }); - - // run suites - this.emit('start'); - this.runSuite(this.suite, function(){ - debug('finished running'); - self.emit('end'); - }); - - // uncaught exception - process.on('uncaughtException', uncaught); - window.__uncaught = uncaught; - - return this; -}; - -/** - * Cleanly abort execution - * - * @return {Runner} for chaining - * @api public - */ -Runner.prototype.abort = function(){ - debug('aborting'); - this._abort = true; -} - -/** - * Filter leaks with the given globals flagged as `ok`. - * - * @param {Array} ok - * @param {Array} globals - * @return {Array} - * @api private - */ - -function filterLeaks(ok, globals) { - return filter(globals, function(key){ - // Firefox and Chrome exposes iframes as index inside the window object - if (/^d+/.test(key)) return false; - - // in firefox - // if runner runs in an iframe, this iframe's window.getInterface method not init at first - // it is assigned in some seconds - if (global.navigator && /^getInterface/.test(key)) return false; - - // an iframe could be approached by window[iframeIndex] - // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak - if (global.navigator && /^\d+/.test(key)) return false; - - // Opera and IE expose global variables for HTML element IDs (issue #243) - if (/^mocha-/.test(key)) return false; - - var matched = filter(ok, function(ok){ - if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); - return key == ok; - }); - return matched.length == 0 && (!global.navigator || 'onerror' !== key); - }); -} - -/** - * Array of globals dependent on the environment. - * - * @return {Array} - * @api private - */ - - function extraGlobals() { - if (typeof(process) === 'object' && - typeof(process.version) === 'string') { - - var nodeVersion = process.version.split('.').reduce(function(a, v) { - return a << 8 | v; - }); - - // 'errno' was renamed to process._errno in v0.9.11. - - if (nodeVersion < 0x00090B) { - return ['errno']; - } - } - - return []; - } - -}); // module: runner.js - -require.register("suite.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var EventEmitter = require('browser/events').EventEmitter - , debug = require('browser/debug')('mocha:suite') - , milliseconds = require('./ms') - , utils = require('./utils') - , Hook = require('./hook'); - -/** - * Expose `Suite`. - */ - -exports = module.exports = Suite; - -/** - * Create a new `Suite` with the given `title` - * and parent `Suite`. When a suite with the - * same title is already present, that suite - * is returned to provide nicer reporter - * and more flexible meta-testing. - * - * @param {Suite} parent - * @param {String} title - * @return {Suite} - * @api public - */ - -exports.create = function(parent, title){ - var suite = new Suite(title, parent.ctx); - suite.parent = parent; - if (parent.pending) suite.pending = true; - title = suite.fullTitle(); - parent.addSuite(suite); - return suite; -}; - -/** - * Initialize a new `Suite` with the given - * `title` and `ctx`. - * - * @param {String} title - * @param {Context} ctx - * @api private - */ - -function Suite(title, ctx) { - this.title = title; - this.ctx = ctx; - this.suites = []; - this.tests = []; - this.pending = false; - this._beforeEach = []; - this._beforeAll = []; - this._afterEach = []; - this._afterAll = []; - this.root = !title; - this._timeout = 2000; - this._slow = 75; - this._bail = false; -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -function F(){}; -F.prototype = EventEmitter.prototype; -Suite.prototype = new F; -Suite.prototype.constructor = Suite; - - -/** - * Return a clone of this `Suite`. - * - * @return {Suite} - * @api private - */ - -Suite.prototype.clone = function(){ - var suite = new Suite(this.title); - debug('clone'); - suite.ctx = this.ctx; - suite.timeout(this.timeout()); - suite.slow(this.slow()); - suite.bail(this.bail()); - return suite; -}; - -/** - * Set timeout `ms` or short-hand such as "2s". - * - * @param {Number|String} ms - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.timeout = function(ms){ - if (0 == arguments.length) return this._timeout; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('timeout %d', ms); - this._timeout = parseInt(ms, 10); - return this; -}; - -/** - * Set slow `ms` or short-hand such as "2s". - * - * @param {Number|String} ms - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.slow = function(ms){ - if (0 === arguments.length) return this._slow; - if ('string' == typeof ms) ms = milliseconds(ms); - debug('slow %d', ms); - this._slow = ms; - return this; -}; - -/** - * Sets whether to bail after first error. - * - * @parma {Boolean} bail - * @return {Suite|Number} for chaining - * @api private - */ - -Suite.prototype.bail = function(bail){ - if (0 == arguments.length) return this._bail; - debug('bail %s', bail); - this._bail = bail; - return this; -}; - -/** - * Run `fn(test[, done])` before running tests. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.beforeAll = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"before all" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeAll.push(hook); - this.emit('beforeAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after running tests. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.afterAll = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"after all" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterAll.push(hook); - this.emit('afterAll', hook); - return this; -}; - -/** - * Run `fn(test[, done])` before each test case. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.beforeEach = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"before each" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._beforeEach.push(hook); - this.emit('beforeEach', hook); - return this; -}; - -/** - * Run `fn(test[, done])` after each test case. - * - * @param {Function} fn - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.afterEach = function(title, fn){ - if (this.pending) return this; - if ('function' === typeof title) { - fn = title; - title = fn.name; - } - title = '"after each" hook' + (title ? ': ' + title : ''); - - var hook = new Hook(title, fn); - hook.parent = this; - hook.timeout(this.timeout()); - hook.slow(this.slow()); - hook.ctx = this.ctx; - this._afterEach.push(hook); - this.emit('afterEach', hook); - return this; -}; - -/** - * Add a test `suite`. - * - * @param {Suite} suite - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.addSuite = function(suite){ - suite.parent = this; - suite.timeout(this.timeout()); - suite.slow(this.slow()); - suite.bail(this.bail()); - this.suites.push(suite); - this.emit('suite', suite); - return this; -}; - -/** - * Add a `test` to this suite. - * - * @param {Test} test - * @return {Suite} for chaining - * @api private - */ - -Suite.prototype.addTest = function(test){ - test.parent = this; - test.timeout(this.timeout()); - test.slow(this.slow()); - test.ctx = this.ctx; - this.tests.push(test); - this.emit('test', test); - return this; -}; - -/** - * Return the full title generated by recursively - * concatenating the parent's full title. - * - * @return {String} - * @api public - */ - -Suite.prototype.fullTitle = function(){ - if (this.parent) { - var full = this.parent.fullTitle(); - if (full) return full + ' ' + this.title; - } - return this.title; -}; - -/** - * Return the total number of tests. - * - * @return {Number} - * @api public - */ - -Suite.prototype.total = function(){ - return utils.reduce(this.suites, function(sum, suite){ - return sum + suite.total(); - }, 0) + this.tests.length; -}; - -/** - * Iterates through each suite recursively to find - * all tests. Applies a function in the format - * `fn(test)`. - * - * @param {Function} fn - * @return {Suite} - * @api private - */ - -Suite.prototype.eachTest = function(fn){ - utils.forEach(this.tests, fn); - utils.forEach(this.suites, function(suite){ - suite.eachTest(fn); - }); - return this; -}; - -}); // module: suite.js - -require.register("test.js", function(module, exports, require){ - -/** - * Module dependencies. - */ - -var Runnable = require('./runnable'); - -/** - * Expose `Test`. - */ - -module.exports = Test; - -/** - * Initialize a new `Test` with the given `title` and callback `fn`. - * - * @param {String} title - * @param {Function} fn - * @api private - */ - -function Test(title, fn) { - Runnable.call(this, title, fn); - this.pending = !fn; - this.type = 'test'; -} - -/** - * Inherit from `Runnable.prototype`. - */ - -function F(){}; -F.prototype = Runnable.prototype; -Test.prototype = new F; -Test.prototype.constructor = Test; - - -}); // module: test.js - -require.register("utils.js", function(module, exports, require){ -/** - * Module dependencies. - */ - -var fs = require('browser/fs') - , path = require('browser/path') - , join = path.join - , debug = require('browser/debug')('mocha:watch'); - -/** - * Ignored directories. - */ - -var ignore = ['node_modules', '.git']; - -/** - * Escape special characters in the given string of html. - * - * @param {String} html - * @return {String} - * @api private - */ - -exports.escape = function(html){ - return String(html) - .replace(/&/g, '&') - .replace(/"/g, '"') - .replace(//g, '>'); -}; - -/** - * Array#forEach (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} scope - * @api private - */ - -exports.forEach = function(arr, fn, scope){ - for (var i = 0, l = arr.length; i < l; i++) - fn.call(scope, arr[i], i); -}; - -/** - * Array#map (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} scope - * @api private - */ - -exports.map = function(arr, fn, scope){ - var result = []; - for (var i = 0, l = arr.length; i < l; i++) - result.push(fn.call(scope, arr[i], i)); - return result; -}; - -/** - * Array#indexOf (<=IE8) - * - * @parma {Array} arr - * @param {Object} obj to find index of - * @param {Number} start - * @api private - */ - -exports.indexOf = function(arr, obj, start){ - for (var i = start || 0, l = arr.length; i < l; i++) { - if (arr[i] === obj) - return i; - } - return -1; -}; - -/** - * Array#reduce (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @param {Object} initial value - * @api private - */ - -exports.reduce = function(arr, fn, val){ - var rval = val; - - for (var i = 0, l = arr.length; i < l; i++) { - rval = fn(rval, arr[i], i, arr); - } - - return rval; -}; - -/** - * Array#filter (<=IE8) - * - * @param {Array} array - * @param {Function} fn - * @api private - */ - -exports.filter = function(arr, fn){ - var ret = []; - - for (var i = 0, l = arr.length; i < l; i++) { - var val = arr[i]; - if (fn(val, i, arr)) ret.push(val); - } - - return ret; -}; - -/** - * Object.keys (<=IE8) - * - * @param {Object} obj - * @return {Array} keys - * @api private - */ - -exports.keys = Object.keys || function(obj) { - var keys = [] - , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 - - for (var key in obj) { - if (has.call(obj, key)) { - keys.push(key); - } - } - - return keys; -}; - -/** - * Watch the given `files` for changes - * and invoke `fn(file)` on modification. - * - * @param {Array} files - * @param {Function} fn - * @api private - */ - -exports.watch = function(files, fn){ - var options = { interval: 100 }; - files.forEach(function(file){ - debug('file %s', file); - fs.watchFile(file, options, function(curr, prev){ - if (prev.mtime < curr.mtime) fn(file); - }); - }); -}; - -/** - * Ignored files. - */ - -function ignored(path){ - return !~ignore.indexOf(path); -} - -/** - * Lookup files in the given `dir`. - * - * @return {Array} - * @api private - */ - -exports.files = function(dir, ret){ - ret = ret || []; - - fs.readdirSync(dir) - .filter(ignored) - .forEach(function(path){ - path = join(dir, path); - if (fs.statSync(path).isDirectory()) { - exports.files(path, ret); - } else if (path.match(/\.(js|coffee|litcoffee|coffee.md)$/)) { - ret.push(path); - } - }); - - return ret; -}; - -/** - * Compute a slug from the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.slug = function(str){ - return str - .toLowerCase() - .replace(/ +/g, '-') - .replace(/[^-\w]/g, ''); -}; - -/** - * Strip the function definition from `str`, - * and re-indent for pre whitespace. - */ - -exports.clean = function(str) { - str = str - .replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '') - .replace(/^function *\(.*\) *{/, '') - .replace(/\s+\}$/, ''); - - var spaces = str.match(/^\n?( *)/)[1].length - , tabs = str.match(/^\n?(\t*)/)[1].length - , re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm'); - - str = str.replace(re, ''); - - return exports.trim(str); -}; - -/** - * Escape regular expression characters in `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.escapeRegexp = function(str){ - return str.replace(/[-\\^$*+?.()|[\]{}]/g, "\\$&"); -}; - -/** - * Trim the given `str`. - * - * @param {String} str - * @return {String} - * @api private - */ - -exports.trim = function(str){ - return str.replace(/^\s+|\s+$/g, ''); -}; - -/** - * Parse the given `qs`. - * - * @param {String} qs - * @return {Object} - * @api private - */ - -exports.parseQuery = function(qs){ - return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){ - var i = pair.indexOf('=') - , key = pair.slice(0, i) - , val = pair.slice(++i); - - obj[key] = decodeURIComponent(val); - return obj; - }, {}); -}; - -/** - * Highlight the given string of `js`. - * - * @param {String} js - * @return {String} - * @api private - */ - -function highlight(js) { - return js - .replace(//g, '>') - .replace(/\/\/(.*)/gm, '//$1') - .replace(/('.*?')/gm, '$1') - .replace(/(\d+\.\d+)/gm, '$1') - .replace(/(\d+)/gm, '$1') - .replace(/\bnew *(\w+)/gm, 'new $1') - .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') -} - -/** - * Highlight the contents of tag `name`. - * - * @param {String} name - * @api private - */ - -exports.highlightTags = function(name) { - var code = document.getElementsByTagName(name); - for (var i = 0, len = code.length; i < len; ++i) { - code[i].innerHTML = highlight(code[i].innerHTML); - } -}; - -}); // module: utils.js -// The global object is "self" in Web Workers. -global = (function() { return this; })(); - -/** - * Save timer references to avoid Sinon interfering (see GH-237). - */ - -var Date = global.Date; -var setTimeout = global.setTimeout; -var setInterval = global.setInterval; -var clearTimeout = global.clearTimeout; -var clearInterval = global.clearInterval; - -/** - * Node shims. - * - * These are meant only to allow - * mocha.js to run untouched, not - * to allow running node code in - * the browser. - */ - -var process = {}; -process.exit = function(status){}; -process.stdout = {}; - -var uncaughtExceptionHandlers = []; - -/** - * Remove uncaughtException listener. - */ - -process.removeListener = function(e, fn){ - if ('uncaughtException' == e) { - global.onerror = function() {}; - var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn); - if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); } - } -}; - -/** - * Implements uncaughtException listener. - */ - -process.on = function(e, fn){ - if ('uncaughtException' == e) { - global.onerror = function(err, url, line){ - fn(new Error(err + ' (' + url + ':' + line + ')')); - return true; - }; - uncaughtExceptionHandlers.push(fn); - } -}; - -/** - * Expose mocha. - */ - -var Mocha = global.Mocha = require('mocha'), - mocha = global.mocha = new Mocha({ reporter: 'html' }); - -// The BDD UI is registered by default, but no UI will be functional in the -// browser without an explicit call to the overridden `mocha.ui` (see below). -// Ensure that this default UI does not expose its methods to the global scope. -mocha.suite.removeAllListeners('pre-require'); - -var immediateQueue = [] - , immediateTimeout; - -function timeslice() { - var immediateStart = new Date().getTime(); - while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) { - immediateQueue.shift()(); - } - if (immediateQueue.length) { - immediateTimeout = setTimeout(timeslice, 0); - } else { - immediateTimeout = null; - } -} - -/** - * High-performance override of Runner.immediately. - */ - -Mocha.Runner.immediately = function(callback) { - immediateQueue.push(callback); - if (!immediateTimeout) { - immediateTimeout = setTimeout(timeslice, 0); - } -}; - -/** - * Function to allow assertion libraries to throw errors directly into mocha. - * This is useful when running tests in a browser because window.onerror will - * only receive the 'message' attribute of the Error. - */ -mocha.throwError = function(err) { - Mocha.utils.forEach(uncaughtExceptionHandlers, function (fn) { - fn(err); - }); - throw err; -}; - -/** - * Override ui to ensure that the ui functions are initialized. - * Normally this would happen in Mocha.prototype.loadFiles. - */ - -mocha.ui = function(ui){ - Mocha.prototype.ui.call(this, ui); - this.suite.emit('pre-require', global, null, this); - return this; -}; - -/** - * Setup mocha with the given setting options. - */ - -mocha.setup = function(opts){ - if ('string' == typeof opts) opts = { ui: opts }; - for (var opt in opts) this[opt](opts[opt]); - return this; -}; - -/** - * Run mocha, returning the Runner. - */ - -mocha.run = function(fn){ - var options = mocha.options; - mocha.globals('location'); - - var query = Mocha.utils.parseQuery(global.location.search || ''); - if (query.grep) mocha.grep(query.grep); - if (query.invert) mocha.invert(); - - return Mocha.prototype.run.call(mocha, function(){ - // The DOM Document is not available in Web Workers. - if (global.document) { - Mocha.utils.highlightTags('code'); - } - if (fn) fn(); - }); -}; - -/** - * Expose the process shim. - */ - -Mocha.process = process; -})();})(window||global||undefined); \ No newline at end of file diff --git a/tests/mocha/node_modules/commander/History.md b/tests/mocha/node_modules/commander/History.md deleted file mode 100644 index 2e665828cf..0000000000 --- a/tests/mocha/node_modules/commander/History.md +++ /dev/null @@ -1,179 +0,0 @@ - -2.0.0 / 2013-07-18 -================== - - * remove input methods (.prompt, .confirm, etc) - -1.3.2 / 2013-07-18 -================== - - * add support for sub-commands to co-exist with the original command - -1.3.1 / 2013-07-18 -================== - - * add quick .runningCommand hack so you can opt-out of other logic when running a sub command - -1.3.0 / 2013-07-09 -================== - - * add EACCES error handling - * fix sub-command --help - -1.2.0 / 2013-06-13 -================== - - * allow "-" hyphen as an option argument - * support for RegExp coercion - -1.1.1 / 2012-11-20 -================== - - * add more sub-command padding - * fix .usage() when args are present. Closes #106 - -1.1.0 / 2012-11-16 -================== - - * add git-style executable subcommand support. Closes #94 - -1.0.5 / 2012-10-09 -================== - - * fix `--name` clobbering. Closes #92 - * fix examples/help. Closes #89 - -1.0.4 / 2012-09-03 -================== - - * add `outputHelp()` method. - -1.0.3 / 2012-08-30 -================== - - * remove invalid .version() defaulting - -1.0.2 / 2012-08-24 -================== - - * add `--foo=bar` support [arv] - * fix password on node 0.8.8. Make backward compatible with 0.6 [focusaurus] - -1.0.1 / 2012-08-03 -================== - - * fix issue #56 - * fix tty.setRawMode(mode) was moved to tty.ReadStream#setRawMode() (i.e. process.stdin.setRawMode()) - -1.0.0 / 2012-07-05 -================== - - * add support for optional option descriptions - * add defaulting of `.version()` to package.json's version - -0.6.1 / 2012-06-01 -================== - - * Added: append (yes or no) on confirmation - * Added: allow node.js v0.7.x - -0.6.0 / 2012-04-10 -================== - - * Added `.prompt(obj, callback)` support. Closes #49 - * Added default support to .choose(). Closes #41 - * Fixed the choice example - -0.5.1 / 2011-12-20 -================== - - * Fixed `password()` for recent nodes. Closes #36 - -0.5.0 / 2011-12-04 -================== - - * Added sub-command option support [itay] - -0.4.3 / 2011-12-04 -================== - - * Fixed custom help ordering. Closes #32 - -0.4.2 / 2011-11-24 -================== - - * Added travis support - * Fixed: line-buffered input automatically trimmed. Closes #31 - -0.4.1 / 2011-11-18 -================== - - * Removed listening for "close" on --help - -0.4.0 / 2011-11-15 -================== - - * Added support for `--`. Closes #24 - -0.3.3 / 2011-11-14 -================== - - * Fixed: wait for close event when writing help info [Jerry Hamlet] - -0.3.2 / 2011-11-01 -================== - - * Fixed long flag definitions with values [felixge] - -0.3.1 / 2011-10-31 -================== - - * Changed `--version` short flag to `-V` from `-v` - * Changed `.version()` so it's configurable [felixge] - -0.3.0 / 2011-10-31 -================== - - * Added support for long flags only. Closes #18 - -0.2.1 / 2011-10-24 -================== - - * "node": ">= 0.4.x < 0.7.0". Closes #20 - -0.2.0 / 2011-09-26 -================== - - * Allow for defaults that are not just boolean. Default peassignment only occurs for --no-*, optional, and required arguments. [Jim Isaacs] - -0.1.0 / 2011-08-24 -================== - - * Added support for custom `--help` output - -0.0.5 / 2011-08-18 -================== - - * Changed: when the user enters nothing prompt for password again - * Fixed issue with passwords beginning with numbers [NuckChorris] - -0.0.4 / 2011-08-15 -================== - - * Fixed `Commander#args` - -0.0.3 / 2011-08-15 -================== - - * Added default option value support - -0.0.2 / 2011-08-15 -================== - - * Added mask support to `Command#password(str[, mask], fn)` - * Added `Command#password(str, fn)` - -0.0.1 / 2010-01-03 -================== - - * Initial release diff --git a/tests/mocha/node_modules/commander/Readme.md b/tests/mocha/node_modules/commander/Readme.md deleted file mode 100644 index d1644012c5..0000000000 --- a/tests/mocha/node_modules/commander/Readme.md +++ /dev/null @@ -1,195 +0,0 @@ -# Commander.js - - The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander). - - [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js) - -## Installation - - $ npm install commander - -## Option parsing - - Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options. - -```js -#!/usr/bin/env node - -/** - * Module dependencies. - */ - -var program = require('commander'); - -program - .version('0.0.1') - .option('-p, --peppers', 'Add peppers') - .option('-P, --pineapple', 'Add pineapple') - .option('-b, --bbq', 'Add bbq sauce') - .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble') - .parse(process.argv); - -console.log('you ordered a pizza with:'); -if (program.peppers) console.log(' - peppers'); -if (program.pineapple) console.log(' - pineapple'); -if (program.bbq) console.log(' - bbq'); -console.log(' - %s cheese', program.cheese); -``` - - Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as "--template-engine" are camel-cased, becoming `program.templateEngine` etc. - -## Automated --help - - The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free: - -``` - $ ./examples/pizza --help - - Usage: pizza [options] - - Options: - - -V, --version output the version number - -p, --peppers Add peppers - -P, --pineapple Add pineapple - -b, --bbq Add bbq sauce - -c, --cheese Add the specified type of cheese [marble] - -h, --help output usage information - -``` - -## Coercion - -```js -function range(val) { - return val.split('..').map(Number); -} - -function list(val) { - return val.split(','); -} - -program - .version('0.0.1') - .usage('[options] ') - .option('-i, --integer ', 'An integer argument', parseInt) - .option('-f, --float ', 'A float argument', parseFloat) - .option('-r, --range ..', 'A range', range) - .option('-l, --list ', 'A list', list) - .option('-o, --optional [value]', 'An optional value') - .parse(process.argv); - -console.log(' int: %j', program.integer); -console.log(' float: %j', program.float); -console.log(' optional: %j', program.optional); -program.range = program.range || []; -console.log(' range: %j..%j', program.range[0], program.range[1]); -console.log(' list: %j', program.list); -console.log(' args: %j', program.args); -``` - -## Custom help - - You can display arbitrary `-h, --help` information - by listening for "--help". Commander will automatically - exit once you are done so that the remainder of your program - does not execute causing undesired behaviours, for example - in the following executable "stuff" will not output when - `--help` is used. - -```js -#!/usr/bin/env node - -/** - * Module dependencies. - */ - -var program = require('../'); - -function list(val) { - return val.split(',').map(Number); -} - -program - .version('0.0.1') - .option('-f, --foo', 'enable some foo') - .option('-b, --bar', 'enable some bar') - .option('-B, --baz', 'enable some baz'); - -// must be before .parse() since -// node's emit() is immediate - -program.on('--help', function(){ - console.log(' Examples:'); - console.log(''); - console.log(' $ custom-help --help'); - console.log(' $ custom-help -h'); - console.log(''); -}); - -program.parse(process.argv); - -console.log('stuff'); -``` - -yielding the following help output: - -``` - -Usage: custom-help [options] - -Options: - - -h, --help output usage information - -V, --version output the version number - -f, --foo enable some foo - -b, --bar enable some bar - -B, --baz enable some baz - -Examples: - - $ custom-help --help - $ custom-help -h - -``` - -## .outputHelp() - - Output help information without exiting. - -## .help() - - Output help information and exit immediately. - -## Links - - - [API documentation](http://visionmedia.github.com/commander.js/) - - [ascii tables](https://github.com/LearnBoost/cli-table) - - [progress bars](https://github.com/visionmedia/node-progress) - - [more progress bars](https://github.com/substack/node-multimeter) - - [examples](https://github.com/visionmedia/commander.js/tree/master/examples) - -## License - -(The MIT License) - -Copyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca> - -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 copies 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 all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 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. diff --git a/tests/mocha/node_modules/commander/index.js b/tests/mocha/node_modules/commander/index.js deleted file mode 100644 index d5778a75ba..0000000000 --- a/tests/mocha/node_modules/commander/index.js +++ /dev/null @@ -1,847 +0,0 @@ - -/** - * Module dependencies. - */ - -var EventEmitter = require('events').EventEmitter; -var spawn = require('child_process').spawn; -var fs = require('fs'); -var exists = fs.existsSync; -var path = require('path'); -var dirname = path.dirname; -var basename = path.basename; - -/** - * Expose the root command. - */ - -exports = module.exports = new Command; - -/** - * Expose `Command`. - */ - -exports.Command = Command; - -/** - * Expose `Option`. - */ - -exports.Option = Option; - -/** - * Initialize a new `Option` with the given `flags` and `description`. - * - * @param {String} flags - * @param {String} description - * @api public - */ - -function Option(flags, description) { - this.flags = flags; - this.required = ~flags.indexOf('<'); - this.optional = ~flags.indexOf('['); - this.bool = !~flags.indexOf('-no-'); - flags = flags.split(/[ ,|]+/); - if (flags.length > 1 && !/^[[<]/.test(flags[1])) this.short = flags.shift(); - this.long = flags.shift(); - this.description = description || ''; -} - -/** - * Return option name. - * - * @return {String} - * @api private - */ - -Option.prototype.name = function(){ - return this.long - .replace('--', '') - .replace('no-', ''); -}; - -/** - * Check if `arg` matches the short or long flag. - * - * @param {String} arg - * @return {Boolean} - * @api private - */ - -Option.prototype.is = function(arg){ - return arg == this.short - || arg == this.long; -}; - -/** - * Initialize a new `Command`. - * - * @param {String} name - * @api public - */ - -function Command(name) { - this.commands = []; - this.options = []; - this._execs = []; - this._args = []; - this._name = name; -} - -/** - * Inherit from `EventEmitter.prototype`. - */ - -Command.prototype.__proto__ = EventEmitter.prototype; - -/** - * Add command `name`. - * - * The `.action()` callback is invoked when the - * command `name` is specified via __ARGV__, - * and the remaining arguments are applied to the - * function for access. - * - * When the `name` is "*" an un-matched command - * will be passed as the first arg, followed by - * the rest of __ARGV__ remaining. - * - * Examples: - * - * program - * .version('0.0.1') - * .option('-C, --chdir ', 'change the working directory') - * .option('-c, --config ', 'set config path. defaults to ./deploy.conf') - * .option('-T, --no-tests', 'ignore test hook') - * - * program - * .command('setup') - * .description('run remote setup commands') - * .action(function(){ - * console.log('setup'); - * }); - * - * program - * .command('exec ') - * .description('run the given remote command') - * .action(function(cmd){ - * console.log('exec "%s"', cmd); - * }); - * - * program - * .command('*') - * .description('deploy the given env') - * .action(function(env){ - * console.log('deploying "%s"', env); - * }); - * - * program.parse(process.argv); - * - * @param {String} name - * @param {String} [desc] - * @return {Command} the new command - * @api public - */ - -Command.prototype.command = function(name, desc){ - var args = name.split(/ +/); - var cmd = new Command(args.shift()); - if (desc) cmd.description(desc); - if (desc) this.executables = true; - if (desc) this._execs[cmd._name] = true; - this.commands.push(cmd); - cmd.parseExpectedArgs(args); - cmd.parent = this; - if (desc) return this; - return cmd; -}; - -/** - * Add an implicit `help [cmd]` subcommand - * which invokes `--help` for the given command. - * - * @api private - */ - -Command.prototype.addImplicitHelpCommand = function() { - this.command('help [cmd]', 'display help for [cmd]'); -}; - -/** - * Parse expected `args`. - * - * For example `["[type]"]` becomes `[{ required: false, name: 'type' }]`. - * - * @param {Array} args - * @return {Command} for chaining - * @api public - */ - -Command.prototype.parseExpectedArgs = function(args){ - if (!args.length) return; - var self = this; - args.forEach(function(arg){ - switch (arg[0]) { - case '<': - self._args.push({ required: true, name: arg.slice(1, -1) }); - break; - case '[': - self._args.push({ required: false, name: arg.slice(1, -1) }); - break; - } - }); - return this; -}; - -/** - * Register callback `fn` for the command. - * - * Examples: - * - * program - * .command('help') - * .description('display verbose help') - * .action(function(){ - * // output help here - * }); - * - * @param {Function} fn - * @return {Command} for chaining - * @api public - */ - -Command.prototype.action = function(fn){ - var self = this; - this.parent.on(this._name, function(args, unknown){ - // Parse any so-far unknown options - unknown = unknown || []; - var parsed = self.parseOptions(unknown); - - // Output help if necessary - outputHelpIfNecessary(self, parsed.unknown); - - // If there are still any unknown options, then we simply - // die, unless someone asked for help, in which case we give it - // to them, and then we die. - if (parsed.unknown.length > 0) { - self.unknownOption(parsed.unknown[0]); - } - - // Leftover arguments need to be pushed back. Fixes issue #56 - if (parsed.args.length) args = parsed.args.concat(args); - - self._args.forEach(function(arg, i){ - if (arg.required && null == args[i]) { - self.missingArgument(arg.name); - } - }); - - // Always append ourselves to the end of the arguments, - // to make sure we match the number of arguments the user - // expects - if (self._args.length) { - args[self._args.length] = self; - } else { - args.push(self); - } - - fn.apply(this, args); - }); - return this; -}; - -/** - * Define option with `flags`, `description` and optional - * coercion `fn`. - * - * The `flags` string should contain both the short and long flags, - * separated by comma, a pipe or space. The following are all valid - * all will output this way when `--help` is used. - * - * "-p, --pepper" - * "-p|--pepper" - * "-p --pepper" - * - * Examples: - * - * // simple boolean defaulting to false - * program.option('-p, --pepper', 'add pepper'); - * - * --pepper - * program.pepper - * // => Boolean - * - * // simple boolean defaulting to false - * program.option('-C, --no-cheese', 'remove cheese'); - * - * program.cheese - * // => true - * - * --no-cheese - * program.cheese - * // => true - * - * // required argument - * program.option('-C, --chdir ', 'change the working directory'); - * - * --chdir /tmp - * program.chdir - * // => "/tmp" - * - * // optional argument - * program.option('-c, --cheese [type]', 'add cheese [marble]'); - * - * @param {String} flags - * @param {String} description - * @param {Function|Mixed} fn or default - * @param {Mixed} defaultValue - * @return {Command} for chaining - * @api public - */ - -Command.prototype.option = function(flags, description, fn, defaultValue){ - var self = this - , option = new Option(flags, description) - , oname = option.name() - , name = camelcase(oname); - - // default as 3rd arg - if ('function' != typeof fn) defaultValue = fn, fn = null; - - // preassign default value only for --no-*, [optional], or - if (false == option.bool || option.optional || option.required) { - // when --no-* we make sure default is true - if (false == option.bool) defaultValue = true; - // preassign only if we have a default - if (undefined !== defaultValue) self[name] = defaultValue; - } - - // register the option - this.options.push(option); - - // when it's passed assign the value - // and conditionally invoke the callback - this.on(oname, function(val){ - // coercion - if (null != val && fn) val = fn(val); - - // unassigned or bool - if ('boolean' == typeof self[name] || 'undefined' == typeof self[name]) { - // if no value, bool true, and we have a default, then use it! - if (null == val) { - self[name] = option.bool - ? defaultValue || true - : false; - } else { - self[name] = val; - } - } else if (null !== val) { - // reassign - self[name] = val; - } - }); - - return this; -}; - -/** - * Parse `argv`, settings options and invoking commands when defined. - * - * @param {Array} argv - * @return {Command} for chaining - * @api public - */ - -Command.prototype.parse = function(argv){ - // implicit help - if (this.executables) this.addImplicitHelpCommand(); - - // store raw args - this.rawArgs = argv; - - // guess name - this._name = this._name || basename(argv[1]); - - // process argv - var parsed = this.parseOptions(this.normalize(argv.slice(2))); - var args = this.args = parsed.args; - - var result = this.parseArgs(this.args, parsed.unknown); - - // executable sub-commands - var name = result.args[0]; - if (this._execs[name]) return this.executeSubCommand(argv, args, parsed.unknown); - - return result; -}; - -/** - * Execute a sub-command executable. - * - * @param {Array} argv - * @param {Array} args - * @param {Array} unknown - * @api private - */ - -Command.prototype.executeSubCommand = function(argv, args, unknown) { - args = args.concat(unknown); - - if (!args.length) this.help(); - if ('help' == args[0] && 1 == args.length) this.help(); - - // --help - if ('help' == args[0]) { - args[0] = args[1]; - args[1] = '--help'; - } - - // executable - var dir = dirname(argv[1]); - var bin = basename(argv[1]) + '-' + args[0]; - - // check for ./ first - var local = path.join(dir, bin); - - // run it - args = args.slice(1); - var proc = spawn(local, args, { stdio: 'inherit', customFds: [0, 1, 2] }); - proc.on('error', function(err){ - if (err.code == "ENOENT") { - console.error('\n %s(1) does not exist, try --help\n', bin); - } else if (err.code == "EACCES") { - console.error('\n %s(1) not executable. try chmod or run with root\n', bin); - } - }); - - this.runningCommand = proc; -}; - -/** - * Normalize `args`, splitting joined short flags. For example - * the arg "-abc" is equivalent to "-a -b -c". - * This also normalizes equal sign and splits "--abc=def" into "--abc def". - * - * @param {Array} args - * @return {Array} - * @api private - */ - -Command.prototype.normalize = function(args){ - var ret = [] - , arg - , index; - - for (var i = 0, len = args.length; i < len; ++i) { - arg = args[i]; - if (arg.length > 1 && '-' == arg[0] && '-' != arg[1]) { - arg.slice(1).split('').forEach(function(c){ - ret.push('-' + c); - }); - } else if (/^--/.test(arg) && ~(index = arg.indexOf('='))) { - ret.push(arg.slice(0, index), arg.slice(index + 1)); - } else { - ret.push(arg); - } - } - - return ret; -}; - -/** - * Parse command `args`. - * - * When listener(s) are available those - * callbacks are invoked, otherwise the "*" - * event is emitted and those actions are invoked. - * - * @param {Array} args - * @return {Command} for chaining - * @api private - */ - -Command.prototype.parseArgs = function(args, unknown){ - var cmds = this.commands - , len = cmds.length - , name; - - if (args.length) { - name = args[0]; - if (this.listeners(name).length) { - this.emit(args.shift(), args, unknown); - } else { - this.emit('*', args); - } - } else { - outputHelpIfNecessary(this, unknown); - - // If there were no args and we have unknown options, - // then they are extraneous and we need to error. - if (unknown.length > 0) { - this.unknownOption(unknown[0]); - } - } - - return this; -}; - -/** - * Return an option matching `arg` if any. - * - * @param {String} arg - * @return {Option} - * @api private - */ - -Command.prototype.optionFor = function(arg){ - for (var i = 0, len = this.options.length; i < len; ++i) { - if (this.options[i].is(arg)) { - return this.options[i]; - } - } -}; - -/** - * Parse options from `argv` returning `argv` - * void of these options. - * - * @param {Array} argv - * @return {Array} - * @api public - */ - -Command.prototype.parseOptions = function(argv){ - var args = [] - , len = argv.length - , literal - , option - , arg; - - var unknownOptions = []; - - // parse options - for (var i = 0; i < len; ++i) { - arg = argv[i]; - - // literal args after -- - if ('--' == arg) { - literal = true; - continue; - } - - if (literal) { - args.push(arg); - continue; - } - - // find matching Option - option = this.optionFor(arg); - - // option is defined - if (option) { - // requires arg - if (option.required) { - arg = argv[++i]; - if (null == arg) return this.optionMissingArgument(option); - if ('-' == arg[0] && '-' != arg) return this.optionMissingArgument(option, arg); - this.emit(option.name(), arg); - // optional arg - } else if (option.optional) { - arg = argv[i+1]; - if (null == arg || ('-' == arg[0] && '-' != arg)) { - arg = null; - } else { - ++i; - } - this.emit(option.name(), arg); - // bool - } else { - this.emit(option.name()); - } - continue; - } - - // looks like an option - if (arg.length > 1 && '-' == arg[0]) { - unknownOptions.push(arg); - - // If the next argument looks like it might be - // an argument for this option, we pass it on. - // If it isn't, then it'll simply be ignored - if (argv[i+1] && '-' != argv[i+1][0]) { - unknownOptions.push(argv[++i]); - } - continue; - } - - // arg - args.push(arg); - } - - return { args: args, unknown: unknownOptions }; -}; - -/** - * Argument `name` is missing. - * - * @param {String} name - * @api private - */ - -Command.prototype.missingArgument = function(name){ - console.error(); - console.error(" error: missing required argument `%s'", name); - console.error(); - process.exit(1); -}; - -/** - * `Option` is missing an argument, but received `flag` or nothing. - * - * @param {String} option - * @param {String} flag - * @api private - */ - -Command.prototype.optionMissingArgument = function(option, flag){ - console.error(); - if (flag) { - console.error(" error: option `%s' argument missing, got `%s'", option.flags, flag); - } else { - console.error(" error: option `%s' argument missing", option.flags); - } - console.error(); - process.exit(1); -}; - -/** - * Unknown option `flag`. - * - * @param {String} flag - * @api private - */ - -Command.prototype.unknownOption = function(flag){ - console.error(); - console.error(" error: unknown option `%s'", flag); - console.error(); - process.exit(1); -}; - - -/** - * Set the program version to `str`. - * - * This method auto-registers the "-V, --version" flag - * which will print the version number when passed. - * - * @param {String} str - * @param {String} flags - * @return {Command} for chaining - * @api public - */ - -Command.prototype.version = function(str, flags){ - if (0 == arguments.length) return this._version; - this._version = str; - flags = flags || '-V, --version'; - this.option(flags, 'output the version number'); - this.on('version', function(){ - console.log(str); - process.exit(0); - }); - return this; -}; - -/** - * Set the description `str`. - * - * @param {String} str - * @return {String|Command} - * @api public - */ - -Command.prototype.description = function(str){ - if (0 == arguments.length) return this._description; - this._description = str; - return this; -}; - -/** - * Set / get the command usage `str`. - * - * @param {String} str - * @return {String|Command} - * @api public - */ - -Command.prototype.usage = function(str){ - var args = this._args.map(function(arg){ - return arg.required - ? '<' + arg.name + '>' - : '[' + arg.name + ']'; - }); - - var usage = '[options' - + (this.commands.length ? '] [command' : '') - + ']' - + (this._args.length ? ' ' + args : ''); - - if (0 == arguments.length) return this._usage || usage; - this._usage = str; - - return this; -}; - -/** - * Return the largest option length. - * - * @return {Number} - * @api private - */ - -Command.prototype.largestOptionLength = function(){ - return this.options.reduce(function(max, option){ - return Math.max(max, option.flags.length); - }, 0); -}; - -/** - * Return help for options. - * - * @return {String} - * @api private - */ - -Command.prototype.optionHelp = function(){ - var width = this.largestOptionLength(); - - // Prepend the help information - return [pad('-h, --help', width) + ' ' + 'output usage information'] - .concat(this.options.map(function(option){ - return pad(option.flags, width) - + ' ' + option.description; - })) - .join('\n'); -}; - -/** - * Return command help documentation. - * - * @return {String} - * @api private - */ - -Command.prototype.commandHelp = function(){ - if (!this.commands.length) return ''; - return [ - '' - , ' Commands:' - , '' - , this.commands.map(function(cmd){ - var args = cmd._args.map(function(arg){ - return arg.required - ? '<' + arg.name + '>' - : '[' + arg.name + ']'; - }).join(' '); - - return pad(cmd._name - + (cmd.options.length - ? ' [options]' - : '') + ' ' + args, 22) - + (cmd.description() - ? ' ' + cmd.description() - : ''); - }).join('\n').replace(/^/gm, ' ') - , '' - ].join('\n'); -}; - -/** - * Return program help documentation. - * - * @return {String} - * @api private - */ - -Command.prototype.helpInformation = function(){ - return [ - '' - , ' Usage: ' + this._name + ' ' + this.usage() - , '' + this.commandHelp() - , ' Options:' - , '' - , '' + this.optionHelp().replace(/^/gm, ' ') - , '' - , '' - ].join('\n'); -}; - -/** - * Output help information for this command - * - * @api public - */ - -Command.prototype.outputHelp = function(){ - process.stdout.write(this.helpInformation()); - this.emit('--help'); -}; - -/** - * Output help information and exit. - * - * @api public - */ - -Command.prototype.help = function(){ - this.outputHelp(); - process.exit(); -}; - -/** - * Camel-case the given `flag` - * - * @param {String} flag - * @return {String} - * @api private - */ - -function camelcase(flag) { - return flag.split('-').reduce(function(str, word){ - return str + word[0].toUpperCase() + word.slice(1); - }); -} - -/** - * Pad `str` to `width`. - * - * @param {String} str - * @param {Number} width - * @return {String} - * @api private - */ - -function pad(str, width) { - var len = Math.max(0, width - str.length); - return str + Array(len + 1).join(' '); -} - -/** - * Output help information if necessary - * - * @param {Command} command to output help for - * @param {Array} array of options to search for -h or --help - * @api private - */ - -function outputHelpIfNecessary(cmd, options) { - options = options || []; - for (var i = 0; i < options.length; i++) { - if (options[i] == '--help' || options[i] == '-h') { - cmd.outputHelp(); - process.exit(0); - } - } -} diff --git a/tests/mocha/node_modules/commander/package.json b/tests/mocha/node_modules/commander/package.json deleted file mode 100644 index e25ed273ff..0000000000 --- a/tests/mocha/node_modules/commander/package.json +++ /dev/null @@ -1,38 +0,0 @@ -{ - "name": "commander", - "version": "2.0.0", - "description": "the complete solution for node.js command-line programs", - "keywords": [ - "command", - "option", - "parser", - "prompt", - "stdin" - ], - "author": { - "name": "TJ Holowaychuk", - "email": "tj@vision-media.ca" - }, - "repository": { - "type": "git", - "url": "https://github.com/visionmedia/commander.js.git" - }, - "devDependencies": { - "should": ">= 0.0.1" - }, - "scripts": { - "test": "make test" - }, - "main": "index", - "engines": { - "node": ">= 0.6.x" - }, - "readme": "# Commander.js\n\n The complete solution for [node.js](http://nodejs.org) command-line interfaces, inspired by Ruby's [commander](https://github.com/visionmedia/commander).\n\n [![Build Status](https://secure.travis-ci.org/visionmedia/commander.js.png)](http://travis-ci.org/visionmedia/commander.js)\n\n## Installation\n\n $ npm install commander\n\n## Option parsing\n\n Options with commander are defined with the `.option()` method, also serving as documentation for the options. The example below parses args and options from `process.argv`, leaving remaining args as the `program.args` array which were not consumed by options.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('commander');\n\nprogram\n .version('0.0.1')\n .option('-p, --peppers', 'Add peppers')\n .option('-P, --pineapple', 'Add pineapple')\n .option('-b, --bbq', 'Add bbq sauce')\n .option('-c, --cheese [type]', 'Add the specified type of cheese [marble]', 'marble')\n .parse(process.argv);\n\nconsole.log('you ordered a pizza with:');\nif (program.peppers) console.log(' - peppers');\nif (program.pineapple) console.log(' - pineapple');\nif (program.bbq) console.log(' - bbq');\nconsole.log(' - %s cheese', program.cheese);\n```\n\n Short flags may be passed as a single arg, for example `-abc` is equivalent to `-a -b -c`. Multi-word options such as \"--template-engine\" are camel-cased, becoming `program.templateEngine` etc.\n\n## Automated --help\n\n The help information is auto-generated based on the information commander already knows about your program, so the following `--help` info is for free:\n\n``` \n $ ./examples/pizza --help\n\n Usage: pizza [options]\n\n Options:\n\n -V, --version output the version number\n -p, --peppers Add peppers\n -P, --pineapple Add pineapple\n -b, --bbq Add bbq sauce\n -c, --cheese Add the specified type of cheese [marble]\n -h, --help output usage information\n\n```\n\n## Coercion\n\n```js\nfunction range(val) {\n return val.split('..').map(Number);\n}\n\nfunction list(val) {\n return val.split(',');\n}\n\nprogram\n .version('0.0.1')\n .usage('[options] ')\n .option('-i, --integer ', 'An integer argument', parseInt)\n .option('-f, --float ', 'A float argument', parseFloat)\n .option('-r, --range ..', 'A range', range)\n .option('-l, --list ', 'A list', list)\n .option('-o, --optional [value]', 'An optional value')\n .parse(process.argv);\n\nconsole.log(' int: %j', program.integer);\nconsole.log(' float: %j', program.float);\nconsole.log(' optional: %j', program.optional);\nprogram.range = program.range || [];\nconsole.log(' range: %j..%j', program.range[0], program.range[1]);\nconsole.log(' list: %j', program.list);\nconsole.log(' args: %j', program.args);\n```\n\n## Custom help\n\n You can display arbitrary `-h, --help` information\n by listening for \"--help\". Commander will automatically\n exit once you are done so that the remainder of your program\n does not execute causing undesired behaviours, for example\n in the following executable \"stuff\" will not output when\n `--help` is used.\n\n```js\n#!/usr/bin/env node\n\n/**\n * Module dependencies.\n */\n\nvar program = require('../');\n\nfunction list(val) {\n return val.split(',').map(Number);\n}\n\nprogram\n .version('0.0.1')\n .option('-f, --foo', 'enable some foo')\n .option('-b, --bar', 'enable some bar')\n .option('-B, --baz', 'enable some baz');\n\n// must be before .parse() since\n// node's emit() is immediate\n\nprogram.on('--help', function(){\n console.log(' Examples:');\n console.log('');\n console.log(' $ custom-help --help');\n console.log(' $ custom-help -h');\n console.log('');\n});\n\nprogram.parse(process.argv);\n\nconsole.log('stuff');\n```\n\nyielding the following help output:\n\n```\n\nUsage: custom-help [options]\n\nOptions:\n\n -h, --help output usage information\n -V, --version output the version number\n -f, --foo enable some foo\n -b, --bar enable some bar\n -B, --baz enable some baz\n\nExamples:\n\n $ custom-help --help\n $ custom-help -h\n\n```\n\n## .outputHelp()\n\n Output help information without exiting.\n\n## .help()\n\n Output help information and exit immediately.\n\n## Links\n\n - [API documentation](http://visionmedia.github.com/commander.js/)\n - [ascii tables](https://github.com/LearnBoost/cli-table)\n - [progress bars](https://github.com/visionmedia/node-progress)\n - [more progress bars](https://github.com/substack/node-multimeter)\n - [examples](https://github.com/visionmedia/commander.js/tree/master/examples)\n\n## License \n\n(The MIT License)\n\nCopyright (c) 2011 TJ Holowaychuk <tj@vision-media.ca>\n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", - "readmeFilename": "Readme.md", - "bugs": { - "url": "https://github.com/visionmedia/commander.js/issues" - }, - "homepage": "https://github.com/visionmedia/commander.js", - "_id": "commander@2.0.0", - "_from": "commander@2.0.0" -} diff --git a/tests/mocha/node_modules/diff/README.md b/tests/mocha/node_modules/diff/README.md deleted file mode 100644 index 95bd8da294..0000000000 --- a/tests/mocha/node_modules/diff/README.md +++ /dev/null @@ -1,101 +0,0 @@ -# jsdiff - -[![Build Status](https://secure.travis-ci.org/kpdecker/jsdiff.png)](http://travis-ci.org/kpdecker/jsdiff) - -A javascript text differencing implementation. - -Based on the algorithm proposed in -["An O(ND) Difference Algorithm and its Variations" (Myers, 1986)](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927). - -## Installation - - npm install diff - -or - - git clone git://github.com/kpdecker/jsdiff.git - -## API - -* JsDiff.diffChars(oldStr, newStr) - Diffs two blocks of text, comparing character by character. - - Returns a list of change objects (See below). - -* JsDiff.diffWords(oldStr, newStr) - Diffs two blocks of text, comparing word by word. - - Returns a list of change objects (See below). - -* JsDiff.diffLines(oldStr, newStr) - Diffs two blocks of text, comparing line by line. - - Returns a list of change objects (See below). - -* JsDiff.diffCss(oldStr, newStr) - Diffs two blocks of text, comparing CSS tokens. - - Returns a list of change objects (See below). - -* JsDiff.createPatch(fileName, oldStr, newStr, oldHeader, newHeader) - Creates a unified diff patch. - - Parameters: - * fileName : String to be output in the filename sections of the patch - * oldStr : Original string value - * newStr : New string value - * oldHeader : Additional information to include in the old file header - * newHeader : Additional information to include in thew new file header - -* JsDiff.applyPatch(oldStr, diffStr) - Applies a unified diff patch. - - Return a string containing new version of provided data. - -* convertChangesToXML(changes) - Converts a list of changes to a serialized XML format - -### Change Objects -Many of the methods above return change objects. These objects are consist of the following fields: - -* value: Text content -* added: True if the value was inserted into the new string -* removed: True of the value was removed from the old string - -Note that some cases may omit a particular flag field. Comparison on the flag fields should always be done in a truthy or falsy manner. - -## [Example](http://kpdecker.github.com/jsdiff) - -## License - -Software License Agreement (BSD License) - -Copyright (c) 2009-2011, Kevin Decker kpdecker@gmail.com - -All rights reserved. - -Redistribution and use of this software in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above - copyright notice, this list of conditions and the - following disclaimer. - -* Redistributions in binary form must reproduce the above - copyright notice, this list of conditions and the - following disclaimer in the documentation and/or other - materials provided with the distribution. - -* Neither the name of Kevin Decker nor the names of its - contributors may be used to endorse or promote products - derived from this software without specific prior - written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR -IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER -IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT -OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/mocha/node_modules/diff/diff.js b/tests/mocha/node_modules/diff/diff.js deleted file mode 100644 index a34c22a044..0000000000 --- a/tests/mocha/node_modules/diff/diff.js +++ /dev/null @@ -1,354 +0,0 @@ -/* See LICENSE file for terms of use */ - -/* - * Text diff implementation. - * - * This library supports the following APIS: - * JsDiff.diffChars: Character by character diff - * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace - * JsDiff.diffLines: Line based diff - * - * JsDiff.diffCss: Diff targeted at CSS content - * - * These methods are based on the implementation proposed in - * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). - * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 - */ -var JsDiff = (function() { - /*jshint maxparams: 5*/ - function clonePath(path) { - return { newPos: path.newPos, components: path.components.slice(0) }; - } - function removeEmpty(array) { - var ret = []; - for (var i = 0; i < array.length; i++) { - if (array[i]) { - ret.push(array[i]); - } - } - return ret; - } - function escapeHTML(s) { - var n = s; - n = n.replace(/&/g, '&'); - n = n.replace(//g, '>'); - n = n.replace(/"/g, '"'); - - return n; - } - - var Diff = function(ignoreWhitespace) { - this.ignoreWhitespace = ignoreWhitespace; - }; - Diff.prototype = { - diff: function(oldString, newString) { - // Handle the identity case (this is due to unrolling editLength == 0 - if (newString === oldString) { - return [{ value: newString }]; - } - if (!newString) { - return [{ value: oldString, removed: true }]; - } - if (!oldString) { - return [{ value: newString, added: true }]; - } - - newString = this.tokenize(newString); - oldString = this.tokenize(oldString); - - var newLen = newString.length, oldLen = oldString.length; - var maxEditLength = newLen + oldLen; - var bestPath = [{ newPos: -1, components: [] }]; - - // Seed editLength = 0 - var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); - if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) { - return bestPath[0].components; - } - - for (var editLength = 1; editLength <= maxEditLength; editLength++) { - for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) { - var basePath; - var addPath = bestPath[diagonalPath-1], - removePath = bestPath[diagonalPath+1]; - oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; - if (addPath) { - // No one else is going to attempt to use this value, clear it - bestPath[diagonalPath-1] = undefined; - } - - var canAdd = addPath && addPath.newPos+1 < newLen; - var canRemove = removePath && 0 <= oldPos && oldPos < oldLen; - if (!canAdd && !canRemove) { - bestPath[diagonalPath] = undefined; - continue; - } - - // Select the diagonal that we want to branch from. We select the prior - // path whose position in the new string is the farthest from the origin - // and does not pass the bounds of the diff graph - if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { - basePath = clonePath(removePath); - this.pushComponent(basePath.components, oldString[oldPos], undefined, true); - } else { - basePath = clonePath(addPath); - basePath.newPos++; - this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined); - } - - var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath); - - if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) { - return basePath.components; - } else { - bestPath[diagonalPath] = basePath; - } - } - } - }, - - pushComponent: function(components, value, added, removed) { - var last = components[components.length-1]; - if (last && last.added === added && last.removed === removed) { - // We need to clone here as the component clone operation is just - // as shallow array clone - components[components.length-1] = - {value: this.join(last.value, value), added: added, removed: removed }; - } else { - components.push({value: value, added: added, removed: removed }); - } - }, - extractCommon: function(basePath, newString, oldString, diagonalPath) { - var newLen = newString.length, - oldLen = oldString.length, - newPos = basePath.newPos, - oldPos = newPos - diagonalPath; - while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) { - newPos++; - oldPos++; - - this.pushComponent(basePath.components, newString[newPos], undefined, undefined); - } - basePath.newPos = newPos; - return oldPos; - }, - - equals: function(left, right) { - var reWhitespace = /\S/; - if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) { - return true; - } else { - return left === right; - } - }, - join: function(left, right) { - return left + right; - }, - tokenize: function(value) { - return value; - } - }; - - var CharDiff = new Diff(); - - var WordDiff = new Diff(true); - var WordWithSpaceDiff = new Diff(); - WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { - return removeEmpty(value.split(/(\s+|\b)/)); - }; - - var CssDiff = new Diff(true); - CssDiff.tokenize = function(value) { - return removeEmpty(value.split(/([{}:;,]|\s+)/)); - }; - - var LineDiff = new Diff(); - LineDiff.tokenize = function(value) { - return value.split(/^/m); - }; - - return { - Diff: Diff, - - diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); }, - diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); }, - diffWordsWithSpace: function(oldStr, newStr) { return WordWithSpaceDiff.diff(oldStr, newStr); }, - diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); }, - - diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); }, - - createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { - var ret = []; - - ret.push('Index: ' + fileName); - ret.push('==================================================================='); - ret.push('--- ' + fileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); - ret.push('+++ ' + fileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); - - var diff = LineDiff.diff(oldStr, newStr); - if (!diff[diff.length-1].value) { - diff.pop(); // Remove trailing newline add - } - diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier - - function contextLines(lines) { - return lines.map(function(entry) { return ' ' + entry; }); - } - function eofNL(curRange, i, current) { - var last = diff[diff.length-2], - isLast = i === diff.length-2, - isLastOfType = i === diff.length-3 && (current.added !== last.added || current.removed !== last.removed); - - // Figure out if this is the last line for the given file and missing NL - if (!/\n$/.test(current.value) && (isLast || isLastOfType)) { - curRange.push('\\ No newline at end of file'); - } - } - - var oldRangeStart = 0, newRangeStart = 0, curRange = [], - oldLine = 1, newLine = 1; - for (var i = 0; i < diff.length; i++) { - var current = diff[i], - lines = current.lines || current.value.replace(/\n$/, '').split('\n'); - current.lines = lines; - - if (current.added || current.removed) { - if (!oldRangeStart) { - var prev = diff[i-1]; - oldRangeStart = oldLine; - newRangeStart = newLine; - - if (prev) { - curRange = contextLines(prev.lines.slice(-4)); - oldRangeStart -= curRange.length; - newRangeStart -= curRange.length; - } - } - curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?'+':'-') + entry; })); - eofNL(curRange, i, current); - - if (current.added) { - newLine += lines.length; - } else { - oldLine += lines.length; - } - } else { - if (oldRangeStart) { - // Close out any changes that have been output (or join overlapping) - if (lines.length <= 8 && i < diff.length-2) { - // Overlapping - curRange.push.apply(curRange, contextLines(lines)); - } else { - // end the range and output - var contextSize = Math.min(lines.length, 4); - ret.push( - '@@ -' + oldRangeStart + ',' + (oldLine-oldRangeStart+contextSize) - + ' +' + newRangeStart + ',' + (newLine-newRangeStart+contextSize) - + ' @@'); - ret.push.apply(ret, curRange); - ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); - if (lines.length <= 4) { - eofNL(ret, i, current); - } - - oldRangeStart = 0; newRangeStart = 0; curRange = []; - } - } - oldLine += lines.length; - newLine += lines.length; - } - } - - return ret.join('\n') + '\n'; - }, - - applyPatch: function(oldStr, uniDiff) { - var diffstr = uniDiff.split('\n'); - var diff = []; - var remEOFNL = false, - addEOFNL = false; - - for (var i = (diffstr[0][0]==='I'?4:0); i < diffstr.length; i++) { - if(diffstr[i][0] === '@') { - var meh = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); - diff.unshift({ - start:meh[3], - oldlength:meh[2], - oldlines:[], - newlength:meh[4], - newlines:[] - }); - } else if(diffstr[i][0] === '+') { - diff[0].newlines.push(diffstr[i].substr(1)); - } else if(diffstr[i][0] === '-') { - diff[0].oldlines.push(diffstr[i].substr(1)); - } else if(diffstr[i][0] === ' ') { - diff[0].newlines.push(diffstr[i].substr(1)); - diff[0].oldlines.push(diffstr[i].substr(1)); - } else if(diffstr[i][0] === '\\') { - if (diffstr[i-1][0] === '+') { - remEOFNL = true; - } else if(diffstr[i-1][0] === '-') { - addEOFNL = true; - } - } - } - - var str = oldStr.split('\n'); - for (var i = diff.length - 1; i >= 0; i--) { - var d = diff[i]; - for (var j = 0; j < d.oldlength; j++) { - if(str[d.start-1+j] !== d.oldlines[j]) { - return false; - } - } - Array.prototype.splice.apply(str,[d.start-1,+d.oldlength].concat(d.newlines)); - } - - if (remEOFNL) { - while (!str[str.length-1]) { - str.pop(); - } - } else if (addEOFNL) { - str.push(''); - } - return str.join('\n'); - }, - - convertChangesToXML: function(changes){ - var ret = []; - for ( var i = 0; i < changes.length; i++) { - var change = changes[i]; - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } - - ret.push(escapeHTML(change.value)); - - if (change.added) { - ret.push(''); - } else if (change.removed) { - ret.push(''); - } - } - return ret.join(''); - }, - - // See: http://code.google.com/p/google-diff-match-patch/wiki/API - convertChangesToDMP: function(changes){ - var ret = [], change; - for ( var i = 0; i < changes.length; i++) { - change = changes[i]; - ret.push([(change.added ? 1 : change.removed ? -1 : 0), change.value]); - } - return ret; - } - }; -})(); - -if (typeof module !== 'undefined') { - module.exports = JsDiff; -} diff --git a/tests/mocha/node_modules/diff/package.json b/tests/mocha/node_modules/diff/package.json deleted file mode 100644 index 867fd0ce84..0000000000 --- a/tests/mocha/node_modules/diff/package.json +++ /dev/null @@ -1,51 +0,0 @@ -{ - "name": "diff", - "version": "1.0.7", - "description": "A javascript text diff implementation.", - "keywords": [ - "diff", - "javascript" - ], - "maintainers": [ - { - "name": "Kevin Decker", - "email": "kpdecker@gmail.com", - "url": "http://incaseofstairs.com" - } - ], - "bugs": { - "url": "http://github.com/kpdecker/jsdiff/issues", - "email": "kpdecker@gmail.com" - }, - "licenses": [ - { - "type": "BSD", - "url": "http://github.com/kpdecker/jsdiff/blob/master/LICENSE" - } - ], - "repository": { - "type": "git", - "url": "git://github.com/kpdecker/jsdiff.git" - }, - "engines": { - "node": ">=0.3.1" - }, - "main": "./diff", - "scripts": { - "test": "mocha test/*.js" - }, - "dependencies": {}, - "devDependencies": { - "mocha": "~1.6", - "should": "~1.2" - }, - "optionalDependencies": {}, - "files": [ - "diff.js" - ], - "readme": "# jsdiff\n\n[![Build Status](https://secure.travis-ci.org/kpdecker/jsdiff.png)](http://travis-ci.org/kpdecker/jsdiff)\n\nA javascript text differencing implementation.\n\nBased on the algorithm proposed in\n[\"An O(ND) Difference Algorithm and its Variations\" (Myers, 1986)](http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927).\n\n## Installation\n\n npm install diff\n\nor\n\n git clone git://github.com/kpdecker/jsdiff.git\n\n## API\n\n* JsDiff.diffChars(oldStr, newStr)\n Diffs two blocks of text, comparing character by character.\n\n Returns a list of change objects (See below).\n\n* JsDiff.diffWords(oldStr, newStr)\n Diffs two blocks of text, comparing word by word.\n\n Returns a list of change objects (See below).\n\n* JsDiff.diffLines(oldStr, newStr)\n Diffs two blocks of text, comparing line by line.\n\n Returns a list of change objects (See below).\n\n* JsDiff.diffCss(oldStr, newStr)\n Diffs two blocks of text, comparing CSS tokens.\n\n Returns a list of change objects (See below).\n\n* JsDiff.createPatch(fileName, oldStr, newStr, oldHeader, newHeader)\n Creates a unified diff patch.\n\n Parameters:\n * fileName : String to be output in the filename sections of the patch\n * oldStr : Original string value\n * newStr : New string value\n * oldHeader : Additional information to include in the old file header\n * newHeader : Additional information to include in thew new file header\n\n* JsDiff.applyPatch(oldStr, diffStr)\n Applies a unified diff patch.\n\n Return a string containing new version of provided data.\n\n* convertChangesToXML(changes)\n Converts a list of changes to a serialized XML format\n\n### Change Objects\nMany of the methods above return change objects. These objects are consist of the following fields:\n\n* value: Text content\n* added: True if the value was inserted into the new string\n* removed: True of the value was removed from the old string\n\nNote that some cases may omit a particular flag field. Comparison on the flag fields should always be done in a truthy or falsy manner.\n\n## [Example](http://kpdecker.github.com/jsdiff)\n\n## License\n\nSoftware License Agreement (BSD License)\n\nCopyright (c) 2009-2011, Kevin Decker kpdecker@gmail.com\n\nAll rights reserved.\n\nRedistribution and use of this software in source and binary forms, with or without modification,\nare permitted provided that the following conditions are met:\n\n* Redistributions of source code must retain the above\n copyright notice, this list of conditions and the\n following disclaimer.\n\n* Redistributions in binary form must reproduce the above\n copyright notice, this list of conditions and the\n following disclaimer in the documentation and/or other\n materials provided with the distribution.\n\n* Neither the name of Kevin Decker nor the names of its\n contributors may be used to endorse or promote products\n derived from this software without specific prior\n written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR\nIMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND\nFITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\nCONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\nDAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,\nDATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER\nIN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT\nOF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n", - "readmeFilename": "README.md", - "homepage": "https://github.com/kpdecker/jsdiff", - "_id": "diff@1.0.7", - "_from": "diff@1.0.7" -} diff --git a/tests/mocha/node_modules/glob/.npmignore b/tests/mocha/node_modules/glob/.npmignore deleted file mode 100644 index 2af4b71c93..0000000000 --- a/tests/mocha/node_modules/glob/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -.*.swp -test/a/ diff --git a/tests/mocha/node_modules/glob/.travis.yml b/tests/mocha/node_modules/glob/.travis.yml deleted file mode 100644 index baa0031d50..0000000000 --- a/tests/mocha/node_modules/glob/.travis.yml +++ /dev/null @@ -1,3 +0,0 @@ -language: node_js -node_js: - - 0.8 diff --git a/tests/mocha/node_modules/glob/LICENSE b/tests/mocha/node_modules/glob/LICENSE deleted file mode 100644 index 0c44ae716d..0000000000 --- a/tests/mocha/node_modules/glob/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) Isaac Z. Schlueter ("Author") -All rights reserved. - -The BSD License - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/mocha/node_modules/glob/README.md b/tests/mocha/node_modules/glob/README.md deleted file mode 100644 index cc69164510..0000000000 --- a/tests/mocha/node_modules/glob/README.md +++ /dev/null @@ -1,250 +0,0 @@ -# Glob - -Match files using the patterns the shell uses, like stars and stuff. - -This is a glob implementation in JavaScript. It uses the `minimatch` -library to do its matching. - -## Attention: node-glob users! - -The API has changed dramatically between 2.x and 3.x. This library is -now 100% JavaScript, and the integer flags have been replaced with an -options object. - -Also, there's an event emitter class, proper tests, and all the other -things you've come to expect from node modules. - -And best of all, no compilation! - -## Usage - -```javascript -var glob = require("glob") - -// options is optional -glob("**/*.js", options, function (er, files) { - // files is an array of filenames. - // If the `nonull` option is set, and nothing - // was found, then files is ["**/*.js"] - // er is an error object or null. -}) -``` - -## Features - -Please see the [minimatch -documentation](https://github.com/isaacs/minimatch) for more details. - -Supports these glob features: - -* Brace Expansion -* Extended glob matching -* "Globstar" `**` matching - -See: - -* `man sh` -* `man bash` -* `man 3 fnmatch` -* `man 5 gitignore` -* [minimatch documentation](https://github.com/isaacs/minimatch) - -## glob(pattern, [options], cb) - -* `pattern` {String} Pattern to be matched -* `options` {Object} -* `cb` {Function} - * `err` {Error | null} - * `matches` {Array} filenames found matching the pattern - -Perform an asynchronous glob search. - -## glob.sync(pattern, [options]) - -* `pattern` {String} Pattern to be matched -* `options` {Object} -* return: {Array} filenames found matching the pattern - -Perform a synchronous glob search. - -## Class: glob.Glob - -Create a Glob object by instanting the `glob.Glob` class. - -```javascript -var Glob = require("glob").Glob -var mg = new Glob(pattern, options, cb) -``` - -It's an EventEmitter, and starts walking the filesystem to find matches -immediately. - -### new glob.Glob(pattern, [options], [cb]) - -* `pattern` {String} pattern to search for -* `options` {Object} -* `cb` {Function} Called when an error occurs, or matches are found - * `err` {Error | null} - * `matches` {Array} filenames found matching the pattern - -Note that if the `sync` flag is set in the options, then matches will -be immediately available on the `g.found` member. - -### Properties - -* `minimatch` The minimatch object that the glob uses. -* `options` The options object passed in. -* `error` The error encountered. When an error is encountered, the - glob object is in an undefined state, and should be discarded. -* `aborted` Boolean which is set to true when calling `abort()`. There - is no way at this time to continue a glob search after aborting, but - you can re-use the statCache to avoid having to duplicate syscalls. -* `statCache` Collection of all the stat results the glob search - performed. -* `cache` Convenience object. Each field has the following possible - values: - * `false` - Path does not exist - * `true` - Path exists - * `1` - Path exists, and is not a directory - * `2` - Path exists, and is a directory - * `[file, entries, ...]` - Path exists, is a directory, and the - array value is the results of `fs.readdir` - -### Events - -* `end` When the matching is finished, this is emitted with all the - matches found. If the `nonull` option is set, and no match was found, - then the `matches` list contains the original pattern. The matches - are sorted, unless the `nosort` flag is set. -* `match` Every time a match is found, this is emitted with the matched. -* `error` Emitted when an unexpected error is encountered, or whenever - any fs error occurs if `options.strict` is set. -* `abort` When `abort()` is called, this event is raised. - -### Methods - -* `abort` Stop the search. - -### Options - -All the options that can be passed to Minimatch can also be passed to -Glob to change pattern matching behavior. Also, some have been added, -or have glob-specific ramifications. - -All options are false by default, unless otherwise noted. - -All options are added to the glob object, as well. - -* `cwd` The current working directory in which to search. Defaults - to `process.cwd()`. -* `root` The place where patterns starting with `/` will be mounted - onto. Defaults to `path.resolve(options.cwd, "/")` (`/` on Unix - systems, and `C:\` or some such on Windows.) -* `dot` Include `.dot` files in normal matches and `globstar` matches. - Note that an explicit dot in a portion of the pattern will always - match dot files. -* `nomount` By default, a pattern starting with a forward-slash will be - "mounted" onto the root setting, so that a valid filesystem path is - returned. Set this flag to disable that behavior. -* `mark` Add a `/` character to directory matches. Note that this - requires additional stat calls. -* `nosort` Don't sort the results. -* `stat` Set to true to stat *all* results. This reduces performance - somewhat, and is completely unnecessary, unless `readdir` is presumed - to be an untrustworthy indicator of file existence. It will cause - ELOOP to be triggered one level sooner in the case of cyclical - symbolic links. -* `silent` When an unusual error is encountered - when attempting to read a directory, a warning will be printed to - stderr. Set the `silent` option to true to suppress these warnings. -* `strict` When an unusual error is encountered - when attempting to read a directory, the process will just continue on - in search of other matches. Set the `strict` option to raise an error - in these cases. -* `cache` See `cache` property above. Pass in a previously generated - cache object to save some fs calls. -* `statCache` A cache of results of filesystem information, to prevent - unnecessary stat calls. While it should not normally be necessary to - set this, you may pass the statCache from one glob() call to the - options object of another, if you know that the filesystem will not - change between calls. (See "Race Conditions" below.) -* `sync` Perform a synchronous glob search. -* `nounique` In some cases, brace-expanded patterns can result in the - same file showing up multiple times in the result set. By default, - this implementation prevents duplicates in the result set. - Set this flag to disable that behavior. -* `nonull` Set to never return an empty set, instead returning a set - containing the pattern itself. This is the default in glob(3). -* `nocase` Perform a case-insensitive match. Note that case-insensitive - filesystems will sometimes result in glob returning results that are - case-insensitively matched anyway, since readdir and stat will not - raise an error. -* `debug` Set to enable debug logging in minimatch and glob. -* `globDebug` Set to enable debug logging in glob, but not minimatch. - -## Comparisons to other fnmatch/glob implementations - -While strict compliance with the existing standards is a worthwhile -goal, some discrepancies exist between node-glob and other -implementations, and are intentional. - -If the pattern starts with a `!` character, then it is negated. Set the -`nonegate` flag to suppress this behavior, and treat leading `!` -characters normally. This is perhaps relevant if you wish to start the -pattern with a negative extglob pattern like `!(a|B)`. Multiple `!` -characters at the start of a pattern will negate the pattern multiple -times. - -If a pattern starts with `#`, then it is treated as a comment, and -will not match anything. Use `\#` to match a literal `#` at the -start of a line, or set the `nocomment` flag to suppress this behavior. - -The double-star character `**` is supported by default, unless the -`noglobstar` flag is set. This is supported in the manner of bsdglob -and bash 4.1, where `**` only has special significance if it is the only -thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but -`a/**b` will not. - -If an escaped pattern has no matches, and the `nonull` flag is set, -then glob returns the pattern as-provided, rather than -interpreting the character escapes. For example, -`glob.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than -`"*a?"`. This is akin to setting the `nullglob` option in bash, except -that it does not resolve escaped pattern characters. - -If brace expansion is not disabled, then it is performed before any -other interpretation of the glob pattern. Thus, a pattern like -`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded -**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are -checked for validity. Since those two are valid, matching proceeds. - -## Windows - -**Please only use forward-slashes in glob expressions.** - -Though windows uses either `/` or `\` as its path separator, only `/` -characters are used by this glob implementation. You must use -forward-slashes **only** in glob expressions. Back-slashes will always -be interpreted as escape characters, not path separators. - -Results from absolute patterns such as `/foo/*` are mounted onto the -root setting using `path.join`. On windows, this will by default result -in `/foo/*` matching `C:\foo\bar.txt`. - -## Race Conditions - -Glob searching, by its very nature, is susceptible to race conditions, -since it relies on directory walking and such. - -As a result, it is possible that a file that exists when glob looks for -it may have been deleted or modified by the time it returns the result. - -As part of its internal implementation, this program caches all stat -and readdir calls that it makes, in order to cut down on system -overhead. However, this also makes it even more susceptible to races, -especially if the cache or statCache objects are reused between glob -calls. - -Users are thus advised not to use a glob result as a guarantee of -filesystem state in the face of rapid changes. For the vast majority -of operations, this is never a problem. diff --git a/tests/mocha/node_modules/glob/examples/g.js b/tests/mocha/node_modules/glob/examples/g.js deleted file mode 100644 index be122df002..0000000000 --- a/tests/mocha/node_modules/glob/examples/g.js +++ /dev/null @@ -1,9 +0,0 @@ -var Glob = require("../").Glob - -var pattern = "test/a/**/[cg]/../[cg]" -console.log(pattern) - -var mg = new Glob(pattern, {mark: true, sync:true}, function (er, matches) { - console.log("matches", matches) -}) -console.log("after") diff --git a/tests/mocha/node_modules/glob/examples/usr-local.js b/tests/mocha/node_modules/glob/examples/usr-local.js deleted file mode 100644 index 327a425e47..0000000000 --- a/tests/mocha/node_modules/glob/examples/usr-local.js +++ /dev/null @@ -1,9 +0,0 @@ -var Glob = require("../").Glob - -var pattern = "{./*/*,/*,/usr/local/*}" -console.log(pattern) - -var mg = new Glob(pattern, {mark: true}, function (er, matches) { - console.log("matches", matches) -}) -console.log("after") diff --git a/tests/mocha/node_modules/glob/glob.js b/tests/mocha/node_modules/glob/glob.js deleted file mode 100644 index f0118a4f47..0000000000 --- a/tests/mocha/node_modules/glob/glob.js +++ /dev/null @@ -1,675 +0,0 @@ -// Approach: -// -// 1. Get the minimatch set -// 2. For each pattern in the set, PROCESS(pattern) -// 3. Store matches per-set, then uniq them -// -// PROCESS(pattern) -// Get the first [n] items from pattern that are all strings -// Join these together. This is PREFIX. -// If there is no more remaining, then stat(PREFIX) and -// add to matches if it succeeds. END. -// readdir(PREFIX) as ENTRIES -// If fails, END -// If pattern[n] is GLOBSTAR -// // handle the case where the globstar match is empty -// // by pruning it out, and testing the resulting pattern -// PROCESS(pattern[0..n] + pattern[n+1 .. $]) -// // handle other cases. -// for ENTRY in ENTRIES (not dotfiles) -// // attach globstar + tail onto the entry -// PROCESS(pattern[0..n] + ENTRY + pattern[n .. $]) -// -// else // not globstar -// for ENTRY in ENTRIES (not dotfiles, unless pattern[n] is dot) -// Test ENTRY against pattern[n] -// If fails, continue -// If passes, PROCESS(pattern[0..n] + item + pattern[n+1 .. $]) -// -// Caveat: -// Cache all stats and readdirs results to minimize syscall. Since all -// we ever care about is existence and directory-ness, we can just keep -// `true` for files, and [children,...] for directories, or `false` for -// things that don't exist. - - - -module.exports = glob - -var fs = require("graceful-fs") -, minimatch = require("minimatch") -, Minimatch = minimatch.Minimatch -, inherits = require("inherits") -, EE = require("events").EventEmitter -, path = require("path") -, isDir = {} -, assert = require("assert").ok - -function glob (pattern, options, cb) { - if (typeof options === "function") cb = options, options = {} - if (!options) options = {} - - if (typeof options === "number") { - deprecated() - return - } - - var g = new Glob(pattern, options, cb) - return g.sync ? g.found : g -} - -glob.fnmatch = deprecated - -function deprecated () { - throw new Error("glob's interface has changed. Please see the docs.") -} - -glob.sync = globSync -function globSync (pattern, options) { - if (typeof options === "number") { - deprecated() - return - } - - options = options || {} - options.sync = true - return glob(pattern, options) -} - - -glob.Glob = Glob -inherits(Glob, EE) -function Glob (pattern, options, cb) { - if (!(this instanceof Glob)) { - return new Glob(pattern, options, cb) - } - - if (typeof cb === "function") { - this.on("error", cb) - this.on("end", function (matches) { - cb(null, matches) - }) - } - - options = options || {} - - this.EOF = {} - this._emitQueue = [] - - this.maxDepth = options.maxDepth || 1000 - this.maxLength = options.maxLength || Infinity - this.cache = options.cache || {} - this.statCache = options.statCache || {} - - this.changedCwd = false - var cwd = process.cwd() - if (!options.hasOwnProperty("cwd")) this.cwd = cwd - else { - this.cwd = options.cwd - this.changedCwd = path.resolve(options.cwd) !== cwd - } - - this.root = options.root || path.resolve(this.cwd, "/") - this.root = path.resolve(this.root) - if (process.platform === "win32") - this.root = this.root.replace(/\\/g, "/") - - this.nomount = !!options.nomount - - if (!pattern) { - throw new Error("must provide pattern") - } - - // base-matching: just use globstar for that. - if (options.matchBase && -1 === pattern.indexOf("/")) { - if (options.noglobstar) { - throw new Error("base matching requires globstar") - } - pattern = "**/" + pattern - } - - this.strict = options.strict !== false - this.dot = !!options.dot - this.mark = !!options.mark - this.sync = !!options.sync - this.nounique = !!options.nounique - this.nonull = !!options.nonull - this.nosort = !!options.nosort - this.nocase = !!options.nocase - this.stat = !!options.stat - - this.debug = !!options.debug || !!options.globDebug - if (this.debug) - this.log = console.error - - this.silent = !!options.silent - - var mm = this.minimatch = new Minimatch(pattern, options) - this.options = mm.options - pattern = this.pattern = mm.pattern - - this.error = null - this.aborted = false - - // list of all the patterns that ** has resolved do, so - // we can avoid visiting multiple times. - this._globstars = {} - - EE.call(this) - - // process each pattern in the minimatch set - var n = this.minimatch.set.length - - // The matches are stored as {: true,...} so that - // duplicates are automagically pruned. - // Later, we do an Object.keys() on these. - // Keep them as a list so we can fill in when nonull is set. - this.matches = new Array(n) - - this.minimatch.set.forEach(iterator.bind(this)) - function iterator (pattern, i, set) { - this._process(pattern, 0, i, function (er) { - if (er) this.emit("error", er) - if (-- n <= 0) this._finish() - }) - } -} - -Glob.prototype.log = function () {} - -Glob.prototype._finish = function () { - assert(this instanceof Glob) - - var nou = this.nounique - , all = nou ? [] : {} - - for (var i = 0, l = this.matches.length; i < l; i ++) { - var matches = this.matches[i] - this.log("matches[%d] =", i, matches) - // do like the shell, and spit out the literal glob - if (!matches) { - if (this.nonull) { - var literal = this.minimatch.globSet[i] - if (nou) all.push(literal) - else all[literal] = true - } - } else { - // had matches - var m = Object.keys(matches) - if (nou) all.push.apply(all, m) - else m.forEach(function (m) { - all[m] = true - }) - } - } - - if (!nou) all = Object.keys(all) - - if (!this.nosort) { - all = all.sort(this.nocase ? alphasorti : alphasort) - } - - if (this.mark) { - // at *some* point we statted all of these - all = all.map(function (m) { - var sc = this.cache[m] - if (!sc) - return m - var isDir = (Array.isArray(sc) || sc === 2) - if (isDir && m.slice(-1) !== "/") { - return m + "/" - } - if (!isDir && m.slice(-1) === "/") { - return m.replace(/\/+$/, "") - } - return m - }, this) - } - - this.log("emitting end", all) - - this.EOF = this.found = all - this.emitMatch(this.EOF) -} - -function alphasorti (a, b) { - a = a.toLowerCase() - b = b.toLowerCase() - return alphasort(a, b) -} - -function alphasort (a, b) { - return a > b ? 1 : a < b ? -1 : 0 -} - -Glob.prototype.abort = function () { - this.aborted = true - this.emit("abort") -} - -Glob.prototype.pause = function () { - if (this.paused) return - if (this.sync) - this.emit("error", new Error("Can't pause/resume sync glob")) - this.paused = true - this.emit("pause") -} - -Glob.prototype.resume = function () { - if (!this.paused) return - if (this.sync) - this.emit("error", new Error("Can't pause/resume sync glob")) - this.paused = false - this.emit("resume") - this._processEmitQueue() - //process.nextTick(this.emit.bind(this, "resume")) -} - -Glob.prototype.emitMatch = function (m) { - if (!this.stat || this.statCache[m] || m === this.EOF) { - this._emitQueue.push(m) - this._processEmitQueue() - } else { - this._stat(m, function(exists, isDir) { - if (exists) { - this._emitQueue.push(m) - this._processEmitQueue() - } - }) - } -} - -Glob.prototype._processEmitQueue = function (m) { - while (!this._processingEmitQueue && - !this.paused) { - this._processingEmitQueue = true - var m = this._emitQueue.shift() - if (!m) { - this._processingEmitQueue = false - break - } - - this.log('emit!', m === this.EOF ? "end" : "match") - - this.emit(m === this.EOF ? "end" : "match", m) - this._processingEmitQueue = false - } -} - -Glob.prototype._process = function (pattern, depth, index, cb_) { - assert(this instanceof Glob) - - var cb = function cb (er, res) { - assert(this instanceof Glob) - if (this.paused) { - if (!this._processQueue) { - this._processQueue = [] - this.once("resume", function () { - var q = this._processQueue - this._processQueue = null - q.forEach(function (cb) { cb() }) - }) - } - this._processQueue.push(cb_.bind(this, er, res)) - } else { - cb_.call(this, er, res) - } - }.bind(this) - - if (this.aborted) return cb() - - if (depth > this.maxDepth) return cb() - - // Get the first [n] parts of pattern that are all strings. - var n = 0 - while (typeof pattern[n] === "string") { - n ++ - } - // now n is the index of the first one that is *not* a string. - - // see if there's anything else - var prefix - switch (n) { - // if not, then this is rather simple - case pattern.length: - prefix = pattern.join("/") - this._stat(prefix, function (exists, isDir) { - // either it's there, or it isn't. - // nothing more to do, either way. - if (exists) { - if (prefix && isAbsolute(prefix) && !this.nomount) { - if (prefix.charAt(0) === "/") { - prefix = path.join(this.root, prefix) - } else { - prefix = path.resolve(this.root, prefix) - } - } - - if (process.platform === "win32") - prefix = prefix.replace(/\\/g, "/") - - this.matches[index] = this.matches[index] || {} - this.matches[index][prefix] = true - this.emitMatch(prefix) - } - return cb() - }) - return - - case 0: - // pattern *starts* with some non-trivial item. - // going to readdir(cwd), but not include the prefix in matches. - prefix = null - break - - default: - // pattern has some string bits in the front. - // whatever it starts with, whether that's "absolute" like /foo/bar, - // or "relative" like "../baz" - prefix = pattern.slice(0, n) - prefix = prefix.join("/") - break - } - - // get the list of entries. - var read - if (prefix === null) read = "." - else if (isAbsolute(prefix) || isAbsolute(pattern.join("/"))) { - if (!prefix || !isAbsolute(prefix)) { - prefix = path.join("/", prefix) - } - read = prefix = path.resolve(prefix) - - // if (process.platform === "win32") - // read = prefix = prefix.replace(/^[a-zA-Z]:|\\/g, "/") - - this.log('absolute: ', prefix, this.root, pattern, read) - } else { - read = prefix - } - - this.log('readdir(%j)', read, this.cwd, this.root) - - return this._readdir(read, function (er, entries) { - if (er) { - // not a directory! - // this means that, whatever else comes after this, it can never match - return cb() - } - - // globstar is special - if (pattern[n] === minimatch.GLOBSTAR) { - // test without the globstar, and with every child both below - // and replacing the globstar. - var s = [ pattern.slice(0, n).concat(pattern.slice(n + 1)) ] - entries.forEach(function (e) { - if (e.charAt(0) === "." && !this.dot) return - // instead of the globstar - s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1))) - // below the globstar - s.push(pattern.slice(0, n).concat(e).concat(pattern.slice(n))) - }, this) - - s = s.filter(function (pattern) { - var key = gsKey(pattern) - var seen = !this._globstars[key] - this._globstars[key] = true - return seen - }, this) - - if (!s.length) - return cb() - - // now asyncForEach over this - var l = s.length - , errState = null - s.forEach(function (gsPattern) { - this._process(gsPattern, depth + 1, index, function (er) { - if (errState) return - if (er) return cb(errState = er) - if (--l <= 0) return cb() - }) - }, this) - - return - } - - // not a globstar - // It will only match dot entries if it starts with a dot, or if - // dot is set. Stuff like @(.foo|.bar) isn't allowed. - var pn = pattern[n] - var rawGlob = pattern[n]._glob - , dotOk = this.dot || rawGlob.charAt(0) === "." - - entries = entries.filter(function (e) { - return (e.charAt(0) !== "." || dotOk) && - e.match(pattern[n]) - }) - - // If n === pattern.length - 1, then there's no need for the extra stat - // *unless* the user has specified "mark" or "stat" explicitly. - // We know that they exist, since the readdir returned them. - if (n === pattern.length - 1 && - !this.mark && - !this.stat) { - entries.forEach(function (e) { - if (prefix) { - if (prefix !== "/") e = prefix + "/" + e - else e = prefix + e - } - if (e.charAt(0) === "/" && !this.nomount) { - e = path.join(this.root, e) - } - - if (process.platform === "win32") - e = e.replace(/\\/g, "/") - - this.matches[index] = this.matches[index] || {} - this.matches[index][e] = true - this.emitMatch(e) - }, this) - return cb.call(this) - } - - - // now test all the remaining entries as stand-ins for that part - // of the pattern. - var l = entries.length - , errState = null - if (l === 0) return cb() // no matches possible - entries.forEach(function (e) { - var p = pattern.slice(0, n).concat(e).concat(pattern.slice(n + 1)) - this._process(p, depth + 1, index, function (er) { - if (errState) return - if (er) return cb(errState = er) - if (--l === 0) return cb.call(this) - }) - }, this) - }) - -} - -function gsKey (pattern) { - return '**' + pattern.map(function (p) { - return (p === minimatch.GLOBSTAR) ? '**' : (''+p) - }).join('/') -} - -Glob.prototype._stat = function (f, cb) { - assert(this instanceof Glob) - var abs = f - if (f.charAt(0) === "/") { - abs = path.join(this.root, f) - } else if (this.changedCwd) { - abs = path.resolve(this.cwd, f) - } - - if (f.length > this.maxLength) { - var er = new Error("Path name too long") - er.code = "ENAMETOOLONG" - er.path = f - return this._afterStat(f, abs, cb, er) - } - - this.log('stat', [this.cwd, f, '=', abs]) - - if (!this.stat && this.cache.hasOwnProperty(f)) { - var exists = this.cache[f] - , isDir = exists && (Array.isArray(exists) || exists === 2) - if (this.sync) return cb.call(this, !!exists, isDir) - return process.nextTick(cb.bind(this, !!exists, isDir)) - } - - var stat = this.statCache[abs] - if (this.sync || stat) { - var er - try { - stat = fs.statSync(abs) - } catch (e) { - er = e - } - this._afterStat(f, abs, cb, er, stat) - } else { - fs.stat(abs, this._afterStat.bind(this, f, abs, cb)) - } -} - -Glob.prototype._afterStat = function (f, abs, cb, er, stat) { - var exists - assert(this instanceof Glob) - - if (abs.slice(-1) === "/" && stat && !stat.isDirectory()) { - this.log("should be ENOTDIR, fake it") - - er = new Error("ENOTDIR, not a directory '" + abs + "'") - er.path = abs - er.code = "ENOTDIR" - stat = null - } - - var emit = !this.statCache[abs] - this.statCache[abs] = stat - - if (er || !stat) { - exists = false - } else { - exists = stat.isDirectory() ? 2 : 1 - if (emit) - this.emit('stat', f, stat) - } - this.cache[f] = this.cache[f] || exists - cb.call(this, !!exists, exists === 2) -} - -Glob.prototype._readdir = function (f, cb) { - assert(this instanceof Glob) - var abs = f - if (f.charAt(0) === "/") { - abs = path.join(this.root, f) - } else if (isAbsolute(f)) { - abs = f - } else if (this.changedCwd) { - abs = path.resolve(this.cwd, f) - } - - if (f.length > this.maxLength) { - var er = new Error("Path name too long") - er.code = "ENAMETOOLONG" - er.path = f - return this._afterReaddir(f, abs, cb, er) - } - - this.log('readdir', [this.cwd, f, abs]) - if (this.cache.hasOwnProperty(f)) { - var c = this.cache[f] - if (Array.isArray(c)) { - if (this.sync) return cb.call(this, null, c) - return process.nextTick(cb.bind(this, null, c)) - } - - if (!c || c === 1) { - // either ENOENT or ENOTDIR - var code = c ? "ENOTDIR" : "ENOENT" - , er = new Error((c ? "Not a directory" : "Not found") + ": " + f) - er.path = f - er.code = code - this.log(f, er) - if (this.sync) return cb.call(this, er) - return process.nextTick(cb.bind(this, er)) - } - - // at this point, c === 2, meaning it's a dir, but we haven't - // had to read it yet, or c === true, meaning it's *something* - // but we don't have any idea what. Need to read it, either way. - } - - if (this.sync) { - var er, entries - try { - entries = fs.readdirSync(abs) - } catch (e) { - er = e - } - return this._afterReaddir(f, abs, cb, er, entries) - } - - fs.readdir(abs, this._afterReaddir.bind(this, f, abs, cb)) -} - -Glob.prototype._afterReaddir = function (f, abs, cb, er, entries) { - assert(this instanceof Glob) - if (entries && !er) { - this.cache[f] = entries - // if we haven't asked to stat everything for suresies, then just - // assume that everything in there exists, so we can avoid - // having to stat it a second time. This also gets us one step - // further into ELOOP territory. - if (!this.mark && !this.stat) { - entries.forEach(function (e) { - if (f === "/") e = f + e - else e = f + "/" + e - this.cache[e] = true - }, this) - } - - return cb.call(this, er, entries) - } - - // now handle errors, and cache the information - if (er) switch (er.code) { - case "ENOTDIR": // totally normal. means it *does* exist. - this.cache[f] = 1 - return cb.call(this, er) - case "ENOENT": // not terribly unusual - case "ELOOP": - case "ENAMETOOLONG": - case "UNKNOWN": - this.cache[f] = false - return cb.call(this, er) - default: // some unusual error. Treat as failure. - this.cache[f] = false - if (this.strict) this.emit("error", er) - if (!this.silent) console.error("glob error", er) - return cb.call(this, er) - } -} - -var isAbsolute = process.platform === "win32" ? absWin : absUnix - -function absWin (p) { - if (absUnix(p)) return true - // pull off the device/UNC bit from a windows path. - // from node's lib/path.js - var splitDeviceRe = - /^([a-zA-Z]:|[\\\/]{2}[^\\\/]+[\\\/]+[^\\\/]+)?([\\\/])?([\s\S]*?)$/ - , result = splitDeviceRe.exec(p) - , device = result[1] || '' - , isUnc = device && device.charAt(1) !== ':' - , isAbsolute = !!result[2] || isUnc // UNC paths are always absolute - - return isAbsolute -} - -function absUnix (p) { - return p.charAt(0) === "/" || p === "" -} diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/.npmignore b/tests/mocha/node_modules/glob/node_modules/graceful-fs/.npmignore deleted file mode 100644 index c2658d7d1b..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/graceful-fs/.npmignore +++ /dev/null @@ -1 +0,0 @@ -node_modules/ diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/LICENSE b/tests/mocha/node_modules/glob/node_modules/graceful-fs/LICENSE deleted file mode 100644 index 0c44ae716d..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/graceful-fs/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) Isaac Z. Schlueter ("Author") -All rights reserved. - -The BSD License - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/README.md b/tests/mocha/node_modules/glob/node_modules/graceful-fs/README.md deleted file mode 100644 index eb1a109356..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/graceful-fs/README.md +++ /dev/null @@ -1,26 +0,0 @@ -# graceful-fs - -graceful-fs functions as a drop-in replacement for the fs module, -making various improvements. - -The improvements are meant to normalize behavior across different -platforms and environments, and to make filesystem access more -resilient to errors. - -## Improvements over fs module - -graceful-fs: - -* Queues up `open` and `readdir` calls, and retries them once - something closes if there is an EMFILE error from too many file - descriptors. -* fixes `lchmod` for Node versions prior to 0.6.2. -* implements `fs.lutimes` if possible. Otherwise it becomes a noop. -* ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or - `lchown` if the user isn't root. -* makes `lchmod` and `lchown` become noops, if not available. -* retries reading a file if `read` results in EAGAIN error. - -On Windows, it retries renaming a file for up to one second if `EACCESS` -or `EPERM` error occurs, likely because antivirus software has locked -the directory. diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/graceful-fs.js b/tests/mocha/node_modules/glob/node_modules/graceful-fs/graceful-fs.js deleted file mode 100644 index c84db91019..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/graceful-fs/graceful-fs.js +++ /dev/null @@ -1,160 +0,0 @@ -// Monkey-patching the fs module. -// It's ugly, but there is simply no other way to do this. -var fs = module.exports = require('fs') - -var assert = require('assert') - -// fix up some busted stuff, mostly on windows and old nodes -require('./polyfills.js') - -// The EMFILE enqueuing stuff - -var util = require('util') - -function noop () {} - -var debug = noop -if (util.debuglog) - debug = util.debuglog('gfs') -else if (/\bgfs\b/i.test(process.env.NODE_DEBUG || '')) - debug = function() { - var m = util.format.apply(util, arguments) - m = 'GFS: ' + m.split(/\n/).join('\nGFS: ') - console.error(m) - } - -if (/\bgfs\b/i.test(process.env.NODE_DEBUG || '')) { - process.on('exit', function() { - debug('fds', fds) - debug(queue) - assert.equal(queue.length, 0) - }) -} - - -var originalOpen = fs.open -fs.open = open - -function open(path, flags, mode, cb) { - if (typeof mode === "function") cb = mode, mode = null - if (typeof cb !== "function") cb = noop - new OpenReq(path, flags, mode, cb) -} - -function OpenReq(path, flags, mode, cb) { - this.path = path - this.flags = flags - this.mode = mode - this.cb = cb - Req.call(this) -} - -util.inherits(OpenReq, Req) - -OpenReq.prototype.process = function() { - originalOpen.call(fs, this.path, this.flags, this.mode, this.done) -} - -var fds = {} -OpenReq.prototype.done = function(er, fd) { - debug('open done', er, fd) - if (fd) - fds['fd' + fd] = this.path - Req.prototype.done.call(this, er, fd) -} - - -var originalReaddir = fs.readdir -fs.readdir = readdir - -function readdir(path, cb) { - if (typeof cb !== "function") cb = noop - new ReaddirReq(path, cb) -} - -function ReaddirReq(path, cb) { - this.path = path - this.cb = cb - Req.call(this) -} - -util.inherits(ReaddirReq, Req) - -ReaddirReq.prototype.process = function() { - originalReaddir.call(fs, this.path, this.done) -} - -ReaddirReq.prototype.done = function(er, files) { - if (files && files.sort) - files = files.sort() - Req.prototype.done.call(this, er, files) - onclose() -} - - -var originalClose = fs.close -fs.close = close - -function close (fd, cb) { - debug('close', fd) - if (typeof cb !== "function") cb = noop - delete fds['fd' + fd] - originalClose.call(fs, fd, function(er) { - onclose() - cb(er) - }) -} - - -var originalCloseSync = fs.closeSync -fs.closeSync = closeSync - -function closeSync (fd) { - try { - return originalCloseSync(fd) - } finally { - onclose() - } -} - - -// Req class -function Req () { - // start processing - this.done = this.done.bind(this) - this.failures = 0 - this.process() -} - -Req.prototype.done = function (er, result) { - var tryAgain = false - if (er) { - var code = er.code - var tryAgain = code === "EMFILE" - if (process.platform === "win32") - tryAgain = tryAgain || code === "OK" - } - - if (tryAgain) { - this.failures ++ - enqueue(this) - } else { - var cb = this.cb - cb(er, result) - } -} - -var queue = [] - -function enqueue(req) { - queue.push(req) - debug('enqueue %d %s', queue.length, req.constructor.name, req) -} - -function onclose() { - var req = queue.shift() - if (req) { - debug('process', req.constructor.name, req) - req.process() - } -} diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/package.json b/tests/mocha/node_modules/glob/node_modules/graceful-fs/package.json deleted file mode 100644 index 89d7462c3e..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/graceful-fs/package.json +++ /dev/null @@ -1,49 +0,0 @@ -{ - "author": { - "name": "Isaac Z. Schlueter", - "email": "i@izs.me", - "url": "http://blog.izs.me" - }, - "name": "graceful-fs", - "description": "A drop-in replacement for fs, making various improvements.", - "version": "2.0.3", - "repository": { - "type": "git", - "url": "git://github.com/isaacs/node-graceful-fs.git" - }, - "main": "graceful-fs.js", - "engines": { - "node": ">=0.4.0" - }, - "directories": { - "test": "test" - }, - "scripts": { - "test": "tap test/*.js" - }, - "keywords": [ - "fs", - "module", - "reading", - "retry", - "retries", - "queue", - "error", - "errors", - "handling", - "EMFILE", - "EAGAIN", - "EINVAL", - "EPERM", - "EACCESS" - ], - "license": "BSD", - "readme": "# graceful-fs\n\ngraceful-fs functions as a drop-in replacement for the fs module,\nmaking various improvements.\n\nThe improvements are meant to normalize behavior across different\nplatforms and environments, and to make filesystem access more\nresilient to errors.\n\n## Improvements over fs module\n\ngraceful-fs:\n\n* Queues up `open` and `readdir` calls, and retries them once\n something closes if there is an EMFILE error from too many file\n descriptors.\n* fixes `lchmod` for Node versions prior to 0.6.2.\n* implements `fs.lutimes` if possible. Otherwise it becomes a noop.\n* ignores `EINVAL` and `EPERM` errors in `chown`, `fchown` or\n `lchown` if the user isn't root.\n* makes `lchmod` and `lchown` become noops, if not available.\n* retries reading a file if `read` results in EAGAIN error.\n\nOn Windows, it retries renaming a file for up to one second if `EACCESS`\nor `EPERM` error occurs, likely because antivirus software has locked\nthe directory.\n", - "readmeFilename": "README.md", - "bugs": { - "url": "https://github.com/isaacs/node-graceful-fs/issues" - }, - "homepage": "https://github.com/isaacs/node-graceful-fs", - "_id": "graceful-fs@2.0.3", - "_from": "graceful-fs@~2.0.0" -} diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/polyfills.js b/tests/mocha/node_modules/glob/node_modules/graceful-fs/polyfills.js deleted file mode 100644 index afc83b3f2c..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/graceful-fs/polyfills.js +++ /dev/null @@ -1,228 +0,0 @@ -var fs = require('fs') -var constants = require('constants') - -var origCwd = process.cwd -var cwd = null -process.cwd = function() { - if (!cwd) - cwd = origCwd.call(process) - return cwd -} -var chdir = process.chdir -process.chdir = function(d) { - cwd = null - chdir.call(process, d) -} - -// (re-)implement some things that are known busted or missing. - -// lchmod, broken prior to 0.6.2 -// back-port the fix here. -if (constants.hasOwnProperty('O_SYMLINK') && - process.version.match(/^v0\.6\.[0-2]|^v0\.5\./)) { - fs.lchmod = function (path, mode, callback) { - callback = callback || noop - fs.open( path - , constants.O_WRONLY | constants.O_SYMLINK - , mode - , function (err, fd) { - if (err) { - callback(err) - return - } - // prefer to return the chmod error, if one occurs, - // but still try to close, and report closing errors if they occur. - fs.fchmod(fd, mode, function (err) { - fs.close(fd, function(err2) { - callback(err || err2) - }) - }) - }) - } - - fs.lchmodSync = function (path, mode) { - var fd = fs.openSync(path, constants.O_WRONLY | constants.O_SYMLINK, mode) - - // prefer to return the chmod error, if one occurs, - // but still try to close, and report closing errors if they occur. - var err, err2 - try { - var ret = fs.fchmodSync(fd, mode) - } catch (er) { - err = er - } - try { - fs.closeSync(fd) - } catch (er) { - err2 = er - } - if (err || err2) throw (err || err2) - return ret - } -} - - -// lutimes implementation, or no-op -if (!fs.lutimes) { - if (constants.hasOwnProperty("O_SYMLINK")) { - fs.lutimes = function (path, at, mt, cb) { - fs.open(path, constants.O_SYMLINK, function (er, fd) { - cb = cb || noop - if (er) return cb(er) - fs.futimes(fd, at, mt, function (er) { - fs.close(fd, function (er2) { - return cb(er || er2) - }) - }) - }) - } - - fs.lutimesSync = function (path, at, mt) { - var fd = fs.openSync(path, constants.O_SYMLINK) - , err - , err2 - , ret - - try { - var ret = fs.futimesSync(fd, at, mt) - } catch (er) { - err = er - } - try { - fs.closeSync(fd) - } catch (er) { - err2 = er - } - if (err || err2) throw (err || err2) - return ret - } - - } else if (fs.utimensat && constants.hasOwnProperty("AT_SYMLINK_NOFOLLOW")) { - // maybe utimensat will be bound soonish? - fs.lutimes = function (path, at, mt, cb) { - fs.utimensat(path, at, mt, constants.AT_SYMLINK_NOFOLLOW, cb) - } - - fs.lutimesSync = function (path, at, mt) { - return fs.utimensatSync(path, at, mt, constants.AT_SYMLINK_NOFOLLOW) - } - - } else { - fs.lutimes = function (_a, _b, _c, cb) { process.nextTick(cb) } - fs.lutimesSync = function () {} - } -} - - -// https://github.com/isaacs/node-graceful-fs/issues/4 -// Chown should not fail on einval or eperm if non-root. - -fs.chown = chownFix(fs.chown) -fs.fchown = chownFix(fs.fchown) -fs.lchown = chownFix(fs.lchown) - -fs.chownSync = chownFixSync(fs.chownSync) -fs.fchownSync = chownFixSync(fs.fchownSync) -fs.lchownSync = chownFixSync(fs.lchownSync) - -function chownFix (orig) { - if (!orig) return orig - return function (target, uid, gid, cb) { - return orig.call(fs, target, uid, gid, function (er, res) { - if (chownErOk(er)) er = null - cb(er, res) - }) - } -} - -function chownFixSync (orig) { - if (!orig) return orig - return function (target, uid, gid) { - try { - return orig.call(fs, target, uid, gid) - } catch (er) { - if (!chownErOk(er)) throw er - } - } -} - -function chownErOk (er) { - // if there's no getuid, or if getuid() is something other than 0, - // and the error is EINVAL or EPERM, then just ignore it. - // This specific case is a silent failure in cp, install, tar, - // and most other unix tools that manage permissions. - // When running as root, or if other types of errors are encountered, - // then it's strict. - if (!er || (!process.getuid || process.getuid() !== 0) - && (er.code === "EINVAL" || er.code === "EPERM")) return true -} - - -// if lchmod/lchown do not exist, then make them no-ops -if (!fs.lchmod) { - fs.lchmod = function (path, mode, cb) { - process.nextTick(cb) - } - fs.lchmodSync = function () {} -} -if (!fs.lchown) { - fs.lchown = function (path, uid, gid, cb) { - process.nextTick(cb) - } - fs.lchownSync = function () {} -} - - - -// on Windows, A/V software can lock the directory, causing this -// to fail with an EACCES or EPERM if the directory contains newly -// created files. Try again on failure, for up to 1 second. -if (process.platform === "win32") { - var rename_ = fs.rename - fs.rename = function rename (from, to, cb) { - var start = Date.now() - rename_(from, to, function CB (er) { - if (er - && (er.code === "EACCES" || er.code === "EPERM") - && Date.now() - start < 1000) { - return rename_(from, to, CB) - } - cb(er) - }) - } -} - - -// if read() returns EAGAIN, then just try it again. -var read = fs.read -fs.read = function (fd, buffer, offset, length, position, callback_) { - var callback - if (callback_ && typeof callback_ === 'function') { - var eagCounter = 0 - callback = function (er, _, __) { - if (er && er.code === 'EAGAIN' && eagCounter < 10) { - eagCounter ++ - return read.call(fs, fd, buffer, offset, length, position, callback) - } - callback_.apply(this, arguments) - } - } - return read.call(fs, fd, buffer, offset, length, position, callback) -} - -var readSync = fs.readSync -fs.readSync = function (fd, buffer, offset, length, position) { - var eagCounter = 0 - while (true) { - try { - return readSync.call(fs, fd, buffer, offset, length, position) - } catch (er) { - if (er.code === 'EAGAIN' && eagCounter < 10) { - eagCounter ++ - continue - } - throw er - } - } -} - diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/open.js b/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/open.js deleted file mode 100644 index 104f36b0b9..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/open.js +++ /dev/null @@ -1,39 +0,0 @@ -var test = require('tap').test -var fs = require('../graceful-fs.js') - -test('graceful fs is monkeypatched fs', function (t) { - t.equal(fs, require('fs')) - t.end() -}) - -test('open an existing file works', function (t) { - var fd = fs.openSync(__filename, 'r') - fs.closeSync(fd) - fs.open(__filename, 'r', function (er, fd) { - if (er) throw er - fs.close(fd, function (er) { - if (er) throw er - t.pass('works') - t.end() - }) - }) -}) - -test('open a non-existing file throws', function (t) { - var er - try { - var fd = fs.openSync('this file does not exist', 'r') - } catch (x) { - er = x - } - t.ok(er, 'should throw') - t.notOk(fd, 'should not get an fd') - t.equal(er.code, 'ENOENT') - - fs.open('neither does this file', 'r', function (er, fd) { - t.ok(er, 'should throw') - t.notOk(fd, 'should not get an fd') - t.equal(er.code, 'ENOENT') - t.end() - }) -}) diff --git a/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/readdir-sort.js b/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/readdir-sort.js deleted file mode 100644 index aeaedf1c16..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/graceful-fs/test/readdir-sort.js +++ /dev/null @@ -1,21 +0,0 @@ -var test = require("tap").test -var fs = require("fs") - -var readdir = fs.readdir -fs.readdir = function(path, cb) { - process.nextTick(function() { - cb(null, ["b", "z", "a"]) - }) -} - -var g = require("../") - -test("readdir reorder", function (t) { - g.readdir("whatevers", function (er, files) { - if (er) - throw er - console.error(files) - t.same(files, [ "a", "b", "z" ]) - t.end() - }) -}) diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/LICENSE b/tests/mocha/node_modules/glob/node_modules/inherits/LICENSE deleted file mode 100644 index dea3013d67..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/inherits/LICENSE +++ /dev/null @@ -1,16 +0,0 @@ -The ISC License - -Copyright (c) Isaac Z. Schlueter - -Permission to use, copy, modify, and/or distribute this software for any -purpose with or without fee is hereby granted, provided that the above -copyright notice and this permission notice appear in all copies. - -THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH -REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND -FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, -INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM -LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR -OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR -PERFORMANCE OF THIS SOFTWARE. - diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/README.md b/tests/mocha/node_modules/glob/node_modules/inherits/README.md deleted file mode 100644 index b1c5665855..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/inherits/README.md +++ /dev/null @@ -1,42 +0,0 @@ -Browser-friendly inheritance fully compatible with standard node.js -[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor). - -This package exports standard `inherits` from node.js `util` module in -node environment, but also provides alternative browser-friendly -implementation through [browser -field](https://gist.github.com/shtylman/4339901). Alternative -implementation is a literal copy of standard one located in standalone -module to avoid requiring of `util`. It also has a shim for old -browsers with no `Object.create` support. - -While keeping you sure you are using standard `inherits` -implementation in node.js environment, it allows bundlers such as -[browserify](https://github.com/substack/node-browserify) to not -include full `util` package to your client code if all you need is -just `inherits` function. It worth, because browser shim for `util` -package is large and `inherits` is often the single function you need -from it. - -It's recommended to use this package instead of -`require('util').inherits` for any code that has chances to be used -not only in node.js but in browser too. - -## usage - -```js -var inherits = require('inherits'); -// then use exactly as the standard one -``` - -## note on version ~1.0 - -Version ~1.0 had completely different motivation and is not compatible -neither with 2.0 nor with standard node.js `inherits`. - -If you are using version ~1.0 and planning to switch to ~2.0, be -careful: - -* new version uses `super_` instead of `super` for referencing - superclass -* new version overwrites current prototype while old one preserves any - existing fields on it diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/inherits.js b/tests/mocha/node_modules/glob/node_modules/inherits/inherits.js deleted file mode 100644 index 29f5e24f57..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/inherits/inherits.js +++ /dev/null @@ -1 +0,0 @@ -module.exports = require('util').inherits diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/inherits_browser.js b/tests/mocha/node_modules/glob/node_modules/inherits/inherits_browser.js deleted file mode 100644 index c1e78a75e6..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/inherits/inherits_browser.js +++ /dev/null @@ -1,23 +0,0 @@ -if (typeof Object.create === 'function') { - // implementation from standard node.js 'util' module - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - ctor.prototype = Object.create(superCtor.prototype, { - constructor: { - value: ctor, - enumerable: false, - writable: true, - configurable: true - } - }); - }; -} else { - // old school shim for old browsers - module.exports = function inherits(ctor, superCtor) { - ctor.super_ = superCtor - var TempCtor = function () {} - TempCtor.prototype = superCtor.prototype - ctor.prototype = new TempCtor() - ctor.prototype.constructor = ctor - } -} diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/package.json b/tests/mocha/node_modules/glob/node_modules/inherits/package.json deleted file mode 100644 index c532ca6d14..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/inherits/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "inherits", - "description": "Browser-friendly inheritance fully compatible with standard node.js inherits()", - "version": "2.0.1", - "keywords": [ - "inheritance", - "class", - "klass", - "oop", - "object-oriented", - "inherits", - "browser", - "browserify" - ], - "main": "./inherits.js", - "browser": "./inherits_browser.js", - "repository": { - "type": "git", - "url": "git://github.com/isaacs/inherits" - }, - "license": "ISC", - "scripts": { - "test": "node test" - }, - "readme": "Browser-friendly inheritance fully compatible with standard node.js\n[inherits](http://nodejs.org/api/util.html#util_util_inherits_constructor_superconstructor).\n\nThis package exports standard `inherits` from node.js `util` module in\nnode environment, but also provides alternative browser-friendly\nimplementation through [browser\nfield](https://gist.github.com/shtylman/4339901). Alternative\nimplementation is a literal copy of standard one located in standalone\nmodule to avoid requiring of `util`. It also has a shim for old\nbrowsers with no `Object.create` support.\n\nWhile keeping you sure you are using standard `inherits`\nimplementation in node.js environment, it allows bundlers such as\n[browserify](https://github.com/substack/node-browserify) to not\ninclude full `util` package to your client code if all you need is\njust `inherits` function. It worth, because browser shim for `util`\npackage is large and `inherits` is often the single function you need\nfrom it.\n\nIt's recommended to use this package instead of\n`require('util').inherits` for any code that has chances to be used\nnot only in node.js but in browser too.\n\n## usage\n\n```js\nvar inherits = require('inherits');\n// then use exactly as the standard one\n```\n\n## note on version ~1.0\n\nVersion ~1.0 had completely different motivation and is not compatible\nneither with 2.0 nor with standard node.js `inherits`.\n\nIf you are using version ~1.0 and planning to switch to ~2.0, be\ncareful:\n\n* new version uses `super_` instead of `super` for referencing\n superclass\n* new version overwrites current prototype while old one preserves any\n existing fields on it\n", - "readmeFilename": "README.md", - "bugs": { - "url": "https://github.com/isaacs/inherits/issues" - }, - "homepage": "https://github.com/isaacs/inherits", - "_id": "inherits@2.0.1", - "_from": "inherits@~2.0.1" -} diff --git a/tests/mocha/node_modules/glob/node_modules/inherits/test.js b/tests/mocha/node_modules/glob/node_modules/inherits/test.js deleted file mode 100644 index fc53012d31..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/inherits/test.js +++ /dev/null @@ -1,25 +0,0 @@ -var inherits = require('./inherits.js') -var assert = require('assert') - -function test(c) { - assert(c.constructor === Child) - assert(c.constructor.super_ === Parent) - assert(Object.getPrototypeOf(c) === Child.prototype) - assert(Object.getPrototypeOf(Object.getPrototypeOf(c)) === Parent.prototype) - assert(c instanceof Child) - assert(c instanceof Parent) -} - -function Child() { - Parent.call(this) - test(this) -} - -function Parent() {} - -inherits(Child, Parent) - -var c = new Child -test(c) - -console.log('ok') diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/.npmignore b/tests/mocha/node_modules/glob/node_modules/minimatch/.npmignore deleted file mode 100644 index 3c3629e647..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/.npmignore +++ /dev/null @@ -1 +0,0 @@ -node_modules diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/LICENSE b/tests/mocha/node_modules/glob/node_modules/minimatch/LICENSE deleted file mode 100644 index 05a4010949..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright 2009, 2010, 2011 Isaac Z. Schlueter. -All rights reserved. - -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 -copies 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 all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER 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. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/README.md b/tests/mocha/node_modules/glob/node_modules/minimatch/README.md deleted file mode 100644 index 978268e275..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/README.md +++ /dev/null @@ -1,218 +0,0 @@ -# minimatch - -A minimal matching utility. - -[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.png)](http://travis-ci.org/isaacs/minimatch) - - -This is the matching library used internally by npm. - -Eventually, it will replace the C binding in node-glob. - -It works by converting glob expressions into JavaScript `RegExp` -objects. - -## Usage - -```javascript -var minimatch = require("minimatch") - -minimatch("bar.foo", "*.foo") // true! -minimatch("bar.foo", "*.bar") // false! -minimatch("bar.foo", "*.+(bar|foo)", { debug: true }) // true, and noisy! -``` - -## Features - -Supports these glob features: - -* Brace Expansion -* Extended glob matching -* "Globstar" `**` matching - -See: - -* `man sh` -* `man bash` -* `man 3 fnmatch` -* `man 5 gitignore` - -## Minimatch Class - -Create a minimatch object by instanting the `minimatch.Minimatch` class. - -```javascript -var Minimatch = require("minimatch").Minimatch -var mm = new Minimatch(pattern, options) -``` - -### Properties - -* `pattern` The original pattern the minimatch object represents. -* `options` The options supplied to the constructor. -* `set` A 2-dimensional array of regexp or string expressions. - Each row in the - array corresponds to a brace-expanded pattern. Each item in the row - corresponds to a single path-part. For example, the pattern - `{a,b/c}/d` would expand to a set of patterns like: - - [ [ a, d ] - , [ b, c, d ] ] - - If a portion of the pattern doesn't have any "magic" in it - (that is, it's something like `"foo"` rather than `fo*o?`), then it - will be left as a string rather than converted to a regular - expression. - -* `regexp` Created by the `makeRe` method. A single regular expression - expressing the entire pattern. This is useful in cases where you wish - to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled. -* `negate` True if the pattern is negated. -* `comment` True if the pattern is a comment. -* `empty` True if the pattern is `""`. - -### Methods - -* `makeRe` Generate the `regexp` member if necessary, and return it. - Will return `false` if the pattern is invalid. -* `match(fname)` Return true if the filename matches the pattern, or - false otherwise. -* `matchOne(fileArray, patternArray, partial)` Take a `/`-split - filename, and match it against a single row in the `regExpSet`. This - method is mainly for internal use, but is exposed so that it can be - used by a glob-walker that needs to avoid excessive filesystem calls. - -All other methods are internal, and will be called as necessary. - -## Functions - -The top-level exported function has a `cache` property, which is an LRU -cache set to store 100 items. So, calling these methods repeatedly -with the same pattern and options will use the same Minimatch object, -saving the cost of parsing it multiple times. - -### minimatch(path, pattern, options) - -Main export. Tests a path against the pattern using the options. - -```javascript -var isJS = minimatch(file, "*.js", { matchBase: true }) -``` - -### minimatch.filter(pattern, options) - -Returns a function that tests its -supplied argument, suitable for use with `Array.filter`. Example: - -```javascript -var javascripts = fileList.filter(minimatch.filter("*.js", {matchBase: true})) -``` - -### minimatch.match(list, pattern, options) - -Match against the list of -files, in the style of fnmatch or glob. If nothing is matched, and -options.nonull is set, then return a list containing the pattern itself. - -```javascript -var javascripts = minimatch.match(fileList, "*.js", {matchBase: true})) -``` - -### minimatch.makeRe(pattern, options) - -Make a regular expression object from the pattern. - -## Options - -All options are `false` by default. - -### debug - -Dump a ton of stuff to stderr. - -### nobrace - -Do not expand `{a,b}` and `{1..3}` brace sets. - -### noglobstar - -Disable `**` matching against multiple folder names. - -### dot - -Allow patterns to match filenames starting with a period, even if -the pattern does not explicitly have a period in that spot. - -Note that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot` -is set. - -### noext - -Disable "extglob" style patterns like `+(a|b)`. - -### nocase - -Perform a case-insensitive match. - -### nonull - -When a match is not found by `minimatch.match`, return a list containing -the pattern itself. When set, an empty list is returned if there are -no matches. - -### matchBase - -If set, then patterns without slashes will be matched -against the basename of the path if it contains slashes. For example, -`a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`. - -### nocomment - -Suppress the behavior of treating `#` at the start of a pattern as a -comment. - -### nonegate - -Suppress the behavior of treating a leading `!` character as negation. - -### flipNegate - -Returns from negate expressions the same as if they were not negated. -(Ie, true on a hit, false on a miss.) - - -## Comparisons to other fnmatch/glob implementations - -While strict compliance with the existing standards is a worthwhile -goal, some discrepancies exist between minimatch and other -implementations, and are intentional. - -If the pattern starts with a `!` character, then it is negated. Set the -`nonegate` flag to suppress this behavior, and treat leading `!` -characters normally. This is perhaps relevant if you wish to start the -pattern with a negative extglob pattern like `!(a|B)`. Multiple `!` -characters at the start of a pattern will negate the pattern multiple -times. - -If a pattern starts with `#`, then it is treated as a comment, and -will not match anything. Use `\#` to match a literal `#` at the -start of a line, or set the `nocomment` flag to suppress this behavior. - -The double-star character `**` is supported by default, unless the -`noglobstar` flag is set. This is supported in the manner of bsdglob -and bash 4.1, where `**` only has special significance if it is the only -thing in a path part. That is, `a/**/b` will match `a/x/y/b`, but -`a/**b` will not. - -If an escaped pattern has no matches, and the `nonull` flag is set, -then minimatch.match returns the pattern as-provided, rather than -interpreting the character escapes. For example, -`minimatch.match([], "\\*a\\?")` will return `"\\*a\\?"` rather than -`"*a?"`. This is akin to setting the `nullglob` option in bash, except -that it does not resolve escaped pattern characters. - -If brace expansion is not disabled, then it is performed before any -other interpretation of the glob pattern. Thus, a pattern like -`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded -**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are -checked for validity. Since those two are valid, matching proceeds. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/minimatch.js b/tests/mocha/node_modules/glob/node_modules/minimatch/minimatch.js deleted file mode 100644 index c633f89fab..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/minimatch.js +++ /dev/null @@ -1,1055 +0,0 @@ -;(function (require, exports, module, platform) { - -if (module) module.exports = minimatch -else exports.minimatch = minimatch - -if (!require) { - require = function (id) { - switch (id) { - case "sigmund": return function sigmund (obj) { - return JSON.stringify(obj) - } - case "path": return { basename: function (f) { - f = f.split(/[\/\\]/) - var e = f.pop() - if (!e) e = f.pop() - return e - }} - case "lru-cache": return function LRUCache () { - // not quite an LRU, but still space-limited. - var cache = {} - var cnt = 0 - this.set = function (k, v) { - cnt ++ - if (cnt >= 100) cache = {} - cache[k] = v - } - this.get = function (k) { return cache[k] } - } - } - } -} - -minimatch.Minimatch = Minimatch - -var LRU = require("lru-cache") - , cache = minimatch.cache = new LRU({max: 100}) - , GLOBSTAR = minimatch.GLOBSTAR = Minimatch.GLOBSTAR = {} - , sigmund = require("sigmund") - -var path = require("path") - // any single thing other than / - // don't need to escape / when using new RegExp() - , qmark = "[^/]" - - // * => any number of characters - , star = qmark + "*?" - - // ** when dots are allowed. Anything goes, except .. and . - // not (^ or / followed by one or two dots followed by $ or /), - // followed by anything, any number of times. - , twoStarDot = "(?:(?!(?:\\\/|^)(?:\\.{1,2})($|\\\/)).)*?" - - // not a ^ or / followed by a dot, - // followed by anything, any number of times. - , twoStarNoDot = "(?:(?!(?:\\\/|^)\\.).)*?" - - // characters that need to be escaped in RegExp. - , reSpecials = charSet("().*{}+?[]^$\\!") - -// "abc" -> { a:true, b:true, c:true } -function charSet (s) { - return s.split("").reduce(function (set, c) { - set[c] = true - return set - }, {}) -} - -// normalizes slashes. -var slashSplit = /\/+/ - -minimatch.filter = filter -function filter (pattern, options) { - options = options || {} - return function (p, i, list) { - return minimatch(p, pattern, options) - } -} - -function ext (a, b) { - a = a || {} - b = b || {} - var t = {} - Object.keys(b).forEach(function (k) { - t[k] = b[k] - }) - Object.keys(a).forEach(function (k) { - t[k] = a[k] - }) - return t -} - -minimatch.defaults = function (def) { - if (!def || !Object.keys(def).length) return minimatch - - var orig = minimatch - - var m = function minimatch (p, pattern, options) { - return orig.minimatch(p, pattern, ext(def, options)) - } - - m.Minimatch = function Minimatch (pattern, options) { - return new orig.Minimatch(pattern, ext(def, options)) - } - - return m -} - -Minimatch.defaults = function (def) { - if (!def || !Object.keys(def).length) return Minimatch - return minimatch.defaults(def).Minimatch -} - - -function minimatch (p, pattern, options) { - if (typeof pattern !== "string") { - throw new TypeError("glob pattern string required") - } - - if (!options) options = {} - - // shortcut: comments match nothing. - if (!options.nocomment && pattern.charAt(0) === "#") { - return false - } - - // "" only matches "" - if (pattern.trim() === "") return p === "" - - return new Minimatch(pattern, options).match(p) -} - -function Minimatch (pattern, options) { - if (!(this instanceof Minimatch)) { - return new Minimatch(pattern, options, cache) - } - - if (typeof pattern !== "string") { - throw new TypeError("glob pattern string required") - } - - if (!options) options = {} - pattern = pattern.trim() - - // windows: need to use /, not \ - // On other platforms, \ is a valid (albeit bad) filename char. - if (platform === "win32") { - pattern = pattern.split("\\").join("/") - } - - // lru storage. - // these things aren't particularly big, but walking down the string - // and turning it into a regexp can get pretty costly. - var cacheKey = pattern + "\n" + sigmund(options) - var cached = minimatch.cache.get(cacheKey) - if (cached) return cached - minimatch.cache.set(cacheKey, this) - - this.options = options - this.set = [] - this.pattern = pattern - this.regexp = null - this.negate = false - this.comment = false - this.empty = false - - // make the set of regexps etc. - this.make() -} - -Minimatch.prototype.debug = function() {} - -Minimatch.prototype.make = make -function make () { - // don't do it more than once. - if (this._made) return - - var pattern = this.pattern - var options = this.options - - // empty patterns and comments match nothing. - if (!options.nocomment && pattern.charAt(0) === "#") { - this.comment = true - return - } - if (!pattern) { - this.empty = true - return - } - - // step 1: figure out negation, etc. - this.parseNegate() - - // step 2: expand braces - var set = this.globSet = this.braceExpand() - - if (options.debug) this.debug = console.error - - this.debug(this.pattern, set) - - // step 3: now we have a set, so turn each one into a series of path-portion - // matching patterns. - // These will be regexps, except in the case of "**", which is - // set to the GLOBSTAR object for globstar behavior, - // and will not contain any / characters - set = this.globParts = set.map(function (s) { - return s.split(slashSplit) - }) - - this.debug(this.pattern, set) - - // glob --> regexps - set = set.map(function (s, si, set) { - return s.map(this.parse, this) - }, this) - - this.debug(this.pattern, set) - - // filter out everything that didn't compile properly. - set = set.filter(function (s) { - return -1 === s.indexOf(false) - }) - - this.debug(this.pattern, set) - - this.set = set -} - -Minimatch.prototype.parseNegate = parseNegate -function parseNegate () { - var pattern = this.pattern - , negate = false - , options = this.options - , negateOffset = 0 - - if (options.nonegate) return - - for ( var i = 0, l = pattern.length - ; i < l && pattern.charAt(i) === "!" - ; i ++) { - negate = !negate - negateOffset ++ - } - - if (negateOffset) this.pattern = pattern.substr(negateOffset) - this.negate = negate -} - -// Brace expansion: -// a{b,c}d -> abd acd -// a{b,}c -> abc ac -// a{0..3}d -> a0d a1d a2d a3d -// a{b,c{d,e}f}g -> abg acdfg acefg -// a{b,c}d{e,f}g -> abdeg acdeg abdeg abdfg -// -// Invalid sets are not expanded. -// a{2..}b -> a{2..}b -// a{b}c -> a{b}c -minimatch.braceExpand = function (pattern, options) { - return new Minimatch(pattern, options).braceExpand() -} - -Minimatch.prototype.braceExpand = braceExpand -function braceExpand (pattern, options) { - options = options || this.options - pattern = typeof pattern === "undefined" - ? this.pattern : pattern - - if (typeof pattern === "undefined") { - throw new Error("undefined pattern") - } - - if (options.nobrace || - !pattern.match(/\{.*\}/)) { - // shortcut. no need to expand. - return [pattern] - } - - var escaping = false - - // examples and comments refer to this crazy pattern: - // a{b,c{d,e},{f,g}h}x{y,z} - // expected: - // abxy - // abxz - // acdxy - // acdxz - // acexy - // acexz - // afhxy - // afhxz - // aghxy - // aghxz - - // everything before the first \{ is just a prefix. - // So, we pluck that off, and work with the rest, - // and then prepend it to everything we find. - if (pattern.charAt(0) !== "{") { - this.debug(pattern) - var prefix = null - for (var i = 0, l = pattern.length; i < l; i ++) { - var c = pattern.charAt(i) - this.debug(i, c) - if (c === "\\") { - escaping = !escaping - } else if (c === "{" && !escaping) { - prefix = pattern.substr(0, i) - break - } - } - - // actually no sets, all { were escaped. - if (prefix === null) { - this.debug("no sets") - return [pattern] - } - - var tail = braceExpand.call(this, pattern.substr(i), options) - return tail.map(function (t) { - return prefix + t - }) - } - - // now we have something like: - // {b,c{d,e},{f,g}h}x{y,z} - // walk through the set, expanding each part, until - // the set ends. then, we'll expand the suffix. - // If the set only has a single member, then'll put the {} back - - // first, handle numeric sets, since they're easier - var numset = pattern.match(/^\{(-?[0-9]+)\.\.(-?[0-9]+)\}/) - if (numset) { - this.debug("numset", numset[1], numset[2]) - var suf = braceExpand.call(this, pattern.substr(numset[0].length), options) - , start = +numset[1] - , end = +numset[2] - , inc = start > end ? -1 : 1 - , set = [] - for (var i = start; i != (end + inc); i += inc) { - // append all the suffixes - for (var ii = 0, ll = suf.length; ii < ll; ii ++) { - set.push(i + suf[ii]) - } - } - return set - } - - // ok, walk through the set - // We hope, somewhat optimistically, that there - // will be a } at the end. - // If the closing brace isn't found, then the pattern is - // interpreted as braceExpand("\\" + pattern) so that - // the leading \{ will be interpreted literally. - var i = 1 // skip the \{ - , depth = 1 - , set = [] - , member = "" - , sawEnd = false - , escaping = false - - function addMember () { - set.push(member) - member = "" - } - - this.debug("Entering for") - FOR: for (i = 1, l = pattern.length; i < l; i ++) { - var c = pattern.charAt(i) - this.debug("", i, c) - - if (escaping) { - escaping = false - member += "\\" + c - } else { - switch (c) { - case "\\": - escaping = true - continue - - case "{": - depth ++ - member += "{" - continue - - case "}": - depth -- - // if this closes the actual set, then we're done - if (depth === 0) { - addMember() - // pluck off the close-brace - i ++ - break FOR - } else { - member += c - continue - } - - case ",": - if (depth === 1) { - addMember() - } else { - member += c - } - continue - - default: - member += c - continue - } // switch - } // else - } // for - - // now we've either finished the set, and the suffix is - // pattern.substr(i), or we have *not* closed the set, - // and need to escape the leading brace - if (depth !== 0) { - this.debug("didn't close", pattern) - return braceExpand.call(this, "\\" + pattern, options) - } - - // x{y,z} -> ["xy", "xz"] - this.debug("set", set) - this.debug("suffix", pattern.substr(i)) - var suf = braceExpand.call(this, pattern.substr(i), options) - // ["b", "c{d,e}","{f,g}h"] -> - // [["b"], ["cd", "ce"], ["fh", "gh"]] - var addBraces = set.length === 1 - this.debug("set pre-expanded", set) - set = set.map(function (p) { - return braceExpand.call(this, p, options) - }, this) - this.debug("set expanded", set) - - - // [["b"], ["cd", "ce"], ["fh", "gh"]] -> - // ["b", "cd", "ce", "fh", "gh"] - set = set.reduce(function (l, r) { - return l.concat(r) - }) - - if (addBraces) { - set = set.map(function (s) { - return "{" + s + "}" - }) - } - - // now attach the suffixes. - var ret = [] - for (var i = 0, l = set.length; i < l; i ++) { - for (var ii = 0, ll = suf.length; ii < ll; ii ++) { - ret.push(set[i] + suf[ii]) - } - } - return ret -} - -// parse a component of the expanded set. -// At this point, no pattern may contain "/" in it -// so we're going to return a 2d array, where each entry is the full -// pattern, split on '/', and then turned into a regular expression. -// A regexp is made at the end which joins each array with an -// escaped /, and another full one which joins each regexp with |. -// -// Following the lead of Bash 4.1, note that "**" only has special meaning -// when it is the *only* thing in a path portion. Otherwise, any series -// of * is equivalent to a single *. Globstar behavior is enabled by -// default, and can be disabled by setting options.noglobstar. -Minimatch.prototype.parse = parse -var SUBPARSE = {} -function parse (pattern, isSub) { - var options = this.options - - // shortcuts - if (!options.noglobstar && pattern === "**") return GLOBSTAR - if (pattern === "") return "" - - var re = "" - , hasMagic = !!options.nocase - , escaping = false - // ? => one single character - , patternListStack = [] - , plType - , stateChar - , inClass = false - , reClassStart = -1 - , classStart = -1 - // . and .. never match anything that doesn't start with ., - // even when options.dot is set. - , patternStart = pattern.charAt(0) === "." ? "" // anything - // not (start or / followed by . or .. followed by / or end) - : options.dot ? "(?!(?:^|\\\/)\\.{1,2}(?:$|\\\/))" - : "(?!\\.)" - , self = this - - function clearStateChar () { - if (stateChar) { - // we had some state-tracking character - // that wasn't consumed by this pass. - switch (stateChar) { - case "*": - re += star - hasMagic = true - break - case "?": - re += qmark - hasMagic = true - break - default: - re += "\\"+stateChar - break - } - self.debug('clearStateChar %j %j', stateChar, re) - stateChar = false - } - } - - for ( var i = 0, len = pattern.length, c - ; (i < len) && (c = pattern.charAt(i)) - ; i ++ ) { - - this.debug("%s\t%s %s %j", pattern, i, re, c) - - // skip over any that are escaped. - if (escaping && reSpecials[c]) { - re += "\\" + c - escaping = false - continue - } - - SWITCH: switch (c) { - case "/": - // completely not allowed, even escaped. - // Should already be path-split by now. - return false - - case "\\": - clearStateChar() - escaping = true - continue - - // the various stateChar values - // for the "extglob" stuff. - case "?": - case "*": - case "+": - case "@": - case "!": - this.debug("%s\t%s %s %j <-- stateChar", pattern, i, re, c) - - // all of those are literals inside a class, except that - // the glob [!a] means [^a] in regexp - if (inClass) { - this.debug(' in class') - if (c === "!" && i === classStart + 1) c = "^" - re += c - continue - } - - // if we already have a stateChar, then it means - // that there was something like ** or +? in there. - // Handle the stateChar, then proceed with this one. - self.debug('call clearStateChar %j', stateChar) - clearStateChar() - stateChar = c - // if extglob is disabled, then +(asdf|foo) isn't a thing. - // just clear the statechar *now*, rather than even diving into - // the patternList stuff. - if (options.noext) clearStateChar() - continue - - case "(": - if (inClass) { - re += "(" - continue - } - - if (!stateChar) { - re += "\\(" - continue - } - - plType = stateChar - patternListStack.push({ type: plType - , start: i - 1 - , reStart: re.length }) - // negation is (?:(?!js)[^/]*) - re += stateChar === "!" ? "(?:(?!" : "(?:" - this.debug('plType %j %j', stateChar, re) - stateChar = false - continue - - case ")": - if (inClass || !patternListStack.length) { - re += "\\)" - continue - } - - clearStateChar() - hasMagic = true - re += ")" - plType = patternListStack.pop().type - // negation is (?:(?!js)[^/]*) - // The others are (?:) - switch (plType) { - case "!": - re += "[^/]*?)" - break - case "?": - case "+": - case "*": re += plType - case "@": break // the default anyway - } - continue - - case "|": - if (inClass || !patternListStack.length || escaping) { - re += "\\|" - escaping = false - continue - } - - clearStateChar() - re += "|" - continue - - // these are mostly the same in regexp and glob - case "[": - // swallow any state-tracking char before the [ - clearStateChar() - - if (inClass) { - re += "\\" + c - continue - } - - inClass = true - classStart = i - reClassStart = re.length - re += c - continue - - case "]": - // a right bracket shall lose its special - // meaning and represent itself in - // a bracket expression if it occurs - // first in the list. -- POSIX.2 2.8.3.2 - if (i === classStart + 1 || !inClass) { - re += "\\" + c - escaping = false - continue - } - - // finish up the class. - hasMagic = true - inClass = false - re += c - continue - - default: - // swallow any state char that wasn't consumed - clearStateChar() - - if (escaping) { - // no need - escaping = false - } else if (reSpecials[c] - && !(c === "^" && inClass)) { - re += "\\" - } - - re += c - - } // switch - } // for - - - // handle the case where we left a class open. - // "[abc" is valid, equivalent to "\[abc" - if (inClass) { - // split where the last [ was, and escape it - // this is a huge pita. We now have to re-walk - // the contents of the would-be class to re-translate - // any characters that were passed through as-is - var cs = pattern.substr(classStart + 1) - , sp = this.parse(cs, SUBPARSE) - re = re.substr(0, reClassStart) + "\\[" + sp[0] - hasMagic = hasMagic || sp[1] - } - - // handle the case where we had a +( thing at the *end* - // of the pattern. - // each pattern list stack adds 3 chars, and we need to go through - // and escape any | chars that were passed through as-is for the regexp. - // Go through and escape them, taking care not to double-escape any - // | chars that were already escaped. - var pl - while (pl = patternListStack.pop()) { - var tail = re.slice(pl.reStart + 3) - // maybe some even number of \, then maybe 1 \, followed by a | - tail = tail.replace(/((?:\\{2})*)(\\?)\|/g, function (_, $1, $2) { - if (!$2) { - // the | isn't already escaped, so escape it. - $2 = "\\" - } - - // need to escape all those slashes *again*, without escaping the - // one that we need for escaping the | character. As it works out, - // escaping an even number of slashes can be done by simply repeating - // it exactly after itself. That's why this trick works. - // - // I am sorry that you have to see this. - return $1 + $1 + $2 + "|" - }) - - this.debug("tail=%j\n %s", tail, tail) - var t = pl.type === "*" ? star - : pl.type === "?" ? qmark - : "\\" + pl.type - - hasMagic = true - re = re.slice(0, pl.reStart) - + t + "\\(" - + tail - } - - // handle trailing things that only matter at the very end. - clearStateChar() - if (escaping) { - // trailing \\ - re += "\\\\" - } - - // only need to apply the nodot start if the re starts with - // something that could conceivably capture a dot - var addPatternStart = false - switch (re.charAt(0)) { - case ".": - case "[": - case "(": addPatternStart = true - } - - // if the re is not "" at this point, then we need to make sure - // it doesn't match against an empty path part. - // Otherwise a/* will match a/, which it should not. - if (re !== "" && hasMagic) re = "(?=.)" + re - - if (addPatternStart) re = patternStart + re - - // parsing just a piece of a larger pattern. - if (isSub === SUBPARSE) { - return [ re, hasMagic ] - } - - // skip the regexp for non-magical patterns - // unescape anything in it, though, so that it'll be - // an exact match against a file etc. - if (!hasMagic) { - return globUnescape(pattern) - } - - var flags = options.nocase ? "i" : "" - , regExp = new RegExp("^" + re + "$", flags) - - regExp._glob = pattern - regExp._src = re - - return regExp -} - -minimatch.makeRe = function (pattern, options) { - return new Minimatch(pattern, options || {}).makeRe() -} - -Minimatch.prototype.makeRe = makeRe -function makeRe () { - if (this.regexp || this.regexp === false) return this.regexp - - // at this point, this.set is a 2d array of partial - // pattern strings, or "**". - // - // It's better to use .match(). This function shouldn't - // be used, really, but it's pretty convenient sometimes, - // when you just want to work with a regex. - var set = this.set - - if (!set.length) return this.regexp = false - var options = this.options - - var twoStar = options.noglobstar ? star - : options.dot ? twoStarDot - : twoStarNoDot - , flags = options.nocase ? "i" : "" - - var re = set.map(function (pattern) { - return pattern.map(function (p) { - return (p === GLOBSTAR) ? twoStar - : (typeof p === "string") ? regExpEscape(p) - : p._src - }).join("\\\/") - }).join("|") - - // must match entire pattern - // ending in a * or ** will make it less strict. - re = "^(?:" + re + ")$" - - // can match anything, as long as it's not this. - if (this.negate) re = "^(?!" + re + ").*$" - - try { - return this.regexp = new RegExp(re, flags) - } catch (ex) { - return this.regexp = false - } -} - -minimatch.match = function (list, pattern, options) { - var mm = new Minimatch(pattern, options) - list = list.filter(function (f) { - return mm.match(f) - }) - if (options.nonull && !list.length) { - list.push(pattern) - } - return list -} - -Minimatch.prototype.match = match -function match (f, partial) { - this.debug("match", f, this.pattern) - // short-circuit in the case of busted things. - // comments, etc. - if (this.comment) return false - if (this.empty) return f === "" - - if (f === "/" && partial) return true - - var options = this.options - - // windows: need to use /, not \ - // On other platforms, \ is a valid (albeit bad) filename char. - if (platform === "win32") { - f = f.split("\\").join("/") - } - - // treat the test path as a set of pathparts. - f = f.split(slashSplit) - this.debug(this.pattern, "split", f) - - // just ONE of the pattern sets in this.set needs to match - // in order for it to be valid. If negating, then just one - // match means that we have failed. - // Either way, return on the first hit. - - var set = this.set - this.debug(this.pattern, "set", set) - - var splitFile = path.basename(f.join("/")).split("/") - - for (var i = 0, l = set.length; i < l; i ++) { - var pattern = set[i], file = f - if (options.matchBase && pattern.length === 1) { - file = splitFile - } - var hit = this.matchOne(file, pattern, partial) - if (hit) { - if (options.flipNegate) return true - return !this.negate - } - } - - // didn't get any hits. this is success if it's a negative - // pattern, failure otherwise. - if (options.flipNegate) return false - return this.negate -} - -// set partial to true to test if, for example, -// "/a/b" matches the start of "/*/b/*/d" -// Partial means, if you run out of file before you run -// out of pattern, then that's fine, as long as all -// the parts match. -Minimatch.prototype.matchOne = function (file, pattern, partial) { - var options = this.options - - this.debug("matchOne", - { "this": this - , file: file - , pattern: pattern }) - - this.debug("matchOne", file.length, pattern.length) - - for ( var fi = 0 - , pi = 0 - , fl = file.length - , pl = pattern.length - ; (fi < fl) && (pi < pl) - ; fi ++, pi ++ ) { - - this.debug("matchOne loop") - var p = pattern[pi] - , f = file[fi] - - this.debug(pattern, p, f) - - // should be impossible. - // some invalid regexp stuff in the set. - if (p === false) return false - - if (p === GLOBSTAR) { - this.debug('GLOBSTAR', [pattern, p, f]) - - // "**" - // a/**/b/**/c would match the following: - // a/b/x/y/z/c - // a/x/y/z/b/c - // a/b/x/b/x/c - // a/b/c - // To do this, take the rest of the pattern after - // the **, and see if it would match the file remainder. - // If so, return success. - // If not, the ** "swallows" a segment, and try again. - // This is recursively awful. - // - // a/**/b/**/c matching a/b/x/y/z/c - // - a matches a - // - doublestar - // - matchOne(b/x/y/z/c, b/**/c) - // - b matches b - // - doublestar - // - matchOne(x/y/z/c, c) -> no - // - matchOne(y/z/c, c) -> no - // - matchOne(z/c, c) -> no - // - matchOne(c, c) yes, hit - var fr = fi - , pr = pi + 1 - if (pr === pl) { - this.debug('** at the end') - // a ** at the end will just swallow the rest. - // We have found a match. - // however, it will not swallow /.x, unless - // options.dot is set. - // . and .. are *never* matched by **, for explosively - // exponential reasons. - for ( ; fi < fl; fi ++) { - if (file[fi] === "." || file[fi] === ".." || - (!options.dot && file[fi].charAt(0) === ".")) return false - } - return true - } - - // ok, let's see if we can swallow whatever we can. - WHILE: while (fr < fl) { - var swallowee = file[fr] - - this.debug('\nglobstar while', - file, fr, pattern, pr, swallowee) - - // XXX remove this slice. Just pass the start index. - if (this.matchOne(file.slice(fr), pattern.slice(pr), partial)) { - this.debug('globstar found match!', fr, fl, swallowee) - // found a match. - return true - } else { - // can't swallow "." or ".." ever. - // can only swallow ".foo" when explicitly asked. - if (swallowee === "." || swallowee === ".." || - (!options.dot && swallowee.charAt(0) === ".")) { - this.debug("dot detected!", file, fr, pattern, pr) - break WHILE - } - - // ** swallows a segment, and continue. - this.debug('globstar swallow a segment, and continue') - fr ++ - } - } - // no match was found. - // However, in partial mode, we can't say this is necessarily over. - // If there's more *pattern* left, then - if (partial) { - // ran out of file - this.debug("\n>>> no match, partial?", file, fr, pattern, pr) - if (fr === fl) return true - } - return false - } - - // something other than ** - // non-magic patterns just have to match exactly - // patterns with magic have been turned into regexps. - var hit - if (typeof p === "string") { - if (options.nocase) { - hit = f.toLowerCase() === p.toLowerCase() - } else { - hit = f === p - } - this.debug("string match", p, f, hit) - } else { - hit = f.match(p) - this.debug("pattern match", p, f, hit) - } - - if (!hit) return false - } - - // Note: ending in / means that we'll get a final "" - // at the end of the pattern. This can only match a - // corresponding "" at the end of the file. - // If the file ends in /, then it can only match a - // a pattern that ends in /, unless the pattern just - // doesn't have any more for it. But, a/b/ should *not* - // match "a/b/*", even though "" matches against the - // [^/]*? pattern, except in partial mode, where it might - // simply not be reached yet. - // However, a/b/ should still satisfy a/* - - // now either we fell off the end of the pattern, or we're done. - if (fi === fl && pi === pl) { - // ran out of pattern and filename at the same time. - // an exact hit! - return true - } else if (fi === fl) { - // ran out of file, but still had pattern left. - // this is ok if we're doing the match as part of - // a glob fs traversal. - return partial - } else if (pi === pl) { - // ran out of pattern, still have file left. - // this is only acceptable if we're on the very last - // empty segment of a file with a trailing slash. - // a/* should match a/b/ - var emptyFileEnd = (fi === fl - 1) && (file[fi] === "") - return emptyFileEnd - } - - // should be unreachable. - throw new Error("wtf?") -} - - -// replace stuff like \* with * -function globUnescape (s) { - return s.replace(/\\(.)/g, "$1") -} - - -function regExpEscape (s) { - return s.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&") -} - -})( typeof require === "function" ? require : null, - this, - typeof module === "object" ? module : null, - typeof process === "object" ? process.platform : "win32" - ) diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/.npmignore b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/.npmignore deleted file mode 100644 index 07e6e472cc..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/.npmignore +++ /dev/null @@ -1 +0,0 @@ -/node_modules diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/CONTRIBUTORS b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/CONTRIBUTORS deleted file mode 100644 index 4a0bc5033a..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/CONTRIBUTORS +++ /dev/null @@ -1,14 +0,0 @@ -# Authors, sorted by whether or not they are me -Isaac Z. Schlueter -Brian Cottingham -Carlos Brito Lage -Jesse Dailey -Kevin O'Hara -Marco Rogers -Mark Cavage -Marko Mikulicic -Nathan Rajlich -Satheesh Natesan -Trent Mick -ashleybrener -n4kz diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/LICENSE b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/LICENSE deleted file mode 100644 index 05a4010949..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/LICENSE +++ /dev/null @@ -1,23 +0,0 @@ -Copyright 2009, 2010, 2011 Isaac Z. Schlueter. -All rights reserved. - -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 -copies 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 all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES -OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT -HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, -WHETHER 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. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/README.md b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/README.md deleted file mode 100644 index 03ee0f9850..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/README.md +++ /dev/null @@ -1,97 +0,0 @@ -# lru cache - -A cache object that deletes the least-recently-used items. - -## Usage: - -```javascript -var LRU = require("lru-cache") - , options = { max: 500 - , length: function (n) { return n * 2 } - , dispose: function (key, n) { n.close() } - , maxAge: 1000 * 60 * 60 } - , cache = LRU(options) - , otherCache = LRU(50) // sets just the max size - -cache.set("key", "value") -cache.get("key") // "value" - -cache.reset() // empty the cache -``` - -If you put more stuff in it, then items will fall out. - -If you try to put an oversized thing in it, then it'll fall out right -away. - -## Options - -* `max` The maximum size of the cache, checked by applying the length - function to all values in the cache. Not setting this is kind of - silly, since that's the whole purpose of this lib, but it defaults - to `Infinity`. -* `maxAge` Maximum age in ms. Items are not pro-actively pruned out - as they age, but if you try to get an item that is too old, it'll - drop it and return undefined instead of giving it to you. -* `length` Function that is used to calculate the length of stored - items. If you're storing strings or buffers, then you probably want - to do something like `function(n){return n.length}`. The default is - `function(n){return 1}`, which is fine if you want to store `n` - like-sized things. -* `dispose` Function that is called on items when they are dropped - from the cache. This can be handy if you want to close file - descriptors or do other cleanup tasks when items are no longer - accessible. Called with `key, value`. It's called *before* - actually removing the item from the internal cache, so if you want - to immediately put it back in, you'll have to do that in a - `nextTick` or `setTimeout` callback or it won't do anything. -* `stale` By default, if you set a `maxAge`, it'll only actually pull - stale items out of the cache when you `get(key)`. (That is, it's - not pre-emptively doing a `setTimeout` or anything.) If you set - `stale:true`, it'll return the stale value before deleting it. If - you don't set this, then it'll return `undefined` when you try to - get a stale entry, as if it had already been deleted. - -## API - -* `set(key, value)` -* `get(key) => value` - - Both of these will update the "recently used"-ness of the key. - They do what you think. - -* `peek(key)` - - Returns the key value (or `undefined` if not found) without - updating the "recently used"-ness of the key. - - (If you find yourself using this a lot, you *might* be using the - wrong sort of data structure, but there are some use cases where - it's handy.) - -* `del(key)` - - Deletes a key out of the cache. - -* `reset()` - - Clear the cache entirely, throwing away all values. - -* `has(key)` - - Check if a key is in the cache, without updating the recent-ness - or deleting it for being stale. - -* `forEach(function(value,key,cache), [thisp])` - - Just like `Array.prototype.forEach`. Iterates over all the keys - in the cache, in order of recent-ness. (Ie, more recently used - items are iterated over first.) - -* `keys()` - - Return an array of the keys in the cache. - -* `values()` - - Return an array of the values in the cache. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js deleted file mode 100644 index d1d1381720..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/lib/lru-cache.js +++ /dev/null @@ -1,252 +0,0 @@ -;(function () { // closure for web browsers - -if (typeof module === 'object' && module.exports) { - module.exports = LRUCache -} else { - // just set the global for non-node platforms. - this.LRUCache = LRUCache -} - -function hOP (obj, key) { - return Object.prototype.hasOwnProperty.call(obj, key) -} - -function naiveLength () { return 1 } - -function LRUCache (options) { - if (!(this instanceof LRUCache)) - return new LRUCache(options) - - if (typeof options === 'number') - options = { max: options } - - if (!options) - options = {} - - this._max = options.max - // Kind of weird to have a default max of Infinity, but oh well. - if (!this._max || !(typeof this._max === "number") || this._max <= 0 ) - this._max = Infinity - - this._lengthCalculator = options.length || naiveLength - if (typeof this._lengthCalculator !== "function") - this._lengthCalculator = naiveLength - - this._allowStale = options.stale || false - this._maxAge = options.maxAge || null - this._dispose = options.dispose - this.reset() -} - -// resize the cache when the max changes. -Object.defineProperty(LRUCache.prototype, "max", - { set : function (mL) { - if (!mL || !(typeof mL === "number") || mL <= 0 ) mL = Infinity - this._max = mL - if (this._length > this._max) trim(this) - } - , get : function () { return this._max } - , enumerable : true - }) - -// resize the cache when the lengthCalculator changes. -Object.defineProperty(LRUCache.prototype, "lengthCalculator", - { set : function (lC) { - if (typeof lC !== "function") { - this._lengthCalculator = naiveLength - this._length = this._itemCount - for (var key in this._cache) { - this._cache[key].length = 1 - } - } else { - this._lengthCalculator = lC - this._length = 0 - for (var key in this._cache) { - this._cache[key].length = this._lengthCalculator(this._cache[key].value) - this._length += this._cache[key].length - } - } - - if (this._length > this._max) trim(this) - } - , get : function () { return this._lengthCalculator } - , enumerable : true - }) - -Object.defineProperty(LRUCache.prototype, "length", - { get : function () { return this._length } - , enumerable : true - }) - - -Object.defineProperty(LRUCache.prototype, "itemCount", - { get : function () { return this._itemCount } - , enumerable : true - }) - -LRUCache.prototype.forEach = function (fn, thisp) { - thisp = thisp || this - var i = 0; - for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) { - i++ - var hit = this._lruList[k] - if (this._maxAge && (Date.now() - hit.now > this._maxAge)) { - del(this, hit) - if (!this._allowStale) hit = undefined - } - if (hit) { - fn.call(thisp, hit.value, hit.key, this) - } - } -} - -LRUCache.prototype.keys = function () { - var keys = new Array(this._itemCount) - var i = 0 - for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) { - var hit = this._lruList[k] - keys[i++] = hit.key - } - return keys -} - -LRUCache.prototype.values = function () { - var values = new Array(this._itemCount) - var i = 0 - for (var k = this._mru - 1; k >= 0 && i < this._itemCount; k--) if (this._lruList[k]) { - var hit = this._lruList[k] - values[i++] = hit.value - } - return values -} - -LRUCache.prototype.reset = function () { - if (this._dispose && this._cache) { - for (var k in this._cache) { - this._dispose(k, this._cache[k].value) - } - } - - this._cache = Object.create(null) // hash of items by key - this._lruList = Object.create(null) // list of items in order of use recency - this._mru = 0 // most recently used - this._lru = 0 // least recently used - this._length = 0 // number of items in the list - this._itemCount = 0 -} - -// Provided for debugging/dev purposes only. No promises whatsoever that -// this API stays stable. -LRUCache.prototype.dump = function () { - return this._cache -} - -LRUCache.prototype.dumpLru = function () { - return this._lruList -} - -LRUCache.prototype.set = function (key, value) { - if (hOP(this._cache, key)) { - // dispose of the old one before overwriting - if (this._dispose) this._dispose(key, this._cache[key].value) - if (this._maxAge) this._cache[key].now = Date.now() - this._cache[key].value = value - this.get(key) - return true - } - - var len = this._lengthCalculator(value) - var age = this._maxAge ? Date.now() : 0 - var hit = new Entry(key, value, this._mru++, len, age) - - // oversized objects fall out of cache automatically. - if (hit.length > this._max) { - if (this._dispose) this._dispose(key, value) - return false - } - - this._length += hit.length - this._lruList[hit.lu] = this._cache[key] = hit - this._itemCount ++ - - if (this._length > this._max) trim(this) - return true -} - -LRUCache.prototype.has = function (key) { - if (!hOP(this._cache, key)) return false - var hit = this._cache[key] - if (this._maxAge && (Date.now() - hit.now > this._maxAge)) { - return false - } - return true -} - -LRUCache.prototype.get = function (key) { - return get(this, key, true) -} - -LRUCache.prototype.peek = function (key) { - return get(this, key, false) -} - -LRUCache.prototype.pop = function () { - var hit = this._lruList[this._lru] - del(this, hit) - return hit || null -} - -LRUCache.prototype.del = function (key) { - del(this, this._cache[key]) -} - -function get (self, key, doUse) { - var hit = self._cache[key] - if (hit) { - if (self._maxAge && (Date.now() - hit.now > self._maxAge)) { - del(self, hit) - if (!self._allowStale) hit = undefined - } else { - if (doUse) use(self, hit) - } - if (hit) hit = hit.value - } - return hit -} - -function use (self, hit) { - shiftLU(self, hit) - hit.lu = self._mru ++ - self._lruList[hit.lu] = hit -} - -function trim (self) { - while (self._lru < self._mru && self._length > self._max) - del(self, self._lruList[self._lru]) -} - -function shiftLU (self, hit) { - delete self._lruList[ hit.lu ] - while (self._lru < self._mru && !self._lruList[self._lru]) self._lru ++ -} - -function del (self, hit) { - if (hit) { - if (self._dispose) self._dispose(hit.key, hit.value) - self._length -= hit.length - self._itemCount -- - delete self._cache[ hit.key ] - shiftLU(self, hit) - } -} - -// classy, since V8 prefers predictable objects. -function Entry (key, value, lu, length, now) { - this.key = key - this.value = value - this.lu = lu - this.length = length - this.now = now -} - -})() diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/package.json b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/package.json deleted file mode 100644 index 4472725df9..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/package.json +++ /dev/null @@ -1,33 +0,0 @@ -{ - "name": "lru-cache", - "description": "A cache object that deletes the least-recently-used items.", - "version": "2.5.0", - "author": { - "name": "Isaac Z. Schlueter", - "email": "i@izs.me" - }, - "scripts": { - "test": "tap test --gc" - }, - "main": "lib/lru-cache.js", - "repository": { - "type": "git", - "url": "git://github.com/isaacs/node-lru-cache.git" - }, - "devDependencies": { - "tap": "", - "weak": "" - }, - "license": { - "type": "MIT", - "url": "http://github.com/isaacs/node-lru-cache/raw/master/LICENSE" - }, - "readme": "# lru cache\n\nA cache object that deletes the least-recently-used items.\n\n## Usage:\n\n```javascript\nvar LRU = require(\"lru-cache\")\n , options = { max: 500\n , length: function (n) { return n * 2 }\n , dispose: function (key, n) { n.close() }\n , maxAge: 1000 * 60 * 60 }\n , cache = LRU(options)\n , otherCache = LRU(50) // sets just the max size\n\ncache.set(\"key\", \"value\")\ncache.get(\"key\") // \"value\"\n\ncache.reset() // empty the cache\n```\n\nIf you put more stuff in it, then items will fall out.\n\nIf you try to put an oversized thing in it, then it'll fall out right\naway.\n\n## Options\n\n* `max` The maximum size of the cache, checked by applying the length\n function to all values in the cache. Not setting this is kind of\n silly, since that's the whole purpose of this lib, but it defaults\n to `Infinity`.\n* `maxAge` Maximum age in ms. Items are not pro-actively pruned out\n as they age, but if you try to get an item that is too old, it'll\n drop it and return undefined instead of giving it to you.\n* `length` Function that is used to calculate the length of stored\n items. If you're storing strings or buffers, then you probably want\n to do something like `function(n){return n.length}`. The default is\n `function(n){return 1}`, which is fine if you want to store `n`\n like-sized things.\n* `dispose` Function that is called on items when they are dropped\n from the cache. This can be handy if you want to close file\n descriptors or do other cleanup tasks when items are no longer\n accessible. Called with `key, value`. It's called *before*\n actually removing the item from the internal cache, so if you want\n to immediately put it back in, you'll have to do that in a\n `nextTick` or `setTimeout` callback or it won't do anything.\n* `stale` By default, if you set a `maxAge`, it'll only actually pull\n stale items out of the cache when you `get(key)`. (That is, it's\n not pre-emptively doing a `setTimeout` or anything.) If you set\n `stale:true`, it'll return the stale value before deleting it. If\n you don't set this, then it'll return `undefined` when you try to\n get a stale entry, as if it had already been deleted.\n\n## API\n\n* `set(key, value)`\n* `get(key) => value`\n\n Both of these will update the \"recently used\"-ness of the key.\n They do what you think.\n\n* `peek(key)`\n\n Returns the key value (or `undefined` if not found) without\n updating the \"recently used\"-ness of the key.\n\n (If you find yourself using this a lot, you *might* be using the\n wrong sort of data structure, but there are some use cases where\n it's handy.)\n\n* `del(key)`\n\n Deletes a key out of the cache.\n\n* `reset()`\n\n Clear the cache entirely, throwing away all values.\n\n* `has(key)`\n\n Check if a key is in the cache, without updating the recent-ness\n or deleting it for being stale.\n\n* `forEach(function(value,key,cache), [thisp])`\n\n Just like `Array.prototype.forEach`. Iterates over all the keys\n in the cache, in order of recent-ness. (Ie, more recently used\n items are iterated over first.)\n\n* `keys()`\n\n Return an array of the keys in the cache.\n\n* `values()`\n\n Return an array of the values in the cache.\n", - "readmeFilename": "README.md", - "bugs": { - "url": "https://github.com/isaacs/node-lru-cache/issues" - }, - "homepage": "https://github.com/isaacs/node-lru-cache", - "_id": "lru-cache@2.5.0", - "_from": "lru-cache@2" -} diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/basic.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/basic.js deleted file mode 100644 index f72697c461..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/basic.js +++ /dev/null @@ -1,369 +0,0 @@ -var test = require("tap").test - , LRU = require("../") - -test("basic", function (t) { - var cache = new LRU({max: 10}) - cache.set("key", "value") - t.equal(cache.get("key"), "value") - t.equal(cache.get("nada"), undefined) - t.equal(cache.length, 1) - t.equal(cache.max, 10) - t.end() -}) - -test("least recently set", function (t) { - var cache = new LRU(2) - cache.set("a", "A") - cache.set("b", "B") - cache.set("c", "C") - t.equal(cache.get("c"), "C") - t.equal(cache.get("b"), "B") - t.equal(cache.get("a"), undefined) - t.end() -}) - -test("lru recently gotten", function (t) { - var cache = new LRU(2) - cache.set("a", "A") - cache.set("b", "B") - cache.get("a") - cache.set("c", "C") - t.equal(cache.get("c"), "C") - t.equal(cache.get("b"), undefined) - t.equal(cache.get("a"), "A") - t.end() -}) - -test("del", function (t) { - var cache = new LRU(2) - cache.set("a", "A") - cache.del("a") - t.equal(cache.get("a"), undefined) - t.end() -}) - -test("max", function (t) { - var cache = new LRU(3) - - // test changing the max, verify that the LRU items get dropped. - cache.max = 100 - for (var i = 0; i < 100; i ++) cache.set(i, i) - t.equal(cache.length, 100) - for (var i = 0; i < 100; i ++) { - t.equal(cache.get(i), i) - } - cache.max = 3 - t.equal(cache.length, 3) - for (var i = 0; i < 97; i ++) { - t.equal(cache.get(i), undefined) - } - for (var i = 98; i < 100; i ++) { - t.equal(cache.get(i), i) - } - - // now remove the max restriction, and try again. - cache.max = "hello" - for (var i = 0; i < 100; i ++) cache.set(i, i) - t.equal(cache.length, 100) - for (var i = 0; i < 100; i ++) { - t.equal(cache.get(i), i) - } - // should trigger an immediate resize - cache.max = 3 - t.equal(cache.length, 3) - for (var i = 0; i < 97; i ++) { - t.equal(cache.get(i), undefined) - } - for (var i = 98; i < 100; i ++) { - t.equal(cache.get(i), i) - } - t.end() -}) - -test("reset", function (t) { - var cache = new LRU(10) - cache.set("a", "A") - cache.set("b", "B") - cache.reset() - t.equal(cache.length, 0) - t.equal(cache.max, 10) - t.equal(cache.get("a"), undefined) - t.equal(cache.get("b"), undefined) - t.end() -}) - - -// Note: `.dump()` is a debugging tool only. No guarantees are made -// about the format/layout of the response. -test("dump", function (t) { - var cache = new LRU(10) - var d = cache.dump(); - t.equal(Object.keys(d).length, 0, "nothing in dump for empty cache") - cache.set("a", "A") - var d = cache.dump() // { a: { key: "a", value: "A", lu: 0 } } - t.ok(d.a) - t.equal(d.a.key, "a") - t.equal(d.a.value, "A") - t.equal(d.a.lu, 0) - - cache.set("b", "B") - cache.get("b") - d = cache.dump() - t.ok(d.b) - t.equal(d.b.key, "b") - t.equal(d.b.value, "B") - t.equal(d.b.lu, 2) - - t.end() -}) - - -test("basic with weighed length", function (t) { - var cache = new LRU({ - max: 100, - length: function (item) { return item.size } - }) - cache.set("key", {val: "value", size: 50}) - t.equal(cache.get("key").val, "value") - t.equal(cache.get("nada"), undefined) - t.equal(cache.lengthCalculator(cache.get("key")), 50) - t.equal(cache.length, 50) - t.equal(cache.max, 100) - t.end() -}) - - -test("weighed length item too large", function (t) { - var cache = new LRU({ - max: 10, - length: function (item) { return item.size } - }) - t.equal(cache.max, 10) - - // should fall out immediately - cache.set("key", {val: "value", size: 50}) - - t.equal(cache.length, 0) - t.equal(cache.get("key"), undefined) - t.end() -}) - -test("least recently set with weighed length", function (t) { - var cache = new LRU({ - max:8, - length: function (item) { return item.length } - }) - cache.set("a", "A") - cache.set("b", "BB") - cache.set("c", "CCC") - cache.set("d", "DDDD") - t.equal(cache.get("d"), "DDDD") - t.equal(cache.get("c"), "CCC") - t.equal(cache.get("b"), undefined) - t.equal(cache.get("a"), undefined) - t.end() -}) - -test("lru recently gotten with weighed length", function (t) { - var cache = new LRU({ - max: 8, - length: function (item) { return item.length } - }) - cache.set("a", "A") - cache.set("b", "BB") - cache.set("c", "CCC") - cache.get("a") - cache.get("b") - cache.set("d", "DDDD") - t.equal(cache.get("c"), undefined) - t.equal(cache.get("d"), "DDDD") - t.equal(cache.get("b"), "BB") - t.equal(cache.get("a"), "A") - t.end() -}) - -test("set returns proper booleans", function(t) { - var cache = new LRU({ - max: 5, - length: function (item) { return item.length } - }) - - t.equal(cache.set("a", "A"), true) - - // should return false for max exceeded - t.equal(cache.set("b", "donuts"), false) - - t.equal(cache.set("b", "B"), true) - t.equal(cache.set("c", "CCCC"), true) - t.end() -}) - -test("drop the old items", function(t) { - var cache = new LRU({ - max: 5, - maxAge: 50 - }) - - cache.set("a", "A") - - setTimeout(function () { - cache.set("b", "b") - t.equal(cache.get("a"), "A") - }, 25) - - setTimeout(function () { - cache.set("c", "C") - // timed out - t.notOk(cache.get("a")) - }, 60) - - setTimeout(function () { - t.notOk(cache.get("b")) - t.equal(cache.get("c"), "C") - }, 90) - - setTimeout(function () { - t.notOk(cache.get("c")) - t.end() - }, 155) -}) - -test("disposal function", function(t) { - var disposed = false - var cache = new LRU({ - max: 1, - dispose: function (k, n) { - disposed = n - } - }) - - cache.set(1, 1) - cache.set(2, 2) - t.equal(disposed, 1) - cache.set(3, 3) - t.equal(disposed, 2) - cache.reset() - t.equal(disposed, 3) - t.end() -}) - -test("disposal function on too big of item", function(t) { - var disposed = false - var cache = new LRU({ - max: 1, - length: function (k) { - return k.length - }, - dispose: function (k, n) { - disposed = n - } - }) - var obj = [ 1, 2 ] - - t.equal(disposed, false) - cache.set("obj", obj) - t.equal(disposed, obj) - t.end() -}) - -test("has()", function(t) { - var cache = new LRU({ - max: 1, - maxAge: 10 - }) - - cache.set('foo', 'bar') - t.equal(cache.has('foo'), true) - cache.set('blu', 'baz') - t.equal(cache.has('foo'), false) - t.equal(cache.has('blu'), true) - setTimeout(function() { - t.equal(cache.has('blu'), false) - t.end() - }, 15) -}) - -test("stale", function(t) { - var cache = new LRU({ - maxAge: 10, - stale: true - }) - - cache.set('foo', 'bar') - t.equal(cache.get('foo'), 'bar') - t.equal(cache.has('foo'), true) - setTimeout(function() { - t.equal(cache.has('foo'), false) - t.equal(cache.get('foo'), 'bar') - t.equal(cache.get('foo'), undefined) - t.end() - }, 15) -}) - -test("lru update via set", function(t) { - var cache = LRU({ max: 2 }); - - cache.set('foo', 1); - cache.set('bar', 2); - cache.del('bar'); - cache.set('baz', 3); - cache.set('qux', 4); - - t.equal(cache.get('foo'), undefined) - t.equal(cache.get('bar'), undefined) - t.equal(cache.get('baz'), 3) - t.equal(cache.get('qux'), 4) - t.end() -}) - -test("least recently set w/ peek", function (t) { - var cache = new LRU(2) - cache.set("a", "A") - cache.set("b", "B") - t.equal(cache.peek("a"), "A") - cache.set("c", "C") - t.equal(cache.get("c"), "C") - t.equal(cache.get("b"), "B") - t.equal(cache.get("a"), undefined) - t.end() -}) - -test("pop the least used item", function (t) { - var cache = new LRU(3) - , last - - cache.set("a", "A") - cache.set("b", "B") - cache.set("c", "C") - - t.equal(cache.length, 3) - t.equal(cache.max, 3) - - // Ensure we pop a, c, b - cache.get("b", "B") - - last = cache.pop() - t.equal(last.key, "a") - t.equal(last.value, "A") - t.equal(cache.length, 2) - t.equal(cache.max, 3) - - last = cache.pop() - t.equal(last.key, "c") - t.equal(last.value, "C") - t.equal(cache.length, 1) - t.equal(cache.max, 3) - - last = cache.pop() - t.equal(last.key, "b") - t.equal(last.value, "B") - t.equal(cache.length, 0) - t.equal(cache.max, 3) - - last = cache.pop() - t.equal(last, null) - t.equal(cache.length, 0) - t.equal(cache.max, 3) - - t.end() -}) diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/foreach.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/foreach.js deleted file mode 100644 index eefb80d9d1..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/foreach.js +++ /dev/null @@ -1,52 +0,0 @@ -var test = require('tap').test -var LRU = require('../') - -test('forEach', function (t) { - var l = new LRU(5) - for (var i = 0; i < 10; i ++) { - l.set(i.toString(), i.toString(2)) - } - - var i = 9 - l.forEach(function (val, key, cache) { - t.equal(cache, l) - t.equal(key, i.toString()) - t.equal(val, i.toString(2)) - i -= 1 - }) - - // get in order of most recently used - l.get(6) - l.get(8) - - var order = [ 8, 6, 9, 7, 5 ] - var i = 0 - - l.forEach(function (val, key, cache) { - var j = order[i ++] - t.equal(cache, l) - t.equal(key, j.toString()) - t.equal(val, j.toString(2)) - }) - - t.end() -}) - -test('keys() and values()', function (t) { - var l = new LRU(5) - for (var i = 0; i < 10; i ++) { - l.set(i.toString(), i.toString(2)) - } - - t.similar(l.keys(), ['9', '8', '7', '6', '5']) - t.similar(l.values(), ['1001', '1000', '111', '110', '101']) - - // get in order of most recently used - l.get(6) - l.get(8) - - t.similar(l.keys(), ['8', '6', '9', '7', '5']) - t.similar(l.values(), ['1000', '110', '1001', '111', '101']) - - t.end() -}) diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js deleted file mode 100644 index 7af45b0221..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/lru-cache/test/memory-leak.js +++ /dev/null @@ -1,50 +0,0 @@ -#!/usr/bin/env node --expose_gc - -var weak = require('weak'); -var test = require('tap').test -var LRU = require('../') -var l = new LRU({ max: 10 }) -var refs = 0 -function X() { - refs ++ - weak(this, deref) -} - -function deref() { - refs -- -} - -test('no leaks', function (t) { - // fill up the cache - for (var i = 0; i < 100; i++) { - l.set(i, new X); - // throw some gets in there, too. - if (i % 2 === 0) - l.get(i / 2) - } - - gc() - - var start = process.memoryUsage() - - // capture the memory - var startRefs = refs - - // do it again, but more - for (var i = 0; i < 10000; i++) { - l.set(i, new X); - // throw some gets in there, too. - if (i % 2 === 0) - l.get(i / 2) - } - - gc() - - var end = process.memoryUsage() - t.equal(refs, startRefs, 'no leaky refs') - - console.error('start: %j\n' + - 'end: %j', start, end); - t.pass(); - t.end(); -}) diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/LICENSE b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/LICENSE deleted file mode 100644 index 0c44ae716d..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) Isaac Z. Schlueter ("Author") -All rights reserved. - -The BSD License - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions -are met: - -1. Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS -BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR -BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, -WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN -IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/README.md b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/README.md deleted file mode 100644 index 7e365129e4..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/README.md +++ /dev/null @@ -1,53 +0,0 @@ -# sigmund - -Quick and dirty signatures for Objects. - -This is like a much faster `deepEquals` comparison, which returns a -string key suitable for caches and the like. - -## Usage - -```javascript -function doSomething (someObj) { - var key = sigmund(someObj, maxDepth) // max depth defaults to 10 - var cached = cache.get(key) - if (cached) return cached) - - var result = expensiveCalculation(someObj) - cache.set(key, result) - return result -} -``` - -The resulting key will be as unique and reproducible as calling -`JSON.stringify` or `util.inspect` on the object, but is much faster. -In order to achieve this speed, some differences are glossed over. -For example, the object `{0:'foo'}` will be treated identically to the -array `['foo']`. - -Also, just as there is no way to summon the soul from the scribblings -of a cocain-addled psychoanalyst, there is no way to revive the object -from the signature string that sigmund gives you. In fact, it's -barely even readable. - -As with `sys.inspect` and `JSON.stringify`, larger objects will -produce larger signature strings. - -Because sigmund is a bit less strict than the more thorough -alternatives, the strings will be shorter, and also there is a -slightly higher chance for collisions. For example, these objects -have the same signature: - - var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]} - var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']} - -Like a good Freudian, sigmund is most effective when you already have -some understanding of what you're looking for. It can help you help -yourself, but you must be willing to do some work as well. - -Cycles are handled, and cyclical objects are silently omitted (though -the key is included in the signature output.) - -The second argument is the maximum depth, which defaults to 10, -because that is the maximum object traversal depth covered by most -insurance carriers. diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/bench.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/bench.js deleted file mode 100644 index 5acfd6d90d..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/bench.js +++ /dev/null @@ -1,283 +0,0 @@ -// different ways to id objects -// use a req/res pair, since it's crazy deep and cyclical - -// sparseFE10 and sigmund are usually pretty close, which is to be expected, -// since they are essentially the same algorithm, except that sigmund handles -// regular expression objects properly. - - -var http = require('http') -var util = require('util') -var sigmund = require('./sigmund.js') -var sreq, sres, creq, cres, test - -http.createServer(function (q, s) { - sreq = q - sres = s - sres.end('ok') - this.close(function () { setTimeout(function () { - start() - }, 200) }) -}).listen(1337, function () { - creq = http.get({ port: 1337 }) - creq.on('response', function (s) { cres = s }) -}) - -function start () { - test = [sreq, sres, creq, cres] - // test = sreq - // sreq.sres = sres - // sreq.creq = creq - // sreq.cres = cres - - for (var i in exports.compare) { - console.log(i) - var hash = exports.compare[i]() - console.log(hash) - console.log(hash.length) - console.log('') - } - - require('bench').runMain() -} - -function customWs (obj, md, d) { - d = d || 0 - var to = typeof obj - if (to === 'undefined' || to === 'function' || to === null) return '' - if (d > md || !obj || to !== 'object') return ('' + obj).replace(/[\n ]+/g, '') - - if (Array.isArray(obj)) { - return obj.map(function (i, _, __) { - return customWs(i, md, d + 1) - }).reduce(function (a, b) { return a + b }, '') - } - - var keys = Object.keys(obj) - return keys.map(function (k, _, __) { - return k + ':' + customWs(obj[k], md, d + 1) - }).reduce(function (a, b) { return a + b }, '') -} - -function custom (obj, md, d) { - d = d || 0 - var to = typeof obj - if (to === 'undefined' || to === 'function' || to === null) return '' - if (d > md || !obj || to !== 'object') return '' + obj - - if (Array.isArray(obj)) { - return obj.map(function (i, _, __) { - return custom(i, md, d + 1) - }).reduce(function (a, b) { return a + b }, '') - } - - var keys = Object.keys(obj) - return keys.map(function (k, _, __) { - return k + ':' + custom(obj[k], md, d + 1) - }).reduce(function (a, b) { return a + b }, '') -} - -function sparseFE2 (obj, maxDepth) { - var seen = [] - var soFar = '' - function ch (v, depth) { - if (depth > maxDepth) return - if (typeof v === 'function' || typeof v === 'undefined') return - if (typeof v !== 'object' || !v) { - soFar += v - return - } - if (seen.indexOf(v) !== -1 || depth === maxDepth) return - seen.push(v) - soFar += '{' - Object.keys(v).forEach(function (k, _, __) { - // pseudo-private values. skip those. - if (k.charAt(0) === '_') return - var to = typeof v[k] - if (to === 'function' || to === 'undefined') return - soFar += k + ':' - ch(v[k], depth + 1) - }) - soFar += '}' - } - ch(obj, 0) - return soFar -} - -function sparseFE (obj, maxDepth) { - var seen = [] - var soFar = '' - function ch (v, depth) { - if (depth > maxDepth) return - if (typeof v === 'function' || typeof v === 'undefined') return - if (typeof v !== 'object' || !v) { - soFar += v - return - } - if (seen.indexOf(v) !== -1 || depth === maxDepth) return - seen.push(v) - soFar += '{' - Object.keys(v).forEach(function (k, _, __) { - // pseudo-private values. skip those. - if (k.charAt(0) === '_') return - var to = typeof v[k] - if (to === 'function' || to === 'undefined') return - soFar += k - ch(v[k], depth + 1) - }) - } - ch(obj, 0) - return soFar -} - -function sparse (obj, maxDepth) { - var seen = [] - var soFar = '' - function ch (v, depth) { - if (depth > maxDepth) return - if (typeof v === 'function' || typeof v === 'undefined') return - if (typeof v !== 'object' || !v) { - soFar += v - return - } - if (seen.indexOf(v) !== -1 || depth === maxDepth) return - seen.push(v) - soFar += '{' - for (var k in v) { - // pseudo-private values. skip those. - if (k.charAt(0) === '_') continue - var to = typeof v[k] - if (to === 'function' || to === 'undefined') continue - soFar += k - ch(v[k], depth + 1) - } - } - ch(obj, 0) - return soFar -} - -function noCommas (obj, maxDepth) { - var seen = [] - var soFar = '' - function ch (v, depth) { - if (depth > maxDepth) return - if (typeof v === 'function' || typeof v === 'undefined') return - if (typeof v !== 'object' || !v) { - soFar += v - return - } - if (seen.indexOf(v) !== -1 || depth === maxDepth) return - seen.push(v) - soFar += '{' - for (var k in v) { - // pseudo-private values. skip those. - if (k.charAt(0) === '_') continue - var to = typeof v[k] - if (to === 'function' || to === 'undefined') continue - soFar += k + ':' - ch(v[k], depth + 1) - } - soFar += '}' - } - ch(obj, 0) - return soFar -} - - -function flatten (obj, maxDepth) { - var seen = [] - var soFar = '' - function ch (v, depth) { - if (depth > maxDepth) return - if (typeof v === 'function' || typeof v === 'undefined') return - if (typeof v !== 'object' || !v) { - soFar += v - return - } - if (seen.indexOf(v) !== -1 || depth === maxDepth) return - seen.push(v) - soFar += '{' - for (var k in v) { - // pseudo-private values. skip those. - if (k.charAt(0) === '_') continue - var to = typeof v[k] - if (to === 'function' || to === 'undefined') continue - soFar += k + ':' - ch(v[k], depth + 1) - soFar += ',' - } - soFar += '}' - } - ch(obj, 0) - return soFar -} - -exports.compare = -{ - // 'custom 2': function () { - // return custom(test, 2, 0) - // }, - // 'customWs 2': function () { - // return customWs(test, 2, 0) - // }, - 'JSON.stringify (guarded)': function () { - var seen = [] - return JSON.stringify(test, function (k, v) { - if (typeof v !== 'object' || !v) return v - if (seen.indexOf(v) !== -1) return undefined - seen.push(v) - return v - }) - }, - - 'flatten 10': function () { - return flatten(test, 10) - }, - - // 'flattenFE 10': function () { - // return flattenFE(test, 10) - // }, - - 'noCommas 10': function () { - return noCommas(test, 10) - }, - - 'sparse 10': function () { - return sparse(test, 10) - }, - - 'sparseFE 10': function () { - return sparseFE(test, 10) - }, - - 'sparseFE2 10': function () { - return sparseFE2(test, 10) - }, - - sigmund: function() { - return sigmund(test, 10) - }, - - - // 'util.inspect 1': function () { - // return util.inspect(test, false, 1, false) - // }, - // 'util.inspect undefined': function () { - // util.inspect(test) - // }, - // 'util.inspect 2': function () { - // util.inspect(test, false, 2, false) - // }, - // 'util.inspect 3': function () { - // util.inspect(test, false, 3, false) - // }, - // 'util.inspect 4': function () { - // util.inspect(test, false, 4, false) - // }, - // 'util.inspect Infinity': function () { - // util.inspect(test, false, Infinity, false) - // } -} - -/** results -**/ diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/package.json b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/package.json deleted file mode 100644 index cb7e2bd4b7..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/package.json +++ /dev/null @@ -1,42 +0,0 @@ -{ - "name": "sigmund", - "version": "1.0.0", - "description": "Quick and dirty signatures for Objects.", - "main": "sigmund.js", - "directories": { - "test": "test" - }, - "dependencies": {}, - "devDependencies": { - "tap": "~0.3.0" - }, - "scripts": { - "test": "tap test/*.js", - "bench": "node bench.js" - }, - "repository": { - "type": "git", - "url": "git://github.com/isaacs/sigmund" - }, - "keywords": [ - "object", - "signature", - "key", - "data", - "psychoanalysis" - ], - "author": { - "name": "Isaac Z. Schlueter", - "email": "i@izs.me", - "url": "http://blog.izs.me/" - }, - "license": "BSD", - "readme": "# sigmund\n\nQuick and dirty signatures for Objects.\n\nThis is like a much faster `deepEquals` comparison, which returns a\nstring key suitable for caches and the like.\n\n## Usage\n\n```javascript\nfunction doSomething (someObj) {\n var key = sigmund(someObj, maxDepth) // max depth defaults to 10\n var cached = cache.get(key)\n if (cached) return cached)\n\n var result = expensiveCalculation(someObj)\n cache.set(key, result)\n return result\n}\n```\n\nThe resulting key will be as unique and reproducible as calling\n`JSON.stringify` or `util.inspect` on the object, but is much faster.\nIn order to achieve this speed, some differences are glossed over.\nFor example, the object `{0:'foo'}` will be treated identically to the\narray `['foo']`.\n\nAlso, just as there is no way to summon the soul from the scribblings\nof a cocain-addled psychoanalyst, there is no way to revive the object\nfrom the signature string that sigmund gives you. In fact, it's\nbarely even readable.\n\nAs with `sys.inspect` and `JSON.stringify`, larger objects will\nproduce larger signature strings.\n\nBecause sigmund is a bit less strict than the more thorough\nalternatives, the strings will be shorter, and also there is a\nslightly higher chance for collisions. For example, these objects\nhave the same signature:\n\n var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]}\n var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']}\n\nLike a good Freudian, sigmund is most effective when you already have\nsome understanding of what you're looking for. It can help you help\nyourself, but you must be willing to do some work as well.\n\nCycles are handled, and cyclical objects are silently omitted (though\nthe key is included in the signature output.)\n\nThe second argument is the maximum depth, which defaults to 10,\nbecause that is the maximum object traversal depth covered by most\ninsurance carriers.\n", - "readmeFilename": "README.md", - "bugs": { - "url": "https://github.com/isaacs/sigmund/issues" - }, - "homepage": "https://github.com/isaacs/sigmund", - "_id": "sigmund@1.0.0", - "_from": "sigmund@~1.0.0" -} diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/sigmund.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/sigmund.js deleted file mode 100644 index 82c7ab8ce9..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/sigmund.js +++ /dev/null @@ -1,39 +0,0 @@ -module.exports = sigmund -function sigmund (subject, maxSessions) { - maxSessions = maxSessions || 10; - var notes = []; - var analysis = ''; - var RE = RegExp; - - function psychoAnalyze (subject, session) { - if (session > maxSessions) return; - - if (typeof subject === 'function' || - typeof subject === 'undefined') { - return; - } - - if (typeof subject !== 'object' || !subject || - (subject instanceof RE)) { - analysis += subject; - return; - } - - if (notes.indexOf(subject) !== -1 || session === maxSessions) return; - - notes.push(subject); - analysis += '{'; - Object.keys(subject).forEach(function (issue, _, __) { - // pseudo-private values. skip those. - if (issue.charAt(0) === '_') return; - var to = typeof subject[issue]; - if (to === 'function' || to === 'undefined') return; - analysis += issue; - psychoAnalyze(subject[issue], session + 1); - }); - } - psychoAnalyze(subject, 0); - return analysis; -} - -// vim: set softtabstop=4 shiftwidth=4: diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/test/basic.js b/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/test/basic.js deleted file mode 100644 index 50c53a13e9..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/node_modules/sigmund/test/basic.js +++ /dev/null @@ -1,24 +0,0 @@ -var test = require('tap').test -var sigmund = require('../sigmund.js') - - -// occasionally there are duplicates -// that's an acceptable edge-case. JSON.stringify and util.inspect -// have some collision potential as well, though less, and collision -// detection is expensive. -var hash = '{abc/def/g{0h1i2{jkl' -var obj1 = {a:'b',c:/def/,g:['h','i',{j:'',k:'l'}]} -var obj2 = {a:'b',c:'/def/',g:['h','i','{jkl']} - -var obj3 = JSON.parse(JSON.stringify(obj1)) -obj3.c = /def/ -obj3.g[2].cycle = obj3 -var cycleHash = '{abc/def/g{0h1i2{jklcycle' - -test('basic', function (t) { - t.equal(sigmund(obj1), hash) - t.equal(sigmund(obj2), hash) - t.equal(sigmund(obj3), cycleHash) - t.end() -}) - diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/package.json b/tests/mocha/node_modules/glob/node_modules/minimatch/package.json deleted file mode 100644 index f8f545aa3f..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "author": { - "name": "Isaac Z. Schlueter", - "email": "i@izs.me", - "url": "http://blog.izs.me" - }, - "name": "minimatch", - "description": "a glob matcher in javascript", - "version": "0.2.14", - "repository": { - "type": "git", - "url": "git://github.com/isaacs/minimatch.git" - }, - "main": "minimatch.js", - "scripts": { - "test": "tap test/*.js" - }, - "engines": { - "node": "*" - }, - "dependencies": { - "lru-cache": "2", - "sigmund": "~1.0.0" - }, - "devDependencies": { - "tap": "" - }, - "license": { - "type": "MIT", - "url": "http://github.com/isaacs/minimatch/raw/master/LICENSE" - }, - "readme": "# minimatch\n\nA minimal matching utility.\n\n[![Build Status](https://secure.travis-ci.org/isaacs/minimatch.png)](http://travis-ci.org/isaacs/minimatch)\n\n\nThis is the matching library used internally by npm.\n\nEventually, it will replace the C binding in node-glob.\n\nIt works by converting glob expressions into JavaScript `RegExp`\nobjects.\n\n## Usage\n\n```javascript\nvar minimatch = require(\"minimatch\")\n\nminimatch(\"bar.foo\", \"*.foo\") // true!\nminimatch(\"bar.foo\", \"*.bar\") // false!\nminimatch(\"bar.foo\", \"*.+(bar|foo)\", { debug: true }) // true, and noisy!\n```\n\n## Features\n\nSupports these glob features:\n\n* Brace Expansion\n* Extended glob matching\n* \"Globstar\" `**` matching\n\nSee:\n\n* `man sh`\n* `man bash`\n* `man 3 fnmatch`\n* `man 5 gitignore`\n\n## Minimatch Class\n\nCreate a minimatch object by instanting the `minimatch.Minimatch` class.\n\n```javascript\nvar Minimatch = require(\"minimatch\").Minimatch\nvar mm = new Minimatch(pattern, options)\n```\n\n### Properties\n\n* `pattern` The original pattern the minimatch object represents.\n* `options` The options supplied to the constructor.\n* `set` A 2-dimensional array of regexp or string expressions.\n Each row in the\n array corresponds to a brace-expanded pattern. Each item in the row\n corresponds to a single path-part. For example, the pattern\n `{a,b/c}/d` would expand to a set of patterns like:\n\n [ [ a, d ]\n , [ b, c, d ] ]\n\n If a portion of the pattern doesn't have any \"magic\" in it\n (that is, it's something like `\"foo\"` rather than `fo*o?`), then it\n will be left as a string rather than converted to a regular\n expression.\n\n* `regexp` Created by the `makeRe` method. A single regular expression\n expressing the entire pattern. This is useful in cases where you wish\n to use the pattern somewhat like `fnmatch(3)` with `FNM_PATH` enabled.\n* `negate` True if the pattern is negated.\n* `comment` True if the pattern is a comment.\n* `empty` True if the pattern is `\"\"`.\n\n### Methods\n\n* `makeRe` Generate the `regexp` member if necessary, and return it.\n Will return `false` if the pattern is invalid.\n* `match(fname)` Return true if the filename matches the pattern, or\n false otherwise.\n* `matchOne(fileArray, patternArray, partial)` Take a `/`-split\n filename, and match it against a single row in the `regExpSet`. This\n method is mainly for internal use, but is exposed so that it can be\n used by a glob-walker that needs to avoid excessive filesystem calls.\n\nAll other methods are internal, and will be called as necessary.\n\n## Functions\n\nThe top-level exported function has a `cache` property, which is an LRU\ncache set to store 100 items. So, calling these methods repeatedly\nwith the same pattern and options will use the same Minimatch object,\nsaving the cost of parsing it multiple times.\n\n### minimatch(path, pattern, options)\n\nMain export. Tests a path against the pattern using the options.\n\n```javascript\nvar isJS = minimatch(file, \"*.js\", { matchBase: true })\n```\n\n### minimatch.filter(pattern, options)\n\nReturns a function that tests its\nsupplied argument, suitable for use with `Array.filter`. Example:\n\n```javascript\nvar javascripts = fileList.filter(minimatch.filter(\"*.js\", {matchBase: true}))\n```\n\n### minimatch.match(list, pattern, options)\n\nMatch against the list of\nfiles, in the style of fnmatch or glob. If nothing is matched, and\noptions.nonull is set, then return a list containing the pattern itself.\n\n```javascript\nvar javascripts = minimatch.match(fileList, \"*.js\", {matchBase: true}))\n```\n\n### minimatch.makeRe(pattern, options)\n\nMake a regular expression object from the pattern.\n\n## Options\n\nAll options are `false` by default.\n\n### debug\n\nDump a ton of stuff to stderr.\n\n### nobrace\n\nDo not expand `{a,b}` and `{1..3}` brace sets.\n\n### noglobstar\n\nDisable `**` matching against multiple folder names.\n\n### dot\n\nAllow patterns to match filenames starting with a period, even if\nthe pattern does not explicitly have a period in that spot.\n\nNote that by default, `a/**/b` will **not** match `a/.d/b`, unless `dot`\nis set.\n\n### noext\n\nDisable \"extglob\" style patterns like `+(a|b)`.\n\n### nocase\n\nPerform a case-insensitive match.\n\n### nonull\n\nWhen a match is not found by `minimatch.match`, return a list containing\nthe pattern itself. When set, an empty list is returned if there are\nno matches.\n\n### matchBase\n\nIf set, then patterns without slashes will be matched\nagainst the basename of the path if it contains slashes. For example,\n`a?b` would match the path `/xyz/123/acb`, but not `/xyz/acb/123`.\n\n### nocomment\n\nSuppress the behavior of treating `#` at the start of a pattern as a\ncomment.\n\n### nonegate\n\nSuppress the behavior of treating a leading `!` character as negation.\n\n### flipNegate\n\nReturns from negate expressions the same as if they were not negated.\n(Ie, true on a hit, false on a miss.)\n\n\n## Comparisons to other fnmatch/glob implementations\n\nWhile strict compliance with the existing standards is a worthwhile\ngoal, some discrepancies exist between minimatch and other\nimplementations, and are intentional.\n\nIf the pattern starts with a `!` character, then it is negated. Set the\n`nonegate` flag to suppress this behavior, and treat leading `!`\ncharacters normally. This is perhaps relevant if you wish to start the\npattern with a negative extglob pattern like `!(a|B)`. Multiple `!`\ncharacters at the start of a pattern will negate the pattern multiple\ntimes.\n\nIf a pattern starts with `#`, then it is treated as a comment, and\nwill not match anything. Use `\\#` to match a literal `#` at the\nstart of a line, or set the `nocomment` flag to suppress this behavior.\n\nThe double-star character `**` is supported by default, unless the\n`noglobstar` flag is set. This is supported in the manner of bsdglob\nand bash 4.1, where `**` only has special significance if it is the only\nthing in a path part. That is, `a/**/b` will match `a/x/y/b`, but\n`a/**b` will not.\n\nIf an escaped pattern has no matches, and the `nonull` flag is set,\nthen minimatch.match returns the pattern as-provided, rather than\ninterpreting the character escapes. For example,\n`minimatch.match([], \"\\\\*a\\\\?\")` will return `\"\\\\*a\\\\?\"` rather than\n`\"*a?\"`. This is akin to setting the `nullglob` option in bash, except\nthat it does not resolve escaped pattern characters.\n\nIf brace expansion is not disabled, then it is performed before any\nother interpretation of the glob pattern. Thus, a pattern like\n`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded\n**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are\nchecked for validity. Since those two are valid, matching proceeds.\n", - "readmeFilename": "README.md", - "bugs": { - "url": "https://github.com/isaacs/minimatch/issues" - }, - "homepage": "https://github.com/isaacs/minimatch", - "_id": "minimatch@0.2.14", - "_from": "minimatch@~0.2.11" -} diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/test/basic.js b/tests/mocha/node_modules/glob/node_modules/minimatch/test/basic.js deleted file mode 100644 index ae7ac73c77..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/test/basic.js +++ /dev/null @@ -1,399 +0,0 @@ -// http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test -// -// TODO: Some of these tests do very bad things with backslashes, and will -// most likely fail badly on windows. They should probably be skipped. - -var tap = require("tap") - , globalBefore = Object.keys(global) - , mm = require("../") - , files = [ "a", "b", "c", "d", "abc" - , "abd", "abe", "bb", "bcd" - , "ca", "cb", "dd", "de" - , "bdir/", "bdir/cfile"] - , next = files.concat([ "a-b", "aXb" - , ".x", ".y" ]) - - -var patterns = - [ "http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test" - , ["a*", ["a", "abc", "abd", "abe"]] - , ["X*", ["X*"], {nonull: true}] - - // allow null glob expansion - , ["X*", []] - - // isaacs: Slightly different than bash/sh/ksh - // \\* is not un-escaped to literal "*" in a failed match, - // but it does make it get treated as a literal star - , ["\\*", ["\\*"], {nonull: true}] - , ["\\**", ["\\**"], {nonull: true}] - , ["\\*\\*", ["\\*\\*"], {nonull: true}] - - , ["b*/", ["bdir/"]] - , ["c*", ["c", "ca", "cb"]] - , ["**", files] - - , ["\\.\\./*/", ["\\.\\./*/"], {nonull: true}] - , ["s/\\..*//", ["s/\\..*//"], {nonull: true}] - - , "legendary larry crashes bashes" - , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/" - , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/"], {nonull: true}] - , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/" - , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/"], {nonull: true}] - - , "character classes" - , ["[a-c]b*", ["abc", "abd", "abe", "bb", "cb"]] - , ["[a-y]*[^c]", ["abd", "abe", "bb", "bcd", - "bdir/", "ca", "cb", "dd", "de"]] - , ["a*[^c]", ["abd", "abe"]] - , function () { files.push("a-b", "aXb") } - , ["a[X-]b", ["a-b", "aXb"]] - , function () { files.push(".x", ".y") } - , ["[^a-c]*", ["d", "dd", "de"]] - , function () { files.push("a*b/", "a*b/ooo") } - , ["a\\*b/*", ["a*b/ooo"]] - , ["a\\*?/*", ["a*b/ooo"]] - , ["*\\\\!*", [], {null: true}, ["echo !7"]] - , ["*\\!*", ["echo !7"], null, ["echo !7"]] - , ["*.\\*", ["r.*"], null, ["r.*"]] - , ["a[b]c", ["abc"]] - , ["a[\\b]c", ["abc"]] - , ["a?c", ["abc"]] - , ["a\\*c", [], {null: true}, ["abc"]] - , ["", [""], { null: true }, [""]] - - , "http://www.opensource.apple.com/source/bash/bash-23/" + - "bash/tests/glob-test" - , function () { files.push("man/", "man/man1/", "man/man1/bash.1") } - , ["*/man*/bash.*", ["man/man1/bash.1"]] - , ["man/man1/bash.1", ["man/man1/bash.1"]] - , ["a***c", ["abc"], null, ["abc"]] - , ["a*****?c", ["abc"], null, ["abc"]] - , ["?*****??", ["abc"], null, ["abc"]] - , ["*****??", ["abc"], null, ["abc"]] - , ["?*****?c", ["abc"], null, ["abc"]] - , ["?***?****c", ["abc"], null, ["abc"]] - , ["?***?****?", ["abc"], null, ["abc"]] - , ["?***?****", ["abc"], null, ["abc"]] - , ["*******c", ["abc"], null, ["abc"]] - , ["*******?", ["abc"], null, ["abc"]] - , ["a*cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["a**?**cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["a**?**cd**?**??k***", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["a**?**cd**?**??***k", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["a**?**cd**?**??***k**", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["a****c**?**??*****", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["[-abc]", ["-"], null, ["-"]] - , ["[abc-]", ["-"], null, ["-"]] - , ["\\", ["\\"], null, ["\\"]] - , ["[\\\\]", ["\\"], null, ["\\"]] - , ["[[]", ["["], null, ["["]] - , ["[", ["["], null, ["["]] - , ["[*", ["[abc"], null, ["[abc"]] - , "a right bracket shall lose its special meaning and\n" + - "represent itself in a bracket expression if it occurs\n" + - "first in the list. -- POSIX.2 2.8.3.2" - , ["[]]", ["]"], null, ["]"]] - , ["[]-]", ["]"], null, ["]"]] - , ["[a-\z]", ["p"], null, ["p"]] - , ["??**********?****?", [], { null: true }, ["abc"]] - , ["??**********?****c", [], { null: true }, ["abc"]] - , ["?************c****?****", [], { null: true }, ["abc"]] - , ["*c*?**", [], { null: true }, ["abc"]] - , ["a*****c*?**", [], { null: true }, ["abc"]] - , ["a********???*******", [], { null: true }, ["abc"]] - , ["[]", [], { null: true }, ["a"]] - , ["[abc", [], { null: true }, ["["]] - - , "nocase tests" - , ["XYZ", ["xYz"], { nocase: true, null: true } - , ["xYz", "ABC", "IjK"]] - , ["ab*", ["ABC"], { nocase: true, null: true } - , ["xYz", "ABC", "IjK"]] - , ["[ia]?[ck]", ["ABC", "IjK"], { nocase: true, null: true } - , ["xYz", "ABC", "IjK"]] - - // [ pattern, [matches], MM opts, files, TAP opts] - , "onestar/twostar" - , ["{/*,*}", [], {null: true}, ["/asdf/asdf/asdf"]] - , ["{/?,*}", ["/a", "bb"], {null: true} - , ["/a", "/b/b", "/a/b/c", "bb"]] - - , "dots should not match unless requested" - , ["**", ["a/b"], {}, ["a/b", "a/.d", ".a/.d"]] - - // .. and . can only match patterns starting with ., - // even when options.dot is set. - , function () { - files = ["a/./b", "a/../b", "a/c/b", "a/.d/b"] - } - , ["a/*/b", ["a/c/b", "a/.d/b"], {dot: true}] - , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: true}] - , ["a/*/b", ["a/c/b"], {dot:false}] - , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: false}] - - - // this also tests that changing the options needs - // to change the cache key, even if the pattern is - // the same! - , ["**", ["a/b","a/.d",".a/.d"], { dot: true } - , [ ".a/.d", "a/.d", "a/b"]] - - , "paren sets cannot contain slashes" - , ["*(a/b)", ["*(a/b)"], {nonull: true}, ["a/b"]] - - // brace sets trump all else. - // - // invalid glob pattern. fails on bash4 and bsdglob. - // however, in this implementation, it's easier just - // to do the intuitive thing, and let brace-expansion - // actually come before parsing any extglob patterns, - // like the documentation seems to say. - // - // XXX: if anyone complains about this, either fix it - // or tell them to grow up and stop complaining. - // - // bash/bsdglob says this: - // , ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]] - // but we do this instead: - , ["*(a|{b),c)}", ["a", "ab", "ac"], {}, ["a", "ab", "ac", "ad"]] - - // test partial parsing in the presence of comment/negation chars - , ["[!a*", ["[!ab"], {}, ["[!ab", "[ab"]] - , ["[#a*", ["[#ab"], {}, ["[#ab", "[ab"]] - - // like: {a,b|c\\,d\\\|e} except it's unclosed, so it has to be escaped. - , ["+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g" - , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g"] - , {} - , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g", "a", "b\\c"]] - - - // crazy nested {,,} and *(||) tests. - , function () { - files = [ "a", "b", "c", "d" - , "ab", "ac", "ad" - , "bc", "cb" - , "bc,d", "c,db", "c,d" - , "d)", "(b|c", "*(b|c" - , "b|c", "b|cc", "cb|c" - , "x(a|b|c)", "x(a|c)" - , "(a|b|c)", "(a|c)"] - } - , ["*(a|{b,c})", ["a", "b", "c", "ab", "ac"]] - , ["{a,*(b|c,d)}", ["a","(b|c", "*(b|c", "d)"]] - // a - // *(b|c) - // *(b|d) - , ["{a,*(b|{c,d})}", ["a","b", "bc", "cb", "c", "d"]] - , ["*(a|{b|c,c})", ["a", "b", "c", "ab", "ac", "bc", "cb"]] - - - // test various flag settings. - , [ "*(a|{b|c,c})", ["x(a|b|c)", "x(a|c)", "(a|b|c)", "(a|c)"] - , { noext: true } ] - , ["a?b", ["x/y/acb", "acb/"], {matchBase: true} - , ["x/y/acb", "acb/", "acb/d/e", "x/y/acb/d"] ] - , ["#*", ["#a", "#b"], {nocomment: true}, ["#a", "#b", "c#d"]] - - - // begin channelling Boole and deMorgan... - , "negation tests" - , function () { - files = ["d", "e", "!ab", "!abc", "a!b", "\\!a"] - } - - // anything that is NOT a* matches. - , ["!a*", ["\\!a", "d", "e", "!ab", "!abc"]] - - // anything that IS !a* matches. - , ["!a*", ["!ab", "!abc"], {nonegate: true}] - - // anything that IS a* matches - , ["!!a*", ["a!b"]] - - // anything that is NOT !a* matches - , ["!\\!a*", ["a!b", "d", "e", "\\!a"]] - - // negation nestled within a pattern - , function () { - files = [ "foo.js" - , "foo.bar" - // can't match this one without negative lookbehind. - , "foo.js.js" - , "blar.js" - , "foo." - , "boo.js.boo" ] - } - , ["*.!(js)", ["foo.bar", "foo.", "boo.js.boo"] ] - - // https://github.com/isaacs/minimatch/issues/5 - , function () { - files = [ 'a/b/.x/c' - , 'a/b/.x/c/d' - , 'a/b/.x/c/d/e' - , 'a/b/.x' - , 'a/b/.x/' - , 'a/.x/b' - , '.x' - , '.x/' - , '.x/a' - , '.x/a/b' - , 'a/.x/b/.x/c' - , '.x/.x' ] - } - , ["**/.x/**", [ '.x/' - , '.x/a' - , '.x/a/b' - , 'a/.x/b' - , 'a/b/.x/' - , 'a/b/.x/c' - , 'a/b/.x/c/d' - , 'a/b/.x/c/d/e' ] ] - - ] - -var regexps = - [ '/^(?:(?=.)a[^/]*?)$/', - '/^(?:(?=.)X[^/]*?)$/', - '/^(?:(?=.)X[^/]*?)$/', - '/^(?:\\*)$/', - '/^(?:(?=.)\\*[^/]*?)$/', - '/^(?:\\*\\*)$/', - '/^(?:(?=.)b[^/]*?\\/)$/', - '/^(?:(?=.)c[^/]*?)$/', - '/^(?:(?:(?!(?:\\/|^)\\.).)*?)$/', - '/^(?:\\.\\.\\/(?!\\.)(?=.)[^/]*?\\/)$/', - '/^(?:s\\/(?=.)\\.\\.[^/]*?\\/)$/', - '/^(?:\\/\\^root:\\/\\{s\\/(?=.)\\^[^:][^/]*?:[^:][^/]*?:\\([^:]\\)[^/]*?\\.[^/]*?\\$\\/1\\/)$/', - '/^(?:\\/\\^root:\\/\\{s\\/(?=.)\\^[^:][^/]*?:[^:][^/]*?:\\([^:]\\)[^/]*?\\.[^/]*?\\$\\/\u0001\\/)$/', - '/^(?:(?!\\.)(?=.)[a-c]b[^/]*?)$/', - '/^(?:(?!\\.)(?=.)[a-y][^/]*?[^c])$/', - '/^(?:(?=.)a[^/]*?[^c])$/', - '/^(?:(?=.)a[X-]b)$/', - '/^(?:(?!\\.)(?=.)[^a-c][^/]*?)$/', - '/^(?:a\\*b\\/(?!\\.)(?=.)[^/]*?)$/', - '/^(?:(?=.)a\\*[^/]\\/(?!\\.)(?=.)[^/]*?)$/', - '/^(?:(?!\\.)(?=.)[^/]*?\\\\\\![^/]*?)$/', - '/^(?:(?!\\.)(?=.)[^/]*?\\![^/]*?)$/', - '/^(?:(?!\\.)(?=.)[^/]*?\\.\\*)$/', - '/^(?:(?=.)a[b]c)$/', - '/^(?:(?=.)a[b]c)$/', - '/^(?:(?=.)a[^/]c)$/', - '/^(?:a\\*c)$/', - 'false', - '/^(?:(?!\\.)(?=.)[^/]*?\\/(?=.)man[^/]*?\\/(?=.)bash\\.[^/]*?)$/', - '/^(?:man\\/man1\\/bash\\.1)$/', - '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?c)$/', - '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/', - '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/', - '/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/])$/', - '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]c)$/', - '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/', - '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/', - '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/', - '/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c)$/', - '/^(?:(?!\\.)(?=.)[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/])$/', - '/^(?:(?=.)a[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/', - '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k)$/', - '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/]k[^/]*?[^/]*?[^/]*?)$/', - '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k)$/', - '/^(?:(?=.)a[^/]*?[^/]*?[^/][^/]*?[^/]*?cd[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?k[^/]*?[^/]*?)$/', - '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/', - '/^(?:(?!\\.)(?=.)[-abc])$/', - '/^(?:(?!\\.)(?=.)[abc-])$/', - '/^(?:\\\\)$/', - '/^(?:(?!\\.)(?=.)[\\\\])$/', - '/^(?:(?!\\.)(?=.)[\\[])$/', - '/^(?:\\[)$/', - '/^(?:(?=.)\\[(?!\\.)(?=.)[^/]*?)$/', - '/^(?:(?!\\.)(?=.)[\\]])$/', - '/^(?:(?!\\.)(?=.)[\\]-])$/', - '/^(?:(?!\\.)(?=.)[a-z])$/', - '/^(?:(?!\\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/])$/', - '/^(?:(?!\\.)(?=.)[^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?c)$/', - '/^(?:(?!\\.)(?=.)[^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/]*?[^/]*?[^/]*?[^/]*?)$/', - '/^(?:(?!\\.)(?=.)[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/', - '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?c[^/]*?[^/][^/]*?[^/]*?)$/', - '/^(?:(?=.)a[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/][^/][^/][^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?[^/]*?)$/', - '/^(?:\\[\\])$/', - '/^(?:\\[abc)$/', - '/^(?:(?=.)XYZ)$/i', - '/^(?:(?=.)ab[^/]*?)$/i', - '/^(?:(?!\\.)(?=.)[ia][^/][ck])$/i', - '/^(?:\\/(?!\\.)(?=.)[^/]*?|(?!\\.)(?=.)[^/]*?)$/', - '/^(?:\\/(?!\\.)(?=.)[^/]|(?!\\.)(?=.)[^/]*?)$/', - '/^(?:(?:(?!(?:\\/|^)\\.).)*?)$/', - '/^(?:a\\/(?!(?:^|\\/)\\.{1,2}(?:$|\\/))(?=.)[^/]*?\\/b)$/', - '/^(?:a\\/(?=.)\\.[^/]*?\\/b)$/', - '/^(?:a\\/(?!\\.)(?=.)[^/]*?\\/b)$/', - '/^(?:a\\/(?=.)\\.[^/]*?\\/b)$/', - '/^(?:(?:(?!(?:\\/|^)(?:\\.{1,2})($|\\/)).)*?)$/', - '/^(?:(?!\\.)(?=.)[^/]*?\\(a\\/b\\))$/', - '/^(?:(?!\\.)(?=.)(?:a|b)*|(?!\\.)(?=.)(?:a|c)*)$/', - '/^(?:(?=.)\\[(?=.)\\!a[^/]*?)$/', - '/^(?:(?=.)\\[(?=.)#a[^/]*?)$/', - '/^(?:(?=.)\\+\\(a\\|[^/]*?\\|c\\\\\\\\\\|d\\\\\\\\\\|e\\\\\\\\\\\\\\\\\\|f\\\\\\\\\\\\\\\\\\|g)$/', - '/^(?:(?!\\.)(?=.)(?:a|b)*|(?!\\.)(?=.)(?:a|c)*)$/', - '/^(?:a|(?!\\.)(?=.)[^/]*?\\(b\\|c|d\\))$/', - '/^(?:a|(?!\\.)(?=.)(?:b|c)*|(?!\\.)(?=.)(?:b|d)*)$/', - '/^(?:(?!\\.)(?=.)(?:a|b|c)*|(?!\\.)(?=.)(?:a|c)*)$/', - '/^(?:(?!\\.)(?=.)[^/]*?\\(a\\|b\\|c\\)|(?!\\.)(?=.)[^/]*?\\(a\\|c\\))$/', - '/^(?:(?=.)a[^/]b)$/', - '/^(?:(?=.)#[^/]*?)$/', - '/^(?!^(?:(?=.)a[^/]*?)$).*$/', - '/^(?:(?=.)\\!a[^/]*?)$/', - '/^(?:(?=.)a[^/]*?)$/', - '/^(?!^(?:(?=.)\\!a[^/]*?)$).*$/', - '/^(?:(?!\\.)(?=.)[^/]*?\\.(?:(?!js)[^/]*?))$/', - '/^(?:(?:(?!(?:\\/|^)\\.).)*?\\/\\.x\\/(?:(?!(?:\\/|^)\\.).)*?)$/' ] -var re = 0; - -tap.test("basic tests", function (t) { - var start = Date.now() - - // [ pattern, [matches], MM opts, files, TAP opts] - patterns.forEach(function (c) { - if (typeof c === "function") return c() - if (typeof c === "string") return t.comment(c) - - var pattern = c[0] - , expect = c[1].sort(alpha) - , options = c[2] || {} - , f = c[3] || files - , tapOpts = c[4] || {} - - // options.debug = true - var m = new mm.Minimatch(pattern, options) - var r = m.makeRe() - var expectRe = regexps[re++] - tapOpts.re = String(r) || JSON.stringify(r) - tapOpts.files = JSON.stringify(f) - tapOpts.pattern = pattern - tapOpts.set = m.set - tapOpts.negated = m.negate - - var actual = mm.match(f, pattern, options) - actual.sort(alpha) - - t.equivalent( actual, expect - , JSON.stringify(pattern) + " " + JSON.stringify(expect) - , tapOpts ) - - t.equal(tapOpts.re, expectRe, tapOpts) - }) - - t.comment("time=" + (Date.now() - start) + "ms") - t.end() -}) - -tap.test("global leak test", function (t) { - var globalAfter = Object.keys(global) - t.equivalent(globalAfter, globalBefore, "no new globals, please") - t.end() -}) - -function alpha (a, b) { - return a > b ? 1 : -1 -} diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/test/brace-expand.js b/tests/mocha/node_modules/glob/node_modules/minimatch/test/brace-expand.js deleted file mode 100644 index 7ee278a274..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/test/brace-expand.js +++ /dev/null @@ -1,33 +0,0 @@ -var tap = require("tap") - , minimatch = require("../") - -tap.test("brace expansion", function (t) { - // [ pattern, [expanded] ] - ; [ [ "a{b,c{d,e},{f,g}h}x{y,z}" - , [ "abxy" - , "abxz" - , "acdxy" - , "acdxz" - , "acexy" - , "acexz" - , "afhxy" - , "afhxz" - , "aghxy" - , "aghxz" ] ] - , [ "a{1..5}b" - , [ "a1b" - , "a2b" - , "a3b" - , "a4b" - , "a5b" ] ] - , [ "a{b}c", ["a{b}c"] ] - ].forEach(function (tc) { - var p = tc[0] - , expect = tc[1] - t.equivalent(minimatch.braceExpand(p), expect, p) - }) - console.error("ending") - t.end() -}) - - diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/test/caching.js b/tests/mocha/node_modules/glob/node_modules/minimatch/test/caching.js deleted file mode 100644 index 0fec4b0fad..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/test/caching.js +++ /dev/null @@ -1,14 +0,0 @@ -var Minimatch = require("../minimatch.js").Minimatch -var tap = require("tap") -tap.test("cache test", function (t) { - var mm1 = new Minimatch("a?b") - var mm2 = new Minimatch("a?b") - t.equal(mm1, mm2, "should get the same object") - // the lru should drop it after 100 entries - for (var i = 0; i < 100; i ++) { - new Minimatch("a"+i) - } - mm2 = new Minimatch("a?b") - t.notEqual(mm1, mm2, "cache should have dropped") - t.end() -}) diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/test/defaults.js b/tests/mocha/node_modules/glob/node_modules/minimatch/test/defaults.js deleted file mode 100644 index 25f1f601cd..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/test/defaults.js +++ /dev/null @@ -1,274 +0,0 @@ -// http://www.bashcookbook.com/bashinfo/source/bash-1.14.7/tests/glob-test -// -// TODO: Some of these tests do very bad things with backslashes, and will -// most likely fail badly on windows. They should probably be skipped. - -var tap = require("tap") - , globalBefore = Object.keys(global) - , mm = require("../") - , files = [ "a", "b", "c", "d", "abc" - , "abd", "abe", "bb", "bcd" - , "ca", "cb", "dd", "de" - , "bdir/", "bdir/cfile"] - , next = files.concat([ "a-b", "aXb" - , ".x", ".y" ]) - -tap.test("basic tests", function (t) { - var start = Date.now() - - // [ pattern, [matches], MM opts, files, TAP opts] - ; [ "http://www.bashcookbook.com/bashinfo" + - "/source/bash-1.14.7/tests/glob-test" - , ["a*", ["a", "abc", "abd", "abe"]] - , ["X*", ["X*"], {nonull: true}] - - // allow null glob expansion - , ["X*", []] - - // isaacs: Slightly different than bash/sh/ksh - // \\* is not un-escaped to literal "*" in a failed match, - // but it does make it get treated as a literal star - , ["\\*", ["\\*"], {nonull: true}] - , ["\\**", ["\\**"], {nonull: true}] - , ["\\*\\*", ["\\*\\*"], {nonull: true}] - - , ["b*/", ["bdir/"]] - , ["c*", ["c", "ca", "cb"]] - , ["**", files] - - , ["\\.\\./*/", ["\\.\\./*/"], {nonull: true}] - , ["s/\\..*//", ["s/\\..*//"], {nonull: true}] - - , "legendary larry crashes bashes" - , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/" - , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\\1/"], {nonull: true}] - , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/" - , ["/^root:/{s/^[^:]*:[^:]*:\([^:]*\).*$/\1/"], {nonull: true}] - - , "character classes" - , ["[a-c]b*", ["abc", "abd", "abe", "bb", "cb"]] - , ["[a-y]*[^c]", ["abd", "abe", "bb", "bcd", - "bdir/", "ca", "cb", "dd", "de"]] - , ["a*[^c]", ["abd", "abe"]] - , function () { files.push("a-b", "aXb") } - , ["a[X-]b", ["a-b", "aXb"]] - , function () { files.push(".x", ".y") } - , ["[^a-c]*", ["d", "dd", "de"]] - , function () { files.push("a*b/", "a*b/ooo") } - , ["a\\*b/*", ["a*b/ooo"]] - , ["a\\*?/*", ["a*b/ooo"]] - , ["*\\\\!*", [], {null: true}, ["echo !7"]] - , ["*\\!*", ["echo !7"], null, ["echo !7"]] - , ["*.\\*", ["r.*"], null, ["r.*"]] - , ["a[b]c", ["abc"]] - , ["a[\\b]c", ["abc"]] - , ["a?c", ["abc"]] - , ["a\\*c", [], {null: true}, ["abc"]] - , ["", [""], { null: true }, [""]] - - , "http://www.opensource.apple.com/source/bash/bash-23/" + - "bash/tests/glob-test" - , function () { files.push("man/", "man/man1/", "man/man1/bash.1") } - , ["*/man*/bash.*", ["man/man1/bash.1"]] - , ["man/man1/bash.1", ["man/man1/bash.1"]] - , ["a***c", ["abc"], null, ["abc"]] - , ["a*****?c", ["abc"], null, ["abc"]] - , ["?*****??", ["abc"], null, ["abc"]] - , ["*****??", ["abc"], null, ["abc"]] - , ["?*****?c", ["abc"], null, ["abc"]] - , ["?***?****c", ["abc"], null, ["abc"]] - , ["?***?****?", ["abc"], null, ["abc"]] - , ["?***?****", ["abc"], null, ["abc"]] - , ["*******c", ["abc"], null, ["abc"]] - , ["*******?", ["abc"], null, ["abc"]] - , ["a*cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["a**?**cd**?**??k", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["a**?**cd**?**??k***", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["a**?**cd**?**??***k", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["a**?**cd**?**??***k**", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["a****c**?**??*****", ["abcdecdhjk"], null, ["abcdecdhjk"]] - , ["[-abc]", ["-"], null, ["-"]] - , ["[abc-]", ["-"], null, ["-"]] - , ["\\", ["\\"], null, ["\\"]] - , ["[\\\\]", ["\\"], null, ["\\"]] - , ["[[]", ["["], null, ["["]] - , ["[", ["["], null, ["["]] - , ["[*", ["[abc"], null, ["[abc"]] - , "a right bracket shall lose its special meaning and\n" + - "represent itself in a bracket expression if it occurs\n" + - "first in the list. -- POSIX.2 2.8.3.2" - , ["[]]", ["]"], null, ["]"]] - , ["[]-]", ["]"], null, ["]"]] - , ["[a-\z]", ["p"], null, ["p"]] - , ["??**********?****?", [], { null: true }, ["abc"]] - , ["??**********?****c", [], { null: true }, ["abc"]] - , ["?************c****?****", [], { null: true }, ["abc"]] - , ["*c*?**", [], { null: true }, ["abc"]] - , ["a*****c*?**", [], { null: true }, ["abc"]] - , ["a********???*******", [], { null: true }, ["abc"]] - , ["[]", [], { null: true }, ["a"]] - , ["[abc", [], { null: true }, ["["]] - - , "nocase tests" - , ["XYZ", ["xYz"], { nocase: true, null: true } - , ["xYz", "ABC", "IjK"]] - , ["ab*", ["ABC"], { nocase: true, null: true } - , ["xYz", "ABC", "IjK"]] - , ["[ia]?[ck]", ["ABC", "IjK"], { nocase: true, null: true } - , ["xYz", "ABC", "IjK"]] - - // [ pattern, [matches], MM opts, files, TAP opts] - , "onestar/twostar" - , ["{/*,*}", [], {null: true}, ["/asdf/asdf/asdf"]] - , ["{/?,*}", ["/a", "bb"], {null: true} - , ["/a", "/b/b", "/a/b/c", "bb"]] - - , "dots should not match unless requested" - , ["**", ["a/b"], {}, ["a/b", "a/.d", ".a/.d"]] - - // .. and . can only match patterns starting with ., - // even when options.dot is set. - , function () { - files = ["a/./b", "a/../b", "a/c/b", "a/.d/b"] - } - , ["a/*/b", ["a/c/b", "a/.d/b"], {dot: true}] - , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: true}] - , ["a/*/b", ["a/c/b"], {dot:false}] - , ["a/.*/b", ["a/./b", "a/../b", "a/.d/b"], {dot: false}] - - - // this also tests that changing the options needs - // to change the cache key, even if the pattern is - // the same! - , ["**", ["a/b","a/.d",".a/.d"], { dot: true } - , [ ".a/.d", "a/.d", "a/b"]] - - , "paren sets cannot contain slashes" - , ["*(a/b)", ["*(a/b)"], {nonull: true}, ["a/b"]] - - // brace sets trump all else. - // - // invalid glob pattern. fails on bash4 and bsdglob. - // however, in this implementation, it's easier just - // to do the intuitive thing, and let brace-expansion - // actually come before parsing any extglob patterns, - // like the documentation seems to say. - // - // XXX: if anyone complains about this, either fix it - // or tell them to grow up and stop complaining. - // - // bash/bsdglob says this: - // , ["*(a|{b),c)}", ["*(a|{b),c)}"], {}, ["a", "ab", "ac", "ad"]] - // but we do this instead: - , ["*(a|{b),c)}", ["a", "ab", "ac"], {}, ["a", "ab", "ac", "ad"]] - - // test partial parsing in the presence of comment/negation chars - , ["[!a*", ["[!ab"], {}, ["[!ab", "[ab"]] - , ["[#a*", ["[#ab"], {}, ["[#ab", "[ab"]] - - // like: {a,b|c\\,d\\\|e} except it's unclosed, so it has to be escaped. - , ["+(a|*\\|c\\\\|d\\\\\\|e\\\\\\\\|f\\\\\\\\\\|g" - , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g"] - , {} - , ["+(a|b\\|c\\\\|d\\\\|e\\\\\\\\|f\\\\\\\\|g", "a", "b\\c"]] - - - // crazy nested {,,} and *(||) tests. - , function () { - files = [ "a", "b", "c", "d" - , "ab", "ac", "ad" - , "bc", "cb" - , "bc,d", "c,db", "c,d" - , "d)", "(b|c", "*(b|c" - , "b|c", "b|cc", "cb|c" - , "x(a|b|c)", "x(a|c)" - , "(a|b|c)", "(a|c)"] - } - , ["*(a|{b,c})", ["a", "b", "c", "ab", "ac"]] - , ["{a,*(b|c,d)}", ["a","(b|c", "*(b|c", "d)"]] - // a - // *(b|c) - // *(b|d) - , ["{a,*(b|{c,d})}", ["a","b", "bc", "cb", "c", "d"]] - , ["*(a|{b|c,c})", ["a", "b", "c", "ab", "ac", "bc", "cb"]] - - - // test various flag settings. - , [ "*(a|{b|c,c})", ["x(a|b|c)", "x(a|c)", "(a|b|c)", "(a|c)"] - , { noext: true } ] - , ["a?b", ["x/y/acb", "acb/"], {matchBase: true} - , ["x/y/acb", "acb/", "acb/d/e", "x/y/acb/d"] ] - , ["#*", ["#a", "#b"], {nocomment: true}, ["#a", "#b", "c#d"]] - - - // begin channelling Boole and deMorgan... - , "negation tests" - , function () { - files = ["d", "e", "!ab", "!abc", "a!b", "\\!a"] - } - - // anything that is NOT a* matches. - , ["!a*", ["\\!a", "d", "e", "!ab", "!abc"]] - - // anything that IS !a* matches. - , ["!a*", ["!ab", "!abc"], {nonegate: true}] - - // anything that IS a* matches - , ["!!a*", ["a!b"]] - - // anything that is NOT !a* matches - , ["!\\!a*", ["a!b", "d", "e", "\\!a"]] - - // negation nestled within a pattern - , function () { - files = [ "foo.js" - , "foo.bar" - // can't match this one without negative lookbehind. - , "foo.js.js" - , "blar.js" - , "foo." - , "boo.js.boo" ] - } - , ["*.!(js)", ["foo.bar", "foo.", "boo.js.boo"] ] - - ].forEach(function (c) { - if (typeof c === "function") return c() - if (typeof c === "string") return t.comment(c) - - var pattern = c[0] - , expect = c[1].sort(alpha) - , options = c[2] || {} - , f = c[3] || files - , tapOpts = c[4] || {} - - // options.debug = true - var Class = mm.defaults(options).Minimatch - var m = new Class(pattern, {}) - var r = m.makeRe() - tapOpts.re = String(r) || JSON.stringify(r) - tapOpts.files = JSON.stringify(f) - tapOpts.pattern = pattern - tapOpts.set = m.set - tapOpts.negated = m.negate - - var actual = mm.match(f, pattern, options) - actual.sort(alpha) - - t.equivalent( actual, expect - , JSON.stringify(pattern) + " " + JSON.stringify(expect) - , tapOpts ) - }) - - t.comment("time=" + (Date.now() - start) + "ms") - t.end() -}) - -tap.test("global leak test", function (t) { - var globalAfter = Object.keys(global) - t.equivalent(globalAfter, globalBefore, "no new globals, please") - t.end() -}) - -function alpha (a, b) { - return a > b ? 1 : -1 -} diff --git a/tests/mocha/node_modules/glob/node_modules/minimatch/test/extglob-ending-with-state-char.js b/tests/mocha/node_modules/glob/node_modules/minimatch/test/extglob-ending-with-state-char.js deleted file mode 100644 index 6676e2629a..0000000000 --- a/tests/mocha/node_modules/glob/node_modules/minimatch/test/extglob-ending-with-state-char.js +++ /dev/null @@ -1,8 +0,0 @@ -var test = require('tap').test -var minimatch = require('../') - -test('extglob ending with statechar', function(t) { - t.notOk(minimatch('ax', 'a?(b*)')) - t.ok(minimatch('ax', '?(a*|b)')) - t.end() -}) diff --git a/tests/mocha/node_modules/glob/package.json b/tests/mocha/node_modules/glob/package.json deleted file mode 100644 index bfbbbcca06..0000000000 --- a/tests/mocha/node_modules/glob/package.json +++ /dev/null @@ -1,40 +0,0 @@ -{ - "author": { - "name": "Isaac Z. Schlueter", - "email": "i@izs.me", - "url": "http://blog.izs.me/" - }, - "name": "glob", - "description": "a little globber", - "version": "3.2.3", - "repository": { - "type": "git", - "url": "git://github.com/isaacs/node-glob.git" - }, - "main": "glob.js", - "engines": { - "node": "*" - }, - "dependencies": { - "minimatch": "~0.2.11", - "graceful-fs": "~2.0.0", - "inherits": "2" - }, - "devDependencies": { - "tap": "~0.4.0", - "mkdirp": "0", - "rimraf": "1" - }, - "scripts": { - "test": "tap test/*.js" - }, - "license": "BSD", - "readme": "# Glob\n\nMatch files using the patterns the shell uses, like stars and stuff.\n\nThis is a glob implementation in JavaScript. It uses the `minimatch`\nlibrary to do its matching.\n\n## Attention: node-glob users!\n\nThe API has changed dramatically between 2.x and 3.x. This library is\nnow 100% JavaScript, and the integer flags have been replaced with an\noptions object.\n\nAlso, there's an event emitter class, proper tests, and all the other\nthings you've come to expect from node modules.\n\nAnd best of all, no compilation!\n\n## Usage\n\n```javascript\nvar glob = require(\"glob\")\n\n// options is optional\nglob(\"**/*.js\", options, function (er, files) {\n // files is an array of filenames.\n // If the `nonull` option is set, and nothing\n // was found, then files is [\"**/*.js\"]\n // er is an error object or null.\n})\n```\n\n## Features\n\nPlease see the [minimatch\ndocumentation](https://github.com/isaacs/minimatch) for more details.\n\nSupports these glob features:\n\n* Brace Expansion\n* Extended glob matching\n* \"Globstar\" `**` matching\n\nSee:\n\n* `man sh`\n* `man bash`\n* `man 3 fnmatch`\n* `man 5 gitignore`\n* [minimatch documentation](https://github.com/isaacs/minimatch)\n\n## glob(pattern, [options], cb)\n\n* `pattern` {String} Pattern to be matched\n* `options` {Object}\n* `cb` {Function}\n * `err` {Error | null}\n * `matches` {Array} filenames found matching the pattern\n\nPerform an asynchronous glob search.\n\n## glob.sync(pattern, [options])\n\n* `pattern` {String} Pattern to be matched\n* `options` {Object}\n* return: {Array} filenames found matching the pattern\n\nPerform a synchronous glob search.\n\n## Class: glob.Glob\n\nCreate a Glob object by instanting the `glob.Glob` class.\n\n```javascript\nvar Glob = require(\"glob\").Glob\nvar mg = new Glob(pattern, options, cb)\n```\n\nIt's an EventEmitter, and starts walking the filesystem to find matches\nimmediately.\n\n### new glob.Glob(pattern, [options], [cb])\n\n* `pattern` {String} pattern to search for\n* `options` {Object}\n* `cb` {Function} Called when an error occurs, or matches are found\n * `err` {Error | null}\n * `matches` {Array} filenames found matching the pattern\n\nNote that if the `sync` flag is set in the options, then matches will\nbe immediately available on the `g.found` member.\n\n### Properties\n\n* `minimatch` The minimatch object that the glob uses.\n* `options` The options object passed in.\n* `error` The error encountered. When an error is encountered, the\n glob object is in an undefined state, and should be discarded.\n* `aborted` Boolean which is set to true when calling `abort()`. There\n is no way at this time to continue a glob search after aborting, but\n you can re-use the statCache to avoid having to duplicate syscalls.\n* `statCache` Collection of all the stat results the glob search\n performed.\n* `cache` Convenience object. Each field has the following possible\n values:\n * `false` - Path does not exist\n * `true` - Path exists\n * `1` - Path exists, and is not a directory\n * `2` - Path exists, and is a directory\n * `[file, entries, ...]` - Path exists, is a directory, and the\n array value is the results of `fs.readdir`\n\n### Events\n\n* `end` When the matching is finished, this is emitted with all the\n matches found. If the `nonull` option is set, and no match was found,\n then the `matches` list contains the original pattern. The matches\n are sorted, unless the `nosort` flag is set.\n* `match` Every time a match is found, this is emitted with the matched.\n* `error` Emitted when an unexpected error is encountered, or whenever\n any fs error occurs if `options.strict` is set.\n* `abort` When `abort()` is called, this event is raised.\n\n### Methods\n\n* `abort` Stop the search.\n\n### Options\n\nAll the options that can be passed to Minimatch can also be passed to\nGlob to change pattern matching behavior. Also, some have been added,\nor have glob-specific ramifications.\n\nAll options are false by default, unless otherwise noted.\n\nAll options are added to the glob object, as well.\n\n* `cwd` The current working directory in which to search. Defaults\n to `process.cwd()`.\n* `root` The place where patterns starting with `/` will be mounted\n onto. Defaults to `path.resolve(options.cwd, \"/\")` (`/` on Unix\n systems, and `C:\\` or some such on Windows.)\n* `dot` Include `.dot` files in normal matches and `globstar` matches.\n Note that an explicit dot in a portion of the pattern will always\n match dot files.\n* `nomount` By default, a pattern starting with a forward-slash will be\n \"mounted\" onto the root setting, so that a valid filesystem path is\n returned. Set this flag to disable that behavior.\n* `mark` Add a `/` character to directory matches. Note that this\n requires additional stat calls.\n* `nosort` Don't sort the results.\n* `stat` Set to true to stat *all* results. This reduces performance\n somewhat, and is completely unnecessary, unless `readdir` is presumed\n to be an untrustworthy indicator of file existence. It will cause\n ELOOP to be triggered one level sooner in the case of cyclical\n symbolic links.\n* `silent` When an unusual error is encountered\n when attempting to read a directory, a warning will be printed to\n stderr. Set the `silent` option to true to suppress these warnings.\n* `strict` When an unusual error is encountered\n when attempting to read a directory, the process will just continue on\n in search of other matches. Set the `strict` option to raise an error\n in these cases.\n* `cache` See `cache` property above. Pass in a previously generated\n cache object to save some fs calls.\n* `statCache` A cache of results of filesystem information, to prevent\n unnecessary stat calls. While it should not normally be necessary to\n set this, you may pass the statCache from one glob() call to the\n options object of another, if you know that the filesystem will not\n change between calls. (See \"Race Conditions\" below.)\n* `sync` Perform a synchronous glob search.\n* `nounique` In some cases, brace-expanded patterns can result in the\n same file showing up multiple times in the result set. By default,\n this implementation prevents duplicates in the result set.\n Set this flag to disable that behavior.\n* `nonull` Set to never return an empty set, instead returning a set\n containing the pattern itself. This is the default in glob(3).\n* `nocase` Perform a case-insensitive match. Note that case-insensitive\n filesystems will sometimes result in glob returning results that are\n case-insensitively matched anyway, since readdir and stat will not\n raise an error.\n* `debug` Set to enable debug logging in minimatch and glob.\n* `globDebug` Set to enable debug logging in glob, but not minimatch.\n\n## Comparisons to other fnmatch/glob implementations\n\nWhile strict compliance with the existing standards is a worthwhile\ngoal, some discrepancies exist between node-glob and other\nimplementations, and are intentional.\n\nIf the pattern starts with a `!` character, then it is negated. Set the\n`nonegate` flag to suppress this behavior, and treat leading `!`\ncharacters normally. This is perhaps relevant if you wish to start the\npattern with a negative extglob pattern like `!(a|B)`. Multiple `!`\ncharacters at the start of a pattern will negate the pattern multiple\ntimes.\n\nIf a pattern starts with `#`, then it is treated as a comment, and\nwill not match anything. Use `\\#` to match a literal `#` at the\nstart of a line, or set the `nocomment` flag to suppress this behavior.\n\nThe double-star character `**` is supported by default, unless the\n`noglobstar` flag is set. This is supported in the manner of bsdglob\nand bash 4.1, where `**` only has special significance if it is the only\nthing in a path part. That is, `a/**/b` will match `a/x/y/b`, but\n`a/**b` will not.\n\nIf an escaped pattern has no matches, and the `nonull` flag is set,\nthen glob returns the pattern as-provided, rather than\ninterpreting the character escapes. For example,\n`glob.match([], \"\\\\*a\\\\?\")` will return `\"\\\\*a\\\\?\"` rather than\n`\"*a?\"`. This is akin to setting the `nullglob` option in bash, except\nthat it does not resolve escaped pattern characters.\n\nIf brace expansion is not disabled, then it is performed before any\nother interpretation of the glob pattern. Thus, a pattern like\n`+(a|{b),c)}`, which would not be valid in bash or zsh, is expanded\n**first** into the set of `+(a|b)` and `+(a|c)`, and those patterns are\nchecked for validity. Since those two are valid, matching proceeds.\n\n## Windows\n\n**Please only use forward-slashes in glob expressions.**\n\nThough windows uses either `/` or `\\` as its path separator, only `/`\ncharacters are used by this glob implementation. You must use\nforward-slashes **only** in glob expressions. Back-slashes will always\nbe interpreted as escape characters, not path separators.\n\nResults from absolute patterns such as `/foo/*` are mounted onto the\nroot setting using `path.join`. On windows, this will by default result\nin `/foo/*` matching `C:\\foo\\bar.txt`.\n\n## Race Conditions\n\nGlob searching, by its very nature, is susceptible to race conditions,\nsince it relies on directory walking and such.\n\nAs a result, it is possible that a file that exists when glob looks for\nit may have been deleted or modified by the time it returns the result.\n\nAs part of its internal implementation, this program caches all stat\nand readdir calls that it makes, in order to cut down on system\noverhead. However, this also makes it even more susceptible to races,\nespecially if the cache or statCache objects are reused between glob\ncalls.\n\nUsers are thus advised not to use a glob result as a guarantee of\nfilesystem state in the face of rapid changes. For the vast majority\nof operations, this is never a problem.\n", - "readmeFilename": "README.md", - "bugs": { - "url": "https://github.com/isaacs/node-glob/issues" - }, - "homepage": "https://github.com/isaacs/node-glob", - "_id": "glob@3.2.3", - "_from": "glob@3.2.3" -} diff --git a/tests/mocha/node_modules/glob/test/00-setup.js b/tests/mocha/node_modules/glob/test/00-setup.js deleted file mode 100644 index 245afafda4..0000000000 --- a/tests/mocha/node_modules/glob/test/00-setup.js +++ /dev/null @@ -1,176 +0,0 @@ -// just a little pre-run script to set up the fixtures. -// zz-finish cleans it up - -var mkdirp = require("mkdirp") -var path = require("path") -var i = 0 -var tap = require("tap") -var fs = require("fs") -var rimraf = require("rimraf") - -var files = -[ "a/.abcdef/x/y/z/a" -, "a/abcdef/g/h" -, "a/abcfed/g/h" -, "a/b/c/d" -, "a/bc/e/f" -, "a/c/d/c/b" -, "a/cb/e/f" -] - -var symlinkTo = path.resolve(__dirname, "a/symlink/a/b/c") -var symlinkFrom = "../.." - -files = files.map(function (f) { - return path.resolve(__dirname, f) -}) - -tap.test("remove fixtures", function (t) { - rimraf(path.resolve(__dirname, "a"), function (er) { - t.ifError(er, "remove fixtures") - t.end() - }) -}) - -files.forEach(function (f) { - tap.test(f, function (t) { - var d = path.dirname(f) - mkdirp(d, 0755, function (er) { - if (er) { - t.fail(er) - return t.bailout() - } - fs.writeFile(f, "i like tests", function (er) { - t.ifError(er, "make file") - t.end() - }) - }) - }) -}) - -if (process.platform !== "win32") { - tap.test("symlinky", function (t) { - var d = path.dirname(symlinkTo) - console.error("mkdirp", d) - mkdirp(d, 0755, function (er) { - t.ifError(er) - fs.symlink(symlinkFrom, symlinkTo, "dir", function (er) { - t.ifError(er, "make symlink") - t.end() - }) - }) - }) -} - -;["foo","bar","baz","asdf","quux","qwer","rewq"].forEach(function (w) { - w = "/tmp/glob-test/" + w - tap.test("create " + w, function (t) { - mkdirp(w, function (er) { - if (er) - throw er - t.pass(w) - t.end() - }) - }) -}) - - -// generate the bash pattern test-fixtures if possible -if (process.platform === "win32" || !process.env.TEST_REGEN) { - console.error("Windows, or TEST_REGEN unset. Using cached fixtures.") - return -} - -var spawn = require("child_process").spawn; -var globs = - // put more patterns here. - // anything that would be directly in / should be in /tmp/glob-test - ["test/a/*/+(c|g)/./d" - ,"test/a/**/[cg]/../[cg]" - ,"test/a/{b,c,d,e,f}/**/g" - ,"test/a/b/**" - ,"test/**/g" - ,"test/a/abc{fed,def}/g/h" - ,"test/a/abc{fed/g,def}/**/" - ,"test/a/abc{fed/g,def}/**///**/" - ,"test/**/a/**/" - ,"test/+(a|b|c)/a{/,bc*}/**" - ,"test/*/*/*/f" - ,"test/**/f" - ,"test/a/symlink/a/b/c/a/b/c/a/b/c//a/b/c////a/b/c/**/b/c/**" - ,"{./*/*,/tmp/glob-test/*}" - ,"{/tmp/glob-test/*,*}" // evil owl face! how you taunt me! - ,"test/a/!(symlink)/**" - ] -var bashOutput = {} -var fs = require("fs") - -globs.forEach(function (pattern) { - tap.test("generate fixture " + pattern, function (t) { - var cmd = "shopt -s globstar && " + - "shopt -s extglob && " + - "shopt -s nullglob && " + - // "shopt >&2; " + - "eval \'for i in " + pattern + "; do echo $i; done\'" - var cp = spawn("bash", ["-c", cmd], { cwd: path.dirname(__dirname) }) - var out = [] - cp.stdout.on("data", function (c) { - out.push(c) - }) - cp.stderr.pipe(process.stderr) - cp.on("close", function (code) { - out = flatten(out) - if (!out) - out = [] - else - out = cleanResults(out.split(/\r*\n/)) - - bashOutput[pattern] = out - t.notOk(code, "bash test should finish nicely") - t.end() - }) - }) -}) - -tap.test("save fixtures", function (t) { - var fname = path.resolve(__dirname, "bash-results.json") - var data = JSON.stringify(bashOutput, null, 2) + "\n" - fs.writeFile(fname, data, function (er) { - t.ifError(er) - t.end() - }) -}) - -function cleanResults (m) { - // normalize discrepancies in ordering, duplication, - // and ending slashes. - return m.map(function (m) { - return m.replace(/\/+/g, "/").replace(/\/$/, "") - }).sort(alphasort).reduce(function (set, f) { - if (f !== set[set.length - 1]) set.push(f) - return set - }, []).sort(alphasort).map(function (f) { - // de-windows - return (process.platform !== 'win32') ? f - : f.replace(/^[a-zA-Z]:\\\\/, '/').replace(/\\/g, '/') - }) -} - -function flatten (chunks) { - var s = 0 - chunks.forEach(function (c) { s += c.length }) - var out = new Buffer(s) - s = 0 - chunks.forEach(function (c) { - c.copy(out, s) - s += c.length - }) - - return out.toString().trim() -} - -function alphasort (a, b) { - a = a.toLowerCase() - b = b.toLowerCase() - return a > b ? 1 : a < b ? -1 : 0 -} diff --git a/tests/mocha/node_modules/glob/test/bash-comparison.js b/tests/mocha/node_modules/glob/test/bash-comparison.js deleted file mode 100644 index 239ed1a9c3..0000000000 --- a/tests/mocha/node_modules/glob/test/bash-comparison.js +++ /dev/null @@ -1,63 +0,0 @@ -// basic test -// show that it does the same thing by default as the shell. -var tap = require("tap") -, child_process = require("child_process") -, bashResults = require("./bash-results.json") -, globs = Object.keys(bashResults) -, glob = require("../") -, path = require("path") - -// run from the root of the project -// this is usually where you're at anyway, but be sure. -process.chdir(path.resolve(__dirname, "..")) - -function alphasort (a, b) { - a = a.toLowerCase() - b = b.toLowerCase() - return a > b ? 1 : a < b ? -1 : 0 -} - -globs.forEach(function (pattern) { - var expect = bashResults[pattern] - // anything regarding the symlink thing will fail on windows, so just skip it - if (process.platform === "win32" && - expect.some(function (m) { - return /\/symlink\//.test(m) - })) - return - - tap.test(pattern, function (t) { - glob(pattern, function (er, matches) { - if (er) - throw er - - // sort and unmark, just to match the shell results - matches = cleanResults(matches) - - t.deepEqual(matches, expect, pattern) - t.end() - }) - }) - - tap.test(pattern + " sync", function (t) { - var matches = cleanResults(glob.sync(pattern)) - - t.deepEqual(matches, expect, "should match shell") - t.end() - }) -}) - -function cleanResults (m) { - // normalize discrepancies in ordering, duplication, - // and ending slashes. - return m.map(function (m) { - return m.replace(/\/+/g, "/").replace(/\/$/, "") - }).sort(alphasort).reduce(function (set, f) { - if (f !== set[set.length - 1]) set.push(f) - return set - }, []).sort(alphasort).map(function (f) { - // de-windows - return (process.platform !== 'win32') ? f - : f.replace(/^[a-zA-Z]:[\/\\]+/, '/').replace(/[\\\/]+/g, '/') - }) -} diff --git a/tests/mocha/node_modules/glob/test/bash-results.json b/tests/mocha/node_modules/glob/test/bash-results.json deleted file mode 100644 index a9bc347dea..0000000000 --- a/tests/mocha/node_modules/glob/test/bash-results.json +++ /dev/null @@ -1,350 +0,0 @@ -{ - "test/a/*/+(c|g)/./d": [ - "test/a/b/c/./d" - ], - "test/a/**/[cg]/../[cg]": [ - "test/a/abcdef/g/../g", - "test/a/abcfed/g/../g", - "test/a/b/c/../c", - "test/a/c/../c", - "test/a/c/d/c/../c", - "test/a/symlink/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/../c" - ], - "test/a/{b,c,d,e,f}/**/g": [], - "test/a/b/**": [ - "test/a/b", - "test/a/b/c", - "test/a/b/c/d" - ], - "test/**/g": [ - "test/a/abcdef/g", - "test/a/abcfed/g" - ], - "test/a/abc{fed,def}/g/h": [ - "test/a/abcdef/g/h", - "test/a/abcfed/g/h" - ], - "test/a/abc{fed/g,def}/**/": [ - "test/a/abcdef", - "test/a/abcdef/g", - "test/a/abcfed/g" - ], - "test/a/abc{fed/g,def}/**///**/": [ - "test/a/abcdef", - "test/a/abcdef/g", - "test/a/abcfed/g" - ], - "test/**/a/**/": [ - "test/a", - "test/a/abcdef", - "test/a/abcdef/g", - "test/a/abcfed", - "test/a/abcfed/g", - "test/a/b", - "test/a/b/c", - "test/a/bc", - "test/a/bc/e", - "test/a/c", - "test/a/c/d", - "test/a/c/d/c", - "test/a/cb", - "test/a/cb/e", - "test/a/symlink", - "test/a/symlink/a", - "test/a/symlink/a/b", - "test/a/symlink/a/b/c", - "test/a/symlink/a/b/c/a", - "test/a/symlink/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b" - ], - "test/+(a|b|c)/a{/,bc*}/**": [ - "test/a/abcdef", - "test/a/abcdef/g", - "test/a/abcdef/g/h", - "test/a/abcfed", - "test/a/abcfed/g", - "test/a/abcfed/g/h" - ], - "test/*/*/*/f": [ - "test/a/bc/e/f", - "test/a/cb/e/f" - ], - "test/**/f": [ - "test/a/bc/e/f", - "test/a/cb/e/f" - ], - "test/a/symlink/a/b/c/a/b/c/a/b/c//a/b/c////a/b/c/**/b/c/**": [ - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b", - "test/a/symlink/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c/a/b/c" - ], - "{./*/*,/tmp/glob-test/*}": [ - "./examples/g.js", - "./examples/usr-local.js", - "./node_modules/graceful-fs", - "./node_modules/inherits", - "./node_modules/minimatch", - "./node_modules/mkdirp", - "./node_modules/rimraf", - "./node_modules/tap", - "./test/00-setup.js", - "./test/a", - "./test/bash-comparison.js", - "./test/bash-results.json", - "./test/cwd-test.js", - "./test/globstar-match.js", - "./test/mark.js", - "./test/nocase-nomagic.js", - "./test/pause-resume.js", - "./test/root-nomount.js", - "./test/root.js", - "./test/stat.js", - "./test/zz-cleanup.js", - "/tmp/glob-test/asdf", - "/tmp/glob-test/bar", - "/tmp/glob-test/baz", - "/tmp/glob-test/foo", - "/tmp/glob-test/quux", - "/tmp/glob-test/qwer", - "/tmp/glob-test/rewq" - ], - "{/tmp/glob-test/*,*}": [ - "/tmp/glob-test/asdf", - "/tmp/glob-test/bar", - "/tmp/glob-test/baz", - "/tmp/glob-test/foo", - "/tmp/glob-test/quux", - "/tmp/glob-test/qwer", - "/tmp/glob-test/rewq", - "examples", - "glob.js", - "LICENSE", - "node_modules", - "package.json", - "README.md", - "test" - ], - "test/a/!(symlink)/**": [ - "test/a/abcdef", - "test/a/abcdef/g", - "test/a/abcdef/g/h", - "test/a/abcfed", - "test/a/abcfed/g", - "test/a/abcfed/g/h", - "test/a/b", - "test/a/b/c", - "test/a/b/c/d", - "test/a/bc", - "test/a/bc/e", - "test/a/bc/e/f", - "test/a/c", - "test/a/c/d", - "test/a/c/d/c", - "test/a/c/d/c/b", - "test/a/cb", - "test/a/cb/e", - "test/a/cb/e/f" - ] -} diff --git a/tests/mocha/node_modules/glob/test/cwd-test.js b/tests/mocha/node_modules/glob/test/cwd-test.js deleted file mode 100644 index 352c27efad..0000000000 --- a/tests/mocha/node_modules/glob/test/cwd-test.js +++ /dev/null @@ -1,55 +0,0 @@ -var tap = require("tap") - -var origCwd = process.cwd() -process.chdir(__dirname) - -tap.test("changing cwd and searching for **/d", function (t) { - var glob = require('../') - var path = require('path') - t.test('.', function (t) { - glob('**/d', function (er, matches) { - t.ifError(er) - t.like(matches, [ 'a/b/c/d', 'a/c/d' ]) - t.end() - }) - }) - - t.test('a', function (t) { - glob('**/d', {cwd:path.resolve('a')}, function (er, matches) { - t.ifError(er) - t.like(matches, [ 'b/c/d', 'c/d' ]) - t.end() - }) - }) - - t.test('a/b', function (t) { - glob('**/d', {cwd:path.resolve('a/b')}, function (er, matches) { - t.ifError(er) - t.like(matches, [ 'c/d' ]) - t.end() - }) - }) - - t.test('a/b/', function (t) { - glob('**/d', {cwd:path.resolve('a/b/')}, function (er, matches) { - t.ifError(er) - t.like(matches, [ 'c/d' ]) - t.end() - }) - }) - - t.test('.', function (t) { - glob('**/d', {cwd: process.cwd()}, function (er, matches) { - t.ifError(er) - t.like(matches, [ 'a/b/c/d', 'a/c/d' ]) - t.end() - }) - }) - - t.test('cd -', function (t) { - process.chdir(origCwd) - t.end() - }) - - t.end() -}) diff --git a/tests/mocha/node_modules/glob/test/globstar-match.js b/tests/mocha/node_modules/glob/test/globstar-match.js deleted file mode 100644 index 9b234fa2a8..0000000000 --- a/tests/mocha/node_modules/glob/test/globstar-match.js +++ /dev/null @@ -1,19 +0,0 @@ -var Glob = require("../glob.js").Glob -var test = require('tap').test - -test('globstar should not have dupe matches', function(t) { - var pattern = 'a/**/[gh]' - var g = new Glob(pattern, { cwd: __dirname }) - var matches = [] - g.on('match', function(m) { - console.error('match %j', m) - matches.push(m) - }) - g.on('end', function(set) { - console.error('set', set) - matches = matches.sort() - set = set.sort() - t.same(matches, set, 'should have same set of matches') - t.end() - }) -}) diff --git a/tests/mocha/node_modules/glob/test/mark.js b/tests/mocha/node_modules/glob/test/mark.js deleted file mode 100644 index ed68a335c3..0000000000 --- a/tests/mocha/node_modules/glob/test/mark.js +++ /dev/null @@ -1,74 +0,0 @@ -var test = require("tap").test -var glob = require('../') -process.chdir(__dirname) - -test("mark, no / on pattern", function (t) { - glob("a/*", {mark: true}, function (er, results) { - if (er) - throw er - var expect = [ 'a/abcdef/', - 'a/abcfed/', - 'a/b/', - 'a/bc/', - 'a/c/', - 'a/cb/' ] - - if (process.platform !== "win32") - expect.push('a/symlink/') - - t.same(results, expect) - t.end() - }) -}) - -test("mark=false, no / on pattern", function (t) { - glob("a/*", function (er, results) { - if (er) - throw er - var expect = [ 'a/abcdef', - 'a/abcfed', - 'a/b', - 'a/bc', - 'a/c', - 'a/cb' ] - - if (process.platform !== "win32") - expect.push('a/symlink') - t.same(results, expect) - t.end() - }) -}) - -test("mark=true, / on pattern", function (t) { - glob("a/*/", {mark: true}, function (er, results) { - if (er) - throw er - var expect = [ 'a/abcdef/', - 'a/abcfed/', - 'a/b/', - 'a/bc/', - 'a/c/', - 'a/cb/' ] - if (process.platform !== "win32") - expect.push('a/symlink/') - t.same(results, expect) - t.end() - }) -}) - -test("mark=false, / on pattern", function (t) { - glob("a/*/", function (er, results) { - if (er) - throw er - var expect = [ 'a/abcdef/', - 'a/abcfed/', - 'a/b/', - 'a/bc/', - 'a/c/', - 'a/cb/' ] - if (process.platform !== "win32") - expect.push('a/symlink/') - t.same(results, expect) - t.end() - }) -}) diff --git a/tests/mocha/node_modules/glob/test/nocase-nomagic.js b/tests/mocha/node_modules/glob/test/nocase-nomagic.js deleted file mode 100644 index d86297098d..0000000000 --- a/tests/mocha/node_modules/glob/test/nocase-nomagic.js +++ /dev/null @@ -1,113 +0,0 @@ -var fs = require('graceful-fs'); -var test = require('tap').test; -var glob = require('../'); - -test('mock fs', function(t) { - var stat = fs.stat - var statSync = fs.statSync - var readdir = fs.readdir - var readdirSync = fs.readdirSync - - function fakeStat(path) { - var ret - switch (path.toLowerCase()) { - case '/tmp': case '/tmp/': - ret = { isDirectory: function() { return true } } - break - case '/tmp/a': - ret = { isDirectory: function() { return false } } - break - } - return ret - } - - fs.stat = function(path, cb) { - var f = fakeStat(path); - if (f) { - process.nextTick(function() { - cb(null, f) - }) - } else { - stat.call(fs, path, cb) - } - } - - fs.statSync = function(path) { - return fakeStat(path) || statSync.call(fs, path) - } - - function fakeReaddir(path) { - var ret - switch (path.toLowerCase()) { - case '/tmp': case '/tmp/': - ret = [ 'a', 'A' ] - break - case '/': - ret = ['tmp', 'tMp', 'tMP', 'TMP'] - } - return ret - } - - fs.readdir = function(path, cb) { - var f = fakeReaddir(path) - if (f) - process.nextTick(function() { - cb(null, f) - }) - else - readdir.call(fs, path, cb) - } - - fs.readdirSync = function(path) { - return fakeReaddir(path) || readdirSync.call(fs, path) - } - - t.pass('mocked') - t.end() -}) - -test('nocase, nomagic', function(t) { - var n = 2 - var want = [ '/TMP/A', - '/TMP/a', - '/tMP/A', - '/tMP/a', - '/tMp/A', - '/tMp/a', - '/tmp/A', - '/tmp/a' ] - glob('/tmp/a', { nocase: true }, function(er, res) { - if (er) - throw er - t.same(res.sort(), want) - if (--n === 0) t.end() - }) - glob('/tmp/A', { nocase: true }, function(er, res) { - if (er) - throw er - t.same(res.sort(), want) - if (--n === 0) t.end() - }) -}) - -test('nocase, with some magic', function(t) { - t.plan(2) - var want = [ '/TMP/A', - '/TMP/a', - '/tMP/A', - '/tMP/a', - '/tMp/A', - '/tMp/a', - '/tmp/A', - '/tmp/a' ] - glob('/tmp/*', { nocase: true }, function(er, res) { - if (er) - throw er - t.same(res.sort(), want) - }) - glob('/tmp/*', { nocase: true }, function(er, res) { - if (er) - throw er - t.same(res.sort(), want) - }) -}) diff --git a/tests/mocha/node_modules/glob/test/pause-resume.js b/tests/mocha/node_modules/glob/test/pause-resume.js deleted file mode 100644 index e1ffbab1c5..0000000000 --- a/tests/mocha/node_modules/glob/test/pause-resume.js +++ /dev/null @@ -1,73 +0,0 @@ -// show that no match events happen while paused. -var tap = require("tap") -, child_process = require("child_process") -// just some gnarly pattern with lots of matches -, pattern = "test/a/!(symlink)/**" -, bashResults = require("./bash-results.json") -, patterns = Object.keys(bashResults) -, glob = require("../") -, Glob = glob.Glob -, path = require("path") - -// run from the root of the project -// this is usually where you're at anyway, but be sure. -process.chdir(path.resolve(__dirname, "..")) - -function alphasort (a, b) { - a = a.toLowerCase() - b = b.toLowerCase() - return a > b ? 1 : a < b ? -1 : 0 -} - -function cleanResults (m) { - // normalize discrepancies in ordering, duplication, - // and ending slashes. - return m.map(function (m) { - return m.replace(/\/+/g, "/").replace(/\/$/, "") - }).sort(alphasort).reduce(function (set, f) { - if (f !== set[set.length - 1]) set.push(f) - return set - }, []).sort(alphasort).map(function (f) { - // de-windows - return (process.platform !== 'win32') ? f - : f.replace(/^[a-zA-Z]:\\\\/, '/').replace(/\\/g, '/') - }) -} - -var globResults = [] -tap.test("use a Glob object, and pause/resume it", function (t) { - var g = new Glob(pattern) - , paused = false - , res = [] - , expect = bashResults[pattern] - - g.on("pause", function () { - console.error("pause") - }) - - g.on("resume", function () { - console.error("resume") - }) - - g.on("match", function (m) { - t.notOk(g.paused, "must not be paused") - globResults.push(m) - g.pause() - t.ok(g.paused, "must be paused") - setTimeout(g.resume.bind(g), 10) - }) - - g.on("end", function (matches) { - t.pass("reached glob end") - globResults = cleanResults(globResults) - matches = cleanResults(matches) - t.deepEqual(matches, globResults, - "end event matches should be the same as match events") - - t.deepEqual(matches, expect, - "glob matches should be the same as bash results") - - t.end() - }) -}) - diff --git a/tests/mocha/node_modules/glob/test/root-nomount.js b/tests/mocha/node_modules/glob/test/root-nomount.js deleted file mode 100644 index 3ac5979b05..0000000000 --- a/tests/mocha/node_modules/glob/test/root-nomount.js +++ /dev/null @@ -1,39 +0,0 @@ -var tap = require("tap") - -var origCwd = process.cwd() -process.chdir(__dirname) - -tap.test("changing root and searching for /b*/**", function (t) { - var glob = require('../') - var path = require('path') - t.test('.', function (t) { - glob('/b*/**', { globDebug: true, root: '.', nomount: true }, function (er, matches) { - t.ifError(er) - t.like(matches, []) - t.end() - }) - }) - - t.test('a', function (t) { - glob('/b*/**', { globDebug: true, root: path.resolve('a'), nomount: true }, function (er, matches) { - t.ifError(er) - t.like(matches, [ '/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f' ]) - t.end() - }) - }) - - t.test('root=a, cwd=a/b', function (t) { - glob('/b*/**', { globDebug: true, root: 'a', cwd: path.resolve('a/b'), nomount: true }, function (er, matches) { - t.ifError(er) - t.like(matches, [ '/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f' ]) - t.end() - }) - }) - - t.test('cd -', function (t) { - process.chdir(origCwd) - t.end() - }) - - t.end() -}) diff --git a/tests/mocha/node_modules/glob/test/root.js b/tests/mocha/node_modules/glob/test/root.js deleted file mode 100644 index 95c23f99ca..0000000000 --- a/tests/mocha/node_modules/glob/test/root.js +++ /dev/null @@ -1,46 +0,0 @@ -var t = require("tap") - -var origCwd = process.cwd() -process.chdir(__dirname) - -var glob = require('../') -var path = require('path') - -t.test('.', function (t) { - glob('/b*/**', { globDebug: true, root: '.' }, function (er, matches) { - t.ifError(er) - t.like(matches, []) - t.end() - }) -}) - - -t.test('a', function (t) { - console.error("root=" + path.resolve('a')) - glob('/b*/**', { globDebug: true, root: path.resolve('a') }, function (er, matches) { - t.ifError(er) - var wanted = [ - '/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f' - ].map(function (m) { - return path.join(path.resolve('a'), m).replace(/\\/g, '/') - }) - - t.like(matches, wanted) - t.end() - }) -}) - -t.test('root=a, cwd=a/b', function (t) { - glob('/b*/**', { globDebug: true, root: 'a', cwd: path.resolve('a/b') }, function (er, matches) { - t.ifError(er) - t.like(matches, [ '/b', '/b/c', '/b/c/d', '/bc', '/bc/e', '/bc/e/f' ].map(function (m) { - return path.join(path.resolve('a'), m).replace(/\\/g, '/') - })) - t.end() - }) -}) - -t.test('cd -', function (t) { - process.chdir(origCwd) - t.end() -}) diff --git a/tests/mocha/node_modules/glob/test/stat.js b/tests/mocha/node_modules/glob/test/stat.js deleted file mode 100644 index 62917114b4..0000000000 --- a/tests/mocha/node_modules/glob/test/stat.js +++ /dev/null @@ -1,32 +0,0 @@ -var glob = require('../') -var test = require('tap').test -var path = require('path') - -test('stat all the things', function(t) { - var g = new glob.Glob('a/*abc*/**', { stat: true, cwd: __dirname }) - var matches = [] - g.on('match', function(m) { - matches.push(m) - }) - var stats = [] - g.on('stat', function(m) { - stats.push(m) - }) - g.on('end', function(eof) { - stats = stats.sort() - matches = matches.sort() - eof = eof.sort() - t.same(stats, matches) - t.same(eof, matches) - var cache = Object.keys(this.statCache) - t.same(cache.map(function (f) { - return path.relative(__dirname, f) - }).sort(), matches) - - cache.forEach(function(c) { - t.equal(typeof this.statCache[c], 'object') - }, this) - - t.end() - }) -}) diff --git a/tests/mocha/node_modules/glob/test/zz-cleanup.js b/tests/mocha/node_modules/glob/test/zz-cleanup.js deleted file mode 100644 index e085f0fa77..0000000000 --- a/tests/mocha/node_modules/glob/test/zz-cleanup.js +++ /dev/null @@ -1,11 +0,0 @@ -// remove the fixtures -var tap = require("tap") -, rimraf = require("rimraf") -, path = require("path") - -tap.test("cleanup fixtures", function (t) { - rimraf(path.resolve(__dirname, "a"), function (er) { - t.ifError(er, "removed") - t.end() - }) -}) diff --git a/tests/mocha/node_modules/growl/History.md b/tests/mocha/node_modules/growl/History.md deleted file mode 100644 index a4b7b49f27..0000000000 --- a/tests/mocha/node_modules/growl/History.md +++ /dev/null @@ -1,63 +0,0 @@ - -1.7.0 / 2012-12-30 -================== - - * support transient notifications in Gnome - -1.6.1 / 2012-09-25 -================== - - * restore compatibility with node < 0.8 [fgnass] - -1.6.0 / 2012-09-06 -================== - - * add notification center support [drudge] - -1.5.1 / 2012-04-08 -================== - - * Merge pull request #16 from KyleAMathews/patch-1 - * Fixes #15 - -1.5.0 / 2012-02-08 -================== - - * Added windows support [perfusorius] - -1.4.1 / 2011-12-28 -================== - - * Fixed: dont exit(). Closes #9 - -1.4.0 / 2011-12-17 -================== - - * Changed API: `growl.notify()` -> `growl()` - -1.3.0 / 2011-12-17 -================== - - * Added support for Ubuntu/Debian/Linux users [niftylettuce] - * Fixed: send notifications even if title not specified [alessioalex] - -1.2.0 / 2011-10-06 -================== - - * Add support for priority. - -1.1.0 / 2011-03-15 -================== - - * Added optional callbacks - * Added parsing of version - -1.0.1 / 2010-03-26 -================== - - * Fixed; sys.exec -> child_process.exec to support latest node - -1.0.0 / 2010-03-19 -================== - - * Initial release diff --git a/tests/mocha/node_modules/growl/Readme.md b/tests/mocha/node_modules/growl/Readme.md deleted file mode 100644 index 48d717ccb3..0000000000 --- a/tests/mocha/node_modules/growl/Readme.md +++ /dev/null @@ -1,99 +0,0 @@ -# Growl for nodejs - -Growl support for Nodejs. This is essentially a port of my [Ruby Growl Library](http://github.com/visionmedia/growl). Ubuntu/Linux support added thanks to [@niftylettuce](http://github.com/niftylettuce). - -## Installation - -### Install - -### Mac OS X (Darwin): - - Install [growlnotify(1)](http://growl.info/extras.php#growlnotify). On OS X 10.8, Notification Center is supported using [terminal-notifier](https://github.com/alloy/terminal-notifier). To install: - - $ sudo gem install terminal-notifier - - Install [npm](http://npmjs.org/) and run: - - $ npm install growl - -### Ubuntu (Linux): - - Install `notify-send` through the [libnotify-bin](http://packages.ubuntu.com/libnotify-bin) package: - - $ sudo apt-get install libnotify-bin - - Install [npm](http://npmjs.org/) and run: - - $ npm install growl - -### Windows: - - Download and install [Growl for Windows](http://www.growlforwindows.com/gfw/default.aspx) - - Download [growlnotify](http://www.growlforwindows.com/gfw/help/growlnotify.aspx) - **IMPORTANT :** Unpack growlnotify to a folder that is present in your path! - - Install [npm](http://npmjs.org/) and run: - - $ npm install growl - -## Examples - -Callback functions are optional - - var growl = require('growl') - growl('You have mail!') - growl('5 new messages', { sticky: true }) - growl('5 new emails', { title: 'Email Client', image: 'Safari', sticky: true }) - growl('Message with title', { title: 'Title'}) - growl('Set priority', { priority: 2 }) - growl('Show Safari icon', { image: 'Safari' }) - growl('Show icon', { image: 'path/to/icon.icns' }) - growl('Show image', { image: 'path/to/my.image.png' }) - growl('Show png filesystem icon', { image: 'png' }) - growl('Show pdf filesystem icon', { image: 'article.pdf' }) - growl('Show pdf filesystem icon', { image: 'article.pdf' }, function(err){ - // ... notified - }) - -## Options - - - title - - notification title - - name - - application name - - priority - - priority for the notification (default is 0) - - sticky - - weither or not the notification should remainin until closed - - image - - Auto-detects the context: - - path to an icon sets --iconpath - - path to an image sets --image - - capitalized word sets --appIcon - - filename uses extname as --icon - - otherwise treated as --icon - -## License - -(The MIT License) - -Copyright (c) 2009 TJ Holowaychuk - -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 copies 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 all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, -EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 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. diff --git a/tests/mocha/node_modules/growl/lib/growl.js b/tests/mocha/node_modules/growl/lib/growl.js deleted file mode 100644 index 04f4f9b487..0000000000 --- a/tests/mocha/node_modules/growl/lib/growl.js +++ /dev/null @@ -1,234 +0,0 @@ -// Growl - Copyright TJ Holowaychuk (MIT Licensed) - -/** - * Module dependencies. - */ - -var exec = require('child_process').exec - , fs = require('fs') - , path = require('path') - , exists = fs.existsSync || path.existsSync - , os = require('os') - , quote = JSON.stringify - , cmd; - -function which(name) { - var paths = process.env.PATH.split(':'); - var loc; - - for (var i = 0, len = paths.length; i < len; ++i) { - loc = path.join(paths[i], name); - if (exists(loc)) return loc; - } -} - -switch(os.type()) { - case 'Darwin': - if (which('terminal-notifier')) { - cmd = { - type: "Darwin-NotificationCenter" - , pkg: "terminal-notifier" - , msg: '-message' - , title: '-title' - , subtitle: '-subtitle' - , priority: { - cmd: '-execute' - , range: [] - } - }; - } else { - cmd = { - type: "Darwin-Growl" - , pkg: "growlnotify" - , msg: '-m' - , sticky: '--sticky' - , priority: { - cmd: '--priority' - , range: [ - -2 - , -1 - , 0 - , 1 - , 2 - , "Very Low" - , "Moderate" - , "Normal" - , "High" - , "Emergency" - ] - } - }; - } - break; - case 'Linux': - cmd = { - type: "Linux" - , pkg: "notify-send" - , msg: '' - , sticky: '-t 0' - , icon: '-i' - , priority: { - cmd: '-u' - , range: [ - "low" - , "normal" - , "critical" - ] - } - }; - break; - case 'Windows_NT': - cmd = { - type: "Windows" - , pkg: "growlnotify" - , msg: '' - , sticky: '/s:true' - , title: '/t:' - , icon: '/i:' - , priority: { - cmd: '/p:' - , range: [ - -2 - , -1 - , 0 - , 1 - , 2 - ] - } - }; - break; -} - -/** - * Expose `growl`. - */ - -exports = module.exports = growl; - -/** - * Node-growl version. - */ - -exports.version = '1.4.1' - -/** - * Send growl notification _msg_ with _options_. - * - * Options: - * - * - title Notification title - * - sticky Make the notification stick (defaults to false) - * - priority Specify an int or named key (default is 0) - * - name Application name (defaults to growlnotify) - * - image - * - path to an icon sets --iconpath - * - path to an image sets --image - * - capitalized word sets --appIcon - * - filename uses extname as --icon - * - otherwise treated as --icon - * - * Examples: - * - * growl('New email') - * growl('5 new emails', { title: 'Thunderbird' }) - * growl('Email sent', function(){ - * // ... notification sent - * }) - * - * @param {string} msg - * @param {object} options - * @param {function} fn - * @api public - */ - -function growl(msg, options, fn) { - var image - , args - , options = options || {} - , fn = fn || function(){}; - - // noop - if (!cmd) return fn(new Error('growl not supported on this platform')); - args = [cmd.pkg]; - - // image - if (image = options.image) { - switch(cmd.type) { - case 'Darwin-Growl': - var flag, ext = path.extname(image).substr(1) - flag = flag || ext == 'icns' && 'iconpath' - flag = flag || /^[A-Z]/.test(image) && 'appIcon' - flag = flag || /^png|gif|jpe?g$/.test(ext) && 'image' - flag = flag || ext && (image = ext) && 'icon' - flag = flag || 'icon' - args.push('--' + flag, image) - break; - case 'Linux': - args.push(cmd.icon + " " + image); - // libnotify defaults to sticky, set a hint for transient notifications - if (!options.sticky) args.push('--hint=int:transient:1'); - break; - case 'Windows': - args.push(cmd.icon + quote(image)); - break; - } - } - - // sticky - if (options.sticky) args.push(cmd.sticky); - - // priority - if (options.priority) { - var priority = options.priority + ''; - var checkindexOf = cmd.priority.range.indexOf(priority); - if (~cmd.priority.range.indexOf(priority)) { - args.push(cmd.priority, options.priority); - } - } - - // name - if (options.name && cmd.type === "Darwin-Growl") { - args.push('--name', options.name); - } - - switch(cmd.type) { - case 'Darwin-Growl': - args.push(cmd.msg); - args.push(quote(msg)); - if (options.title) args.push(quote(options.title)); - break; - case 'Darwin-NotificationCenter': - args.push(cmd.msg); - args.push(quote(msg)); - if (options.title) { - args.push(cmd.title); - args.push(quote(options.title)); - } - if (options.subtitle) { - args.push(cmd.subtitle); - args.push(quote(options.title)); - } - break; - case 'Darwin-Growl': - args.push(cmd.msg); - args.push(quote(msg)); - if (options.title) args.push(quote(options.title)); - break; - case 'Linux': - if (options.title) { - args.push(quote(options.title)); - args.push(cmd.msg); - args.push(quote(msg)); - } else { - args.push(quote(msg)); - } - break; - case 'Windows': - args.push(quote(msg)); - if (options.title) args.push(cmd.title + quote(options.title)); - break; - } - - // execute - exec(args.join(' '), fn); -}; diff --git a/tests/mocha/node_modules/growl/package.json b/tests/mocha/node_modules/growl/package.json deleted file mode 100644 index 6565e46de6..0000000000 --- a/tests/mocha/node_modules/growl/package.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "name": "growl", - "version": "1.7.0", - "description": "Growl unobtrusive notifications", - "author": { - "name": "TJ Holowaychuk", - "email": "tj@vision-media.ca" - }, - "main": "./lib/growl.js", - "readme": "# Growl for nodejs\n\nGrowl support for Nodejs. This is essentially a port of my [Ruby Growl Library](http://github.com/visionmedia/growl). Ubuntu/Linux support added thanks to [@niftylettuce](http://github.com/niftylettuce). \n\n## Installation\n\n### Install \n\n### Mac OS X (Darwin):\n\n Install [growlnotify(1)](http://growl.info/extras.php#growlnotify). On OS X 10.8, Notification Center is supported using [terminal-notifier](https://github.com/alloy/terminal-notifier). To install:\n \n $ sudo gem install terminal-notifier\n \n Install [npm](http://npmjs.org/) and run:\n \n $ npm install growl\n\n### Ubuntu (Linux):\n\n Install `notify-send` through the [libnotify-bin](http://packages.ubuntu.com/libnotify-bin) package:\n\n $ sudo apt-get install libnotify-bin\n\n Install [npm](http://npmjs.org/) and run:\n \n $ npm install growl\n\n### Windows:\n\n Download and install [Growl for Windows](http://www.growlforwindows.com/gfw/default.aspx)\n\n Download [growlnotify](http://www.growlforwindows.com/gfw/help/growlnotify.aspx) - **IMPORTANT :** Unpack growlnotify to a folder that is present in your path!\n\n Install [npm](http://npmjs.org/) and run:\n \n $ npm install growl\n\n## Examples\n\nCallback functions are optional\n\n var growl = require('growl')\n growl('You have mail!')\n growl('5 new messages', { sticky: true })\n growl('5 new emails', { title: 'Email Client', image: 'Safari', sticky: true })\n growl('Message with title', { title: 'Title'})\n growl('Set priority', { priority: 2 })\n growl('Show Safari icon', { image: 'Safari' })\n growl('Show icon', { image: 'path/to/icon.icns' })\n growl('Show image', { image: 'path/to/my.image.png' })\n growl('Show png filesystem icon', { image: 'png' })\n growl('Show pdf filesystem icon', { image: 'article.pdf' })\n growl('Show pdf filesystem icon', { image: 'article.pdf' }, function(err){\n // ... notified\n })\n\n## Options\n\n - title\n - notification title\n - name\n - application name\n - priority\n - priority for the notification (default is 0)\n - sticky\n - weither or not the notification should remainin until closed\n - image\n - Auto-detects the context:\n - path to an icon sets --iconpath\n - path to an image sets --image\n - capitalized word sets --appIcon\n - filename uses extname as --icon\n - otherwise treated as --icon\n \n## License \n\n(The MIT License)\n\nCopyright (c) 2009 TJ Holowaychuk \n\nPermission is hereby granted, free of charge, to any person obtaining\na copy of this software and associated documentation files (the\n'Software'), to deal in the Software without restriction, including\nwithout limitation the rights to use, copy, modify, merge, publish,\ndistribute, sublicense, and/or sell copies of the Software, and to\npermit persons to whom the Software is furnished to do so, subject to\nthe following conditions:\n\nThe above copyright notice and this permission notice shall be\nincluded in all copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,\nEXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF\nMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.\nIN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY\nCLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,\nTORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE\nSOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.\n", - "readmeFilename": "Readme.md", - "_id": "growl@1.7.0", - "_from": "growl@1.7.x" -} diff --git a/tests/mocha/node_modules/growl/test.js b/tests/mocha/node_modules/growl/test.js deleted file mode 100644 index cf22d90b2c..0000000000 --- a/tests/mocha/node_modules/growl/test.js +++ /dev/null @@ -1,20 +0,0 @@ - -var growl = require('./lib/growl') - -growl('You have mail!') -growl('5 new messages', { sticky: true }) -growl('5 new emails', { title: 'Email Client', image: 'Safari', sticky: true }) -growl('Message with title', { title: 'Title'}) -growl('Set priority', { priority: 2 }) -growl('Show Safari icon', { image: 'Safari' }) -growl('Show icon', { image: 'path/to/icon.icns' }) -growl('Show image', { image: 'path/to/my.image.png' }) -growl('Show png filesystem icon', { image: 'png' }) -growl('Show pdf filesystem icon', { image: 'article.pdf' }) -growl('Show pdf filesystem icon', { image: 'article.pdf' }, function(){ - console.log('callback'); -}) -growl('Show pdf filesystem icon', { title: 'Use show()', image: 'article.pdf' }) -growl('here \' are \n some \\ characters that " need escaping', {}, function(error, stdout, stderr) { - if (error !== null) throw new Error('escaping failed:\n' + stdout + stderr); -}) diff --git a/tests/mocha/node_modules/mkdirp/.npmignore b/tests/mocha/node_modules/mkdirp/.npmignore deleted file mode 100644 index 9303c347ee..0000000000 --- a/tests/mocha/node_modules/mkdirp/.npmignore +++ /dev/null @@ -1,2 +0,0 @@ -node_modules/ -npm-debug.log \ No newline at end of file diff --git a/tests/mocha/node_modules/mkdirp/.travis.yml b/tests/mocha/node_modules/mkdirp/.travis.yml deleted file mode 100644 index 84fd7ca248..0000000000 --- a/tests/mocha/node_modules/mkdirp/.travis.yml +++ /dev/null @@ -1,5 +0,0 @@ -language: node_js -node_js: - - 0.6 - - 0.8 - - 0.9 diff --git a/tests/mocha/node_modules/mkdirp/LICENSE b/tests/mocha/node_modules/mkdirp/LICENSE deleted file mode 100644 index 432d1aeb01..0000000000 --- a/tests/mocha/node_modules/mkdirp/LICENSE +++ /dev/null @@ -1,21 +0,0 @@ -Copyright 2010 James Halliday (mail@substack.net) - -This project is free software released under the MIT/X11 license: - -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 -copies 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 -all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER 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. diff --git a/tests/mocha/node_modules/mkdirp/examples/pow.js b/tests/mocha/node_modules/mkdirp/examples/pow.js deleted file mode 100644 index e6924212e6..0000000000 --- a/tests/mocha/node_modules/mkdirp/examples/pow.js +++ /dev/null @@ -1,6 +0,0 @@ -var mkdirp = require('mkdirp'); - -mkdirp('/tmp/foo/bar/baz', function (err) { - if (err) console.error(err) - else console.log('pow!') -}); diff --git a/tests/mocha/node_modules/mkdirp/index.js b/tests/mocha/node_modules/mkdirp/index.js deleted file mode 100644 index fda6de8a2c..0000000000 --- a/tests/mocha/node_modules/mkdirp/index.js +++ /dev/null @@ -1,82 +0,0 @@ -var path = require('path'); -var fs = require('fs'); - -module.exports = mkdirP.mkdirp = mkdirP.mkdirP = mkdirP; - -function mkdirP (p, mode, f, made) { - if (typeof mode === 'function' || mode === undefined) { - f = mode; - mode = 0777 & (~process.umask()); - } - if (!made) made = null; - - var cb = f || function () {}; - if (typeof mode === 'string') mode = parseInt(mode, 8); - p = path.resolve(p); - - fs.mkdir(p, mode, function (er) { - if (!er) { - made = made || p; - return cb(null, made); - } - switch (er.code) { - case 'ENOENT': - mkdirP(path.dirname(p), mode, function (er, made) { - if (er) cb(er, made); - else mkdirP(p, mode, cb, made); - }); - break; - - // In the case of any other error, just see if there's a dir - // there already. If so, then hooray! If not, then something - // is borked. - default: - fs.stat(p, function (er2, stat) { - // if the stat fails, then that's super weird. - // let the original error be the failure reason. - if (er2 || !stat.isDirectory()) cb(er, made) - else cb(null, made); - }); - break; - } - }); -} - -mkdirP.sync = function sync (p, mode, made) { - if (mode === undefined) { - mode = 0777 & (~process.umask()); - } - if (!made) made = null; - - if (typeof mode === 'string') mode = parseInt(mode, 8); - p = path.resolve(p); - - try { - fs.mkdirSync(p, mode); - made = made || p; - } - catch (err0) { - switch (err0.code) { - case 'ENOENT' : - made = sync(path.dirname(p), mode, made); - sync(p, mode, made); - break; - - // In the case of any other error, just see if there's a dir - // there already. If so, then hooray! If not, then something - // is borked. - default: - var stat; - try { - stat = fs.statSync(p); - } - catch (err1) { - throw err0; - } - if (!stat.isDirectory()) throw err0; - break; - } - } - - return made; -}; diff --git a/tests/mocha/node_modules/mkdirp/package.json b/tests/mocha/node_modules/mkdirp/package.json deleted file mode 100644 index a71d8b77a9..0000000000 --- a/tests/mocha/node_modules/mkdirp/package.json +++ /dev/null @@ -1,34 +0,0 @@ -{ - "name": "mkdirp", - "description": "Recursively mkdir, like `mkdir -p`", - "version": "0.3.5", - "author": { - "name": "James Halliday", - "email": "mail@substack.net", - "url": "http://substack.net" - }, - "main": "./index", - "keywords": [ - "mkdir", - "directory" - ], - "repository": { - "type": "git", - "url": "http://github.com/substack/node-mkdirp.git" - }, - "scripts": { - "test": "tap test/*.js" - }, - "devDependencies": { - "tap": "~0.4.0" - }, - "license": "MIT", - "readme": "# mkdirp\n\nLike `mkdir -p`, but in node.js!\n\n[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp)\n\n# example\n\n## pow.js\n\n```js\nvar mkdirp = require('mkdirp');\n \nmkdirp('/tmp/foo/bar/baz', function (err) {\n if (err) console.error(err)\n else console.log('pow!')\n});\n```\n\nOutput\n\n```\npow!\n```\n\nAnd now /tmp/foo/bar/baz exists, huzzah!\n\n# methods\n\n```js\nvar mkdirp = require('mkdirp');\n```\n\n## mkdirp(dir, mode, cb)\n\nCreate a new directory and any necessary subdirectories at `dir` with octal\npermission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\n`cb(err, made)` fires with the error or the first directory `made`\nthat had to be created, if any.\n\n## mkdirp.sync(dir, mode)\n\nSynchronously create a new directory and any necessary subdirectories at `dir`\nwith octal permission string `mode`.\n\nIf `mode` isn't specified, it defaults to `0777 & (~process.umask())`.\n\nReturns the first directory that had to be created, if any.\n\n# install\n\nWith [npm](http://npmjs.org) do:\n\n```\nnpm install mkdirp\n```\n\n# license\n\nMIT\n", - "readmeFilename": "readme.markdown", - "bugs": { - "url": "https://github.com/substack/node-mkdirp/issues" - }, - "homepage": "https://github.com/substack/node-mkdirp", - "_id": "mkdirp@0.3.5", - "_from": "mkdirp@0.3.5" -} diff --git a/tests/mocha/node_modules/mkdirp/readme.markdown b/tests/mocha/node_modules/mkdirp/readme.markdown deleted file mode 100644 index 83b0216ab5..0000000000 --- a/tests/mocha/node_modules/mkdirp/readme.markdown +++ /dev/null @@ -1,63 +0,0 @@ -# mkdirp - -Like `mkdir -p`, but in node.js! - -[![build status](https://secure.travis-ci.org/substack/node-mkdirp.png)](http://travis-ci.org/substack/node-mkdirp) - -# example - -## pow.js - -```js -var mkdirp = require('mkdirp'); - -mkdirp('/tmp/foo/bar/baz', function (err) { - if (err) console.error(err) - else console.log('pow!') -}); -``` - -Output - -``` -pow! -``` - -And now /tmp/foo/bar/baz exists, huzzah! - -# methods - -```js -var mkdirp = require('mkdirp'); -``` - -## mkdirp(dir, mode, cb) - -Create a new directory and any necessary subdirectories at `dir` with octal -permission string `mode`. - -If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. - -`cb(err, made)` fires with the error or the first directory `made` -that had to be created, if any. - -## mkdirp.sync(dir, mode) - -Synchronously create a new directory and any necessary subdirectories at `dir` -with octal permission string `mode`. - -If `mode` isn't specified, it defaults to `0777 & (~process.umask())`. - -Returns the first directory that had to be created, if any. - -# install - -With [npm](http://npmjs.org) do: - -``` -npm install mkdirp -``` - -# license - -MIT diff --git a/tests/mocha/node_modules/mkdirp/test/chmod.js b/tests/mocha/node_modules/mkdirp/test/chmod.js deleted file mode 100644 index 520dcb8e9b..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/chmod.js +++ /dev/null @@ -1,38 +0,0 @@ -var mkdirp = require('../').mkdirp; -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -var ps = [ '', 'tmp' ]; - -for (var i = 0; i < 25; i++) { - var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); - ps.push(dir); -} - -var file = ps.join('/'); - -test('chmod-pre', function (t) { - var mode = 0744 - mkdirp(file, mode, function (er) { - t.ifError(er, 'should not error'); - fs.stat(file, function (er, stat) { - t.ifError(er, 'should exist'); - t.ok(stat && stat.isDirectory(), 'should be directory'); - t.equal(stat && stat.mode & 0777, mode, 'should be 0744'); - t.end(); - }); - }); -}); - -test('chmod', function (t) { - var mode = 0755 - mkdirp(file, mode, function (er) { - t.ifError(er, 'should not error'); - fs.stat(file, function (er, stat) { - t.ifError(er, 'should exist'); - t.ok(stat && stat.isDirectory(), 'should be directory'); - t.end(); - }); - }); -}); diff --git a/tests/mocha/node_modules/mkdirp/test/clobber.js b/tests/mocha/node_modules/mkdirp/test/clobber.js deleted file mode 100644 index 0eb7099870..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/clobber.js +++ /dev/null @@ -1,37 +0,0 @@ -var mkdirp = require('../').mkdirp; -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -var ps = [ '', 'tmp' ]; - -for (var i = 0; i < 25; i++) { - var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); - ps.push(dir); -} - -var file = ps.join('/'); - -// a file in the way -var itw = ps.slice(0, 3).join('/'); - - -test('clobber-pre', function (t) { - console.error("about to write to "+itw) - fs.writeFileSync(itw, 'I AM IN THE WAY, THE TRUTH, AND THE LIGHT.'); - - fs.stat(itw, function (er, stat) { - t.ifError(er) - t.ok(stat && stat.isFile(), 'should be file') - t.end() - }) -}) - -test('clobber', function (t) { - t.plan(2); - mkdirp(file, 0755, function (err) { - t.ok(err); - t.equal(err.code, 'ENOTDIR'); - t.end(); - }); -}); diff --git a/tests/mocha/node_modules/mkdirp/test/mkdirp.js b/tests/mocha/node_modules/mkdirp/test/mkdirp.js deleted file mode 100644 index b07cd70c10..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/mkdirp.js +++ /dev/null @@ -1,28 +0,0 @@ -var mkdirp = require('../'); -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -test('woo', function (t) { - t.plan(2); - 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 file = '/tmp/' + [x,y,z].join('/'); - - mkdirp(file, 0755, function (err) { - if (err) t.fail(err); - else path.exists(file, function (ex) { - if (!ex) t.fail('file not created') - else fs.stat(file, function (err, stat) { - if (err) t.fail(err) - else { - t.equal(stat.mode & 0777, 0755); - t.ok(stat.isDirectory(), 'target not a directory'); - t.end(); - } - }) - }) - }); -}); diff --git a/tests/mocha/node_modules/mkdirp/test/perm.js b/tests/mocha/node_modules/mkdirp/test/perm.js deleted file mode 100644 index 23a7abbd23..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/perm.js +++ /dev/null @@ -1,32 +0,0 @@ -var mkdirp = require('../'); -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -test('async perm', function (t) { - t.plan(2); - var file = '/tmp/' + (Math.random() * (1<<30)).toString(16); - - mkdirp(file, 0755, function (err) { - if (err) t.fail(err); - else path.exists(file, function (ex) { - if (!ex) t.fail('file not created') - else fs.stat(file, function (err, stat) { - if (err) t.fail(err) - else { - t.equal(stat.mode & 0777, 0755); - t.ok(stat.isDirectory(), 'target not a directory'); - t.end(); - } - }) - }) - }); -}); - -test('async root perm', function (t) { - mkdirp('/tmp', 0755, function (err) { - if (err) t.fail(err); - t.end(); - }); - t.end(); -}); diff --git a/tests/mocha/node_modules/mkdirp/test/perm_sync.js b/tests/mocha/node_modules/mkdirp/test/perm_sync.js deleted file mode 100644 index f685f60906..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/perm_sync.js +++ /dev/null @@ -1,39 +0,0 @@ -var mkdirp = require('../'); -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -test('sync perm', function (t) { - t.plan(2); - var file = '/tmp/' + (Math.random() * (1<<30)).toString(16) + '.json'; - - mkdirp.sync(file, 0755); - path.exists(file, function (ex) { - if (!ex) t.fail('file not created') - else fs.stat(file, function (err, stat) { - if (err) t.fail(err) - else { - t.equal(stat.mode & 0777, 0755); - t.ok(stat.isDirectory(), 'target not a directory'); - t.end(); - } - }) - }); -}); - -test('sync root perm', function (t) { - t.plan(1); - - var file = '/tmp'; - mkdirp.sync(file, 0755); - path.exists(file, function (ex) { - if (!ex) t.fail('file not created') - else fs.stat(file, function (err, stat) { - if (err) t.fail(err) - else { - t.ok(stat.isDirectory(), 'target not a directory'); - t.end(); - } - }) - }); -}); diff --git a/tests/mocha/node_modules/mkdirp/test/race.js b/tests/mocha/node_modules/mkdirp/test/race.js deleted file mode 100644 index 96a0447636..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/race.js +++ /dev/null @@ -1,41 +0,0 @@ -var mkdirp = require('../').mkdirp; -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -test('race', function (t) { - t.plan(4); - var ps = [ '', 'tmp' ]; - - for (var i = 0; i < 25; i++) { - var dir = Math.floor(Math.random() * Math.pow(16,4)).toString(16); - ps.push(dir); - } - var file = ps.join('/'); - - var res = 2; - mk(file, function () { - if (--res === 0) t.end(); - }); - - mk(file, function () { - if (--res === 0) t.end(); - }); - - function mk (file, cb) { - mkdirp(file, 0755, function (err) { - if (err) t.fail(err); - else path.exists(file, function (ex) { - if (!ex) t.fail('file not created') - else fs.stat(file, function (err, stat) { - if (err) t.fail(err) - else { - t.equal(stat.mode & 0777, 0755); - t.ok(stat.isDirectory(), 'target not a directory'); - if (cb) cb(); - } - }) - }) - }); - } -}); diff --git a/tests/mocha/node_modules/mkdirp/test/rel.js b/tests/mocha/node_modules/mkdirp/test/rel.js deleted file mode 100644 index 79858243ab..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/rel.js +++ /dev/null @@ -1,32 +0,0 @@ -var mkdirp = require('../'); -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -test('rel', function (t) { - t.plan(2); - 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) { - if (err) t.fail(err); - else path.exists(file, function (ex) { - if (!ex) t.fail('file not created') - else fs.stat(file, function (err, stat) { - if (err) t.fail(err) - else { - process.chdir(cwd); - t.equal(stat.mode & 0777, 0755); - t.ok(stat.isDirectory(), 'target not a directory'); - t.end(); - } - }) - }) - }); -}); diff --git a/tests/mocha/node_modules/mkdirp/test/return.js b/tests/mocha/node_modules/mkdirp/test/return.js deleted file mode 100644 index bce68e5613..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/return.js +++ /dev/null @@ -1,25 +0,0 @@ -var mkdirp = require('../'); -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -test('return value', function (t) { - t.plan(4); - 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 file = '/tmp/' + [x,y,z].join('/'); - - // should return the first dir created. - // By this point, it would be profoundly surprising if /tmp didn't - // already exist, since every other test makes things in there. - mkdirp(file, function (err, made) { - t.ifError(err); - t.equal(made, '/tmp/' + x); - mkdirp(file, function (err, made) { - t.ifError(err); - t.equal(made, null); - }); - }); -}); diff --git a/tests/mocha/node_modules/mkdirp/test/return_sync.js b/tests/mocha/node_modules/mkdirp/test/return_sync.js deleted file mode 100644 index 7c222d3558..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/return_sync.js +++ /dev/null @@ -1,24 +0,0 @@ -var mkdirp = require('../'); -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -test('return value', function (t) { - t.plan(2); - 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 file = '/tmp/' + [x,y,z].join('/'); - - // should return the first dir created. - // By this point, it would be profoundly surprising if /tmp didn't - // already exist, since every other test makes things in there. - // Note that this will throw on failure, which will fail the test. - var made = mkdirp.sync(file); - t.equal(made, '/tmp/' + x); - - // making the same file again should have no effect. - made = mkdirp.sync(file); - t.equal(made, null); -}); diff --git a/tests/mocha/node_modules/mkdirp/test/root.js b/tests/mocha/node_modules/mkdirp/test/root.js deleted file mode 100644 index 97ad7a2f35..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/root.js +++ /dev/null @@ -1,18 +0,0 @@ -var mkdirp = require('../'); -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -test('root', function (t) { - // '/' on unix, 'c:/' on windows. - var file = path.resolve('/'); - - mkdirp(file, 0755, function (err) { - if (err) throw err - fs.stat(file, function (er, stat) { - if (er) throw er - t.ok(stat.isDirectory(), 'target is a directory'); - t.end(); - }) - }); -}); diff --git a/tests/mocha/node_modules/mkdirp/test/sync.js b/tests/mocha/node_modules/mkdirp/test/sync.js deleted file mode 100644 index 7530cada84..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/sync.js +++ /dev/null @@ -1,32 +0,0 @@ -var mkdirp = require('../'); -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -test('sync', function (t) { - t.plan(2); - 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 file = '/tmp/' + [x,y,z].join('/'); - - try { - mkdirp.sync(file, 0755); - } catch (err) { - t.fail(err); - return t.end(); - } - - path.exists(file, function (ex) { - if (!ex) t.fail('file not created') - else fs.stat(file, function (err, stat) { - if (err) t.fail(err) - else { - t.equal(stat.mode & 0777, 0755); - t.ok(stat.isDirectory(), 'target not a directory'); - t.end(); - } - }); - }); -}); diff --git a/tests/mocha/node_modules/mkdirp/test/umask.js b/tests/mocha/node_modules/mkdirp/test/umask.js deleted file mode 100644 index 64ccafe22b..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/umask.js +++ /dev/null @@ -1,28 +0,0 @@ -var mkdirp = require('../'); -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -test('implicit mode from umask', function (t) { - t.plan(2); - 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 file = '/tmp/' + [x,y,z].join('/'); - - mkdirp(file, function (err) { - if (err) t.fail(err); - else path.exists(file, function (ex) { - if (!ex) t.fail('file not created') - else fs.stat(file, function (err, stat) { - if (err) t.fail(err) - else { - t.equal(stat.mode & 0777, 0777 & (~process.umask())); - t.ok(stat.isDirectory(), 'target not a directory'); - t.end(); - } - }) - }) - }); -}); diff --git a/tests/mocha/node_modules/mkdirp/test/umask_sync.js b/tests/mocha/node_modules/mkdirp/test/umask_sync.js deleted file mode 100644 index 35bd5cbbf4..0000000000 --- a/tests/mocha/node_modules/mkdirp/test/umask_sync.js +++ /dev/null @@ -1,32 +0,0 @@ -var mkdirp = require('../'); -var path = require('path'); -var fs = require('fs'); -var test = require('tap').test; - -test('umask sync modes', function (t) { - t.plan(2); - 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 file = '/tmp/' + [x,y,z].join('/'); - - try { - mkdirp.sync(file); - } catch (err) { - t.fail(err); - return t.end(); - } - - path.exists(file, function (ex) { - if (!ex) t.fail('file not created') - else fs.stat(file, function (err, stat) { - if (err) t.fail(err) - else { - t.equal(stat.mode & 0777, (0777 & (~process.umask()))); - t.ok(stat.isDirectory(), 'target not a directory'); - t.end(); - } - }); - }); -}); diff --git a/tests/mocha/package.json b/tests/mocha/package.json deleted file mode 100644 index 4328f9178c..0000000000 --- a/tests/mocha/package.json +++ /dev/null @@ -1,60 +0,0 @@ -{ - "name": "mocha", - "version": "1.18.2", - "description": "simple, flexible, fun test framework", - "keywords": [ - "mocha", - "test", - "bdd", - "tdd", - "tap" - ], - "author": { - "name": "TJ Holowaychuk", - "email": "tj@vision-media.ca" - }, - "repository": { - "type": "git", - "url": "git://github.com/visionmedia/mocha.git" - }, - "main": "./index", - "bin": { - "mocha": "./bin/mocha", - "_mocha": "./bin/_mocha" - }, - "engines": { - "node": ">= 0.4.x" - }, - "scripts": { - "test": "make test-all" - }, - "dependencies": { - "commander": "2.0.0", - "growl": "1.7.x", - "jade": "0.26.3", - "diff": "1.0.7", - "debug": "*", - "mkdirp": "0.3.5", - "glob": "3.2.3" - }, - "devDependencies": { - "should": ">= 2.0.x", - "coffee-script": "1.2" - }, - "files": [ - "bin", - "images", - "lib", - "index.js", - "mocha.css", - "mocha.js" - ], - "readme": " [![Build Status](https://secure.travis-ci.org/visionmedia/mocha.png)](http://travis-ci.org/visionmedia/mocha)\n\n [![Mocha test framework](http://f.cl.ly/items/3l1k0n2A1U3M1I1L210p/Screen%20Shot%202012-02-24%20at%202.21.43%20PM.png)](http://visionmedia.github.io/mocha)\n\n Mocha is a simple, flexible, fun JavaScript test framework for node.js and the browser. For more information view the [documentation](http://visionmedia.github.io/mocha).\n\n## Contributors\n\n```\n\n project : mocha\n repo age : 2 years, 4 months ago\n commits : 1314\n active : 372 days\n files : 141\n authors :\n 582 TJ Holowaychuk 44.3%\n 389 Tj Holowaychuk 29.6%\n 46 Travis Jeffery 3.5%\n 31 Guillermo Rauch 2.4%\n 13 Attila Domokos 1.0%\n 10 John Firebaugh 0.8%\n 8 Jo Liss 0.6%\n 7 Nathan Rajlich 0.5%\n 6 Mike Pennisi 0.5%\n 6 James Carr 0.5%\n 6 Brendan Nee 0.5%\n 5 Aaron Heckmann 0.4%\n 5 Ryunosuke SATO 0.4%\n 4 hokaccha 0.3%\n 4 Joshua Krall 0.3%\n 4 Xavier Antoviaque 0.3%\n 3 Jesse Dailey 0.2%\n 3 Forbes Lindesay 0.2%\n 3 Sindre Sorhus 0.2%\n 3 Cory Thomas 0.2%\n 3 Fredrik Enestad 0.2%\n 3 Ben Lindsey 0.2%\n 3 Tyson Tate 0.2%\n 3 Mathieu Desvé 0.2%\n 3 Valentin Agachi 0.2%\n 3 Wil Moore III 0.2%\n 3 Merrick Christensen 0.2%\n 3 eiji.ienaga 0.2%\n 3 fool2fish 0.2%\n 3 Nathan Bowser 0.2%\n 3 Paul Miller 0.2%\n 2 Juzer Ali 0.2%\n 2 Pete Hawkins 0.2%\n 2 Jonas Westerlund 0.2%\n 2 Arian Stolwijk 0.2%\n 2 Quang Van 0.2%\n 2 Glen Mailer 0.2%\n 2 Justin DuJardin 0.2%\n 2 FARKAS Máté 0.2%\n 2 Raynos 0.2%\n 2 Michael Riley 0.2%\n 2 Michael Schoonmaker 0.2%\n 2 Domenic Denicola 0.2%\n 2 Simon Gaeremynck 0.2%\n 2 Konstantin Käfer 0.2%\n 2 domenic 0.2%\n 2 Paul Armstrong 0.2%\n 2 fcrisci 0.2%\n 2 Alexander Early 0.2%\n 2 Shawn Krisman 0.2%\n 2 Brian Beck 0.2%\n 2 Nathan Alderson 0.2%\n 2 David Henderson 0.2%\n 2 Timo Tijhof 0.2%\n 2 Ian Storm Taylor 0.2%\n 2 travis jeffery 0.2%\n 1 Matt Smith 0.1%\n 1 Matthew Shanley 0.1%\n 1 Nathan Black 0.1%\n 1 Phil Sung 0.1%\n 1 R56 0.1%\n 1 Refael Ackermann 0.1%\n 1 Richard Dingwall 0.1%\n 1 Romain Prieto 0.1%\n 1 Roman Neuhauser 0.1%\n 1 Roman Shtylman 0.1%\n 1 Russ Bradberry 0.1%\n 1 Russell Munson 0.1%\n 1 Rustem Mustafin 0.1%\n 1 Salehen Shovon Rahman 0.1%\n 1 Sasha Koss 0.1%\n 1 Seiya Konno 0.1%\n 1 Simon Goumaz 0.1%\n 1 Standa Opichal 0.1%\n 1 Stephen Mathieson 0.1%\n 1 Steve Mason 0.1%\n 1 Tapiwa Kelvin 0.1%\n 1 Teddy Zeenny 0.1%\n 1 Tim Ehat 0.1%\n 1 Vadim Nikitin 0.1%\n 1 Victor Costan 0.1%\n 1 Will Langstroth 0.1%\n 1 Yanis Wang 0.1%\n 1 Yuest Wang 0.1%\n 1 abrkn 0.1%\n 1 airportyh 0.1%\n 1 badunk 0.1%\n 1 fengmk2 0.1%\n 1 grasGendarme 0.1%\n 1 lodr 0.1%\n 1 tgautier@yahoo.com 0.1%\n 1 traleig1 0.1%\n 1 vlad 0.1%\n 1 yuitest 0.1%\n 1 Adam Crabtree 0.1%\n 1 Andreas Brekken 0.1%\n 1 Andreas Lind Petersen 0.1%\n 1 Andrew Nesbitt 0.1%\n 1 Andrey Popp 0.1%\n 1 Arnaud Brousseau 0.1%\n 1 Atsuya Takagi 0.1%\n 1 Austin Birch 0.1%\n 1 Bjørge Næss 0.1%\n 1 Brian Lalor 0.1%\n 1 Brian M. Carlson 0.1%\n 1 Brian Moore 0.1%\n 1 Bryan Donovan 0.1%\n 1 Casey Foster 0.1%\n 1 ChrisWren 0.1%\n 1 Corey Butler 0.1%\n 1 Daniel Stockman 0.1%\n 1 Dave McKenna 0.1%\n 1 Di Wu 0.1%\n 1 Dmitry Shirokov 0.1%\n 1 Fedor Indutny 0.1%\n 1 Florian Margaine 0.1%\n 1 Frederico Silva 0.1%\n 1 Fredrik Lindin 0.1%\n 1 Gareth Murphy 0.1%\n 1 Gavin Mogan 0.1%\n 1 Glen Huang 0.1%\n 1 Greg Perkins 0.1%\n 1 Harry Brundage 0.1%\n 1 Herman Junge 0.1%\n 1 Ian Young 0.1%\n 1 Ivan 0.1%\n 1 JP Bochi 0.1%\n 1 Jaakko Salonen 0.1%\n 1 Jakub Nešetřil 0.1%\n 1 James Bowes 0.1%\n 1 James Lal 0.1%\n 1 Jason Barry 0.1%\n 1 Javier Aranda 0.1%\n 1 Jeff Kunkle 0.1%\n 1 Jeremy Martin 0.1%\n 1 Jimmy Cuadra 0.1%\n 1 Jonathan Creamer 0.1%\n 1 Jussi Virtanen 0.1%\n 1 Katie Gengler 0.1%\n 1 Kazuhito Hokamura 0.1%\n 1 Kirill Korolyov 0.1%\n 1 Koen Punt 0.1%\n 1 Laszlo Bacsi 0.1%\n 1 Liam Newman 0.1%\n 1 László Bácsi 0.1%\n 1 Maciej Małecki 0.1%\n 1 Mal Graty 0.1%\n 1 Marc Kuo 0.1%\n 1 Matt Robenolt 0.1%\n```\n\n## Links\n\n - [Google Group](http://groups.google.com/group/mochajs)\n - [Wiki](https://github.com/visionmedia/mocha/wiki)\n - Mocha [Extensions and reporters](https://github.com/visionmedia/mocha/wiki)\n", - "readmeFilename": "Readme.md", - "bugs": { - "url": "https://github.com/visionmedia/mocha/issues" - }, - "homepage": "https://github.com/visionmedia/mocha", - "_id": "mocha@1.18.2", - "_from": "mocha@1.18.2" -} diff --git a/tests/package.json b/tests/package.json index dc6b5c490d..b148c1ed24 100644 --- a/tests/package.json +++ b/tests/package.json @@ -19,6 +19,7 @@ "ms": "0.3.0", "should": "*", "coffee-script": "1.2", + "mocha": "1.7.4", "nw_test_loop": "git+https://github.com/owenc4a4/nw_test_loop_without_handle.git", "bignum": "git+https://github.com/owenc4a4/bignum.git", "node-dtrace-provider": "git+https://github.com/chrisa/node-dtrace-provider.git", diff --git a/tests/server/cookie_server.js b/tests/server/cookie_server.js deleted file mode 100644 index 726f137b00..0000000000 --- a/tests/server/cookie_server.js +++ /dev/null @@ -1,71 +0,0 @@ -var http = require('http'); -var url = require('url'); - -var expires_second = 86400000; - -var id_list = []; - -var request_listener = function(req,res){ - var location = url.parse(req.url,true); - var id = undefined; - var lang = undefined; - var cookies = {}; - var expires = new Date(Date.now()+expires_second).toGMTString(); - var set_cookies = null; - - var cookie_header = req.headers['cookie']; - - if (!cookie_header || cookie_header.length === 0){ - id = Math .random(); - lang = cookies["lang"]||"balabala"; - } else { - var cookie_tokens = cookie_header.split("; "); - for (var i=0;i0){ - headers["Set-Cookie"] = set_cookies; - } - res.writeHead(200,headers); - var html = JSON.stringify(cookies); - res.end(html); -}; - -var server = http.createServer(request_listener); -server.listen(8125); -console.log("Cookie server is running!"); diff --git a/tests/server/server.js b/tests/server/server.js index f751864fe9..9b7d497b3d 100644 --- a/tests/server/server.js +++ b/tests/server/server.js @@ -85,6 +85,3 @@ for (var i = 0; i < ports.length; i++) { } exports.res_save = res_save; - -//import cookie server -require(__dirname+'/cookie_server.js'); From 85ec449de4db4691093503a359874b6e859d0976 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 27 Oct 2014 10:48:37 +0800 Subject: [PATCH 236/492] [README] update for v0.11.0-rc1 --- CHANGELOG.md | 10 +++++++++- README.md | 6 ++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 185c5fbc3b..3d66d88c9b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,7 +1,15 @@ +0.11.0-rc1 / 10-27-2014 +======================= +- Chromium updated to 38.0.2125.104 +- Fix memory leak on navigation +- Show commit id in 'nw:version' page +- Fix: fullscreen in manifest (Linux) +- Fix: #430: handle event when quit from OSX dock + 0.10.5 / 09-16-2014 =================== - Fix: support more Chromium command line args (#1743, Thanks to Joachim Bauch) -- Fix #2171: crash when opening window +- Fix #2171: crash when opening window - Fix #2326: some websites crashes NW in Windows (fixed with the same file as updating to VS2013 Update 2) - Fix: win: crash on invalid parameter error (thanks to Mikael Roos) - Fix #1991 in a better way: [WIN] stalling for seconds under threaded composition on some hardware (#1991) diff --git a/README.md b/README.md index bfc8b7d934..9f5a2c281f 100644 --- a/README.md +++ b/README.md @@ -27,6 +27,12 @@ It's created and developed in the Intel Open Source Technology Center. * Windows: [win32](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-win-ia32.zip) * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-osx-x64.zip) +* **v0.11.0-rc1:** (Oct 27, 2014, based off of Node v0.11.13, Chromium 38.0.2125.104): [release notes](https://groups.google.com/d/msg/node-webkit/ET8C5lYzpfk/7NfqM0LaPlEJ) + + * Linux: [32bit](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-linux-x64.tar.gz) + * Windows: [win32](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-win-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-win-x64.zip) + * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-osx-x64.zip) + * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From c304f446c082410c6f756af88130c503662909a7 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 27 Oct 2014 13:43:47 +0800 Subject: [PATCH 237/492] split uploading path of nw.lib and nw.exp for win64 --- tools/aws_uploader.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/tools/aws_uploader.py b/tools/aws_uploader.py index de9044ac12..35b3b6fd26 100755 --- a/tools/aws_uploader.py +++ b/tools/aws_uploader.py @@ -83,7 +83,10 @@ def aws_upload(upload_path, file_list): print 'Uploading "' + f + '" ...' sys.stdout.flush() # use '/' for s3 - key = bucket.new_key(upload_path + '/' + f) + path_prefix = '' + if builder_name.startswith("win64") and (f == 'nw.lib' or f == 'nw.exp') : + path_prefix = 'x64' + key = bucket.new_key(upload_path + '/' + path_prefix + '/' + f) key.set_contents_from_filename(filename=os.path.join(dist_dir, f), cb=print_progress, num_cb=50, replace=True) for retry in range(3): From b1a2cae31c587000218943b94503c6ea604a474b Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 27 Oct 2014 20:04:56 +0800 Subject: [PATCH 238/492] convert WebLocalFrame* to WebFrame* --- src/renderer/printing/print_web_view_helper_win.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/renderer/printing/print_web_view_helper_win.cc b/src/renderer/printing/print_web_view_helper_win.cc index 7f5c1418b6..0e7e263c51 100644 --- a/src/renderer/printing/print_web_view_helper_win.cc +++ b/src/renderer/printing/print_web_view_helper_win.cc @@ -102,7 +102,7 @@ bool PrintWebViewHelper::RenderPreviewPage( } base::TimeTicks begin_time = base::TimeTicks::Now(); - RenderPage(print_params, page_number, print_preview_context_.prepared_frame(), + RenderPage(print_params, page_number, (WebFrame*)print_preview_context_.prepared_frame(), true, initial_render_metafile, &actual_shrink, NULL, NULL); print_preview_context_.RenderedPreviewPage( base::TimeTicks::Now() - begin_time); From 2fe4becbefe0826db4da78e937684be8a56793fd Mon Sep 17 00:00:00 2001 From: richb-hanover Date: Tue, 28 Oct 2014 21:40:18 -0400 Subject: [PATCH 239/492] Executable within OSX is in a hidden directory Helps resolve https://github.com/rogerwang/node-webkit/issues/2530 --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 9f5a2c281f..43daaedeae 100644 --- a/README.md +++ b/README.md @@ -80,6 +80,10 @@ $ /path/to/nw . (suppose the current directory contains 'package.json') Note: on Windows, you can drag the folder containing `package.json` to `nw.exe` to open it. +Note: on OSX, the executable binary is in a hidden directory within the .app file. To run node-webkit on OSX, type: +```bash +$ /path/to/node-webkit.app/Contents/MacOS/node-webkit . (suppose the current directory contains 'package.json') +``` ## Documents For more information on how to write/package/run apps, see: From f9428297a9521bb817151ec194483ce4f1724baa Mon Sep 17 00:00:00 2001 From: Jefry Date: Fri, 17 Oct 2014 12:08:41 +0800 Subject: [PATCH 240/492] [Notification][OSX] fix for the new code base --- src/nw_notification_manager.cc | 42 ++++++++++++++++-------------- src/nw_notification_manager.h | 16 ++++++------ src/nw_notification_manager_mac.h | 6 ++--- src/nw_notification_manager_mac.mm | 35 ++++++++++++++----------- 4 files changed, 53 insertions(+), 46 deletions(-) diff --git a/src/nw_notification_manager.cc b/src/nw_notification_manager.cc index cd9eb778e3..41f9d0b33c 100644 --- a/src/nw_notification_manager.cc +++ b/src/nw_notification_manager.cc @@ -18,7 +18,9 @@ // CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "ui/gfx/image/image.h" -#include "content/public/browser/render_view_host.h" +#include "content/public/browser/render_frame_host.h" +#include "content/common/desktop_notification_messages.h" + #include "content/nw/src/nw_notification_manager.h" #if defined(OS_MACOSX) @@ -57,13 +59,13 @@ NotificationManager* NotificationManager::getSingleton() { void NotificationManager::ImageDownloadCallback(int id, int http_status, const GURL& image_url, const std::vector& bitmaps, const std::vector& size) { NotificationManager *singleton = getSingleton(); DesktopNotificationParams params = singleton->desktop_notification_params_[id]; - singleton->AddDesktopNotification(params.params_, params.render_process_id_, params.render_view_id_, id, params.worker_, &bitmaps); + singleton->AddDesktopNotification(params.params_, params.render_process_id_, params.render_frame_id_, id, params.worker_, &bitmaps); singleton->desktop_notification_params_.erase(id); } bool NotificationManager::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, const int render_process_id, - const int render_view_id, + const int render_frame_id, const int notification_id, const bool worker, const std::vector* bitmaps) { @@ -71,39 +73,39 @@ bool NotificationManager::AddDesktopNotification(const content::ShowDesktopNotif return false; } -bool NotificationManager::DesktopNotificationPostClick(int render_process_id, int render_view_id, int notification_id) { - content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); - if (host == NULL) +bool NotificationManager::DesktopNotificationPostClick(int render_process_id, int render_frame_id, int notification_id) { + content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(render_process_id, render_frame_id); + if (!rfh) return false; - - // host->DesktopNotificationPostClick(notification_id); + + rfh->Send(new DesktopNotificationMsg_PostClick(rfh->GetRoutingID(), notification_id)); return true; } -bool NotificationManager::DesktopNotificationPostClose(int render_process_id, int render_view_id, int notification_id, bool by_user) { - content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); - if (host == NULL) +bool NotificationManager::DesktopNotificationPostClose(int render_process_id, int render_frame_id, int notification_id, bool by_user) { + content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(render_process_id, render_frame_id); + if (!rfh) return false; - // host->DesktopNotificationPostClose(notification_id, by_user); + rfh->Send(new DesktopNotificationMsg_PostClose(rfh->GetRoutingID(), notification_id, by_user)); return true; } -bool NotificationManager::DesktopNotificationPostDisplay(int render_process_id, int render_view_id, int notification_id) { - content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); - if (host == NULL) +bool NotificationManager::DesktopNotificationPostDisplay(int render_process_id, int render_frame_id, int notification_id) { + content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(render_process_id, render_frame_id); + if (!rfh) return false; - // host->DesktopNotificationPostDisplay(notification_id); + rfh->Send(new DesktopNotificationMsg_PostDisplay(rfh->GetRoutingID(), notification_id)); return true; } -bool NotificationManager::DesktopNotificationPostError(int render_process_id, int render_view_id, int notification_id, const base::string16& message) { - content::RenderViewHost* host = content::RenderViewHost::FromID(render_process_id, render_view_id); - if (host == NULL) +bool NotificationManager::DesktopNotificationPostError(int render_process_id, int render_frame_id, int notification_id, const base::string16& message) { + content::RenderFrameHost* rfh = content::RenderFrameHost::FromID(render_process_id, render_frame_id); + if (!rfh) return false; - // host->DesktopNotificationPostError(notification_id, message); + rfh->Send(new DesktopNotificationMsg_PostError(rfh->GetRoutingID(), notification_id)); return true; } } // namespace nw diff --git a/src/nw_notification_manager.h b/src/nw_notification_manager.h index d999c52ad5..edc666bb17 100644 --- a/src/nw_notification_manager.h +++ b/src/nw_notification_manager.h @@ -37,7 +37,7 @@ class NotificationManager{ struct DesktopNotificationParams { content::ShowDesktopNotificationHostMsgParams params_; int render_process_id_; - int render_view_id_; + int render_frame_id_; bool worker_; }; @@ -46,7 +46,7 @@ class NotificationManager{ // internal function for AddDesktopNotification virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, + const int render_process_id, const int render_frame_id, const int notification_id, const bool worker, const std::vector* bitmaps); @@ -56,15 +56,15 @@ class NotificationManager{ virtual bool AddDesktopNotification( const content::ShowDesktopNotificationHostMsgParams& params, const int render_process_id, - const int render_view_id, + const int render_frame_id, const int notification_id, const bool worker) = 0; - virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) = 0; + virtual bool CancelDesktopNotification(int render_process_id, int render_frame_id, int notification_id) = 0; - bool DesktopNotificationPostClick(int render_process_id, int render_view_id, int notification_id); - bool DesktopNotificationPostClose(int render_process_id, int render_view_id, int notification_id, bool by_user); - bool DesktopNotificationPostDisplay(int render_process_id, int render_view_id, int notification_id); - bool DesktopNotificationPostError(int render_process_id, int render_view_id, int notification_id, const base::string16& message); + bool DesktopNotificationPostClick(int render_process_id, int render_frame_id, int notification_id); + bool DesktopNotificationPostClose(int render_process_id, int render_frame_id, int notification_id, bool by_user); + bool DesktopNotificationPostDisplay(int render_process_id, int render_frame_id, int notification_id); + bool DesktopNotificationPostError(int render_process_id, int render_frame_id, int notification_id, const base::string16& message); }; diff --git a/src/nw_notification_manager_mac.h b/src/nw_notification_manager_mac.h index 8c3ddb942d..13f55b050d 100644 --- a/src/nw_notification_manager_mac.h +++ b/src/nw_notification_manager_mac.h @@ -28,7 +28,7 @@ class NotificationManagerMac : public NotificationManager { // internal function for AddDesktopNotification virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, + const int render_process_id, const int render_frame_id, const int notification_id, const bool worker, const std::vector* bitmaps) OVERRIDE; @@ -36,10 +36,10 @@ class NotificationManagerMac : public NotificationManager { explicit NotificationManagerMac(); virtual ~NotificationManagerMac(){} virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, + const int render_process_id, const int render_frame_id, const int notification_id, const bool worker) OVERRIDE; - virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) OVERRIDE; + virtual bool CancelDesktopNotification(int render_process_id, int render_frame_id, int notification_id) OVERRIDE; }; diff --git a/src/nw_notification_manager_mac.mm b/src/nw_notification_manager_mac.mm index 2654745368..55f0f75c2c 100644 --- a/src/nw_notification_manager_mac.mm +++ b/src/nw_notification_manager_mac.mm @@ -59,21 +59,25 @@ -(BOOL)userNotificationCenter:(NSUserNotificationCenter *)center shouldPresentNotification : (NSUserNotification *)notification { NSNumber *render_process_id = [notification.userInfo objectForKey : @"render_process_id"]; - NSNumber *render_view_id = [notification.userInfo objectForKey : @"render_view_id"]; + NSNumber *render_frame_id = [notification.userInfo objectForKey : @"render_frame_id"]; + NSNumber *notification_id = [notification.userInfo objectForKey : @"notification_id"]; + nw::NotificationManager::getSingleton()->DesktopNotificationPostDisplay(render_process_id.intValue, - render_view_id.intValue, - 0); + render_frame_id.intValue, + notification_id.intValue); return YES; } -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNotification : (NSUserNotification *)notification { NSNumber *render_process_id = [notification.userInfo objectForKey : @"render_process_id"]; - NSNumber *render_view_id = [notification.userInfo objectForKey : @"render_view_id"]; + NSNumber *render_frame_id = [notification.userInfo objectForKey : @"render_frame_id"]; + NSNumber *notification_id = [notification.userInfo objectForKey : @"notification_id"]; + nw::NotificationManager::getSingleton()->DesktopNotificationPostClick(render_process_id.intValue, - render_view_id.intValue, - 0); + render_frame_id.intValue, + notification_id.intValue); } @end @@ -81,14 +85,14 @@ -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNoti NotificationManagerMac::NotificationManagerMac() { } -bool NotificationManagerMac::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams ¶ms, const int render_process_id, const int render_view_id, const int notification_id, const bool worker) { - return AddDesktopNotification(params, render_process_id, render_view_id, notification_id, worker, NULL); +bool NotificationManagerMac::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams ¶ms, const int render_process_id, const int render_frame_id, const int notification_id, const bool worker) { + return AddDesktopNotification(params, render_process_id, render_frame_id, notification_id, worker, NULL); } bool NotificationManagerMac::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const int notification_id, const bool worker, const std::vector* bitmaps) { + const int render_process_id, const int render_frame_id, const int notification_id, const bool worker, const std::vector* bitmaps) { - content::RenderViewHost* host = content::RenderFrameHost::FromID(render_process_id, render_view_id)->GetRenderViewHost(); + content::RenderViewHost* host = content::RenderFrameHost::FromID(render_process_id, render_frame_id)->GetRenderViewHost(); if (host == nullptr) return false; content::Shell* shell = content::Shell::FromRenderViewHost(host); @@ -100,7 +104,7 @@ -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNoti DesktopNotificationParams desktop_notification_params; desktop_notification_params.params_ = params; desktop_notification_params.render_process_id_ = render_process_id; - desktop_notification_params.render_view_id_ = render_view_id; + desktop_notification_params.render_frame_id_ = render_frame_id; // download the icon image first content::WebContents::ImageDownloadCallback imageDownloadCallback = base::Bind(&NotificationManager::ImageDownloadCallback); @@ -127,7 +131,8 @@ -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNoti } notification.userInfo = @{ @"render_process_id" :[NSNumber numberWithInt : render_process_id], - @"render_view_id" :[NSNumber numberWithInt : render_view_id], + @"render_frame_id" :[NSNumber numberWithInt : render_frame_id], + @"notification_id" :[NSNumber numberWithInt : notification_id], }; @@ -140,13 +145,13 @@ -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNoti return true; } -bool NotificationManagerMac::CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id){ +bool NotificationManagerMac::CancelDesktopNotification(int render_process_id, int render_frame_id, int notification_id){ for (NSUserNotification *notification in[[NSUserNotificationCenter defaultUserNotificationCenter] deliveredNotifications]) { NSNumber *current_notification_id = [notification.userInfo objectForKey : @"notification_id"]; - //FIXME: if (current_notification_id.intValue == notification_id){ + if (current_notification_id.intValue == notification_id){ [[NSUserNotificationCenter defaultUserNotificationCenter] removeDeliveredNotification:notification]; return true; - //} + } } return false; } From a40be6253a5aa9bb8f2ea82e4fb80e3a855b741b Mon Sep 17 00:00:00 2001 From: Jefry Date: Thu, 30 Oct 2014 15:21:42 +0800 Subject: [PATCH 241/492] [Notification] [Win] fix for the new code base, add toast notification for win8, add javascript function for creating shortcut (needed for toast notification) --- nw.gypi | 2 + src/api/app/app.cc | 29 ++ src/api/app/app.js | 4 + src/nw_notification_manager.cc | 8 +- src/nw_notification_manager.h | 1 + src/nw_notification_manager_toast_win.cc | 402 +++++++++++++++++++++++ src/nw_notification_manager_toast_win.h | 68 ++++ src/nw_notification_manager_win.cc | 12 +- src/nw_notification_manager_win.h | 18 +- 9 files changed, 528 insertions(+), 16 deletions(-) create mode 100644 src/nw_notification_manager_toast_win.cc create mode 100644 src/nw_notification_manager_toast_win.h diff --git a/nw.gypi b/nw.gypi index 16408f0ce2..7425cc0dd3 100644 --- a/nw.gypi +++ b/nw.gypi @@ -324,6 +324,8 @@ 'src/nw_notification_manager.cc', 'src/nw_notification_manager_win.h', 'src/nw_notification_manager_win.cc', + 'src/nw_notification_manager_toast_win.h', + 'src/nw_notification_manager_toast_win.cc', 'src/nw_notification_manager_mac.h', 'src/nw_notification_manager_mac.mm', 'src/nw_notification_manager_linux.h', diff --git a/src/api/app/app.cc b/src/api/app/app.cc index 21d4bce983..cd933b4efd 100644 --- a/src/api/app/app.cc +++ b/src/api/app/app.cc @@ -24,6 +24,15 @@ #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/values.h" + +#if defined(OS_WIN) +#include "base/strings/utf_string_conversions.h" +#include "base/files/file_path.h" +#include "base/win/shortcut.h" +#include "base/path_service.h" +#include "content/nw/src/common/shell_switches.h" +#endif + #include "content/nw/src/api/api_messages.h" #include "content/nw/src/api/dispatcher_host.h" #include "content/nw/src/api/shortcut/global_shortcut_listener.h" @@ -120,6 +129,26 @@ void App::Call(Shell* shell, } else if (method == "ClearCache") { ClearCache(GetRenderProcessHost()); return; + } else if (method == "CreateShortcut") { +#if defined(OS_WIN) + base::string16 path; + arguments.GetString(0, &path); + + base::win::ShortcutProperties props; + base::string16 appID; + if (content::Shell::GetPackage()->root()->GetString("app-id", &appID) == false) + content::Shell::GetPackage()->root()->GetString(switches::kmName, &appID); + const std::wstring appName = base::UTF8ToWide(content::Shell::GetPackage()->GetName()); + props.set_app_id(appID); + + base::FilePath processPath; + PathService::Get(base::FILE_EXE, &processPath); + props.set_target(processPath); + result->AppendBoolean(base::win::CreateOrUpdateShortcutLink(base::FilePath(path), props, base::win::SHORTCUT_CREATE_ALWAYS)); +#else + result->AppendBoolean(false); +#endif + return; } else if (method == "GetPackage") { result->AppendString(shell->GetPackage()->package_string()); return; diff --git a/src/api/app/app.js b/src/api/app/app.js index b52e8dc697..99ff349dfa 100644 --- a/src/api/app/app.js +++ b/src/api/app/app.js @@ -53,6 +53,10 @@ App.prototype.setCrashDumpDir = function(dir) { return nw.callStaticMethodSync('App', 'SetCrashDumpDir', [ dir ]); } +App.prototype.createShortcut = function(dir) { + return nw.callStaticMethodSync('App', 'CreateShortcut', [ dir ]); +} + App.prototype.clearCache = function() { nw.callStaticMethodSync('App', 'ClearCache', [ ]); } diff --git a/src/nw_notification_manager.cc b/src/nw_notification_manager.cc index 41f9d0b33c..1fcc636a4b 100644 --- a/src/nw_notification_manager.cc +++ b/src/nw_notification_manager.cc @@ -27,6 +27,7 @@ #include "content/nw/src/nw_notification_manager_mac.h" #elif defined(OS_WIN) #include "content/nw/src/nw_notification_manager_win.h" +#include "content/nw/src/nw_notification_manager_toast_win.h" #elif defined(OS_LINUX) #include "content/nw/src/nw_notification_manager_linux.h" #endif @@ -47,7 +48,10 @@ NotificationManager* NotificationManager::getSingleton() { #if defined(OS_MACOSX) singleton_ = new NotificationManagerMac(); #elif defined(OS_WIN) - singleton_ = new NotificationManagerWin(); + if (NotificationManagerToastWin::IsSupported()) + singleton_ = new NotificationManagerToastWin(); + else + singleton_ = new NotificationManagerWin(); #elif defined(OS_LINUX) singleton_ = new NotificationManagerLinux(); #endif @@ -59,7 +63,7 @@ NotificationManager* NotificationManager::getSingleton() { void NotificationManager::ImageDownloadCallback(int id, int http_status, const GURL& image_url, const std::vector& bitmaps, const std::vector& size) { NotificationManager *singleton = getSingleton(); DesktopNotificationParams params = singleton->desktop_notification_params_[id]; - singleton->AddDesktopNotification(params.params_, params.render_process_id_, params.render_frame_id_, id, params.worker_, &bitmaps); + singleton->AddDesktopNotification(params.params_, params.render_process_id_, params.render_frame_id_, params.notification_id_, params.worker_, &bitmaps); singleton->desktop_notification_params_.erase(id); } diff --git a/src/nw_notification_manager.h b/src/nw_notification_manager.h index edc666bb17..22a72c7984 100644 --- a/src/nw_notification_manager.h +++ b/src/nw_notification_manager.h @@ -38,6 +38,7 @@ class NotificationManager{ content::ShowDesktopNotificationHostMsgParams params_; int render_process_id_; int render_frame_id_; + int notification_id_; bool worker_; }; diff --git a/src/nw_notification_manager_toast_win.cc b/src/nw_notification_manager_toast_win.cc new file mode 100644 index 0000000000..211ce74e76 --- /dev/null +++ b/src/nw_notification_manager_toast_win.cc @@ -0,0 +1,402 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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/public/browser/web_contents.h" +#include "content/public/browser/render_frame_host.h" +#include "content/public/browser/render_view_host.h" +#include "content/nw/src/browser/native_window.h" +#include "content/nw/src/nw_package.h" +#include "content/nw/src/nw_shell.h" + +#include "ui/gfx/image/image.h" +#include "base/strings/utf_string_conversions.h" +#include "content/nw/src/common/shell_switches.h" +#include "content/nw/src/nw_notification_manager_toast_win.h" + +#include +#include +#include +#include + +#include +#include +#include +#include +#pragma comment(lib, "runtimeobject.lib") + +using namespace Microsoft::WRL; +using namespace Windows::Foundation; + +namespace nw { + +class StringReferenceWrapper +{ +public: + + // Constructor which takes an existing string buffer and its length as the parameters. + // It fills an HSTRING_HEADER struct with the parameter. + // Warning: The caller must ensure the lifetime of the buffer outlives this + // object as it does not make a copy of the wide string memory. + + StringReferenceWrapper(_In_reads_(length) PCWSTR stringRef, _In_ UINT32 length) throw() + { + HRESULT hr = WindowsCreateStringReference(stringRef, length, &_header, &_hstring); + + if (FAILED(hr)) + { + RaiseException(static_cast(STATUS_INVALID_PARAMETER), EXCEPTION_NONCONTINUABLE, 0, nullptr); + } + } + + ~StringReferenceWrapper() + { + WindowsDeleteString(_hstring); + } + + template + StringReferenceWrapper(_In_reads_(N) wchar_t const (&stringRef)[N]) throw() + { + UINT32 length = N - 1; + HRESULT hr = WindowsCreateStringReference(stringRef, length, &_header, &_hstring); + + if (FAILED(hr)) + { + RaiseException(static_cast(STATUS_INVALID_PARAMETER), EXCEPTION_NONCONTINUABLE, 0, nullptr); + } + } + + template + StringReferenceWrapper(_In_reads_(_) wchar_t(&stringRef)[_]) throw() + { + UINT32 length; + HRESULT hr = SizeTToUInt32(wcslen(stringRef), &length); + + if (FAILED(hr)) + { + RaiseException(static_cast(STATUS_INVALID_PARAMETER), EXCEPTION_NONCONTINUABLE, 0, nullptr); + } + + WindowsCreateStringReference(stringRef, length, &_header, &_hstring); + } + + HSTRING Get() const throw() + { + return _hstring; + } + + +private: + HSTRING _hstring; + HSTRING_HEADER _header; +}; + +typedef ABI::Windows::Foundation::ITypedEventHandler DesktopToastActivatedEventHandler; +typedef ABI::Windows::Foundation::ITypedEventHandler DesktopToastDismissedEventHandler; +typedef ABI::Windows::Foundation::ITypedEventHandler DesktopToastFailedEventHandler; + +class ToastEventHandler : + public Microsoft::WRL::Implements +{ +public: + ToastEventHandler::ToastEventHandler(const int render_process_id, const int render_frame_id, const int notification_id); + ~ToastEventHandler(); + + // DesktopToastActivatedEventHandler + IFACEMETHODIMP Invoke(_In_ ABI::Windows::UI::Notifications::IToastNotification *sender, _In_ IInspectable* args); + + // DesktopToastDismissedEventHandler + IFACEMETHODIMP Invoke(_In_ ABI::Windows::UI::Notifications::IToastNotification *sender, _In_ ABI::Windows::UI::Notifications::IToastDismissedEventArgs *e); + + // DesktopToastFailedEventHandler + IFACEMETHODIMP Invoke(_In_ ABI::Windows::UI::Notifications::IToastNotification *sender, _In_ ABI::Windows::UI::Notifications::IToastFailedEventArgs *e); + + // IUnknown + IFACEMETHODIMP_(ULONG) AddRef() { return InterlockedIncrement(&_ref); } + + IFACEMETHODIMP_(ULONG) Release() { + ULONG l = InterlockedDecrement(&_ref); + if (l == 0) + delete this; + return l; + } + + IFACEMETHODIMP QueryInterface(_In_ REFIID riid, _COM_Outptr_ void **ppv) { + if (IsEqualIID(riid, IID_IUnknown)) + *ppv = static_cast(static_cast(this)); + else if (IsEqualIID(riid, __uuidof(DesktopToastActivatedEventHandler))) + *ppv = static_cast(this); + else if (IsEqualIID(riid, __uuidof(DesktopToastDismissedEventHandler))) + *ppv = static_cast(this); + else if (IsEqualIID(riid, __uuidof(DesktopToastFailedEventHandler))) + *ppv = static_cast(this); + else *ppv = nullptr; + + if (*ppv) { + reinterpret_cast(*ppv)->AddRef(); + return S_OK; + } + + return E_NOINTERFACE; + } + +private: + ULONG _ref; + const int _render_process_id, _render_frame_id, _notification_id; +}; + +// ============= ToastEventHandler Implementation ============= + +ToastEventHandler::ToastEventHandler(const int render_process_id, const int render_frame_id, const int notification_id) : +_ref(0), _render_process_id(render_process_id), _render_frame_id(render_frame_id), _notification_id(notification_id) +{ + +} + +ToastEventHandler::~ToastEventHandler() +{ + +} + +// DesktopToastActivatedEventHandler +IFACEMETHODIMP ToastEventHandler::Invoke(_In_ IToastNotification* /* sender */, _In_ IInspectable* /* args */) +{ + BOOL succeeded = nw::NotificationManager::getSingleton()->DesktopNotificationPostClick(_render_process_id, _render_frame_id, _notification_id); + return succeeded ? S_OK : E_FAIL; +} + +// DesktopToastDismissedEventHandler +IFACEMETHODIMP ToastEventHandler::Invoke(_In_ IToastNotification* /* sender */, _In_ IToastDismissedEventArgs* e) +{ + ToastDismissalReason tdr; + HRESULT hr = e->get_Reason(&tdr); + if (SUCCEEDED(hr)) + { + BOOL succeeded = nw::NotificationManager::getSingleton()->DesktopNotificationPostClose(_render_process_id, _render_frame_id, _notification_id, tdr == ToastDismissalReason_UserCanceled); + hr = succeeded ? S_OK : E_FAIL; + } + return hr; +} + +// DesktopToastFailedEventHandler +IFACEMETHODIMP ToastEventHandler::Invoke(_In_ IToastNotification* /* sender */, _In_ IToastFailedEventArgs* /* e */) +{ + BOOL succeeded = nw::NotificationManager::getSingleton()->DesktopNotificationPostError(_render_process_id, _render_frame_id, _notification_id, L"The toast encountered an error."); + return succeeded ? S_OK : E_FAIL; +} + +// ============= NotificationManagerToastWin Implementation ============= + +HRESULT NotificationManagerToastWin::SetNodeValueString(_In_ HSTRING inputString, _In_ IXmlNode *node, _In_ IXmlDocument *xml) +{ + ComPtr inputText; + + HRESULT hr = xml->CreateTextNode(inputString, &inputText); + if (SUCCEEDED(hr)) + { + ComPtr inputTextNode; + + hr = inputText.As(&inputTextNode); + if (SUCCEEDED(hr)) + { + ComPtr pAppendedChild; + hr = node->AppendChild(inputTextNode.Get(), &pAppendedChild); + } + } + + return hr; +} + +HRESULT NotificationManagerToastWin::SetTextValues(_In_reads_(textValuesCount) const wchar_t **textValues, _In_ UINT32 textValuesCount, + _In_reads_(textValuesCount) UINT32 *textValuesLengths, _In_ IXmlDocument *toastXml) +{ + HRESULT hr = textValues != nullptr && textValuesCount > 0 ? S_OK : E_INVALIDARG; + if (SUCCEEDED(hr)) + { + ComPtr nodeList; + hr = toastXml->GetElementsByTagName(StringReferenceWrapper(L"text").Get(), &nodeList); + if (SUCCEEDED(hr)) + { + UINT32 nodeListLength; + hr = nodeList->get_Length(&nodeListLength); + if (SUCCEEDED(hr)) + { + hr = textValuesCount <= nodeListLength ? S_OK : E_INVALIDARG; + if (SUCCEEDED(hr)) + { + for (UINT32 i = 0; i < textValuesCount; i++) + { + ComPtr textNode; + hr = nodeList->Item(i, &textNode); + if (SUCCEEDED(hr)) + { + hr = SetNodeValueString(StringReferenceWrapper(textValues[i], textValuesLengths[i]).Get(), textNode.Get(), toastXml); + } + } + } + } + } + } + return hr; +} + +HRESULT NotificationManagerToastWin::SetImageSrc(_In_z_ const wchar_t *imagePath, _In_ IXmlDocument *toastXml) +{ + wchar_t imageSrc[MAX_PATH] = L""; + HRESULT hr = StringCchCat(imageSrc, ARRAYSIZE(imageSrc), imagePath); + if (SUCCEEDED(hr)) + { + ComPtr nodeList; + hr = toastXml->GetElementsByTagName(StringReferenceWrapper(L"image").Get(), &nodeList); + if (SUCCEEDED(hr)) + { + ComPtr imageNode; + hr = nodeList->Item(0, &imageNode); + if (SUCCEEDED(hr)) + { + ComPtr attributes; + + hr = imageNode->get_Attributes(&attributes); + if (SUCCEEDED(hr)) + { + ComPtr srcAttribute; + + hr = attributes->GetNamedItem(StringReferenceWrapper(L"src").Get(), &srcAttribute); + if (SUCCEEDED(hr)) + { + hr = SetNodeValueString(StringReferenceWrapper(imageSrc).Get(), srcAttribute.Get(), toastXml); + } + } + } + } + } + return hr; +} + +HRESULT NotificationManagerToastWin::CreateToastXml(_In_ IToastNotificationManagerStatics *toastManager, + const content::ShowDesktopNotificationHostMsgParams& params, _Outptr_ IXmlDocument** inputXml) +{ + const bool bImage = params.icon_url.is_valid() && params.icon_url.spec().find("file:///") == 0; + // Retrieve the template XML + HRESULT hr = toastManager->GetTemplateContent(bImage ? ToastTemplateType_ToastImageAndText03 : ToastTemplateType_ToastText03, inputXml); + if (SUCCEEDED(hr)) + { + if (SUCCEEDED(hr)) + { + hr = bImage ? SetImageSrc(base::UTF8ToWide(params.icon_url.spec()).c_str(), *inputXml) : S_OK; + if (SUCCEEDED(hr)) + { + const wchar_t* textValues[] = { + params.title.c_str(), + params.body.c_str() + }; + + UINT32 textLengths[] = { params.title.length(), params.body.length() }; + + hr = SetTextValues(textValues, 2, textLengths, *inputXml); + } + } + } + return hr; +} + +HRESULT NotificationManagerToastWin::CreateToast(_In_ IToastNotificationManagerStatics *toastManager, _In_ IXmlDocument *xml, + const int render_process_id, const int render_frame_id, const int notification_id) +{ + base::string16 appID; + if (content::Shell::GetPackage()->root()->GetString("app-id", &appID) == false) + content::Shell::GetPackage()->root()->GetString(switches::kmName, &appID); + + ComPtr notifier; + HRESULT hr = toastManager->CreateToastNotifierWithId(StringReferenceWrapper(appID.c_str(), appID.length()).Get(), ¬ifier); + if (SUCCEEDED(hr)) + { + ComPtr factory; + hr = GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &factory); + if (SUCCEEDED(hr)) + { + ComPtr toast; + hr = factory->CreateToastNotification(xml, &toast); + if (SUCCEEDED(hr)) + { + // Register the event handlers + EventRegistrationToken activatedToken, dismissedToken, failedToken; + ComPtr eventHandler = new ToastEventHandler(render_process_id, render_frame_id, notification_id); + + hr = toast->add_Activated(eventHandler.Get(), &activatedToken); + if (SUCCEEDED(hr)) + { + hr = toast->add_Dismissed(eventHandler.Get(), &dismissedToken); + if (SUCCEEDED(hr)) + { + hr = toast->add_Failed(eventHandler.Get(), &failedToken); + if (SUCCEEDED(hr)) + { + hr = notifier->Show(toast.Get()); + } + } + } + } + } + } + return hr; +} + +bool NotificationManagerToastWin::IsSupported() { + ComPtr toastStatics; + HRESULT hr = GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &toastStatics); + return SUCCEEDED(hr); +} + +NotificationManagerToastWin::NotificationManagerToastWin() { +} + +NotificationManagerToastWin::~NotificationManagerToastWin() { + +} + +bool NotificationManagerToastWin::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_frame_id, const int notification_id, + const bool worker, const std::vector* bitmaps) { + + content::RenderViewHost* host = content::RenderFrameHost::FromID(render_process_id, render_frame_id)->GetRenderViewHost(); + if (host == NULL) + return false; + + ComPtr toastStatics; + HRESULT hr = GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &toastStatics); + if (SUCCEEDED(hr)) + { + ComPtr toastXml; + hr = CreateToastXml(toastStatics.Get(), params, &toastXml); + if (SUCCEEDED(hr)) + { + hr = CreateToast(toastStatics.Get(), toastXml.Get(), render_process_id, render_frame_id, notification_id); + if (SUCCEEDED(hr)) + DesktopNotificationPostDisplay(render_process_id, render_frame_id, notification_id); + } + } + + return SUCCEEDED(hr); +} + +bool NotificationManagerToastWin::CancelDesktopNotification(int render_process_id, int render_frame_id, int notification_id) { + return true; +} +} // namespace nw diff --git a/src/nw_notification_manager_toast_win.h b/src/nw_notification_manager_toast_win.h new file mode 100644 index 0000000000..3b22b0d44a --- /dev/null +++ b/src/nw_notification_manager_toast_win.h @@ -0,0 +1,68 @@ +// Copyright (c) 2014 Jefry Tedjokusumo +// +// 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_NOTIFICATION_MANAGER_TOAST_WIN_H_ +#define CONTENT_NW_NOTIFICATION_MANAGER_TOAST_WIN_H_ + +#include "content/nw/src/nw_notification_manager.h" +#include + +namespace nw { + using namespace ABI::Windows::UI::Notifications; + using namespace ABI::Windows::Data::Xml::Dom; + +class NotificationManagerToastWin : public NotificationManager{ + + // internal function for AddDesktopNotification + virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_frame_id, const int notification_id, + const bool worker, const std::vector* bitmaps) OVERRIDE; + + + HRESULT CreateToast(_In_ IToastNotificationManagerStatics *toastManager, _In_ IXmlDocument *xml, + const int render_process_id, const int render_frame_id, const int notification_id); + + // Create the toast XML from a template + HRESULT CreateToastXml(_In_ IToastNotificationManagerStatics *toastManager, + const content::ShowDesktopNotificationHostMsgParams& params, _Outptr_ IXmlDocument** inputXml); + + // Set the value of the "src" attribute of the "image" node + HRESULT SetImageSrc(_In_z_ const wchar_t *imagePath, _In_ IXmlDocument *toastXml); + + // Set the values of each of the text nodes + HRESULT SetTextValues(_In_reads_(textValuesCount) const wchar_t **textValues, _In_ UINT32 textValuesCount, + _In_reads_(textValuesCount) UINT32 *textValuesLengths, _In_ IXmlDocument *toastXml); + + HRESULT SetNodeValueString(_In_ HSTRING inputString, _In_ IXmlNode *node, _In_ IXmlDocument *xml); + +public: + static bool IsSupported(); + explicit NotificationManagerToastWin(); + virtual ~NotificationManagerToastWin(); + virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, + const int render_process_id, const int render_frame_id, const int notification_id, + const bool worker) OVERRIDE{ + return AddDesktopNotification(params, render_process_id, render_frame_id, notification_id, worker, NULL); + } + virtual bool CancelDesktopNotification(int render_process_id, int render_frame_id, int notification_id) OVERRIDE; +}; + +} // namespace nw + +#endif // CONTENT_NW_NOTIFICATION_MANAGER_WIN_H_ diff --git a/src/nw_notification_manager_win.cc b/src/nw_notification_manager_win.cc index 02cfc4a8f5..e7a86946b0 100644 --- a/src/nw_notification_manager_win.cc +++ b/src/nw_notification_manager_win.cc @@ -119,10 +119,10 @@ NotificationManagerWin::~NotificationManagerWin() { } bool NotificationManagerWin::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const int notification_id, + const int render_process_id, const int render_frame_id, const int notification_id, const bool worker, const std::vector* bitmaps) { - content::RenderViewHost* host = content::RenderFrameHost::FromID(render_process_id, render_view_id)->GetRenderViewHost(); + content::RenderViewHost* host = content::RenderFrameHost::FromID(render_process_id, render_frame_id)->GetRenderViewHost(); if (host == NULL) return false; @@ -133,7 +133,8 @@ bool NotificationManagerWin::AddDesktopNotification(const content::ShowDesktopNo DesktopNotificationParams desktop_notification_params; desktop_notification_params.params_ = params; desktop_notification_params.render_process_id_ = render_process_id; - desktop_notification_params.render_view_id_ = render_view_id; + desktop_notification_params.render_frame_id_ = render_frame_id; + desktop_notification_params.notification_id_ = notification_id; // download the icon image first content::WebContents::ImageDownloadCallback imageDownloadCallback = base::Bind(&NotificationManager::ImageDownloadCallback); @@ -146,7 +147,8 @@ bool NotificationManagerWin::AddDesktopNotification(const content::ShowDesktopNo // if we reach here, it means the function is called from image download callback render_process_id_ = render_process_id; - render_view_id_ = render_view_id; + render_frame_id_ = render_frame_id; + notification_id_ = notification_id; // set the default notification icon as the app icon gfx::Image icon = shell->window()->app_icon(); @@ -184,7 +186,7 @@ bool NotificationManagerWin::AddDesktopNotification(const content::ShowDesktopNo return result; } -bool NotificationManagerWin::CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) { +bool NotificationManagerWin::CancelDesktopNotification(int render_process_id, int render_frame_id, int notification_id) { //windows can only have 1 notification, cannot delete existing notification return true; } diff --git a/src/nw_notification_manager_win.h b/src/nw_notification_manager_win.h index 5d2c8e2bbd..ab7cb805d1 100644 --- a/src/nw_notification_manager_win.h +++ b/src/nw_notification_manager_win.h @@ -43,36 +43,36 @@ class NotificationManagerWin : public NotificationManager{ TrayObserver* status_observer_; // variable to store the latest notification data, windows can only show 1 notification - int render_process_id_, render_view_id_; + int render_process_id_, render_frame_id_, notification_id_; // dispatch the events from the latest notification bool DesktopNotificationPostClick() { - return NotificationManager::DesktopNotificationPostClick(render_process_id_, render_view_id_, 0); + return NotificationManager::DesktopNotificationPostClick(render_process_id_, render_frame_id_, notification_id_); } bool DesktopNotificationPostClose(bool by_user) { - return NotificationManager::DesktopNotificationPostClose(render_process_id_, render_view_id_, 0, by_user); + return NotificationManager::DesktopNotificationPostClose(render_process_id_, render_frame_id_, notification_id_, by_user); } bool DesktopNotificationPostDisplay() { - return NotificationManager::DesktopNotificationPostDisplay(render_process_id_, render_view_id_, 0); + return NotificationManager::DesktopNotificationPostDisplay(render_process_id_, render_frame_id_, notification_id_); } bool DesktopNotificationPostError(const base::string16& message) { - return NotificationManager::DesktopNotificationPostError(render_process_id_, render_view_id_, 0, message); + return NotificationManager::DesktopNotificationPostError(render_process_id_, render_frame_id_, notification_id_, message); } // internal function for AddDesktopNotification virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const int notification_id, + const int render_process_id, const int render_frame_id, const int notification_id, const bool worker, const std::vector* bitmaps) OVERRIDE; public: explicit NotificationManagerWin(); virtual ~NotificationManagerWin(); virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, - const int render_process_id, const int render_view_id, const int notification_id, + const int render_process_id, const int render_frame_id, const int notification_id, const bool worker) OVERRIDE{ - return AddDesktopNotification(params, render_process_id, render_view_id, notification_id, worker, NULL); + return AddDesktopNotification(params, render_process_id, render_frame_id, notification_id, worker, NULL); } - virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) OVERRIDE; + virtual bool CancelDesktopNotification(int render_process_id, int render_frame_id, int notification_id) OVERRIDE; }; } // namespace nw From ee296e4c1f0b62b5e0935925adf424f29d65376f Mon Sep 17 00:00:00 2001 From: jtg-gg Date: Thu, 30 Oct 2014 17:52:17 +0800 Subject: [PATCH 242/492] [Notification][linux] change render_view to render_frame --- src/nw_notification_manager_linux.cc | 20 ++++++++++---------- src/nw_notification_manager_linux.h | 6 +++--- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/nw_notification_manager_linux.cc b/src/nw_notification_manager_linux.cc index cd90d5d1f1..2492bf8268 100644 --- a/src/nw_notification_manager_linux.cc +++ b/src/nw_notification_manager_linux.cc @@ -72,12 +72,12 @@ void NotificationManagerLinux::onClose(NotifyNotification *notif) bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, const int render_process_id, - const int render_view_id, + const int render_frame_id, const int notification_id, const bool worker, const std::vector* bitmaps) { - content::RenderViewHost* host = content::RenderFrameHost::FromID(render_process_id, render_view_id)->GetRenderViewHost(); + content::RenderViewHost* host = content::RenderFrameHost::FromID(render_process_id, render_frame_id)->GetRenderViewHost(); if (host == NULL) return false; @@ -88,7 +88,7 @@ bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktop DesktopNotificationParams desktop_notification_params; desktop_notification_params.params_ = params; desktop_notification_params.render_process_id_ = render_process_id; - desktop_notification_params.render_view_id_ = render_view_id; + desktop_notification_params.render_frame_id_ = render_frame_id; // download the icon image first content::WebContents::ImageDownloadCallback imageDownloadCallback = base::Bind(&NotificationManager::ImageDownloadCallback); @@ -118,7 +118,7 @@ bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktop NotificationData data; data.mNotification = notif; data.mRenderProcessId = render_process_id; - data.mRenderViewId = render_view_id; + data.mRenderViewId = render_frame_id; mNotificationIDmap[notification_id] = data; } else { @@ -133,7 +133,7 @@ bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktop g_object_ref(G_OBJECT(notif)); onClose(notif); data.mRenderProcessId = render_process_id; - data.mRenderViewId = render_view_id; + data.mRenderViewId = render_frame_id; mNotificationIDmap[notification_id] = data; } } @@ -146,16 +146,16 @@ bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktop GError* error = NULL; if (notify_notification_show (notif, &error)) { - DesktopNotificationPostDisplay(render_process_id, render_view_id, notification_id); + DesktopNotificationPostDisplay(render_process_id, render_frame_id, notification_id); } else { base::string16 errorMsg = base::UTF8ToUTF16(error->message); - DesktopNotificationPostError(render_process_id, render_view_id, notification_id, errorMsg); + DesktopNotificationPostError(render_process_id, render_frame_id, notification_id, errorMsg); } return error==NULL; } -bool NotificationManagerLinux::CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) { +bool NotificationManagerLinux::CancelDesktopNotification(int render_process_id, int render_frame_id, int notification_id) { NotificationMap::const_iterator i = getNotification(notification_id); if (i!=mNotificationIDmap.end()) { return notify_notification_close(i->second.mNotification, NULL); @@ -165,10 +165,10 @@ bool NotificationManagerLinux::CancelDesktopNotification(int render_process_id, bool NotificationManagerLinux::AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, const int render_process_id, - const int render_view_id, + const int render_frame_id, const int notification_id, const bool worker) { - return AddDesktopNotification(params, render_process_id, render_view_id, notification_id, worker, NULL); + return AddDesktopNotification(params, render_process_id, render_frame_id, notification_id, worker, NULL); } } // namespace nw diff --git a/src/nw_notification_manager_linux.h b/src/nw_notification_manager_linux.h index 4da49b5ba4..b09580983d 100644 --- a/src/nw_notification_manager_linux.h +++ b/src/nw_notification_manager_linux.h @@ -43,7 +43,7 @@ class NotificationManagerLinux : public NotificationManager { // internal function for AddDesktopNotification virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, const int render_process_id, - const int render_view_id, + const int render_frame_id, const int notification_id, const bool worker, const std::vector* bitmaps) OVERRIDE; @@ -53,10 +53,10 @@ class NotificationManagerLinux : public NotificationManager { virtual ~NotificationManagerLinux(); virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, const int render_process_id, - const int render_view_id, + const int render_frame_id, const int notification_id, const bool worker) OVERRIDE; - virtual bool CancelDesktopNotification(int render_process_id, int render_view_id, int notification_id) OVERRIDE; + virtual bool CancelDesktopNotification(int render_process_id, int render_frame_id, int notification_id) OVERRIDE; }; } // namespace nw From dffad3922ea519d86a2dd53b84f0f7337a5a1a2f Mon Sep 17 00:00:00 2001 From: Jefry Date: Fri, 31 Oct 2014 13:56:26 +0800 Subject: [PATCH 243/492] [Screen Geometry] fix for the new code base --- nw.gypi | 8 ++++---- src/api/dispatcher_host.cc | 4 ++-- src/api/screen/screen.cc | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/nw.gypi b/nw.gypi index 16408f0ce2..ac99aec0d1 100644 --- a/nw.gypi +++ b/nw.gypi @@ -149,10 +149,10 @@ 'src/api/dispatcher_bindings_mac.mm', 'src/api/dispatcher_host.cc', 'src/api/dispatcher_host.h', -# 'src/api/event/event.h', -# 'src/api/event/event.cc', -# 'src/api/screen/screen.h', -# 'src/api/screen/screen.cc', + 'src/api/event/event.h', + 'src/api/event/event.cc', + 'src/api/screen/screen.h', + 'src/api/screen/screen.cc', 'src/api/window_bindings.cc', 'src/api/window_bindings.h', 'src/api/menu/menu.cc', diff --git a/src/api/dispatcher_host.cc b/src/api/dispatcher_host.cc index 361b1dbc99..77e7dda143 100644 --- a/src/api/dispatcher_host.cc +++ b/src/api/dispatcher_host.cc @@ -161,7 +161,7 @@ void DispatcherHost::OnAllocateObject(int object_id, } else if (type == "Shortcut") { objects_registry_.AddWithID(new Shortcut(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); } else if (type == "Screen") { - //FIXME: objects_registry_.AddWithID(new EventListener(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); + objects_registry_.AddWithID(new EventListener(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); } else { LOG(ERROR) << "Allocate an object of unknown type: " << type; objects_registry_.AddWithID(new Base(object_id, weak_ptr_factory_.GetWeakPtr(), option), object_id); @@ -253,7 +253,7 @@ void DispatcherHost::OnCallStaticMethodSync( nwapi::App::Call(shell, method, arguments, result); return; } else if (type == "Screen") { - //FIXME: nwapi::Screen::Call(this, method, arguments, result); + nwapi::Screen::Call(this, method, arguments, result); return; } diff --git a/src/api/screen/screen.cc b/src/api/screen/screen.cc index d009dac433..b33690d534 100644 --- a/src/api/screen/screen.cc +++ b/src/api/screen/screen.cc @@ -57,7 +57,7 @@ class JavaScriptDisplayObserver : BaseEvent, public gfx::DisplayObserver { gfx::Screen* screen_; // Called when the |display|'s bound has changed. - virtual void OnDisplayBoundsChanged(const gfx::Display& display) OVERRIDE { + virtual void OnDisplayMetricsChanged(const gfx::Display& display, uint32_t changed_metrics) OVERRIDE { base::ListValue arguments; arguments.AppendString(DisplayToJSON(display)); object_->dispatcher_host()->SendEvent(object_, "displayBoundsChanged", arguments); From aa8da8a62c054dc3320bdd6297fce4f421db7d12 Mon Sep 17 00:00:00 2001 From: Jefry Date: Fri, 31 Oct 2014 18:08:26 +0800 Subject: [PATCH 244/492] [Screen Geometry] expose more information to javascript --- src/api/screen/screen.cc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/api/screen/screen.cc b/src/api/screen/screen.cc index b33690d534..74b6d12070 100644 --- a/src/api/screen/screen.cc +++ b/src/api/screen/screen.cc @@ -46,6 +46,8 @@ std::string DisplayToJSON(const gfx::Display& display) { ret << ",\"scaleFactor\":" << display.device_scale_factor(); ret << ",\"isBuiltIn\":" << (display.IsInternal() ? "true" : "false"); + ret << ",\"rotation\":" << display.RotationAsDegree(); + ret << ",\"touchSupport\":" << display.touch_support(); ret << "}"; return ret.str(); @@ -60,6 +62,7 @@ class JavaScriptDisplayObserver : BaseEvent, public gfx::DisplayObserver { virtual void OnDisplayMetricsChanged(const gfx::Display& display, uint32_t changed_metrics) OVERRIDE { base::ListValue arguments; arguments.AppendString(DisplayToJSON(display)); + arguments.AppendInteger(changed_metrics); object_->dispatcher_host()->SendEvent(object_, "displayBoundsChanged", arguments); } From a05939ec0443eab08bd9f246d4e3d74ae2102b3b Mon Sep 17 00:00:00 2001 From: Jefry Date: Tue, 4 Nov 2014 13:35:10 +0800 Subject: [PATCH 245/492] [Notification][OSX] bug fix, notification_id not initialized --- src/nw_notification_manager_mac.mm | 1 + 1 file changed, 1 insertion(+) diff --git a/src/nw_notification_manager_mac.mm b/src/nw_notification_manager_mac.mm index 55f0f75c2c..476ed572f0 100644 --- a/src/nw_notification_manager_mac.mm +++ b/src/nw_notification_manager_mac.mm @@ -105,6 +105,7 @@ -(void)userNotificationCenter:(NSUserNotificationCenter *)center didActivateNoti desktop_notification_params.params_ = params; desktop_notification_params.render_process_id_ = render_process_id; desktop_notification_params.render_frame_id_ = render_frame_id; + desktop_notification_params.notification_id_ = notification_id; // download the icon image first content::WebContents::ImageDownloadCallback imageDownloadCallback = base::Bind(&NotificationManager::ImageDownloadCallback); From 3d235379cfa8f51dd05366ca57ecaf45473583cf Mon Sep 17 00:00:00 2001 From: Jefry Date: Tue, 4 Nov 2014 16:51:40 +0800 Subject: [PATCH 246/492] [Notification] add manual test --- tests/manual_tests/notification/index.html | 68 ++++++++++++++++++++ tests/manual_tests/notification/package.json | 5 ++ 2 files changed, 73 insertions(+) create mode 100644 tests/manual_tests/notification/index.html create mode 100644 tests/manual_tests/notification/package.json diff --git a/tests/manual_tests/notification/index.html b/tests/manual_tests/notification/index.html new file mode 100644 index 0000000000..35434a4cd6 --- /dev/null +++ b/tests/manual_tests/notification/index.html @@ -0,0 +1,68 @@ + + + Notification + + +

      + + + diff --git a/tests/manual_tests/notification/package.json b/tests/manual_tests/notification/package.json new file mode 100644 index 0000000000..a504bbc01f --- /dev/null +++ b/tests/manual_tests/notification/package.json @@ -0,0 +1,5 @@ +{ + "name": "nw-notification-test", + "main": "index.html", + "app-id": "com.node.webkit.notification.test" +} From 2c545d8995fa8060c5472a66739c0296504deedc Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Wed, 5 Nov 2014 10:51:16 +0100 Subject: [PATCH 247/492] Support setting additional root certificates on supported platforms. To use, add a new entry `additional_trust_anchors` to `package.json` containing a list of PEM-encoded certificates (i.e. `"-----BEGIN CERTIFICATE-----\n...certificate data...\n-----END CERTIFICATE-----\n"`). These certificates are used as additional root certificates for validation, to allow connecting to services using a self-signed certificate or certificates issued by custom CAs. --- src/net/shell_url_request_context_getter.cc | 22 ++++++++++++++- src/net/shell_url_request_context_getter.h | 9 +++++- src/shell_browser_context.cc | 31 +++++++++++++++++++++ 3 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/net/shell_url_request_context_getter.cc b/src/net/shell_url_request_context_getter.cc index 04f2a7379c..8a70eec2cd 100644 --- a/src/net/shell_url_request_context_getter.cc +++ b/src/net/shell_url_request_context_getter.cc @@ -37,6 +37,8 @@ #include "content/nw/src/nw_shell.h" #include "content/nw/src/shell_content_browser_client.h" #include "net/cert/cert_verifier.h" +#include "net/cert/cert_verify_proc.h" +#include "net/cert/multi_threaded_cert_verifier.h" #include "net/dns/host_resolver.h" #include "net/dns/mapped_host_resolver.h" #include "net/ssl/ssl_config_service_defaults.h" @@ -205,7 +207,14 @@ net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() { scoped_ptr host_resolver( net::HostResolver::CreateDefaultResolver(NULL)); - storage_->set_cert_verifier(net::CertVerifier::CreateDefault()); + net::CertVerifyProc *verify_proc = net::CertVerifyProc::CreateDefault(); + if (!verify_proc->SupportsAdditionalTrustAnchors()) { + LOG(WARNING) + << "Additional trust anchors not supported on the current platform!"; + } + net::MultiThreadedCertVerifier *verifier = new net::MultiThreadedCertVerifier(verify_proc); + verifier->SetCertTrustAnchorProvider(this); + storage_->set_cert_verifier(verifier); storage_->set_transport_security_state(new net::TransportSecurityState); net::ProxyService* proxy_service; @@ -296,6 +305,17 @@ net::HostResolver* ShellURLRequestContextGetter::host_resolver() { return url_request_context_->host_resolver(); } +void ShellURLRequestContextGetter::SetAdditionalTrustAnchors(const net::CertificateList& trust_anchors) +{ + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + trust_anchors_ = trust_anchors; +} + +const net::CertificateList& ShellURLRequestContextGetter::GetAdditionalTrustAnchors() { + DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::IO)); + return trust_anchors_; +} + net::HttpAuthHandlerFactory* ShellURLRequestContextGetter::CreateDefaultAuthHandlerFactory( net::HostResolver* resolver) { net::HttpAuthFilterWhitelist* auth_filter_default_credentials = NULL; diff --git a/src/net/shell_url_request_context_getter.h b/src/net/shell_url_request_context_getter.h index 9b92ab13f6..7419d27251 100644 --- a/src/net/shell_url_request_context_getter.h +++ b/src/net/shell_url_request_context_getter.h @@ -26,6 +26,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/scoped_ptr.h" #include "content/public/browser/content_browser_client.h" +#include "net/cert/cert_trust_anchor_provider.h" #include "net/url_request/url_request_context_getter.h" #include "net/url_request/url_request_job_factory.h" @@ -47,7 +48,7 @@ namespace content { class ShellBrowserContext; - class ShellURLRequestContextGetter : public net::URLRequestContextGetter { + class ShellURLRequestContextGetter : public net::URLRequestContextGetter, public net::CertTrustAnchorProvider { public: ShellURLRequestContextGetter( bool ignore_certificate_errors, @@ -69,6 +70,11 @@ class ShellBrowserContext; net::HostResolver* host_resolver(); + void SetAdditionalTrustAnchors(const net::CertificateList& trust_anchors); + + // net::CertTrustAnchorProvider implementation. + virtual const net::CertificateList& GetAdditionalTrustAnchors() OVERRIDE; + protected: virtual ~ShellURLRequestContextGetter(); net::HttpAuthHandlerFactory* CreateDefaultAuthHandlerFactory(net::HostResolver* resolver); @@ -85,6 +91,7 @@ class ShellBrowserContext; std::string auth_delegate_whitelist_; std::string gssapi_library_name_; // std::vector spdyproxy_auth_origins_; + net::CertificateList trust_anchors_; base::MessageLoop* io_loop_; base::MessageLoop* file_loop_; diff --git a/src/shell_browser_context.cc b/src/shell_browser_context.cc index 998384a07b..7d6d264f2d 100644 --- a/src/shell_browser_context.cc +++ b/src/shell_browser_context.cc @@ -35,6 +35,7 @@ #include "content/nw/src/common/shell_switches.h" #include "content/nw/src/net/shell_url_request_context_getter.h" #include "content/nw/src/nw_package.h" +#include "net/cert/x509_certificate.h" #if defined(OS_WIN) #include "base/base_paths_win.h" @@ -190,6 +191,36 @@ net::URLRequestContextGetter* ShellBrowserContext::CreateRequestContext( auth_schemes, auth_server_whitelist, auth_delegate_whitelist, gssapi_library_name); + const base::ListValue *additional_trust_anchors = NULL; + if (package_->root()->GetList("additional_trust_anchors", &additional_trust_anchors)) { + net::CertificateList trust_anchors; + for (size_t i=0; iGetSize(); i++) { + std::string certificate_string; + if (!additional_trust_anchors->GetString(i, &certificate_string)) { + LOG(WARNING) + << "Could not get string from entry " << i; + continue; + } + + net::CertificateList loaded = + net::X509Certificate::CreateCertificateListFromBytes( + certificate_string.c_str(), certificate_string.size(), + net::X509Certificate::FORMAT_AUTO); + if (loaded.empty() && !certificate_string.empty()) { + LOG(WARNING) + << "Could not load certificate from entry " << i; + continue; + } + + trust_anchors.insert(trust_anchors.end(), loaded.begin(), loaded.end()); + } + if (!trust_anchors.empty()) { + LOG(INFO) + << "Added " << trust_anchors.size() << " certificates to trust anchors."; + url_request_getter_->SetAdditionalTrustAnchors(trust_anchors); + } + } + resource_context_->set_url_request_context_getter(url_request_getter_.get()); return url_request_getter_.get(); } From 193e8e670d974a394c5ac51c22f6387f69ca32da Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 6 Nov 2014 11:09:16 +0800 Subject: [PATCH 248/492] [WIN] enable high DPI support Fix #2524 --- src/shell_main.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/shell_main.cc b/src/shell_main.cc index e7ee9641c4..38c0ec2dac 100644 --- a/src/shell_main.cc +++ b/src/shell_main.cc @@ -20,12 +20,15 @@ #include "content/public/app/content_main.h" +#include "base/command_line.h" #include "content/nw/src/shell_main_delegate.h" #include "sandbox/win/src/sandbox_types.h" #if defined(OS_WIN) #include "base/win/win_util.h" +#include "base/win/windows_version.h" #include "content/public/app/startup_helper_win.h" +#include "ui/gfx/win/dpi.h" #endif #if defined(OS_MACOSX) @@ -35,6 +38,11 @@ #if defined(OS_WIN) int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE, wchar_t*, int) { + CommandLine::Init(0, NULL); + if (base::win::GetVersion() > base::win::VERSION_VISTA) + gfx::EnableHighDPISupport(); + + sandbox::SandboxInterfaceInfo sandbox_info = {0}; content::InitializeSandboxInfo(&sandbox_info); content::ShellMainDelegate delegate; From c757ea97274b01bc62acabe2ef7e56f62c0d88fc Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 6 Nov 2014 15:50:17 +0800 Subject: [PATCH 249/492] [WIN] delay loading win8 dlls for notification Fix PR#2546 --- nw.gypi | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nw.gypi b/nw.gypi index 4f5bc3e44c..63ed0bf942 100644 --- a/nw.gypi +++ b/nw.gypi @@ -351,6 +351,14 @@ 'msvs_settings': { 'VCLinkerTool': { 'SubSystem': '2', # Set /SUBSYSTEM:WINDOWS + 'AdditionalDependencies': [ + 'runtimeobject.lib', + ], + 'DelayLoadDLLs': [ + 'API-MS-WIN-CORE-WINRT-ERROR-L1-1-0.DLL', + 'API-MS-WIN-CORE-WINRT-L1-1-0.DLL', + 'API-MS-WIN-CORE-WINRT-STRING-L1-1-0.DLL', + ], }, }, 'configurations': { From 9b1c32320f97e06cd9948b33b47c33aeb703ac09 Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 6 Nov 2014 21:58:45 +0800 Subject: [PATCH 250/492] Fix previous commit --- nw.gypi | 20 ++++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/nw.gypi b/nw.gypi index 63ed0bf942..d101914e6a 100644 --- a/nw.gypi +++ b/nw.gypi @@ -14,6 +14,18 @@ 'nw_use_commit_id%': ' Date: Sat, 13 Sep 2014 22:11:15 +0300 Subject: [PATCH 251/492] Fix #2299: Wrong mask logic in window.setResizable Calling window.setResizable(false) twice causes the window to be resizable, due to wrong XOR bitmask logic. This commit fixes it. --- src/browser/native_window_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index 0839d8ecde..14703797df 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -625,7 +625,7 @@ - (void)drawRect:(NSRect)dirtyRect { [window() setStyleMask:window().styleMask | NSResizableWindowMask]; } else { [[window() standardWindowButton:NSWindowZoomButton] setEnabled:NO]; - [window() setStyleMask:window().styleMask ^ NSResizableWindowMask]; + [window() setStyleMask:window().styleMask & ~NSResizableWindowMask]; } } From ef6af9bdb59543858735dd9aea7561c617e607af Mon Sep 17 00:00:00 2001 From: Daniel Braun Date: Sun, 14 Sep 2014 10:42:34 +0300 Subject: [PATCH 252/492] Updated AUTHORS --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index e75a5d52bd..9f056807fb 100644 --- a/AUTHORS +++ b/AUTHORS @@ -32,3 +32,4 @@ Joachim Bauch Cong Liu Eric Newport Marco Fabbri +Daniel Braun From a55c127bf6b3bcc7df01943365b8ec3127f9c7e9 Mon Sep 17 00:00:00 2001 From: Chase Willden Date: Fri, 7 Nov 2014 07:52:27 -0700 Subject: [PATCH 253/492] Added myself to authors --- AUTHORS | 1 + 1 file changed, 1 insertion(+) diff --git a/AUTHORS b/AUTHORS index 9f056807fb..c468b7237c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -33,3 +33,4 @@ Cong Liu Eric Newport Marco Fabbri Daniel Braun +Chase Willden \ No newline at end of file From 5ebe532277ff0a529d1caf598d46ebd8b507042d Mon Sep 17 00:00:00 2001 From: Jefry Date: Thu, 6 Nov 2014 17:28:53 +0800 Subject: [PATCH 254/492] fix dll dependency problem for non win8 Fix rogerwang/node-webkit#2568 Fix rogerwang/node-webkit#2574 --- src/nw_notification_manager_toast_win.cc | 24 ++++++++++++++++++++---- 1 file changed, 20 insertions(+), 4 deletions(-) diff --git a/src/nw_notification_manager_toast_win.cc b/src/nw_notification_manager_toast_win.cc index 211ce74e76..07e64661a7 100644 --- a/src/nw_notification_manager_toast_win.cc +++ b/src/nw_notification_manager_toast_win.cc @@ -39,7 +39,6 @@ #include #include #include -#pragma comment(lib, "runtimeobject.lib") using namespace Microsoft::WRL; using namespace Windows::Foundation; @@ -55,6 +54,14 @@ class StringReferenceWrapper // Warning: The caller must ensure the lifetime of the buffer outlives this // object as it does not make a copy of the wide string memory. + static bool isSupported() + { + static char cachedRes = -1; + if (cachedRes > -1) return cachedRes; + cachedRes = ::LoadLibrary(L"API-MS-WIN-CORE-WINRT-STRING-L1-1-0.DLL") != 0; + return cachedRes; + } + StringReferenceWrapper(_In_reads_(length) PCWSTR stringRef, _In_ UINT32 length) throw() { HRESULT hr = WindowsCreateStringReference(stringRef, length, &_header, &_hstring); @@ -359,9 +366,18 @@ HRESULT NotificationManagerToastWin::CreateToast(_In_ IToastNotificationManagerS } bool NotificationManagerToastWin::IsSupported() { - ComPtr toastStatics; - HRESULT hr = GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &toastStatics); - return SUCCEEDED(hr); + static char cachedRes = -1; + + if (cachedRes > -1) return cachedRes; + cachedRes = 0; + + if (StringReferenceWrapper::isSupported()) { + ComPtr toastStatics; + HRESULT hr = GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &toastStatics); + cachedRes = SUCCEEDED(hr); + } + + return cachedRes; } NotificationManagerToastWin::NotificationManagerToastWin() { From c3aea0d872bc1cc651712d9235ffe7906f83be5a Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 10 Nov 2014 13:46:06 +0800 Subject: [PATCH 255/492] Fix #2319: honor resizable flag --- src/browser/native_window_aura.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index 196210d958..faf35128ca 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -284,6 +284,7 @@ NativeWindowAura::NativeWindowAura(const base::WeakPtr& shell, last_width_(-1), last_height_(-1) { manifest->GetBoolean("focus", &initial_focus_); manifest->GetBoolean("fullscreen", &is_fullscreen_); + manifest->GetBoolean("resizable", &resizable_); window_ = new views::Widget; views::Widget::InitParams params(views::Widget::InitParams::TYPE_WINDOW); From ad30a9bcf814b15a13be9f844599f1499b5c6955 Mon Sep 17 00:00:00 2001 From: Kevin Fan Date: Mon, 10 Nov 2014 15:34:43 +0800 Subject: [PATCH 256/492] bump version to v0.11.0 --- src/nw_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nw_version.h b/src/nw_version.h index a22b3164c1..aa72aa18e7 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -24,7 +24,7 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 11 #define NW_PATCH_VERSION 0 -#define NW_VERSION_IS_RELEASE 0 +#define NW_VERSION_IS_RELEASE 1 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) From e5def1879f89e3b3daaef4c21252eb9226886ba1 Mon Sep 17 00:00:00 2001 From: Joachim Bauch Date: Mon, 10 Nov 2014 12:15:45 +0100 Subject: [PATCH 257/492] Don't activate app unconditionally on window "Show". Should fix #1032. --- src/browser/native_window_mac.mm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index 14703797df..b821fdb02b 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -478,7 +478,7 @@ - (void)drawRect:(NSRect)dirtyRect { void NativeWindowCocoa::Show() { NSApplication *myApp = [NSApplication sharedApplication]; - [myApp activateIgnoringOtherApps:YES]; + [myApp activateIgnoringOtherApps:NO]; content::RenderWidgetHostView* rwhv = shell_->web_contents()->GetRenderWidgetHostView(); From a694fae257e145d0465cf17209a27eff4a60ae4b Mon Sep 17 00:00:00 2001 From: Kevin Fan Date: Tue, 11 Nov 2014 19:02:58 +0800 Subject: [PATCH 258/492] [README] update for 0.11.0 --- CHANGELOG.md | 16 ++++++++++++++++ README.md | 14 ++++---------- 2 files changed, 20 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3d66d88c9b..47217814f6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,19 @@ +0.11.0 / 11-11-2014 +=================== +- Fix: notification and screen geometry API +- Fix: windows printing crash (#2515) +- Fix: mac: Fix build with 10.9 SDK +- Fix: enable 'high-dpi-support' for windows (#2524) +- Fix: 'resizable' is broken in manifest (#2319) +- Fix: crash on Flash context menu +- Fix: console.log() changes value (#2431) +- Fix: various crash cases (#2545, #2549) +- Fix: 'undefined' network request in devtools (#2529) +- Fix: devtools - breakpoints do not work (#2538) +- Fix: Jailed devtools broken in nw 0.11.0-rc1 (#2569) +- Fix: Window.setResizable(false) twice makes window resizable (#2299) +- Fix: win.setPosition('center') Invalid (#2307) + 0.11.0-rc1 / 10-27-2014 ======================= - Chromium updated to 38.0.2125.104 diff --git a/README.md b/README.md index 43daaedeae..5b99d156a2 100644 --- a/README.md +++ b/README.md @@ -21,17 +21,11 @@ It's created and developed in the Intel Open Source Technology Center. * Available on Linux, Mac OS X and Windows ## Downloads -* **v0.10.5:** (Sep 16, 2014, based off of Node v0.11.13, Chromium 35.0.1916.157): [release notes](https://groups.google.com/d/msg/node-webkit/l2PsW-0G5Oc/Fx19-UrS3ZoJ) +* **v0.11.0:** (Nov 11, 2014, based off of Node v0.11.13, Chromium 38.0.2125.104): [release notes](https://groups.google.com/d/msg/node-webkit/nDN1VclGRAA/_AKK5VIrH6gJ) - * Linux: [32bit](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-linux-x64.tar.gz) - * Windows: [win32](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-win-ia32.zip) - * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.10.5/node-webkit-v0.10.5-osx-x64.zip) - -* **v0.11.0-rc1:** (Oct 27, 2014, based off of Node v0.11.13, Chromium 38.0.2125.104): [release notes](https://groups.google.com/d/msg/node-webkit/ET8C5lYzpfk/7NfqM0LaPlEJ) - - * Linux: [32bit](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-linux-x64.tar.gz) - * Windows: [win32](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-win-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-win-x64.zip) - * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.0-rc1/node-webkit-v0.11.0-rc1-osx-x64.zip) + * Linux: [32bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-linux-x64.tar.gz) + * Windows: [32bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-win-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-win-x64.zip) + * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-osx-x64.zip) * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From 724ed4182578e6416975026e9081bea6ffef09c2 Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 13 Nov 2014 14:43:46 +0800 Subject: [PATCH 259/492] bump version to v0.11.1-pre --- src/mac/app-Info.plist | 2 +- src/nw_version.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/mac/app-Info.plist b/src/mac/app-Info.plist index 9ca35ff029..a8bd5a669c 100644 --- a/src/mac/app-Info.plist +++ b/src/mac/app-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.11.0 + 0.11.1 NSPrincipalClass NSApplication LSMinimumSystemVersion diff --git a/src/nw_version.h b/src/nw_version.h index aa72aa18e7..27d0d9a899 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -23,8 +23,8 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 11 -#define NW_PATCH_VERSION 0 -#define NW_VERSION_IS_RELEASE 1 +#define NW_PATCH_VERSION 1 +#define NW_VERSION_IS_RELEASE 0 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) @@ -38,7 +38,7 @@ #else # define NW_VERSION_STRING NW_STRINGIFY(NW_MAJOR_VERSION) "." \ NW_STRINGIFY(NW_MINOR_VERSION) "." \ - NW_STRINGIFY(NW_PATCH_VERSION) "-rc1" + NW_STRINGIFY(NW_PATCH_VERSION) "-pre" #endif #define NW_VERSION "v" NW_VERSION_STRING From d89780e4dd273b96c58e6c146eef4c3c0d70f194 Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 13 Nov 2014 21:22:27 +0800 Subject: [PATCH 260/492] Fix #2595: Linux MenuBar crash --- src/browser/menubar_controller.cc | 38 +++++++++++++++++++++++++++---- src/browser/menubar_controller.h | 10 ++++++-- src/browser/menubar_view.cc | 17 ++------------ src/browser/menubar_view.h | 1 - 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/src/browser/menubar_controller.cc b/src/browser/menubar_controller.cc index f70c78149d..b661117872 100644 --- a/src/browser/menubar_controller.cc +++ b/src/browser/menubar_controller.cc @@ -1,17 +1,31 @@ #include "content/nw/src/browser/menubar_controller.h" +#include "base/stl_util.h" #include "content/nw/src/browser/menubar_view.h" +#include "ui/views/controls/button/menu_button.h" #include "ui/views/controls/menu/menu_item_view.h" +#include "ui/views/widget/widget.h" namespace nw { MenuBarController::ModelToMenuMap MenuBarController::model_to_menu_map_; +MenuBarController* MenuBarController::master_; -MenuBarController::MenuBarController(MenuBarView* menubar, ui::MenuModel* menu_model) +MenuBarController::MenuBarController(MenuBarView* menubar, ui::MenuModel* menu_model, MenuBarController* master) :MenuModelAdapter(menu_model), menubar_(menubar) { + + views::MenuItemView* menu = MenuBarController::CreateMenu(menubar, menu_model, this); + if (!master) { + master_ = this; + menu_runner_.reset(new views::MenuRunner(menu, views::MenuRunner::HAS_MNEMONICS)); + } } MenuBarController::~MenuBarController() { + if (master_ == this) { + STLDeleteElements(&controllers_); + model_to_menu_map_.clear(); + } } views::MenuItemView* MenuBarController::GetSiblingMenu( @@ -30,14 +44,18 @@ views::MenuItemView* MenuBarController::GetSiblingMenu( *has_mnemonics = false; *anchor = views::MENU_ANCHOR_TOPLEFT; - if (!model_to_menu_map_[model]) - CreateMenu(menubar_, model); + if (!model_to_menu_map_[model]) { + MenuBarController* controller = new MenuBarController(menubar_, model, master_); + CreateMenu(menubar_, model, controller); + controllers_.push_back(controller); + } return model_to_menu_map_[model]; } -views::MenuItemView* MenuBarController::CreateMenu(MenuBarView* menubar, ui::MenuModel* model) { - MenuBarController* controller = new MenuBarController(menubar, model); +views::MenuItemView* MenuBarController::CreateMenu(MenuBarView* menubar, + ui::MenuModel* model, + MenuBarController* controller) { views::MenuItemView* menu = new views::MenuItemView(controller); controller->BuildMenu(menu); model_to_menu_map_[model] = menu; @@ -45,4 +63,14 @@ views::MenuItemView* MenuBarController::CreateMenu(MenuBarView* menubar, ui::Men return menu; } +void MenuBarController::RunMenuAt(views::View* view, const gfx::Point& point) { + + ignore_result(menu_runner_->RunMenuAt(view->GetWidget()->GetTopLevelWidget(), + static_cast(view), + gfx::Rect(point, gfx::Size()), + views::MENU_ANCHOR_TOPRIGHT, + ui::MENU_SOURCE_NONE)); + delete this; +} + } //namespace nw diff --git a/src/browser/menubar_controller.h b/src/browser/menubar_controller.h index 09f2e4284e..90be4c0209 100644 --- a/src/browser/menubar_controller.h +++ b/src/browser/menubar_controller.h @@ -2,6 +2,8 @@ #define NW_BROWSER_MENUBAR_CONTROLLER_H #include "ui/views/controls/menu/menu_model_adapter.h" +#include "ui/views/controls/menu/menu_runner.h" +#include "ui/views/view.h" #include @@ -14,10 +16,11 @@ class MenuBarView; class MenuBarController : public views::MenuModelAdapter { public: - MenuBarController(MenuBarView* menubar, ui::MenuModel* menu_model); + MenuBarController(MenuBarView* menubar, ui::MenuModel* menu_model, MenuBarController* master); virtual ~MenuBarController(); - static views::MenuItemView* CreateMenu(MenuBarView* menubar, ui::MenuModel* model); + static views::MenuItemView* CreateMenu(MenuBarView* menubar, ui::MenuModel* model, MenuBarController* controller); + void RunMenuAt(views::View* view, const gfx::Point& point); virtual views::MenuItemView* GetSiblingMenu( views::MenuItemView* menu, @@ -30,7 +33,10 @@ class MenuBarController : public views::MenuModelAdapter { typedef std::map ModelToMenuMap; MenuBarView* menubar_; + scoped_ptr menu_runner_; + std::vector controllers_; static ModelToMenuMap model_to_menu_map_; + static MenuBarController* master_; DISALLOW_COPY_AND_ASSIGN(MenuBarController); }; diff --git a/src/browser/menubar_view.cc b/src/browser/menubar_view.cc index 03e253a4b8..9aba44e7de 100644 --- a/src/browser/menubar_view.cc +++ b/src/browser/menubar_view.cc @@ -10,7 +10,6 @@ #include "ui/base/window_open_disposition.h" #include "ui/gfx/text_elider.h" #include "ui/views/controls/button/menu_button.h" -#include "ui/views/controls/menu/menu_runner.h" #include "ui/views/layout/box_layout.h" #include "ui/views/widget/widget.h" @@ -112,20 +111,8 @@ void MenuBarView::OnMenuButtonClicked(views::View* view, DCHECK_NE(-1, button_index); ui::MenuModel::ItemType type = model_->GetTypeAt(button_index); if (type == ui::MenuModel::TYPE_SUBMENU) { - views::MenuItemView* menu = MenuBarController::CreateMenu(this, model_->GetSubmenuModelAt(button_index)); - menu_runner_.reset(new MenuRunner(menu, MenuRunner::HAS_MNEMONICS)); - - // menu_runner_.reset(new MenuRunner(model_->GetSubmenuModelAt(button_index), - // MenuRunner::HAS_MNEMONICS)); - - if (menu_runner_->RunMenuAt(GetWidget()->GetTopLevelWidget(), - static_cast(view), - gfx::Rect(point, gfx::Size()), - views::MENU_ANCHOR_TOPRIGHT, - ui::MENU_SOURCE_NONE) == - MenuRunner::MENU_DELETED) { - return; - } + MenuBarController* controller = new MenuBarController(this, model_->GetSubmenuModelAt(button_index), NULL); + controller->RunMenuAt(view, point); } } diff --git a/src/browser/menubar_view.h b/src/browser/menubar_view.h index 74e9330145..51615101a8 100644 --- a/src/browser/menubar_view.h +++ b/src/browser/menubar_view.h @@ -59,7 +59,6 @@ class MenuBarView : private: ui::MenuModel* model_; - scoped_ptr menu_runner_; DISALLOW_COPY_AND_ASSIGN(MenuBarView); }; } //namespace nw From e8d9223399736089ea914f21b3cd93a9770b2f15 Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 13 Nov 2014 22:04:11 +0800 Subject: [PATCH 261/492] Fix #2592: zoomLevel --- src/api/dispatcher.cc | 5 +---- src/api/dispatcher.h | 3 ++- src/api/window_bindings.cc | 6 ++++-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/api/dispatcher.cc b/src/api/dispatcher.cc index 9fa708394c..a8583d5214 100644 --- a/src/api/dispatcher.cc +++ b/src/api/dispatcher.cc @@ -136,12 +136,10 @@ v8::Handle Dispatcher::GetWindowId(blink::WebFrame* frame) { return val; } -#if 0 //FIXME -void Dispatcher::ZoomLevelChanged() { +void Dispatcher::ZoomLevelChanged(blink::WebView* web_view) { v8::Isolate* isolate = v8::Isolate::GetCurrent(); v8::HandleScope scope(isolate); - blink::WebView* web_view = render_view()->GetWebView(); float zoom_level = web_view->zoomLevel(); v8::Handle val = GetWindowId(web_view->mainFrame()); @@ -161,7 +159,6 @@ void Dispatcher::ZoomLevelChanged() { node::MakeCallback(isolate, objects_registry, "handleEvent", 3, argv); } -#endif void Dispatcher::DidCreateDocumentElement(blink::WebLocalFrame* frame) { documentCallback("document-start", frame); diff --git a/src/api/dispatcher.h b/src/api/dispatcher.h index 8649a8a605..90298000fc 100644 --- a/src/api/dispatcher.h +++ b/src/api/dispatcher.h @@ -37,6 +37,7 @@ class RenderView; namespace blink { class WebFrame; class WebURLRequest; +class WebView; } namespace nwapi { @@ -48,6 +49,7 @@ class Dispatcher : public content::RenderViewObserver { static v8::Handle GetObjectRegistry(); static v8::Handle GetWindowId(blink::WebFrame* frame); + static void ZoomLevelChanged(blink::WebView* web_view); static void willHandleNavigationPolicy( content::RenderView* rv, blink::WebFrame* frame, @@ -58,7 +60,6 @@ class Dispatcher : public content::RenderViewObserver { // RenderViewObserver implementation. virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; virtual void DraggableRegionsChanged(blink::WebFrame* frame) OVERRIDE; - //FIXME virtual void ZoomLevelChanged() OVERRIDE; virtual void DidFinishDocumentLoad(blink::WebLocalFrame* frame) OVERRIDE; virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) OVERRIDE; diff --git a/src/api/window_bindings.cc b/src/api/window_bindings.cc index f760c3cd00..0c249471e2 100644 --- a/src/api/window_bindings.cc +++ b/src/api/window_bindings.cc @@ -24,6 +24,7 @@ #include "base/values.h" #include "content/child/child_thread.h" #include "content/nw/src/api/bindings_common.h" +#include "content/nw/src/api/dispatcher.h" #include "content/renderer/render_view_impl.h" #include "grit/nw_resources.h" #undef LOG @@ -185,8 +186,9 @@ WindowBindings::CallObjectMethodSync(const v8::FunctionCallbackInfo& args.GetReturnValue().Set(scope.Escape(array)); return; }else if (method == "SetZoomLevel") { - // double zoom_level = args[2]->ToNumber()->Value(); - //FIXME: render_view->OnSetZoomLevel(zoom_level); + double zoom_level = args[2]->ToNumber()->Value(); + render_view->GetWebView()->setZoomLevel(zoom_level); + nwapi::Dispatcher::ZoomLevelChanged(render_view->GetWebView()); args.GetReturnValue().Set(v8::Undefined(isolate)); return; } From aa802b47ab071f948fe3ed9c3578d9e9c768cfad Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 14 Nov 2014 13:51:07 +0800 Subject: [PATCH 262/492] Revert "disable nwsnapshot for now" This reverts commit 3f795f4b0131583f1128ed25ab88c7265f6bceaa. Fix #2594 --- nw.gypi | 4 ++-- tools/package_binaries.py | 6 +++--- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/nw.gypi b/nw.gypi index d101914e6a..bb42e590d1 100644 --- a/nw.gypi +++ b/nw.gypi @@ -755,7 +755,7 @@ { 'action_name': 'strip_nw_binaries', 'inputs': [ - #'<(PRODUCT_DIR)/nwsnapshot', + '<(PRODUCT_DIR)/nwsnapshot', '<(PRODUCT_DIR)/chromedriver', ], 'outputs': [ @@ -767,7 +767,7 @@ }, ], 'dependencies': [ - # '<(DEPTH)/v8/tools/gyp/v8.gyp:nwsnapshot', + '<(DEPTH)/v8/tools/gyp/v8.gyp:nwsnapshot', '<(DEPTH)/chrome/chrome.gyp:chromedriver', ], }], diff --git a/tools/package_binaries.py b/tools/package_binaries.py index 2d62a3bee4..d5ce274700 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -118,7 +118,7 @@ def generate_target_nw(platform_name, arch, version): 'credits.html', 'libffmpegsumo.so', 'nw.pak', - #'nwsnapshot', + 'nwsnapshot', 'nw', 'icudtl.dat', 'locales', @@ -132,13 +132,13 @@ def generate_target_nw(platform_name, arch, version): 'nw.exe', 'nw.pak', 'locales', - #'nwsnapshot.exe', + 'nwsnapshot.exe', 'credits.html', ] elif platform_name == 'osx': target['input'] = [ 'node-webkit.app', - #'nwsnapshot', + 'nwsnapshot', 'credits.html', ] else: From 324ebf18736186bf95d5f4b345b8050537cbbaab Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 18 Nov 2014 15:44:13 +0800 Subject: [PATCH 263/492] Fix #916: Support SetProxyConfig API --- src/api/app/app.cc | 59 ++++++++++++++++++++++++++++++++++++++-------- src/api/app/app.h | 2 ++ src/api/app/app.js | 4 ++++ 3 files changed, 55 insertions(+), 10 deletions(-) diff --git a/src/api/app/app.cc b/src/api/app/app.cc index cd933b4efd..7dd6befdaf 100644 --- a/src/api/app/app.cc +++ b/src/api/app/app.cc @@ -44,10 +44,17 @@ #include "content/nw/src/nw_shell.h" #include "content/nw/src/shell_browser_context.h" #include "content/common/view_messages.h" +#include "content/public/browser/browser_thread.h" #include "content/public/browser/web_contents.h" #include "content/public/browser/render_process_host.h" +#include "net/proxy/proxy_config.h" +#include "net/proxy/proxy_config_service_fixed.h" +#include "net/proxy/proxy_service.h" +#include "net/url_request/url_request_context.h" +#include "net/url_request/url_request_context_getter.h" using base::MessageLoop; +using content::BrowserThread; using content::Shell; using content::ShellBrowserContext; using content::RenderProcessHost; @@ -81,6 +88,17 @@ void GetRenderProcessHosts(std::set& rphs) { } } +void SetProxyConfigCallback( + base::WaitableEvent* done, + net::URLRequestContextGetter* url_request_context_getter, + const net::ProxyConfig& proxy_config) { + net::ProxyService* proxy_service = + url_request_context_getter->GetURLRequestContext()->proxy_service(); + proxy_service->ResetConfigService( + new net::ProxyConfigServiceFixed(proxy_config)); + done->Signal(); +} + } // namespace // static @@ -133,16 +151,16 @@ void App::Call(Shell* shell, #if defined(OS_WIN) base::string16 path; arguments.GetString(0, &path); - - base::win::ShortcutProperties props; - base::string16 appID; - if (content::Shell::GetPackage()->root()->GetString("app-id", &appID) == false) - content::Shell::GetPackage()->root()->GetString(switches::kmName, &appID); - const std::wstring appName = base::UTF8ToWide(content::Shell::GetPackage()->GetName()); - props.set_app_id(appID); - - base::FilePath processPath; - PathService::Get(base::FILE_EXE, &processPath); + + base::win::ShortcutProperties props; + base::string16 appID; + if (content::Shell::GetPackage()->root()->GetString("app-id", &appID) == false) + content::Shell::GetPackage()->root()->GetString(switches::kmName, &appID); + const std::wstring appName = base::UTF8ToWide(content::Shell::GetPackage()->GetName()); + props.set_app_id(appID); + + base::FilePath processPath; + PathService::Get(base::FILE_EXE, &processPath); props.set_target(processPath); result->AppendBoolean(base::win::CreateOrUpdateShortcutLink(base::FilePath(path), props, base::win::SHORTCUT_CREATE_ALWAYS)); #else @@ -177,6 +195,11 @@ void App::Call(Shell* shell, GlobalShortcutListener::GetInstance()->UnregisterAccelerator( shortcut->GetAccelerator(), shortcut); return; + } else if (method == "SetProxyConfig") { + std::string proxy_config; + arguments.GetString(0, &proxy_config); + SetProxyConfig(GetRenderProcessHost(), proxy_config); + return; } NOTREACHED() << "Calling unknown sync method " << method << " of App"; @@ -266,4 +289,20 @@ void App::ClearCache(content::RenderProcessHost* render_process_host) { render_process_host->GetID()); } +void App::SetProxyConfig(content::RenderProcessHost* render_process_host, + const std::string& proxy_config) { + net::ProxyConfig config; + config.proxy_rules().ParseFromString(proxy_config); + net::URLRequestContextGetter* context_getter = + render_process_host->GetBrowserContext()-> + GetRequestContextForRenderProcess(render_process_host->GetID()); + + base::WaitableEvent done(false, false); + BrowserThread::PostTask( + BrowserThread::IO, FROM_HERE, + base::Bind(&SetProxyConfigCallback, &done, + make_scoped_refptr(context_getter), config)); + done.Wait(); + +} } // namespace nwapi diff --git a/src/api/app/app.h b/src/api/app/app.h index 9cee82ab93..34707436da 100644 --- a/src/api/app/app.h +++ b/src/api/app/app.h @@ -60,6 +60,8 @@ class App { static void EmitReopenEvent(); static void ClearCache(content::RenderProcessHost* render_view_host); + static void SetProxyConfig(content::RenderProcessHost* render_process_host, + const std::string& proxy_config); private: App(); diff --git a/src/api/app/app.js b/src/api/app/app.js index 99ff349dfa..52481c5531 100644 --- a/src/api/app/app.js +++ b/src/api/app/app.js @@ -65,6 +65,10 @@ App.prototype.getProxyForURL = function (url) { return nw.callStaticMethodSync('App', 'getProxyForURL', [ url ]); } +App.prototype.setProxyConfig = function (proxy_config) { + return nw.callStaticMethodSync('App', 'SetProxyConfig', [ proxy_config ]); +} + App.prototype.addOriginAccessWhitelistEntry = function(sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains) { return nw.callStaticMethodSync('App', 'AddOriginAccessWhitelistEntry', sourceOrigin, destinationProtocol, destinationHost, allowDestinationSubdomains); } From ec801e3782f3d29962c42aa5a5cae268db53005c Mon Sep 17 00:00:00 2001 From: Jefry Date: Fri, 14 Nov 2014 17:34:36 +0800 Subject: [PATCH 264/492] [Notification] fix "Cancel Desktop Notification" for all platform. and implement it for win8 (toast notification) --- src/nw_notification_manager_toast_win.cc | 65 +++++++++++++----------- src/nw_notification_manager_toast_win.h | 7 +++ src/shell_content_browser_client.cc | 10 ++++ 3 files changed, 51 insertions(+), 31 deletions(-) diff --git a/src/nw_notification_manager_toast_win.cc b/src/nw_notification_manager_toast_win.cc index 07e64661a7..d34ed4bb82 100644 --- a/src/nw_notification_manager_toast_win.cc +++ b/src/nw_notification_manager_toast_win.cc @@ -37,10 +37,8 @@ #include #include -#include #include -using namespace Microsoft::WRL; using namespace Windows::Foundation; namespace nw { @@ -198,6 +196,7 @@ IFACEMETHODIMP ToastEventHandler::Invoke(_In_ IToastNotification* /* sender */, BOOL succeeded = nw::NotificationManager::getSingleton()->DesktopNotificationPostClose(_render_process_id, _render_frame_id, _notification_id, tdr == ToastDismissalReason_UserCanceled); hr = succeeded ? S_OK : E_FAIL; } + nw::NotificationManager::getSingleton()->CancelDesktopNotification(_render_process_id, _render_frame_id, _notification_id); return hr; } @@ -326,37 +325,28 @@ HRESULT NotificationManagerToastWin::CreateToastXml(_In_ IToastNotificationManag HRESULT NotificationManagerToastWin::CreateToast(_In_ IToastNotificationManagerStatics *toastManager, _In_ IXmlDocument *xml, const int render_process_id, const int render_frame_id, const int notification_id) { - base::string16 appID; - if (content::Shell::GetPackage()->root()->GetString("app-id", &appID) == false) - content::Shell::GetPackage()->root()->GetString(switches::kmName, &appID); - - ComPtr notifier; - HRESULT hr = toastManager->CreateToastNotifierWithId(StringReferenceWrapper(appID.c_str(), appID.length()).Get(), ¬ifier); + ComPtr factory; + HRESULT hr = GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &factory); if (SUCCEEDED(hr)) { - ComPtr factory; - hr = GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotification).Get(), &factory); + ComPtr& toast = notification_map_[notification_id]; + hr = factory->CreateToastNotification(xml, &toast); if (SUCCEEDED(hr)) { - ComPtr toast; - hr = factory->CreateToastNotification(xml, &toast); + // Register the event handlers + EventRegistrationToken activatedToken, dismissedToken, failedToken; + ComPtr eventHandler = new ToastEventHandler(render_process_id, render_frame_id, notification_id); + + hr = toast->add_Activated(eventHandler.Get(), &activatedToken); if (SUCCEEDED(hr)) { - // Register the event handlers - EventRegistrationToken activatedToken, dismissedToken, failedToken; - ComPtr eventHandler = new ToastEventHandler(render_process_id, render_frame_id, notification_id); - - hr = toast->add_Activated(eventHandler.Get(), &activatedToken); + hr = toast->add_Dismissed(eventHandler.Get(), &dismissedToken); if (SUCCEEDED(hr)) { - hr = toast->add_Dismissed(eventHandler.Get(), &dismissedToken); + hr = toast->add_Failed(eventHandler.Get(), &failedToken); if (SUCCEEDED(hr)) { - hr = toast->add_Failed(eventHandler.Get(), &failedToken); - if (SUCCEEDED(hr)) - { - hr = notifier->Show(toast.Get()); - } + hr = notifier_->Show(toast.Get()); } } } @@ -381,6 +371,15 @@ bool NotificationManagerToastWin::IsSupported() { } NotificationManagerToastWin::NotificationManagerToastWin() { + HRESULT hr = GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &toastStatics_); + if (SUCCEEDED(hr)) + { + base::string16 appID; + if (content::Shell::GetPackage()->root()->GetString("app-id", &appID) == false) + content::Shell::GetPackage()->root()->GetString(switches::kmName, &appID); + + HRESULT hr = toastStatics_->CreateToastNotifierWithId(StringReferenceWrapper(appID.c_str(), appID.length()).Get(), ¬ifier_); + } } NotificationManagerToastWin::~NotificationManagerToastWin() { @@ -395,24 +394,28 @@ bool NotificationManagerToastWin::AddDesktopNotification(const content::ShowDesk if (host == NULL) return false; - ComPtr toastStatics; - HRESULT hr = GetActivationFactory(StringReferenceWrapper(RuntimeClass_Windows_UI_Notifications_ToastNotificationManager).Get(), &toastStatics); - if (SUCCEEDED(hr)) - { + ComPtr toastXml; - hr = CreateToastXml(toastStatics.Get(), params, &toastXml); + HRESULT hr = CreateToastXml(toastStatics_.Get(), params, &toastXml); if (SUCCEEDED(hr)) { - hr = CreateToast(toastStatics.Get(), toastXml.Get(), render_process_id, render_frame_id, notification_id); + hr = CreateToast(toastStatics_.Get(), toastXml.Get(), render_process_id, render_frame_id, notification_id); if (SUCCEEDED(hr)) DesktopNotificationPostDisplay(render_process_id, render_frame_id, notification_id); } - } + return SUCCEEDED(hr); } bool NotificationManagerToastWin::CancelDesktopNotification(int render_process_id, int render_frame_id, int notification_id) { - return true; + std::map>::iterator i = notification_map_.find(notification_id); + if (i == notification_map_.end()) + return false; + + ComPtr toast = i->second; + notification_map_.erase(i); + + return SUCCEEDED(notifier_->Hide(toast.Get())); } } // namespace nw diff --git a/src/nw_notification_manager_toast_win.h b/src/nw_notification_manager_toast_win.h index 3b22b0d44a..87415bdef7 100644 --- a/src/nw_notification_manager_toast_win.h +++ b/src/nw_notification_manager_toast_win.h @@ -22,13 +22,20 @@ #include "content/nw/src/nw_notification_manager.h" #include +#include + namespace nw { + using namespace Microsoft::WRL; using namespace ABI::Windows::UI::Notifications; using namespace ABI::Windows::Data::Xml::Dom; class NotificationManagerToastWin : public NotificationManager{ + ComPtr toastStatics_; + ComPtr notifier_; + std::map> notification_map_; + // internal function for AddDesktopNotification virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, const int render_process_id, const int render_frame_id, const int notification_id, diff --git a/src/shell_content_browser_client.cc b/src/shell_content_browser_client.cc index 9a12ea7ee1..1d717b6d15 100644 --- a/src/shell_content_browser_client.cc +++ b/src/shell_content_browser_client.cc @@ -495,6 +495,15 @@ ShellContentBrowserClient::CreateQuotaPermissionContext() { return new ShellQuotaPermissionContext(); } +void CancelDesktopNotification(int render_process_id, int render_frame_id, int notification_id) { + nw::NotificationManager *notificationManager = nw::NotificationManager::getSingleton(); + if (notificationManager == NULL) { + NOTIMPLEMENTED(); + return; + } + notificationManager->CancelDesktopNotification(render_process_id, render_frame_id, notification_id); +} + void ShellContentBrowserClient::ShowDesktopNotification( const ShowDesktopNotificationHostMsgParams& params, RenderFrameHost* render_frame_host, @@ -511,6 +520,7 @@ void ShellContentBrowserClient::ShowDesktopNotification( render_frame_host->GetRoutingID(), delegate->notification_id(), false); + *cancel_callback = base::Bind(&CancelDesktopNotification, process->GetID(), render_frame_host->GetRoutingID(), delegate->notification_id()); #else NOTIMPLEMENTED(); #endif From 7628a18de636c8ac207ece62cc8c2a62f4fc44d9 Mon Sep 17 00:00:00 2001 From: Jefry Date: Tue, 18 Nov 2014 16:11:46 +0800 Subject: [PATCH 265/492] [Notification] fallback to balloon notification if toast notification fail --- src/nw_notification_manager_toast_win.cc | 21 ++++++++++++++++++--- src/nw_notification_manager_toast_win.h | 2 ++ 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/nw_notification_manager_toast_win.cc b/src/nw_notification_manager_toast_win.cc index d34ed4bb82..5a36f7f14b 100644 --- a/src/nw_notification_manager_toast_win.cc +++ b/src/nw_notification_manager_toast_win.cc @@ -201,13 +201,28 @@ IFACEMETHODIMP ToastEventHandler::Invoke(_In_ IToastNotification* /* sender */, } // DesktopToastFailedEventHandler -IFACEMETHODIMP ToastEventHandler::Invoke(_In_ IToastNotification* /* sender */, _In_ IToastFailedEventArgs* /* e */) +IFACEMETHODIMP ToastEventHandler::Invoke(_In_ IToastNotification* /* sender */, _In_ IToastFailedEventArgs* e) { - BOOL succeeded = nw::NotificationManager::getSingleton()->DesktopNotificationPostError(_render_process_id, _render_frame_id, _notification_id, L"The toast encountered an error."); + HRESULT errCode; + e->get_ErrorCode(&errCode); + nw::NotificationManagerToastWin* nmtw = static_cast(nw::NotificationManager::getSingleton()); + std::wstringstream errMsg; errMsg << L"The toast encountered an error code (0x" << std::hex << errCode <<")."; + const bool fallBack = errCode == 0x80070490; + if (fallBack) + errMsg << " Fallback to balloon notification!"; + + BOOL succeeded = nmtw->DesktopNotificationPostError(_render_process_id, _render_frame_id, _notification_id, errMsg.str().c_str()); + nmtw->notification_map_.erase(_notification_id); + + if (fallBack) { + NotificationManagerToastWin::ForceDisable = true; + delete nmtw; + } return succeeded ? S_OK : E_FAIL; } // ============= NotificationManagerToastWin Implementation ============= +bool NotificationManagerToastWin::ForceDisable = false; HRESULT NotificationManagerToastWin::SetNodeValueString(_In_ HSTRING inputString, _In_ IXmlNode *node, _In_ IXmlDocument *xml) { @@ -357,7 +372,7 @@ HRESULT NotificationManagerToastWin::CreateToast(_In_ IToastNotificationManagerS bool NotificationManagerToastWin::IsSupported() { static char cachedRes = -1; - + if (ForceDisable) return false; if (cachedRes > -1) return cachedRes; cachedRes = 0; diff --git a/src/nw_notification_manager_toast_win.h b/src/nw_notification_manager_toast_win.h index 87415bdef7..bf9c28206b 100644 --- a/src/nw_notification_manager_toast_win.h +++ b/src/nw_notification_manager_toast_win.h @@ -31,10 +31,12 @@ namespace nw { using namespace ABI::Windows::Data::Xml::Dom; class NotificationManagerToastWin : public NotificationManager{ + friend class ToastEventHandler; ComPtr toastStatics_; ComPtr notifier_; std::map> notification_map_; + static bool ForceDisable; // internal function for AddDesktopNotification virtual bool AddDesktopNotification(const content::ShowDesktopNotificationHostMsgParams& params, From e7ff868f60722ce27e22e19f95e123bdccd2c891 Mon Sep 17 00:00:00 2001 From: Jefry Date: Thu, 11 Sep 2014 18:22:13 +0800 Subject: [PATCH 266/492] [Transparency] add javascript function and manifest, OSX Implementation, stubs for Linux/Windows --- src/api/window/window.cc | 7 +++++++ src/api/window_bindings.js | 9 +++++++++ src/browser/native_window.cc | 2 ++ src/browser/native_window.h | 4 ++++ src/browser/native_window_aura.h | 1 + src/browser/native_window_gtk.h | 1 + src/browser/native_window_mac.h | 4 ++++ src/browser/native_window_mac.mm | 31 +++++++++++++++++++++++++++++-- src/common/shell_switches.cc | 1 + src/common/shell_switches.h | 1 + src/nw_shell.cc | 1 + 11 files changed, 60 insertions(+), 2 deletions(-) diff --git a/src/api/window/window.cc b/src/api/window/window.cc index 5d54d02e20..9765f51905 100644 --- a/src/api/window/window.cc +++ b/src/api/window/window.cc @@ -268,6 +268,10 @@ void Window::Call(const std::string& method, std::string label; if (arguments.GetString(0, &label)) shell_->window()->SetBadgeLabel(label); + } else if (method == "SetTransparent") { + bool transparent; + if (arguments.GetBoolean(0, &transparent)) + shell_->window()->SetTransparent(transparent); } else if (method == "SetProgressBar") { double progress; if (arguments.GetDouble(0, &progress)) @@ -315,6 +319,9 @@ void Window::CallSync(const std::string& method, gfx::Point position = shell_->window()->GetPosition(); result->AppendInteger(position.x()); result->AppendInteger(position.y()); + } else if (method == "IsTransparent") { + bool transparent = shell_->window()->IsTransparent(); + result->AppendBoolean(transparent); } else if (method == "IsDevToolsOpen") { result->AppendBoolean(shell_->devToolsOpen()); } else if (method == "ShowDevTools") { diff --git a/src/api/window_bindings.js b/src/api/window_bindings.js index 570e8094c6..ae11ec9ad9 100644 --- a/src/api/window_bindings.js +++ b/src/api/window_bindings.js @@ -249,6 +249,11 @@ Window.prototype.__defineGetter__('isFullscreen', function() { var result = CallObjectMethodSync(this, 'IsFullscreen', []); return Boolean(result[0]); }); + +Window.prototype.__defineGetter__('isTransparent', function() { + var result = CallObjectMethodSync(this, 'IsTransparent', []); + return Boolean(result[0]); +}); Window.prototype.__defineSetter__('isKioskMode', function(flag) { if (flag) @@ -425,6 +430,10 @@ Window.prototype.setProgressBar = function(progress) { throw new String('progress must be a number'); CallObjectMethod(this, 'SetProgressBar', [ progress ]); } + +Window.prototype.setTransparent = function(transparent) { + CallObjectMethod(this, 'SetTransparent', [ transparent ]); +} Window.prototype.setPosition = function(position) { if (position != 'center' && position != 'mouse') diff --git a/src/browser/native_window.cc b/src/browser/native_window.cc index 548e2c763b..7168893b61 100644 --- a/src/browser/native_window.cc +++ b/src/browser/native_window.cc @@ -69,9 +69,11 @@ NativeWindow* NativeWindow::Create(const base::WeakPtr& shell, NativeWindow::NativeWindow(const base::WeakPtr& shell, base::DictionaryValue* manifest) : shell_(shell), + transparent_(false), has_frame_(true), capture_page_helper_(NULL) { manifest->GetBoolean(switches::kmFrame, &has_frame_); + manifest->GetBoolean(switches::kmTransparent, &transparent_); LoadAppIconFromPackage(manifest); } diff --git a/src/browser/native_window.h b/src/browser/native_window.h index b01a830a23..da72f275a1 100644 --- a/src/browser/native_window.h +++ b/src/browser/native_window.h @@ -88,6 +88,7 @@ class NativeWindow { virtual void Restore() = 0; virtual void SetFullscreen(bool fullscreen) = 0; virtual bool IsFullscreen() = 0; + virtual void SetTransparent(bool transparent) = 0; virtual void SetSize(const gfx::Size& size) = 0; virtual gfx::Size GetSize() = 0; virtual void SetMinimumSize(int width, int height) = 0; @@ -140,6 +141,7 @@ class NativeWindow { bool has_frame() const { return has_frame_; } const gfx::Image& app_icon() const { return app_icon_; } void CapturePage(const std::string& image_format); + bool IsTransparent() { return transparent_; } protected: void OnNativeWindowDestory() { @@ -151,6 +153,8 @@ class NativeWindow { // Weak reference to parent. base::WeakPtr shell_; + + bool transparent_; bool has_frame_; diff --git a/src/browser/native_window_aura.h b/src/browser/native_window_aura.h index b3d7585ca2..98b8e43243 100644 --- a/src/browser/native_window_aura.h +++ b/src/browser/native_window_aura.h @@ -78,6 +78,7 @@ class NativeWindowAura : public NativeWindow, virtual void Restore() OVERRIDE; virtual void SetFullscreen(bool fullscreen) OVERRIDE; virtual bool IsFullscreen() OVERRIDE; + virtual void SetTransparent(bool transparent) OVERRIDE; virtual void SetSize(const gfx::Size& size) OVERRIDE; virtual gfx::Size GetSize() OVERRIDE; virtual void SetMinimumSize(int width, int height) OVERRIDE; diff --git a/src/browser/native_window_gtk.h b/src/browser/native_window_gtk.h index f9265432e0..c0a9111519 100644 --- a/src/browser/native_window_gtk.h +++ b/src/browser/native_window_gtk.h @@ -48,6 +48,7 @@ class NativeWindowGtk : public NativeWindow { virtual void Restore() OVERRIDE; virtual void SetFullscreen(bool fullscreen) OVERRIDE; virtual bool IsFullscreen() OVERRIDE; + virtual void SetTransparent(bool transparent) OVERRIDE; virtual void SetSize(const gfx::Size& size) OVERRIDE; virtual gfx::Size GetSize() OVERRIDE; virtual void SetMinimumSize(int width, int height) OVERRIDE; diff --git a/src/browser/native_window_mac.h b/src/browser/native_window_mac.h index 28f05080e3..7283c1a97c 100644 --- a/src/browser/native_window_mac.h +++ b/src/browser/native_window_mac.h @@ -52,6 +52,7 @@ class NativeWindowCocoa : public NativeWindow { virtual void Restore() OVERRIDE; virtual void SetFullscreen(bool fullscreen) OVERRIDE; virtual bool IsFullscreen() OVERRIDE; + virtual void SetTransparent(bool transparent) OVERRIDE; virtual void SetSize(const gfx::Size& size) OVERRIDE; virtual gfx::Size GetSize() OVERRIDE; virtual void SetMinimumSize(int width, int height) OVERRIDE; @@ -111,6 +112,9 @@ class NativeWindowCocoa : public NativeWindow { // Delegate to the toolbar. base::scoped_nsobject toolbar_delegate_; + + // Data for transparency + NSColor *opaque_color_; bool is_fullscreen_; bool is_kiosk_; diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index b821fdb02b..b572552c82 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -35,7 +35,7 @@ #include "content/nw/src/nw_package.h" #include "content/nw/src/nw_shell.h" #include "content/public/browser/native_web_keyboard_event.h" -#include "content/public/browser/render_widget_host_view.h" +#include "content/browser/renderer_host/render_widget_host_view_mac.h" #include "content/public/browser/web_contents.h" #include "extensions/common/draggable_region.h" #include "third_party/skia/include/core/SkRegion.h" @@ -282,7 +282,11 @@ - (void)drawCustomFrameRect:(NSRect)rect forView:(NSView*)view { [[NSBezierPath bezierPathWithRoundedRect:[view bounds] xRadius:cornerRadius yRadius:cornerRadius] addClip]; - [[NSColor whiteColor] set]; + if ([self isOpaque]) + [[NSColor whiteColor] set]; + else + [[NSColor clearColor] set]; + NSRectFill(rect); } @@ -385,10 +389,13 @@ - (void)drawRect:(NSRect)dirtyRect { defer:NO]; } window_ = shell_window; + opaque_color_ = [window() backgroundColor]; [shell_window setShell:shell]; [[window() contentView] setWantsLayer:YES]; [window() setDelegate:[[NativeWindowDelegate alloc] initWithShell:shell]]; + SetTransparent(transparent_); + // Disable fullscreen button when 'fullscreen' is specified to false. bool fullscreen; if (!(manifest->GetBoolean(switches::kmFullscreen, &fullscreen) && @@ -539,6 +546,26 @@ - (void)drawRect:(NSRect)dirtyRect { return is_fullscreen_; } +void NativeWindowCocoa::SetTransparent(bool transparent) { + + if (!transparent_ && transparent) { + opaque_color_ = [window() backgroundColor]; + } + + [window() setHasShadow:transparent ? NO : YES]; + [window() setOpaque:transparent ? NO : YES]; + [window() setBackgroundColor:transparent ? [NSColor clearColor] : opaque_color_]; + + content::RenderWidgetHostViewMac* rwhv = static_cast(shell_->web_contents()->GetRenderWidgetHostView()); + + if (rwhv) { + rwhv->SetBackgroundOpaque(!transparent); + [rwhv->background_layer_ setBackgroundColor:CGColorGetConstantColor(transparent ? kCGColorClear : kCGColorWhite)]; + } + + transparent_ = transparent; + +} void NativeWindowCocoa::SetNonLionFullscreen(bool fullscreen) { if (fullscreen == is_fullscreen_) return; diff --git a/src/common/shell_switches.cc b/src/common/shell_switches.cc index be6bb8c1ed..ed77eb444d 100644 --- a/src/common/shell_switches.cc +++ b/src/common/shell_switches.cc @@ -72,6 +72,7 @@ const char kmResizable[] = "resizable"; const char kmAsDesktop[] = "as_desktop"; const char kmFullscreen[] = "fullscreen"; const char kmInitialFocus[] = "focus"; +const char kmTransparent[] = "transparent"; // Make windows icon hide show or hide in taskbar. const char kmShowInTaskbar[] = "show_in_taskbar"; diff --git a/src/common/shell_switches.h b/src/common/shell_switches.h index 2eaf0d2814..2a8264805e 100644 --- a/src/common/shell_switches.h +++ b/src/common/shell_switches.h @@ -54,6 +54,7 @@ extern const char kmShowInTaskbar[]; extern const char kmKiosk[]; extern const char kmAlwaysOnTop[]; extern const char kmInitialFocus[]; +extern const char kmTransparent[]; extern const char kmWebgl[]; extern const char kmJava[]; diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 61c88671cf..dd7a398b93 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -710,6 +710,7 @@ GURL Shell::OverrideDOMStorageOrigin(const GURL& origin) { void Shell::RenderViewCreated(RenderViewHost* render_view_host) { //FIXME: handle removal new nwapi::DispatcherHost(render_view_host); + window()->SetTransparent(window()->IsTransparent()); } #if defined(OS_WIN) || defined(OS_LINUX) From e837e004dad86e52ef230e0c7e0243e02ce7b864 Mon Sep 17 00:00:00 2001 From: Jefry Date: Wed, 1 Oct 2014 13:59:37 +0800 Subject: [PATCH 267/492] [Transparency][WIN/Linux] rebase for the new chrome (+1 squashed commits) Squashed commits: [393645c] [Transparency][Win] add d3dcompiler_46 when packaging, fix the marginVal for compatibility (+1 squashed commits) Squashed commits: [26d1c7e] [Transparency][WIN] implement the windowsversion, changing the style, and background --- src/browser/native_window_aura.cc | 85 +++++++++++++++++++++++++++++++ tools/package_binaries.py | 1 + 2 files changed, 86 insertions(+) diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index faf35128ca..f865ba4ad3 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -22,10 +22,12 @@ #if defined(OS_WIN) #include +#include #endif #include "base/strings/utf_string_conversions.h" #include "base/values.h" +#include "base/command_line.h" #if defined(OS_WIN) #include "base/win/scoped_comptr.h" @@ -44,6 +46,7 @@ #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 "content/public/common/content_switches.h" #include "extensions/common/draggable_region.h" #include "third_party/skia/include/core/SkPaint.h" #include "ui/base/hit_test.h" @@ -58,9 +61,11 @@ #include "ui/gfx/font_list.h" #include "ui/gfx/platform_font.h" #include "ui/gfx/image/image_skia_operations.h" +#include "ui/views/background.h" #include "ui/views/controls/webview/webview.h" #include "ui/views/layout/box_layout.h" #include "ui/views/views_delegate.h" +#include "ui/views/views_switches.h" #include "ui/views/widget/widget.h" #include "ui/views/window/native_frame_view.h" #include "ui/views/widget/native_widget_private.h" @@ -291,6 +296,7 @@ NativeWindowAura::NativeWindowAura(const base::WeakPtr& shell, params.delegate = this; params.remove_standard_frame = !has_frame(); params.use_system_default_icon = true; + if (transparent_) params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; if (is_fullscreen_) params.show_state = ui::SHOW_STATE_FULLSCREEN; @@ -389,6 +395,85 @@ bool NativeWindowAura::IsFullscreen() { return is_fullscreen_; } +void NativeWindowAura::SetTransparent(bool transparent) { +#if defined(OS_WIN) + // Check for Windows Vista or higher, transparency isn't supported in + // anything lower. + if (base::win::GetVersion() < base::win::VERSION_VISTA) { + NOTREACHED() << "The operating system does not support transparency."; + transparent_ = false; + return; + } + + // Check to see if composition is disabled, if so we have to throw an + // error, there's no graceful recovery, yet. TODO: Graceful recovery. + BOOL enabled = FALSE; + HRESULT result = ::DwmIsCompositionEnabled(&enabled); + if (!enabled || !SUCCEEDED(result)) { + NOTREACHED() << "Windows DWM composition is not enabled, transparency is not supported."; + transparent_ = false; + return; + } + + HWND hWnd = views::HWNDForWidget(window_); + + const int marginVal = transparent ? -1 : 0; + MARGINS mgMarInset = { marginVal, marginVal, marginVal, marginVal }; + if (DwmExtendFrameIntoClientArea(hWnd, &mgMarInset) != S_OK) { + NOTREACHED() << "Windows DWM extending to client area failed, transparency is not supported."; + transparent_ = false; + return; + } + + // this is needed, or transparency will fail if it defined on startup + bool change_window_style = false; + + if (!has_frame_) { + const LONG lastStyle = GetWindowLong(hWnd, GWL_STYLE); + const LONG style = WS_CAPTION; + const LONG newStyle = transparent ? lastStyle | style : lastStyle & ~style; + SetWindowLong(hWnd, GWL_STYLE, newStyle); + change_window_style |= lastStyle != newStyle; + } + + const LONG lastExStyle = GetWindowLong(hWnd, GWL_EXSTYLE); + const LONG exStyle = WS_EX_COMPOSITED; + const LONG newExStyle = transparent ? lastExStyle | exStyle : lastExStyle & ~exStyle; + SetWindowLong(hWnd, GWL_EXSTYLE, newExStyle); + change_window_style |= lastExStyle != newExStyle; + + if (change_window_style) { + window_->FrameTypeChanged(); + } +#elif defined(USE_X11) && !defined(OS_CHROMEOS) + + static char cachedRes = -1; + if ( cachedRes<0 ) { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); + cachedRes = !command_line.HasSwitch(switches::kDisableGpu) || + !command_line.HasSwitch(views::switches::kEnableTransparentVisuals); + } + + if (cachedRes && transparent) { + LOG(INFO) << "if transparency does not work, try with --enable-transparent-visuals --disable-gpu"; + } + + #endif + + if (toolbar_) { + toolbar_->set_background(transparent ? views::Background::CreateSolidBackground(SK_ColorTRANSPARENT) : + views::Background::CreateStandardPanelBackground()); + toolbar_->SchedulePaint(); + } + + content::RenderWidgetHostView* rwhv = shell_->web_contents()->GetRenderWidgetHostView(); + if (rwhv) { + rwhv->SetBackgroundOpaque(!transparent); + } + + transparent_ = transparent; +} + void NativeWindowAura::SetSize(const gfx::Size& size) { window_->SetSize(size); } diff --git a/tools/package_binaries.py b/tools/package_binaries.py index d5ce274700..85299d77a5 100755 --- a/tools/package_binaries.py +++ b/tools/package_binaries.py @@ -125,6 +125,7 @@ def generate_target_nw(platform_name, arch, version): ] elif platform_name == 'win': target['input'] = [ + 'd3dcompiler_46.dll', 'ffmpegsumo.dll', 'icudtl.dat', 'libEGL.dll', From eae620fe2c28d744e1f2818546c720bd57991fa5 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Wed, 19 Nov 2014 23:22:42 +0800 Subject: [PATCH 268/492] Fix #1021: maximize frameless window in windows 8 --- src/browser/native_window_aura.cc | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index faf35128ca..be5e55942e 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -296,6 +296,14 @@ NativeWindowAura::NativeWindowAura(const base::WeakPtr& shell, window_->Init(params); + // WS_CAPTION is needed or the size will be miscalculated on maximizing + // see upstream issue #224924 +#if defined(OS_WIN) + HWND hwnd = views::HWNDForWidget(window_->GetTopLevelWidget()); + int current_style = ::GetWindowLong(hwnd, GWL_STYLE); + ::SetWindowLong(hwnd, GWL_STYLE, current_style | WS_CAPTION); +#endif + if (!has_frame()) InstallEasyResizeTargeterOnContainer(); From e920798d8d474e3eb8a9de2ec75371ba62f01d59 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Wed, 19 Nov 2014 23:23:56 +0800 Subject: [PATCH 269/492] Fix #2590: save as Filetypes not populating use SelectFileDialog in ui/ --- src/browser/shell_download_manager_delegate.h | 15 +++++ .../shell_download_manager_delegate_win.cc | 61 ++++++++++++------- 2 files changed, 54 insertions(+), 22 deletions(-) diff --git a/src/browser/shell_download_manager_delegate.h b/src/browser/shell_download_manager_delegate.h index 4688eb433e..10bd782af0 100644 --- a/src/browser/shell_download_manager_delegate.h +++ b/src/browser/shell_download_manager_delegate.h @@ -25,12 +25,19 @@ #include "base/memory/ref_counted.h" #include "content/public/browser/download_manager_delegate.h" +#if defined(OS_WIN) +#include "ui/shell_dialogs/select_file_dialog.h" +#endif + namespace content { class DownloadManager; class ShellDownloadManagerDelegate : public DownloadManagerDelegate, +#if defined(OS_WIN) + public ui::SelectFileDialog::Listener, +#endif public base::RefCountedThreadSafe { public: ShellDownloadManagerDelegate(); @@ -49,6 +56,9 @@ class ShellDownloadManagerDelegate // Inhibits prompting and sets the default download path. void SetDownloadBehaviorForTesting( const base::FilePath& default_download_path); + virtual void FileSelected( + const base::FilePath& path, int index, void* params) OVERRIDE; + virtual void FileSelectionCanceled(void* params) OVERRIDE; protected: // To allow subclasses for testing. @@ -70,10 +80,15 @@ class ShellDownloadManagerDelegate void ChooseDownloadPath(int32 download_id, const DownloadTargetCallback& callback, const base::FilePath& suggested_path); + void OnFileSelected(const base::FilePath& path); DownloadManager* download_manager_; base::FilePath default_download_path_; bool suppress_prompting_; +#if defined(OS_WIN) + DownloadTargetCallback callback_; + scoped_refptr select_file_dialog_; +#endif DISALLOW_COPY_AND_ASSIGN(ShellDownloadManagerDelegate); }; diff --git a/src/browser/shell_download_manager_delegate_win.cc b/src/browser/shell_download_manager_delegate_win.cc index 9004a2af0c..a0d3a1b265 100644 --- a/src/browser/shell_download_manager_delegate_win.cc +++ b/src/browser/shell_download_manager_delegate_win.cc @@ -30,6 +30,7 @@ #include "base/logging.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "chrome/browser/platform_util.h" #include "content/public/browser/browser_context.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/download_manager.h" @@ -50,31 +51,47 @@ void ShellDownloadManagerDelegate::ChooseDownloadPath( if (!item || (item->GetState() != DownloadItem::IN_PROGRESS)) return; - base::FilePath result; + WebContents* web_contents = item->GetWebContents(); + select_file_dialog_ = ui::SelectFileDialog::Create(this, NULL); + ui::SelectFileDialog::FileTypeInfo file_type_info; + // Platform file pickers, notably on Mac and Windows, tend to break + // with double extensions like .tar.gz, so only pass in normal ones. + base::FilePath::StringType extension = suggested_path.FinalExtension(); + if (!extension.empty()) { + extension.erase(extension.begin()); // drop the . + file_type_info.extensions.resize(1); + file_type_info.extensions[0].push_back(extension); + } + file_type_info.include_all_files = true; + file_type_info.support_drive = true; + gfx::NativeWindow owning_window = web_contents ? + platform_util::GetTopLevel(web_contents->GetNativeView()) : NULL; - std::wstring file_part = base::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 = (HWND)item->GetWebContents()->GetNativeView()-> - GetHost()->GetAcceleratedWidget(); - save_as.lpstrFile = file_name; - save_as.nMaxFile = arraysize(file_name); - - std::wstring directory; - if (!suggested_path.empty()) - directory = suggested_path.DirName().value(); + callback_ = callback; + base::FilePath working_path; + select_file_dialog_->SelectFile(ui::SelectFileDialog::SELECT_SAVEAS_FILE, + base::string16(), + suggested_path, + &file_type_info, + 0, + base::FilePath::StringType(), + owning_window, + NULL, working_path); +} - save_as.lpstrInitialDir = directory.c_str(); - save_as.Flags = OFN_OVERWRITEPROMPT | OFN_EXPLORER | OFN_ENABLESIZING | - OFN_NOCHANGEDIR | OFN_PATHMUSTEXIST; +void ShellDownloadManagerDelegate::OnFileSelected(const base::FilePath& path) { + callback_.Run(path, DownloadItem::TARGET_DISPOSITION_PROMPT, + DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, path); +} - if (GetSaveFileName(&save_as)) - result = base::FilePath(std::wstring(save_as.lpstrFile)); +void ShellDownloadManagerDelegate::FileSelected(const base::FilePath& path, + int index, + void* params) { + OnFileSelected(path); +} - callback.Run(result, DownloadItem::TARGET_DISPOSITION_PROMPT, - DOWNLOAD_DANGER_TYPE_NOT_DANGEROUS, result); +void ShellDownloadManagerDelegate::FileSelectionCanceled(void* params) { + OnFileSelected(base::FilePath()); } + } // namespace content From effc4d94c7ae29df7024b595071acd621803fb01 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Wed, 19 Nov 2014 23:43:21 +0800 Subject: [PATCH 270/492] Fix previous commit --- src/browser/shell_download_manager_delegate.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/browser/shell_download_manager_delegate.h b/src/browser/shell_download_manager_delegate.h index 10bd782af0..3f7c623923 100644 --- a/src/browser/shell_download_manager_delegate.h +++ b/src/browser/shell_download_manager_delegate.h @@ -56,9 +56,11 @@ class ShellDownloadManagerDelegate // Inhibits prompting and sets the default download path. void SetDownloadBehaviorForTesting( const base::FilePath& default_download_path); +#if defined(OS_WIN) virtual void FileSelected( const base::FilePath& path, int index, void* params) OVERRIDE; virtual void FileSelectionCanceled(void* params) OVERRIDE; +#endif protected: // To allow subclasses for testing. From 2872f33edb5f3c5d45c591863f4f5b56b3fe55b8 Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 20 Nov 2014 08:54:18 +0800 Subject: [PATCH 271/492] bump version to 0.11.1 --- src/nw_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nw_version.h b/src/nw_version.h index 27d0d9a899..0cbc2f8766 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -24,7 +24,7 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 11 #define NW_PATCH_VERSION 1 -#define NW_VERSION_IS_RELEASE 0 +#define NW_VERSION_IS_RELEASE 1 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) From 4627bba81b654623d15c75e0d80ab0c9cb520ab6 Mon Sep 17 00:00:00 2001 From: Roger Date: Thu, 20 Nov 2014 10:27:41 +0800 Subject: [PATCH 272/492] [README] update for 0.11.1 --- CHANGELOG.md | 13 +++++++++++++ README.md | 8 ++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47217814f6..7fff02a6dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +0.11.1 / 11-20-2014 +=================== +- add nwsnapshot +- Support setting additional root certificates on supported platforms (thanks to Joachim Bauch) +- Support SetProxyConfig API (#916) +- [WIN] Fix startup crash on high DPI systems (#2649) +- Fix #1021: maximize frameless window in windows 8 +- Fix #2590: save as Filetypes not populating +- Fix #2592: zoomLevel +- Fix #2595: Linux MenuBar crash +- Fix #2393: link target with "_blank" opens page in current window +- Fix: Don't activate app unconditionally on window "Show". + 0.11.0 / 11-11-2014 =================== - Fix: notification and screen geometry API diff --git a/README.md b/README.md index 5b99d156a2..408782318d 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ It's created and developed in the Intel Open Source Technology Center. * Available on Linux, Mac OS X and Windows ## Downloads -* **v0.11.0:** (Nov 11, 2014, based off of Node v0.11.13, Chromium 38.0.2125.104): [release notes](https://groups.google.com/d/msg/node-webkit/nDN1VclGRAA/_AKK5VIrH6gJ) +* **v0.11.1:** (Nov 20, 2014, based off of Node v0.11.13, Chromium 38.0.2125.104): [release notes](https://groups.google.com/d/msg/node-webkit/zR_ZWxMvDqs/kYOC7sJ7XOUJ) - * Linux: [32bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-linux-x64.tar.gz) - * Windows: [32bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-win-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-win-x64.zip) - * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.0/node-webkit-v0.11.0-osx-x64.zip) + * Linux: [32bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-linux-x64.tar.gz) + * Windows: [32bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-win-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-win-x64.zip) + * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-osx-x64.zip) * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From 3d2da3f751503ec60144cba2b438a71678a67fd4 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Thu, 20 Nov 2014 14:31:54 +0800 Subject: [PATCH 273/492] bump version to 0.11.2-pre --- src/mac/app-Info.plist | 2 +- src/nw_version.h | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mac/app-Info.plist b/src/mac/app-Info.plist index a8bd5a669c..09fed03749 100644 --- a/src/mac/app-Info.plist +++ b/src/mac/app-Info.plist @@ -19,7 +19,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.11.1 + 0.11.2 NSPrincipalClass NSApplication LSMinimumSystemVersion diff --git a/src/nw_version.h b/src/nw_version.h index 0cbc2f8766..cfb514b4ec 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -23,8 +23,8 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 11 -#define NW_PATCH_VERSION 1 -#define NW_VERSION_IS_RELEASE 1 +#define NW_PATCH_VERSION 2 +#define NW_VERSION_IS_RELEASE 0 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) From c740fd60fcfde041d5a7dd800a7e73e3b8428f11 Mon Sep 17 00:00:00 2001 From: Jefry Date: Thu, 20 Nov 2014 13:55:13 +0800 Subject: [PATCH 274/492] [Transparency] add switch to disable the code --- src/browser/native_window.cc | 8 +++++++- src/browser/native_window_aura.cc | 8 +++++++- src/browser/native_window_mac.mm | 7 ++++++- src/common/shell_switches.cc | 1 + src/common/shell_switches.h | 1 + 5 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/browser/native_window.cc b/src/browser/native_window.cc index 7168893b61..6de6268641 100644 --- a/src/browser/native_window.cc +++ b/src/browser/native_window.cc @@ -22,6 +22,7 @@ #include "base/memory/weak_ptr.h" #include "base/values.h" +#include "base/command_line.h" #include "content/nw/src/browser/capture_page_helper.h" #include "content/nw/src/common/shell_switches.h" #include "content/nw/src/nw_package.h" @@ -38,6 +39,9 @@ #include "content/nw/src/browser/native_window_aura.h" #endif +namespace content { + extern bool g_support_transparency; +} namespace nw { @@ -73,7 +77,9 @@ NativeWindow::NativeWindow(const base::WeakPtr& shell, has_frame_(true), capture_page_helper_(NULL) { manifest->GetBoolean(switches::kmFrame, &has_frame_); - manifest->GetBoolean(switches::kmTransparent, &transparent_); + content::g_support_transparency = !base::CommandLine::ForCurrentProcess()->HasSwitch(switches::kmDisableTransparency); + if (content::g_support_transparency) + manifest->GetBoolean(switches::kmTransparent, &transparent_); LoadAppIconFromPackage(manifest); } diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index f865ba4ad3..850533e158 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -82,6 +82,9 @@ #include "ash/accelerators/accelerator_table.h" #endif +namespace content { + extern bool g_support_transparency; +} namespace nw { @@ -296,7 +299,8 @@ NativeWindowAura::NativeWindowAura(const base::WeakPtr& shell, params.delegate = this; params.remove_standard_frame = !has_frame(); params.use_system_default_icon = true; - if (transparent_) params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; + if (content::g_support_transparency && transparent_) + params.opacity = views::Widget::InitParams::TRANSLUCENT_WINDOW; if (is_fullscreen_) params.show_state = ui::SHOW_STATE_FULLSCREEN; @@ -396,6 +400,8 @@ bool NativeWindowAura::IsFullscreen() { } void NativeWindowAura::SetTransparent(bool transparent) { + if (!content::g_support_transparency) + return; #if defined(OS_WIN) // Check for Windows Vista or higher, transparency isn't supported in // anything lower. diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index b572552c82..e7572fd0bb 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -41,6 +41,10 @@ #include "third_party/skia/include/core/SkRegion.h" #import "ui/base/cocoa/underlay_opengl_hosting_window.h" +namespace content { + extern bool g_support_transparency; +} + @interface NSWindow (NSPrivateApis) - (void)setBottomCornerRounded:(BOOL)rounded; @end @@ -282,7 +286,7 @@ - (void)drawCustomFrameRect:(NSRect)rect forView:(NSView*)view { [[NSBezierPath bezierPathWithRoundedRect:[view bounds] xRadius:cornerRadius yRadius:cornerRadius] addClip]; - if ([self isOpaque]) + if ([self isOpaque] || !content::g_support_transparency) [[NSColor whiteColor] set]; else [[NSColor clearColor] set]; @@ -548,6 +552,7 @@ - (void)drawRect:(NSRect)dirtyRect { void NativeWindowCocoa::SetTransparent(bool transparent) { + if (!content::g_support_transparency) return; if (!transparent_ && transparent) { opaque_color_ = [window() backgroundColor]; } diff --git a/src/common/shell_switches.cc b/src/common/shell_switches.cc index ed77eb444d..9e7af75263 100644 --- a/src/common/shell_switches.cc +++ b/src/common/shell_switches.cc @@ -73,6 +73,7 @@ const char kmAsDesktop[] = "as_desktop"; const char kmFullscreen[] = "fullscreen"; const char kmInitialFocus[] = "focus"; const char kmTransparent[] = "transparent"; +const char kmDisableTransparency[] = "disable_transparency"; // Make windows icon hide show or hide in taskbar. const char kmShowInTaskbar[] = "show_in_taskbar"; diff --git a/src/common/shell_switches.h b/src/common/shell_switches.h index 2a8264805e..203fb328cc 100644 --- a/src/common/shell_switches.h +++ b/src/common/shell_switches.h @@ -55,6 +55,7 @@ extern const char kmKiosk[]; extern const char kmAlwaysOnTop[]; extern const char kmInitialFocus[]; extern const char kmTransparent[]; +extern const char kmDisableTransparency[]; extern const char kmWebgl[]; extern const char kmJava[]; From 60d2ecbfd246680a1ab2584f003ccf5a1ee465d7 Mon Sep 17 00:00:00 2001 From: Jefry Date: Wed, 19 Nov 2014 11:06:24 +0800 Subject: [PATCH 275/492] [Notification] change the shortcut to update if it existed --- src/api/app/app.cc | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/api/app/app.cc b/src/api/app/app.cc index 7dd6befdaf..cd3ec6bc81 100644 --- a/src/api/app/app.cc +++ b/src/api/app/app.cc @@ -28,6 +28,7 @@ #if defined(OS_WIN) #include "base/strings/utf_string_conversions.h" #include "base/files/file_path.h" +#include "base/files/file_util.h" #include "base/win/shortcut.h" #include "base/path_service.h" #include "content/nw/src/common/shell_switches.h" @@ -162,7 +163,10 @@ void App::Call(Shell* shell, base::FilePath processPath; PathService::Get(base::FILE_EXE, &processPath); props.set_target(processPath); - result->AppendBoolean(base::win::CreateOrUpdateShortcutLink(base::FilePath(path), props, base::win::SHORTCUT_CREATE_ALWAYS)); + + base::FilePath shortcutPath(path); + result->AppendBoolean(base::win::CreateOrUpdateShortcutLink(shortcutPath, props, + base::PathExists(shortcutPath) ? base::win::SHORTCUT_UPDATE_EXISTING : base::win::SHORTCUT_CREATE_ALWAYS)); #else result->AppendBoolean(false); #endif From a3c2eb0beafbbfb1be3c7ba536038f7eb5b1b3f6 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 21 Nov 2014 15:27:55 +0800 Subject: [PATCH 276/492] Fix #2657: force native frame for frame window --- src/browser/native_window_aura.cc | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index be5e55942e..edee9c0056 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -293,7 +293,10 @@ NativeWindowAura::NativeWindowAura(const base::WeakPtr& shell, params.use_system_default_icon = true; if (is_fullscreen_) params.show_state = ui::SHOW_STATE_FULLSCREEN; - +#if defined(OS_WIN) + if (has_frame()) + window_->set_frame_type(views::Widget::FRAME_TYPE_FORCE_NATIVE); +#endif window_->Init(params); // WS_CAPTION is needed or the size will be miscalculated on maximizing From 9134c4756adb26e6408956fa8860a1cb92e5fc27 Mon Sep 17 00:00:00 2001 From: Roger Date: Fri, 21 Nov 2014 22:19:05 +0800 Subject: [PATCH 277/492] [OSX] update autofill popup view code Fix #2653 --- nw.gypi | 2 + src/browser/autofill_popup_base_view_cocoa.h | 48 ++++ src/browser/autofill_popup_base_view_cocoa.mm | 175 +++++++++++ src/browser/autofill_popup_view_bridge.h | 21 +- src/browser/autofill_popup_view_bridge.mm | 48 +--- src/browser/autofill_popup_view_cocoa.h | 12 +- src/browser/autofill_popup_view_cocoa.mm | 271 +++++++++--------- 7 files changed, 382 insertions(+), 195 deletions(-) create mode 100644 src/browser/autofill_popup_base_view_cocoa.h create mode 100644 src/browser/autofill_popup_base_view_cocoa.mm diff --git a/nw.gypi b/nw.gypi index bb42e590d1..a7681f5324 100644 --- a/nw.gypi +++ b/nw.gypi @@ -201,6 +201,8 @@ 'src/api/window/window.h', 'src/browser/app_controller_mac.h', 'src/browser/app_controller_mac.mm', + 'src/browser/autofill_popup_base_view_cocoa.h', + 'src/browser/autofill_popup_base_view_cocoa.mm', 'src/browser/autofill_popup_view_cocoa.h', 'src/browser/autofill_popup_view_cocoa.mm', 'src/browser/autofill_popup_view_bridge.h', diff --git a/src/browser/autofill_popup_base_view_cocoa.h b/src/browser/autofill_popup_base_view_cocoa.h new file mode 100644 index 0000000000..24212726c4 --- /dev/null +++ b/src/browser/autofill_popup_base_view_cocoa.h @@ -0,0 +1,48 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_BASE_VIEW_COCOA_H_ +#define CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_BASE_VIEW_COCOA_H_ + +#import + +#import "ui/base/cocoa/base_view.h" + +namespace autofill { +class AutofillPopupViewDelegate; +} + +@interface AutofillPopupBaseViewCocoa : BaseView { + @private + __weak autofill::AutofillPopupViewDelegate* delegate_; +} + +- (NSColor*)backgroundColor; +- (NSColor*)borderColor; +- (NSColor*)highlightColor; +- (NSColor*)nameColor; +- (NSColor*)separatorColor; +- (NSColor*)subtextColor; +- (NSColor*)warningColor; + +- (id)initWithDelegate:(autofill::AutofillPopupViewDelegate*)delegate + frame:(NSRect)frame; + +// Informs the view that its delegate has been (or will imminently be) +// destroyed. +- (void)delegateDestroyed; + +// Draw the popup's background and border. +- (void)drawBackgroundAndBorder; + +// Draws a thin separator in the popup UI. +- (void)drawSeparatorWithBounds:(NSRect)bounds; + +// Messages from AutofillPopupViewBridge: +- (void)updateBoundsAndRedrawPopup; +- (void)showPopup; +- (void)hidePopup; +@end + +#endif // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_BASE_VIEW_COCOA_H_ diff --git a/src/browser/autofill_popup_base_view_cocoa.mm b/src/browser/autofill_popup_base_view_cocoa.mm new file mode 100644 index 0000000000..c6f5440186 --- /dev/null +++ b/src/browser/autofill_popup_base_view_cocoa.mm @@ -0,0 +1,175 @@ +// Copyright 2014 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. + +#import "content/nw/src/browser/autofill_popup_base_view_cocoa.h" + +#include "chrome/browser/ui/autofill/autofill_popup_view_delegate.h" +#include "chrome/browser/ui/autofill/popup_constants.h" +#include "ui/base/cocoa/window_size_constants.h" + +@implementation AutofillPopupBaseViewCocoa + +#pragma mark - +#pragma mark Colors + +- (NSColor*)backgroundColor { + return [NSColor whiteColor]; +} + +- (NSColor*)borderColor { + return [NSColor colorForControlTint:[NSColor currentControlTint]]; +} + +- (NSColor*)highlightColor { + return [NSColor selectedControlColor]; +} + +- (NSColor*)nameColor { + return [NSColor blackColor]; +} + +- (NSColor*)separatorColor { + return [NSColor colorWithCalibratedWhite:220 / 255.0 alpha:1]; +} + +- (NSColor*)subtextColor { + return [NSColor grayColor]; +} + +- (NSColor*)warningColor { + return [NSColor grayColor]; +} + +#pragma mark - +#pragma mark Public methods + +- (id)initWithDelegate:(autofill::AutofillPopupViewDelegate*)delegate + frame:(NSRect)frame { + self = [super initWithFrame:frame]; + if (self) + delegate_ = delegate; + + return self; +} + +- (void)delegateDestroyed { + delegate_ = NULL; +} + +- (void)drawSeparatorWithBounds:(NSRect)bounds { + [[self separatorColor] set]; + [NSBezierPath fillRect:bounds]; +} + +// A slight optimization for drawing: +// https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaViewsGuide/Optimizing/Optimizing.html +- (BOOL)isOpaque { + return YES; +} + +- (BOOL)isFlipped { + // Flipped so that it's easier to share controller logic with other OSes. + return YES; +} + +- (void)drawBackgroundAndBorder { + // The inset is needed since the border is centered on the |path|. + // TODO(isherman): We should consider using asset-based drawing for the + // border, creating simple bitmaps for the view's border and background, and + // drawing them using NSDrawNinePartImage(). + CGFloat inset = autofill::kPopupBorderThickness / 2.0; + NSRect borderRect = NSInsetRect([self bounds], inset, inset); + NSBezierPath* path = [NSBezierPath bezierPathWithRect:borderRect]; + [[self backgroundColor] setFill]; + [path fill]; + [path setLineWidth:autofill::kPopupBorderThickness]; + [[self borderColor] setStroke]; + [path stroke]; +} + +- (void)mouseUp:(NSEvent*)theEvent { + // If the view is in the process of being destroyed, abort. + if (!delegate_) + return; + + // Only accept single-click. + if ([theEvent clickCount] > 1) + return; + + NSPoint location = [self convertPoint:[theEvent locationInWindow] + fromView:nil]; + + if (NSPointInRect(location, [self bounds])) { + delegate_->SetSelectionAtPoint(gfx::Point(NSPointToCGPoint(location))); + delegate_->AcceptSelectedLine(); + } +} + +- (void)mouseMoved:(NSEvent*)theEvent { + // If the view is in the process of being destroyed, abort. + if (!delegate_) + return; + + NSPoint location = [self convertPoint:[theEvent locationInWindow] + fromView:nil]; + + delegate_->SetSelectionAtPoint(gfx::Point(NSPointToCGPoint(location))); +} + +- (void)mouseDragged:(NSEvent*)theEvent { + [self mouseMoved:theEvent]; +} + +- (void)mouseExited:(NSEvent*)theEvent { + // If the view is in the process of being destroyed, abort. + if (!delegate_) + return; + + delegate_->SelectionCleared(); +} + +#pragma mark - +#pragma mark Messages from AutofillPopupViewBridge: + +- (void)updateBoundsAndRedrawPopup { + NSRect frame = NSRectFromCGRect(delegate_->popup_bounds().ToCGRect()); + + // Flip coordinates back into Cocoa-land. The controller's platform-neutral + // coordinate space places the origin at the top-left of the first screen, + // whereas Cocoa's coordinate space expects the origin to be at the + // bottom-left of this same screen. + NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; + frame.origin.y = NSMaxY([screen frame]) - NSMaxY(frame); + + // TODO(isherman): The view should support scrolling if the popup gets too + // big to fit on the screen. + [[self window] setFrame:frame display:YES]; + [self setNeedsDisplay:YES]; +} + +- (void)showPopup { + NSWindow* window = + [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater + styleMask:NSBorderlessWindowMask + backing:NSBackingStoreBuffered + defer:YES]; + [window setContentView:self]; + + // Telling Cocoa that the window is opaque enables some drawing optimizations. + [window setOpaque:YES]; + + [self updateBoundsAndRedrawPopup]; + [[delegate_->container_view() window] addChildWindow:window + ordered:NSWindowAbove]; +} + +- (void)hidePopup { + // Remove the child window before closing, otherwise it can mess up + // display ordering. + NSWindow* window = [self window]; + [[window parentWindow] removeChildWindow:window]; + [window close]; +} + +@end diff --git a/src/browser/autofill_popup_view_bridge.h b/src/browser/autofill_popup_view_bridge.h index 09119f4a97..b2e80d4fc7 100644 --- a/src/browser/autofill_popup_view_bridge.h +++ b/src/browser/autofill_popup_view_bridge.h @@ -9,18 +9,20 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" +#include "base/mac/scoped_nsobject.h" #include "chrome/browser/ui/autofill/autofill_popup_view.h" +#include "content/nw/src/browser/autofill_popup_view_cocoa.h" @class AutofillPopupViewCocoa; @class NSWindow; namespace autofill { -class AutofillPopupController; +class AutofillPopupViewDelegate; -// Mac implementation for AutofillPopupView interface. -// Serves as a bridge to the Objective-C class AutofillPopupViewCocoa which -// actually implements the view. +// Mac implementation of the AutofillPopupView interface. +// Serves as a bridge to an instance of the Objective-C class which actually +// implements the view. class AutofillPopupViewBridge : public AutofillPopupView { public: explicit AutofillPopupViewBridge(AutofillPopupController* controller); @@ -34,16 +36,13 @@ class AutofillPopupViewBridge : public AutofillPopupView { virtual void InvalidateRow(size_t row) OVERRIDE; virtual void UpdateBoundsAndRedrawPopup() OVERRIDE; - // Set the initial bounds of the popup to show, including the placement - // of it. + // Set the initial bounds of the popup, including its placement. void SetInitialBounds(); - // The controller for this view. - AutofillPopupController* controller_; // Weak reference. + // The native Cocoa view. + base::scoped_nsobject view_; - // The native Cocoa window and view. - NSWindow* window_; // Weak reference, owns itself. - AutofillPopupViewCocoa* view_; // Weak reference, owned by the |window_|. + AutofillPopupController* controller_; // Weak. DISALLOW_COPY_AND_ASSIGN(AutofillPopupViewBridge); }; diff --git a/src/browser/autofill_popup_view_bridge.mm b/src/browser/autofill_popup_view_bridge.mm index dc6e59a5fe..928a020c45 100644 --- a/src/browser/autofill_popup_view_bridge.mm +++ b/src/browser/autofill_popup_view_bridge.mm @@ -7,9 +7,9 @@ #include "content/nw/src/browser/autofill_popup_view_bridge.h" #include "base/logging.h" -#include "content/nw/src/browser/autofill_popup_controller.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller.h" +#include "chrome/browser/ui/autofill/autofill_popup_view_delegate.h" #import "content/nw/src/browser/autofill_popup_view_cocoa.h" -#include "ui/base/cocoa/window_size_constants.h" #include "ui/gfx/rect.h" namespace autofill { @@ -17,28 +17,14 @@ AutofillPopupViewBridge::AutofillPopupViewBridge( AutofillPopupController* controller) : controller_(controller) { - window_ = - [[NSWindow alloc] initWithContentRect:ui::kWindowSizeDeterminedLater - styleMask:NSBorderlessWindowMask - backing:NSBackingStoreBuffered - defer:YES]; - // Telling Cocoa that the window is opaque enables some drawing optimizations. - [window_ setOpaque:YES]; - - view_ = [[[AutofillPopupViewCocoa alloc] - initWithController:controller_ - frame:NSZeroRect] autorelease]; - [window_ setContentView:view_]; + view_.reset( + [[AutofillPopupViewCocoa alloc] initWithController:controller + frame:NSZeroRect]); } AutofillPopupViewBridge::~AutofillPopupViewBridge() { [view_ controllerDestroyed]; - - // Remove the child window before closing, otherwise it can mess up - // display ordering. - [[window_ parentWindow] removeChildWindow:window_]; - - [window_ close]; + [view_ hidePopup]; } void AutofillPopupViewBridge::Hide() { @@ -46,31 +32,15 @@ } void AutofillPopupViewBridge::Show() { - UpdateBoundsAndRedrawPopup(); - [[controller_->container_view() window] addChildWindow:window_ - ordered:NSWindowAbove]; + [view_ showPopup]; } void AutofillPopupViewBridge::InvalidateRow(size_t row) { - NSRect dirty_rect = - NSRectFromCGRect(controller_->GetRowBounds(row).ToCGRect()); - [view_ setNeedsDisplayInRect:dirty_rect]; + [view_ invalidateRow:row]; } void AutofillPopupViewBridge::UpdateBoundsAndRedrawPopup() { - NSRect frame = NSRectFromCGRect(controller_->popup_bounds().ToCGRect()); - - // Flip coordinates back into Cocoa-land. The controller's platform-neutral - // coordinate space places the origin at the top-left of the first screen, - // whereas Cocoa's coordinate space expects the origin to be at the - // bottom-left of this same screen. - NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; - frame.origin.y = NSMaxY([screen frame]) - NSMaxY(frame); - - // TODO(isherman): The view should support scrolling if the popup gets too - // big to fit on the screen. - [window_ setFrame:frame display:YES]; - [view_ setNeedsDisplay:YES]; + [view_ updateBoundsAndRedrawPopup]; } AutofillPopupView* AutofillPopupView::Create( diff --git a/src/browser/autofill_popup_view_cocoa.h b/src/browser/autofill_popup_view_cocoa.h index c51a6ed8d0..698c768ed5 100644 --- a/src/browser/autofill_popup_view_cocoa.h +++ b/src/browser/autofill_popup_view_cocoa.h @@ -2,19 +2,19 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_CONTENT_VIEW_H_ -#define CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_CONTENT_VIEW_H_ +#ifndef CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_VIEW_COCOA_H_ +#define CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_VIEW_COCOA_H_ #import -#import "ui/base/cocoa/base_view.h" +#import "content/nw/src/browser/autofill_popup_base_view_cocoa.h" namespace autofill { class AutofillPopupController; } // namespace autofill // Draws the native Autofill popup view on Mac. -@interface AutofillPopupViewCocoa : BaseView { +@interface AutofillPopupViewCocoa : AutofillPopupBaseViewCocoa { @private // The cross-platform controller for this view. __weak autofill::AutofillPopupController* controller_; @@ -28,6 +28,8 @@ class AutofillPopupController; // destroyed. - (void)controllerDestroyed; +- (void)invalidateRow:(size_t)row; + @end -#endif // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_CONTENT_VIEW_H_ +#endif // CHROME_BROWSER_UI_COCOA_AUTOFILL_AUTOFILL_POPUP_VIEW_COCOA_H_ diff --git a/src/browser/autofill_popup_view_cocoa.mm b/src/browser/autofill_popup_view_cocoa.mm index 387e6ef82e..89fd114fe9 100644 --- a/src/browser/autofill_popup_view_cocoa.mm +++ b/src/browser/autofill_popup_view_cocoa.mm @@ -6,11 +6,11 @@ #include "base/logging.h" #include "base/strings/sys_string_conversions.h" -#include "content/nw/src/browser/autofill_popup_controller.h" +#include "chrome/browser/ui/autofill/autofill_popup_controller.h" #include "chrome/browser/ui/autofill/popup_constants.h" #include "content/nw/src/browser/autofill_popup_view_bridge.h" #include "components/autofill/core/browser/popup_item_ids.h" -#include "grit/ui_resources.h" +#include "ui/base/cocoa/window_size_constants.h" #include "ui/base/resource/resource_bundle.h" #include "ui/gfx/font_list.h" #include "ui/gfx/image/image.h" @@ -19,56 +19,48 @@ using autofill::AutofillPopupView; -namespace { - -NSColor* BackgroundColor() { - return [NSColor whiteColor]; -} - -// The color of the border around the popup. -NSColor* BorderColor() { - return [NSColor colorForControlTint:[NSColor currentControlTint]]; -} - -NSColor* SeparatorColor() { - return [NSColor colorWithCalibratedWhite:220 / 255.0 alpha:1]; -} - -NSColor* HighlightColor() { - return [NSColor selectedControlColor]; -} - -NSColor* NameColor() { - return [NSColor blackColor]; -} - -NSColor* WarningColor() { - return [NSColor grayColor]; -} - -NSColor* SubtextColor() { - return [NSColor grayColor]; -} - -} // namespace +@interface AutofillPopupViewCocoa () #pragma mark - #pragma mark Private methods -@interface AutofillPopupViewCocoa () - -// Draws a thin separator in the popup UI. -- (void)drawSeparatorWithBounds:(NSRect)bounds; - // Draws an Autofill suggestion in the given |bounds|, labeled with the given // |name| and |subtext| hint. If the suggestion |isSelected|, then it is drawn // with a highlight. |index| determines the font to use, as well as the icon, -// if the row requires it -- such as for credit cards. +// if the row requires it -- such as for credit cards. |imageFirst| indicates +// whether the image should be drawn before the name, and with the same +// alignment, or whether it should be drawn afterwards, with the opposite +// alignment. - (void)drawSuggestionWithName:(NSString*)name subtext:(NSString*)subtext index:(size_t)index bounds:(NSRect)bounds - selected:(BOOL)isSelected; + selected:(BOOL)isSelected + imageFirst:(BOOL)imageFirst + textYOffset:(CGFloat)textYOffset; + +// This comment block applies to all three draw* methods that follow. +// If |rightAlign| == YES. +// Draws the widget with right border aligned to |x|. +// Returns the x value of left border of the widget. +// If |rightAlign| == NO. +// Draws the widget with left border aligned to |x|. +// Returns the x value of right border of the widget. +- (CGFloat)drawName:(NSString*)name + atX:(CGFloat)x + index:(size_t)index + rightAlign:(BOOL)rightAlign + bounds:(NSRect)bounds + textYOffset:(CGFloat)textYOffset; +- (CGFloat)drawIconAtIndex:(size_t)index + atX:(CGFloat)x + rightAlign:(BOOL)rightAlign + bounds:(NSRect)bounds; +- (CGFloat)drawSubtext:(NSString*)subtext + atX:(CGFloat)x + rightAlign:(BOOL)rightAlign + bounds:(NSRect)bounds + textYOffset:(CGFloat)textYOffset; // Returns the icon for the row with the given |index|, or |nil| if there is // none. @@ -88,7 +80,7 @@ - (id)initWithFrame:(NSRect)frame { - (id)initWithController:(autofill::AutofillPopupController*)controller frame:(NSRect)frame { - self = [super initWithFrame:frame]; + self = [super initWithDelegate:controller frame:frame]; if (self) controller_ = controller; @@ -98,35 +90,12 @@ - (id)initWithController:(autofill::AutofillPopupController*)controller #pragma mark - #pragma mark NSView implementation: -// A slight optimization for drawing: -// https://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/CocoaViewsGuide/Optimizing/Optimizing.html -- (BOOL)isOpaque { - return YES; -} - -- (BOOL)isFlipped { - // Flipped so that it's easier to share controller logic with other OSes. - return YES; -} - - (void)drawRect:(NSRect)dirtyRect { // If the view is in the process of being destroyed, don't bother drawing. if (!controller_) return; - // Draw the popup's background and border. - // The inset is needed since the border is centered on the |path|. - // TODO(isherman): We should consider using asset-based drawing for the - // border, creating simple bitmaps for the view's border and background, and - // drawing them using NSDrawNinePartImage(). - CGFloat inset = autofill::kPopupBorderThickness / 2.0; - NSRect borderRect = NSInsetRect([self bounds], inset, inset); - NSBezierPath* path = [NSBezierPath bezierPathWithRect:borderRect]; - [BackgroundColor() setFill]; - [path fill]; - [path setLineWidth:autofill::kPopupBorderThickness]; - [BorderColor() setStroke]; - [path stroke]; + [self drawBackgroundAndBorder]; for (size_t i = 0; i < controller_->names().size(); ++i) { // Skip rows outside of the dirty rect. @@ -137,56 +106,33 @@ - (void)drawRect:(NSRect)dirtyRect { if (controller_->identifiers()[i] == autofill::POPUP_ITEM_ID_SEPARATOR) { [self drawSeparatorWithBounds:rowBounds]; - } else { - NSString* name = SysUTF16ToNSString(controller_->names()[i]); - NSString* subtext = SysUTF16ToNSString(controller_->subtexts()[i]); - BOOL isSelected = static_cast(i) == controller_->selected_line(); - [self drawSuggestionWithName:name - subtext:subtext - index:i - bounds:rowBounds - selected:isSelected]; + continue; } - } -} -- (void)mouseUp:(NSEvent*)theEvent { - // If the view is in the process of being destroyed, abort. - if (!controller_) - return; - - NSPoint location = [self convertPoint:[theEvent locationInWindow] - fromView:nil]; + // Additional offset applied to the text in the vertical direction. + CGFloat textYOffset = 0; + BOOL imageFirst = NO; + if (controller_->identifiers()[i] == + autofill::POPUP_ITEM_ID_MAC_ACCESS_CONTACTS) { + // Due to the weighting of the asset used for this autofill entry, the + // text needs to be bumped up by 1 pt to make it look vertically aligned. + textYOffset = -1; + imageFirst = YES; + } - if (NSPointInRect(location, [self bounds])) { - controller_->SetSelectionAtPoint(gfx::Point(NSPointToCGPoint(location))); - controller_->AcceptSelectedLine(); + NSString* name = SysUTF16ToNSString(controller_->names()[i]); + NSString* subtext = SysUTF16ToNSString(controller_->subtexts()[i]); + BOOL isSelected = static_cast(i) == controller_->selected_line(); + [self drawSuggestionWithName:name + subtext:subtext + index:i + bounds:rowBounds + selected:isSelected + imageFirst:imageFirst + textYOffset:textYOffset]; } } -- (void)mouseMoved:(NSEvent*)theEvent { - // If the view is in the process of being destroyed, abort. - if (!controller_) - return; - - NSPoint location = [self convertPoint:[theEvent locationInWindow] - fromView:nil]; - - controller_->SetSelectionAtPoint(gfx::Point(NSPointToCGPoint(location))); -} - -- (void)mouseDragged:(NSEvent*)theEvent { - [self mouseMoved:theEvent]; -} - -- (void)mouseExited:(NSEvent*)theEvent { - // If the view is in the process of being destroyed, abort. - if (!controller_) - return; - - controller_->SelectionCleared(); -} - #pragma mark - #pragma mark Public API: @@ -194,31 +140,67 @@ - (void)controllerDestroyed { // Since the |controller_| either already has been destroyed or is about to // be, about the only thing we can safely do with it is to null it out. controller_ = NULL; + [super delegateDestroyed]; +} + +- (void)invalidateRow:(size_t)row { + NSRect dirty_rect = + NSRectFromCGRect(controller_->GetRowBounds(row).ToCGRect()); + [self setNeedsDisplayInRect:dirty_rect]; } #pragma mark - #pragma mark Private API: -- (void)drawSeparatorWithBounds:(NSRect)bounds { - [SeparatorColor() set]; - [NSBezierPath fillRect:bounds]; -} - - (void)drawSuggestionWithName:(NSString*)name subtext:(NSString*)subtext index:(size_t)index bounds:(NSRect)bounds - selected:(BOOL)isSelected { + selected:(BOOL)isSelected + imageFirst:(BOOL)imageFirst + textYOffset:(CGFloat)textYOffset { // If this row is selected, highlight it. if (isSelected) { - [HighlightColor() set]; + [[self highlightColor] set]; [NSBezierPath fillRect:bounds]; } BOOL isRTL = controller_->IsRTL(); + // The X values of the left and right borders of the autofill widget. + CGFloat leftX = NSMinX(bounds) + AutofillPopupView::kEndPadding; + CGFloat rightX = NSMaxX(bounds) - AutofillPopupView::kEndPadding; + + // Draw left side if isRTL == NO, right side if isRTL == YES. + CGFloat x = isRTL ? rightX : leftX; + if (imageFirst) + x = [self drawIconAtIndex:index atX:x rightAlign:isRTL bounds:bounds]; + [self drawName:name + atX:x + index:index + rightAlign:isRTL + bounds:bounds + textYOffset:textYOffset]; + + // Draw right side if isRTL == NO, left side if isRTL == YES. + x = isRTL ? leftX : rightX; + if (!imageFirst) + x = [self drawIconAtIndex:index atX:x rightAlign:!isRTL bounds:bounds]; + [self drawSubtext:subtext + atX:x + rightAlign:!isRTL + bounds:bounds + textYOffset:textYOffset]; +} + +- (CGFloat)drawName:(NSString*)name + atX:(CGFloat)x + index:(size_t)index + rightAlign:(BOOL)rightAlign + bounds:(NSRect)bounds + textYOffset:(CGFloat)textYOffset { NSColor* nameColor = - controller_->IsWarning(index) ? WarningColor() : NameColor(); + controller_->IsWarning(index) ? [self warningColor] : [self nameColor]; NSDictionary* nameAttributes = [NSDictionary dictionaryWithObjectsAndKeys: controller_->GetNameFontListForRow(index).GetPrimaryFont(). @@ -226,26 +208,26 @@ - (void)drawSuggestionWithName:(NSString*)name NSFontAttributeName, nameColor, NSForegroundColorAttributeName, nil]; NSSize nameSize = [name sizeWithAttributes:nameAttributes]; - CGFloat x = bounds.origin.x + - (isRTL ? - bounds.size.width - AutofillPopupView::kEndPadding - nameSize.width : - AutofillPopupView::kEndPadding); + x -= rightAlign ? nameSize.width : 0; CGFloat y = bounds.origin.y + (bounds.size.height - nameSize.height) / 2; + y += textYOffset; [name drawAtPoint:NSMakePoint(x, y) withAttributes:nameAttributes]; - // The x-coordinate will be updated as each element is drawn. - x = bounds.origin.x + - (isRTL ? - AutofillPopupView::kEndPadding : - bounds.size.width - AutofillPopupView::kEndPadding); + x += rightAlign ? 0 : nameSize.width; + return x; +} - // Draw the Autofill icon, if one exists. +- (CGFloat)drawIconAtIndex:(size_t)index + atX:(CGFloat)x + rightAlign:(BOOL)rightAlign + bounds:(NSRect)bounds { NSImage* icon = [self iconAtIndex:index]; - if (icon) { - NSSize iconSize = [icon size]; - x += isRTL ? 0 : -iconSize.width; - y = bounds.origin.y + (bounds.size.height - iconSize.height) / 2; + if (!icon) + return x; + NSSize iconSize = [icon size]; + x -= rightAlign ? iconSize.width : 0; + CGFloat y = bounds.origin.y + (bounds.size.height - iconSize.height) / 2; [icon drawInRect:NSMakeRect(x, y, iconSize.width, iconSize.height) fromRect:NSZeroRect operation:NSCompositeSourceOver @@ -253,22 +235,31 @@ - (void)drawSuggestionWithName:(NSString*)name respectFlipped:YES hints:nil]; - x += isRTL ? - iconSize.width + AutofillPopupView::kIconPadding : - -AutofillPopupView::kIconPadding; - } + x += rightAlign ? -AutofillPopupView::kIconPadding + : iconSize.width + AutofillPopupView::kIconPadding; + return x; +} - // Draw the subtext. +- (CGFloat)drawSubtext:(NSString*)subtext + atX:(CGFloat)x + rightAlign:(BOOL)rightAlign + bounds:(NSRect)bounds + textYOffset:(CGFloat)textYOffset { NSDictionary* subtextAttributes = [NSDictionary dictionaryWithObjectsAndKeys: controller_->subtext_font_list().GetPrimaryFont().GetNativeFont(), - NSFontAttributeName, SubtextColor(), NSForegroundColorAttributeName, + NSFontAttributeName, + [self subtextColor], + NSForegroundColorAttributeName, nil]; NSSize subtextSize = [subtext sizeWithAttributes:subtextAttributes]; - x += isRTL ? 0 : -subtextSize.width; - y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2; + x -= rightAlign ? subtextSize.width : 0; + CGFloat y = bounds.origin.y + (bounds.size.height - subtextSize.height) / 2; + y += textYOffset; [subtext drawAtPoint:NSMakePoint(x, y) withAttributes:subtextAttributes]; + x += rightAlign ? 0 : subtextSize.width; + return x; } - (NSImage*)iconAtIndex:(size_t)index { From 0b2dabc2ef8434672d14854e36f140fbe6519438 Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Sat, 22 Nov 2014 08:16:04 +0800 Subject: [PATCH 278/492] rename disable_transparency to disable-transparency --- src/common/shell_switches.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common/shell_switches.cc b/src/common/shell_switches.cc index 9e7af75263..6a8aff14ca 100644 --- a/src/common/shell_switches.cc +++ b/src/common/shell_switches.cc @@ -73,7 +73,7 @@ const char kmAsDesktop[] = "as_desktop"; const char kmFullscreen[] = "fullscreen"; const char kmInitialFocus[] = "focus"; const char kmTransparent[] = "transparent"; -const char kmDisableTransparency[] = "disable_transparency"; +const char kmDisableTransparency[] = "disable-transparency"; // Make windows icon hide show or hide in taskbar. const char kmShowInTaskbar[] = "show_in_taskbar"; From e1975eca70c67cb808a58b39da4b4f8fbc795cb4 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 24 Nov 2014 15:59:55 +0800 Subject: [PATCH 279/492] [Linux] support 'maximize' window event for Aura Part of #2631 --- src/browser/native_window_aura.cc | 22 ++++++++++++++++++++++ src/browser/native_window_aura.h | 2 ++ 2 files changed, 24 insertions(+) diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index 479af37bbe..04758cb5d1 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -991,6 +991,28 @@ bool NativeWindowAura::ExecuteWindowsCommand(int command_id) { return false; } +void NativeWindowAura::HandleWMStateUpdate() { + if (window_->IsMaximized()) { + if (!is_maximized_ && shell()) + shell()->SendEvent("maximize"); + is_maximized_ = true; + }else if (is_maximized_) { + if (shell()) + shell()->SendEvent("unmaximize"); + is_maximized_ = false; + } + + if (window_->IsMinimized()) { + if (!is_minimized_ && shell()) + shell()->SendEvent("minimize"); + is_minimized_ = true; + }else if (is_minimized_) { + if (shell()) + shell()->SendEvent("restore"); + is_minimized_ = false; + } +} + bool NativeWindowAura::HandleSize(unsigned int param, const gfx::Size& size) { #if defined(OS_WIN) if (param == SIZE_MAXIMIZED) { diff --git a/src/browser/native_window_aura.h b/src/browser/native_window_aura.h index 98b8e43243..84ddc8ad31 100644 --- a/src/browser/native_window_aura.h +++ b/src/browser/native_window_aura.h @@ -120,6 +120,8 @@ class NativeWindowAura : public NativeWindow, virtual gfx::ImageSkia GetWindowIcon() OVERRIDE; virtual bool ShouldShowWindowTitle() const OVERRIDE; virtual bool ShouldHandleOnSize() const OVERRIDE; + virtual void HandleWMStateUpdate() OVERRIDE; + views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_; From 23430c26be715f48817c0ac0c5674cfc3d949e78 Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 24 Nov 2014 20:57:19 +0800 Subject: [PATCH 280/492] [Linux] Fix broken 'focus' and 'blur' event Part of #2631 --- src/browser/native_window_aura.cc | 14 ++++++++++++++ src/browser/native_window_aura.h | 2 ++ 2 files changed, 16 insertions(+) diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index 04758cb5d1..b8da0ebe72 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -565,6 +565,20 @@ void NativeWindowAura::SetAlwaysOnTop(bool top) { window_->SetAlwaysOnTop(top); } +void NativeWindowAura::OnWidgetActivationChanged(views::Widget* widget, bool active) { + if (active) { + if (shell()) + shell()->SendEvent("focus"); + is_focus_ = true; + is_blur_ = false; + }else{ + if (shell()) + shell()->SendEvent("blur"); + is_focus_ = false; + is_blur_ = true; + } +} + void NativeWindowAura::OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) { int w = new_bounds.width(); int h = new_bounds.height(); diff --git a/src/browser/native_window_aura.h b/src/browser/native_window_aura.h index 84ddc8ad31..861e540356 100644 --- a/src/browser/native_window_aura.h +++ b/src/browser/native_window_aura.h @@ -132,6 +132,8 @@ class NativeWindowAura : public NativeWindow, // WidgetObserver implementation virtual void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) OVERRIDE; + virtual void OnWidgetActivationChanged(views::Widget* widget, + bool active) OVERRIDE; virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; From cb83de3d9f4bf4824e742092986ffe00bf6dc88e Mon Sep 17 00:00:00 2001 From: Roger Wang Date: Tue, 25 Nov 2014 21:04:01 +0800 Subject: [PATCH 281/492] Fix #2666: release image properly when create icon --- src/nw_package.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nw_package.cc b/src/nw_package.cc index 937809d57e..845f2a6868 100644 --- a/src/nw_package.cc +++ b/src/nw_package.cc @@ -204,7 +204,7 @@ bool Package::GetImage(const FilePath& icon_path, gfx::Image* image) { if (decoded->empty()) return false; // Unable to decode. - *image = gfx::Image::CreateFrom1xBitmap(*decoded.release()); + *image = gfx::Image::CreateFrom1xBitmap(*decoded); return true; } From 67882a717a31b87750292fa6127880e66bb086a5 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Wed, 26 Nov 2014 10:23:47 +0800 Subject: [PATCH 282/492] Add automation tests for node-webkit. The automation can replace existing automatic tests in node-webkit. This is fundmental framework enabling users to add mocha test cases in it. All test cases are running in seperated process so the whole test would not be blocked if some test case hang. Each test case would output separated report in file system. It becomes easier to check the test results. It allows to either run all test cases in batch or run each of them individually. How to: Assume the current directory is in "automation" folder. 1, At first time, install the npm modules: $npm install 2, Run all test cases $node mocha_test.js or simply call `run.sh` on Linux 3, Run individual test case $nw or $quiet=false nw The test reports will be generated under the "output" folder, sub folders named by timestamp would be generated under it. --- tests/automation/.gitignore | 3 + tests/automation/README.md | 36 + .../index.html | 11 + .../internal/index.html | 18 + .../internal/package.json | 4 + .../mocha_test.js | 39 + .../package.json | 4 + tests/automation/app/index.html | 22 + tests/automation/app/index2.html | 33 + tests/automation/app/mocha_test.js | 55 + tests/automation/app/package.json | 4 + tests/automation/app_path_escape/index.html | 9 + .../automation/app_path_escape/mocha_test.js | 25 + tests/automation/app_path_escape/package.json | 4 + .../automation/app_path_escape/xdk/index.html | 15 + .../app_path_escape/xdk/package.json | 4 + tests/automation/config.json | 10 + tests/automation/globals.js | 5 + tests/automation/mocha_test.js | 181 + tests/automation/package.json | 13 + tests/automation/res/assert.js | 431 ++ tests/automation/res/build.sh | 4 + tests/automation/res/chai.js | 4800 +++++++++++++ tests/automation/res/mocha.css | 270 + tests/automation/res/mocha.js | 6069 +++++++++++++++++ tests/automation/res/mocha_util.js | 3 + tests/automation/res/util.js | 98 + tests/automation/run.sh | 4 + tests/automation/sample/index.html | 18 + tests/automation/sample/mocha_test.js | 32 + tests/automation/sample/package.json | 4 + tests/automation/window/index.html | 59 + tests/automation/window/index1.html | 19 + tests/automation/window/index2.html | 10 + tests/automation/window/mocha_test.js | 30 + tests/automation/window/package.json | 4 + 36 files changed, 12350 insertions(+) create mode 100644 tests/automation/.gitignore create mode 100644 tests/automation/README.md create mode 100644 tests/automation/after_close_previous_window_then_open_new/index.html create mode 100644 tests/automation/after_close_previous_window_then_open_new/internal/index.html create mode 100644 tests/automation/after_close_previous_window_then_open_new/internal/package.json create mode 100644 tests/automation/after_close_previous_window_then_open_new/mocha_test.js create mode 100644 tests/automation/after_close_previous_window_then_open_new/package.json create mode 100644 tests/automation/app/index.html create mode 100644 tests/automation/app/index2.html create mode 100644 tests/automation/app/mocha_test.js create mode 100644 tests/automation/app/package.json create mode 100644 tests/automation/app_path_escape/index.html create mode 100644 tests/automation/app_path_escape/mocha_test.js create mode 100644 tests/automation/app_path_escape/package.json create mode 100644 tests/automation/app_path_escape/xdk/index.html create mode 100644 tests/automation/app_path_escape/xdk/package.json create mode 100644 tests/automation/config.json create mode 100644 tests/automation/globals.js create mode 100644 tests/automation/mocha_test.js create mode 100644 tests/automation/package.json create mode 100644 tests/automation/res/assert.js create mode 100755 tests/automation/res/build.sh create mode 100644 tests/automation/res/chai.js create mode 100644 tests/automation/res/mocha.css create mode 100644 tests/automation/res/mocha.js create mode 100644 tests/automation/res/mocha_util.js create mode 100644 tests/automation/res/util.js create mode 100755 tests/automation/run.sh create mode 100644 tests/automation/sample/index.html create mode 100644 tests/automation/sample/mocha_test.js create mode 100644 tests/automation/sample/package.json create mode 100644 tests/automation/window/index.html create mode 100644 tests/automation/window/index1.html create mode 100644 tests/automation/window/index2.html create mode 100644 tests/automation/window/mocha_test.js create mode 100644 tests/automation/window/package.json diff --git a/tests/automation/.gitignore b/tests/automation/.gitignore new file mode 100644 index 0000000000..eb9a4456d9 --- /dev/null +++ b/tests/automation/.gitignore @@ -0,0 +1,3 @@ +node_modules +output/ + diff --git a/tests/automation/README.md b/tests/automation/README.md new file mode 100644 index 0000000000..5d1237b359 --- /dev/null +++ b/tests/automation/README.md @@ -0,0 +1,36 @@ +Automation +================= + +## Background + +The automation can replace existing automatic tests in node-webkit. + +This is fundmental framework enabling users to add mocha test cases in it. + +All test cases are running in seperated process so the whole test would not be blocked if some test case hang. + +Each test case would output separated report in file system. It becomes easier to check the test results. + +It allows to either run all test cases in batch or run each of them individually. + +## How to run automation: +Assume the current directory is in "automation" folder. + +1, At first time, install the npm modules: + + $npm install + +2, Run all test cases + + $node mocha_test.js + or simply call `run.sh` on Linux + +3, Run individual test case + + $nw + or + $quiet=false nw + +4, The test report will be generated under the `output` folder and sub folders named by current timestamp could be created. + + diff --git a/tests/automation/after_close_previous_window_then_open_new/index.html b/tests/automation/after_close_previous_window_then_open_new/index.html new file mode 100644 index 0000000000..bb4a76bccd --- /dev/null +++ b/tests/automation/after_close_previous_window_then_open_new/index.html @@ -0,0 +1,11 @@ + + + + +Test Window + + + + + + diff --git a/tests/automation/after_close_previous_window_then_open_new/internal/index.html b/tests/automation/after_close_previous_window_then_open_new/internal/index.html new file mode 100644 index 0000000000..d9480feeaa --- /dev/null +++ b/tests/automation/after_close_previous_window_then_open_new/internal/index.html @@ -0,0 +1,18 @@ + + + + +hi + + + diff --git a/tests/automation/after_close_previous_window_then_open_new/internal/package.json b/tests/automation/after_close_previous_window_then_open_new/internal/package.json new file mode 100644 index 0000000000..8748842da0 --- /dev/null +++ b/tests/automation/after_close_previous_window_then_open_new/internal/package.json @@ -0,0 +1,4 @@ +{ +"name": "nw-#1236", +"main": "index.html" +} diff --git a/tests/automation/after_close_previous_window_then_open_new/mocha_test.js b/tests/automation/after_close_previous_window_then_open_new/mocha_test.js new file mode 100644 index 0000000000..f14fcfbfb1 --- /dev/null +++ b/tests/automation/after_close_previous_window_then_open_new/mocha_test.js @@ -0,0 +1,39 @@ +var path = require('path'); +var app_test = require('../../nw_test_app'); +var assert =require('assert'); +var fs = require('fs'); +var fs_extra = require('fs-extra'); +var spawn = require('child_process').spawn; +var global = require('../globals'); +var result; + +var dumpDir = path.join(global.tests_dir, 'internal', 'tmp'); +console.log('dumpDir:' + dumpDir); + +describe('after close previous window then open new', function() { + after(function () { + fs_extra.remove(dumpDir, function (er) { + if (er) throw er; + }); + }); + + before(function(done) { + this.timeout(0); + if (!fs.exists(dumpDir)) + fs.mkdirSync(dumpDir); + + var appPath = path.join(global.tests_dir, 'internal'); + + var exec_argv = [appPath]; + app = spawn(process.execPath, exec_argv); + setTimeout(function() { + done(); + }, 2000); + }); + + it('should not crash', function() { + result = fs.readdirSync(dumpDir); + assert.equal(result.length, 0); + }); + +}); diff --git a/tests/automation/after_close_previous_window_then_open_new/package.json b/tests/automation/after_close_previous_window_then_open_new/package.json new file mode 100644 index 0000000000..2d5dd8b8e4 --- /dev/null +++ b/tests/automation/after_close_previous_window_then_open_new/package.json @@ -0,0 +1,4 @@ +{ +"name": "after_close_previous_window_then_open_new_wrapper", +"main": "index.html" +} diff --git a/tests/automation/app/index.html b/tests/automation/app/index.html new file mode 100644 index 0000000000..808e75c8d6 --- /dev/null +++ b/tests/automation/app/index.html @@ -0,0 +1,22 @@ + + + + + Test Case for 'App.clearCache' + + +

      Please wait to be closed.

      + + + + + + diff --git a/tests/automation/app/index2.html b/tests/automation/app/index2.html new file mode 100644 index 0000000000..99c17b5c12 --- /dev/null +++ b/tests/automation/app/index2.html @@ -0,0 +1,33 @@ + + + + + Test Case for 'App.clearCache' + + +

      Please wait to be closed.

      + + + + + diff --git a/tests/automation/app/mocha_test.js b/tests/automation/app/mocha_test.js new file mode 100644 index 0000000000..b3bec638c2 --- /dev/null +++ b/tests/automation/app/mocha_test.js @@ -0,0 +1,55 @@ +var gui = require('nw.gui'); +var assert = require('assert'); +var app_test = require('../../nw_test_app'); +//var local_server = require('../../server/server'); +var global = require('../globals'); + +describe('gui.App', function() { + before(function(done) { + this.timeout(0); + var checkDone = function() { + if (test_done) + done(); + else + setTimeout(function() {checkDone();}, 2000); + } + checkDone(); + + }); + + describe('manifest', function() { + it('`gui.App.manifest` should equle to value of package.json', function() { + assert.equal(gui.App.manifest.name, 'nw-gui.App-test'); + }); + + it('have main', function() { + assert.equal(typeof gui.App.manifest.main, 'string'); + assert.equal(gui.App.manifest.main, 'index.html'); + }); + +/* + it('have window', function() { + console.log('====have window:' + typeof gui.App.manifest.window); + assert.equal(typeof gui.App.manifest.window, 'object'); + }); + + it('have dependencies', function() { + assert.equal(typeof gui.App.manifest.dependencies, 'object'); + }); +*/ + }); +/* + describe('clearCache()', function(done) { + it('should clear the HTTP cache in memory and the one on disk', function() { + var res_save = global.local_server.res_save; + + assert.equal(res_save[1].status, 304); + assert.equal(res_save[1].pathname, 'img.jpg'); + assert.equal(res_save[2].status, 200); + assert.equal(res_save[2].pathname, 'img.jpg'); + }); + }); +*/ +}); + + diff --git a/tests/automation/app/package.json b/tests/automation/app/package.json new file mode 100644 index 0000000000..8509f5d10e --- /dev/null +++ b/tests/automation/app/package.json @@ -0,0 +1,4 @@ +{ + "name": "nw-gui.App-test", + "main": "index.html" +} diff --git a/tests/automation/app_path_escape/index.html b/tests/automation/app_path_escape/index.html new file mode 100644 index 0000000000..5d7d344211 --- /dev/null +++ b/tests/automation/app_path_escape/index.html @@ -0,0 +1,9 @@ + + + + +Test path escape + + + + diff --git a/tests/automation/app_path_escape/mocha_test.js b/tests/automation/app_path_escape/mocha_test.js new file mode 100644 index 0000000000..e418b3155a --- /dev/null +++ b/tests/automation/app_path_escape/mocha_test.js @@ -0,0 +1,25 @@ +var spawn = require('child_process').spawn; +var os = require('os'); +var path = require('path'); +var global = require('../globals'); + +describe('app_path_escaping',function(){ + it('app should start normally with directory named xdk',function(done){ + this.timeout(0); + var opened = false; + var app = spawn(process.execPath, [path.join(global.tests_dir, 'xdk')]); + app.on('close',function(){ + opened = true; + done(); + }); + + setTimeout(function() { + if(!opened){ + app.kill(); + done('the app is not executed'); + } + }, 5000); + + }); +}); + diff --git a/tests/automation/app_path_escape/package.json b/tests/automation/app_path_escape/package.json new file mode 100644 index 0000000000..83005264a3 --- /dev/null +++ b/tests/automation/app_path_escape/package.json @@ -0,0 +1,4 @@ +{ +"name": "app_path_escape_wrapper", +"main": "index.html" +} diff --git a/tests/automation/app_path_escape/xdk/index.html b/tests/automation/app_path_escape/xdk/index.html new file mode 100644 index 0000000000..1b39fbb659 --- /dev/null +++ b/tests/automation/app_path_escape/xdk/index.html @@ -0,0 +1,15 @@ + + + + + test xdk + + + +hello world + + + diff --git a/tests/automation/app_path_escape/xdk/package.json b/tests/automation/app_path_escape/xdk/package.json new file mode 100644 index 0000000000..afd0be80f7 --- /dev/null +++ b/tests/automation/app_path_escape/xdk/package.json @@ -0,0 +1,4 @@ +{ + "name":"app path", + "main":"index.html" +} diff --git a/tests/automation/config.json b/tests/automation/config.json new file mode 100644 index 0000000000..98b7c1eb69 --- /dev/null +++ b/tests/automation/config.json @@ -0,0 +1,10 @@ +{ + "format": "xunit-file", + "exclude": ["node_modules", "output", "internal", "res", "app", + "document_cookies", "menu", "menu_item", "shortcut"], + "single": "", + "timeout": "5000", + "slow": "200", + "quiet": false +} + diff --git a/tests/automation/globals.js b/tests/automation/globals.js new file mode 100644 index 0000000000..24ac6fbad1 --- /dev/null +++ b/tests/automation/globals.js @@ -0,0 +1,5 @@ +var fs = require('fs'); + +exports.tests_dir = fs.realpathSync('.'); + + diff --git a/tests/automation/mocha_test.js b/tests/automation/mocha_test.js new file mode 100644 index 0000000000..990f4b970a --- /dev/null +++ b/tests/automation/mocha_test.js @@ -0,0 +1,181 @@ +var fs = require('fs'); +var path = require('path'); +var child_process = require('child_process'); +var colors = require('colors'); +//var toMarkdown = require('to-markdown').toMarkdown; + +var g_quiet = false; +var g_outputDir; +var g_outputLog; +var g_format; + +function print(str, err) { + if (!g_quiet) { + if (err) { + console.error(str); + } else { + console.log(str); + } + } + if (g_outputLog) { + fs.appendFile(g_outputLog, str + '\n'); + } +} + +function preTest() { + print(colors.green('===============')); + print(colors.green('Begin testing')); + print(colors.green('===============')); +} + +function postTest() { + print(colors.green('===============')); + print(colors.green('End testing')); + print(colors.green('===============')); + + if (g_format === 'markdown' && fs.existsSync(g_outputDir)) { + // convert xml to md for better reading + var subFiles = fs.readdirSync(g_outputDir); + for (var i = 0, len = subFiles.length; i < len; i++) { + var filePath = subFiles[i]; + if (path.extname(filePath) === '.xml') { + var conent = fs.readFileSync(path.join(g_outputDir, filePath)); + content = encodeURIComponent(conent); + var mdData = toMarkdown(content); + fs.writeFileSync(path.join(g_outputDir, path.basename(filePath)+'.md'), mdData); + } + } + } +} + +function performTests(config) { + + g_quiet = config.quiet; + + var curPath = fs.realpathSync('.'); + if (!fs.existsSync('output')) + fs.mkdirSync('output'); + g_outputDir = path.join(curPath, 'output', (new Date()).toUTCString()); + if (!fs.existsSync(g_outputDir)) + fs.mkdirSync(g_outputDir); + g_outputLog = path.join(g_outputDir, 'summary.log'); + print('The test results will output to : ' + colors.underline(g_outputDir) + '\n'); + + var subDirs = fs.readdirSync(curPath); + var testSuites = []; + var isExcluded = function(testsuite) { + for (var i = 0, len = config.exclude.length; i < len; i++) { + if (config.exclude[i] === testsuite) + return true; + } + return false; + }; + + if (config.single && config.single !== '' && fs.existsSync(path.join(curPath, config.single))) { + testSuites.push(config.single); + } else { + for (var i = 0, len = subDirs.length; i < len; i++) { + var subDir = subDirs[i]; + var status = fs.statSync(path.join(curPath, subDir)); + if (status && status.isDirectory() && !isExcluded(subDir)) { + testSuites.push(subDir); + } + } + } + + /* ============ running test cases ================ */ + if (testSuites.length === 0) { + print('No test cases are found in ' + curPath); + return; + } + preTest(); + g_format = config.format; + var arg_timeout = config.timeout ? ['--timeout', config.timeout] : []; + var arg_slow = config.slow ? ['--slow', config.slow] : []; + var argv = undefined; + var cmd = undefined; + var child = undefined; + var env = process.env; + var timerId = undefined; + var children = []; + + var timeout = parseInt(config.timeout); + if (Number.isNaN(timeout) || timeout <= 0) + timeout = 5000; + + var resetTimeout = function() { + if (timerId) + clearTimeout(timerId); + timerId = setTimeout(function() { + timerId = undefined; + for (var i = 0, len = children.length; i < len; i++) { + print(colors.red('[Timeout]: ') + colors.underline(children[i].testcase)); + children[i].kill('SIGTERM'); + } + }, timeout); + }; + + env['out_dir'] = g_outputDir; + + var bindChildExit = function(child, code, signal) { + child.on('exit', function(code, signal) { + var prefix = code === 0 ? '[Success]' : '[Failure]'; + print((code === 0 ? colors.green(prefix) : colors.red(prefix)) + + ': ' + colors.underline(child.testcase) + ' with exit code ' + code); + //console.log('Done: ' + child.testcase + ' with exit code ' + code); + var idx = children.indexOf(child); + if (idx >= 0) { + children.splice(idx, 1); + resetTimeout(); + } + if (children.length === 0) { + if (timerId) + clearTimeout(timerId); + postTest(); + } + }); + }; + + var spawTestProcessByNW = function(testcase) { + cmd = 'nw'; + argv = [testcase]; + print('Running: ' + colors.underline(testcase)); + child = child_process.spawn(cmd, argv, {env: env}); + child.testcase = testcase; + return child; + }; + + var spawTestProcessByMocha = function(testcase) { + cmd = 'mocha'; + argv = [testcase + path.sep + 'mocha_test'].concat(['-R', 'xunit-file']) + .concat(arg_timeout).concat(arg_slow); + env['XUNIT_FILE'] = path.join(g_outputDir, testcase + '.xml'); + print('Running:' + colors.underline(testcase)); + child = child_process.spawn(cmd, argv, {env: env}); + child.testcase = testcase; + return child; + }; + + for (var i = 0, len = testSuites.length; i < len; i++) { + child = spawTestProcessByNW(testSuites[i]); + if (child) { + child.testcase = testSuites[i]; + bindChildExit(child); + //(function(theChild) { + // theChild.on('exit', function(code, signal) { + // onChildExit(theChild, code, signal); + // }); + //})(child); + children.push(child); + } + } + resetTimeout(); +} // end of performTests() + +var content = fs.readFileSync('./config.json'); +if (content) + performTests(JSON.parse(content)); +else + print('Failed to read configuration.', true); + + diff --git a/tests/automation/package.json b/tests/automation/package.json new file mode 100644 index 0000000000..03957725b8 --- /dev/null +++ b/tests/automation/package.json @@ -0,0 +1,13 @@ +{ + "name": "automation", + "version": "0.1.0", + "main": "index.html", + "window": { + "position": "center", + "show": false + }, + "dependencies": { + "xunit-file": "*", + "colors": "*" + } +} diff --git a/tests/automation/res/assert.js b/tests/automation/res/assert.js new file mode 100644 index 0000000000..73c9fa55ce --- /dev/null +++ b/tests/automation/res/assert.js @@ -0,0 +1,431 @@ +// http://wiki.commonjs.org/wiki/Unit_Testing/1.0 +// +// THIS IS NOT TESTED NOR LIKELY TO WORK OUTSIDE V8! +// +// Copyright (c) 2011 Jxck +// +// Originally from node.js (http://nodejs.org) +// Copyright Joyent, Inc. +// +// 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 copies 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 +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 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. + +(function(module) { + +if (typeof module.exports === 'undefined') { + module.exports = module; // this case must be browser +} + +// UTILITY + +// Object.create compatible in IE +var create = Object.create || function(p) { + if (!p) throw Error('no type'); + function f() {}; + f.prototype = p; + return new f(); +}; + +// UTILITY +var util = { + inherits: function(ctor, superCtor) { + ctor.super_ = superCtor; + ctor.prototype = create(superCtor.prototype, { + constructor: { + value: ctor, + enumerable: false, + writable: true, + configurable: true + } + }); + }, + isArray: function(ar) { + return Array.isArray(ar); + }, + isBoolean: function(arg) { + return typeof arg === 'boolean'; + }, + isNull: function(arg) { + return arg === null; + }, + isNullOrUndefined: function(arg) { + return arg == null; + }, + isNumber: function(arg) { + return typeof arg === 'number'; + }, + isString: function(arg) { + return typeof arg === 'string'; + }, + isSymbol: function(arg) { + return typeof arg === 'symbol'; + }, + isUndefined: function(arg) { + return arg === void 0; + }, + isRegExp: function(re) { + return util.isObject(re) && util.objectToString(re) === '[object RegExp]'; + }, + isObject: function(arg) { + return typeof arg === 'object' && arg !== null; + }, + isDate: function(d) { + return util.isObject(d) && util.objectToString(d) === '[object Date]'; + }, + isError: function(e) { + return isObject(e) && + (objectToString(e) === '[object Error]' || e instanceof Error); + }, + isFunction: function(arg) { + return typeof arg === 'function'; + }, + isPrimitive: function(arg) { + return arg === null || + typeof arg === 'boolean' || + typeof arg === 'number' || + typeof arg === 'string' || + typeof arg === 'symbol' || // ES6 symbol + typeof arg === 'undefined'; + }, + objectToString: function(o) { + return Object.prototype.toString.call(o); + } +}; + +var pSlice = Array.prototype.slice; + +// from https://github.com/substack/node-deep-equal +var Object_keys = typeof Object.keys === 'function' + ? Object.keys + : function (obj) { + var keys = []; + for (var key in obj) keys.push(key); + return keys; + } +; + +// 1. The assert module provides functions that throw +// AssertionError's when particular conditions are not met. The +// assert module must conform to the following interface. + +var assert = module.exports = ok; + +// 2. The AssertionError is defined in assert. +// new assert.AssertionError({ message: message, +// actual: actual, +// expected: expected }) + +assert.AssertionError = function AssertionError(options) { + this.name = 'AssertionError'; + this.actual = options.actual; + this.expected = options.expected; + this.operator = options.operator; + if (options.message) { + this.message = options.message; + this.generatedMessage = false; + } else { + this.message = getMessage(this); + this.generatedMessage = true; + } + var stackStartFunction = options.stackStartFunction || fail; + if (Error.captureStackTrace) { + Error.captureStackTrace(this, stackStartFunction); + } else { + // try to throw an error now, and from the stack property + // work out the line that called in to assert.js. + try { + this.stack = (new Error).stack.toString(); + } catch (e) {} + } +}; + +// assert.AssertionError instanceof Error +util.inherits(assert.AssertionError, Error); + +function replacer(key, value) { + if (util.isUndefined(value)) { + return '' + value; + } + if (util.isNumber(value) && (isNaN(value) || !isFinite(value))) { + return value.toString(); + } + if (util.isFunction(value) || util.isRegExp(value)) { + return value.toString(); + } + return value; +} + +function truncate(s, n) { + if (util.isString(s)) { + return s.length < n ? s : s.slice(0, n); + } else { + return s; + } +} + +function getMessage(self) { + return truncate(JSON.stringify(self.actual, replacer), 128) + ' ' + + self.operator + ' ' + + truncate(JSON.stringify(self.expected, replacer), 128); +} + +// At present only the three keys mentioned above are used and +// understood by the spec. Implementations or sub modules can pass +// other keys to the AssertionError's constructor - they will be +// ignored. + +// 3. All of the following functions must throw an AssertionError +// when a corresponding condition is not met, with a message that +// may be undefined if not provided. All assertion methods provide +// both the actual and expected values to the assertion error for +// display purposes. + +function fail(actual, expected, message, operator, stackStartFunction) { + throw new assert.AssertionError({ + message: message, + actual: actual, + expected: expected, + operator: operator, + stackStartFunction: stackStartFunction + }); +} + +// EXTENSION! allows for well behaved errors defined elsewhere. +assert.fail = fail; + +// 4. Pure assertion tests whether a value is truthy, as determined +// by !!guard. +// assert.ok(guard, message_opt); +// This statement is equivalent to assert.equal(true, !!guard, +// message_opt);. To test strictly for the value true, use +// assert.strictEqual(true, guard, message_opt);. + +function ok(value, message) { + if (!value) fail(value, true, message, '==', assert.ok); +} +assert.ok = ok; + +// 5. The equality assertion tests shallow, coercive equality with +// ==. +// assert.equal(actual, expected, message_opt); + +assert.equal = function equal(actual, expected, message) { + if (actual != expected) fail(actual, expected, message, '==', assert.equal); +}; + +// 6. The non-equality assertion tests for whether two objects are not equal +// with != assert.notEqual(actual, expected, message_opt); + +assert.notEqual = function notEqual(actual, expected, message) { + if (actual == expected) { + fail(actual, expected, message, '!=', assert.notEqual); + } +}; + +// 7. The equivalence assertion tests a deep equality relation. +// assert.deepEqual(actual, expected, message_opt); + +assert.deepEqual = function deepEqual(actual, expected, message) { + if (!_deepEqual(actual, expected)) { + fail(actual, expected, message, 'deepEqual', assert.deepEqual); + } +}; + +function _deepEqual(actual, expected) { + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + return true; + + // } else if (util.isBuffer(actual) && util.isBuffer(expected)) { + // if (actual.length != expected.length) return false; + // + // for (var i = 0; i < actual.length; i++) { + // if (actual[i] !== expected[i]) return false; + // } + // + // return true; + // + // 7.2. If the expected value is a Date object, the actual value is + // equivalent if it is also a Date object that refers to the same time. + } else if (util.isDate(actual) && util.isDate(expected)) { + return actual.getTime() === expected.getTime(); + + // 7.3 If the expected value is a RegExp object, the actual value is + // equivalent if it is also a RegExp object with the same source and + // properties (`global`, `multiline`, `lastIndex`, `ignoreCase`). + } else if (util.isRegExp(actual) && util.isRegExp(expected)) { + return actual.source === expected.source && + actual.global === expected.global && + actual.multiline === expected.multiline && + actual.lastIndex === expected.lastIndex && + actual.ignoreCase === expected.ignoreCase; + + // 7.4. Other pairs that do not both pass typeof value == 'object', + // equivalence is determined by ==. + } else if (!util.isObject(actual) && !util.isObject(expected)) { + return actual == expected; + + // 7.5 For all other Object pairs, including Array objects, equivalence is + // determined by having the same number of owned properties (as verified + // with Object.prototype.hasOwnProperty.call), the same set of keys + // (although not necessarily the same order), equivalent values for every + // corresponding key, and an identical 'prototype' property. Note: this + // accounts for both named and indexed properties on Arrays. + } else { + return objEquiv(actual, expected); + } +} + +function isArguments(object) { + return Object.prototype.toString.call(object) == '[object Arguments]'; +} + +function objEquiv(a, b) { + if (util.isNullOrUndefined(a) || util.isNullOrUndefined(b)) + return false; + // an identical 'prototype' property. + if (a.prototype !== b.prototype) return false; + //~~~I've managed to break Object.keys through screwy arguments passing. + // Converting to array solves the problem. + var aIsArgs = isArguments(a), + bIsArgs = isArguments(b); + if ((aIsArgs && !bIsArgs) || (!aIsArgs && bIsArgs)) + return false; + if (aIsArgs) { + a = pSlice.call(a); + b = pSlice.call(b); + return _deepEqual(a, b); + } + try { + var ka = Object.keys(a), + kb = Object.keys(b), + key, i; + } catch (e) {//happens when one is a string literal and the other isn't + return false; + } + // having the same number of owned properties (keys incorporates + // hasOwnProperty) + if (ka.length != kb.length) + return false; + //the same set of keys (although not necessarily the same order), + ka.sort(); + kb.sort(); + //~~~cheap key test + for (i = ka.length - 1; i >= 0; i--) { + if (ka[i] != kb[i]) + return false; + } + //equivalent values for every corresponding key, and + //~~~possibly expensive deep test + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!_deepEqual(a[key], b[key])) return false; + } + return true; +} + +// 8. The non-equivalence assertion tests for any deep inequality. +// assert.notDeepEqual(actual, expected, message_opt); + +assert.notDeepEqual = function notDeepEqual(actual, expected, message) { + if (_deepEqual(actual, expected)) { + fail(actual, expected, message, 'notDeepEqual', assert.notDeepEqual); + } +}; + +// 9. The strict equality assertion tests strict equality, as determined by ===. +// assert.strictEqual(actual, expected, message_opt); + +assert.strictEqual = function strictEqual(actual, expected, message) { + if (actual !== expected) { + fail(actual, expected, message, '===', assert.strictEqual); + } +}; + +// 10. The strict non-equality assertion tests for strict inequality, as +// determined by !==. assert.notStrictEqual(actual, expected, message_opt); + +assert.notStrictEqual = function notStrictEqual(actual, expected, message) { + if (actual === expected) { + fail(actual, expected, message, '!==', assert.notStrictEqual); + } +}; + +function expectedException(actual, expected) { + if (!actual || !expected) { + return false; + } + + if (Object.prototype.toString.call(expected) == '[object RegExp]') { + return expected.test(actual); + } else if (actual instanceof expected) { + return true; + } else if (expected.call({}, actual) === true) { + return true; + } + + return false; +} + +function _throws(shouldThrow, block, expected, message) { + var actual; + + if (util.isString(expected)) { + message = expected; + expected = null; + } + + try { + block(); + } catch (e) { + actual = e; + } + + message = (expected && expected.name ? ' (' + expected.name + ').' : '.') + + (message ? ' ' + message : '.'); + + if (shouldThrow && !actual) { + fail(actual, expected, 'Missing expected exception' + message); + } + + if (!shouldThrow && expectedException(actual, expected)) { + fail(actual, expected, 'Got unwanted exception' + message); + } + + if ((shouldThrow && actual && expected && + !expectedException(actual, expected)) || (!shouldThrow && actual)) { + throw actual; + } +} + +// 11. Expected to throw an error: +// assert.throws(block, Error_opt, message_opt); + +assert.throws = function(block, /*optional*/error, /*optional*/message) { + _throws.apply(this, [true].concat(pSlice.call(arguments))); +}; + +// EXTENSION! This is annoying to write outside this module. +assert.doesNotThrow = function(block, /*optional*/message) { + _throws.apply(this, [false].concat(pSlice.call(arguments))); +}; + +assert.ifError = function(err) { if (err) {throw err;}}; + +module.assert = module.exports; +delete module.exports; +})(this); diff --git a/tests/automation/res/build.sh b/tests/automation/res/build.sh new file mode 100755 index 0000000000..484afb91fd --- /dev/null +++ b/tests/automation/res/build.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +uglifyjs mocha.js chai.js assert.js util.js -c -m -o mocha_util.js + diff --git a/tests/automation/res/chai.js b/tests/automation/res/chai.js new file mode 100644 index 0000000000..75eaecbb65 --- /dev/null +++ b/tests/automation/res/chai.js @@ -0,0 +1,4800 @@ + +;(function(){ + +/** + * Require the module at `name`. + * + * @param {String} name + * @return {Object} exports + * @api public + */ + +function require(name) { + var module = require.modules[name]; + if (!module) throw new Error('failed to require "' + name + '"'); + + if (!('exports' in module) && typeof module.definition === 'function') { + module.client = module.component = true; + module.definition.call(this, module.exports = {}, module); + delete module.definition; + } + + return module.exports; +} + +/** + * Meta info, accessible in the global scope unless you use AMD option. + */ + +require.loader = 'component'; + +/** + * Internal helper object, contains a sorting function for semantiv versioning + */ +require.helper = {}; +require.helper.semVerSort = function(a, b) { + var aArray = a.version.split('.'); + var bArray = b.version.split('.'); + for (var i=0; i bLex ? 1 : -1; + continue; + } else if (aInt > bInt) { + return 1; + } else { + return -1; + } + } + return 0; +} + +/** + * Find and require a module which name starts with the provided name. + * If multiple modules exists, the highest semver is used. + * This function can only be used for remote dependencies. + + * @param {String} name - module name: `user~repo` + * @param {Boolean} returnPath - returns the canonical require path if true, + * otherwise it returns the epxorted module + */ +require.latest = function (name, returnPath) { + function showError(name) { + throw new Error('failed to find latest module of "' + name + '"'); + } + // only remotes with semvers, ignore local files conataining a '/' + var versionRegexp = /(.*)~(.*)@v?(\d+\.\d+\.\d+[^\/]*)$/; + var remoteRegexp = /(.*)~(.*)/; + if (!remoteRegexp.test(name)) showError(name); + var moduleNames = Object.keys(require.modules); + var semVerCandidates = []; + var otherCandidates = []; // for instance: name of the git branch + for (var i=0; i 0) { + var module = semVerCandidates.sort(require.helper.semVerSort).pop().name; + if (returnPath === true) { + return module; + } + return require(module); + } + // if the build contains more than one branch of the same module + // you should not use this funciton + var module = otherCandidates.pop().name; + if (returnPath === true) { + return module; + } + return require(module); +} + +/** + * Registered modules. + */ + +require.modules = {}; + +/** + * Register module at `name` with callback `definition`. + * + * @param {String} name + * @param {Function} definition + * @api private + */ + +require.register = function (name, definition) { + require.modules[name] = { + definition: definition + }; +}; + +/** + * Define a module's exports immediately with `exports`. + * + * @param {String} name + * @param {Generic} exports + * @api private + */ + +require.define = function (name, exports) { + require.modules[name] = { + exports: exports + }; +}; +require.register("chaijs~assertion-error@1.0.0", function (exports, module) { +/*! + * assertion-error + * Copyright(c) 2013 Jake Luer + * MIT Licensed + */ + +/*! + * Return a function that will copy properties from + * one object to another excluding any originally + * listed. Returned function will create a new `{}`. + * + * @param {String} excluded properties ... + * @return {Function} + */ + +function exclude () { + var excludes = [].slice.call(arguments); + + function excludeProps (res, obj) { + Object.keys(obj).forEach(function (key) { + if (!~excludes.indexOf(key)) res[key] = obj[key]; + }); + } + + return function extendExclude () { + var args = [].slice.call(arguments) + , i = 0 + , res = {}; + + for (; i < args.length; i++) { + excludeProps(res, args[i]); + } + + return res; + }; +}; + +/*! + * Primary Exports + */ + +module.exports = AssertionError; + +/** + * ### AssertionError + * + * An extension of the JavaScript `Error` constructor for + * assertion and validation scenarios. + * + * @param {String} message + * @param {Object} properties to include (optional) + * @param {callee} start stack function (optional) + */ + +function AssertionError (message, _props, ssf) { + var extend = exclude('name', 'message', 'stack', 'constructor', 'toJSON') + , props = extend(_props || {}); + + // default values + this.message = message || 'Unspecified AssertionError'; + this.showDiff = false; + + // copy from properties + for (var key in props) { + this[key] = props[key]; + } + + // capture stack trace + ssf = ssf || arguments.callee; + if (ssf && Error.captureStackTrace) { + Error.captureStackTrace(this, ssf); + } +} + +/*! + * Inherit from Error.prototype + */ + +AssertionError.prototype = Object.create(Error.prototype); + +/*! + * Statically set name + */ + +AssertionError.prototype.name = 'AssertionError'; + +/*! + * Ensure correct constructor + */ + +AssertionError.prototype.constructor = AssertionError; + +/** + * Allow errors to be converted to JSON for static transfer. + * + * @param {Boolean} include stack (default: `true`) + * @return {Object} object that can be `JSON.stringify` + */ + +AssertionError.prototype.toJSON = function (stack) { + var extend = exclude('constructor', 'toJSON', 'stack') + , props = extend({ name: this.name }, this); + + // include stack if exists and not turned off + if (false !== stack && this.stack) { + props.stack = this.stack; + } + + return props; +}; + +}); + +require.register("chaijs~type-detect@0.1.1", function (exports, module) { +/*! + * type-detect + * Copyright(c) 2013 jake luer + * MIT Licensed + */ + +/*! + * Primary Exports + */ + +var exports = module.exports = getType; + +/*! + * Detectable javascript natives + */ + +var natives = { + '[object Array]': 'array' + , '[object RegExp]': 'regexp' + , '[object Function]': 'function' + , '[object Arguments]': 'arguments' + , '[object Date]': 'date' +}; + +/** + * ### typeOf (obj) + * + * Use several different techniques to determine + * the type of object being tested. + * + * + * @param {Mixed} object + * @return {String} object type + * @api public + */ + +function getType (obj) { + var str = Object.prototype.toString.call(obj); + if (natives[str]) return natives[str]; + if (obj === null) return 'null'; + if (obj === undefined) return 'undefined'; + if (obj === Object(obj)) return 'object'; + return typeof obj; +} + +exports.Library = Library; + +/** + * ### Library + * + * Create a repository for custom type detection. + * + * ```js + * var lib = new type.Library; + * ``` + * + */ + +function Library () { + this.tests = {}; +} + +/** + * #### .of (obj) + * + * Expose replacement `typeof` detection to the library. + * + * ```js + * if ('string' === lib.of('hello world')) { + * // ... + * } + * ``` + * + * @param {Mixed} object to test + * @return {String} type + */ + +Library.prototype.of = getType; + +/** + * #### .define (type, test) + * + * Add a test to for the `.test()` assertion. + * + * Can be defined as a regular expression: + * + * ```js + * lib.define('int', /^[0-9]+$/); + * ``` + * + * ... or as a function: + * + * ```js + * lib.define('bln', function (obj) { + * if ('boolean' === lib.of(obj)) return true; + * var blns = [ 'yes', 'no', 'true', 'false', 1, 0 ]; + * if ('string' === lib.of(obj)) obj = obj.toLowerCase(); + * return !! ~blns.indexOf(obj); + * }); + * ``` + * + * @param {String} type + * @param {RegExp|Function} test + * @api public + */ + +Library.prototype.define = function (type, test) { + if (arguments.length === 1) return this.tests[type]; + this.tests[type] = test; + return this; +}; + +/** + * #### .test (obj, test) + * + * Assert that an object is of type. Will first + * check natives, and if that does not pass it will + * use the user defined custom tests. + * + * ```js + * assert(lib.test('1', 'int')); + * assert(lib.test('yes', 'bln')); + * ``` + * + * @param {Mixed} object + * @param {String} type + * @return {Boolean} result + * @api public + */ + +Library.prototype.test = function (obj, type) { + if (type === getType(obj)) return true; + var test = this.tests[type]; + + if (test && 'regexp' === getType(test)) { + return test.test(obj); + } else if (test && 'function' === getType(test)) { + return test(obj); + } else { + throw new ReferenceError('Type test "' + type + '" not defined or invalid.'); + } +}; + +}); + +require.register("chaijs~deep-eql@0.1.3", function (exports, module) { +/*! + * deep-eql + * Copyright(c) 2013 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependencies + */ + +var type = require('chaijs~type-detect@0.1.1'); + +/*! + * Buffer.isBuffer browser shim + */ + +var Buffer; +try { Buffer = require('buffer').Buffer; } +catch(ex) { + Buffer = {}; + Buffer.isBuffer = function() { return false; } +} + +/*! + * Primary Export + */ + +module.exports = deepEqual; + +/** + * Assert super-strict (egal) equality between + * two objects of any type. + * + * @param {Mixed} a + * @param {Mixed} b + * @param {Array} memoised (optional) + * @return {Boolean} equal match + */ + +function deepEqual(a, b, m) { + if (sameValue(a, b)) { + return true; + } else if ('date' === type(a)) { + return dateEqual(a, b); + } else if ('regexp' === type(a)) { + return regexpEqual(a, b); + } else if (Buffer.isBuffer(a)) { + return bufferEqual(a, b); + } else if ('arguments' === type(a)) { + return argumentsEqual(a, b, m); + } else if (!typeEqual(a, b)) { + return false; + } else if (('object' !== type(a) && 'object' !== type(b)) + && ('array' !== type(a) && 'array' !== type(b))) { + return sameValue(a, b); + } else { + return objectEqual(a, b, m); + } +} + +/*! + * Strict (egal) equality test. Ensures that NaN always + * equals NaN and `-0` does not equal `+0`. + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} equal match + */ + +function sameValue(a, b) { + if (a === b) return a !== 0 || 1 / a === 1 / b; + return a !== a && b !== b; +} + +/*! + * Compare the types of two given objects and + * return if they are equal. Note that an Array + * has a type of `array` (not `object`) and arguments + * have a type of `arguments` (not `array`/`object`). + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function typeEqual(a, b) { + return type(a) === type(b); +} + +/*! + * Compare two Date objects by asserting that + * the time values are equal using `saveValue`. + * + * @param {Date} a + * @param {Date} b + * @return {Boolean} result + */ + +function dateEqual(a, b) { + if ('date' !== type(b)) return false; + return sameValue(a.getTime(), b.getTime()); +} + +/*! + * Compare two regular expressions by converting them + * to string and checking for `sameValue`. + * + * @param {RegExp} a + * @param {RegExp} b + * @return {Boolean} result + */ + +function regexpEqual(a, b) { + if ('regexp' !== type(b)) return false; + return sameValue(a.toString(), b.toString()); +} + +/*! + * Assert deep equality of two `arguments` objects. + * Unfortunately, these must be sliced to arrays + * prior to test to ensure no bad behavior. + * + * @param {Arguments} a + * @param {Arguments} b + * @param {Array} memoize (optional) + * @return {Boolean} result + */ + +function argumentsEqual(a, b, m) { + if ('arguments' !== type(b)) return false; + a = [].slice.call(a); + b = [].slice.call(b); + return deepEqual(a, b, m); +} + +/*! + * Get enumerable properties of a given object. + * + * @param {Object} a + * @return {Array} property names + */ + +function enumerable(a) { + var res = []; + for (var key in a) res.push(key); + return res; +} + +/*! + * Simple equality for flat iterable objects + * such as Arrays or Node.js buffers. + * + * @param {Iterable} a + * @param {Iterable} b + * @return {Boolean} result + */ + +function iterableEqual(a, b) { + if (a.length !== b.length) return false; + + var i = 0; + var match = true; + + for (; i < a.length; i++) { + if (a[i] !== b[i]) { + match = false; + break; + } + } + + return match; +} + +/*! + * Extension to `iterableEqual` specifically + * for Node.js Buffers. + * + * @param {Buffer} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function bufferEqual(a, b) { + if (!Buffer.isBuffer(b)) return false; + return iterableEqual(a, b); +} + +/*! + * Block for `objectEqual` ensuring non-existing + * values don't get in. + * + * @param {Mixed} object + * @return {Boolean} result + */ + +function isValue(a) { + return a !== null && a !== undefined; +} + +/*! + * Recursively check the equality of two objects. + * Once basic sameness has been established it will + * defer to `deepEqual` for each enumerable key + * in the object. + * + * @param {Mixed} a + * @param {Mixed} b + * @return {Boolean} result + */ + +function objectEqual(a, b, m) { + if (!isValue(a) || !isValue(b)) { + return false; + } + + if (a.prototype !== b.prototype) { + return false; + } + + var i; + if (m) { + for (i = 0; i < m.length; i++) { + if ((m[i][0] === a && m[i][1] === b) + || (m[i][0] === b && m[i][1] === a)) { + return true; + } + } + } else { + m = []; + } + + try { + var ka = enumerable(a); + var kb = enumerable(b); + } catch (ex) { + return false; + } + + ka.sort(); + kb.sort(); + + if (!iterableEqual(ka, kb)) { + return false; + } + + m.push([ a, b ]); + + var key; + for (i = ka.length - 1; i >= 0; i--) { + key = ka[i]; + if (!deepEqual(a[key], b[key], m)) { + return false; + } + } + + return true; +} + +}); + +require.register("chai", function (exports, module) { +module.exports = require('chai/lib/chai.js'); + +}); + +require.register("chai/lib/chai.js", function (exports, module) { +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +var used = [] + , exports = module.exports = {}; + +/*! + * Chai version + */ + +exports.version = '1.10.0'; + +/*! + * Assertion Error + */ + +exports.AssertionError = require('chaijs~assertion-error@1.0.0'); + +/*! + * Utils for plugins (not exported) + */ + +var util = require('chai/lib/chai/utils/index.js'); + +/** + * # .use(function) + * + * Provides a way to extend the internals of Chai + * + * @param {Function} + * @returns {this} for chaining + * @api public + */ + +exports.use = function (fn) { + if (!~used.indexOf(fn)) { + fn(this, util); + used.push(fn); + } + + return this; +}; + +/*! + * Configuration + */ + +var config = require('chai/lib/chai/config.js'); +exports.config = config; + +/*! + * Primary `Assertion` prototype + */ + +var assertion = require('chai/lib/chai/assertion.js'); +exports.use(assertion); + +/*! + * Core Assertions + */ + +var core = require('chai/lib/chai/core/assertions.js'); +exports.use(core); + +/*! + * Expect interface + */ + +var expect = require('chai/lib/chai/interface/expect.js'); +exports.use(expect); + +/*! + * Should interface + */ + +var should = require('chai/lib/chai/interface/should.js'); +exports.use(should); + +/*! + * Assert interface + */ + +var assert = require('chai/lib/chai/interface/assert.js'); +exports.use(assert); + +}); + +require.register("chai/lib/chai/assertion.js", function (exports, module) { +/*! + * chai + * http://chaijs.com + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +var config = require('chai/lib/chai/config.js'); +var NOOP = function() { }; + +module.exports = function (_chai, util) { + /*! + * Module dependencies. + */ + + var AssertionError = _chai.AssertionError + , flag = util.flag; + + /*! + * Module export. + */ + + _chai.Assertion = Assertion; + + /*! + * Assertion Constructor + * + * Creates object for chaining. + * + * @api private + */ + + function Assertion (obj, msg, stack) { + flag(this, 'ssfi', stack || arguments.callee); + flag(this, 'object', obj); + flag(this, 'message', msg); + } + + Object.defineProperty(Assertion, 'includeStack', { + get: function() { + console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); + return config.includeStack; + }, + set: function(value) { + console.warn('Assertion.includeStack is deprecated, use chai.config.includeStack instead.'); + config.includeStack = value; + } + }); + + Object.defineProperty(Assertion, 'showDiff', { + get: function() { + console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); + return config.showDiff; + }, + set: function(value) { + console.warn('Assertion.showDiff is deprecated, use chai.config.showDiff instead.'); + config.showDiff = value; + } + }); + + Assertion.addProperty = function (name, fn) { + util.addProperty(this.prototype, name, fn); + }; + + Assertion.addMethod = function (name, fn) { + util.addMethod(this.prototype, name, fn); + }; + + Assertion.addChainableMethod = function (name, fn, chainingBehavior) { + util.addChainableMethod(this.prototype, name, fn, chainingBehavior); + }; + + Assertion.addChainableNoop = function(name, fn) { + util.addChainableMethod(this.prototype, name, NOOP, fn); + }; + + Assertion.overwriteProperty = function (name, fn) { + util.overwriteProperty(this.prototype, name, fn); + }; + + Assertion.overwriteMethod = function (name, fn) { + util.overwriteMethod(this.prototype, name, fn); + }; + + Assertion.overwriteChainableMethod = function (name, fn, chainingBehavior) { + util.overwriteChainableMethod(this.prototype, name, fn, chainingBehavior); + }; + + /*! + * ### .assert(expression, message, negateMessage, expected, actual) + * + * Executes an expression and check expectations. Throws AssertionError for reporting if test doesn't pass. + * + * @name assert + * @param {Philosophical} expression to be tested + * @param {String or Function} message or function that returns message to display if fails + * @param {String or Function} negatedMessage or function that returns negatedMessage to display if negated expression fails + * @param {Mixed} expected value (remember to check for negation) + * @param {Mixed} actual (optional) will default to `this.obj` + * @api private + */ + + Assertion.prototype.assert = function (expr, msg, negateMsg, expected, _actual, showDiff) { + var ok = util.test(this, arguments); + if (true !== showDiff) showDiff = false; + if (true !== config.showDiff) showDiff = false; + + if (!ok) { + var msg = util.getMessage(this, arguments) + , actual = util.getActual(this, arguments); + throw new AssertionError(msg, { + actual: actual + , expected: expected + , showDiff: showDiff + }, (config.includeStack) ? this.assert : flag(this, 'ssfi')); + } + }; + + /*! + * ### ._obj + * + * Quick reference to stored `actual` value for plugin developers. + * + * @api private + */ + + Object.defineProperty(Assertion.prototype, '_obj', + { get: function () { + return flag(this, 'object'); + } + , set: function (val) { + flag(this, 'object', val); + } + }); +}; + +}); + +require.register("chai/lib/chai/config.js", function (exports, module) { +module.exports = { + + /** + * ### config.includeStack + * + * User configurable property, influences whether stack trace + * is included in Assertion error message. Default of false + * suppresses stack trace in the error message. + * + * chai.config.includeStack = true; // enable stack on error + * + * @param {Boolean} + * @api public + */ + + includeStack: false, + + /** + * ### config.showDiff + * + * User configurable property, influences whether or not + * the `showDiff` flag should be included in the thrown + * AssertionErrors. `false` will always be `false`; `true` + * will be true when the assertion has requested a diff + * be shown. + * + * @param {Boolean} + * @api public + */ + + showDiff: true, + + /** + * ### config.truncateThreshold + * + * User configurable property, sets length threshold for actual and + * expected values in assertion errors. If this threshold is exceeded, + * the value is truncated. + * + * Set it to zero if you want to disable truncating altogether. + * + * chai.config.truncateThreshold = 0; // disable truncating + * + * @param {Number} + * @api public + */ + + truncateThreshold: 40 + +}; + +}); + +require.register("chai/lib/chai/core/assertions.js", function (exports, module) { +/*! + * chai + * http://chaijs.com + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +module.exports = function (chai, _) { + var Assertion = chai.Assertion + , toString = Object.prototype.toString + , flag = _.flag; + + /** + * ### Language Chains + * + * The following are provided as chainable getters to + * improve the readability of your assertions. They + * do not provide testing capabilities unless they + * have been overwritten by a plugin. + * + * **Chains** + * + * - to + * - be + * - been + * - is + * - that + * - and + * - has + * - have + * - with + * - at + * - of + * - same + * + * @name language chains + * @api public + */ + + [ 'to', 'be', 'been' + , 'is', 'and', 'has', 'have' + , 'with', 'that', 'at' + , 'of', 'same' ].forEach(function (chain) { + Assertion.addProperty(chain, function () { + return this; + }); + }); + + /** + * ### .not + * + * Negates any of assertions following in the chain. + * + * expect(foo).to.not.equal('bar'); + * expect(goodFn).to.not.throw(Error); + * expect({ foo: 'baz' }).to.have.property('foo') + * .and.not.equal('bar'); + * + * @name not + * @api public + */ + + Assertion.addProperty('not', function () { + flag(this, 'negate', true); + }); + + /** + * ### .deep + * + * Sets the `deep` flag, later used by the `equal` and + * `property` assertions. + * + * expect(foo).to.deep.equal({ bar: 'baz' }); + * expect({ foo: { bar: { baz: 'quux' } } }) + * .to.have.deep.property('foo.bar.baz', 'quux'); + * + * @name deep + * @api public + */ + + Assertion.addProperty('deep', function () { + flag(this, 'deep', true); + }); + + /** + * ### .a(type) + * + * The `a` and `an` assertions are aliases that can be + * used either as language chains or to assert a value's + * type. + * + * // typeof + * expect('test').to.be.a('string'); + * expect({ foo: 'bar' }).to.be.an('object'); + * expect(null).to.be.a('null'); + * expect(undefined).to.be.an('undefined'); + * + * // language chain + * expect(foo).to.be.an.instanceof(Foo); + * + * @name a + * @alias an + * @param {String} type + * @param {String} message _optional_ + * @api public + */ + + function an (type, msg) { + if (msg) flag(this, 'message', msg); + type = type.toLowerCase(); + var obj = flag(this, 'object') + , article = ~[ 'a', 'e', 'i', 'o', 'u' ].indexOf(type.charAt(0)) ? 'an ' : 'a '; + + this.assert( + type === _.type(obj) + , 'expected #{this} to be ' + article + type + , 'expected #{this} not to be ' + article + type + ); + } + + Assertion.addChainableMethod('an', an); + Assertion.addChainableMethod('a', an); + + /** + * ### .include(value) + * + * The `include` and `contain` assertions can be used as either property + * based language chains or as methods to assert the inclusion of an object + * in an array or a substring in a string. When used as language chains, + * they toggle the `contain` flag for the `keys` assertion. + * + * expect([1,2,3]).to.include(2); + * expect('foobar').to.contain('foo'); + * expect({ foo: 'bar', hello: 'universe' }).to.include.keys('foo'); + * + * @name include + * @alias contain + * @param {Object|String|Number} obj + * @param {String} message _optional_ + * @api public + */ + + function includeChainingBehavior () { + flag(this, 'contains', true); + } + + function include (val, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var expected = false; + if (_.type(obj) === 'array' && _.type(val) === 'object') { + for (var i in obj) { + if (_.eql(obj[i], val)) { + expected = true; + break; + } + } + } else if (_.type(val) === 'object') { + if (!flag(this, 'negate')) { + for (var k in val) new Assertion(obj).property(k, val[k]); + return; + } + var subset = {} + for (var k in val) subset[k] = obj[k] + expected = _.eql(subset, val); + } else { + expected = obj && ~obj.indexOf(val) + } + this.assert( + expected + , 'expected #{this} to include ' + _.inspect(val) + , 'expected #{this} to not include ' + _.inspect(val)); + } + + Assertion.addChainableMethod('include', include, includeChainingBehavior); + Assertion.addChainableMethod('contain', include, includeChainingBehavior); + + /** + * ### .ok + * + * Asserts that the target is truthy. + * + * expect('everthing').to.be.ok; + * expect(1).to.be.ok; + * expect(false).to.not.be.ok; + * expect(undefined).to.not.be.ok; + * expect(null).to.not.be.ok; + * + * Can also be used as a function, which prevents some linter errors. + * + * expect('everthing').to.be.ok(); + * + * @name ok + * @api public + */ + + Assertion.addChainableNoop('ok', function () { + this.assert( + flag(this, 'object') + , 'expected #{this} to be truthy' + , 'expected #{this} to be falsy'); + }); + + /** + * ### .true + * + * Asserts that the target is `true`. + * + * expect(true).to.be.true; + * expect(1).to.not.be.true; + * + * Can also be used as a function, which prevents some linter errors. + * + * expect(true).to.be.true(); + * + * @name true + * @api public + */ + + Assertion.addChainableNoop('true', function () { + this.assert( + true === flag(this, 'object') + , 'expected #{this} to be true' + , 'expected #{this} to be false' + , this.negate ? false : true + ); + }); + + /** + * ### .false + * + * Asserts that the target is `false`. + * + * expect(false).to.be.false; + * expect(0).to.not.be.false; + * + * Can also be used as a function, which prevents some linter errors. + * + * expect(false).to.be.false(); + * + * @name false + * @api public + */ + + Assertion.addChainableNoop('false', function () { + this.assert( + false === flag(this, 'object') + , 'expected #{this} to be false' + , 'expected #{this} to be true' + , this.negate ? true : false + ); + }); + + /** + * ### .null + * + * Asserts that the target is `null`. + * + * expect(null).to.be.null; + * expect(undefined).not.to.be.null; + * + * Can also be used as a function, which prevents some linter errors. + * + * expect(null).to.be.null(); + * + * @name null + * @api public + */ + + Assertion.addChainableNoop('null', function () { + this.assert( + null === flag(this, 'object') + , 'expected #{this} to be null' + , 'expected #{this} not to be null' + ); + }); + + /** + * ### .undefined + * + * Asserts that the target is `undefined`. + * + * expect(undefined).to.be.undefined; + * expect(null).to.not.be.undefined; + * + * Can also be used as a function, which prevents some linter errors. + * + * expect(undefined).to.be.undefined(); + * + * @name undefined + * @api public + */ + + Assertion.addChainableNoop('undefined', function () { + this.assert( + undefined === flag(this, 'object') + , 'expected #{this} to be undefined' + , 'expected #{this} not to be undefined' + ); + }); + + /** + * ### .exist + * + * Asserts that the target is neither `null` nor `undefined`. + * + * var foo = 'hi' + * , bar = null + * , baz; + * + * expect(foo).to.exist; + * expect(bar).to.not.exist; + * expect(baz).to.not.exist; + * + * Can also be used as a function, which prevents some linter errors. + * + * expect(foo).to.exist(); + * + * @name exist + * @api public + */ + + Assertion.addChainableNoop('exist', function () { + this.assert( + null != flag(this, 'object') + , 'expected #{this} to exist' + , 'expected #{this} to not exist' + ); + }); + + + /** + * ### .empty + * + * Asserts that the target's length is `0`. For arrays, it checks + * the `length` property. For objects, it gets the count of + * enumerable keys. + * + * expect([]).to.be.empty; + * expect('').to.be.empty; + * expect({}).to.be.empty; + * + * Can also be used as a function, which prevents some linter errors. + * + * expect([]).to.be.empty(); + * + * @name empty + * @api public + */ + + Assertion.addChainableNoop('empty', function () { + var obj = flag(this, 'object') + , expected = obj; + + if (Array.isArray(obj) || 'string' === typeof object) { + expected = obj.length; + } else if (typeof obj === 'object') { + expected = Object.keys(obj).length; + } + + this.assert( + !expected + , 'expected #{this} to be empty' + , 'expected #{this} not to be empty' + ); + }); + + /** + * ### .arguments + * + * Asserts that the target is an arguments object. + * + * function test () { + * expect(arguments).to.be.arguments; + * } + * + * Can also be used as a function, which prevents some linter errors. + * + * function test () { + * expect(arguments).to.be.arguments(); + * } + * + * @name arguments + * @alias Arguments + * @api public + */ + + function checkArguments () { + var obj = flag(this, 'object') + , type = Object.prototype.toString.call(obj); + this.assert( + '[object Arguments]' === type + , 'expected #{this} to be arguments but got ' + type + , 'expected #{this} to not be arguments' + ); + } + + Assertion.addChainableNoop('arguments', checkArguments); + Assertion.addChainableNoop('Arguments', checkArguments); + + /** + * ### .equal(value) + * + * Asserts that the target is strictly equal (`===`) to `value`. + * Alternately, if the `deep` flag is set, asserts that + * the target is deeply equal to `value`. + * + * expect('hello').to.equal('hello'); + * expect(42).to.equal(42); + * expect(1).to.not.equal(true); + * expect({ foo: 'bar' }).to.not.equal({ foo: 'bar' }); + * expect({ foo: 'bar' }).to.deep.equal({ foo: 'bar' }); + * + * @name equal + * @alias equals + * @alias eq + * @alias deep.equal + * @param {Mixed} value + * @param {String} message _optional_ + * @api public + */ + + function assertEqual (val, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'deep')) { + return this.eql(val); + } else { + this.assert( + val === obj + , 'expected #{this} to equal #{exp}' + , 'expected #{this} to not equal #{exp}' + , val + , this._obj + , true + ); + } + } + + Assertion.addMethod('equal', assertEqual); + Assertion.addMethod('equals', assertEqual); + Assertion.addMethod('eq', assertEqual); + + /** + * ### .eql(value) + * + * Asserts that the target is deeply equal to `value`. + * + * expect({ foo: 'bar' }).to.eql({ foo: 'bar' }); + * expect([ 1, 2, 3 ]).to.eql([ 1, 2, 3 ]); + * + * @name eql + * @alias eqls + * @param {Mixed} value + * @param {String} message _optional_ + * @api public + */ + + function assertEql(obj, msg) { + if (msg) flag(this, 'message', msg); + this.assert( + _.eql(obj, flag(this, 'object')) + , 'expected #{this} to deeply equal #{exp}' + , 'expected #{this} to not deeply equal #{exp}' + , obj + , this._obj + , true + ); + } + + Assertion.addMethod('eql', assertEql); + Assertion.addMethod('eqls', assertEql); + + /** + * ### .above(value) + * + * Asserts that the target is greater than `value`. + * + * expect(10).to.be.above(5); + * + * Can also be used in conjunction with `length` to + * assert a minimum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.above(2); + * expect([ 1, 2, 3 ]).to.have.length.above(2); + * + * @name above + * @alias gt + * @alias greaterThan + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertAbove (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len > n + , 'expected #{this} to have a length above #{exp} but got #{act}' + , 'expected #{this} to not have a length above #{exp}' + , n + , len + ); + } else { + this.assert( + obj > n + , 'expected #{this} to be above ' + n + , 'expected #{this} to be at most ' + n + ); + } + } + + Assertion.addMethod('above', assertAbove); + Assertion.addMethod('gt', assertAbove); + Assertion.addMethod('greaterThan', assertAbove); + + /** + * ### .least(value) + * + * Asserts that the target is greater than or equal to `value`. + * + * expect(10).to.be.at.least(10); + * + * Can also be used in conjunction with `length` to + * assert a minimum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.of.at.least(2); + * expect([ 1, 2, 3 ]).to.have.length.of.at.least(3); + * + * @name least + * @alias gte + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertLeast (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len >= n + , 'expected #{this} to have a length at least #{exp} but got #{act}' + , 'expected #{this} to have a length below #{exp}' + , n + , len + ); + } else { + this.assert( + obj >= n + , 'expected #{this} to be at least ' + n + , 'expected #{this} to be below ' + n + ); + } + } + + Assertion.addMethod('least', assertLeast); + Assertion.addMethod('gte', assertLeast); + + /** + * ### .below(value) + * + * Asserts that the target is less than `value`. + * + * expect(5).to.be.below(10); + * + * Can also be used in conjunction with `length` to + * assert a maximum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.below(4); + * expect([ 1, 2, 3 ]).to.have.length.below(4); + * + * @name below + * @alias lt + * @alias lessThan + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertBelow (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len < n + , 'expected #{this} to have a length below #{exp} but got #{act}' + , 'expected #{this} to not have a length below #{exp}' + , n + , len + ); + } else { + this.assert( + obj < n + , 'expected #{this} to be below ' + n + , 'expected #{this} to be at least ' + n + ); + } + } + + Assertion.addMethod('below', assertBelow); + Assertion.addMethod('lt', assertBelow); + Assertion.addMethod('lessThan', assertBelow); + + /** + * ### .most(value) + * + * Asserts that the target is less than or equal to `value`. + * + * expect(5).to.be.at.most(5); + * + * Can also be used in conjunction with `length` to + * assert a maximum length. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.of.at.most(4); + * expect([ 1, 2, 3 ]).to.have.length.of.at.most(3); + * + * @name most + * @alias lte + * @param {Number} value + * @param {String} message _optional_ + * @api public + */ + + function assertMost (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len <= n + , 'expected #{this} to have a length at most #{exp} but got #{act}' + , 'expected #{this} to have a length above #{exp}' + , n + , len + ); + } else { + this.assert( + obj <= n + , 'expected #{this} to be at most ' + n + , 'expected #{this} to be above ' + n + ); + } + } + + Assertion.addMethod('most', assertMost); + Assertion.addMethod('lte', assertMost); + + /** + * ### .within(start, finish) + * + * Asserts that the target is within a range. + * + * expect(7).to.be.within(5,10); + * + * Can also be used in conjunction with `length` to + * assert a length range. The benefit being a + * more informative error message than if the length + * was supplied directly. + * + * expect('foo').to.have.length.within(2,4); + * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * + * @name within + * @param {Number} start lowerbound inclusive + * @param {Number} finish upperbound inclusive + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('within', function (start, finish, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object') + , range = start + '..' + finish; + if (flag(this, 'doLength')) { + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + this.assert( + len >= start && len <= finish + , 'expected #{this} to have a length within ' + range + , 'expected #{this} to not have a length within ' + range + ); + } else { + this.assert( + obj >= start && obj <= finish + , 'expected #{this} to be within ' + range + , 'expected #{this} to not be within ' + range + ); + } + }); + + /** + * ### .instanceof(constructor) + * + * Asserts that the target is an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , Chai = new Tea('chai'); + * + * expect(Chai).to.be.an.instanceof(Tea); + * expect([ 1, 2, 3 ]).to.be.instanceof(Array); + * + * @name instanceof + * @param {Constructor} constructor + * @param {String} message _optional_ + * @alias instanceOf + * @api public + */ + + function assertInstanceOf (constructor, msg) { + if (msg) flag(this, 'message', msg); + var name = _.getName(constructor); + this.assert( + flag(this, 'object') instanceof constructor + , 'expected #{this} to be an instance of ' + name + , 'expected #{this} to not be an instance of ' + name + ); + }; + + Assertion.addMethod('instanceof', assertInstanceOf); + Assertion.addMethod('instanceOf', assertInstanceOf); + + /** + * ### .property(name, [value]) + * + * Asserts that the target has a property `name`, optionally asserting that + * the value of that property is strictly equal to `value`. + * If the `deep` flag is set, you can use dot- and bracket-notation for deep + * references into objects and arrays. + * + * // simple referencing + * var obj = { foo: 'bar' }; + * expect(obj).to.have.property('foo'); + * expect(obj).to.have.property('foo', 'bar'); + * + * // deep referencing + * var deepObj = { + * green: { tea: 'matcha' } + * , teas: [ 'chai', 'matcha', { tea: 'konacha' } ] + * }; + + * expect(deepObj).to.have.deep.property('green.tea', 'matcha'); + * expect(deepObj).to.have.deep.property('teas[1]', 'matcha'); + * expect(deepObj).to.have.deep.property('teas[2].tea', 'konacha'); + * + * You can also use an array as the starting point of a `deep.property` + * assertion, or traverse nested arrays. + * + * var arr = [ + * [ 'chai', 'matcha', 'konacha' ] + * , [ { tea: 'chai' } + * , { tea: 'matcha' } + * , { tea: 'konacha' } ] + * ]; + * + * expect(arr).to.have.deep.property('[0][1]', 'matcha'); + * expect(arr).to.have.deep.property('[1][2].tea', 'konacha'); + * + * Furthermore, `property` changes the subject of the assertion + * to be the value of that property from the original object. This + * permits for further chainable assertions on that property. + * + * expect(obj).to.have.property('foo') + * .that.is.a('string'); + * expect(deepObj).to.have.property('green') + * .that.is.an('object') + * .that.deep.equals({ tea: 'matcha' }); + * expect(deepObj).to.have.property('teas') + * .that.is.an('array') + * .with.deep.property('[2]') + * .that.deep.equals({ tea: 'konacha' }); + * + * @name property + * @alias deep.property + * @param {String} name + * @param {Mixed} value (optional) + * @param {String} message _optional_ + * @returns value of property for chaining + * @api public + */ + + Assertion.addMethod('property', function (name, val, msg) { + if (msg) flag(this, 'message', msg); + + var descriptor = flag(this, 'deep') ? 'deep property ' : 'property ' + , negate = flag(this, 'negate') + , obj = flag(this, 'object') + , value = flag(this, 'deep') + ? _.getPathValue(name, obj) + : obj[name]; + + if (negate && undefined !== val) { + if (undefined === value) { + msg = (msg != null) ? msg + ': ' : ''; + throw new Error(msg + _.inspect(obj) + ' has no ' + descriptor + _.inspect(name)); + } + } else { + this.assert( + undefined !== value + , 'expected #{this} to have a ' + descriptor + _.inspect(name) + , 'expected #{this} to not have ' + descriptor + _.inspect(name)); + } + + if (undefined !== val) { + this.assert( + val === value + , 'expected #{this} to have a ' + descriptor + _.inspect(name) + ' of #{exp}, but got #{act}' + , 'expected #{this} to not have a ' + descriptor + _.inspect(name) + ' of #{act}' + , val + , value + ); + } + + flag(this, 'object', value); + }); + + + /** + * ### .ownProperty(name) + * + * Asserts that the target has an own property `name`. + * + * expect('test').to.have.ownProperty('length'); + * + * @name ownProperty + * @alias haveOwnProperty + * @param {String} name + * @param {String} message _optional_ + * @api public + */ + + function assertOwnProperty (name, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + obj.hasOwnProperty(name) + , 'expected #{this} to have own property ' + _.inspect(name) + , 'expected #{this} to not have own property ' + _.inspect(name) + ); + } + + Assertion.addMethod('ownProperty', assertOwnProperty); + Assertion.addMethod('haveOwnProperty', assertOwnProperty); + + /** + * ### .length(value) + * + * Asserts that the target's `length` property has + * the expected value. + * + * expect([ 1, 2, 3]).to.have.length(3); + * expect('foobar').to.have.length(6); + * + * Can also be used as a chain precursor to a value + * comparison for the length property. + * + * expect('foo').to.have.length.above(2); + * expect([ 1, 2, 3 ]).to.have.length.above(2); + * expect('foo').to.have.length.below(4); + * expect([ 1, 2, 3 ]).to.have.length.below(4); + * expect('foo').to.have.length.within(2,4); + * expect([ 1, 2, 3 ]).to.have.length.within(2,4); + * + * @name length + * @alias lengthOf + * @param {Number} length + * @param {String} message _optional_ + * @api public + */ + + function assertLengthChain () { + flag(this, 'doLength', true); + } + + function assertLength (n, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).to.have.property('length'); + var len = obj.length; + + this.assert( + len == n + , 'expected #{this} to have a length of #{exp} but got #{act}' + , 'expected #{this} to not have a length of #{act}' + , n + , len + ); + } + + Assertion.addChainableMethod('length', assertLength, assertLengthChain); + Assertion.addMethod('lengthOf', assertLength); + + /** + * ### .match(regexp) + * + * Asserts that the target matches a regular expression. + * + * expect('foobar').to.match(/^foo/); + * + * @name match + * @param {RegExp} RegularExpression + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('match', function (re, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + this.assert( + re.exec(obj) + , 'expected #{this} to match ' + re + , 'expected #{this} not to match ' + re + ); + }); + + /** + * ### .string(string) + * + * Asserts that the string target contains another string. + * + * expect('foobar').to.have.string('bar'); + * + * @name string + * @param {String} string + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('string', function (str, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).is.a('string'); + + this.assert( + ~obj.indexOf(str) + , 'expected #{this} to contain ' + _.inspect(str) + , 'expected #{this} to not contain ' + _.inspect(str) + ); + }); + + + /** + * ### .keys(key1, [key2], [...]) + * + * Asserts that the target has exactly the given keys, or + * asserts the inclusion of some keys when using the + * `include` or `contain` modifiers. + * + * expect({ foo: 1, bar: 2 }).to.have.keys(['foo', 'bar']); + * expect({ foo: 1, bar: 2, baz: 3 }).to.contain.keys('foo', 'bar'); + * + * @name keys + * @alias key + * @param {String...|Array} keys + * @api public + */ + + function assertKeys (keys) { + var obj = flag(this, 'object') + , str + , ok = true; + + keys = keys instanceof Array + ? keys + : Array.prototype.slice.call(arguments); + + if (!keys.length) throw new Error('keys required'); + + var actual = Object.keys(obj) + , expected = keys + , len = keys.length; + + // Inclusion + ok = keys.every(function(key){ + return ~actual.indexOf(key); + }); + + // Strict + if (!flag(this, 'negate') && !flag(this, 'contains')) { + ok = ok && keys.length == actual.length; + } + + // Key string + if (len > 1) { + keys = keys.map(function(key){ + return _.inspect(key); + }); + var last = keys.pop(); + str = keys.join(', ') + ', and ' + last; + } else { + str = _.inspect(keys[0]); + } + + // Form + str = (len > 1 ? 'keys ' : 'key ') + str; + + // Have / include + str = (flag(this, 'contains') ? 'contain ' : 'have ') + str; + + // Assertion + this.assert( + ok + , 'expected #{this} to ' + str + , 'expected #{this} to not ' + str + , expected.sort() + , actual.sort() + , true + ); + } + + Assertion.addMethod('keys', assertKeys); + Assertion.addMethod('key', assertKeys); + + /** + * ### .throw(constructor) + * + * Asserts that the function target will throw a specific error, or specific type of error + * (as determined using `instanceof`), optionally with a RegExp or string inclusion test + * for the error's message. + * + * var err = new ReferenceError('This is a bad function.'); + * var fn = function () { throw err; } + * expect(fn).to.throw(ReferenceError); + * expect(fn).to.throw(Error); + * expect(fn).to.throw(/bad function/); + * expect(fn).to.not.throw('good function'); + * expect(fn).to.throw(ReferenceError, /bad function/); + * expect(fn).to.throw(err); + * expect(fn).to.not.throw(new RangeError('Out of range.')); + * + * Please note that when a throw expectation is negated, it will check each + * parameter independently, starting with error constructor type. The appropriate way + * to check for the existence of a type of error but for a message that does not match + * is to use `and`. + * + * expect(fn).to.throw(ReferenceError) + * .and.not.throw(/good function/); + * + * @name throw + * @alias throws + * @alias Throw + * @param {ErrorConstructor} constructor + * @param {String|RegExp} expected error message + * @param {String} message _optional_ + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @returns error for chaining (null if no error) + * @api public + */ + + function assertThrows (constructor, errMsg, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + new Assertion(obj, msg).is.a('function'); + + var thrown = false + , desiredError = null + , name = null + , thrownError = null; + + if (arguments.length === 0) { + errMsg = null; + constructor = null; + } else if (constructor && (constructor instanceof RegExp || 'string' === typeof constructor)) { + errMsg = constructor; + constructor = null; + } else if (constructor && constructor instanceof Error) { + desiredError = constructor; + constructor = null; + errMsg = null; + } else if (typeof constructor === 'function') { + name = constructor.prototype.name || constructor.name; + if (name === 'Error' && constructor !== Error) { + name = (new constructor()).name; + } + } else { + constructor = null; + } + + try { + obj(); + } catch (err) { + // first, check desired error + if (desiredError) { + this.assert( + err === desiredError + , 'expected #{this} to throw #{exp} but #{act} was thrown' + , 'expected #{this} to not throw #{exp}' + , (desiredError instanceof Error ? desiredError.toString() : desiredError) + , (err instanceof Error ? err.toString() : err) + ); + + flag(this, 'object', err); + return this; + } + + // next, check constructor + if (constructor) { + this.assert( + err instanceof constructor + , 'expected #{this} to throw #{exp} but #{act} was thrown' + , 'expected #{this} to not throw #{exp} but #{act} was thrown' + , name + , (err instanceof Error ? err.toString() : err) + ); + + if (!errMsg) { + flag(this, 'object', err); + return this; + } + } + + // next, check message + var message = 'object' === _.type(err) && "message" in err + ? err.message + : '' + err; + + if ((message != null) && errMsg && errMsg instanceof RegExp) { + this.assert( + errMsg.exec(message) + , 'expected #{this} to throw error matching #{exp} but got #{act}' + , 'expected #{this} to throw error not matching #{exp}' + , errMsg + , message + ); + + flag(this, 'object', err); + return this; + } else if ((message != null) && errMsg && 'string' === typeof errMsg) { + this.assert( + ~message.indexOf(errMsg) + , 'expected #{this} to throw error including #{exp} but got #{act}' + , 'expected #{this} to throw error not including #{act}' + , errMsg + , message + ); + + flag(this, 'object', err); + return this; + } else { + thrown = true; + thrownError = err; + } + } + + var actuallyGot = '' + , expectedThrown = name !== null + ? name + : desiredError + ? '#{exp}' //_.inspect(desiredError) + : 'an error'; + + if (thrown) { + actuallyGot = ' but #{act} was thrown' + } + + this.assert( + thrown === true + , 'expected #{this} to throw ' + expectedThrown + actuallyGot + , 'expected #{this} to not throw ' + expectedThrown + actuallyGot + , (desiredError instanceof Error ? desiredError.toString() : desiredError) + , (thrownError instanceof Error ? thrownError.toString() : thrownError) + ); + + flag(this, 'object', thrownError); + }; + + Assertion.addMethod('throw', assertThrows); + Assertion.addMethod('throws', assertThrows); + Assertion.addMethod('Throw', assertThrows); + + /** + * ### .respondTo(method) + * + * Asserts that the object or class target will respond to a method. + * + * Klass.prototype.bar = function(){}; + * expect(Klass).to.respondTo('bar'); + * expect(obj).to.respondTo('bar'); + * + * To check if a constructor will respond to a static function, + * set the `itself` flag. + * + * Klass.baz = function(){}; + * expect(Klass).itself.to.respondTo('baz'); + * + * @name respondTo + * @param {String} method + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('respondTo', function (method, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object') + , itself = flag(this, 'itself') + , context = ('function' === _.type(obj) && !itself) + ? obj.prototype[method] + : obj[method]; + + this.assert( + 'function' === typeof context + , 'expected #{this} to respond to ' + _.inspect(method) + , 'expected #{this} to not respond to ' + _.inspect(method) + ); + }); + + /** + * ### .itself + * + * Sets the `itself` flag, later used by the `respondTo` assertion. + * + * function Foo() {} + * Foo.bar = function() {} + * Foo.prototype.baz = function() {} + * + * expect(Foo).itself.to.respondTo('bar'); + * expect(Foo).itself.not.to.respondTo('baz'); + * + * @name itself + * @api public + */ + + Assertion.addProperty('itself', function () { + flag(this, 'itself', true); + }); + + /** + * ### .satisfy(method) + * + * Asserts that the target passes a given truth test. + * + * expect(1).to.satisfy(function(num) { return num > 0; }); + * + * @name satisfy + * @param {Function} matcher + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('satisfy', function (matcher, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + var result = matcher(obj); + this.assert( + result + , 'expected #{this} to satisfy ' + _.objDisplay(matcher) + , 'expected #{this} to not satisfy' + _.objDisplay(matcher) + , this.negate ? false : true + , result + ); + }); + + /** + * ### .closeTo(expected, delta) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * expect(1.5).to.be.closeTo(1, 0.5); + * + * @name closeTo + * @param {Number} expected + * @param {Number} delta + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('closeTo', function (expected, delta, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + + new Assertion(obj, msg).is.a('number'); + if (_.type(expected) !== 'number' || _.type(delta) !== 'number') { + throw new Error('the arguments to closeTo must be numbers'); + } + + this.assert( + Math.abs(obj - expected) <= delta + , 'expected #{this} to be close to ' + expected + ' +/- ' + delta + , 'expected #{this} not to be close to ' + expected + ' +/- ' + delta + ); + }); + + function isSubsetOf(subset, superset, cmp) { + return subset.every(function(elem) { + if (!cmp) return superset.indexOf(elem) !== -1; + + return superset.some(function(elem2) { + return cmp(elem, elem2); + }); + }) + } + + /** + * ### .members(set) + * + * Asserts that the target is a superset of `set`, + * or that the target and `set` have the same strictly-equal (===) members. + * Alternately, if the `deep` flag is set, set members are compared for deep + * equality. + * + * expect([1, 2, 3]).to.include.members([3, 2]); + * expect([1, 2, 3]).to.not.include.members([3, 2, 8]); + * + * expect([4, 2]).to.have.members([2, 4]); + * expect([5, 2]).to.not.have.members([5, 2, 1]); + * + * expect([{ id: 1 }]).to.deep.include.members([{ id: 1 }]); + * + * @name members + * @param {Array} set + * @param {String} message _optional_ + * @api public + */ + + Assertion.addMethod('members', function (subset, msg) { + if (msg) flag(this, 'message', msg); + var obj = flag(this, 'object'); + + new Assertion(obj).to.be.an('array'); + new Assertion(subset).to.be.an('array'); + + var cmp = flag(this, 'deep') ? _.eql : undefined; + + if (flag(this, 'contains')) { + return this.assert( + isSubsetOf(subset, obj, cmp) + , 'expected #{this} to be a superset of #{act}' + , 'expected #{this} to not be a superset of #{act}' + , obj + , subset + ); + } + + this.assert( + isSubsetOf(obj, subset, cmp) && isSubsetOf(subset, obj, cmp) + , 'expected #{this} to have the same members as #{act}' + , 'expected #{this} to not have the same members as #{act}' + , obj + , subset + ); + }); +}; + +}); + +require.register("chai/lib/chai/interface/assert.js", function (exports, module) { +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + + +module.exports = function (chai, util) { + + /*! + * Chai dependencies. + */ + + var Assertion = chai.Assertion + , flag = util.flag; + + /*! + * Module export. + */ + + /** + * ### assert(expression, message) + * + * Write your own test expressions. + * + * assert('foo' !== 'bar', 'foo is not bar'); + * assert(Array.isArray([]), 'empty arrays are arrays'); + * + * @param {Mixed} expression to test for truthiness + * @param {String} message to display on error + * @name assert + * @api public + */ + + var assert = chai.assert = function (express, errmsg) { + var test = new Assertion(null, null, chai.assert); + test.assert( + express + , errmsg + , '[ negation message unavailable ]' + ); + }; + + /** + * ### .fail(actual, expected, [message], [operator]) + * + * Throw a failure. Node.js `assert` module-compatible. + * + * @name fail + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @param {String} operator + * @api public + */ + + assert.fail = function (actual, expected, message, operator) { + message = message || 'assert.fail()'; + throw new chai.AssertionError(message, { + actual: actual + , expected: expected + , operator: operator + }, assert.fail); + }; + + /** + * ### .ok(object, [message]) + * + * Asserts that `object` is truthy. + * + * assert.ok('everything', 'everything is ok'); + * assert.ok(false, 'this will fail'); + * + * @name ok + * @param {Mixed} object to test + * @param {String} message + * @api public + */ + + assert.ok = function (val, msg) { + new Assertion(val, msg).is.ok; + }; + + /** + * ### .notOk(object, [message]) + * + * Asserts that `object` is falsy. + * + * assert.notOk('everything', 'this will fail'); + * assert.notOk(false, 'this will pass'); + * + * @name notOk + * @param {Mixed} object to test + * @param {String} message + * @api public + */ + + assert.notOk = function (val, msg) { + new Assertion(val, msg).is.not.ok; + }; + + /** + * ### .equal(actual, expected, [message]) + * + * Asserts non-strict equality (`==`) of `actual` and `expected`. + * + * assert.equal(3, '3', '== coerces values to strings'); + * + * @name equal + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.equal = function (act, exp, msg) { + var test = new Assertion(act, msg, assert.equal); + + test.assert( + exp == flag(test, 'object') + , 'expected #{this} to equal #{exp}' + , 'expected #{this} to not equal #{act}' + , exp + , act + ); + }; + + /** + * ### .notEqual(actual, expected, [message]) + * + * Asserts non-strict inequality (`!=`) of `actual` and `expected`. + * + * assert.notEqual(3, 4, 'these numbers are not equal'); + * + * @name notEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.notEqual = function (act, exp, msg) { + var test = new Assertion(act, msg, assert.notEqual); + + test.assert( + exp != flag(test, 'object') + , 'expected #{this} to not equal #{exp}' + , 'expected #{this} to equal #{act}' + , exp + , act + ); + }; + + /** + * ### .strictEqual(actual, expected, [message]) + * + * Asserts strict equality (`===`) of `actual` and `expected`. + * + * assert.strictEqual(true, true, 'these booleans are strictly equal'); + * + * @name strictEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.strictEqual = function (act, exp, msg) { + new Assertion(act, msg).to.equal(exp); + }; + + /** + * ### .notStrictEqual(actual, expected, [message]) + * + * Asserts strict inequality (`!==`) of `actual` and `expected`. + * + * assert.notStrictEqual(3, '3', 'no coercion for strict equality'); + * + * @name notStrictEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.notStrictEqual = function (act, exp, msg) { + new Assertion(act, msg).to.not.equal(exp); + }; + + /** + * ### .deepEqual(actual, expected, [message]) + * + * Asserts that `actual` is deeply equal to `expected`. + * + * assert.deepEqual({ tea: 'green' }, { tea: 'green' }); + * + * @name deepEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.deepEqual = function (act, exp, msg) { + new Assertion(act, msg).to.eql(exp); + }; + + /** + * ### .notDeepEqual(actual, expected, [message]) + * + * Assert that `actual` is not deeply equal to `expected`. + * + * assert.notDeepEqual({ tea: 'green' }, { tea: 'jasmine' }); + * + * @name notDeepEqual + * @param {Mixed} actual + * @param {Mixed} expected + * @param {String} message + * @api public + */ + + assert.notDeepEqual = function (act, exp, msg) { + new Assertion(act, msg).to.not.eql(exp); + }; + + /** + * ### .isTrue(value, [message]) + * + * Asserts that `value` is true. + * + * var teaServed = true; + * assert.isTrue(teaServed, 'the tea has been served'); + * + * @name isTrue + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isTrue = function (val, msg) { + new Assertion(val, msg).is['true']; + }; + + /** + * ### .isFalse(value, [message]) + * + * Asserts that `value` is false. + * + * var teaServed = false; + * assert.isFalse(teaServed, 'no tea yet? hmm...'); + * + * @name isFalse + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isFalse = function (val, msg) { + new Assertion(val, msg).is['false']; + }; + + /** + * ### .isNull(value, [message]) + * + * Asserts that `value` is null. + * + * assert.isNull(err, 'there was no error'); + * + * @name isNull + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNull = function (val, msg) { + new Assertion(val, msg).to.equal(null); + }; + + /** + * ### .isNotNull(value, [message]) + * + * Asserts that `value` is not null. + * + * var tea = 'tasty chai'; + * assert.isNotNull(tea, 'great, time for tea!'); + * + * @name isNotNull + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotNull = function (val, msg) { + new Assertion(val, msg).to.not.equal(null); + }; + + /** + * ### .isUndefined(value, [message]) + * + * Asserts that `value` is `undefined`. + * + * var tea; + * assert.isUndefined(tea, 'no tea defined'); + * + * @name isUndefined + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isUndefined = function (val, msg) { + new Assertion(val, msg).to.equal(undefined); + }; + + /** + * ### .isDefined(value, [message]) + * + * Asserts that `value` is not `undefined`. + * + * var tea = 'cup of chai'; + * assert.isDefined(tea, 'tea has been defined'); + * + * @name isDefined + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isDefined = function (val, msg) { + new Assertion(val, msg).to.not.equal(undefined); + }; + + /** + * ### .isFunction(value, [message]) + * + * Asserts that `value` is a function. + * + * function serveTea() { return 'cup of tea'; }; + * assert.isFunction(serveTea, 'great, we can have tea now'); + * + * @name isFunction + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isFunction = function (val, msg) { + new Assertion(val, msg).to.be.a('function'); + }; + + /** + * ### .isNotFunction(value, [message]) + * + * Asserts that `value` is _not_ a function. + * + * var serveTea = [ 'heat', 'pour', 'sip' ]; + * assert.isNotFunction(serveTea, 'great, we have listed the steps'); + * + * @name isNotFunction + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotFunction = function (val, msg) { + new Assertion(val, msg).to.not.be.a('function'); + }; + + /** + * ### .isObject(value, [message]) + * + * Asserts that `value` is an object (as revealed by + * `Object.prototype.toString`). + * + * var selection = { name: 'Chai', serve: 'with spices' }; + * assert.isObject(selection, 'tea selection is an object'); + * + * @name isObject + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isObject = function (val, msg) { + new Assertion(val, msg).to.be.a('object'); + }; + + /** + * ### .isNotObject(value, [message]) + * + * Asserts that `value` is _not_ an object. + * + * var selection = 'chai' + * assert.isNotObject(selection, 'tea selection is not an object'); + * assert.isNotObject(null, 'null is not an object'); + * + * @name isNotObject + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotObject = function (val, msg) { + new Assertion(val, msg).to.not.be.a('object'); + }; + + /** + * ### .isArray(value, [message]) + * + * Asserts that `value` is an array. + * + * var menu = [ 'green', 'chai', 'oolong' ]; + * assert.isArray(menu, 'what kind of tea do we want?'); + * + * @name isArray + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isArray = function (val, msg) { + new Assertion(val, msg).to.be.an('array'); + }; + + /** + * ### .isNotArray(value, [message]) + * + * Asserts that `value` is _not_ an array. + * + * var menu = 'green|chai|oolong'; + * assert.isNotArray(menu, 'what kind of tea do we want?'); + * + * @name isNotArray + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotArray = function (val, msg) { + new Assertion(val, msg).to.not.be.an('array'); + }; + + /** + * ### .isString(value, [message]) + * + * Asserts that `value` is a string. + * + * var teaOrder = 'chai'; + * assert.isString(teaOrder, 'order placed'); + * + * @name isString + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isString = function (val, msg) { + new Assertion(val, msg).to.be.a('string'); + }; + + /** + * ### .isNotString(value, [message]) + * + * Asserts that `value` is _not_ a string. + * + * var teaOrder = 4; + * assert.isNotString(teaOrder, 'order placed'); + * + * @name isNotString + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotString = function (val, msg) { + new Assertion(val, msg).to.not.be.a('string'); + }; + + /** + * ### .isNumber(value, [message]) + * + * Asserts that `value` is a number. + * + * var cups = 2; + * assert.isNumber(cups, 'how many cups'); + * + * @name isNumber + * @param {Number} value + * @param {String} message + * @api public + */ + + assert.isNumber = function (val, msg) { + new Assertion(val, msg).to.be.a('number'); + }; + + /** + * ### .isNotNumber(value, [message]) + * + * Asserts that `value` is _not_ a number. + * + * var cups = '2 cups please'; + * assert.isNotNumber(cups, 'how many cups'); + * + * @name isNotNumber + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotNumber = function (val, msg) { + new Assertion(val, msg).to.not.be.a('number'); + }; + + /** + * ### .isBoolean(value, [message]) + * + * Asserts that `value` is a boolean. + * + * var teaReady = true + * , teaServed = false; + * + * assert.isBoolean(teaReady, 'is the tea ready'); + * assert.isBoolean(teaServed, 'has tea been served'); + * + * @name isBoolean + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isBoolean = function (val, msg) { + new Assertion(val, msg).to.be.a('boolean'); + }; + + /** + * ### .isNotBoolean(value, [message]) + * + * Asserts that `value` is _not_ a boolean. + * + * var teaReady = 'yep' + * , teaServed = 'nope'; + * + * assert.isNotBoolean(teaReady, 'is the tea ready'); + * assert.isNotBoolean(teaServed, 'has tea been served'); + * + * @name isNotBoolean + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.isNotBoolean = function (val, msg) { + new Assertion(val, msg).to.not.be.a('boolean'); + }; + + /** + * ### .typeOf(value, name, [message]) + * + * Asserts that `value`'s type is `name`, as determined by + * `Object.prototype.toString`. + * + * assert.typeOf({ tea: 'chai' }, 'object', 'we have an object'); + * assert.typeOf(['chai', 'jasmine'], 'array', 'we have an array'); + * assert.typeOf('tea', 'string', 'we have a string'); + * assert.typeOf(/tea/, 'regexp', 'we have a regular expression'); + * assert.typeOf(null, 'null', 'we have a null'); + * assert.typeOf(undefined, 'undefined', 'we have an undefined'); + * + * @name typeOf + * @param {Mixed} value + * @param {String} name + * @param {String} message + * @api public + */ + + assert.typeOf = function (val, type, msg) { + new Assertion(val, msg).to.be.a(type); + }; + + /** + * ### .notTypeOf(value, name, [message]) + * + * Asserts that `value`'s type is _not_ `name`, as determined by + * `Object.prototype.toString`. + * + * assert.notTypeOf('tea', 'number', 'strings are not numbers'); + * + * @name notTypeOf + * @param {Mixed} value + * @param {String} typeof name + * @param {String} message + * @api public + */ + + assert.notTypeOf = function (val, type, msg) { + new Assertion(val, msg).to.not.be.a(type); + }; + + /** + * ### .instanceOf(object, constructor, [message]) + * + * Asserts that `value` is an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , chai = new Tea('chai'); + * + * assert.instanceOf(chai, Tea, 'chai is an instance of tea'); + * + * @name instanceOf + * @param {Object} object + * @param {Constructor} constructor + * @param {String} message + * @api public + */ + + assert.instanceOf = function (val, type, msg) { + new Assertion(val, msg).to.be.instanceOf(type); + }; + + /** + * ### .notInstanceOf(object, constructor, [message]) + * + * Asserts `value` is not an instance of `constructor`. + * + * var Tea = function (name) { this.name = name; } + * , chai = new String('chai'); + * + * assert.notInstanceOf(chai, Tea, 'chai is not an instance of tea'); + * + * @name notInstanceOf + * @param {Object} object + * @param {Constructor} constructor + * @param {String} message + * @api public + */ + + assert.notInstanceOf = function (val, type, msg) { + new Assertion(val, msg).to.not.be.instanceOf(type); + }; + + /** + * ### .include(haystack, needle, [message]) + * + * Asserts that `haystack` includes `needle`. Works + * for strings and arrays. + * + * assert.include('foobar', 'bar', 'foobar contains string "bar"'); + * assert.include([ 1, 2, 3 ], 3, 'array contains value'); + * + * @name include + * @param {Array|String} haystack + * @param {Mixed} needle + * @param {String} message + * @api public + */ + + assert.include = function (exp, inc, msg) { + new Assertion(exp, msg, assert.include).include(inc); + }; + + /** + * ### .notInclude(haystack, needle, [message]) + * + * Asserts that `haystack` does not include `needle`. Works + * for strings and arrays. + *i + * assert.notInclude('foobar', 'baz', 'string not include substring'); + * assert.notInclude([ 1, 2, 3 ], 4, 'array not include contain value'); + * + * @name notInclude + * @param {Array|String} haystack + * @param {Mixed} needle + * @param {String} message + * @api public + */ + + assert.notInclude = function (exp, inc, msg) { + new Assertion(exp, msg, assert.notInclude).not.include(inc); + }; + + /** + * ### .match(value, regexp, [message]) + * + * Asserts that `value` matches the regular expression `regexp`. + * + * assert.match('foobar', /^foo/, 'regexp matches'); + * + * @name match + * @param {Mixed} value + * @param {RegExp} regexp + * @param {String} message + * @api public + */ + + assert.match = function (exp, re, msg) { + new Assertion(exp, msg).to.match(re); + }; + + /** + * ### .notMatch(value, regexp, [message]) + * + * Asserts that `value` does not match the regular expression `regexp`. + * + * assert.notMatch('foobar', /^foo/, 'regexp does not match'); + * + * @name notMatch + * @param {Mixed} value + * @param {RegExp} regexp + * @param {String} message + * @api public + */ + + assert.notMatch = function (exp, re, msg) { + new Assertion(exp, msg).to.not.match(re); + }; + + /** + * ### .property(object, property, [message]) + * + * Asserts that `object` has a property named by `property`. + * + * assert.property({ tea: { green: 'matcha' }}, 'tea'); + * + * @name property + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.property = function (obj, prop, msg) { + new Assertion(obj, msg).to.have.property(prop); + }; + + /** + * ### .notProperty(object, property, [message]) + * + * Asserts that `object` does _not_ have a property named by `property`. + * + * assert.notProperty({ tea: { green: 'matcha' }}, 'coffee'); + * + * @name notProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.notProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.not.have.property(prop); + }; + + /** + * ### .deepProperty(object, property, [message]) + * + * Asserts that `object` has a property named by `property`, which can be a + * string using dot- and bracket-notation for deep reference. + * + * assert.deepProperty({ tea: { green: 'matcha' }}, 'tea.green'); + * + * @name deepProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.deepProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.have.deep.property(prop); + }; + + /** + * ### .notDeepProperty(object, property, [message]) + * + * Asserts that `object` does _not_ have a property named by `property`, which + * can be a string using dot- and bracket-notation for deep reference. + * + * assert.notDeepProperty({ tea: { green: 'matcha' }}, 'tea.oolong'); + * + * @name notDeepProperty + * @param {Object} object + * @param {String} property + * @param {String} message + * @api public + */ + + assert.notDeepProperty = function (obj, prop, msg) { + new Assertion(obj, msg).to.not.have.deep.property(prop); + }; + + /** + * ### .propertyVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property` with value given + * by `value`. + * + * assert.propertyVal({ tea: 'is good' }, 'tea', 'is good'); + * + * @name propertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.propertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.have.property(prop, val); + }; + + /** + * ### .propertyNotVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property`, but with a value + * different from that given by `value`. + * + * assert.propertyNotVal({ tea: 'is good' }, 'tea', 'is bad'); + * + * @name propertyNotVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.propertyNotVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.not.have.property(prop, val); + }; + + /** + * ### .deepPropertyVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property` with value given + * by `value`. `property` can use dot- and bracket-notation for deep + * reference. + * + * assert.deepPropertyVal({ tea: { green: 'matcha' }}, 'tea.green', 'matcha'); + * + * @name deepPropertyVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.deepPropertyVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.have.deep.property(prop, val); + }; + + /** + * ### .deepPropertyNotVal(object, property, value, [message]) + * + * Asserts that `object` has a property named by `property`, but with a value + * different from that given by `value`. `property` can use dot- and + * bracket-notation for deep reference. + * + * assert.deepPropertyNotVal({ tea: { green: 'matcha' }}, 'tea.green', 'konacha'); + * + * @name deepPropertyNotVal + * @param {Object} object + * @param {String} property + * @param {Mixed} value + * @param {String} message + * @api public + */ + + assert.deepPropertyNotVal = function (obj, prop, val, msg) { + new Assertion(obj, msg).to.not.have.deep.property(prop, val); + }; + + /** + * ### .lengthOf(object, length, [message]) + * + * Asserts that `object` has a `length` property with the expected value. + * + * assert.lengthOf([1,2,3], 3, 'array has length of 3'); + * assert.lengthOf('foobar', 5, 'string has length of 6'); + * + * @name lengthOf + * @param {Mixed} object + * @param {Number} length + * @param {String} message + * @api public + */ + + assert.lengthOf = function (exp, len, msg) { + new Assertion(exp, msg).to.have.length(len); + }; + + /** + * ### .throws(function, [constructor/string/regexp], [string/regexp], [message]) + * + * Asserts that `function` will throw an error that is an instance of + * `constructor`, or alternately that it will throw an error with message + * matching `regexp`. + * + * assert.throw(fn, 'function throws a reference error'); + * assert.throw(fn, /function throws a reference error/); + * assert.throw(fn, ReferenceError); + * assert.throw(fn, ReferenceError, 'function throws a reference error'); + * assert.throw(fn, ReferenceError, /function throws a reference error/); + * + * @name throws + * @alias throw + * @alias Throw + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @api public + */ + + assert.Throw = function (fn, errt, errs, msg) { + if ('string' === typeof errt || errt instanceof RegExp) { + errs = errt; + errt = null; + } + + var assertErr = new Assertion(fn, msg).to.Throw(errt, errs); + return flag(assertErr, 'object'); + }; + + /** + * ### .doesNotThrow(function, [constructor/regexp], [message]) + * + * Asserts that `function` will _not_ throw an error that is an instance of + * `constructor`, or alternately that it will not throw an error with message + * matching `regexp`. + * + * assert.doesNotThrow(fn, Error, 'function does not throw'); + * + * @name doesNotThrow + * @param {Function} function + * @param {ErrorConstructor} constructor + * @param {RegExp} regexp + * @param {String} message + * @see https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Error#Error_types + * @api public + */ + + assert.doesNotThrow = function (fn, type, msg) { + if ('string' === typeof type) { + msg = type; + type = null; + } + + new Assertion(fn, msg).to.not.Throw(type); + }; + + /** + * ### .operator(val1, operator, val2, [message]) + * + * Compares two values using `operator`. + * + * assert.operator(1, '<', 2, 'everything is ok'); + * assert.operator(1, '>', 2, 'this will fail'); + * + * @name operator + * @param {Mixed} val1 + * @param {String} operator + * @param {Mixed} val2 + * @param {String} message + * @api public + */ + + assert.operator = function (val, operator, val2, msg) { + if (!~['==', '===', '>', '>=', '<', '<=', '!=', '!=='].indexOf(operator)) { + throw new Error('Invalid operator "' + operator + '"'); + } + var test = new Assertion(eval(val + operator + val2), msg); + test.assert( + true === flag(test, 'object') + , 'expected ' + util.inspect(val) + ' to be ' + operator + ' ' + util.inspect(val2) + , 'expected ' + util.inspect(val) + ' to not be ' + operator + ' ' + util.inspect(val2) ); + }; + + /** + * ### .closeTo(actual, expected, delta, [message]) + * + * Asserts that the target is equal `expected`, to within a +/- `delta` range. + * + * assert.closeTo(1.5, 1, 0.5, 'numbers are close'); + * + * @name closeTo + * @param {Number} actual + * @param {Number} expected + * @param {Number} delta + * @param {String} message + * @api public + */ + + assert.closeTo = function (act, exp, delta, msg) { + new Assertion(act, msg).to.be.closeTo(exp, delta); + }; + + /** + * ### .sameMembers(set1, set2, [message]) + * + * Asserts that `set1` and `set2` have the same members. + * Order is not taken into account. + * + * assert.sameMembers([ 1, 2, 3 ], [ 2, 1, 3 ], 'same members'); + * + * @name sameMembers + * @param {Array} set1 + * @param {Array} set2 + * @param {String} message + * @api public + */ + + assert.sameMembers = function (set1, set2, msg) { + new Assertion(set1, msg).to.have.same.members(set2); + } + + /** + * ### .includeMembers(superset, subset, [message]) + * + * Asserts that `subset` is included in `superset`. + * Order is not taken into account. + * + * assert.includeMembers([ 1, 2, 3 ], [ 2, 1 ], 'include members'); + * + * @name includeMembers + * @param {Array} superset + * @param {Array} subset + * @param {String} message + * @api public + */ + + assert.includeMembers = function (superset, subset, msg) { + new Assertion(superset, msg).to.include.members(subset); + } + + /*! + * Undocumented / untested + */ + + assert.ifError = function (val, msg) { + new Assertion(val, msg).to.not.be.ok; + }; + + /*! + * Aliases. + */ + + (function alias(name, as){ + assert[as] = assert[name]; + return alias; + }) + ('Throw', 'throw') + ('Throw', 'throws'); +}; + +}); + +require.register("chai/lib/chai/interface/expect.js", function (exports, module) { +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +module.exports = function (chai, util) { + chai.expect = function (val, message) { + return new chai.Assertion(val, message); + }; +}; + + +}); + +require.register("chai/lib/chai/interface/should.js", function (exports, module) { +/*! + * chai + * Copyright(c) 2011-2014 Jake Luer + * MIT Licensed + */ + +module.exports = function (chai, util) { + var Assertion = chai.Assertion; + + function loadShould () { + // explicitly define this method as function as to have it's name to include as `ssfi` + function shouldGetter() { + if (this instanceof String || this instanceof Number) { + return new Assertion(this.constructor(this), null, shouldGetter); + } else if (this instanceof Boolean) { + return new Assertion(this == true, null, shouldGetter); + } + return new Assertion(this, null, shouldGetter); + } + function shouldSetter(value) { + // See https://github.com/chaijs/chai/issues/86: this makes + // `whatever.should = someValue` actually set `someValue`, which is + // especially useful for `global.should = require('chai').should()`. + // + // Note that we have to use [[DefineProperty]] instead of [[Put]] + // since otherwise we would trigger this very setter! + Object.defineProperty(this, 'should', { + value: value, + enumerable: true, + configurable: true, + writable: true + }); + } + // modify Object.prototype to have `should` + Object.defineProperty(Object.prototype, 'should', { + set: shouldSetter + , get: shouldGetter + , configurable: true + }); + + var should = {}; + + should.equal = function (val1, val2, msg) { + new Assertion(val1, msg).to.equal(val2); + }; + + should.Throw = function (fn, errt, errs, msg) { + new Assertion(fn, msg).to.Throw(errt, errs); + }; + + should.exist = function (val, msg) { + new Assertion(val, msg).to.exist; + } + + // negation + should.not = {} + + should.not.equal = function (val1, val2, msg) { + new Assertion(val1, msg).to.not.equal(val2); + }; + + should.not.Throw = function (fn, errt, errs, msg) { + new Assertion(fn, msg).to.not.Throw(errt, errs); + }; + + should.not.exist = function (val, msg) { + new Assertion(val, msg).to.not.exist; + } + + should['throw'] = should['Throw']; + should.not['throw'] = should.not['Throw']; + + return should; + }; + + chai.should = loadShould; + chai.Should = loadShould; +}; + +}); + +require.register("chai/lib/chai/utils/addChainableMethod.js", function (exports, module) { +/*! + * Chai - addChainingMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependencies + */ + +var transferFlags = require('chai/lib/chai/utils/transferFlags.js'); +var flag = require('chai/lib/chai/utils/flag.js'); +var config = require('chai/lib/chai/config.js'); + +/*! + * Module variables + */ + +// Check whether `__proto__` is supported +var hasProtoSupport = '__proto__' in Object; + +// Without `__proto__` support, this module will need to add properties to a function. +// However, some Function.prototype methods cannot be overwritten, +// and there seems no easy cross-platform way to detect them (@see chaijs/chai/issues/69). +var excludeNames = /^(?:length|name|arguments|caller)$/; + +// Cache `Function` properties +var call = Function.prototype.call, + apply = Function.prototype.apply; + +/** + * ### addChainableMethod (ctx, name, method, chainingBehavior) + * + * Adds a method to an object, such that the method can also be chained. + * + * utils.addChainableMethod(chai.Assertion.prototype, 'foo', function (str) { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.equal(str); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addChainableMethod('foo', fn, chainingBehavior); + * + * The result can then be used as both a method assertion, executing both `method` and + * `chainingBehavior`, or as a language chain, which only executes `chainingBehavior`. + * + * expect(fooStr).to.be.foo('bar'); + * expect(fooStr).to.be.foo.equal('foo'); + * + * @param {Object} ctx object to which the method is added + * @param {String} name of method to add + * @param {Function} method function to be used for `name`, when called + * @param {Function} chainingBehavior function to be called every time the property is accessed + * @name addChainableMethod + * @api public + */ + +module.exports = function (ctx, name, method, chainingBehavior) { + if (typeof chainingBehavior !== 'function') { + chainingBehavior = function () { }; + } + + var chainableBehavior = { + method: method + , chainingBehavior: chainingBehavior + }; + + // save the methods so we can overwrite them later, if we need to. + if (!ctx.__methods) { + ctx.__methods = {}; + } + ctx.__methods[name] = chainableBehavior; + + Object.defineProperty(ctx, name, + { get: function () { + chainableBehavior.chainingBehavior.call(this); + + var assert = function assert() { + var old_ssfi = flag(this, 'ssfi'); + if (old_ssfi && config.includeStack === false) + flag(this, 'ssfi', assert); + var result = chainableBehavior.method.apply(this, arguments); + return result === undefined ? this : result; + }; + + // Use `__proto__` if available + if (hasProtoSupport) { + // Inherit all properties from the object by replacing the `Function` prototype + var prototype = assert.__proto__ = Object.create(this); + // Restore the `call` and `apply` methods from `Function` + prototype.call = call; + prototype.apply = apply; + } + // Otherwise, redefine all properties (slow!) + else { + var asserterNames = Object.getOwnPropertyNames(ctx); + asserterNames.forEach(function (asserterName) { + if (!excludeNames.test(asserterName)) { + var pd = Object.getOwnPropertyDescriptor(ctx, asserterName); + Object.defineProperty(assert, asserterName, pd); + } + }); + } + + transferFlags(this, assert); + return assert; + } + , configurable: true + }); +}; + +}); + +require.register("chai/lib/chai/utils/addMethod.js", function (exports, module) { +/*! + * Chai - addMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +var config = require('chai/lib/chai/config.js'); + +/** + * ### .addMethod (ctx, name, method) + * + * Adds a method to the prototype of an object. + * + * utils.addMethod(chai.Assertion.prototype, 'foo', function (str) { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.equal(str); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addMethod('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(fooStr).to.be.foo('bar'); + * + * @param {Object} ctx object to which the method is added + * @param {String} name of method to add + * @param {Function} method function to be used for name + * @name addMethod + * @api public + */ +var flag = require('chai/lib/chai/utils/flag.js'); + +module.exports = function (ctx, name, method) { + ctx[name] = function () { + var old_ssfi = flag(this, 'ssfi'); + if (old_ssfi && config.includeStack === false) + flag(this, 'ssfi', ctx[name]); + var result = method.apply(this, arguments); + return result === undefined ? this : result; + }; +}; + +}); + +require.register("chai/lib/chai/utils/addProperty.js", function (exports, module) { +/*! + * Chai - addProperty utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### addProperty (ctx, name, getter) + * + * Adds a property to the prototype of an object. + * + * utils.addProperty(chai.Assertion.prototype, 'foo', function () { + * var obj = utils.flag(this, 'object'); + * new chai.Assertion(obj).to.be.instanceof(Foo); + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.addProperty('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.be.foo; + * + * @param {Object} ctx object to which the property is added + * @param {String} name of property to add + * @param {Function} getter function to be used for name + * @name addProperty + * @api public + */ + +module.exports = function (ctx, name, getter) { + Object.defineProperty(ctx, name, + { get: function () { + var result = getter.call(this); + return result === undefined ? this : result; + } + , configurable: true + }); +}; + +}); + +require.register("chai/lib/chai/utils/flag.js", function (exports, module) { +/*! + * Chai - flag utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### flag(object ,key, [value]) + * + * Get or set a flag value on an object. If a + * value is provided it will be set, else it will + * return the currently set value or `undefined` if + * the value is not set. + * + * utils.flag(this, 'foo', 'bar'); // setter + * utils.flag(this, 'foo'); // getter, returns `bar` + * + * @param {Object} object (constructed Assertion + * @param {String} key + * @param {Mixed} value (optional) + * @name flag + * @api private + */ + +module.exports = function (obj, key, value) { + var flags = obj.__flags || (obj.__flags = Object.create(null)); + if (arguments.length === 3) { + flags[key] = value; + } else { + return flags[key]; + } +}; + +}); + +require.register("chai/lib/chai/utils/getActual.js", function (exports, module) { +/*! + * Chai - getActual utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * # getActual(object, [actual]) + * + * Returns the `actual` value for an Assertion + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + */ + +module.exports = function (obj, args) { + return args.length > 4 ? args[4] : obj._obj; +}; + +}); + +require.register("chai/lib/chai/utils/getEnumerableProperties.js", function (exports, module) { +/*! + * Chai - getEnumerableProperties utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### .getEnumerableProperties(object) + * + * This allows the retrieval of enumerable property names of an object, + * inherited or not. + * + * @param {Object} object + * @returns {Array} + * @name getEnumerableProperties + * @api public + */ + +module.exports = function getEnumerableProperties(object) { + var result = []; + for (var name in object) { + result.push(name); + } + return result; +}; + +}); + +require.register("chai/lib/chai/utils/getMessage.js", function (exports, module) { +/*! + * Chai - message composition utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var flag = require('chai/lib/chai/utils/flag.js') + , getActual = require('chai/lib/chai/utils/getActual.js') + , inspect = require('chai/lib/chai/utils/inspect.js') + , objDisplay = require('chai/lib/chai/utils/objDisplay.js'); + +/** + * ### .getMessage(object, message, negateMessage) + * + * Construct the error message based on flags + * and template tags. Template tags will return + * a stringified inspection of the object referenced. + * + * Message template tags: + * - `#{this}` current asserted object + * - `#{act}` actual value + * - `#{exp}` expected value + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + * @name getMessage + * @api public + */ + +module.exports = function (obj, args) { + var negate = flag(obj, 'negate') + , val = flag(obj, 'object') + , expected = args[3] + , actual = getActual(obj, args) + , msg = negate ? args[2] : args[1] + , flagMsg = flag(obj, 'message'); + + if(typeof msg === "function") msg = msg(); + msg = msg || ''; + msg = msg + .replace(/#{this}/g, objDisplay(val)) + .replace(/#{act}/g, objDisplay(actual)) + .replace(/#{exp}/g, objDisplay(expected)); + + return flagMsg ? flagMsg + ': ' + msg : msg; +}; + +}); + +require.register("chai/lib/chai/utils/getName.js", function (exports, module) { +/*! + * Chai - getName utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * # getName(func) + * + * Gets the name of a function, in a cross-browser way. + * + * @param {Function} a function (usually a constructor) + */ + +module.exports = function (func) { + if (func.name) return func.name; + + var match = /^\s?function ([^(]*)\(/.exec(func); + return match && match[1] ? match[1] : ""; +}; + +}); + +require.register("chai/lib/chai/utils/getPathValue.js", function (exports, module) { +/*! + * Chai - getPathValue utility + * Copyright(c) 2012-2014 Jake Luer + * @see https://github.com/logicalparadox/filtr + * MIT Licensed + */ + +/** + * ### .getPathValue(path, object) + * + * This allows the retrieval of values in an + * object given a string path. + * + * var obj = { + * prop1: { + * arr: ['a', 'b', 'c'] + * , str: 'Hello' + * } + * , prop2: { + * arr: [ { nested: 'Universe' } ] + * , str: 'Hello again!' + * } + * } + * + * The following would be the results. + * + * getPathValue('prop1.str', obj); // Hello + * getPathValue('prop1.att[2]', obj); // b + * getPathValue('prop2.arr[0].nested', obj); // Universe + * + * @param {String} path + * @param {Object} object + * @returns {Object} value or `undefined` + * @name getPathValue + * @api public + */ + +var getPathValue = module.exports = function (path, obj) { + var parsed = parsePath(path); + return _getPathValue(parsed, obj); +}; + +/*! + * ## parsePath(path) + * + * Helper function used to parse string object + * paths. Use in conjunction with `_getPathValue`. + * + * var parsed = parsePath('myobject.property.subprop'); + * + * ### Paths: + * + * * Can be as near infinitely deep and nested + * * Arrays are also valid using the formal `myobject.document[3].property`. + * + * @param {String} path + * @returns {Object} parsed + * @api private + */ + +function parsePath (path) { + var str = path.replace(/\[/g, '.[') + , parts = str.match(/(\\\.|[^.]+?)+/g); + return parts.map(function (value) { + var re = /\[(\d+)\]$/ + , mArr = re.exec(value) + if (mArr) return { i: parseFloat(mArr[1]) }; + else return { p: value }; + }); +}; + +/*! + * ## _getPathValue(parsed, obj) + * + * Helper companion function for `.parsePath` that returns + * the value located at the parsed address. + * + * var value = getPathValue(parsed, obj); + * + * @param {Object} parsed definition from `parsePath`. + * @param {Object} object to search against + * @returns {Object|Undefined} value + * @api private + */ + +function _getPathValue (parsed, obj) { + var tmp = obj + , res; + for (var i = 0, l = parsed.length; i < l; i++) { + var part = parsed[i]; + if (tmp) { + if ('undefined' !== typeof part.p) + tmp = tmp[part.p]; + else if ('undefined' !== typeof part.i) + tmp = tmp[part.i]; + if (i == (l - 1)) res = tmp; + } else { + res = undefined; + } + } + return res; +}; + +}); + +require.register("chai/lib/chai/utils/getProperties.js", function (exports, module) { +/*! + * Chai - getProperties utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### .getProperties(object) + * + * This allows the retrieval of property names of an object, enumerable or not, + * inherited or not. + * + * @param {Object} object + * @returns {Array} + * @name getProperties + * @api public + */ + +module.exports = function getProperties(object) { + var result = Object.getOwnPropertyNames(subject); + + function addProperty(property) { + if (result.indexOf(property) === -1) { + result.push(property); + } + } + + var proto = Object.getPrototypeOf(subject); + while (proto !== null) { + Object.getOwnPropertyNames(proto).forEach(addProperty); + proto = Object.getPrototypeOf(proto); + } + + return result; +}; + +}); + +require.register("chai/lib/chai/utils/index.js", function (exports, module) { +/*! + * chai + * Copyright(c) 2011 Jake Luer + * MIT Licensed + */ + +/*! + * Main exports + */ + +var exports = module.exports = {}; + +/*! + * test utility + */ + +exports.test = require('chai/lib/chai/utils/test.js'); + +/*! + * type utility + */ + +exports.type = require('chai/lib/chai/utils/type.js'); + +/*! + * message utility + */ + +exports.getMessage = require('chai/lib/chai/utils/getMessage.js'); + +/*! + * actual utility + */ + +exports.getActual = require('chai/lib/chai/utils/getActual.js'); + +/*! + * Inspect util + */ + +exports.inspect = require('chai/lib/chai/utils/inspect.js'); + +/*! + * Object Display util + */ + +exports.objDisplay = require('chai/lib/chai/utils/objDisplay.js'); + +/*! + * Flag utility + */ + +exports.flag = require('chai/lib/chai/utils/flag.js'); + +/*! + * Flag transferring utility + */ + +exports.transferFlags = require('chai/lib/chai/utils/transferFlags.js'); + +/*! + * Deep equal utility + */ + +exports.eql = require('chaijs~deep-eql@0.1.3'); + +/*! + * Deep path value + */ + +exports.getPathValue = require('chai/lib/chai/utils/getPathValue.js'); + +/*! + * Function name + */ + +exports.getName = require('chai/lib/chai/utils/getName.js'); + +/*! + * add Property + */ + +exports.addProperty = require('chai/lib/chai/utils/addProperty.js'); + +/*! + * add Method + */ + +exports.addMethod = require('chai/lib/chai/utils/addMethod.js'); + +/*! + * overwrite Property + */ + +exports.overwriteProperty = require('chai/lib/chai/utils/overwriteProperty.js'); + +/*! + * overwrite Method + */ + +exports.overwriteMethod = require('chai/lib/chai/utils/overwriteMethod.js'); + +/*! + * Add a chainable method + */ + +exports.addChainableMethod = require('chai/lib/chai/utils/addChainableMethod.js'); + +/*! + * Overwrite chainable method + */ + +exports.overwriteChainableMethod = require('chai/lib/chai/utils/overwriteChainableMethod.js'); + + +}); + +require.register("chai/lib/chai/utils/inspect.js", function (exports, module) { +// This is (almost) directly from Node.js utils +// https://github.com/joyent/node/blob/f8c335d0caf47f16d31413f89aa28eda3878e3aa/lib/util.js + +var getName = require('chai/lib/chai/utils/getName.js'); +var getProperties = require('chai/lib/chai/utils/getProperties.js'); +var getEnumerableProperties = require('chai/lib/chai/utils/getEnumerableProperties.js'); + +module.exports = inspect; + +/** + * Echos the value of a value. Trys to print the value out + * in the best way possible given the different types. + * + * @param {Object} obj The object to print out. + * @param {Boolean} showHidden Flag that shows hidden (not enumerable) + * properties of objects. + * @param {Number} depth Depth in which to descend in object. Default is 2. + * @param {Boolean} colors Flag to turn on ANSI escape codes to color the + * output. Default is false (no coloring). + */ +function inspect(obj, showHidden, depth, colors) { + var ctx = { + showHidden: showHidden, + seen: [], + stylize: function (str) { return str; } + }; + return formatValue(ctx, obj, (typeof depth === 'undefined' ? 2 : depth)); +} + +// Returns true if object is a DOM element. +var isDOMElement = function (object) { + if (typeof HTMLElement === 'object') { + return object instanceof HTMLElement; + } else { + return object && + typeof object === 'object' && + object.nodeType === 1 && + typeof object.nodeName === 'string'; + } +}; + +function formatValue(ctx, value, recurseTimes) { + // Provide a hook for user-specified inspect functions. + // Check that value is an object with an inspect function on it + if (value && typeof value.inspect === 'function' && + // Filter out the util module, it's inspect function is special + value.inspect !== exports.inspect && + // Also filter out any prototype objects using the circular check. + !(value.constructor && value.constructor.prototype === value)) { + var ret = value.inspect(recurseTimes); + if (typeof ret !== 'string') { + ret = formatValue(ctx, ret, recurseTimes); + } + return ret; + } + + // Primitive types cannot have properties + var primitive = formatPrimitive(ctx, value); + if (primitive) { + return primitive; + } + + // If this is a DOM element, try to get the outer HTML. + if (isDOMElement(value)) { + if ('outerHTML' in value) { + return value.outerHTML; + // This value does not have an outerHTML attribute, + // it could still be an XML element + } else { + // Attempt to serialize it + try { + if (document.xmlVersion) { + var xmlSerializer = new XMLSerializer(); + return xmlSerializer.serializeToString(value); + } else { + // Firefox 11- do not support outerHTML + // It does, however, support innerHTML + // Use the following to render the element + var ns = "http://www.w3.org/1999/xhtml"; + var container = document.createElementNS(ns, '_'); + + container.appendChild(value.cloneNode(false)); + html = container.innerHTML + .replace('><', '>' + value.innerHTML + '<'); + container.innerHTML = ''; + return html; + } + } catch (err) { + // This could be a non-native DOM implementation, + // continue with the normal flow: + // printing the element as if it is an object. + } + } + } + + // Look up the keys of the object. + var visibleKeys = getEnumerableProperties(value); + var keys = ctx.showHidden ? getProperties(value) : visibleKeys; + + // Some type of object without properties can be shortcutted. + // In IE, errors have a single `stack` property, or if they are vanilla `Error`, + // a `stack` plus `description` property; ignore those for consistency. + if (keys.length === 0 || (isError(value) && ( + (keys.length === 1 && keys[0] === 'stack') || + (keys.length === 2 && keys[0] === 'description' && keys[1] === 'stack') + ))) { + if (typeof value === 'function') { + var name = getName(value); + var nameSuffix = name ? ': ' + name : ''; + return ctx.stylize('[Function' + nameSuffix + ']', 'special'); + } + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } + if (isDate(value)) { + return ctx.stylize(Date.prototype.toUTCString.call(value), 'date'); + } + if (isError(value)) { + return formatError(value); + } + } + + var base = '', array = false, braces = ['{', '}']; + + // Make Array say that they are Array + if (isArray(value)) { + array = true; + braces = ['[', ']']; + } + + // Make functions say that they are functions + if (typeof value === 'function') { + var name = getName(value); + var nameSuffix = name ? ': ' + name : ''; + base = ' [Function' + nameSuffix + ']'; + } + + // Make RegExps say that they are RegExps + if (isRegExp(value)) { + base = ' ' + RegExp.prototype.toString.call(value); + } + + // Make dates with properties first say the date + if (isDate(value)) { + base = ' ' + Date.prototype.toUTCString.call(value); + } + + // Make error with message first say the error + if (isError(value)) { + return formatError(value); + } + + if (keys.length === 0 && (!array || value.length == 0)) { + return braces[0] + base + braces[1]; + } + + if (recurseTimes < 0) { + if (isRegExp(value)) { + return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp'); + } else { + return ctx.stylize('[Object]', 'special'); + } + } + + ctx.seen.push(value); + + var output; + if (array) { + output = formatArray(ctx, value, recurseTimes, visibleKeys, keys); + } else { + output = keys.map(function(key) { + return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array); + }); + } + + ctx.seen.pop(); + + return reduceToSingleString(output, base, braces); +} + + +function formatPrimitive(ctx, value) { + switch (typeof value) { + case 'undefined': + return ctx.stylize('undefined', 'undefined'); + + case 'string': + var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '') + .replace(/'/g, "\\'") + .replace(/\\"/g, '"') + '\''; + return ctx.stylize(simple, 'string'); + + case 'number': + if (value === 0 && (1/value) === -Infinity) { + return ctx.stylize('-0', 'number'); + } + return ctx.stylize('' + value, 'number'); + + case 'boolean': + return ctx.stylize('' + value, 'boolean'); + } + // For some reason typeof null is "object", so special case here. + if (value === null) { + return ctx.stylize('null', 'null'); + } +} + + +function formatError(value) { + return '[' + Error.prototype.toString.call(value) + ']'; +} + + +function formatArray(ctx, value, recurseTimes, visibleKeys, keys) { + var output = []; + for (var i = 0, l = value.length; i < l; ++i) { + if (Object.prototype.hasOwnProperty.call(value, String(i))) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + String(i), true)); + } else { + output.push(''); + } + } + keys.forEach(function(key) { + if (!key.match(/^\d+$/)) { + output.push(formatProperty(ctx, value, recurseTimes, visibleKeys, + key, true)); + } + }); + return output; +} + + +function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) { + var name, str; + if (value.__lookupGetter__) { + if (value.__lookupGetter__(key)) { + if (value.__lookupSetter__(key)) { + str = ctx.stylize('[Getter/Setter]', 'special'); + } else { + str = ctx.stylize('[Getter]', 'special'); + } + } else { + if (value.__lookupSetter__(key)) { + str = ctx.stylize('[Setter]', 'special'); + } + } + } + if (visibleKeys.indexOf(key) < 0) { + name = '[' + key + ']'; + } + if (!str) { + if (ctx.seen.indexOf(value[key]) < 0) { + if (recurseTimes === null) { + str = formatValue(ctx, value[key], null); + } else { + str = formatValue(ctx, value[key], recurseTimes - 1); + } + if (str.indexOf('\n') > -1) { + if (array) { + str = str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n').substr(2); + } else { + str = '\n' + str.split('\n').map(function(line) { + return ' ' + line; + }).join('\n'); + } + } + } else { + str = ctx.stylize('[Circular]', 'special'); + } + } + if (typeof name === 'undefined') { + if (array && key.match(/^\d+$/)) { + return str; + } + name = JSON.stringify('' + key); + if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) { + name = name.substr(1, name.length - 2); + name = ctx.stylize(name, 'name'); + } else { + name = name.replace(/'/g, "\\'") + .replace(/\\"/g, '"') + .replace(/(^"|"$)/g, "'"); + name = ctx.stylize(name, 'string'); + } + } + + return name + ': ' + str; +} + + +function reduceToSingleString(output, base, braces) { + var numLinesEst = 0; + var length = output.reduce(function(prev, cur) { + numLinesEst++; + if (cur.indexOf('\n') >= 0) numLinesEst++; + return prev + cur.length + 1; + }, 0); + + if (length > 60) { + return braces[0] + + (base === '' ? '' : base + '\n ') + + ' ' + + output.join(',\n ') + + ' ' + + braces[1]; + } + + return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1]; +} + +function isArray(ar) { + return Array.isArray(ar) || + (typeof ar === 'object' && objectToString(ar) === '[object Array]'); +} + +function isRegExp(re) { + return typeof re === 'object' && objectToString(re) === '[object RegExp]'; +} + +function isDate(d) { + return typeof d === 'object' && objectToString(d) === '[object Date]'; +} + +function isError(e) { + return typeof e === 'object' && objectToString(e) === '[object Error]'; +} + +function objectToString(o) { + return Object.prototype.toString.call(o); +} + +}); + +require.register("chai/lib/chai/utils/objDisplay.js", function (exports, module) { +/*! + * Chai - flag utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var inspect = require('chai/lib/chai/utils/inspect.js'); +var config = require('chai/lib/chai/config.js'); + +/** + * ### .objDisplay (object) + * + * Determines if an object or an array matches + * criteria to be inspected in-line for error + * messages or should be truncated. + * + * @param {Mixed} javascript object to inspect + * @name objDisplay + * @api public + */ + +module.exports = function (obj) { + var str = inspect(obj) + , type = Object.prototype.toString.call(obj); + + if (config.truncateThreshold && str.length >= config.truncateThreshold) { + if (type === '[object Function]') { + return !obj.name || obj.name === '' + ? '[Function]' + : '[Function: ' + obj.name + ']'; + } else if (type === '[object Array]') { + return '[ Array(' + obj.length + ') ]'; + } else if (type === '[object Object]') { + var keys = Object.keys(obj) + , kstr = keys.length > 2 + ? keys.splice(0, 2).join(', ') + ', ...' + : keys.join(', '); + return '{ Object (' + kstr + ') }'; + } else { + return str; + } + } else { + return str; + } +}; + +}); + +require.register("chai/lib/chai/utils/overwriteMethod.js", function (exports, module) { +/*! + * Chai - overwriteMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### overwriteMethod (ctx, name, fn) + * + * Overwites an already existing method and provides + * access to previous function. Must return function + * to be used for name. + * + * utils.overwriteMethod(chai.Assertion.prototype, 'equal', function (_super) { + * return function (str) { + * var obj = utils.flag(this, 'object'); + * if (obj instanceof Foo) { + * new chai.Assertion(obj.value).to.equal(str); + * } else { + * _super.apply(this, arguments); + * } + * } + * }); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteMethod('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.equal('bar'); + * + * @param {Object} ctx object whose method is to be overwritten + * @param {String} name of method to overwrite + * @param {Function} method function that returns a function to be used for name + * @name overwriteMethod + * @api public + */ + +module.exports = function (ctx, name, method) { + var _method = ctx[name] + , _super = function () { return this; }; + + if (_method && 'function' === typeof _method) + _super = _method; + + ctx[name] = function () { + var result = method(_super).apply(this, arguments); + return result === undefined ? this : result; + } +}; + +}); + +require.register("chai/lib/chai/utils/overwriteProperty.js", function (exports, module) { +/*! + * Chai - overwriteProperty utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### overwriteProperty (ctx, name, fn) + * + * Overwites an already existing property getter and provides + * access to previous value. Must return function to use as getter. + * + * utils.overwriteProperty(chai.Assertion.prototype, 'ok', function (_super) { + * return function () { + * var obj = utils.flag(this, 'object'); + * if (obj instanceof Foo) { + * new chai.Assertion(obj.name).to.equal('bar'); + * } else { + * _super.call(this); + * } + * } + * }); + * + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteProperty('foo', fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.be.ok; + * + * @param {Object} ctx object whose property is to be overwritten + * @param {String} name of property to overwrite + * @param {Function} getter function that returns a getter function to be used for name + * @name overwriteProperty + * @api public + */ + +module.exports = function (ctx, name, getter) { + var _get = Object.getOwnPropertyDescriptor(ctx, name) + , _super = function () {}; + + if (_get && 'function' === typeof _get.get) + _super = _get.get + + Object.defineProperty(ctx, name, + { get: function () { + var result = getter(_super).call(this); + return result === undefined ? this : result; + } + , configurable: true + }); +}; + +}); + +require.register("chai/lib/chai/utils/overwriteChainableMethod.js", function (exports, module) { +/*! + * Chai - overwriteChainableMethod utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### overwriteChainableMethod (ctx, name, fn) + * + * Overwites an already existing chainable method + * and provides access to the previous function or + * property. Must return functions to be used for + * name. + * + * utils.overwriteChainableMethod(chai.Assertion.prototype, 'length', + * function (_super) { + * } + * , function (_super) { + * } + * ); + * + * Can also be accessed directly from `chai.Assertion`. + * + * chai.Assertion.overwriteChainableMethod('foo', fn, fn); + * + * Then can be used as any other assertion. + * + * expect(myFoo).to.have.length(3); + * expect(myFoo).to.have.length.above(3); + * + * @param {Object} ctx object whose method / property is to be overwritten + * @param {String} name of method / property to overwrite + * @param {Function} method function that returns a function to be used for name + * @param {Function} chainingBehavior function that returns a function to be used for property + * @name overwriteChainableMethod + * @api public + */ + +module.exports = function (ctx, name, method, chainingBehavior) { + var chainableBehavior = ctx.__methods[name]; + + var _chainingBehavior = chainableBehavior.chainingBehavior; + chainableBehavior.chainingBehavior = function () { + var result = chainingBehavior(_chainingBehavior).call(this); + return result === undefined ? this : result; + }; + + var _method = chainableBehavior.method; + chainableBehavior.method = function () { + var result = method(_method).apply(this, arguments); + return result === undefined ? this : result; + }; +}; + +}); + +require.register("chai/lib/chai/utils/test.js", function (exports, module) { +/*! + * Chai - test utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Module dependancies + */ + +var flag = require('chai/lib/chai/utils/flag.js'); + +/** + * # test(object, expression) + * + * Test and object for expression. + * + * @param {Object} object (constructed Assertion) + * @param {Arguments} chai.Assertion.prototype.assert arguments + */ + +module.exports = function (obj, args) { + var negate = flag(obj, 'negate') + , expr = args[0]; + return negate ? !expr : expr; +}; + +}); + +require.register("chai/lib/chai/utils/transferFlags.js", function (exports, module) { +/*! + * Chai - transferFlags utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/** + * ### transferFlags(assertion, object, includeAll = true) + * + * Transfer all the flags for `assertion` to `object`. If + * `includeAll` is set to `false`, then the base Chai + * assertion flags (namely `object`, `ssfi`, and `message`) + * will not be transferred. + * + * + * var newAssertion = new Assertion(); + * utils.transferFlags(assertion, newAssertion); + * + * var anotherAsseriton = new Assertion(myObj); + * utils.transferFlags(assertion, anotherAssertion, false); + * + * @param {Assertion} assertion the assertion to transfer the flags from + * @param {Object} object the object to transfer the flags too; usually a new assertion + * @param {Boolean} includeAll + * @name getAllFlags + * @api private + */ + +module.exports = function (assertion, object, includeAll) { + var flags = assertion.__flags || (assertion.__flags = Object.create(null)); + + if (!object.__flags) { + object.__flags = Object.create(null); + } + + includeAll = arguments.length === 3 ? includeAll : true; + + for (var flag in flags) { + if (includeAll || + (flag !== 'object' && flag !== 'ssfi' && flag != 'message')) { + object.__flags[flag] = flags[flag]; + } + } +}; + +}); + +require.register("chai/lib/chai/utils/type.js", function (exports, module) { +/*! + * Chai - type utility + * Copyright(c) 2012-2014 Jake Luer + * MIT Licensed + */ + +/*! + * Detectable javascript natives + */ + +var natives = { + '[object Arguments]': 'arguments' + , '[object Array]': 'array' + , '[object Date]': 'date' + , '[object Function]': 'function' + , '[object Number]': 'number' + , '[object RegExp]': 'regexp' + , '[object String]': 'string' +}; + +/** + * ### type(object) + * + * Better implementation of `typeof` detection that can + * be used cross-browser. Handles the inconsistencies of + * Array, `null`, and `undefined` detection. + * + * utils.type({}) // 'object' + * utils.type(null) // `null' + * utils.type(undefined) // `undefined` + * utils.type([]) // `array` + * + * @param {Mixed} object to detect type of + * @name type + * @api private + */ + +module.exports = function (obj) { + var str = Object.prototype.toString.call(obj); + if (natives[str]) return natives[str]; + if (obj === null) return 'null'; + if (obj === undefined) return 'undefined'; + if (obj === Object(obj)) return 'object'; + return typeof obj; +}; + +}); + +if (typeof exports == "object") { + module.exports = require("chai"); +} else if (typeof define == "function" && define.amd) { + define("chai", [], function(){ return require("chai"); }); +} else { + (this || window)["chai"] = require("chai"); +} +})() diff --git a/tests/automation/res/mocha.css b/tests/automation/res/mocha.css new file mode 100644 index 0000000000..42b9798fa4 --- /dev/null +++ b/tests/automation/res/mocha.css @@ -0,0 +1,270 @@ +@charset "utf-8"; + +body { + margin:0; +} + +#mocha { + font: 20px/1.5 "Helvetica Neue", Helvetica, Arial, sans-serif; + margin: 60px 50px; +} + +#mocha ul, +#mocha li { + margin: 0; + padding: 0; +} + +#mocha ul { + list-style: none; +} + +#mocha h1, +#mocha h2 { + margin: 0; +} + +#mocha h1 { + margin-top: 15px; + font-size: 1em; + font-weight: 200; +} + +#mocha h1 a { + text-decoration: none; + color: inherit; +} + +#mocha h1 a:hover { + text-decoration: underline; +} + +#mocha .suite .suite h1 { + margin-top: 0; + font-size: .8em; +} + +#mocha .hidden { + display: none; +} + +#mocha h2 { + font-size: 12px; + font-weight: normal; + cursor: pointer; +} + +#mocha .suite { + margin-left: 15px; +} + +#mocha .test { + margin-left: 15px; + overflow: hidden; +} + +#mocha .test.pending:hover h2::after { + content: '(pending)'; + font-family: arial, sans-serif; +} + +#mocha .test.pass.medium .duration { + background: #c09853; +} + +#mocha .test.pass.slow .duration { + background: #b94a48; +} + +#mocha .test.pass::before { + content: '✓'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; + color: #00d6b2; +} + +#mocha .test.pass .duration { + font-size: 9px; + margin-left: 5px; + padding: 2px 5px; + color: #fff; + -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -moz-box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + box-shadow: inset 0 1px 1px rgba(0,0,0,.2); + -webkit-border-radius: 5px; + -moz-border-radius: 5px; + -ms-border-radius: 5px; + -o-border-radius: 5px; + border-radius: 5px; +} + +#mocha .test.pass.fast .duration { + display: none; +} + +#mocha .test.pending { + color: #0b97c4; +} + +#mocha .test.pending::before { + content: '◦'; + color: #0b97c4; +} + +#mocha .test.fail { + color: #c00; +} + +#mocha .test.fail pre { + color: black; +} + +#mocha .test.fail::before { + content: '✖'; + font-size: 12px; + display: block; + float: left; + margin-right: 5px; + color: #c00; +} + +#mocha .test pre.error { + color: #c00; + max-height: 300px; + overflow: auto; +} + +/** + * (1): approximate for browsers not supporting calc + * (2): 42 = 2*15 + 2*10 + 2*1 (padding + margin + border) + * ^^ seriously + */ +#mocha .test pre { + display: block; + float: left; + clear: left; + font: 12px/1.5 monaco, monospace; + margin: 5px; + padding: 15px; + border: 1px solid #eee; + max-width: 85%; /*(1)*/ + max-width: calc(100% - 42px); /*(2)*/ + word-wrap: break-word; + border-bottom-color: #ddd; + -webkit-border-radius: 3px; + -webkit-box-shadow: 0 1px 3px #eee; + -moz-border-radius: 3px; + -moz-box-shadow: 0 1px 3px #eee; + border-radius: 3px; +} + +#mocha .test h2 { + position: relative; +} + +#mocha .test a.replay { + position: absolute; + top: 3px; + right: 0; + text-decoration: none; + vertical-align: middle; + display: block; + width: 15px; + height: 15px; + line-height: 15px; + text-align: center; + background: #eee; + font-size: 15px; + -moz-border-radius: 15px; + border-radius: 15px; + -webkit-transition: opacity 200ms; + -moz-transition: opacity 200ms; + transition: opacity 200ms; + opacity: 0.3; + color: #888; +} + +#mocha .test:hover a.replay { + opacity: 1; +} + +#mocha-report.pass .test.fail { + display: none; +} + +#mocha-report.fail .test.pass { + display: none; +} + +#mocha-report.pending .test.pass, +#mocha-report.pending .test.fail { + display: none; +} +#mocha-report.pending .test.pass.pending { + display: block; +} + +#mocha-error { + color: #c00; + font-size: 1.5em; + font-weight: 100; + letter-spacing: 1px; +} + +#mocha-stats { + position: fixed; + top: 15px; + right: 10px; + font-size: 12px; + margin: 0; + color: #888; + z-index: 1; +} + +#mocha-stats .progress { + float: right; + padding-top: 0; +} + +#mocha-stats em { + color: black; +} + +#mocha-stats a { + text-decoration: none; + color: inherit; +} + +#mocha-stats a:hover { + border-bottom: 1px solid #eee; +} + +#mocha-stats li { + display: inline-block; + margin: 0 5px; + list-style: none; + padding-top: 11px; +} + +#mocha-stats canvas { + width: 40px; + height: 40px; +} + +#mocha code .comment { color: #ddd; } +#mocha code .init { color: #2f6fad; } +#mocha code .string { color: #5890ad; } +#mocha code .keyword { color: #8a6343; } +#mocha code .number { color: #2f6fad; } + +@media screen and (max-device-width: 480px) { + #mocha { + margin: 60px 0px; + } + + #mocha #stats { + position: absolute; + } +} diff --git a/tests/automation/res/mocha.js b/tests/automation/res/mocha.js new file mode 100644 index 0000000000..564a4f3184 --- /dev/null +++ b/tests/automation/res/mocha.js @@ -0,0 +1,6069 @@ +;(function(){ + +// CommonJS require() + +function require(p){ + var path = require.resolve(p) + , mod = require.modules[path]; + if (!mod) throw new Error('failed to require "' + p + '"'); + if (!mod.exports) { + mod.exports = {}; + mod.call(mod.exports, mod, mod.exports, require.relative(path)); + } + return mod.exports; + } + +require.modules = {}; + +require.resolve = function (path){ + var orig = path + , reg = path + '.js' + , index = path + '/index.js'; + return require.modules[reg] && reg + || require.modules[index] && index + || orig; + }; + +require.register = function (path, fn){ + require.modules[path] = fn; + }; + +require.relative = function (parent) { + return function(p){ + if ('.' != p.charAt(0)) return require(p); + + var path = parent.split('/') + , segs = p.split('/'); + path.pop(); + + for (var i = 0; i < segs.length; i++) { + var seg = segs[i]; + if ('..' == seg) path.pop(); + else if ('.' != seg) path.push(seg); + } + + return require(path.join('/')); + }; + }; + + +require.register("browser/debug.js", function(module, exports, require){ +module.exports = function(type){ + return function(){ + } +}; + +}); // module: browser/debug.js + +require.register("browser/diff.js", function(module, exports, require){ +/* See LICENSE file for terms of use */ + +/* + * Text diff implementation. + * + * This library supports the following APIS: + * JsDiff.diffChars: Character by character diff + * JsDiff.diffWords: Word (as defined by \b regex) diff which ignores whitespace + * JsDiff.diffLines: Line based diff + * + * JsDiff.diffCss: Diff targeted at CSS content + * + * These methods are based on the implementation proposed in + * "An O(ND) Difference Algorithm and its Variations" (Myers, 1986). + * http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.4.6927 + */ +var JsDiff = (function() { + /*jshint maxparams: 5*/ + function clonePath(path) { + return { newPos: path.newPos, components: path.components.slice(0) }; + } + function removeEmpty(array) { + var ret = []; + for (var i = 0; i < array.length; i++) { + if (array[i]) { + ret.push(array[i]); + } + } + return ret; + } + function escapeHTML(s) { + var n = s; + n = n.replace(/&/g, '&'); + n = n.replace(//g, '>'); + n = n.replace(/"/g, '"'); + + return n; + } + + var Diff = function(ignoreWhitespace) { + this.ignoreWhitespace = ignoreWhitespace; + }; + Diff.prototype = { + diff: function(oldString, newString) { + // Handle the identity case (this is due to unrolling editLength == 0 + if (newString === oldString) { + return [{ value: newString }]; + } + if (!newString) { + return [{ value: oldString, removed: true }]; + } + if (!oldString) { + return [{ value: newString, added: true }]; + } + + newString = this.tokenize(newString); + oldString = this.tokenize(oldString); + + var newLen = newString.length, oldLen = oldString.length; + var maxEditLength = newLen + oldLen; + var bestPath = [{ newPos: -1, components: [] }]; + + // Seed editLength = 0 + var oldPos = this.extractCommon(bestPath[0], newString, oldString, 0); + if (bestPath[0].newPos+1 >= newLen && oldPos+1 >= oldLen) { + return bestPath[0].components; + } + + for (var editLength = 1; editLength <= maxEditLength; editLength++) { + for (var diagonalPath = -1*editLength; diagonalPath <= editLength; diagonalPath+=2) { + var basePath; + var addPath = bestPath[diagonalPath-1], + removePath = bestPath[diagonalPath+1]; + oldPos = (removePath ? removePath.newPos : 0) - diagonalPath; + if (addPath) { + // No one else is going to attempt to use this value, clear it + bestPath[diagonalPath-1] = undefined; + } + + var canAdd = addPath && addPath.newPos+1 < newLen; + var canRemove = removePath && 0 <= oldPos && oldPos < oldLen; + if (!canAdd && !canRemove) { + bestPath[diagonalPath] = undefined; + continue; + } + + // Select the diagonal that we want to branch from. We select the prior + // path whose position in the new string is the farthest from the origin + // and does not pass the bounds of the diff graph + if (!canAdd || (canRemove && addPath.newPos < removePath.newPos)) { + basePath = clonePath(removePath); + this.pushComponent(basePath.components, oldString[oldPos], undefined, true); + } else { + basePath = clonePath(addPath); + basePath.newPos++; + this.pushComponent(basePath.components, newString[basePath.newPos], true, undefined); + } + + var oldPos = this.extractCommon(basePath, newString, oldString, diagonalPath); + + if (basePath.newPos+1 >= newLen && oldPos+1 >= oldLen) { + return basePath.components; + } else { + bestPath[diagonalPath] = basePath; + } + } + } + }, + + pushComponent: function(components, value, added, removed) { + var last = components[components.length-1]; + if (last && last.added === added && last.removed === removed) { + // We need to clone here as the component clone operation is just + // as shallow array clone + components[components.length-1] = + {value: this.join(last.value, value), added: added, removed: removed }; + } else { + components.push({value: value, added: added, removed: removed }); + } + }, + extractCommon: function(basePath, newString, oldString, diagonalPath) { + var newLen = newString.length, + oldLen = oldString.length, + newPos = basePath.newPos, + oldPos = newPos - diagonalPath; + while (newPos+1 < newLen && oldPos+1 < oldLen && this.equals(newString[newPos+1], oldString[oldPos+1])) { + newPos++; + oldPos++; + + this.pushComponent(basePath.components, newString[newPos], undefined, undefined); + } + basePath.newPos = newPos; + return oldPos; + }, + + equals: function(left, right) { + var reWhitespace = /\S/; + if (this.ignoreWhitespace && !reWhitespace.test(left) && !reWhitespace.test(right)) { + return true; + } else { + return left === right; + } + }, + join: function(left, right) { + return left + right; + }, + tokenize: function(value) { + return value; + } + }; + + var CharDiff = new Diff(); + + var WordDiff = new Diff(true); + var WordWithSpaceDiff = new Diff(); + WordDiff.tokenize = WordWithSpaceDiff.tokenize = function(value) { + return removeEmpty(value.split(/(\s+|\b)/)); + }; + + var CssDiff = new Diff(true); + CssDiff.tokenize = function(value) { + return removeEmpty(value.split(/([{}:;,]|\s+)/)); + }; + + var LineDiff = new Diff(); + LineDiff.tokenize = function(value) { + return value.split(/^/m); + }; + + return { + Diff: Diff, + + diffChars: function(oldStr, newStr) { return CharDiff.diff(oldStr, newStr); }, + diffWords: function(oldStr, newStr) { return WordDiff.diff(oldStr, newStr); }, + diffWordsWithSpace: function(oldStr, newStr) { return WordWithSpaceDiff.diff(oldStr, newStr); }, + diffLines: function(oldStr, newStr) { return LineDiff.diff(oldStr, newStr); }, + + diffCss: function(oldStr, newStr) { return CssDiff.diff(oldStr, newStr); }, + + createPatch: function(fileName, oldStr, newStr, oldHeader, newHeader) { + var ret = []; + + ret.push('Index: ' + fileName); + ret.push('==================================================================='); + ret.push('--- ' + fileName + (typeof oldHeader === 'undefined' ? '' : '\t' + oldHeader)); + ret.push('+++ ' + fileName + (typeof newHeader === 'undefined' ? '' : '\t' + newHeader)); + + var diff = LineDiff.diff(oldStr, newStr); + if (!diff[diff.length-1].value) { + diff.pop(); // Remove trailing newline add + } + diff.push({value: '', lines: []}); // Append an empty value to make cleanup easier + + function contextLines(lines) { + return lines.map(function(entry) { return ' ' + entry; }); + } + function eofNL(curRange, i, current) { + var last = diff[diff.length-2], + isLast = i === diff.length-2, + isLastOfType = i === diff.length-3 && (current.added !== last.added || current.removed !== last.removed); + + // Figure out if this is the last line for the given file and missing NL + if (!/\n$/.test(current.value) && (isLast || isLastOfType)) { + curRange.push('\\ No newline at end of file'); + } + } + + var oldRangeStart = 0, newRangeStart = 0, curRange = [], + oldLine = 1, newLine = 1; + for (var i = 0; i < diff.length; i++) { + var current = diff[i], + lines = current.lines || current.value.replace(/\n$/, '').split('\n'); + current.lines = lines; + + if (current.added || current.removed) { + if (!oldRangeStart) { + var prev = diff[i-1]; + oldRangeStart = oldLine; + newRangeStart = newLine; + + if (prev) { + curRange = contextLines(prev.lines.slice(-4)); + oldRangeStart -= curRange.length; + newRangeStart -= curRange.length; + } + } + curRange.push.apply(curRange, lines.map(function(entry) { return (current.added?'+':'-') + entry; })); + eofNL(curRange, i, current); + + if (current.added) { + newLine += lines.length; + } else { + oldLine += lines.length; + } + } else { + if (oldRangeStart) { + // Close out any changes that have been output (or join overlapping) + if (lines.length <= 8 && i < diff.length-2) { + // Overlapping + curRange.push.apply(curRange, contextLines(lines)); + } else { + // end the range and output + var contextSize = Math.min(lines.length, 4); + ret.push( + '@@ -' + oldRangeStart + ',' + (oldLine-oldRangeStart+contextSize) + + ' +' + newRangeStart + ',' + (newLine-newRangeStart+contextSize) + + ' @@'); + ret.push.apply(ret, curRange); + ret.push.apply(ret, contextLines(lines.slice(0, contextSize))); + if (lines.length <= 4) { + eofNL(ret, i, current); + } + + oldRangeStart = 0; newRangeStart = 0; curRange = []; + } + } + oldLine += lines.length; + newLine += lines.length; + } + } + + return ret.join('\n') + '\n'; + }, + + applyPatch: function(oldStr, uniDiff) { + var diffstr = uniDiff.split('\n'); + var diff = []; + var remEOFNL = false, + addEOFNL = false; + + for (var i = (diffstr[0][0]==='I'?4:0); i < diffstr.length; i++) { + if(diffstr[i][0] === '@') { + var meh = diffstr[i].split(/@@ -(\d+),(\d+) \+(\d+),(\d+) @@/); + diff.unshift({ + start:meh[3], + oldlength:meh[2], + oldlines:[], + newlength:meh[4], + newlines:[] + }); + } else if(diffstr[i][0] === '+') { + diff[0].newlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === '-') { + diff[0].oldlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === ' ') { + diff[0].newlines.push(diffstr[i].substr(1)); + diff[0].oldlines.push(diffstr[i].substr(1)); + } else if(diffstr[i][0] === '\\') { + if (diffstr[i-1][0] === '+') { + remEOFNL = true; + } else if(diffstr[i-1][0] === '-') { + addEOFNL = true; + } + } + } + + var str = oldStr.split('\n'); + for (var i = diff.length - 1; i >= 0; i--) { + var d = diff[i]; + for (var j = 0; j < d.oldlength; j++) { + if(str[d.start-1+j] !== d.oldlines[j]) { + return false; + } + } + Array.prototype.splice.apply(str,[d.start-1,+d.oldlength].concat(d.newlines)); + } + + if (remEOFNL) { + while (!str[str.length-1]) { + str.pop(); + } + } else if (addEOFNL) { + str.push(''); + } + return str.join('\n'); + }, + + convertChangesToXML: function(changes){ + var ret = []; + for ( var i = 0; i < changes.length; i++) { + var change = changes[i]; + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + + ret.push(escapeHTML(change.value)); + + if (change.added) { + ret.push(''); + } else if (change.removed) { + ret.push(''); + } + } + return ret.join(''); + }, + + // See: http://code.google.com/p/google-diff-match-patch/wiki/API + convertChangesToDMP: function(changes){ + var ret = [], change; + for ( var i = 0; i < changes.length; i++) { + change = changes[i]; + ret.push([(change.added ? 1 : change.removed ? -1 : 0), change.value]); + } + return ret; + } + }; +})(); + +if (typeof module !== 'undefined') { + module.exports = JsDiff; +} + +}); // module: browser/diff.js + +require.register("browser/escape-string-regexp.js", function(module, exports, require){ +'use strict'; + +var matchOperatorsRe = /[|\\{}()[\]^$+*?.]/g; + +module.exports = function (str) { + if (typeof str !== 'string') { + throw new TypeError('Expected a string'); + } + + return str.replace(matchOperatorsRe, '\\$&'); +}; + +}); // module: browser/escape-string-regexp.js + +require.register("browser/events.js", function(module, exports, require){ +/** + * Module exports. + */ + +exports.EventEmitter = EventEmitter; + +/** + * Check if `obj` is an array. + */ + +function isArray(obj) { + return '[object Array]' == {}.toString.call(obj); +} + +/** + * Event emitter constructor. + * + * @api public + */ + +function EventEmitter(){}; + +/** + * Adds a listener. + * + * @api public + */ + +EventEmitter.prototype.on = function (name, fn) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = fn; + } else if (isArray(this.$events[name])) { + this.$events[name].push(fn); + } else { + this.$events[name] = [this.$events[name], fn]; + } + + return this; +}; + +EventEmitter.prototype.addListener = EventEmitter.prototype.on; + +/** + * Adds a volatile listener. + * + * @api public + */ + +EventEmitter.prototype.once = function (name, fn) { + var self = this; + + function on () { + self.removeListener(name, on); + fn.apply(this, arguments); + }; + + on.listener = fn; + this.on(name, on); + + return this; +}; + +/** + * Removes a listener. + * + * @api public + */ + +EventEmitter.prototype.removeListener = function (name, fn) { + if (this.$events && this.$events[name]) { + var list = this.$events[name]; + + if (isArray(list)) { + var pos = -1; + + for (var i = 0, l = list.length; i < l; i++) { + if (list[i] === fn || (list[i].listener && list[i].listener === fn)) { + pos = i; + break; + } + } + + if (pos < 0) { + return this; + } + + list.splice(pos, 1); + + if (!list.length) { + delete this.$events[name]; + } + } else if (list === fn || (list.listener && list.listener === fn)) { + delete this.$events[name]; + } + } + + return this; +}; + +/** + * Removes all listeners for an event. + * + * @api public + */ + +EventEmitter.prototype.removeAllListeners = function (name) { + if (name === undefined) { + this.$events = {}; + return this; + } + + if (this.$events && this.$events[name]) { + this.$events[name] = null; + } + + return this; +}; + +/** + * Gets all listeners for a certain event. + * + * @api public + */ + +EventEmitter.prototype.listeners = function (name) { + if (!this.$events) { + this.$events = {}; + } + + if (!this.$events[name]) { + this.$events[name] = []; + } + + if (!isArray(this.$events[name])) { + this.$events[name] = [this.$events[name]]; + } + + return this.$events[name]; +}; + +/** + * Emits an event. + * + * @api public + */ + +EventEmitter.prototype.emit = function (name) { + if (!this.$events) { + return false; + } + + var handler = this.$events[name]; + + if (!handler) { + return false; + } + + var args = [].slice.call(arguments, 1); + + if ('function' == typeof handler) { + handler.apply(this, args); + } else if (isArray(handler)) { + var listeners = handler.slice(); + + for (var i = 0, l = listeners.length; i < l; i++) { + listeners[i].apply(this, args); + } + } else { + return false; + } + + return true; +}; + +}); // module: browser/events.js + +require.register("browser/fs.js", function(module, exports, require){ + +}); // module: browser/fs.js + +require.register("browser/glob.js", function(module, exports, require){ + +}); // module: browser/glob.js + +require.register("browser/path.js", function(module, exports, require){ + +}); // module: browser/path.js + +require.register("browser/progress.js", function(module, exports, require){ +/** + * Expose `Progress`. + */ + +module.exports = Progress; + +/** + * Initialize a new `Progress` indicator. + */ + +function Progress() { + this.percent = 0; + this.size(0); + this.fontSize(11); + this.font('helvetica, arial, sans-serif'); +} + +/** + * Set progress size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.size = function(n){ + this._size = n; + return this; +}; + +/** + * Set text to `str`. + * + * @param {String} str + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.text = function(str){ + this._text = str; + return this; +}; + +/** + * Set font size to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + * @api public + */ + +Progress.prototype.fontSize = function(n){ + this._fontSize = n; + return this; +}; + +/** + * Set font `family`. + * + * @param {String} family + * @return {Progress} for chaining + */ + +Progress.prototype.font = function(family){ + this._font = family; + return this; +}; + +/** + * Update percentage to `n`. + * + * @param {Number} n + * @return {Progress} for chaining + */ + +Progress.prototype.update = function(n){ + this.percent = n; + return this; +}; + +/** + * Draw on `ctx`. + * + * @param {CanvasRenderingContext2d} ctx + * @return {Progress} for chaining + */ + +Progress.prototype.draw = function(ctx){ + try { + var percent = Math.min(this.percent, 100) + , size = this._size + , half = size / 2 + , x = half + , y = half + , rad = half - 1 + , fontSize = this._fontSize; + + ctx.font = fontSize + 'px ' + this._font; + + var angle = Math.PI * 2 * (percent / 100); + ctx.clearRect(0, 0, size, size); + + // outer circle + ctx.strokeStyle = '#9f9f9f'; + ctx.beginPath(); + ctx.arc(x, y, rad, 0, angle, false); + ctx.stroke(); + + // inner circle + ctx.strokeStyle = '#eee'; + ctx.beginPath(); + ctx.arc(x, y, rad - 1, 0, angle, true); + ctx.stroke(); + + // text + var text = this._text || (percent | 0) + '%' + , w = ctx.measureText(text).width; + + ctx.fillText( + text + , x - w / 2 + 1 + , y + fontSize / 2 - 1); + } catch (ex) {} //don't fail if we can't render progress + return this; +}; + +}); // module: browser/progress.js + +require.register("browser/tty.js", function(module, exports, require){ +exports.isatty = function(){ + return true; +}; + +exports.getWindowSize = function(){ + if ('innerHeight' in global) { + return [global.innerHeight, global.innerWidth]; + } else { + // In a Web Worker, the DOM Window is not available. + return [640, 480]; + } +}; + +}); // module: browser/tty.js + +require.register("context.js", function(module, exports, require){ +/** + * Expose `Context`. + */ + +module.exports = Context; + +/** + * Initialize a new `Context`. + * + * @api private + */ + +function Context(){} + +/** + * Set or get the context `Runnable` to `runnable`. + * + * @param {Runnable} runnable + * @return {Context} + * @api private + */ + +Context.prototype.runnable = function(runnable){ + if (0 == arguments.length) return this._runnable; + this.test = this._runnable = runnable; + return this; +}; + +/** + * Set test timeout `ms`. + * + * @param {Number} ms + * @return {Context} self + * @api private + */ + +Context.prototype.timeout = function(ms){ + if (arguments.length === 0) return this.runnable().timeout(); + this.runnable().timeout(ms); + return this; +}; + +/** + * Set test timeout `enabled`. + * + * @param {Boolean} enabled + * @return {Context} self + * @api private + */ + +Context.prototype.enableTimeouts = function (enabled) { + this.runnable().enableTimeouts(enabled); + return this; +}; + + +/** + * Set test slowness threshold `ms`. + * + * @param {Number} ms + * @return {Context} self + * @api private + */ + +Context.prototype.slow = function(ms){ + this.runnable().slow(ms); + return this; +}; + +/** + * Inspect the context void of `._runnable`. + * + * @return {String} + * @api private + */ + +Context.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + if ('_runnable' == key) return; + if ('test' == key) return; + return val; + }, 2); +}; + +}); // module: context.js + +require.register("hook.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Hook`. + */ + +module.exports = Hook; + +/** + * Initialize a new `Hook` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Hook(title, fn) { + Runnable.call(this, title, fn); + this.type = 'hook'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +function F(){}; +F.prototype = Runnable.prototype; +Hook.prototype = new F; +Hook.prototype.constructor = Hook; + + +/** + * Get or set the test `err`. + * + * @param {Error} err + * @return {Error} + * @api public + */ + +Hook.prototype.error = function(err){ + if (0 == arguments.length) { + var err = this._error; + this._error = null; + return err; + } + + this._error = err; +}; + +}); // module: hook.js + +require.register("interfaces/bdd.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test') + , utils = require('../utils') + , escapeRe = require('browser/escape-string-regexp'); + +/** + * BDD-style interface: + * + * describe('Array', function(){ + * describe('#indexOf()', function(){ + * it('should return -1 when not present', function(){ + * + * }); + * + * it('should return the index when present', function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context, file, mocha){ + + /** + * Execute before running tests. + */ + + context.before = function(name, fn){ + suites[0].beforeAll(name, fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(name, fn){ + suites[0].afterAll(name, fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(name, fn){ + suites[0].beforeEach(name, fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(name, fn){ + suites[0].afterEach(name, fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.describe = context.context = function(title, fn){ + var suite = Suite.create(suites[0], title); + suite.file = file; + suites.unshift(suite); + fn.call(suite); + suites.shift(); + return suite; + }; + + /** + * Pending describe. + */ + + context.xdescribe = + context.xcontext = + context.describe.skip = function(title, fn){ + var suite = Suite.create(suites[0], title); + suite.pending = true; + suites.unshift(suite); + fn.call(suite); + suites.shift(); + }; + + /** + * Exclusive suite. + */ + + context.describe.only = function(title, fn){ + var suite = context.describe(title, fn); + mocha.grep(suite.fullTitle()); + return suite; + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.it = context.specify = function(title, fn){ + var suite = suites[0]; + if (suite.pending) fn = null; + var test = new Test(title, fn); + test.file = file; + suite.addTest(test); + return test; + }; + + /** + * Exclusive test-case. + */ + + context.it.only = function(title, fn){ + var test = context.it(title, fn); + var reString = '^' + escapeRe(test.fullTitle()) + '$'; + mocha.grep(new RegExp(reString)); + return test; + }; + + /** + * Pending test case. + */ + + context.xit = + context.xspecify = + context.it.skip = function(title){ + context.it(title); + }; + }); +}; + +}); // module: interfaces/bdd.js + +require.register("interfaces/exports.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test'); + +/** + * TDD-style interface: + * + * exports.Array = { + * '#indexOf()': { + * 'should return -1 when the value is not present': function(){ + * + * }, + * + * 'should return the correct index when the value is present': function(){ + * + * } + * } + * }; + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('require', visit); + + function visit(obj, file) { + var suite; + for (var key in obj) { + if ('function' == typeof obj[key]) { + var fn = obj[key]; + switch (key) { + case 'before': + suites[0].beforeAll(fn); + break; + case 'after': + suites[0].afterAll(fn); + break; + case 'beforeEach': + suites[0].beforeEach(fn); + break; + case 'afterEach': + suites[0].afterEach(fn); + break; + default: + var test = new Test(key, fn); + test.file = file; + suites[0].addTest(test); + } + } else { + suite = Suite.create(suites[0], key); + suites.unshift(suite); + visit(obj[key]); + suites.shift(); + } + } + } +}; + +}); // module: interfaces/exports.js + +require.register("interfaces/index.js", function(module, exports, require){ +exports.bdd = require('./bdd'); +exports.tdd = require('./tdd'); +exports.qunit = require('./qunit'); +exports.exports = require('./exports'); + +}); // module: interfaces/index.js + +require.register("interfaces/qunit.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test') + , escapeRe = require('browser/escape-string-regexp') + , utils = require('../utils'); + +/** + * QUnit-style interface: + * + * suite('Array'); + * + * test('#length', function(){ + * var arr = [1,2,3]; + * ok(arr.length == 3); + * }); + * + * test('#indexOf()', function(){ + * var arr = [1,2,3]; + * ok(arr.indexOf(1) == 0); + * ok(arr.indexOf(2) == 1); + * ok(arr.indexOf(3) == 2); + * }); + * + * suite('String'); + * + * test('#length', function(){ + * ok('foo'.length == 3); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context, file, mocha){ + + /** + * Execute before running tests. + */ + + context.before = function(name, fn){ + suites[0].beforeAll(name, fn); + }; + + /** + * Execute after running tests. + */ + + context.after = function(name, fn){ + suites[0].afterAll(name, fn); + }; + + /** + * Execute before each test case. + */ + + context.beforeEach = function(name, fn){ + suites[0].beforeEach(name, fn); + }; + + /** + * Execute after each test case. + */ + + context.afterEach = function(name, fn){ + suites[0].afterEach(name, fn); + }; + + /** + * Describe a "suite" with the given `title`. + */ + + context.suite = function(title){ + if (suites.length > 1) suites.shift(); + var suite = Suite.create(suites[0], title); + suite.file = file; + suites.unshift(suite); + return suite; + }; + + /** + * Exclusive test-case. + */ + + context.suite.only = function(title, fn){ + var suite = context.suite(title, fn); + mocha.grep(suite.fullTitle()); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + var test = new Test(title, fn); + test.file = file; + suites[0].addTest(test); + return test; + }; + + /** + * Exclusive test-case. + */ + + context.test.only = function(title, fn){ + var test = context.test(title, fn); + var reString = '^' + escapeRe(test.fullTitle()) + '$'; + mocha.grep(new RegExp(reString)); + }; + + /** + * Pending test case. + */ + + context.test.skip = function(title){ + context.test(title); + }; + }); +}; + +}); // module: interfaces/qunit.js + +require.register("interfaces/tdd.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Suite = require('../suite') + , Test = require('../test') + , escapeRe = require('browser/escape-string-regexp') + , utils = require('../utils'); + +/** + * TDD-style interface: + * + * suite('Array', function(){ + * suite('#indexOf()', function(){ + * suiteSetup(function(){ + * + * }); + * + * test('should return -1 when not present', function(){ + * + * }); + * + * test('should return the index when present', function(){ + * + * }); + * + * suiteTeardown(function(){ + * + * }); + * }); + * }); + * + */ + +module.exports = function(suite){ + var suites = [suite]; + + suite.on('pre-require', function(context, file, mocha){ + + /** + * Execute before each test case. + */ + + context.setup = function(name, fn){ + suites[0].beforeEach(name, fn); + }; + + /** + * Execute after each test case. + */ + + context.teardown = function(name, fn){ + suites[0].afterEach(name, fn); + }; + + /** + * Execute before the suite. + */ + + context.suiteSetup = function(name, fn){ + suites[0].beforeAll(name, fn); + }; + + /** + * Execute after the suite. + */ + + context.suiteTeardown = function(name, fn){ + suites[0].afterAll(name, fn); + }; + + /** + * Describe a "suite" with the given `title` + * and callback `fn` containing nested suites + * and/or tests. + */ + + context.suite = function(title, fn){ + var suite = Suite.create(suites[0], title); + suite.file = file; + suites.unshift(suite); + fn.call(suite); + suites.shift(); + return suite; + }; + + /** + * Pending suite. + */ + context.suite.skip = function(title, fn) { + var suite = Suite.create(suites[0], title); + suite.pending = true; + suites.unshift(suite); + fn.call(suite); + suites.shift(); + }; + + /** + * Exclusive test-case. + */ + + context.suite.only = function(title, fn){ + var suite = context.suite(title, fn); + mocha.grep(suite.fullTitle()); + }; + + /** + * Describe a specification or test-case + * with the given `title` and callback `fn` + * acting as a thunk. + */ + + context.test = function(title, fn){ + var suite = suites[0]; + if (suite.pending) fn = null; + var test = new Test(title, fn); + test.file = file; + suite.addTest(test); + return test; + }; + + /** + * Exclusive test-case. + */ + + context.test.only = function(title, fn){ + var test = context.test(title, fn); + var reString = '^' + escapeRe(test.fullTitle()) + '$'; + mocha.grep(new RegExp(reString)); + }; + + /** + * Pending test case. + */ + + context.test.skip = function(title){ + context.test(title); + }; + }); +}; + +}); // module: interfaces/tdd.js + +require.register("mocha.js", function(module, exports, require){ +/*! + * mocha + * Copyright(c) 2011 TJ Holowaychuk + * MIT Licensed + */ + +/** + * Module dependencies. + */ + +var path = require('browser/path') + , escapeRe = require('browser/escape-string-regexp') + , utils = require('./utils'); + +/** + * Expose `Mocha`. + */ + +exports = module.exports = Mocha; + +/** + * To require local UIs and reporters when running in node. + */ + +if (typeof process !== 'undefined' && typeof process.cwd === 'function') { + var join = path.join + , cwd = process.cwd(); + module.paths.push(cwd, join(cwd, 'node_modules')); +} + +/** + * Expose internals. + */ + +exports.utils = utils; +exports.interfaces = require('./interfaces'); +exports.reporters = require('./reporters'); +exports.Runnable = require('./runnable'); +exports.Context = require('./context'); +exports.Runner = require('./runner'); +exports.Suite = require('./suite'); +exports.Hook = require('./hook'); +exports.Test = require('./test'); + +/** + * Return image `name` path. + * + * @param {String} name + * @return {String} + * @api private + */ + +function image(name) { + return __dirname + '/../images/' + name + '.png'; +} + +/** + * Setup mocha with `options`. + * + * Options: + * + * - `ui` name "bdd", "tdd", "exports" etc + * - `reporter` reporter instance, defaults to `mocha.reporters.spec` + * - `globals` array of accepted globals + * - `timeout` timeout in milliseconds + * - `bail` bail on the first test failure + * - `slow` milliseconds to wait before considering a test slow + * - `ignoreLeaks` ignore global leaks + * - `grep` string or regexp to filter tests with + * + * @param {Object} options + * @api public + */ + +function Mocha(options) { + options = options || {}; + this.files = []; + this.options = options; + this.grep(options.grep); + this.suite = new exports.Suite('', new exports.Context); + this.ui(options.ui); + this.bail(options.bail); + this.reporter(options.reporter); + if (null != options.timeout) this.timeout(options.timeout); + this.useColors(options.useColors) + if (options.enableTimeouts !== null) this.enableTimeouts(options.enableTimeouts); + if (options.slow) this.slow(options.slow); + + this.suite.on('pre-require', function (context) { + exports.afterEach = context.afterEach || context.teardown; + exports.after = context.after || context.suiteTeardown; + exports.beforeEach = context.beforeEach || context.setup; + exports.before = context.before || context.suiteSetup; + exports.describe = context.describe || context.suite; + exports.it = context.it || context.test; + exports.setup = context.setup || context.beforeEach; + exports.suiteSetup = context.suiteSetup || context.before; + exports.suiteTeardown = context.suiteTeardown || context.after; + exports.suite = context.suite || context.describe; + exports.teardown = context.teardown || context.afterEach; + exports.test = context.test || context.it; + }); +} + +/** + * Enable or disable bailing on the first failure. + * + * @param {Boolean} [bail] + * @api public + */ + +Mocha.prototype.bail = function(bail){ + if (0 == arguments.length) bail = true; + this.suite.bail(bail); + return this; +}; + +/** + * Add test `file`. + * + * @param {String} file + * @api public + */ + +Mocha.prototype.addFile = function(file){ + this.files.push(file); + return this; +}; + +/** + * Set reporter to `reporter`, defaults to "spec". + * + * @param {String|Function} reporter name or constructor + * @api public + */ + +Mocha.prototype.reporter = function(reporter){ + if ('function' == typeof reporter) { + this._reporter = reporter; + } else { + reporter = reporter || 'spec'; + var _reporter; + try { _reporter = require('./reporters/' + reporter); } catch (err) {}; + if (!_reporter) try { _reporter = require(reporter); } catch (err) {}; + if (!_reporter && reporter === 'teamcity') + console.warn('The Teamcity reporter was moved to a package named ' + + 'mocha-teamcity-reporter ' + + '(https://npmjs.org/package/mocha-teamcity-reporter).'); + if (!_reporter) throw new Error('invalid reporter "' + reporter + '"'); + this._reporter = _reporter; + } + return this; +}; + +/** + * Set test UI `name`, defaults to "bdd". + * + * @param {String} bdd + * @api public + */ + +Mocha.prototype.ui = function(name){ + name = name || 'bdd'; + this._ui = exports.interfaces[name]; + if (!this._ui) try { this._ui = require(name); } catch (err) {}; + if (!this._ui) throw new Error('invalid interface "' + name + '"'); + this._ui = this._ui(this.suite); + return this; +}; + +/** + * Load registered files. + * + * @api private + */ + +Mocha.prototype.loadFiles = function(fn){ + var self = this; + var suite = this.suite; + var pending = this.files.length; + this.files.forEach(function(file){ + file = path.resolve(file); + suite.emit('pre-require', global, file, self); + suite.emit('require', require(file), file, self); + suite.emit('post-require', global, file, self); + --pending || (fn && fn()); + }); +}; + +/** + * Enable growl support. + * + * @api private + */ + +Mocha.prototype._growl = function(runner, reporter) { + var notify = require('growl'); + + runner.on('end', function(){ + var stats = reporter.stats; + if (stats.failures) { + var msg = stats.failures + ' of ' + runner.total + ' tests failed'; + notify(msg, { name: 'mocha', title: 'Failed', image: image('error') }); + } else { + notify(stats.passes + ' tests passed in ' + stats.duration + 'ms', { + name: 'mocha' + , title: 'Passed' + , image: image('ok') + }); + } + }); +}; + +/** + * Add regexp to grep, if `re` is a string it is escaped. + * + * @param {RegExp|String} re + * @return {Mocha} + * @api public + */ + +Mocha.prototype.grep = function(re){ + this.options.grep = 'string' == typeof re + ? new RegExp(escapeRe(re)) + : re; + return this; +}; + +/** + * Invert `.grep()` matches. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.invert = function(){ + this.options.invert = true; + return this; +}; + +/** + * Ignore global leaks. + * + * @param {Boolean} ignore + * @return {Mocha} + * @api public + */ + +Mocha.prototype.ignoreLeaks = function(ignore){ + this.options.ignoreLeaks = !!ignore; + return this; +}; + +/** + * Enable global leak checking. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.checkLeaks = function(){ + this.options.ignoreLeaks = false; + return this; +}; + +/** + * Enable growl support. + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.growl = function(){ + this.options.growl = true; + return this; +}; + +/** + * Ignore `globals` array or string. + * + * @param {Array|String} globals + * @return {Mocha} + * @api public + */ + +Mocha.prototype.globals = function(globals){ + this.options.globals = (this.options.globals || []).concat(globals); + return this; +}; + +/** + * Emit color output. + * + * @param {Boolean} colors + * @return {Mocha} + * @api public + */ + +Mocha.prototype.useColors = function(colors){ + this.options.useColors = arguments.length && colors != undefined + ? colors + : true; + return this; +}; + +/** + * Use inline diffs rather than +/-. + * + * @param {Boolean} inlineDiffs + * @return {Mocha} + * @api public + */ + +Mocha.prototype.useInlineDiffs = function(inlineDiffs) { + this.options.useInlineDiffs = arguments.length && inlineDiffs != undefined + ? inlineDiffs + : false; + return this; +}; + +/** + * Set the timeout in milliseconds. + * + * @param {Number} timeout + * @return {Mocha} + * @api public + */ + +Mocha.prototype.timeout = function(timeout){ + this.suite.timeout(timeout); + return this; +}; + +/** + * Set slowness threshold in milliseconds. + * + * @param {Number} slow + * @return {Mocha} + * @api public + */ + +Mocha.prototype.slow = function(slow){ + this.suite.slow(slow); + return this; +}; + +/** + * Enable timeouts. + * + * @param {Boolean} enabled + * @return {Mocha} + * @api public + */ + +Mocha.prototype.enableTimeouts = function(enabled) { + this.suite.enableTimeouts(arguments.length && enabled !== undefined + ? enabled + : true); + return this +}; + +/** + * Makes all tests async (accepting a callback) + * + * @return {Mocha} + * @api public + */ + +Mocha.prototype.asyncOnly = function(){ + this.options.asyncOnly = true; + return this; +}; + +/** + * Disable syntax highlighting (in browser). + * @returns {Mocha} + * @api public + */ +Mocha.prototype.noHighlighting = function() { + this.options.noHighlighting = true; + return this; +}; + +/** + * Run tests and invoke `fn()` when complete. + * + * @param {Function} fn + * @return {Runner} + * @api public + */ + +Mocha.prototype.run = function(fn){ + if (this.files.length) this.loadFiles(); + var suite = this.suite; + var options = this.options; + options.files = this.files; + var runner = new exports.Runner(suite); + var reporter = new this._reporter(runner, options); + runner.ignoreLeaks = false !== options.ignoreLeaks; + runner.asyncOnly = options.asyncOnly; + if (options.grep) runner.grep(options.grep, options.invert); + if (options.globals) runner.globals(options.globals); + if (options.growl) this._growl(runner, reporter); + exports.reporters.Base.useColors = options.useColors; + exports.reporters.Base.inlineDiffs = options.useInlineDiffs; + return runner.run(fn); +}; + +}); // module: mocha.js + +require.register("ms.js", function(module, exports, require){ +/** + * Helpers. + */ + +var s = 1000; +var m = s * 60; +var h = m * 60; +var d = h * 24; +var y = d * 365.25; + +/** + * Parse or format the given `val`. + * + * Options: + * + * - `long` verbose formatting [false] + * + * @param {String|Number} val + * @param {Object} options + * @return {String|Number} + * @api public + */ + +module.exports = function(val, options){ + options = options || {}; + if ('string' == typeof val) return parse(val); + return options['long'] ? longFormat(val) : shortFormat(val); +}; + +/** + * Parse the given `str` and return milliseconds. + * + * @param {String} str + * @return {Number} + * @api private + */ + +function parse(str) { + var match = /^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(str); + if (!match) return; + var n = parseFloat(match[1]); + var type = (match[2] || 'ms').toLowerCase(); + switch (type) { + case 'years': + case 'year': + case 'y': + return n * y; + case 'days': + case 'day': + case 'd': + return n * d; + case 'hours': + case 'hour': + case 'h': + return n * h; + case 'minutes': + case 'minute': + case 'm': + return n * m; + case 'seconds': + case 'second': + case 's': + return n * s; + case 'ms': + return n; + } +} + +/** + * Short format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function shortFormat(ms) { + if (ms >= d) return Math.round(ms / d) + 'd'; + if (ms >= h) return Math.round(ms / h) + 'h'; + if (ms >= m) return Math.round(ms / m) + 'm'; + if (ms >= s) return Math.round(ms / s) + 's'; + return ms + 'ms'; +} + +/** + * Long format for `ms`. + * + * @param {Number} ms + * @return {String} + * @api private + */ + +function longFormat(ms) { + return plural(ms, d, 'day') + || plural(ms, h, 'hour') + || plural(ms, m, 'minute') + || plural(ms, s, 'second') + || ms + ' ms'; +} + +/** + * Pluralization helper. + */ + +function plural(ms, n, name) { + if (ms < n) return; + if (ms < n * 1.5) return Math.floor(ms / n) + ' ' + name; + return Math.ceil(ms / n) + ' ' + name + 's'; +} + +}); // module: ms.js + +require.register("reporters/base.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var tty = require('browser/tty') + , diff = require('browser/diff') + , ms = require('../ms') + , utils = require('../utils'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Check if both stdio streams are associated with a tty. + */ + +var isatty = tty.isatty(1) && tty.isatty(2); + +/** + * Expose `Base`. + */ + +exports = module.exports = Base; + +/** + * Enable coloring by default. + */ + +exports.useColors = isatty || (process.env.MOCHA_COLORS !== undefined); + +/** + * Inline diffs instead of +/- + */ + +exports.inlineDiffs = false; + +/** + * Default color map. + */ + +exports.colors = { + 'pass': 90 + , 'fail': 31 + , 'bright pass': 92 + , 'bright fail': 91 + , 'bright yellow': 93 + , 'pending': 36 + , 'suite': 0 + , 'error title': 0 + , 'error message': 31 + , 'error stack': 90 + , 'checkmark': 32 + , 'fast': 90 + , 'medium': 33 + , 'slow': 31 + , 'green': 32 + , 'light': 90 + , 'diff gutter': 90 + , 'diff added': 42 + , 'diff removed': 41 +}; + +/** + * Default symbol map. + */ + +exports.symbols = { + ok: '✓', + err: '✖', + dot: '․' +}; + +// With node.js on Windows: use symbols available in terminal default fonts +if ('win32' == process.platform) { + exports.symbols.ok = '\u221A'; + exports.symbols.err = '\u00D7'; + exports.symbols.dot = '.'; +} + +/** + * Color `str` with the given `type`, + * allowing colors to be disabled, + * as well as user-defined color + * schemes. + * + * @param {String} type + * @param {String} str + * @return {String} + * @api private + */ + +var color = exports.color = function(type, str) { + if (!exports.useColors) return str; + return '\u001b[' + exports.colors[type] + 'm' + str + '\u001b[0m'; +}; + +/** + * Expose term window size, with some + * defaults for when stderr is not a tty. + */ + +exports.window = { + width: isatty + ? process.stdout.getWindowSize + ? process.stdout.getWindowSize(1)[0] + : tty.getWindowSize()[1] + : 75 +}; + +/** + * Expose some basic cursor interactions + * that are common among reporters. + */ + +exports.cursor = { + hide: function(){ + isatty && process.stdout.write('\u001b[?25l'); + }, + + show: function(){ + isatty && process.stdout.write('\u001b[?25h'); + }, + + deleteLine: function(){ + isatty && process.stdout.write('\u001b[2K'); + }, + + beginningOfLine: function(){ + isatty && process.stdout.write('\u001b[0G'); + }, + + CR: function(){ + if (isatty) { + exports.cursor.deleteLine(); + exports.cursor.beginningOfLine(); + } else { + process.stdout.write('\r'); + } + } +}; + +/** + * Outut the given `failures` as a list. + * + * @param {Array} failures + * @api public + */ + +exports.list = function(failures){ + console.error(); + failures.forEach(function(test, i){ + // format + var fmt = color('error title', ' %s) %s:\n') + + color('error message', ' %s') + + color('error stack', '\n%s\n'); + + // msg + var err = test.err + , message = err.message || '' + , stack = err.stack || message + , index = stack.indexOf(message) + message.length + , msg = stack.slice(0, index) + , actual = err.actual + , expected = err.expected + , escape = true; + + // uncaught + if (err.uncaught) { + msg = 'Uncaught ' + msg; + } + + // explicitly show diff + if (err.showDiff && sameType(actual, expected)) { + escape = false; + err.actual = actual = utils.stringify(actual); + err.expected = expected = utils.stringify(expected); + } + + // actual / expected diff + if (err.showDiff && 'string' == typeof actual && 'string' == typeof expected) { + fmt = color('error title', ' %s) %s:\n%s') + color('error stack', '\n%s\n'); + var match = message.match(/^([^:]+): expected/); + msg = '\n ' + color('error message', match ? match[1] : msg); + + if (exports.inlineDiffs) { + msg += inlineDiff(err, escape); + } else { + msg += unifiedDiff(err, escape); + } + } + + // indent stack trace without msg + stack = stack.slice(index ? index + 1 : index) + .replace(/^/gm, ' '); + + console.error(fmt, (i + 1), test.fullTitle(), msg, stack); + }); +}; + +/** + * Initialize a new `Base` reporter. + * + * All other reporters generally + * inherit from this reporter, providing + * stats such as test duration, number + * of tests passed / failed etc. + * + * @param {Runner} runner + * @api public + */ + +function Base(runner) { + var self = this + , stats = this.stats = { suites: 0, tests: 0, passes: 0, pending: 0, failures: 0 } + , failures = this.failures = []; + + if (!runner) return; + this.runner = runner; + + runner.stats = stats; + + runner.on('start', function(){ + stats.start = new Date; + }); + + runner.on('suite', function(suite){ + stats.suites = stats.suites || 0; + suite.root || stats.suites++; + }); + + runner.on('test end', function(test){ + stats.tests = stats.tests || 0; + stats.tests++; + }); + + runner.on('pass', function(test){ + stats.passes = stats.passes || 0; + + var medium = test.slow() / 2; + test.speed = test.duration > test.slow() + ? 'slow' + : test.duration > medium + ? 'medium' + : 'fast'; + + stats.passes++; + }); + + runner.on('fail', function(test, err){ + stats.failures = stats.failures || 0; + stats.failures++; + test.err = err; + failures.push(test); + }); + + runner.on('end', function(){ + stats.end = new Date; + stats.duration = new Date - stats.start; + }); + + runner.on('pending', function(){ + stats.pending++; + }); +} + +/** + * Output common epilogue used by many of + * the bundled reporters. + * + * @api public + */ + +Base.prototype.epilogue = function(){ + var stats = this.stats; + var tests; + var fmt; + + console.log(); + + // passes + fmt = color('bright pass', ' ') + + color('green', ' %d passing') + + color('light', ' (%s)'); + + console.log(fmt, + stats.passes || 0, + ms(stats.duration)); + + // pending + if (stats.pending) { + fmt = color('pending', ' ') + + color('pending', ' %d pending'); + + console.log(fmt, stats.pending); + } + + // failures + if (stats.failures) { + fmt = color('fail', ' %d failing'); + + console.error(fmt, + stats.failures); + + Base.list(this.failures); + console.error(); + } + + console.log(); +}; + +/** + * Pad the given `str` to `len`. + * + * @param {String} str + * @param {String} len + * @return {String} + * @api private + */ + +function pad(str, len) { + str = String(str); + return Array(len - str.length + 1).join(' ') + str; +} + + +/** + * Returns an inline diff between 2 strings with coloured ANSI output + * + * @param {Error} Error with actual/expected + * @return {String} Diff + * @api private + */ + +function inlineDiff(err, escape) { + var msg = errorDiff(err, 'WordsWithSpace', escape); + + // linenos + var lines = msg.split('\n'); + if (lines.length > 4) { + var width = String(lines.length).length; + msg = lines.map(function(str, i){ + return pad(++i, width) + ' |' + ' ' + str; + }).join('\n'); + } + + // legend + msg = '\n' + + color('diff removed', 'actual') + + ' ' + + color('diff added', 'expected') + + '\n\n' + + msg + + '\n'; + + // indent + msg = msg.replace(/^/gm, ' '); + return msg; +} + +/** + * Returns a unified diff between 2 strings + * + * @param {Error} Error with actual/expected + * @return {String} Diff + * @api private + */ + +function unifiedDiff(err, escape) { + var indent = ' '; + function cleanUp(line) { + if (escape) { + line = escapeInvisibles(line); + } + if (line[0] === '+') return indent + colorLines('diff added', line); + if (line[0] === '-') return indent + colorLines('diff removed', line); + if (line.match(/\@\@/)) return null; + if (line.match(/\\ No newline/)) return null; + else return indent + line; + } + function notBlank(line) { + return line != null; + } + msg = diff.createPatch('string', err.actual, err.expected); + var lines = msg.split('\n').splice(4); + return '\n ' + + colorLines('diff added', '+ expected') + ' ' + + colorLines('diff removed', '- actual') + + '\n\n' + + lines.map(cleanUp).filter(notBlank).join('\n'); +} + +/** + * Return a character diff for `err`. + * + * @param {Error} err + * @return {String} + * @api private + */ + +function errorDiff(err, type, escape) { + var actual = escape ? escapeInvisibles(err.actual) : err.actual; + var expected = escape ? escapeInvisibles(err.expected) : err.expected; + return diff['diff' + type](actual, expected).map(function(str){ + if (str.added) return colorLines('diff added', str.value); + if (str.removed) return colorLines('diff removed', str.value); + return str.value; + }).join(''); +} + +/** + * Returns a string with all invisible characters in plain text + * + * @param {String} line + * @return {String} + * @api private + */ +function escapeInvisibles(line) { + return line.replace(/\t/g, '') + .replace(/\r/g, '') + .replace(/\n/g, '\n'); +} + +/** + * Color lines for `str`, using the color `name`. + * + * @param {String} name + * @param {String} str + * @return {String} + * @api private + */ + +function colorLines(name, str) { + return str.split('\n').map(function(str){ + return color(name, str); + }).join('\n'); +} + +/** + * Check that a / b have the same type. + * + * @param {Object} a + * @param {Object} b + * @return {Boolean} + * @api private + */ + +function sameType(a, b) { + a = Object.prototype.toString.call(a); + b = Object.prototype.toString.call(b); + return a == b; +} + +}); // module: reporters/base.js + +require.register("reporters/doc.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Doc`. + */ + +exports = module.exports = Doc; + +/** + * Initialize a new `Doc` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Doc(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , indents = 2; + + function indent() { + return Array(indents).join(' '); + } + + runner.on('suite', function(suite){ + if (suite.root) return; + ++indents; + console.log('%s
      ', indent()); + ++indents; + console.log('%s

      %s

      ', indent(), utils.escape(suite.title)); + console.log('%s
      ', indent()); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + console.log('%s
      ', indent()); + --indents; + console.log('%s
      ', indent()); + --indents; + }); + + runner.on('pass', function(test){ + console.log('%s
      %s
      ', indent(), utils.escape(test.title)); + var code = utils.escape(utils.clean(test.fn.toString())); + console.log('%s
      %s
      ', indent(), code); + }); + + runner.on('fail', function(test, err){ + console.log('%s
      %s
      ', indent(), utils.escape(test.title)); + var code = utils.escape(utils.clean(test.fn.toString())); + console.log('%s
      %s
      ', indent(), code); + console.log('%s
      %s
      ', indent(), utils.escape(err)); + }); +} + +}); // module: reporters/doc.js + +require.register("reporters/dot.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `Dot`. + */ + +exports = module.exports = Dot; + +/** + * Initialize a new `Dot` matrix test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Dot(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , n = -1; + + runner.on('start', function(){ + process.stdout.write('\n '); + }); + + runner.on('pending', function(test){ + if (++n % width == 0) process.stdout.write('\n '); + process.stdout.write(color('pending', Base.symbols.dot)); + }); + + runner.on('pass', function(test){ + if (++n % width == 0) process.stdout.write('\n '); + if ('slow' == test.speed) { + process.stdout.write(color('bright yellow', Base.symbols.dot)); + } else { + process.stdout.write(color(test.speed, Base.symbols.dot)); + } + }); + + runner.on('fail', function(test, err){ + if (++n % width == 0) process.stdout.write('\n '); + process.stdout.write(color('fail', Base.symbols.dot)); + }); + + runner.on('end', function(){ + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Dot.prototype = new F; +Dot.prototype.constructor = Dot; + + +}); // module: reporters/dot.js + +require.register("reporters/html-cov.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var JSONCov = require('./json-cov') + , fs = require('browser/fs'); + +/** + * Expose `HTMLCov`. + */ + +exports = module.exports = HTMLCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTMLCov(runner) { + var jade = require('jade') + , file = __dirname + '/templates/coverage.jade' + , str = fs.readFileSync(file, 'utf8') + , fn = jade.compile(str, { filename: file }) + , self = this; + + JSONCov.call(this, runner, false); + + runner.on('end', function(){ + process.stdout.write(fn({ + cov: self.cov + , coverageClass: coverageClass + })); + }); +} + +/** + * Return coverage class for `n`. + * + * @return {String} + * @api private + */ + +function coverageClass(n) { + if (n >= 75) return 'high'; + if (n >= 50) return 'medium'; + if (n >= 25) return 'low'; + return 'terrible'; +} + +}); // module: reporters/html-cov.js + +require.register("reporters/html.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , Progress = require('../browser/progress') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `HTML`. + */ + +exports = module.exports = HTML; + +/** + * Stats template. + */ + +var statsTemplate = '
      '; + +/** + * Initialize a new `HTML` reporter. + * + * @param {Runner} runner + * @api public + */ + +function HTML(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total + , stat = fragment(statsTemplate) + , items = stat.getElementsByTagName('li') + , passes = items[1].getElementsByTagName('em')[0] + , passesLink = items[1].getElementsByTagName('a')[0] + , failures = items[2].getElementsByTagName('em')[0] + , failuresLink = items[2].getElementsByTagName('a')[0] + , duration = items[3].getElementsByTagName('em')[0] + , canvas = stat.getElementsByTagName('canvas')[0] + , report = fragment('
        ') + , stack = [report] + , progress + , ctx + , root = document.getElementById('mocha'); + + if (canvas.getContext) { + var ratio = window.devicePixelRatio || 1; + canvas.style.width = canvas.width; + canvas.style.height = canvas.height; + canvas.width *= ratio; + canvas.height *= ratio; + ctx = canvas.getContext('2d'); + ctx.scale(ratio, ratio); + progress = new Progress; + } + + if (!root) return error('#mocha div missing, add it to your document'); + + // pass toggle + on(passesLink, 'click', function(){ + unhide(); + var name = /pass/.test(report.className) ? '' : ' pass'; + report.className = report.className.replace(/fail|pass/g, '') + name; + if (report.className.trim()) hideSuitesWithout('test pass'); + }); + + // failure toggle + on(failuresLink, 'click', function(){ + unhide(); + var name = /fail/.test(report.className) ? '' : ' fail'; + report.className = report.className.replace(/fail|pass/g, '') + name; + if (report.className.trim()) hideSuitesWithout('test fail'); + }); + + root.appendChild(stat); + root.appendChild(report); + + if (progress) progress.size(40); + + runner.on('suite', function(suite){ + if (suite.root) return; + + // suite + var url = self.suiteURL(suite); + var el = fragment('
      • %s

      • ', url, escape(suite.title)); + + // container + stack[0].appendChild(el); + stack.unshift(document.createElement('ul')); + el.appendChild(stack[0]); + }); + + runner.on('suite end', function(suite){ + if (suite.root) return; + stack.shift(); + }); + + runner.on('fail', function(test, err){ + if ('hook' == test.type) runner.emit('test end', test); + }); + + runner.on('test end', function(test){ + // TODO: add to stats + var percent = stats.tests / this.total * 100 | 0; + if (progress) progress.update(percent).draw(ctx); + + // update stats + var ms = new Date - stats.start; + text(passes, stats.passes); + text(failures, stats.failures); + text(duration, (ms / 1000).toFixed(2)); + + // test + if ('passed' == test.state) { + var url = self.testURL(test); + var el = fragment('
      • %e%ems

      • ', test.speed, test.title, test.duration, url); + } else if (test.pending) { + var el = fragment('
      • %e

      • ', test.title); + } else { + var el = fragment('
      • %e

      • ', test.title, encodeURIComponent(test.fullTitle())); + var str = test.err.stack || test.err.toString(); + + // FF / Opera do not add the message + if (!~str.indexOf(test.err.message)) { + str = test.err.message + '\n' + str; + } + + // <=IE7 stringifies to [Object Error]. Since it can be overloaded, we + // check for the result of the stringifying. + if ('[object Error]' == str) str = test.err.message; + + // Safari doesn't give you a stack. Let's at least provide a source line. + if (!test.err.stack && test.err.sourceURL && test.err.line !== undefined) { + str += "\n(" + test.err.sourceURL + ":" + test.err.line + ")"; + } + + el.appendChild(fragment('
        %e
        ', str)); + } + + // toggle code + // TODO: defer + if (!test.pending) { + var h2 = el.getElementsByTagName('h2')[0]; + + on(h2, 'click', function(){ + pre.style.display = 'none' == pre.style.display + ? 'block' + : 'none'; + }); + + var pre = fragment('
        %e
        ', utils.clean(test.fn.toString())); + el.appendChild(pre); + pre.style.display = 'none'; + } + + // Don't call .appendChild if #mocha-report was already .shift()'ed off the stack. + if (stack[0]) stack[0].appendChild(el); + }); +} + +/** + * Makes a URL, preserving querystring ("search") parameters. + * @param {string} s + * @returns {string} your new URL + */ +var makeUrl = function makeUrl(s) { + var search = window.location.search; + return (search ? search + '&' : '?' ) + 'grep=' + encodeURIComponent(s); +}; + +/** + * Provide suite URL + * + * @param {Object} [suite] + */ +HTML.prototype.suiteURL = function(suite){ + return makeUrl(suite.fullTitle()); +}; + +/** + * Provide test URL + * + * @param {Object} [test] + */ + +HTML.prototype.testURL = function(test){ + return makeUrl(test.fullTitle()); +}; + +/** + * Display error `msg`. + */ + +function error(msg) { + document.body.appendChild(fragment('
        %s
        ', msg)); +} + +/** + * Return a DOM fragment from `html`. + */ + +function fragment(html) { + var args = arguments + , div = document.createElement('div') + , i = 1; + + div.innerHTML = html.replace(/%([se])/g, function(_, type){ + switch (type) { + case 's': return String(args[i++]); + case 'e': return escape(args[i++]); + } + }); + + return div.firstChild; +} + +/** + * Check for suites that do not have elements + * with `classname`, and hide them. + */ + +function hideSuitesWithout(classname) { + var suites = document.getElementsByClassName('suite'); + for (var i = 0; i < suites.length; i++) { + var els = suites[i].getElementsByClassName(classname); + if (0 == els.length) suites[i].className += ' hidden'; + } +} + +/** + * Unhide .hidden suites. + */ + +function unhide() { + var els = document.getElementsByClassName('suite hidden'); + for (var i = 0; i < els.length; ++i) { + els[i].className = els[i].className.replace('suite hidden', 'suite'); + } +} + +/** + * Set `el` text to `str`. + */ + +function text(el, str) { + if (el.textContent) { + el.textContent = str; + } else { + el.innerText = str; + } +} + +/** + * Listen on `event` with callback `fn`. + */ + +function on(el, event, fn) { + if (el.addEventListener) { + el.addEventListener(event, fn, false); + } else { + el.attachEvent('on' + event, fn); + } +} + +}); // module: reporters/html.js + +require.register("reporters/index.js", function(module, exports, require){ +exports.Base = require('./base'); +exports.Dot = require('./dot'); +exports.Doc = require('./doc'); +exports.TAP = require('./tap'); +exports.JSON = require('./json'); +exports.HTML = require('./html'); +exports.List = require('./list'); +exports.Min = require('./min'); +exports.Spec = require('./spec'); +exports.Nyan = require('./nyan'); +exports.XUnit = require('./xunit'); +exports.Markdown = require('./markdown'); +exports.Progress = require('./progress'); +exports.Landing = require('./landing'); +exports.JSONCov = require('./json-cov'); +exports.HTMLCov = require('./html-cov'); +exports.JSONStream = require('./json-stream'); + +}); // module: reporters/index.js + +require.register("reporters/json-cov.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `JSONCov`. + */ + +exports = module.exports = JSONCov; + +/** + * Initialize a new `JsCoverage` reporter. + * + * @param {Runner} runner + * @param {Boolean} output + * @api public + */ + +function JSONCov(runner, output) { + var self = this + , output = 1 == arguments.length ? true : output; + + Base.call(this, runner); + + var tests = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('end', function(){ + var cov = global._$jscoverage || {}; + var result = self.cov = map(cov); + result.stats = self.stats; + result.tests = tests.map(clean); + result.failures = failures.map(clean); + result.passes = passes.map(clean); + if (!output) return; + process.stdout.write(JSON.stringify(result, null, 2 )); + }); +} + +/** + * Map jscoverage data to a JSON structure + * suitable for reporting. + * + * @param {Object} cov + * @return {Object} + * @api private + */ + +function map(cov) { + var ret = { + instrumentation: 'node-jscoverage' + , sloc: 0 + , hits: 0 + , misses: 0 + , coverage: 0 + , files: [] + }; + + for (var filename in cov) { + var data = coverage(filename, cov[filename]); + ret.files.push(data); + ret.hits += data.hits; + ret.misses += data.misses; + ret.sloc += data.sloc; + } + + ret.files.sort(function(a, b) { + return a.filename.localeCompare(b.filename); + }); + + if (ret.sloc > 0) { + ret.coverage = (ret.hits / ret.sloc) * 100; + } + + return ret; +} + +/** + * Map jscoverage data for a single source file + * to a JSON structure suitable for reporting. + * + * @param {String} filename name of the source file + * @param {Object} data jscoverage coverage data + * @return {Object} + * @api private + */ + +function coverage(filename, data) { + var ret = { + filename: filename, + coverage: 0, + hits: 0, + misses: 0, + sloc: 0, + source: {} + }; + + data.source.forEach(function(line, num){ + num++; + + if (data[num] === 0) { + ret.misses++; + ret.sloc++; + } else if (data[num] !== undefined) { + ret.hits++; + ret.sloc++; + } + + ret.source[num] = { + source: line + , coverage: data[num] === undefined + ? '' + : data[num] + }; + }); + + ret.coverage = ret.hits / ret.sloc * 100; + + return ret; +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} + +}); // module: reporters/json-cov.js + +require.register("reporters/json-stream.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , total = runner.total; + + runner.on('start', function(){ + console.log(JSON.stringify(['start', { total: total }])); + }); + + runner.on('pass', function(test){ + console.log(JSON.stringify(['pass', clean(test)])); + }); + + runner.on('fail', function(test, err){ + test = clean(test); + test.err = err.message; + console.log(JSON.stringify(['fail', test])); + }); + + runner.on('end', function(){ + process.stdout.write(JSON.stringify(['end', self.stats])); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title + , fullTitle: test.fullTitle() + , duration: test.duration + } +} + +}); // module: reporters/json-stream.js + +require.register("reporters/json.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `JSON`. + */ + +exports = module.exports = JSONReporter; + +/** + * Initialize a new `JSON` reporter. + * + * @param {Runner} runner + * @api public + */ + +function JSONReporter(runner) { + var self = this; + Base.call(this, runner); + + var tests = [] + , pending = [] + , failures = [] + , passes = []; + + runner.on('test end', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + passes.push(test); + }); + + runner.on('fail', function(test){ + failures.push(test); + }); + + runner.on('pending', function(test){ + pending.push(test); + }); + + runner.on('end', function(){ + var obj = { + stats: self.stats, + tests: tests.map(clean), + pending: pending.map(clean), + failures: failures.map(clean), + passes: passes.map(clean) + }; + + runner.testResults = obj; + + process.stdout.write(JSON.stringify(obj, null, 2)); + }); +} + +/** + * Return a plain-object representation of `test` + * free of cyclic properties etc. + * + * @param {Object} test + * @return {Object} + * @api private + */ + +function clean(test) { + return { + title: test.title, + fullTitle: test.fullTitle(), + duration: test.duration, + err: errorJSON(test.err || {}) + } +} + +/** + * Transform `error` into a JSON object. + * @param {Error} err + * @return {Object} + */ + +function errorJSON(err) { + var res = {}; + Object.getOwnPropertyNames(err).forEach(function(key) { + res[key] = err[key]; + }, err); + return res; +} + +}); // module: reporters/json.js + +require.register("reporters/landing.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Landing`. + */ + +exports = module.exports = Landing; + +/** + * Airplane color. + */ + +Base.colors.plane = 0; + +/** + * Airplane crash color. + */ + +Base.colors['plane crash'] = 31; + +/** + * Runway color. + */ + +Base.colors.runway = 90; + +/** + * Initialize a new `Landing` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Landing(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , total = runner.total + , stream = process.stdout + , plane = color('plane', '✈') + , crashed = -1 + , n = 0; + + function runway() { + var buf = Array(width).join('-'); + return ' ' + color('runway', buf); + } + + runner.on('start', function(){ + stream.write('\n\n\n '); + cursor.hide(); + }); + + runner.on('test end', function(test){ + // check if the plane crashed + var col = -1 == crashed + ? width * ++n / total | 0 + : crashed; + + // show the crash + if ('failed' == test.state) { + plane = color('plane crash', '✈'); + crashed = col; + } + + // render landing strip + stream.write('\u001b['+(width+1)+'D\u001b[2A'); + stream.write(runway()); + stream.write('\n '); + stream.write(color('runway', Array(col).join('⋅'))); + stream.write(plane) + stream.write(color('runway', Array(width - col).join('⋅') + '\n')); + stream.write(runway()); + stream.write('\u001b[0m'); + }); + + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Landing.prototype = new F; +Landing.prototype.constructor = Landing; + + +}); // module: reporters/landing.js + +require.register("reporters/list.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `List`. + */ + +exports = module.exports = List; + +/** + * Initialize a new `List` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function List(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , n = 0; + + runner.on('start', function(){ + console.log(); + }); + + runner.on('test', function(test){ + process.stdout.write(color('pass', ' ' + test.fullTitle() + ': ')); + }); + + runner.on('pending', function(test){ + var fmt = color('checkmark', ' -') + + color('pending', ' %s'); + console.log(fmt, test.fullTitle()); + }); + + runner.on('pass', function(test){ + var fmt = color('checkmark', ' '+Base.symbols.dot) + + color('pass', ' %s: ') + + color(test.speed, '%dms'); + cursor.CR(); + console.log(fmt, test.fullTitle(), test.duration); + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(color('fail', ' %d) %s'), ++n, test.fullTitle()); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +List.prototype = new F; +List.prototype.constructor = List; + + +}); // module: reporters/list.js + +require.register("reporters/markdown.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils'); + +/** + * Expose `Markdown`. + */ + +exports = module.exports = Markdown; + +/** + * Initialize a new `Markdown` reporter. + * + * @param {Runner} runner + * @api public + */ + +function Markdown(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , level = 0 + , buf = ''; + + function title(str) { + return Array(level).join('#') + ' ' + str; + } + + function indent() { + return Array(level).join(' '); + } + + function mapTOC(suite, obj) { + var ret = obj; + obj = obj[suite.title] = obj[suite.title] || { suite: suite }; + suite.suites.forEach(function(suite){ + mapTOC(suite, obj); + }); + return ret; + } + + function stringifyTOC(obj, level) { + ++level; + var buf = ''; + var link; + for (var key in obj) { + if ('suite' == key) continue; + if (key) link = ' - [' + key + '](#' + utils.slug(obj[key].suite.fullTitle()) + ')\n'; + if (key) buf += Array(level).join(' ') + link; + buf += stringifyTOC(obj[key], level); + } + --level; + return buf; + } + + function generateTOC(suite) { + var obj = mapTOC(suite, {}); + return stringifyTOC(obj, 0); + } + + generateTOC(runner.suite); + + runner.on('suite', function(suite){ + ++level; + var slug = utils.slug(suite.fullTitle()); + buf += '' + '\n'; + buf += title(suite.title) + '\n'; + }); + + runner.on('suite end', function(suite){ + --level; + }); + + runner.on('pass', function(test){ + var code = utils.clean(test.fn.toString()); + buf += test.title + '.\n'; + buf += '\n```js\n'; + buf += code + '\n'; + buf += '```\n\n'; + }); + + runner.on('end', function(){ + process.stdout.write('# TOC\n'); + process.stdout.write(generateTOC(runner.suite)); + process.stdout.write(buf); + }); +} + +}); // module: reporters/markdown.js + +require.register("reporters/min.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base'); + +/** + * Expose `Min`. + */ + +exports = module.exports = Min; + +/** + * Initialize a new `Min` minimal test reporter (best used with --watch). + * + * @param {Runner} runner + * @api public + */ + +function Min(runner) { + Base.call(this, runner); + + runner.on('start', function(){ + // clear screen + process.stdout.write('\u001b[2J'); + // set cursor position + process.stdout.write('\u001b[1;3H'); + }); + + runner.on('end', this.epilogue.bind(this)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Min.prototype = new F; +Min.prototype.constructor = Min; + + +}); // module: reporters/min.js + +require.register("reporters/nyan.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , color = Base.color; + +/** + * Expose `Dot`. + */ + +exports = module.exports = NyanCat; + +/** + * Initialize a new `Dot` matrix test reporter. + * + * @param {Runner} runner + * @api public + */ + +function NyanCat(runner) { + Base.call(this, runner); + var self = this + , stats = this.stats + , width = Base.window.width * .75 | 0 + , rainbowColors = this.rainbowColors = self.generateColors() + , colorIndex = this.colorIndex = 0 + , numerOfLines = this.numberOfLines = 4 + , trajectories = this.trajectories = [[], [], [], []] + , nyanCatWidth = this.nyanCatWidth = 11 + , trajectoryWidthMax = this.trajectoryWidthMax = (width - nyanCatWidth) + , scoreboardWidth = this.scoreboardWidth = 5 + , tick = this.tick = 0 + , n = 0; + + runner.on('start', function(){ + Base.cursor.hide(); + self.draw(); + }); + + runner.on('pending', function(test){ + self.draw(); + }); + + runner.on('pass', function(test){ + self.draw(); + }); + + runner.on('fail', function(test, err){ + self.draw(); + }); + + runner.on('end', function(){ + Base.cursor.show(); + for (var i = 0; i < self.numberOfLines; i++) write('\n'); + self.epilogue(); + }); +} + +/** + * Draw the nyan cat + * + * @api private + */ + +NyanCat.prototype.draw = function(){ + this.appendRainbow(); + this.drawScoreboard(); + this.drawRainbow(); + this.drawNyanCat(); + this.tick = !this.tick; +}; + +/** + * Draw the "scoreboard" showing the number + * of passes, failures and pending tests. + * + * @api private + */ + +NyanCat.prototype.drawScoreboard = function(){ + var stats = this.stats; + var colors = Base.colors; + + function draw(color, n) { + write(' '); + write('\u001b[' + color + 'm' + n + '\u001b[0m'); + write('\n'); + } + + draw(colors.green, stats.passes); + draw(colors.fail, stats.failures); + draw(colors.pending, stats.pending); + write('\n'); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Append the rainbow. + * + * @api private + */ + +NyanCat.prototype.appendRainbow = function(){ + var segment = this.tick ? '_' : '-'; + var rainbowified = this.rainbowify(segment); + + for (var index = 0; index < this.numberOfLines; index++) { + var trajectory = this.trajectories[index]; + if (trajectory.length >= this.trajectoryWidthMax) trajectory.shift(); + trajectory.push(rainbowified); + } +}; + +/** + * Draw the rainbow. + * + * @api private + */ + +NyanCat.prototype.drawRainbow = function(){ + var self = this; + + this.trajectories.forEach(function(line, index) { + write('\u001b[' + self.scoreboardWidth + 'C'); + write(line.join('')); + write('\n'); + }); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Draw the nyan cat + * + * @api private + */ + +NyanCat.prototype.drawNyanCat = function() { + var self = this; + var startWidth = this.scoreboardWidth + this.trajectories[0].length; + var color = '\u001b[' + startWidth + 'C'; + var padding = ''; + + write(color); + write('_,------,'); + write('\n'); + + write(color); + padding = self.tick ? ' ' : ' '; + write('_|' + padding + '/\\_/\\ '); + write('\n'); + + write(color); + padding = self.tick ? '_' : '__'; + var tail = self.tick ? '~' : '^'; + var face; + write(tail + '|' + padding + this.face() + ' '); + write('\n'); + + write(color); + padding = self.tick ? ' ' : ' '; + write(padding + '"" "" '); + write('\n'); + + this.cursorUp(this.numberOfLines); +}; + +/** + * Draw nyan cat face. + * + * @return {String} + * @api private + */ + +NyanCat.prototype.face = function() { + var stats = this.stats; + if (stats.failures) { + return '( x .x)'; + } else if (stats.pending) { + return '( o .o)'; + } else if(stats.passes) { + return '( ^ .^)'; + } else { + return '( - .-)'; + } +}; + +/** + * Move cursor up `n`. + * + * @param {Number} n + * @api private + */ + +NyanCat.prototype.cursorUp = function(n) { + write('\u001b[' + n + 'A'); +}; + +/** + * Move cursor down `n`. + * + * @param {Number} n + * @api private + */ + +NyanCat.prototype.cursorDown = function(n) { + write('\u001b[' + n + 'B'); +}; + +/** + * Generate rainbow colors. + * + * @return {Array} + * @api private + */ + +NyanCat.prototype.generateColors = function(){ + var colors = []; + + for (var i = 0; i < (6 * 7); i++) { + var pi3 = Math.floor(Math.PI / 3); + var n = (i * (1.0 / 6)); + var r = Math.floor(3 * Math.sin(n) + 3); + var g = Math.floor(3 * Math.sin(n + 2 * pi3) + 3); + var b = Math.floor(3 * Math.sin(n + 4 * pi3) + 3); + colors.push(36 * r + 6 * g + b + 16); + } + + return colors; +}; + +/** + * Apply rainbow to the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +NyanCat.prototype.rainbowify = function(str){ + var color = this.rainbowColors[this.colorIndex % this.rainbowColors.length]; + this.colorIndex += 1; + return '\u001b[38;5;' + color + 'm' + str + '\u001b[0m'; +}; + +/** + * Stdout helper. + */ + +function write(string) { + process.stdout.write(string); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +NyanCat.prototype = new F; +NyanCat.prototype.constructor = NyanCat; + + +}); // module: reporters/nyan.js + +require.register("reporters/progress.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Progress`. + */ + +exports = module.exports = Progress; + +/** + * General progress bar color. + */ + +Base.colors.progress = 90; + +/** + * Initialize a new `Progress` bar test reporter. + * + * @param {Runner} runner + * @param {Object} options + * @api public + */ + +function Progress(runner, options) { + Base.call(this, runner); + + var self = this + , options = options || {} + , stats = this.stats + , width = Base.window.width * .50 | 0 + , total = runner.total + , complete = 0 + , max = Math.max + , lastN = -1; + + // default chars + options.open = options.open || '['; + options.complete = options.complete || '▬'; + options.incomplete = options.incomplete || Base.symbols.dot; + options.close = options.close || ']'; + options.verbose = false; + + // tests started + runner.on('start', function(){ + console.log(); + cursor.hide(); + }); + + // tests complete + runner.on('test end', function(){ + complete++; + var incomplete = total - complete + , percent = complete / total + , n = width * percent | 0 + , i = width - n; + + if (lastN === n && !options.verbose) { + // Don't re-render the line if it hasn't changed + return; + } + lastN = n; + + cursor.CR(); + process.stdout.write('\u001b[J'); + process.stdout.write(color('progress', ' ' + options.open)); + process.stdout.write(Array(n).join(options.complete)); + process.stdout.write(Array(i).join(options.incomplete)); + process.stdout.write(color('progress', options.close)); + if (options.verbose) { + process.stdout.write(color('progress', ' ' + complete + ' of ' + total)); + } + }); + + // tests are complete, output some stats + // and the failures if any + runner.on('end', function(){ + cursor.show(); + console.log(); + self.epilogue(); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Progress.prototype = new F; +Progress.prototype.constructor = Progress; + + +}); // module: reporters/progress.js + +require.register("reporters/spec.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `Spec`. + */ + +exports = module.exports = Spec; + +/** + * Initialize a new `Spec` test reporter. + * + * @param {Runner} runner + * @api public + */ + +function Spec(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , indents = 0 + , n = 0; + + function indent() { + return Array(indents).join(' ') + } + + runner.on('start', function(){ + console.log(); + }); + + runner.on('suite', function(suite){ + ++indents; + console.log(color('suite', '%s%s'), indent(), suite.title); + }); + + runner.on('suite end', function(suite){ + --indents; + if (1 == indents) console.log(); + }); + + runner.on('pending', function(test){ + var fmt = indent() + color('pending', ' - %s'); + console.log(fmt, test.title); + }); + + runner.on('pass', function(test){ + if ('fast' == test.speed) { + var fmt = indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s '); + cursor.CR(); + console.log(fmt, test.title); + } else { + var fmt = indent() + + color('checkmark', ' ' + Base.symbols.ok) + + color('pass', ' %s ') + + color(test.speed, '(%dms)'); + cursor.CR(); + console.log(fmt, test.title, test.duration); + } + }); + + runner.on('fail', function(test, err){ + cursor.CR(); + console.log(indent() + color('fail', ' %d) %s'), ++n, test.title); + }); + + runner.on('end', self.epilogue.bind(self)); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +Spec.prototype = new F; +Spec.prototype.constructor = Spec; + + +}); // module: reporters/spec.js + +require.register("reporters/tap.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , cursor = Base.cursor + , color = Base.color; + +/** + * Expose `TAP`. + */ + +exports = module.exports = TAP; + +/** + * Initialize a new `TAP` reporter. + * + * @param {Runner} runner + * @api public + */ + +function TAP(runner) { + Base.call(this, runner); + + var self = this + , stats = this.stats + , n = 1 + , passes = 0 + , failures = 0; + + runner.on('start', function(){ + var total = runner.grepTotal(runner.suite); + console.log('%d..%d', 1, total); + }); + + runner.on('test end', function(){ + ++n; + }); + + runner.on('pending', function(test){ + console.log('ok %d %s # SKIP -', n, title(test)); + }); + + runner.on('pass', function(test){ + passes++; + console.log('ok %d %s', n, title(test)); + }); + + runner.on('fail', function(test, err){ + failures++; + console.log('not ok %d %s', n, title(test)); + if (err.stack) console.log(err.stack.replace(/^/gm, ' ')); + }); + + runner.on('end', function(){ + console.log('# tests ' + (passes + failures)); + console.log('# pass ' + passes); + console.log('# fail ' + failures); + }); +} + +/** + * Return a TAP-safe title of `test` + * + * @param {Object} test + * @return {String} + * @api private + */ + +function title(test) { + return test.fullTitle().replace(/#/g, ''); +} + +}); // module: reporters/tap.js + +require.register("reporters/xunit.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Base = require('./base') + , utils = require('../utils') + , escape = utils.escape; + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Expose `XUnit`. + */ + +exports = module.exports = XUnit; + +/** + * Initialize a new `XUnit` reporter. + * + * @param {Runner} runner + * @api public + */ + +function XUnit(runner) { + Base.call(this, runner); + var stats = this.stats + , tests = [] + , self = this; + + runner.on('pending', function(test){ + tests.push(test); + }); + + runner.on('pass', function(test){ + tests.push(test); + }); + + runner.on('fail', function(test){ + tests.push(test); + }); + + runner.on('end', function(){ + console.log(tag('testsuite', { + name: 'Mocha Tests' + , tests: stats.tests + , failures: stats.failures + , errors: stats.failures + , skipped: stats.tests - stats.failures - stats.passes + , timestamp: (new Date).toUTCString() + , time: (stats.duration / 1000) || 0 + }, false)); + + tests.forEach(test); + console.log(''); + }); +} + +/** + * Inherit from `Base.prototype`. + */ + +function F(){}; +F.prototype = Base.prototype; +XUnit.prototype = new F; +XUnit.prototype.constructor = XUnit; + + +/** + * Output tag for the given `test.` + */ + +function test(test) { + var attrs = { + classname: test.parent.fullTitle() + , name: test.title + , time: (test.duration / 1000) || 0 + }; + + if ('failed' == test.state) { + var err = test.err; + console.log(tag('testcase', attrs, false, tag('failure', {}, false, cdata(escape(err.message) + "\n" + err.stack)))); + } else if (test.pending) { + console.log(tag('testcase', attrs, false, tag('skipped', {}, true))); + } else { + console.log(tag('testcase', attrs, true) ); + } +} + +/** + * HTML tag helper. + */ + +function tag(name, attrs, close, content) { + var end = close ? '/>' : '>' + , pairs = [] + , tag; + + for (var key in attrs) { + pairs.push(key + '="' + escape(attrs[key]) + '"'); + } + + tag = '<' + name + (pairs.length ? ' ' + pairs.join(' ') : '') + end; + if (content) tag += content + ''; +} + +}); // module: reporters/xunit.js + +require.register("runnable.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:runnable') + , milliseconds = require('./ms'); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date + , setTimeout = global.setTimeout + , setInterval = global.setInterval + , clearTimeout = global.clearTimeout + , clearInterval = global.clearInterval; + +/** + * Object#toString(). + */ + +var toString = Object.prototype.toString; + +/** + * Expose `Runnable`. + */ + +module.exports = Runnable; + +/** + * Initialize a new `Runnable` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Runnable(title, fn) { + this.title = title; + this.fn = fn; + this.async = fn && fn.length; + this.sync = ! this.async; + this._timeout = 2000; + this._slow = 75; + this._enableTimeouts = true; + this.timedOut = false; + this._trace = new Error('done() called multiple times') +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Runnable.prototype = new F; +Runnable.prototype.constructor = Runnable; + + +/** + * Set & get timeout `ms`. + * + * @param {Number|String} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if (ms === 0) this._enableTimeouts = false; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._timeout = ms; + if (this.timer) this.resetTimeout(); + return this; +}; + +/** + * Set & get slow `ms`. + * + * @param {Number|String} ms + * @return {Runnable|Number} ms or self + * @api private + */ + +Runnable.prototype.slow = function(ms){ + if (0 === arguments.length) return this._slow; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._slow = ms; + return this; +}; + +/** + * Set and & get timeout `enabled`. + * + * @param {Boolean} enabled + * @return {Runnable|Boolean} enabled or self + * @api private + */ + +Runnable.prototype.enableTimeouts = function(enabled){ + if (arguments.length === 0) return this._enableTimeouts; + debug('enableTimeouts %s', enabled); + this._enableTimeouts = enabled; + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Runnable.prototype.fullTitle = function(){ + return this.parent.fullTitle() + ' ' + this.title; +}; + +/** + * Clear the timeout. + * + * @api private + */ + +Runnable.prototype.clearTimeout = function(){ + clearTimeout(this.timer); +}; + +/** + * Inspect the runnable void of private properties. + * + * @return {String} + * @api private + */ + +Runnable.prototype.inspect = function(){ + return JSON.stringify(this, function(key, val){ + if ('_' == key[0]) return; + if ('parent' == key) return '#'; + if ('ctx' == key) return '#'; + return val; + }, 2); +}; + +/** + * Reset the timeout. + * + * @api private + */ + +Runnable.prototype.resetTimeout = function(){ + var self = this; + var ms = this.timeout() || 1e9; + + if (!this._enableTimeouts) return; + this.clearTimeout(); + this.timer = setTimeout(function(){ + if (!self._enableTimeouts) return; + self.callback(new Error('timeout of ' + ms + 'ms exceeded')); + self.timedOut = true; + }, ms); +}; + +/** + * Whitelist these globals for this test run + * + * @api private + */ +Runnable.prototype.globals = function(arr){ + var self = this; + this._allowedGlobals = arr; +}; + +/** + * Run the test and invoke `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runnable.prototype.run = function(fn){ + var self = this + , start = new Date + , ctx = this.ctx + , finished + , emitted; + + // Some times the ctx exists but it is not runnable + if (ctx && ctx.runnable) ctx.runnable(this); + + // called multiple times + function multiple(err) { + if (emitted) return; + emitted = true; + self.emit('error', err || new Error('done() called multiple times; stacktrace may be inaccurate')); + } + + // finished + function done(err) { + var ms = self.timeout(); + if (self.timedOut) return; + if (finished) return multiple(err || self._trace); + self.clearTimeout(); + self.duration = new Date - start; + finished = true; + if (!err && self.duration > ms && self._enableTimeouts) err = new Error('timeout of ' + ms + 'ms exceeded'); + fn(err); + } + + // for .resetTimeout() + this.callback = done; + + // explicit async with `done` argument + if (this.async) { + this.resetTimeout(); + + try { + this.fn.call(ctx, function(err){ + if (err instanceof Error || toString.call(err) === "[object Error]") return done(err); + if (null != err) { + if (Object.prototype.toString.call(err) === '[object Object]') { + return done(new Error('done() invoked with non-Error: ' + JSON.stringify(err))); + } else { + return done(new Error('done() invoked with non-Error: ' + err)); + } + } + done(); + }); + } catch (err) { + done(err); + } + return; + } + + if (this.asyncOnly) { + return done(new Error('--async-only option in use without declaring `done()`')); + } + + // sync or promise-returning + try { + if (this.pending) { + done(); + } else { + callFn(this.fn); + } + } catch (err) { + done(err); + } + + function callFn(fn) { + var result = fn.call(ctx); + if (result && typeof result.then === 'function') { + self.resetTimeout(); + result + .then(function() { + done() + }, + function(reason) { + done(reason || new Error('Promise rejected with no or falsy reason')) + }); + } else { + done(); + } + } +}; + +}); // module: runnable.js + +require.register("runner.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:runner') + , Test = require('./test') + , utils = require('./utils') + , filter = utils.filter + , keys = utils.keys; + +/** + * Non-enumerable globals. + */ + +var globals = [ + 'setTimeout', + 'clearTimeout', + 'setInterval', + 'clearInterval', + 'XMLHttpRequest', + 'Date' +]; + +/** + * Expose `Runner`. + */ + +module.exports = Runner; + +/** + * Initialize a `Runner` for the given `suite`. + * + * Events: + * + * - `start` execution started + * - `end` execution complete + * - `suite` (suite) test suite execution started + * - `suite end` (suite) all tests (and sub-suites) have finished + * - `test` (test) test execution started + * - `test end` (test) test completed + * - `hook` (hook) hook execution started + * - `hook end` (hook) hook complete + * - `pass` (test) test passed + * - `fail` (test, err) test failed + * - `pending` (test) test pending + * + * @api public + */ + +function Runner(suite) { + var self = this; + this._globals = []; + this._abort = false; + this.suite = suite; + this.total = suite.total(); + this.failures = 0; + this.on('test end', function(test){ self.checkGlobals(test); }); + this.on('hook end', function(hook){ self.checkGlobals(hook); }); + this.grep(/.*/); + this.globals(this.globalProps().concat(extraGlobals())); +} + +/** + * Wrapper for setImmediate, process.nextTick, or browser polyfill. + * + * @param {Function} fn + * @api private + */ + +Runner.immediately = global.setImmediate || process.nextTick; + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Runner.prototype = new F; +Runner.prototype.constructor = Runner; + + +/** + * Run tests with full titles matching `re`. Updates runner.total + * with number of tests matched. + * + * @param {RegExp} re + * @param {Boolean} invert + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.grep = function(re, invert){ + debug('grep %s', re); + this._grep = re; + this._invert = invert; + this.total = this.grepTotal(this.suite); + return this; +}; + +/** + * Returns the number of tests matching the grep search for the + * given suite. + * + * @param {Suite} suite + * @return {Number} + * @api public + */ + +Runner.prototype.grepTotal = function(suite) { + var self = this; + var total = 0; + + suite.eachTest(function(test){ + var match = self._grep.test(test.fullTitle()); + if (self._invert) match = !match; + if (match) total++; + }); + + return total; +}; + +/** + * Return a list of global properties. + * + * @return {Array} + * @api private + */ + +Runner.prototype.globalProps = function() { + var props = utils.keys(global); + + // non-enumerables + for (var i = 0; i < globals.length; ++i) { + if (~utils.indexOf(props, globals[i])) continue; + props.push(globals[i]); + } + + return props; +}; + +/** + * Allow the given `arr` of globals. + * + * @param {Array} arr + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.globals = function(arr){ + if (0 == arguments.length) return this._globals; + debug('globals %j', arr); + this._globals = this._globals.concat(arr); + return this; +}; + +/** + * Check for global variable leaks. + * + * @api private + */ + +Runner.prototype.checkGlobals = function(test){ + if (this.ignoreLeaks) return; + var ok = this._globals; + + var globals = this.globalProps(); + var leaks; + + if (test) { + ok = ok.concat(test._allowedGlobals || []); + } + + if(this.prevGlobalsLength == globals.length) return; + this.prevGlobalsLength = globals.length; + + leaks = filterLeaks(ok, globals); + this._globals = this._globals.concat(leaks); + + if (leaks.length > 1) { + this.fail(test, new Error('global leaks detected: ' + leaks.join(', ') + '')); + } else if (leaks.length) { + this.fail(test, new Error('global leak detected: ' + leaks[0])); + } +}; + +/** + * Fail the given `test`. + * + * @param {Test} test + * @param {Error} err + * @api private + */ + +Runner.prototype.fail = function(test, err){ + ++this.failures; + test.state = 'failed'; + + if ('string' == typeof err) { + err = new Error('the string "' + err + '" was thrown, throw an Error :)'); + } + + this.emit('fail', test, err); +}; + +/** + * Fail the given `hook` with `err`. + * + * Hook failures work in the following pattern: + * - If bail, then exit + * - Failed `before` hook skips all tests in a suite and subsuites, + * but jumps to corresponding `after` hook + * - Failed `before each` hook skips remaining tests in a + * suite and jumps to corresponding `after each` hook, + * which is run only once + * - Failed `after` hook does not alter + * execution order + * - Failed `after each` hook skips remaining tests in a + * suite and subsuites, but executes other `after each` + * hooks + * + * @param {Hook} hook + * @param {Error} err + * @api private + */ + +Runner.prototype.failHook = function(hook, err){ + this.fail(hook, err); + if (this.suite.bail()) { + this.emit('end'); + } +}; + +/** + * Run hook `name` callbacks and then invoke `fn()`. + * + * @param {String} name + * @param {Function} function + * @api private + */ + +Runner.prototype.hook = function(name, fn){ + var suite = this.suite + , hooks = suite['_' + name] + , self = this + , timer; + + function next(i) { + var hook = hooks[i]; + if (!hook) return fn(); + if (self.failures && suite.bail()) return fn(); + self.currentRunnable = hook; + + hook.ctx.currentTest = self.test; + + self.emit('hook', hook); + + hook.on('error', function(err){ + self.failHook(hook, err); + }); + + hook.run(function(err){ + hook.removeAllListeners('error'); + var testError = hook.error(); + if (testError) self.fail(self.test, testError); + if (err) { + self.failHook(hook, err); + + // stop executing hooks, notify callee of hook err + return fn(err); + } + self.emit('hook end', hook); + delete hook.ctx.currentTest; + next(++i); + }); + } + + Runner.immediately(function(){ + next(0); + }); +}; + +/** + * Run hook `name` for the given array of `suites` + * in order, and callback `fn(err, errSuite)`. + * + * @param {String} name + * @param {Array} suites + * @param {Function} fn + * @api private + */ + +Runner.prototype.hooks = function(name, suites, fn){ + var self = this + , orig = this.suite; + + function next(suite) { + self.suite = suite; + + if (!suite) { + self.suite = orig; + return fn(); + } + + self.hook(name, function(err){ + if (err) { + var errSuite = self.suite; + self.suite = orig; + return fn(err, errSuite); + } + + next(suites.pop()); + }); + } + + next(suites.pop()); +}; + +/** + * Run hooks from the top level down. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookUp = function(name, fn){ + var suites = [this.suite].concat(this.parents()).reverse(); + this.hooks(name, suites, fn); +}; + +/** + * Run hooks from the bottom up. + * + * @param {String} name + * @param {Function} fn + * @api private + */ + +Runner.prototype.hookDown = function(name, fn){ + var suites = [this.suite].concat(this.parents()); + this.hooks(name, suites, fn); +}; + +/** + * Return an array of parent Suites from + * closest to furthest. + * + * @return {Array} + * @api private + */ + +Runner.prototype.parents = function(){ + var suite = this.suite + , suites = []; + while (suite = suite.parent) suites.push(suite); + return suites; +}; + +/** + * Run the current test and callback `fn(err)`. + * + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTest = function(fn){ + var test = this.test + , self = this; + + if (this.asyncOnly) test.asyncOnly = true; + + try { + test.on('error', function(err){ + self.fail(test, err); + }); + test.run(fn); + } catch (err) { + fn(err); + } +}; + +/** + * Run tests in the given `suite` and invoke + * the callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runTests = function(suite, fn){ + var self = this + , tests = suite.tests.slice() + , test; + + + function hookErr(err, errSuite, after) { + // before/after Each hook for errSuite failed: + var orig = self.suite; + + // for failed 'after each' hook start from errSuite parent, + // otherwise start from errSuite itself + self.suite = after ? errSuite.parent : errSuite; + + if (self.suite) { + // call hookUp afterEach + self.hookUp('afterEach', function(err2, errSuite2) { + self.suite = orig; + // some hooks may fail even now + if (err2) return hookErr(err2, errSuite2, true); + // report error suite + fn(errSuite); + }); + } else { + // there is no need calling other 'after each' hooks + self.suite = orig; + fn(errSuite); + } + } + + function next(err, errSuite) { + // if we bail after first err + if (self.failures && suite._bail) return fn(); + + if (self._abort) return fn(); + + if (err) return hookErr(err, errSuite, true); + + // next test + test = tests.shift(); + + // all done + if (!test) return fn(); + + // grep + var match = self._grep.test(test.fullTitle()); + if (self._invert) match = !match; + if (!match) return next(); + + // pending + if (test.pending) { + self.emit('pending', test); + self.emit('test end', test); + return next(); + } + + // execute test and hook(s) + self.emit('test', self.test = test); + self.hookDown('beforeEach', function(err, errSuite){ + + if (err) return hookErr(err, errSuite, false); + + self.currentRunnable = self.test; + self.runTest(function(err){ + test = self.test; + + if (err) { + self.fail(test, err); + self.emit('test end', test); + return self.hookUp('afterEach', next); + } + + test.state = 'passed'; + self.emit('pass', test); + self.emit('test end', test); + self.hookUp('afterEach', next); + }); + }); + } + + this.next = next; + next(); +}; + +/** + * Run the given `suite` and invoke the + * callback `fn()` when complete. + * + * @param {Suite} suite + * @param {Function} fn + * @api private + */ + +Runner.prototype.runSuite = function(suite, fn){ + var total = this.grepTotal(suite) + , self = this + , i = 0; + + debug('run suite %s', suite.fullTitle()); + + if (!total) return fn(); + + this.emit('suite', this.suite = suite); + + function next(errSuite) { + if (errSuite) { + // current suite failed on a hook from errSuite + if (errSuite == suite) { + // if errSuite is current suite + // continue to the next sibling suite + return done(); + } else { + // errSuite is among the parents of current suite + // stop execution of errSuite and all sub-suites + return done(errSuite); + } + } + + if (self._abort) return done(); + + var curr = suite.suites[i++]; + if (!curr) return done(); + self.runSuite(curr, next); + } + + function done(errSuite) { + self.suite = suite; + self.hook('afterAll', function(){ + self.emit('suite end', suite); + fn(errSuite); + }); + } + + this.hook('beforeAll', function(err){ + if (err) return done(); + self.runTests(suite, next); + }); +}; + +/** + * Handle uncaught exceptions. + * + * @param {Error} err + * @api private + */ + +Runner.prototype.uncaught = function(err){ + if (err) { + debug('uncaught exception %s', err !== function () { + return this; + }.call(err) ? err : ( err.message || err )); + } else { + debug('uncaught undefined exception'); + err = new Error('Caught undefined error, did you throw without specifying what?'); + } + err.uncaught = true; + + var runnable = this.currentRunnable; + if (!runnable) return; + + var wasAlreadyDone = runnable.state; + this.fail(runnable, err); + + runnable.clearTimeout(); + + if (wasAlreadyDone) return; + + // recover from test + if ('test' == runnable.type) { + this.emit('test end', runnable); + this.hookUp('afterEach', this.next); + return; + } + + // bail on hooks + this.emit('end'); +}; + +/** + * Run the root suite and invoke `fn(failures)` + * on completion. + * + * @param {Function} fn + * @return {Runner} for chaining + * @api public + */ + +Runner.prototype.run = function(fn){ + var self = this + , fn = fn || function(){}; + + function uncaught(err){ + self.uncaught(err); + } + + debug('start'); + + // callback + this.on('end', function(){ + debug('end'); + process.removeListener('uncaughtException', uncaught); + fn(self.failures); + }); + + // run suites + this.emit('start'); + this.runSuite(this.suite, function(){ + debug('finished running'); + self.emit('end'); + }); + + // uncaught exception + process.on('uncaughtException', uncaught); + + return this; +}; + +/** + * Cleanly abort execution + * + * @return {Runner} for chaining + * @api public + */ +Runner.prototype.abort = function(){ + debug('aborting'); + this._abort = true; +}; + +/** + * Filter leaks with the given globals flagged as `ok`. + * + * @param {Array} ok + * @param {Array} globals + * @return {Array} + * @api private + */ + +function filterLeaks(ok, globals) { + return filter(globals, function(key){ + // Firefox and Chrome exposes iframes as index inside the window object + if (/^d+/.test(key)) return false; + + // in firefox + // if runner runs in an iframe, this iframe's window.getInterface method not init at first + // it is assigned in some seconds + if (global.navigator && /^getInterface/.test(key)) return false; + + // an iframe could be approached by window[iframeIndex] + // in ie6,7,8 and opera, iframeIndex is enumerable, this could cause leak + if (global.navigator && /^\d+/.test(key)) return false; + + // Opera and IE expose global variables for HTML element IDs (issue #243) + if (/^mocha-/.test(key)) return false; + + var matched = filter(ok, function(ok){ + if (~ok.indexOf('*')) return 0 == key.indexOf(ok.split('*')[0]); + return key == ok; + }); + return matched.length == 0 && (!global.navigator || 'onerror' !== key); + }); +} + +/** + * Array of globals dependent on the environment. + * + * @return {Array} + * @api private + */ + + function extraGlobals() { + if (typeof(process) === 'object' && + typeof(process.version) === 'string') { + + var nodeVersion = process.version.split('.').reduce(function(a, v) { + return a << 8 | v; + }); + + // 'errno' was renamed to process._errno in v0.9.11. + + if (nodeVersion < 0x00090B) { + return ['errno']; + } + } + + return []; + } + +}); // module: runner.js + +require.register("suite.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var EventEmitter = require('browser/events').EventEmitter + , debug = require('browser/debug')('mocha:suite') + , milliseconds = require('./ms') + , utils = require('./utils') + , Hook = require('./hook'); + +/** + * Expose `Suite`. + */ + +exports = module.exports = Suite; + +/** + * Create a new `Suite` with the given `title` + * and parent `Suite`. When a suite with the + * same title is already present, that suite + * is returned to provide nicer reporter + * and more flexible meta-testing. + * + * @param {Suite} parent + * @param {String} title + * @return {Suite} + * @api public + */ + +exports.create = function(parent, title){ + var suite = new Suite(title, parent.ctx); + suite.parent = parent; + if (parent.pending) suite.pending = true; + title = suite.fullTitle(); + parent.addSuite(suite); + return suite; +}; + +/** + * Initialize a new `Suite` with the given + * `title` and `ctx`. + * + * @param {String} title + * @param {Context} ctx + * @api private + */ + +function Suite(title, parentContext) { + this.title = title; + var context = function() {}; + context.prototype = parentContext; + this.ctx = new context(); + this.suites = []; + this.tests = []; + this.pending = false; + this._beforeEach = []; + this._beforeAll = []; + this._afterEach = []; + this._afterAll = []; + this.root = !title; + this._timeout = 2000; + this._enableTimeouts = true; + this._slow = 75; + this._bail = false; +} + +/** + * Inherit from `EventEmitter.prototype`. + */ + +function F(){}; +F.prototype = EventEmitter.prototype; +Suite.prototype = new F; +Suite.prototype.constructor = Suite; + + +/** + * Return a clone of this `Suite`. + * + * @return {Suite} + * @api private + */ + +Suite.prototype.clone = function(){ + var suite = new Suite(this.title); + debug('clone'); + suite.ctx = this.ctx; + suite.timeout(this.timeout()); + suite.enableTimeouts(this.enableTimeouts()); + suite.slow(this.slow()); + suite.bail(this.bail()); + return suite; +}; + +/** + * Set timeout `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.timeout = function(ms){ + if (0 == arguments.length) return this._timeout; + if (ms === 0) this._enableTimeouts = false; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('timeout %d', ms); + this._timeout = parseInt(ms, 10); + return this; +}; + +/** + * Set timeout `enabled`. + * + * @param {Boolean} enabled + * @return {Suite|Boolean} self or enabled + * @api private + */ + +Suite.prototype.enableTimeouts = function(enabled){ + if (arguments.length === 0) return this._enableTimeouts; + debug('enableTimeouts %s', enabled); + this._enableTimeouts = enabled; + return this; +}; + +/** + * Set slow `ms` or short-hand such as "2s". + * + * @param {Number|String} ms + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.slow = function(ms){ + if (0 === arguments.length) return this._slow; + if ('string' == typeof ms) ms = milliseconds(ms); + debug('slow %d', ms); + this._slow = ms; + return this; +}; + +/** + * Sets whether to bail after first error. + * + * @parma {Boolean} bail + * @return {Suite|Number} for chaining + * @api private + */ + +Suite.prototype.bail = function(bail){ + if (0 == arguments.length) return this._bail; + debug('bail %s', bail); + this._bail = bail; + return this; +}; + +/** + * Run `fn(test[, done])` before running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeAll = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"before all" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.enableTimeouts(this.enableTimeouts()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._beforeAll.push(hook); + this.emit('beforeAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after running tests. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterAll = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"after all" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.enableTimeouts(this.enableTimeouts()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._afterAll.push(hook); + this.emit('afterAll', hook); + return this; +}; + +/** + * Run `fn(test[, done])` before each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.beforeEach = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"before each" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.enableTimeouts(this.enableTimeouts()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._beforeEach.push(hook); + this.emit('beforeEach', hook); + return this; +}; + +/** + * Run `fn(test[, done])` after each test case. + * + * @param {Function} fn + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.afterEach = function(title, fn){ + if (this.pending) return this; + if ('function' === typeof title) { + fn = title; + title = fn.name; + } + title = '"after each" hook' + (title ? ': ' + title : ''); + + var hook = new Hook(title, fn); + hook.parent = this; + hook.timeout(this.timeout()); + hook.enableTimeouts(this.enableTimeouts()); + hook.slow(this.slow()); + hook.ctx = this.ctx; + this._afterEach.push(hook); + this.emit('afterEach', hook); + return this; +}; + +/** + * Add a test `suite`. + * + * @param {Suite} suite + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addSuite = function(suite){ + suite.parent = this; + suite.timeout(this.timeout()); + suite.enableTimeouts(this.enableTimeouts()); + suite.slow(this.slow()); + suite.bail(this.bail()); + this.suites.push(suite); + this.emit('suite', suite); + return this; +}; + +/** + * Add a `test` to this suite. + * + * @param {Test} test + * @return {Suite} for chaining + * @api private + */ + +Suite.prototype.addTest = function(test){ + test.parent = this; + test.timeout(this.timeout()); + test.enableTimeouts(this.enableTimeouts()); + test.slow(this.slow()); + test.ctx = this.ctx; + this.tests.push(test); + this.emit('test', test); + return this; +}; + +/** + * Return the full title generated by recursively + * concatenating the parent's full title. + * + * @return {String} + * @api public + */ + +Suite.prototype.fullTitle = function(){ + if (this.parent) { + var full = this.parent.fullTitle(); + if (full) return full + ' ' + this.title; + } + return this.title; +}; + +/** + * Return the total number of tests. + * + * @return {Number} + * @api public + */ + +Suite.prototype.total = function(){ + return utils.reduce(this.suites, function(sum, suite){ + return sum + suite.total(); + }, 0) + this.tests.length; +}; + +/** + * Iterates through each suite recursively to find + * all tests. Applies a function in the format + * `fn(test)`. + * + * @param {Function} fn + * @return {Suite} + * @api private + */ + +Suite.prototype.eachTest = function(fn){ + utils.forEach(this.tests, fn); + utils.forEach(this.suites, function(suite){ + suite.eachTest(fn); + }); + return this; +}; + +}); // module: suite.js + +require.register("test.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var Runnable = require('./runnable'); + +/** + * Expose `Test`. + */ + +module.exports = Test; + +/** + * Initialize a new `Test` with the given `title` and callback `fn`. + * + * @param {String} title + * @param {Function} fn + * @api private + */ + +function Test(title, fn) { + Runnable.call(this, title, fn); + this.pending = !fn; + this.type = 'test'; +} + +/** + * Inherit from `Runnable.prototype`. + */ + +function F(){}; +F.prototype = Runnable.prototype; +Test.prototype = new F; +Test.prototype.constructor = Test; + + +}); // module: test.js + +require.register("utils.js", function(module, exports, require){ +/** + * Module dependencies. + */ + +var fs = require('browser/fs') + , path = require('browser/path') + , basename = path.basename + , exists = fs.existsSync || path.existsSync + , glob = require('browser/glob') + , join = path.join + , debug = require('browser/debug')('mocha:watch'); + +/** + * Ignored directories. + */ + +var ignore = ['node_modules', '.git']; + +/** + * Escape special characters in the given string of html. + * + * @param {String} html + * @return {String} + * @api private + */ + +exports.escape = function(html){ + return String(html) + .replace(/&/g, '&') + .replace(/"/g, '"') + .replace(//g, '>'); +}; + +/** + * Array#forEach (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.forEach = function(arr, fn, scope){ + for (var i = 0, l = arr.length; i < l; i++) + fn.call(scope, arr[i], i); +}; + +/** + * Array#map (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} scope + * @api private + */ + +exports.map = function(arr, fn, scope){ + var result = []; + for (var i = 0, l = arr.length; i < l; i++) + result.push(fn.call(scope, arr[i], i)); + return result; +}; + +/** + * Array#indexOf (<=IE8) + * + * @parma {Array} arr + * @param {Object} obj to find index of + * @param {Number} start + * @api private + */ + +exports.indexOf = function(arr, obj, start){ + for (var i = start || 0, l = arr.length; i < l; i++) { + if (arr[i] === obj) + return i; + } + return -1; +}; + +/** + * Array#reduce (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @param {Object} initial value + * @api private + */ + +exports.reduce = function(arr, fn, val){ + var rval = val; + + for (var i = 0, l = arr.length; i < l; i++) { + rval = fn(rval, arr[i], i, arr); + } + + return rval; +}; + +/** + * Array#filter (<=IE8) + * + * @param {Array} array + * @param {Function} fn + * @api private + */ + +exports.filter = function(arr, fn){ + var ret = []; + + for (var i = 0, l = arr.length; i < l; i++) { + var val = arr[i]; + if (fn(val, i, arr)) ret.push(val); + } + + return ret; +}; + +/** + * Object.keys (<=IE8) + * + * @param {Object} obj + * @return {Array} keys + * @api private + */ + +exports.keys = Object.keys || function(obj) { + var keys = [] + , has = Object.prototype.hasOwnProperty // for `window` on <=IE8 + + for (var key in obj) { + if (has.call(obj, key)) { + keys.push(key); + } + } + + return keys; +}; + +/** + * Watch the given `files` for changes + * and invoke `fn(file)` on modification. + * + * @param {Array} files + * @param {Function} fn + * @api private + */ + +exports.watch = function(files, fn){ + var options = { interval: 100 }; + files.forEach(function(file){ + debug('file %s', file); + fs.watchFile(file, options, function(curr, prev){ + if (prev.mtime < curr.mtime) fn(file); + }); + }); +}; + +/** + * Ignored files. + */ + +function ignored(path){ + return !~ignore.indexOf(path); +} + +/** + * Lookup files in the given `dir`. + * + * @return {Array} + * @api private + */ + +exports.files = function(dir, ext, ret){ + ret = ret || []; + ext = ext || ['js']; + + var re = new RegExp('\\.(' + ext.join('|') + ')$'); + + fs.readdirSync(dir) + .filter(ignored) + .forEach(function(path){ + path = join(dir, path); + if (fs.statSync(path).isDirectory()) { + exports.files(path, ext, ret); + } else if (path.match(re)) { + ret.push(path); + } + }); + + return ret; +}; + +/** + * Compute a slug from the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.slug = function(str){ + return str + .toLowerCase() + .replace(/ +/g, '-') + .replace(/[^-\w]/g, ''); +}; + +/** + * Strip the function definition from `str`, + * and re-indent for pre whitespace. + */ + +exports.clean = function(str) { + str = str + .replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, '') + .replace(/^function *\(.*\) *{|\(.*\) *=> *{?/, '') + .replace(/\s+\}$/, ''); + + var spaces = str.match(/^\n?( *)/)[1].length + , tabs = str.match(/^\n?(\t*)/)[1].length + , re = new RegExp('^\n?' + (tabs ? '\t' : ' ') + '{' + (tabs ? tabs : spaces) + '}', 'gm'); + + str = str.replace(re, ''); + + return exports.trim(str); +}; + +/** + * Trim the given `str`. + * + * @param {String} str + * @return {String} + * @api private + */ + +exports.trim = function(str){ + return str.replace(/^\s+|\s+$/g, ''); +}; + +/** + * Parse the given `qs`. + * + * @param {String} qs + * @return {Object} + * @api private + */ + +exports.parseQuery = function(qs){ + return exports.reduce(qs.replace('?', '').split('&'), function(obj, pair){ + var i = pair.indexOf('=') + , key = pair.slice(0, i) + , val = pair.slice(++i); + + obj[key] = decodeURIComponent(val); + return obj; + }, {}); +}; + +/** + * Highlight the given string of `js`. + * + * @param {String} js + * @return {String} + * @api private + */ + +function highlight(js) { + return js + .replace(//g, '>') + .replace(/\/\/(.*)/gm, '//$1') + .replace(/('.*?')/gm, '$1') + .replace(/(\d+\.\d+)/gm, '$1') + .replace(/(\d+)/gm, '$1') + .replace(/\bnew[ \t]+(\w+)/gm, 'new $1') + .replace(/\b(function|new|throw|return|var|if|else)\b/gm, '$1') +} + +/** + * Highlight the contents of tag `name`. + * + * @param {String} name + * @api private + */ + +exports.highlightTags = function(name) { + var code = document.getElementById('mocha').getElementsByTagName(name); + for (var i = 0, len = code.length; i < len; ++i) { + code[i].innerHTML = highlight(code[i].innerHTML); + } +}; + + +/** + * Stringify `obj`. + * + * @param {Object} obj + * @return {String} + * @api private + */ + +exports.stringify = function(obj) { + if (obj instanceof RegExp) return obj.toString(); + return JSON.stringify(exports.canonicalize(obj), null, 2).replace(/,(\n|$)/g, '$1'); +}; + +/** + * Return a new object that has the keys in sorted order. + * @param {Object} obj + * @param {Array} [stack] + * @return {Object} + * @api private + */ + +exports.canonicalize = function(obj, stack) { + stack = stack || []; + + if (exports.indexOf(stack, obj) !== -1) return '[Circular]'; + + var canonicalizedObj; + + if ({}.toString.call(obj) === '[object Array]') { + stack.push(obj); + canonicalizedObj = exports.map(obj, function (item) { + return exports.canonicalize(item, stack); + }); + stack.pop(); + } else if (typeof obj === 'object' && obj !== null) { + stack.push(obj); + canonicalizedObj = {}; + exports.forEach(exports.keys(obj).sort(), function (key) { + canonicalizedObj[key] = exports.canonicalize(obj[key], stack); + }); + stack.pop(); + } else { + canonicalizedObj = obj; + } + + return canonicalizedObj; + }; + +/** + * Lookup file names at the given `path`. + */ +exports.lookupFiles = function lookupFiles(path, extensions, recursive) { + var files = []; + var re = new RegExp('\\.(' + extensions.join('|') + ')$'); + + if (!exists(path)) { + if (exists(path + '.js')) { + path += '.js'; + } else { + files = glob.sync(path); + if (!files.length) throw new Error("cannot resolve path (or pattern) '" + path + "'"); + return files; + } + } + + try { + var stat = fs.statSync(path); + if (stat.isFile()) return path; + } + catch (ignored) { + return; + } + + fs.readdirSync(path).forEach(function(file){ + file = join(path, file); + try { + var stat = fs.statSync(file); + if (stat.isDirectory()) { + if (recursive) { + files = files.concat(lookupFiles(file, extensions, recursive)); + } + return; + } + } + catch (ignored) { + return; + } + if (!stat.isFile() || !re.test(file) || basename(file)[0] === '.') return; + files.push(file); + }); + + return files; +}; + +}); // module: utils.js +// The global object is "self" in Web Workers. +var global = (function() { return this; })(); + +/** + * Save timer references to avoid Sinon interfering (see GH-237). + */ + +var Date = global.Date; +var setTimeout = global.setTimeout; +var setInterval = global.setInterval; +var clearTimeout = global.clearTimeout; +var clearInterval = global.clearInterval; + +/** + * Node shims. + * + * These are meant only to allow + * mocha.js to run untouched, not + * to allow running node code in + * the browser. + */ + +var process = {}; +process.exit = function(status){}; +process.stdout = {}; + +var uncaughtExceptionHandlers = []; + +var originalOnerrorHandler = global.onerror; + +/** + * Remove uncaughtException listener. + * Revert to original onerror handler if previously defined. + */ + +process.removeListener = function(e, fn){ + if ('uncaughtException' == e) { + if (originalOnerrorHandler) { + global.onerror = originalOnerrorHandler; + } else { + global.onerror = function() {}; + } + var i = Mocha.utils.indexOf(uncaughtExceptionHandlers, fn); + if (i != -1) { uncaughtExceptionHandlers.splice(i, 1); } + } +}; + +/** + * Implements uncaughtException listener. + */ + +process.on = function(e, fn){ + if ('uncaughtException' == e) { + global.onerror = function(err, url, line){ + fn(new Error(err + ' (' + url + ':' + line + ')')); + return true; + }; + uncaughtExceptionHandlers.push(fn); + } +}; + +/** + * Expose mocha. + */ + +var Mocha = global.Mocha = require('mocha'), + mocha = global.mocha = new Mocha({ reporter: 'html' }); + +// The BDD UI is registered by default, but no UI will be functional in the +// browser without an explicit call to the overridden `mocha.ui` (see below). +// Ensure that this default UI does not expose its methods to the global scope. +mocha.suite.removeAllListeners('pre-require'); + +var immediateQueue = [] + , immediateTimeout; + +function timeslice() { + var immediateStart = new Date().getTime(); + while (immediateQueue.length && (new Date().getTime() - immediateStart) < 100) { + immediateQueue.shift()(); + } + if (immediateQueue.length) { + immediateTimeout = setTimeout(timeslice, 0); + } else { + immediateTimeout = null; + } +} + +/** + * High-performance override of Runner.immediately. + */ + +Mocha.Runner.immediately = function(callback) { + immediateQueue.push(callback); + if (!immediateTimeout) { + immediateTimeout = setTimeout(timeslice, 0); + } +}; + +/** + * Function to allow assertion libraries to throw errors directly into mocha. + * This is useful when running tests in a browser because window.onerror will + * only receive the 'message' attribute of the Error. + */ +mocha.throwError = function(err) { + Mocha.utils.forEach(uncaughtExceptionHandlers, function (fn) { + fn(err); + }); + throw err; +}; + +/** + * Override ui to ensure that the ui functions are initialized. + * Normally this would happen in Mocha.prototype.loadFiles. + */ + +mocha.ui = function(ui){ + Mocha.prototype.ui.call(this, ui); + this.suite.emit('pre-require', global, null, this); + return this; +}; + +/** + * Setup mocha with the given setting options. + */ + +mocha.setup = function(opts){ + if ('string' == typeof opts) opts = { ui: opts }; + for (var opt in opts) this[opt](opts[opt]); + return this; +}; + +/** + * Run mocha, returning the Runner. + */ + +mocha.run = function(fn){ + var options = mocha.options; + mocha.globals('location'); + + var query = Mocha.utils.parseQuery(global.location.search || ''); + if (query.grep) mocha.grep(query.grep); + if (query.invert) mocha.invert(); + + return Mocha.prototype.run.call(mocha, function(err){ + // The DOM Document is not available in Web Workers. + var document = global.document; + if (document && document.getElementById('mocha') && options.noHighlighting !== true) { + Mocha.utils.highlightTags('code'); + } + if (fn) fn(err); + }); +}; + +/** + * Expose the process shim. + */ + +Mocha.process = process; +})(); diff --git a/tests/automation/res/mocha_util.js b/tests/automation/res/mocha_util.js new file mode 100644 index 0000000000..f60c4d4658 --- /dev/null +++ b/tests/automation/res/mocha_util.js @@ -0,0 +1,3 @@ +!function(){function t(e){var n=t.resolve(e),r=t.modules[n];if(!r)throw new Error('failed to require "'+e+'"');return r.exports||(r.exports={},r.call(r.exports,r,r.exports,t.relative(n))),r.exports}function e(){for(var t=(new r).getTime();h.length&&(new r).getTime()-t<100;)h.shift()();l=h.length?i(e,0):null}t.modules={},t.resolve=function(e){var n=e,r=e+".js",i=e+"/index.js";return t.modules[r]&&r||t.modules[i]&&i||n},t.register=function(e,n){t.modules[e]=n},t.relative=function(e){return function(n){if("."!=n.charAt(0))return t(n);var r=e.split("/"),i=n.split("/");r.pop();for(var o=0;o/g,">"),e=e.replace(/"/g,""")}var r=function(t){this.ignoreWhitespace=t};r.prototype={diff:function(e,n){if(n===e)return[{value:n}];if(!n)return[{value:e,removed:!0}];if(!e)return[{value:n,added:!0}];n=this.tokenize(n),e=this.tokenize(e);var r=n.length,i=e.length,o=r+i,s=[{newPos:-1,components:[]}],a=this.extractCommon(s[0],n,e,0);if(s[0].newPos+1>=r&&a+1>=i)return s[0].components;for(var u=1;o>=u;u++)for(var c=-1*u;u>=c;c+=2){var l,h=s[c-1],f=s[c+1];a=(f?f.newPos:0)-c,h&&(s[c-1]=void 0);var p=h&&h.newPos+1=0&&i>a;if(p||d){!p||d&&h.newPos=r&&a+1>=i)return l.components;s[c]=l}else s[c]=void 0}},pushComponent:function(t,e,n,r){var i=t[t.length-1];i&&i.added===n&&i.removed===r?t[t.length-1]={value:this.join(i.value,e),added:n,removed:r}:t.push({value:e,added:n,removed:r})},extractCommon:function(t,e,n,r){for(var i=e.length,o=n.length,s=t.newPos,a=s-r;i>s+1&&o>a+1&&this.equals(e[s+1],n[a+1]);)s++,a++,this.pushComponent(t.components,e[s],void 0,void 0);return t.newPos=s,a},equals:function(t,e){var n=/\S/;return!this.ignoreWhitespace||n.test(t)||n.test(e)?t===e:!0},join:function(t,e){return t+e},tokenize:function(t){return t}};var i=new r,o=new r(!0),s=new r;o.tokenize=s.tokenize=function(t){return e(t.split(/(\s+|\b)/))};var a=new r(!0);a.tokenize=function(t){return e(t.split(/([{}:;,]|\s+)/))};var u=new r;return u.tokenize=function(t){return t.split(/^/m)},{Diff:r,diffChars:function(t,e){return i.diff(t,e)},diffWords:function(t,e){return o.diff(t,e)},diffWordsWithSpace:function(t,e){return s.diff(t,e)},diffLines:function(t,e){return u.diff(t,e)},diffCss:function(t,e){return a.diff(t,e)},createPatch:function(t,e,n,r,i){function o(t){return t.map(function(t){return" "+t})}function s(t,e,n){var r=c[c.length-2],i=e===c.length-2,o=e===c.length-3&&(n.added!==r.added||n.removed!==r.removed);/\n$/.test(n.value)||!i&&!o||t.push("\\ No newline at end of file")}var a=[];a.push("Index: "+t),a.push("==================================================================="),a.push("--- "+t+("undefined"==typeof r?"":" "+r)),a.push("+++ "+t+("undefined"==typeof i?"":" "+i));var c=u.diff(e,n);c[c.length-1].value||c.pop(),c.push({value:"",lines:[]});for(var l=0,h=0,f=[],p=1,d=1,g=0;g=0;s--){for(var c=r[s],l=0;l"):i.removed&&e.push(""),e.push(n(i.value)),i.added?e.push(""):i.removed&&e.push("")}return e.join("")},convertChangesToDMP:function(t){for(var e,n=[],r=0;ro;o++)if(r[o]===e||r[o].listener&&r[o].listener===e){i=o;break}if(0>i)return this;r.splice(i,1),r.length||delete this.$events[t]}else(r===e||r.listener&&r.listener===e)&&delete this.$events[t]}return this},r.prototype.removeAllListeners=function(t){return void 0===t?(this.$events={},this):(this.$events&&this.$events[t]&&(this.$events[t]=null),this)},r.prototype.listeners=function(t){return this.$events||(this.$events={}),this.$events[t]||(this.$events[t]=[]),n(this.$events[t])||(this.$events[t]=[this.$events[t]]),this.$events[t]},r.prototype.emit=function(t){if(!this.$events)return!1;var e=this.$events[t];if(!e)return!1;var r=[].slice.call(arguments,1);if("function"==typeof e)e.apply(this,r);else{if(!n(e))return!1;for(var i=e.slice(),o=0,s=i.length;s>o;o++)i[o].apply(this,r)}return!0}}),t.register("browser/fs.js",function(){}),t.register("browser/glob.js",function(){}),t.register("browser/path.js",function(){}),t.register("browser/progress.js",function(t){function e(){this.percent=0,this.size(0),this.fontSize(11),this.font("helvetica, arial, sans-serif")}t.exports=e,e.prototype.size=function(t){return this._size=t,this},e.prototype.text=function(t){return this._text=t,this},e.prototype.fontSize=function(t){return this._fontSize=t,this},e.prototype.font=function(t){return this._font=t,this},e.prototype.update=function(t){return this.percent=t,this},e.prototype.draw=function(t){try{var e=Math.min(this.percent,100),n=this._size,r=n/2,i=r,o=r,s=r-1,a=this._fontSize;t.font=a+"px "+this._font;var u=2*Math.PI*(e/100);t.clearRect(0,0,n,n),t.strokeStyle="#9f9f9f",t.beginPath(),t.arc(i,o,s,0,u,!1),t.stroke(),t.strokeStyle="#eee",t.beginPath(),t.arc(i,o,s-1,0,u,!0),t.stroke();var c=this._text||(0|e)+"%",l=t.measureText(c).width;t.fillText(c,i-l/2+1,o+a/2-1)}catch(h){}return this}}),t.register("browser/tty.js",function(t,e){e.isatty=function(){return!0},e.getWindowSize=function(){return"innerHeight"in n?[n.innerHeight,n.innerWidth]:[640,480]}}),t.register("context.js",function(t){function e(){}t.exports=e,e.prototype.runnable=function(t){return 0==arguments.length?this._runnable:(this.test=this._runnable=t,this)},e.prototype.timeout=function(t){return 0===arguments.length?this.runnable().timeout():(this.runnable().timeout(t),this)},e.prototype.enableTimeouts=function(t){return this.runnable().enableTimeouts(t),this},e.prototype.slow=function(t){return this.runnable().slow(t),this},e.prototype.inspect=function(){return JSON.stringify(this,function(t,e){return"_runnable"!=t&&"test"!=t?e:void 0},2)}}),t.register("hook.js",function(t,e,n){function r(t,e){o.call(this,t,e),this.type="hook"}function i(){}var o=n("./runnable");t.exports=r,i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r,r.prototype.error=function(t){if(0==arguments.length){var t=this._error;return this._error=null,t}this._error=t}}),t.register("interfaces/bdd.js",function(t,e,n){var r=n("../suite"),i=n("../test"),o=(n("../utils"),n("browser/escape-string-regexp"));t.exports=function(t){var e=[t];t.on("pre-require",function(t,n,s){t.before=function(t,n){e[0].beforeAll(t,n)},t.after=function(t,n){e[0].afterAll(t,n)},t.beforeEach=function(t,n){e[0].beforeEach(t,n)},t.afterEach=function(t,n){e[0].afterEach(t,n)},t.describe=t.context=function(t,i){var o=r.create(e[0],t);return o.file=n,e.unshift(o),i.call(o),e.shift(),o},t.xdescribe=t.xcontext=t.describe.skip=function(t,n){var i=r.create(e[0],t);i.pending=!0,e.unshift(i),n.call(i),e.shift()},t.describe.only=function(e,n){var r=t.describe(e,n);return s.grep(r.fullTitle()),r},t.it=t.specify=function(t,r){var o=e[0];o.pending&&(r=null);var s=new i(t,r);return s.file=n,o.addTest(s),s},t.it.only=function(e,n){var r=t.it(e,n),i="^"+o(r.fullTitle())+"$";return s.grep(new RegExp(i)),r},t.xit=t.xspecify=t.it.skip=function(e){t.it(e)}})}}),t.register("interfaces/exports.js",function(t,e,n){var r=n("../suite"),i=n("../test");t.exports=function(t){function e(t,o){var s;for(var a in t)if("function"==typeof t[a]){var u=t[a];switch(a){case"before":n[0].beforeAll(u);break;case"after":n[0].afterAll(u);break;case"beforeEach":n[0].beforeEach(u);break;case"afterEach":n[0].afterEach(u);break;default:var c=new i(a,u);c.file=o,n[0].addTest(c)}}else s=r.create(n[0],a),n.unshift(s),e(t[a]),n.shift()}var n=[t];t.on("require",e)}}),t.register("interfaces/index.js",function(t,e,n){e.bdd=n("./bdd"),e.tdd=n("./tdd"),e.qunit=n("./qunit"),e.exports=n("./exports")}),t.register("interfaces/qunit.js",function(t,e,n){{var r=n("../suite"),i=n("../test"),o=n("browser/escape-string-regexp");n("../utils")}t.exports=function(t){var e=[t];t.on("pre-require",function(t,n,s){t.before=function(t,n){e[0].beforeAll(t,n)},t.after=function(t,n){e[0].afterAll(t,n)},t.beforeEach=function(t,n){e[0].beforeEach(t,n)},t.afterEach=function(t,n){e[0].afterEach(t,n)},t.suite=function(t){e.length>1&&e.shift();var i=r.create(e[0],t);return i.file=n,e.unshift(i),i},t.suite.only=function(e,n){var r=t.suite(e,n);s.grep(r.fullTitle())},t.test=function(t,r){var o=new i(t,r);return o.file=n,e[0].addTest(o),o},t.test.only=function(e,n){var r=t.test(e,n),i="^"+o(r.fullTitle())+"$";s.grep(new RegExp(i))},t.test.skip=function(e){t.test(e)}})}}),t.register("interfaces/tdd.js",function(t,e,n){{var r=n("../suite"),i=n("../test"),o=n("browser/escape-string-regexp");n("../utils")}t.exports=function(t){var e=[t];t.on("pre-require",function(t,n,s){t.setup=function(t,n){e[0].beforeEach(t,n)},t.teardown=function(t,n){e[0].afterEach(t,n)},t.suiteSetup=function(t,n){e[0].beforeAll(t,n)},t.suiteTeardown=function(t,n){e[0].afterAll(t,n)},t.suite=function(t,i){var o=r.create(e[0],t);return o.file=n,e.unshift(o),i.call(o),e.shift(),o},t.suite.skip=function(t,n){var i=r.create(e[0],t);i.pending=!0,e.unshift(i),n.call(i),e.shift()},t.suite.only=function(e,n){var r=t.suite(e,n);s.grep(r.fullTitle())},t.test=function(t,r){var o=e[0];o.pending&&(r=null);var s=new i(t,r);return s.file=n,o.addTest(s),s},t.test.only=function(e,n){var r=t.test(e,n),i="^"+o(r.fullTitle())+"$";s.grep(new RegExp(i))},t.test.skip=function(e){t.test(e)}})}}),t.register("mocha.js",function(t,e,r){function i(t){return __dirname+"/../images/"+t+".png"}function s(t){t=t||{},this.files=[],this.options=t,this.grep(t.grep),this.suite=new e.Suite("",new e.Context),this.ui(t.ui),this.bail(t.bail),this.reporter(t.reporter),null!=t.timeout&&this.timeout(t.timeout),this.useColors(t.useColors),null!==t.enableTimeouts&&this.enableTimeouts(t.enableTimeouts),t.slow&&this.slow(t.slow),this.suite.on("pre-require",function(t){e.afterEach=t.afterEach||t.teardown,e.after=t.after||t.suiteTeardown,e.beforeEach=t.beforeEach||t.setup,e.before=t.before||t.suiteSetup,e.describe=t.describe||t.suite,e.it=t.it||t.test,e.setup=t.setup||t.beforeEach,e.suiteSetup=t.suiteSetup||t.before,e.suiteTeardown=t.suiteTeardown||t.after,e.suite=t.suite||t.describe,e.teardown=t.teardown||t.afterEach,e.test=t.test||t.it})}var a=r("browser/path"),u=r("browser/escape-string-regexp"),c=r("./utils");if(e=t.exports=s,"undefined"!=typeof o&&"function"==typeof o.cwd){var l=a.join,h=o.cwd();t.paths.push(h,l(h,"node_modules"))}e.utils=c,e.interfaces=r("./interfaces"),e.reporters=r("./reporters"),e.Runnable=r("./runnable"),e.Context=r("./context"),e.Runner=r("./runner"),e.Suite=r("./suite"),e.Hook=r("./hook"),e.Test=r("./test"),s.prototype.bail=function(t){return 0==arguments.length&&(t=!0),this.suite.bail(t),this},s.prototype.addFile=function(t){return this.files.push(t),this},s.prototype.reporter=function(t){if("function"==typeof t)this._reporter=t;else{t=t||"spec";var e;try{e=r("./reporters/"+t)}catch(n){}if(!e)try{e=r(t)}catch(n){}if(e||"teamcity"!==t||console.warn("The Teamcity reporter was moved to a package named mocha-teamcity-reporter (https://npmjs.org/package/mocha-teamcity-reporter)."),!e)throw new Error('invalid reporter "'+t+'"');this._reporter=e}return this},s.prototype.ui=function(t){if(t=t||"bdd",this._ui=e.interfaces[t],!this._ui)try{this._ui=r(t)}catch(n){}if(!this._ui)throw new Error('invalid interface "'+t+'"');return this._ui=this._ui(this.suite),this},s.prototype.loadFiles=function(t){var e=this,i=this.suite,o=this.files.length;this.files.forEach(function(s){s=a.resolve(s),i.emit("pre-require",n,s,e),i.emit("require",r(s),s,e),i.emit("post-require",n,s,e),--o||t&&t()})},s.prototype._growl=function(t,e){var n=r("growl");t.on("end",function(){var r=e.stats;if(r.failures){var o=r.failures+" of "+t.total+" tests failed";n(o,{name:"mocha",title:"Failed",image:i("error")})}else n(r.passes+" tests passed in "+r.duration+"ms",{name:"mocha",title:"Passed",image:i("ok")})})},s.prototype.grep=function(t){return this.options.grep="string"==typeof t?new RegExp(u(t)):t,this},s.prototype.invert=function(){return this.options.invert=!0,this},s.prototype.ignoreLeaks=function(t){return this.options.ignoreLeaks=!!t,this},s.prototype.checkLeaks=function(){return this.options.ignoreLeaks=!1,this},s.prototype.growl=function(){return this.options.growl=!0,this},s.prototype.globals=function(t){return this.options.globals=(this.options.globals||[]).concat(t),this},s.prototype.useColors=function(t){return this.options.useColors=arguments.length&&void 0!=t?t:!0,this},s.prototype.useInlineDiffs=function(t){return this.options.useInlineDiffs=arguments.length&&void 0!=t?t:!1,this},s.prototype.timeout=function(t){return this.suite.timeout(t),this},s.prototype.slow=function(t){return this.suite.slow(t),this},s.prototype.enableTimeouts=function(t){return this.suite.enableTimeouts(arguments.length&&void 0!==t?t:!0),this},s.prototype.asyncOnly=function(){return this.options.asyncOnly=!0,this},s.prototype.noHighlighting=function(){return this.options.noHighlighting=!0,this},s.prototype.run=function(t){this.files.length&&this.loadFiles();var n=this.suite,r=this.options;r.files=this.files;var i=new e.Runner(n),o=new this._reporter(i,r);return i.ignoreLeaks=!1!==r.ignoreLeaks,i.asyncOnly=r.asyncOnly,r.grep&&i.grep(r.grep,r.invert),r.globals&&i.globals(r.globals),r.growl&&this._growl(i,o),e.reporters.Base.useColors=r.useColors,e.reporters.Base.inlineDiffs=r.useInlineDiffs,i.run(t)}}),t.register("ms.js",function(t){function e(t){var e=/^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(t);if(e){var n=parseFloat(e[1]),r=(e[2]||"ms").toLowerCase();switch(r){case"years":case"year":case"y":return n*c;case"days":case"day":case"d":return n*u;case"hours":case"hour":case"h":return n*a;case"minutes":case"minute":case"m":return n*s;case"seconds":case"second":case"s":return n*o;case"ms":return n}}}function n(t){return t>=u?Math.round(t/u)+"d":t>=a?Math.round(t/a)+"h":t>=s?Math.round(t/s)+"m":t>=o?Math.round(t/o)+"s":t+"ms"}function r(t){return i(t,u,"day")||i(t,a,"hour")||i(t,s,"minute")||i(t,o,"second")||t+" ms"}function i(t,e,n){return e>t?void 0:1.5*e>t?Math.floor(t/e)+" "+n:Math.ceil(t/e)+" "+n+"s"}var o=1e3,s=60*o,a=60*s,u=24*a,c=365.25*u;t.exports=function(t,i){return i=i||{},"string"==typeof t?e(t):i["long"]?r(t):n(t)}}),t.register("reporters/base.js",function(t,e,r){function i(t){var e=this.stats={suites:0,tests:0,passes:0,pending:0,failures:0},n=this.failures=[];t&&(this.runner=t,t.stats=e,t.on("start",function(){e.start=new m}),t.on("suite",function(t){e.suites=e.suites||0,t.root||e.suites++}),t.on("test end",function(){e.tests=e.tests||0,e.tests++}),t.on("pass",function(t){e.passes=e.passes||0;var n=t.slow()/2;t.speed=t.duration>t.slow()?"slow":t.duration>n?"medium":"fast",e.passes++}),t.on("fail",function(t,r){e.failures=e.failures||0,e.failures++,t.err=r,n.push(t)}),t.on("end",function(){e.end=new m,e.duration=new m-e.start}),t.on("pending",function(){e.pending++}))}function s(t,e){return t=String(t),Array(e-t.length+1).join(" ")+t}function a(t,e){var n=c(t,"WordsWithSpace",e),r=n.split("\n");if(r.length>4){var i=String(r.length).length;n=r.map(function(t,e){return s(++e,i)+" | "+t}).join("\n")}return n="\n"+y("diff removed","actual")+" "+y("diff added","expected")+"\n\n"+n+"\n",n=n.replace(/^/gm," ")}function u(t,e){function n(t){return e&&(t=l(t)),"+"===t[0]?i+h("diff added",t):"-"===t[0]?i+h("diff removed",t):t.match(/\@\@/)?null:t.match(/\\ No newline/)?null:i+t}function r(t){return null!=t}var i=" ";msg=d.createPatch("string",t.actual,t.expected);var o=msg.split("\n").splice(4);return"\n "+h("diff added","+ expected")+" "+h("diff removed","- actual")+"\n\n"+o.map(n).filter(r).join("\n")}function c(t,e,n){var r=n?l(t.actual):t.actual,i=n?l(t.expected):t.expected;return d["diff"+e](r,i).map(function(t){return t.added?h("diff added",t.value):t.removed?h("diff removed",t.value):t.value}).join("")}function l(t){return t.replace(/\t/g,"").replace(/\r/g,"").replace(/\n/g,"\n")}function h(t,e){return e.split("\n").map(function(e){return y(t,e)}).join("\n")}function f(t,e){return t=Object.prototype.toString.call(t),e=Object.prototype.toString.call(e),t==e}var p=r("browser/tty"),d=r("browser/diff"),g=r("../ms"),v=r("../utils"),m=n.Date,b=(n.setTimeout,n.setInterval,n.clearTimeout,n.clearInterval,p.isatty(1)&&p.isatty(2));e=t.exports=i,e.useColors=b||void 0!==o.env.MOCHA_COLORS,e.inlineDiffs=!1,e.colors={pass:90,fail:31,"bright pass":92,"bright fail":91,"bright yellow":93,pending:36,suite:0,"error title":0,"error message":31,"error stack":90,checkmark:32,fast:90,medium:33,slow:31,green:32,light:90,"diff gutter":90,"diff added":42,"diff removed":41},e.symbols={ok:"✓",err:"✖",dot:"․"},"win32"==o.platform&&(e.symbols.ok="√",e.symbols.err="×",e.symbols.dot=".");var y=e.color=function(t,n){return e.useColors?"["+e.colors[t]+"m"+n+"":n};e.window={width:b?o.stdout.getWindowSize?o.stdout.getWindowSize(1)[0]:p.getWindowSize()[1]:75},e.cursor={hide:function(){b&&o.stdout.write("[?25l")},show:function(){b&&o.stdout.write("[?25h")},deleteLine:function(){b&&o.stdout.write("")},beginningOfLine:function(){b&&o.stdout.write("")},CR:function(){b?(e.cursor.deleteLine(),e.cursor.beginningOfLine()):o.stdout.write("\r")}},e.list=function(t){console.error(),t.forEach(function(t,n){var r=y("error title"," %s) %s:\n")+y("error message"," %s")+y("error stack","\n%s\n"),i=t.err,o=i.message||"",s=i.stack||o,c=s.indexOf(o)+o.length,l=s.slice(0,c),h=i.actual,p=i.expected,d=!0;if(i.uncaught&&(l="Uncaught "+l),i.showDiff&&f(h,p)&&(d=!1,i.actual=h=v.stringify(h),i.expected=p=v.stringify(p)),i.showDiff&&"string"==typeof h&&"string"==typeof p){r=y("error title"," %s) %s:\n%s")+y("error stack","\n%s\n");var g=o.match(/^([^:]+): expected/);l="\n "+y("error message",g?g[1]:l),l+=e.inlineDiffs?a(i,d):u(i,d)}s=s.slice(c?c+1:c).replace(/^/gm," "),console.error(r,n+1,t.fullTitle(),l,s)})},i.prototype.epilogue=function(){var t,e=this.stats;console.log(),t=y("bright pass"," ")+y("green"," %d passing")+y("light"," (%s)"),console.log(t,e.passes||0,g(e.duration)),e.pending&&(t=y("pending"," ")+y("pending"," %d pending"),console.log(t,e.pending)),e.failures&&(t=y("fail"," %d failing"),console.error(t,e.failures),i.list(this.failures),console.error()),console.log()}}),t.register("reporters/doc.js",function(t,e,n){function r(t){function e(){return Array(n).join(" ")}i.call(this,t);var n=(this.stats,t.total,2);t.on("suite",function(t){t.root||(++n,console.log('%s
        ',e()),++n,console.log("%s

        %s

        ",e(),o.escape(t.title)),console.log("%s
        ",e()))}),t.on("suite end",function(t){t.root||(console.log("%s
        ",e()),--n,console.log("%s
        ",e()),--n)}),t.on("pass",function(t){console.log("%s
        %s
        ",e(),o.escape(t.title));var n=o.escape(o.clean(t.fn.toString()));console.log("%s
        %s
        ",e(),n)}),t.on("fail",function(t,n){console.log('%s
        %s
        ',e(),o.escape(t.title));var r=o.escape(o.clean(t.fn.toString()));console.log('%s
        %s
        ',e(),r),console.log('%s
        %s
        ',e(),o.escape(n))})}var i=n("./base"),o=n("../utils");e=t.exports=r}),t.register("reporters/dot.js",function(t,e,n){function r(t){s.call(this,t);var e=this,n=(this.stats,.75*s.window.width|0),r=-1;t.on("start",function(){o.stdout.write("\n ")}),t.on("pending",function(){++r%n==0&&o.stdout.write("\n "),o.stdout.write(a("pending",s.symbols.dot))}),t.on("pass",function(t){++r%n==0&&o.stdout.write("\n "),o.stdout.write("slow"==t.speed?a("bright yellow",s.symbols.dot):a(t.speed,s.symbols.dot))}),t.on("fail",function(){++r%n==0&&o.stdout.write("\n "),o.stdout.write(a("fail",s.symbols.dot))}),t.on("end",function(){console.log(),e.epilogue()})}function i(){}var s=n("./base"),a=s.color;e=t.exports=r,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/html-cov.js",function(t,e,n){function r(t){var e=n("jade"),r=__dirname+"/templates/coverage.jade",u=a.readFileSync(r,"utf8"),c=e.compile(u,{filename:r}),l=this;s.call(this,t,!1),t.on("end",function(){o.stdout.write(c({cov:l.cov,coverageClass:i}))})}function i(t){return t>=75?"high":t>=50?"medium":t>=25?"low":"terrible"}var s=n("./json-cov"),a=n("browser/fs");e=t.exports=r}),t.register("reporters/html.js",function(t,e,r){function i(t){h.call(this,t);var e,n,r=this,i=this.stats,m=(t.total,s(v)),b=m.getElementsByTagName("li"),y=b[1].getElementsByTagName("em")[0],w=b[1].getElementsByTagName("a")[0],x=b[2].getElementsByTagName("em")[0],j=b[2].getElementsByTagName("a")[0],E=b[3].getElementsByTagName("em")[0],T=m.getElementsByTagName("canvas")[0],k=s('
          '),q=[k],_=document.getElementById("mocha");if(T.getContext){var O=window.devicePixelRatio||1;T.style.width=T.width,T.style.height=T.height,T.width*=O,T.height*=O,n=T.getContext("2d"),n.scale(O,O),e=new p}return _?(l(w,"click",function(){u();var t=/pass/.test(k.className)?"":" pass";k.className=k.className.replace(/fail|pass/g,"")+t,k.className.trim()&&a("test pass")}),l(j,"click",function(){u();var t=/fail/.test(k.className)?"":" fail";k.className=k.className.replace(/fail|pass/g,"")+t,k.className.trim()&&a("test fail")}),_.appendChild(m),_.appendChild(k),e&&e.size(40),t.on("suite",function(t){if(!t.root){var e=r.suiteURL(t),n=s('
        • %s

        • ',e,d(t.title));q[0].appendChild(n),q.unshift(document.createElement("ul")),n.appendChild(q[0])}}),t.on("suite end",function(t){t.root||q.shift()}),t.on("fail",function(e){"hook"==e.type&&t.emit("test end",e)}),void t.on("test end",function(t){var o=i.tests/this.total*100|0;e&&e.update(o).draw(n);var a=new g-i.start;if(c(y,i.passes),c(x,i.failures),c(E,(a/1e3).toFixed(2)),"passed"==t.state)var u=r.testURL(t),h=s('
        • %e%ems

        • ',t.speed,t.title,t.duration,u);else if(t.pending)var h=s('
        • %e

        • ',t.title);else{var h=s('
        • %e

        • ',t.title,encodeURIComponent(t.fullTitle())),p=t.err.stack||t.err.toString();~p.indexOf(t.err.message)||(p=t.err.message+"\n"+p),"[object Error]"==p&&(p=t.err.message),!t.err.stack&&t.err.sourceURL&&void 0!==t.err.line&&(p+="\n("+t.err.sourceURL+":"+t.err.line+")"),h.appendChild(s('
          %e
          ',p))}if(!t.pending){var d=h.getElementsByTagName("h2")[0];l(d,"click",function(){v.style.display="none"==v.style.display?"block":"none"});var v=s("
          %e
          ",f.clean(t.fn.toString()));h.appendChild(v),v.style.display="none"}q[0]&&q[0].appendChild(h)})):o("#mocha div missing, add it to your document")}function o(t){document.body.appendChild(s('
          %s
          ',t))}function s(t){var e=arguments,n=document.createElement("div"),r=1;return n.innerHTML=t.replace(/%([se])/g,function(t,n){switch(n){case"s":return String(e[r++]);case"e":return d(e[r++])}}),n.firstChild}function a(t){for(var e=document.getElementsByClassName("suite"),n=0;n0&&(e.coverage=e.hits/e.sloc*100),e}function a(t,e){var n={filename:t,coverage:0,hits:0,misses:0,sloc:0,source:{}};return e.source.forEach(function(t,r){r++,0===e[r]?(n.misses++,n.sloc++):void 0!==e[r]&&(n.hits++,n.sloc++),n.source[r]={source:t,coverage:void 0===e[r]?"":e[r]}}),n.coverage=n.hits/n.sloc*100,n}function u(t){return{title:t.title,fullTitle:t.fullTitle(),duration:t.duration}}var c=r("./base");e=t.exports=i}),t.register("reporters/json-stream.js",function(t,e,n){function r(t){s.call(this,t);var e=this,n=(this.stats,t.total);t.on("start",function(){console.log(JSON.stringify(["start",{total:n}]))}),t.on("pass",function(t){console.log(JSON.stringify(["pass",i(t)]))}),t.on("fail",function(t,e){t=i(t),t.err=e.message,console.log(JSON.stringify(["fail",t]))}),t.on("end",function(){o.stdout.write(JSON.stringify(["end",e.stats]))})}function i(t){return{title:t.title,fullTitle:t.fullTitle(),duration:t.duration}}{var s=n("./base");s.color}e=t.exports=r}),t.register("reporters/json.js",function(t,e,n){function r(t){var e=this;a.call(this,t);var n=[],r=[],s=[],u=[];t.on("test end",function(t){n.push(t)}),t.on("pass",function(t){u.push(t)}),t.on("fail",function(t){s.push(t)}),t.on("pending",function(t){r.push(t)}),t.on("end",function(){var a={stats:e.stats,tests:n.map(i),pending:r.map(i),failures:s.map(i),passes:u.map(i)};t.testResults=a,o.stdout.write(JSON.stringify(a,null,2))})}function i(t){return{title:t.title,fullTitle:t.fullTitle(),duration:t.duration,err:s(t.err||{})}}function s(t){var e={};return Object.getOwnPropertyNames(t).forEach(function(n){e[n]=t[n]},t),e}{var a=n("./base");a.cursor,a.color}e=t.exports=r}),t.register("reporters/landing.js",function(t,e,n){function r(t){function e(){var t=Array(r).join("-");return" "+u("runway",t)}s.call(this,t);var n=this,r=(this.stats,.75*s.window.width|0),i=t.total,c=o.stdout,l=u("plane","✈"),h=-1,f=0;t.on("start",function(){c.write("\n\n\n "),a.hide()}),t.on("test end",function(t){var n=-1==h?r*++f/i|0:h;"failed"==t.state&&(l=u("plane crash","✈"),h=n),c.write("["+(r+1)+"D"),c.write(e()),c.write("\n "),c.write(u("runway",Array(n).join("⋅"))),c.write(l),c.write(u("runway",Array(r-n).join("⋅")+"\n")),c.write(e()),c.write("")}),t.on("end",function(){a.show(),console.log(),n.epilogue()})}function i(){}var s=n("./base"),a=s.cursor,u=s.color;e=t.exports=r,s.colors.plane=0,s.colors["plane crash"]=31,s.colors.runway=90,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/list.js",function(t,e,n){function r(t){s.call(this,t);var e=this,n=(this.stats,0);t.on("start",function(){console.log()}),t.on("test",function(t){o.stdout.write(u("pass"," "+t.fullTitle()+": "))}),t.on("pending",function(t){var e=u("checkmark"," -")+u("pending"," %s");console.log(e,t.fullTitle())}),t.on("pass",function(t){var e=u("checkmark"," "+s.symbols.dot)+u("pass"," %s: ")+u(t.speed,"%dms");a.CR(),console.log(e,t.fullTitle(),t.duration)}),t.on("fail",function(t){a.CR(),console.log(u("fail"," %d) %s"),++n,t.fullTitle())}),t.on("end",e.epilogue.bind(e))}function i(){}var s=n("./base"),a=s.cursor,u=s.color;e=t.exports=r,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/markdown.js",function(t,e,n){function r(t){function e(t){return Array(u).join("#")+" "+t}function n(t,e){var r=e;return e=e[t.title]=e[t.title]||{suite:t},t.suites.forEach(function(t){n(t,e)}),r}function r(t,e){++e;var n,i="";for(var o in t)"suite"!=o&&(o&&(n=" - ["+o+"](#"+s.slug(t[o].suite.fullTitle())+")\n"),o&&(i+=Array(e).join(" ")+n),i+=r(t[o],e));return--e,i}function a(t){var e=n(t,{});return r(e,0)}i.call(this,t);var u=(this.stats,0),c="";a(t.suite),t.on("suite",function(t){++u;var n=s.slug(t.fullTitle());c+='\n',c+=e(t.title)+"\n"}),t.on("suite end",function(){--u}),t.on("pass",function(t){var e=s.clean(t.fn.toString());c+=t.title+".\n",c+="\n```js\n",c+=e+"\n",c+="```\n\n"}),t.on("end",function(){o.stdout.write("# TOC\n"),o.stdout.write(a(t.suite)),o.stdout.write(c) +})}var i=n("./base"),s=n("../utils");e=t.exports=r}),t.register("reporters/min.js",function(t,e,n){function r(t){s.call(this,t),t.on("start",function(){o.stdout.write(""),o.stdout.write("")}),t.on("end",this.epilogue.bind(this))}function i(){}var s=n("./base");e=t.exports=r,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/nyan.js",function(t,e,n){function r(t){a.call(this,t);{var e=this,n=(this.stats,.75*a.window.width|0),r=(this.rainbowColors=e.generateColors(),this.colorIndex=0,this.numberOfLines=4,this.trajectories=[[],[],[],[]],this.nyanCatWidth=11);this.trajectoryWidthMax=n-r,this.scoreboardWidth=5,this.tick=0}t.on("start",function(){a.cursor.hide(),e.draw()}),t.on("pending",function(){e.draw()}),t.on("pass",function(){e.draw()}),t.on("fail",function(){e.draw()}),t.on("end",function(){a.cursor.show();for(var t=0;t=this.trajectoryWidthMax&&r.shift(),r.push(e)}},r.prototype.drawRainbow=function(){var t=this;this.trajectories.forEach(function(e){i("["+t.scoreboardWidth+"C"),i(e.join("")),i("\n")}),this.cursorUp(this.numberOfLines)},r.prototype.drawNyanCat=function(){var t=this,e=this.scoreboardWidth+this.trajectories[0].length,n="["+e+"C",r="";i(n),i("_,------,"),i("\n"),i(n),r=t.tick?" ":" ",i("_|"+r+"/\\_/\\ "),i("\n"),i(n),r=t.tick?"_":"__";var o=t.tick?"~":"^";i(o+"|"+r+this.face()+" "),i("\n"),i(n),r=t.tick?" ":" ",i(r+'"" "" '),i("\n"),this.cursorUp(this.numberOfLines)},r.prototype.face=function(){var t=this.stats;return t.failures?"( x .x)":t.pending?"( o .o)":t.passes?"( ^ .^)":"( - .-)"},r.prototype.cursorUp=function(t){i("["+t+"A")},r.prototype.cursorDown=function(t){i("["+t+"B")},r.prototype.generateColors=function(){for(var t=[],e=0;42>e;e++){var n=Math.floor(Math.PI/3),r=e*(1/6),i=Math.floor(3*Math.sin(r)+3),o=Math.floor(3*Math.sin(r+2*n)+3),s=Math.floor(3*Math.sin(r+4*n)+3);t.push(36*i+6*o+s+16)}return t},r.prototype.rainbowify=function(t){var e=this.rainbowColors[this.colorIndex%this.rainbowColors.length];return this.colorIndex+=1,"[38;5;"+e+"m"+t+""},s.prototype=a.prototype,r.prototype=new s,r.prototype.constructor=r}),t.register("reporters/progress.js",function(t,e,n){function r(t,e){s.call(this,t);var n=this,e=e||{},r=(this.stats,.5*s.window.width|0),i=t.total,c=0,l=(Math.max,-1);e.open=e.open||"[",e.complete=e.complete||"▬",e.incomplete=e.incomplete||s.symbols.dot,e.close=e.close||"]",e.verbose=!1,t.on("start",function(){console.log(),a.hide()}),t.on("test end",function(){c++;var t=c/i,n=r*t|0,s=r-n;(l!==n||e.verbose)&&(l=n,a.CR(),o.stdout.write(""),o.stdout.write(u("progress"," "+e.open)),o.stdout.write(Array(n).join(e.complete)),o.stdout.write(Array(s).join(e.incomplete)),o.stdout.write(u("progress",e.close)),e.verbose&&o.stdout.write(u("progress"," "+c+" of "+i)))}),t.on("end",function(){a.show(),console.log(),n.epilogue()})}function i(){}var s=n("./base"),a=s.cursor,u=s.color;e=t.exports=r,s.colors.progress=90,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/spec.js",function(t,e,n){function r(t){function e(){return Array(r).join(" ")}o.call(this,t);var n=this,r=(this.stats,0),i=0;t.on("start",function(){console.log()}),t.on("suite",function(t){++r,console.log(a("suite","%s%s"),e(),t.title)}),t.on("suite end",function(){--r,1==r&&console.log()}),t.on("pending",function(t){var n=e()+a("pending"," - %s");console.log(n,t.title)}),t.on("pass",function(t){if("fast"==t.speed){var n=e()+a("checkmark"," "+o.symbols.ok)+a("pass"," %s ");s.CR(),console.log(n,t.title)}else{var n=e()+a("checkmark"," "+o.symbols.ok)+a("pass"," %s ")+a(t.speed,"(%dms)");s.CR(),console.log(n,t.title,t.duration)}}),t.on("fail",function(t){s.CR(),console.log(e()+a("fail"," %d) %s"),++i,t.title)}),t.on("end",n.epilogue.bind(n))}function i(){}var o=n("./base"),s=o.cursor,a=o.color;e=t.exports=r,i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/tap.js",function(t,e,n){function r(t){o.call(this,t);var e=(this.stats,1),n=0,r=0;t.on("start",function(){var e=t.grepTotal(t.suite);console.log("%d..%d",1,e)}),t.on("test end",function(){++e}),t.on("pending",function(t){console.log("ok %d %s # SKIP -",e,i(t))}),t.on("pass",function(t){n++,console.log("ok %d %s",e,i(t))}),t.on("fail",function(t,n){r++,console.log("not ok %d %s",e,i(t)),n.stack&&console.log(n.stack.replace(/^/gm," "))}),t.on("end",function(){console.log("# tests "+(n+r)),console.log("# pass "+n),console.log("# fail "+r)})}function i(t){return t.fullTitle().replace(/#/g,"")}{var o=n("./base");o.cursor,o.color}e=t.exports=r}),t.register("reporters/xunit.js",function(t,e,r){function i(t){c.call(this,t);var e=this.stats,n=[];t.on("pending",function(t){n.push(t)}),t.on("pass",function(t){n.push(t)}),t.on("fail",function(t){n.push(t)}),t.on("end",function(){console.log(a("testsuite",{name:"Mocha Tests",tests:e.tests,failures:e.failures,errors:e.failures,skipped:e.tests-e.failures-e.passes,timestamp:(new f).toUTCString(),time:e.duration/1e3||0},!1)),n.forEach(s),console.log("")})}function o(){}function s(t){var e={classname:t.parent.fullTitle(),name:t.title,time:t.duration/1e3||0};if("failed"==t.state){var n=t.err;console.log(a("testcase",e,!1,a("failure",{},!1,u(h(n.message)+"\n"+n.stack))))}else console.log(t.pending?a("testcase",e,!1,a("skipped",{},!0)):a("testcase",e,!0))}function a(t,e,n,r){var i,o=n?"/>":">",s=[];for(var a in e)s.push(a+'="'+h(e[a])+'"');return i="<"+t+(s.length?" "+s.join(" "):"")+o,r&&(i+=r+""}{var c=r("./base"),l=r("../utils"),h=l.escape,f=n.Date;n.setTimeout,n.setInterval,n.clearTimeout,n.clearInterval}e=t.exports=i,o.prototype=c.prototype,i.prototype=new o,i.prototype.constructor=i}),t.register("runnable.js",function(t,e,r){function i(t,e){this.title=t,this.fn=e,this.async=e&&e.length,this.sync=!this.async,this._timeout=2e3,this._slow=75,this._enableTimeouts=!0,this.timedOut=!1,this._trace=new Error("done() called multiple times")}function o(){}var s=r("browser/events").EventEmitter,a=r("browser/debug")("mocha:runnable"),u=r("./ms"),c=n.Date,l=n.setTimeout,h=(n.setInterval,n.clearTimeout),f=(n.clearInterval,Object.prototype.toString);t.exports=i,o.prototype=s.prototype,i.prototype=new o,i.prototype.constructor=i,i.prototype.timeout=function(t){return 0==arguments.length?this._timeout:(0===t&&(this._enableTimeouts=!1),"string"==typeof t&&(t=u(t)),a("timeout %d",t),this._timeout=t,this.timer&&this.resetTimeout(),this)},i.prototype.slow=function(t){return 0===arguments.length?this._slow:("string"==typeof t&&(t=u(t)),a("timeout %d",t),this._slow=t,this)},i.prototype.enableTimeouts=function(t){return 0===arguments.length?this._enableTimeouts:(a("enableTimeouts %s",t),this._enableTimeouts=t,this)},i.prototype.fullTitle=function(){return this.parent.fullTitle()+" "+this.title},i.prototype.clearTimeout=function(){h(this.timer)},i.prototype.inspect=function(){return JSON.stringify(this,function(t,e){return"_"!=t[0]?"parent"==t?"#":"ctx"==t?"#":e:void 0},2)},i.prototype.resetTimeout=function(){var t=this,e=this.timeout()||1e9;this._enableTimeouts&&(this.clearTimeout(),this.timer=l(function(){t._enableTimeouts&&(t.callback(new Error("timeout of "+e+"ms exceeded")),t.timedOut=!0)},e))},i.prototype.globals=function(t){this._allowedGlobals=t},i.prototype.run=function(t){function e(t){o||(o=!0,s.emit("error",t||new Error("done() called multiple times; stacktrace may be inaccurate")))}function n(n){var r=s.timeout();if(!s.timedOut){if(i)return e(n||s._trace);s.clearTimeout(),s.duration=new c-a,i=!0,!n&&s.duration>r&&s._enableTimeouts&&(n=new Error("timeout of "+r+"ms exceeded")),t(n)}}function r(t){var e=t.call(u);e&&"function"==typeof e.then?(s.resetTimeout(),e.then(function(){n()},function(t){n(t||new Error("Promise rejected with no or falsy reason"))})):n()}var i,o,s=this,a=new c,u=this.ctx;if(u&&u.runnable&&u.runnable(this),this.callback=n,this.async){this.resetTimeout();try{this.fn.call(u,function(t){return t instanceof Error||"[object Error]"===f.call(t)?n(t):null!=t?n("[object Object]"===Object.prototype.toString.call(t)?new Error("done() invoked with non-Error: "+JSON.stringify(t)):new Error("done() invoked with non-Error: "+t)):void n()})}catch(l){n(l)}}else{if(this.asyncOnly)return n(new Error("--async-only option in use without declaring `done()`"));try{this.pending?n():r(this.fn)}catch(l){n(l)}}}}),t.register("runner.js",function(t,e,r){function i(t){var e=this;this._globals=[],this._abort=!1,this.suite=t,this.total=t.total(),this.failures=0,this.on("test end",function(t){e.checkGlobals(t)}),this.on("hook end",function(t){e.checkGlobals(t)}),this.grep(/.*/),this.globals(this.globalProps().concat(u()))}function s(){}function a(t,e){return f(e,function(e){if(/^d+/.test(e))return!1;if(n.navigator&&/^getInterface/.test(e))return!1;if(n.navigator&&/^\d+/.test(e))return!1;if(/^mocha-/.test(e))return!1;var r=f(t,function(t){return~t.indexOf("*")?0==e.indexOf(t.split("*")[0]):e==t});return 0==r.length&&(!n.navigator||"onerror"!==e)})}function u(){if("object"==typeof o&&"string"==typeof o.version){var t=o.version.split(".").reduce(function(t,e){return t<<8|e});if(2315>t)return["errno"]}return[]}var c=r("browser/events").EventEmitter,l=r("browser/debug")("mocha:runner"),h=(r("./test"),r("./utils")),f=h.filter,p=(h.keys,["setTimeout","clearTimeout","setInterval","clearInterval","XMLHttpRequest","Date"]);t.exports=i,i.immediately=n.setImmediate||o.nextTick,s.prototype=c.prototype,i.prototype=new s,i.prototype.constructor=i,i.prototype.grep=function(t,e){return l("grep %s",t),this._grep=t,this._invert=e,this.total=this.grepTotal(this.suite),this},i.prototype.grepTotal=function(t){var e=this,n=0;return t.eachTest(function(t){var r=e._grep.test(t.fullTitle());e._invert&&(r=!r),r&&n++}),n},i.prototype.globalProps=function(){for(var t=h.keys(n),e=0;e1?this.fail(t,new Error("global leaks detected: "+e.join(", "))):e.length&&this.fail(t,new Error("global leak detected: "+e[0])))}},i.prototype.fail=function(t,e){++this.failures,t.state="failed","string"==typeof e&&(e=new Error('the string "'+e+'" was thrown, throw an Error :)')),this.emit("fail",t,e)},i.prototype.failHook=function(t,e){this.fail(t,e),this.suite.bail()&&this.emit("end")},i.prototype.hook=function(t,e){function n(t){var i=o[t];return i?s.failures&&r.bail()?e():(s.currentRunnable=i,i.ctx.currentTest=s.test,s.emit("hook",i),i.on("error",function(t){s.failHook(i,t)}),void i.run(function(r){i.removeAllListeners("error");var o=i.error();return o&&s.fail(s.test,o),r?(s.failHook(i,r),e(r)):(s.emit("hook end",i),delete i.ctx.currentTest,void n(++t))})):e()}var r=this.suite,o=r["_"+t],s=this;i.immediately(function(){n(0)})},i.prototype.hooks=function(t,e,n){function r(s){return i.suite=s,s?void i.hook(t,function(t){if(t){var s=i.suite;return i.suite=o,n(t,s)}r(e.pop())}):(i.suite=o,n())}var i=this,o=this.suite;r(e.pop())},i.prototype.hookUp=function(t,e){var n=[this.suite].concat(this.parents()).reverse();this.hooks(t,n,e)},i.prototype.hookDown=function(t,e){var n=[this.suite].concat(this.parents());this.hooks(t,n,e)},i.prototype.parents=function(){for(var t=this.suite,e=[];t=t.parent;)e.push(t);return e},i.prototype.runTest=function(t){var e=this.test,n=this;this.asyncOnly&&(e.asyncOnly=!0);try{e.on("error",function(t){n.fail(e,t)}),e.run(t)}catch(r){t(r)}},i.prototype.runTests=function(t,e){function n(t,r,i){var s=o.suite;o.suite=i?r.parent:r,o.suite?o.hookUp("afterEach",function(t,i){return o.suite=s,t?n(t,i,!0):void e(r)}):(o.suite=s,e(r))}function r(a,u){if(o.failures&&t._bail)return e();if(o._abort)return e();if(a)return n(a,u,!0);if(i=s.shift(),!i)return e();var c=o._grep.test(i.fullTitle());return o._invert&&(c=!c),c?i.pending?(o.emit("pending",i),o.emit("test end",i),r()):(o.emit("test",o.test=i),void o.hookDown("beforeEach",function(t,e){return t?n(t,e,!1):(o.currentRunnable=o.test,void o.runTest(function(t){return i=o.test,t?(o.fail(i,t),o.emit("test end",i),o.hookUp("afterEach",r)):(i.state="passed",o.emit("pass",i),o.emit("test end",i),void o.hookUp("afterEach",r))}))})):r()}var i,o=this,s=t.tests.slice();this.next=r,r()},i.prototype.runSuite=function(t,e){function n(e){if(e)return e==t?r():r(e);if(o._abort)return r();var i=t.suites[s++];return i?void o.runSuite(i,n):r()}function r(n){o.suite=t,o.hook("afterAll",function(){o.emit("suite end",t),e(n)})}var i=this.grepTotal(t),o=this,s=0;return l("run suite %s",t.fullTitle()),i?(this.emit("suite",this.suite=t),void this.hook("beforeAll",function(e){return e?r():void o.runTests(t,n)})):e()},i.prototype.uncaught=function(t){t?l("uncaught exception %s",t!==function(){return this}.call(t)?t:t.message||t):(l("uncaught undefined exception"),t=new Error("Caught undefined error, did you throw without specifying what?")),t.uncaught=!0;var e=this.currentRunnable;if(e){var n=e.state;if(this.fail(e,t),e.clearTimeout(),!n)return"test"==e.type?(this.emit("test end",e),void this.hookUp("afterEach",this.next)):void this.emit("end")}},i.prototype.run=function(t){function e(t){n.uncaught(t)}var n=this,t=t||function(){};return l("start"),this.on("end",function(){l("end"),o.removeListener("uncaughtException",e),t(n.failures)}),this.emit("start"),this.runSuite(this.suite,function(){l("finished running"),n.emit("end")}),o.on("uncaughtException",e),this},i.prototype.abort=function(){l("aborting"),this._abort=!0}}),t.register("suite.js",function(t,e,n){function r(t,e){this.title=t;var n=function(){};n.prototype=e,this.ctx=new n,this.suites=[],this.tests=[],this.pending=!1,this._beforeEach=[],this._beforeAll=[],this._afterEach=[],this._afterAll=[],this.root=!t,this._timeout=2e3,this._enableTimeouts=!0,this._slow=75,this._bail=!1}function i(){}var o=n("browser/events").EventEmitter,s=n("browser/debug")("mocha:suite"),a=n("./ms"),u=n("./utils"),c=n("./hook");e=t.exports=r,e.create=function(t,e){var n=new r(e,t.ctx);return n.parent=t,t.pending&&(n.pending=!0),e=n.fullTitle(),t.addSuite(n),n},i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r,r.prototype.clone=function(){var t=new r(this.title);return s("clone"),t.ctx=this.ctx,t.timeout(this.timeout()),t.enableTimeouts(this.enableTimeouts()),t.slow(this.slow()),t.bail(this.bail()),t},r.prototype.timeout=function(t){return 0==arguments.length?this._timeout:(0===t&&(this._enableTimeouts=!1),"string"==typeof t&&(t=a(t)),s("timeout %d",t),this._timeout=parseInt(t,10),this)},r.prototype.enableTimeouts=function(t){return 0===arguments.length?this._enableTimeouts:(s("enableTimeouts %s",t),this._enableTimeouts=t,this)},r.prototype.slow=function(t){return 0===arguments.length?this._slow:("string"==typeof t&&(t=a(t)),s("slow %d",t),this._slow=t,this)},r.prototype.bail=function(t){return 0==arguments.length?this._bail:(s("bail %s",t),this._bail=t,this)},r.prototype.beforeAll=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"before all" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._beforeAll.push(n),this.emit("beforeAll",n),this},r.prototype.afterAll=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"after all" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._afterAll.push(n),this.emit("afterAll",n),this},r.prototype.beforeEach=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"before each" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._beforeEach.push(n),this.emit("beforeEach",n),this},r.prototype.afterEach=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"after each" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._afterEach.push(n),this.emit("afterEach",n),this},r.prototype.addSuite=function(t){return t.parent=this,t.timeout(this.timeout()),t.enableTimeouts(this.enableTimeouts()),t.slow(this.slow()),t.bail(this.bail()),this.suites.push(t),this.emit("suite",t),this},r.prototype.addTest=function(t){return t.parent=this,t.timeout(this.timeout()),t.enableTimeouts(this.enableTimeouts()),t.slow(this.slow()),t.ctx=this.ctx,this.tests.push(t),this.emit("test",t),this},r.prototype.fullTitle=function(){if(this.parent){var t=this.parent.fullTitle();if(t)return t+" "+this.title}return this.title},r.prototype.total=function(){return u.reduce(this.suites,function(t,e){return t+e.total()},0)+this.tests.length},r.prototype.eachTest=function(t){return u.forEach(this.tests,t),u.forEach(this.suites,function(e){e.eachTest(t)}),this}}),t.register("test.js",function(t,e,n){function r(t,e){o.call(this,t,e),this.pending=!e,this.type="test"}function i(){}var o=n("./runnable");t.exports=r,i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("utils.js",function(t,e,n){function r(t){return!~f.indexOf(t)}function i(t){return t.replace(//g,">").replace(/\/\/(.*)/gm,'//$1').replace(/('.*?')/gm,'$1').replace(/(\d+\.\d+)/gm,'$1').replace(/(\d+)/gm,'$1').replace(/\bnew[ \t]+(\w+)/gm,'new $1').replace(/\b(function|new|throw|return|var|if|else)\b/gm,'$1')}var o=n("browser/fs"),s=n("browser/path"),a=s.basename,u=o.existsSync||s.existsSync,c=n("browser/glob"),l=s.join,h=n("browser/debug")("mocha:watch"),f=["node_modules",".git"];e.escape=function(t){return String(t).replace(/&/g,"&").replace(/"/g,""").replace(//g,">")},e.forEach=function(t,e,n){for(var r=0,i=t.length;i>r;r++)e.call(n,t[r],r)},e.map=function(t,e,n){for(var r=[],i=0,o=t.length;o>i;i++)r.push(e.call(n,t[i],i));return r},e.indexOf=function(t,e,n){for(var r=n||0,i=t.length;i>r;r++)if(t[r]===e)return r;return-1},e.reduce=function(t,e,n){for(var r=n,i=0,o=t.length;o>i;i++)r=e(r,t[i],i,t);return r},e.filter=function(t,e){for(var n=[],r=0,i=t.length;i>r;r++){var o=t[r];e(o,r,t)&&n.push(o)}return n},e.keys=Object.keys||function(t){var e=[],n=Object.prototype.hasOwnProperty;for(var r in t)n.call(t,r)&&e.push(r);return e},e.watch=function(t,e){var n={interval:100};t.forEach(function(t){h("file %s",t),o.watchFile(t,n,function(n,r){r.mtime *{?/,"").replace(/\s+\}$/,"");var n=t.match(/^\n?( *)/)[1].length,r=t.match(/^\n?(\t*)/)[1].length,i=new RegExp("^\n?"+(r?" ":" ")+"{"+(r?r:n)+"}","gm");return t=t.replace(i,""),e.trim(t)},e.trim=function(t){return t.replace(/^\s+|\s+$/g,"")},e.parseQuery=function(t){return e.reduce(t.replace("?","").split("&"),function(t,e){var n=e.indexOf("="),r=e.slice(0,n),i=e.slice(++n);return t[r]=decodeURIComponent(i),t},{})},e.highlightTags=function(t){for(var e=document.getElementById("mocha").getElementsByTagName(t),n=0,r=e.length;r>n;++n)e[n].innerHTML=i(e[n].innerHTML)},e.stringify=function(t){return t instanceof RegExp?t.toString():JSON.stringify(e.canonicalize(t),null,2).replace(/,(\n|$)/g,"$1")},e.canonicalize=function(t,n){if(n=n||[],-1!==e.indexOf(n,t))return"[Circular]";var r;return"[object Array]"==={}.toString.call(t)?(n.push(t),r=e.map(t,function(t){return e.canonicalize(t,n)}),n.pop()):"object"==typeof t&&null!==t?(n.push(t),r={},e.forEach(e.keys(t).sort(),function(i){r[i]=e.canonicalize(t[i],n)}),n.pop()):r=t,r},e.lookupFiles=function p(t,e,n){var r=[],i=new RegExp("\\.("+e.join("|")+")$");if(!u(t)){if(!u(t+".js")){if(r=c.sync(t),!r.length)throw new Error("cannot resolve path (or pattern) '"+t+"'");return r}t+=".js"}try{var s=o.statSync(t);if(s.isFile())return t}catch(h){return}return o.readdirSync(t).forEach(function(s){s=l(t,s);try{var u=o.statSync(s);if(u.isDirectory())return void(n&&(r=r.concat(p(s,e,n))))}catch(c){return}u.isFile()&&i.test(s)&&"."!==a(s)[0]&&r.push(s)}),r}});var n=function(){return this}(),r=n.Date,i=n.setTimeout,o=(n.setInterval,n.clearTimeout,n.clearInterval,{});o.exit=function(){},o.stdout={};var s=[],a=n.onerror;o.removeListener=function(t,e){if("uncaughtException"==t){n.onerror=a?a:function(){};var r=u.utils.indexOf(s,e);-1!=r&&s.splice(r,1)}},o.on=function(t,e){"uncaughtException"==t&&(n.onerror=function(t,n,r){return e(new Error(t+" ("+n+":"+r+")")),!0},s.push(e))};var u=n.Mocha=t("mocha"),c=n.mocha=new u({reporter:"html"});c.suite.removeAllListeners("pre-require");var l,h=[];u.Runner.immediately=function(t){h.push(t),l||(l=i(e,0))},c.throwError=function(t){throw u.utils.forEach(s,function(e){e(t)}),t},c.ui=function(t){return u.prototype.ui.call(this,t),this.suite.emit("pre-require",n,null,this),this},c.setup=function(t){"string"==typeof t&&(t={ui:t});for(var e in t)this[e](t[e]);return this},c.run=function(t){var e=c.options;c.globals("location");var r=u.utils.parseQuery(n.location.search||"");return r.grep&&c.grep(r.grep),r.invert&&c.invert(),u.prototype.run.call(c,function(r){var i=n.document;i&&i.getElementById("mocha")&&e.noHighlighting!==!0&&u.utils.highlightTags("code"),t&&t(r)})},u.process=o}(),function(){function require(t){var e=require.modules[t];if(!e)throw new Error('failed to require "'+t+'"');return"exports"in e||"function"!=typeof e.definition||(e.client=e.component=!0,e.definition.call(this,e.exports={},e),delete e.definition),e.exports}require.loader="component",require.helper={},require.helper.semVerSort=function(t,e){for(var n=t.version.split("."),r=e.version.split("."),i=0;is?1:-1;var a=n[i].substr((""+o).length),u=r[i].substr((""+s).length);if(""===a&&""!==u)return 1;if(""!==a&&""===u)return-1;if(""!==a&&""!==u)return a>u?1:-1}return 0},require.latest=function(t,e){function n(t){throw new Error('failed to find latest module of "'+t+'"')}var r=/(.*)~(.*)@v?(\d+\.\d+\.\d+[^\/]*)$/,i=/(.*)~(.*)/;i.test(t)||n(t);for(var o=Object.keys(require.modules),s=[],a=[],u=0;u0){var f=s.sort(require.helper.semVerSort).pop().name;return e===!0?f:require(f)}var f=a.pop().name;return e===!0?f:require(f)},require.modules={},require.register=function(t,e){require.modules[t]={definition:e}},require.define=function(t,e){require.modules[t]={exports:e}},require.register("chaijs~assertion-error@1.0.0",function(t,e){function n(){function t(t,n){Object.keys(n).forEach(function(r){~e.indexOf(r)||(t[r]=n[r])})}var e=[].slice.call(arguments);return function(){for(var e=[].slice.call(arguments),n=0,r={};n=0;i--)if(l=o[i],!n(t[l],e[l],r))return!1;return!0}var p,d=require("chaijs~type-detect@0.1.1");try{p=require("buffer").Buffer}catch(g){p={},p.isBuffer=function(){return!1}}e.exports=n}),require.register("chai",function(t,e){e.exports=require("chai/lib/chai.js")}),require.register("chai/lib/chai.js",function(t,e){var n=[],t=e.exports={};t.version="1.10.0",t.AssertionError=require("chaijs~assertion-error@1.0.0");var r=require("chai/lib/chai/utils/index.js");t.use=function(t){return~n.indexOf(t)||(t(this,r),n.push(t)),this};var i=require("chai/lib/chai/config.js");t.config=i;var o=require("chai/lib/chai/assertion.js");t.use(o);var s=require("chai/lib/chai/core/assertions.js");t.use(s);var a=require("chai/lib/chai/interface/expect.js");t.use(a);var u=require("chai/lib/chai/interface/should.js");t.use(u);var c=require("chai/lib/chai/interface/assert.js");t.use(c)}),require.register("chai/lib/chai/assertion.js",function(t,e){var n=require("chai/lib/chai/config.js"),r=function(){};e.exports=function(t,e){function i(t,e,n){s(this,"ssfi",n||arguments.callee),s(this,"object",t),s(this,"message",e)}var o=t.AssertionError,s=e.flag;t.Assertion=i,Object.defineProperty(i,"includeStack",{get:function(){return console.warn("Assertion.includeStack is deprecated, use chai.config.includeStack instead."),n.includeStack},set:function(t){console.warn("Assertion.includeStack is deprecated, use chai.config.includeStack instead."),n.includeStack=t}}),Object.defineProperty(i,"showDiff",{get:function(){return console.warn("Assertion.showDiff is deprecated, use chai.config.showDiff instead."),n.showDiff},set:function(t){console.warn("Assertion.showDiff is deprecated, use chai.config.showDiff instead."),n.showDiff=t}}),i.addProperty=function(t,n){e.addProperty(this.prototype,t,n)},i.addMethod=function(t,n){e.addMethod(this.prototype,t,n)},i.addChainableMethod=function(t,n,r){e.addChainableMethod(this.prototype,t,n,r)},i.addChainableNoop=function(t,n){e.addChainableMethod(this.prototype,t,r,n)},i.overwriteProperty=function(t,n){e.overwriteProperty(this.prototype,t,n)},i.overwriteMethod=function(t,n){e.overwriteMethod(this.prototype,t,n)},i.overwriteChainableMethod=function(t,n,r){e.overwriteChainableMethod(this.prototype,t,n,r)},i.prototype.assert=function(t,r,i,a,u,c){var l=e.test(this,arguments);if(!0!==c&&(c=!1),!0!==n.showDiff&&(c=!1),!l){var r=e.getMessage(this,arguments),h=e.getActual(this,arguments);throw new o(r,{actual:h,expected:a,showDiff:c},n.includeStack?this.assert:s(this,"ssfi"))}},Object.defineProperty(i.prototype,"_obj",{get:function(){return s(this,"object")},set:function(t){s(this,"object",t)}})}}),require.register("chai/lib/chai/config.js",function(t,e){e.exports={includeStack:!1,showDiff:!0,truncateThreshold:40}}),require.register("chai/lib/chai/core/assertions.js",function(t,e){e.exports=function(t,e){function n(t,n){n&&w(this,"message",n),t=t.toLowerCase();var r=w(this,"object"),i=~["a","e","i","o","u"].indexOf(t.charAt(0))?"an ":"a ";this.assert(t===e.type(r),"expected #{this} to be "+i+t,"expected #{this} not to be "+i+t)}function r(){w(this,"contains",!0)}function i(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=!1;if("array"===e.type(r)&&"object"===e.type(t)){for(var o in r)if(e.eql(r[o],t)){i=!0;break}}else if("object"===e.type(t)){if(!w(this,"negate")){for(var s in t)new y(r).property(s,t[s]);return}var a={};for(var s in t)a[s]=r[s];i=e.eql(a,t)}else i=r&&~r.indexOf(t);this.assert(i,"expected #{this} to include "+e.inspect(t),"expected #{this} to not include "+e.inspect(t))}function o(){var t=w(this,"object"),e=Object.prototype.toString.call(t);this.assert("[object Arguments]"===e,"expected #{this} to be arguments but got "+e,"expected #{this} to not be arguments")}function s(t,e){e&&w(this,"message",e);var n=w(this,"object");return w(this,"deep")?this.eql(t):void this.assert(t===n,"expected #{this} to equal #{exp}","expected #{this} to not equal #{exp}",t,this._obj,!0)}function a(t,n){n&&w(this,"message",n),this.assert(e.eql(t,w(this,"object")),"expected #{this} to deeply equal #{exp}","expected #{this} to not deeply equal #{exp}",t,this._obj,!0)}function u(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(r>t,"expected #{this} to have a length above #{exp} but got #{act}","expected #{this} to not have a length above #{exp}",t,r)}else this.assert(n>t,"expected #{this} to be above "+t,"expected #{this} to be at most "+t)}function c(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(r>=t,"expected #{this} to have a length at least #{exp} but got #{act}","expected #{this} to have a length below #{exp}",t,r)}else this.assert(n>=t,"expected #{this} to be at least "+t,"expected #{this} to be below "+t)}function l(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(t>r,"expected #{this} to have a length below #{exp} but got #{act}","expected #{this} to not have a length below #{exp}",t,r) +}else this.assert(t>n,"expected #{this} to be below "+t,"expected #{this} to be at least "+t)}function h(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(t>=r,"expected #{this} to have a length at most #{exp} but got #{act}","expected #{this} to have a length above #{exp}",t,r)}else this.assert(t>=n,"expected #{this} to be at most "+t,"expected #{this} to be above "+t)}function f(t,n){n&&w(this,"message",n);var r=e.getName(t);this.assert(w(this,"object")instanceof t,"expected #{this} to be an instance of "+r,"expected #{this} to not be an instance of "+r)}function p(t,n){n&&w(this,"message",n);var r=w(this,"object");this.assert(r.hasOwnProperty(t),"expected #{this} to have own property "+e.inspect(t),"expected #{this} to not have own property "+e.inspect(t))}function d(){w(this,"doLength",!0)}function g(t,e){e&&w(this,"message",e);var n=w(this,"object");new y(n,e).to.have.property("length");var r=n.length;this.assert(r==t,"expected #{this} to have a length of #{exp} but got #{act}","expected #{this} to not have a length of #{act}",t,r)}function v(t){var n,r=w(this,"object"),i=!0;if(t=t instanceof Array?t:Array.prototype.slice.call(arguments),!t.length)throw new Error("keys required");var o=Object.keys(r),s=t,a=t.length;if(i=t.every(function(t){return~o.indexOf(t)}),w(this,"negate")||w(this,"contains")||(i=i&&t.length==o.length),a>1){t=t.map(function(t){return e.inspect(t)});var u=t.pop();n=t.join(", ")+", and "+u}else n=e.inspect(t[0]);n=(a>1?"keys ":"key ")+n,n=(w(this,"contains")?"contain ":"have ")+n,this.assert(i,"expected #{this} to "+n,"expected #{this} to not "+n,s.sort(),o.sort(),!0)}function m(t,n,r){r&&w(this,"message",r);var i=w(this,"object");new y(i,r).is.a("function");var o=!1,s=null,a=null,u=null;0===arguments.length?(n=null,t=null):t&&(t instanceof RegExp||"string"==typeof t)?(n=t,t=null):t&&t instanceof Error?(s=t,t=null,n=null):"function"==typeof t?(a=t.prototype.name||t.name,"Error"===a&&t!==Error&&(a=(new t).name)):t=null;try{i()}catch(c){if(s)return this.assert(c===s,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp}",s instanceof Error?s.toString():s,c instanceof Error?c.toString():c),w(this,"object",c),this;if(t&&(this.assert(c instanceof t,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp} but #{act} was thrown",a,c instanceof Error?c.toString():c),!n))return w(this,"object",c),this;var l="object"===e.type(c)&&"message"in c?c.message:""+c;if(null!=l&&n&&n instanceof RegExp)return this.assert(n.exec(l),"expected #{this} to throw error matching #{exp} but got #{act}","expected #{this} to throw error not matching #{exp}",n,l),w(this,"object",c),this;if(null!=l&&n&&"string"==typeof n)return this.assert(~l.indexOf(n),"expected #{this} to throw error including #{exp} but got #{act}","expected #{this} to throw error not including #{act}",n,l),w(this,"object",c),this;o=!0,u=c}var h="",f=null!==a?a:s?"#{exp}":"an error";o&&(h=" but #{act} was thrown"),this.assert(o===!0,"expected #{this} to throw "+f+h,"expected #{this} to not throw "+f+h,s instanceof Error?s.toString():s,u instanceof Error?u.toString():u),w(this,"object",u)}function b(t,e,n){return t.every(function(t){return n?e.some(function(e){return n(t,e)}):-1!==e.indexOf(t)})}var y=t.Assertion,w=(Object.prototype.toString,e.flag);["to","be","been","is","and","has","have","with","that","at","of","same"].forEach(function(t){y.addProperty(t,function(){return this})}),y.addProperty("not",function(){w(this,"negate",!0)}),y.addProperty("deep",function(){w(this,"deep",!0)}),y.addChainableMethod("an",n),y.addChainableMethod("a",n),y.addChainableMethod("include",i,r),y.addChainableMethod("contain",i,r),y.addChainableNoop("ok",function(){this.assert(w(this,"object"),"expected #{this} to be truthy","expected #{this} to be falsy")}),y.addChainableNoop("true",function(){this.assert(!0===w(this,"object"),"expected #{this} to be true","expected #{this} to be false",this.negate?!1:!0)}),y.addChainableNoop("false",function(){this.assert(!1===w(this,"object"),"expected #{this} to be false","expected #{this} to be true",this.negate?!0:!1)}),y.addChainableNoop("null",function(){this.assert(null===w(this,"object"),"expected #{this} to be null","expected #{this} not to be null")}),y.addChainableNoop("undefined",function(){this.assert(void 0===w(this,"object"),"expected #{this} to be undefined","expected #{this} not to be undefined")}),y.addChainableNoop("exist",function(){this.assert(null!=w(this,"object"),"expected #{this} to exist","expected #{this} to not exist")}),y.addChainableNoop("empty",function(){var t=w(this,"object"),e=t;Array.isArray(t)||"string"==typeof object?e=t.length:"object"==typeof t&&(e=Object.keys(t).length),this.assert(!e,"expected #{this} to be empty","expected #{this} not to be empty")}),y.addChainableNoop("arguments",o),y.addChainableNoop("Arguments",o),y.addMethod("equal",s),y.addMethod("equals",s),y.addMethod("eq",s),y.addMethod("eql",a),y.addMethod("eqls",a),y.addMethod("above",u),y.addMethod("gt",u),y.addMethod("greaterThan",u),y.addMethod("least",c),y.addMethod("gte",c),y.addMethod("below",l),y.addMethod("lt",l),y.addMethod("lessThan",l),y.addMethod("most",h),y.addMethod("lte",h),y.addMethod("within",function(t,e,n){n&&w(this,"message",n);var r=w(this,"object"),i=t+".."+e;if(w(this,"doLength")){new y(r,n).to.have.property("length");var o=r.length;this.assert(o>=t&&e>=o,"expected #{this} to have a length within "+i,"expected #{this} to not have a length within "+i)}else this.assert(r>=t&&e>=r,"expected #{this} to be within "+i,"expected #{this} to not be within "+i)}),y.addMethod("instanceof",f),y.addMethod("instanceOf",f),y.addMethod("property",function(t,n,r){r&&w(this,"message",r);var i=w(this,"deep")?"deep property ":"property ",o=w(this,"negate"),s=w(this,"object"),a=w(this,"deep")?e.getPathValue(t,s):s[t];if(o&&void 0!==n){if(void 0===a)throw r=null!=r?r+": ":"",new Error(r+e.inspect(s)+" has no "+i+e.inspect(t))}else this.assert(void 0!==a,"expected #{this} to have a "+i+e.inspect(t),"expected #{this} to not have "+i+e.inspect(t));void 0!==n&&this.assert(n===a,"expected #{this} to have a "+i+e.inspect(t)+" of #{exp}, but got #{act}","expected #{this} to not have a "+i+e.inspect(t)+" of #{act}",n,a),w(this,"object",a)}),y.addMethod("ownProperty",p),y.addMethod("haveOwnProperty",p),y.addChainableMethod("length",g,d),y.addMethod("lengthOf",g),y.addMethod("match",function(t,e){e&&w(this,"message",e);var n=w(this,"object");this.assert(t.exec(n),"expected #{this} to match "+t,"expected #{this} not to match "+t)}),y.addMethod("string",function(t,n){n&&w(this,"message",n);var r=w(this,"object");new y(r,n).is.a("string"),this.assert(~r.indexOf(t),"expected #{this} to contain "+e.inspect(t),"expected #{this} to not contain "+e.inspect(t))}),y.addMethod("keys",v),y.addMethod("key",v),y.addMethod("throw",m),y.addMethod("throws",m),y.addMethod("Throw",m),y.addMethod("respondTo",function(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=w(this,"itself"),o="function"!==e.type(r)||i?r[t]:r.prototype[t];this.assert("function"==typeof o,"expected #{this} to respond to "+e.inspect(t),"expected #{this} to not respond to "+e.inspect(t))}),y.addProperty("itself",function(){w(this,"itself",!0)}),y.addMethod("satisfy",function(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=t(r);this.assert(i,"expected #{this} to satisfy "+e.objDisplay(t),"expected #{this} to not satisfy"+e.objDisplay(t),this.negate?!1:!0,i)}),y.addMethod("closeTo",function(t,n,r){r&&w(this,"message",r);var i=w(this,"object");if(new y(i,r).is.a("number"),"number"!==e.type(t)||"number"!==e.type(n))throw new Error("the arguments to closeTo must be numbers");this.assert(Math.abs(i-t)<=n,"expected #{this} to be close to "+t+" +/- "+n,"expected #{this} not to be close to "+t+" +/- "+n)}),y.addMethod("members",function(t,n){n&&w(this,"message",n);var r=w(this,"object");new y(r).to.be.an("array"),new y(t).to.be.an("array");var i=w(this,"deep")?e.eql:void 0;return w(this,"contains")?this.assert(b(t,r,i),"expected #{this} to be a superset of #{act}","expected #{this} to not be a superset of #{act}",r,t):void this.assert(b(r,t,i)&&b(t,r,i),"expected #{this} to have the same members as #{act}","expected #{this} to not have the same members as #{act}",r,t)})}}),require.register("chai/lib/chai/interface/assert.js",function(exports,module){module.exports=function(chai,util){var Assertion=chai.Assertion,flag=util.flag,assert=chai.assert=function(t,e){var n=new Assertion(null,null,chai.assert);n.assert(t,e,"[ negation message unavailable ]")};assert.fail=function(t,e,n,r){throw n=n||"assert.fail()",new chai.AssertionError(n,{actual:t,expected:e,operator:r},assert.fail)},assert.ok=function(t,e){new Assertion(t,e).is.ok},assert.notOk=function(t,e){new Assertion(t,e).is.not.ok},assert.equal=function(t,e,n){var r=new Assertion(t,n,assert.equal);r.assert(e==flag(r,"object"),"expected #{this} to equal #{exp}","expected #{this} to not equal #{act}",e,t)},assert.notEqual=function(t,e,n){var r=new Assertion(t,n,assert.notEqual);r.assert(e!=flag(r,"object"),"expected #{this} to not equal #{exp}","expected #{this} to equal #{act}",e,t)},assert.strictEqual=function(t,e,n){new Assertion(t,n).to.equal(e)},assert.notStrictEqual=function(t,e,n){new Assertion(t,n).to.not.equal(e)},assert.deepEqual=function(t,e,n){new Assertion(t,n).to.eql(e)},assert.notDeepEqual=function(t,e,n){new Assertion(t,n).to.not.eql(e)},assert.isTrue=function(t,e){new Assertion(t,e).is["true"]},assert.isFalse=function(t,e){new Assertion(t,e).is["false"]},assert.isNull=function(t,e){new Assertion(t,e).to.equal(null)},assert.isNotNull=function(t,e){new Assertion(t,e).to.not.equal(null)},assert.isUndefined=function(t,e){new Assertion(t,e).to.equal(void 0)},assert.isDefined=function(t,e){new Assertion(t,e).to.not.equal(void 0)},assert.isFunction=function(t,e){new Assertion(t,e).to.be.a("function")},assert.isNotFunction=function(t,e){new Assertion(t,e).to.not.be.a("function")},assert.isObject=function(t,e){new Assertion(t,e).to.be.a("object")},assert.isNotObject=function(t,e){new Assertion(t,e).to.not.be.a("object")},assert.isArray=function(t,e){new Assertion(t,e).to.be.an("array")},assert.isNotArray=function(t,e){new Assertion(t,e).to.not.be.an("array")},assert.isString=function(t,e){new Assertion(t,e).to.be.a("string")},assert.isNotString=function(t,e){new Assertion(t,e).to.not.be.a("string")},assert.isNumber=function(t,e){new Assertion(t,e).to.be.a("number")},assert.isNotNumber=function(t,e){new Assertion(t,e).to.not.be.a("number")},assert.isBoolean=function(t,e){new Assertion(t,e).to.be.a("boolean")},assert.isNotBoolean=function(t,e){new Assertion(t,e).to.not.be.a("boolean")},assert.typeOf=function(t,e,n){new Assertion(t,n).to.be.a(e)},assert.notTypeOf=function(t,e,n){new Assertion(t,n).to.not.be.a(e)},assert.instanceOf=function(t,e,n){new Assertion(t,n).to.be.instanceOf(e)},assert.notInstanceOf=function(t,e,n){new Assertion(t,n).to.not.be.instanceOf(e)},assert.include=function(t,e,n){new Assertion(t,n,assert.include).include(e)},assert.notInclude=function(t,e,n){new Assertion(t,n,assert.notInclude).not.include(e)},assert.match=function(t,e,n){new Assertion(t,n).to.match(e)},assert.notMatch=function(t,e,n){new Assertion(t,n).to.not.match(e)},assert.property=function(t,e,n){new Assertion(t,n).to.have.property(e)},assert.notProperty=function(t,e,n){new Assertion(t,n).to.not.have.property(e)},assert.deepProperty=function(t,e,n){new Assertion(t,n).to.have.deep.property(e)},assert.notDeepProperty=function(t,e,n){new Assertion(t,n).to.not.have.deep.property(e)},assert.propertyVal=function(t,e,n,r){new Assertion(t,r).to.have.property(e,n)},assert.propertyNotVal=function(t,e,n,r){new Assertion(t,r).to.not.have.property(e,n)},assert.deepPropertyVal=function(t,e,n,r){new Assertion(t,r).to.have.deep.property(e,n)},assert.deepPropertyNotVal=function(t,e,n,r){new Assertion(t,r).to.not.have.deep.property(e,n)},assert.lengthOf=function(t,e,n){new Assertion(t,n).to.have.length(e)},assert.Throw=function(t,e,n,r){("string"==typeof e||e instanceof RegExp)&&(n=e,e=null);var i=new Assertion(t,r).to.Throw(e,n);return flag(i,"object")},assert.doesNotThrow=function(t,e,n){"string"==typeof e&&(n=e,e=null),new Assertion(t,n).to.not.Throw(e)},assert.operator=function(val,operator,val2,msg){if(!~["==","===",">",">=","<","<=","!=","!=="].indexOf(operator))throw new Error('Invalid operator "'+operator+'"');var test=new Assertion(eval(val+operator+val2),msg);test.assert(!0===flag(test,"object"),"expected "+util.inspect(val)+" to be "+operator+" "+util.inspect(val2),"expected "+util.inspect(val)+" to not be "+operator+" "+util.inspect(val2))},assert.closeTo=function(t,e,n,r){new Assertion(t,r).to.be.closeTo(e,n)},assert.sameMembers=function(t,e,n){new Assertion(t,n).to.have.same.members(e)},assert.includeMembers=function(t,e,n){new Assertion(t,n).to.include.members(e)},assert.ifError=function(t,e){new Assertion(t,e).to.not.be.ok},function t(e,n){return assert[n]=assert[e],t}("Throw","throw")("Throw","throws")}}),require.register("chai/lib/chai/interface/expect.js",function(t,e){e.exports=function(t){t.expect=function(e,n){return new t.Assertion(e,n)}}}),require.register("chai/lib/chai/interface/should.js",function(t,e){e.exports=function(t){function e(){function t(){return this instanceof String||this instanceof Number?new n(this.constructor(this),null,t):this instanceof Boolean?new n(1==this,null,t):new n(this,null,t)}function e(t){Object.defineProperty(this,"should",{value:t,enumerable:!0,configurable:!0,writable:!0})}Object.defineProperty(Object.prototype,"should",{set:e,get:t,configurable:!0});var r={};return r.equal=function(t,e,r){new n(t,r).to.equal(e)},r.Throw=function(t,e,r,i){new n(t,i).to.Throw(e,r)},r.exist=function(t,e){new n(t,e).to.exist},r.not={},r.not.equal=function(t,e,r){new n(t,r).to.not.equal(e)},r.not.Throw=function(t,e,r,i){new n(t,i).to.not.Throw(e,r)},r.not.exist=function(t,e){new n(t,e).to.not.exist},r["throw"]=r.Throw,r.not["throw"]=r.not.Throw,r}var n=t.Assertion;t.should=e,t.Should=e}}),require.register("chai/lib/chai/utils/addChainableMethod.js",function(t,e){var n=require("chai/lib/chai/utils/transferFlags.js"),r=require("chai/lib/chai/utils/flag.js"),i=require("chai/lib/chai/config.js"),o="__proto__"in Object,s=/^(?:length|name|arguments|caller)$/,a=Function.prototype.call,u=Function.prototype.apply;e.exports=function(t,e,c,l){"function"!=typeof l&&(l=function(){});var h={method:c,chainingBehavior:l};t.__methods||(t.__methods={}),t.__methods[e]=h,Object.defineProperty(t,e,{get:function(){h.chainingBehavior.call(this);var e=function f(){var t=r(this,"ssfi");t&&i.includeStack===!1&&r(this,"ssfi",f);var e=h.method.apply(this,arguments);return void 0===e?this:e};if(o){var c=e.__proto__=Object.create(this);c.call=a,c.apply=u}else{var l=Object.getOwnPropertyNames(t);l.forEach(function(n){if(!s.test(n)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r)}})}return n(this,e),e},configurable:!0})}}),require.register("chai/lib/chai/utils/addMethod.js",function(t,e){var n=require("chai/lib/chai/config.js"),r=require("chai/lib/chai/utils/flag.js");e.exports=function(t,e,i){t[e]=function(){var o=r(this,"ssfi");o&&n.includeStack===!1&&r(this,"ssfi",t[e]);var s=i.apply(this,arguments);return void 0===s?this:s}}}),require.register("chai/lib/chai/utils/addProperty.js",function(t,e){e.exports=function(t,e,n){Object.defineProperty(t,e,{get:function(){var t=n.call(this);return void 0===t?this:t},configurable:!0})}}),require.register("chai/lib/chai/utils/flag.js",function(t,e){e.exports=function(t,e,n){var r=t.__flags||(t.__flags=Object.create(null));return 3!==arguments.length?r[e]:void(r[e]=n)}}),require.register("chai/lib/chai/utils/getActual.js",function(t,e){e.exports=function(t,e){return e.length>4?e[4]:t._obj}}),require.register("chai/lib/chai/utils/getEnumerableProperties.js",function(t,e){e.exports=function(t){var e=[];for(var n in t)e.push(n);return e}}),require.register("chai/lib/chai/utils/getMessage.js",function(t,e){var n=require("chai/lib/chai/utils/flag.js"),r=require("chai/lib/chai/utils/getActual.js"),i=(require("chai/lib/chai/utils/inspect.js"),require("chai/lib/chai/utils/objDisplay.js"));e.exports=function(t,e){var o=n(t,"negate"),s=n(t,"object"),a=e[3],u=r(t,e),c=o?e[2]:e[1],l=n(t,"message");return"function"==typeof c&&(c=c()),c=c||"",c=c.replace(/#{this}/g,i(s)).replace(/#{act}/g,i(u)).replace(/#{exp}/g,i(a)),l?l+": "+c:c}}),require.register("chai/lib/chai/utils/getName.js",function(t,e){e.exports=function(t){if(t.name)return t.name;var e=/^\s?function ([^(]*)\(/.exec(t);return e&&e[1]?e[1]:""}}),require.register("chai/lib/chai/utils/getPathValue.js",function(t,e){function n(t){var e=t.replace(/\[/g,".["),n=e.match(/(\\\.|[^.]+?)+/g);return n.map(function(t){var e=/\[(\d+)\]$/,n=e.exec(t);return n?{i:parseFloat(n[1])}:{p:t}})}function r(t,e){for(var n,r=e,i=0,o=t.length;o>i;i++){var s=t[i];r?("undefined"!=typeof s.p?r=r[s.p]:"undefined"!=typeof s.i&&(r=r[s.i]),i==o-1&&(n=r)):n=void 0}return n}e.exports=function(t,e){var i=n(t);return r(i,e)}}),require.register("chai/lib/chai/utils/getProperties.js",function(t,e){e.exports=function(){function t(t){-1===e.indexOf(t)&&e.push(t)}for(var e=Object.getOwnPropertyNames(subject),n=Object.getPrototypeOf(subject);null!==n;)Object.getOwnPropertyNames(n).forEach(t),n=Object.getPrototypeOf(n);return e}}),require.register("chai/lib/chai/utils/index.js",function(t,e){var t=e.exports={};t.test=require("chai/lib/chai/utils/test.js"),t.type=require("chai/lib/chai/utils/type.js"),t.getMessage=require("chai/lib/chai/utils/getMessage.js"),t.getActual=require("chai/lib/chai/utils/getActual.js"),t.inspect=require("chai/lib/chai/utils/inspect.js"),t.objDisplay=require("chai/lib/chai/utils/objDisplay.js"),t.flag=require("chai/lib/chai/utils/flag.js"),t.transferFlags=require("chai/lib/chai/utils/transferFlags.js"),t.eql=require("chaijs~deep-eql@0.1.3"),t.getPathValue=require("chai/lib/chai/utils/getPathValue.js"),t.getName=require("chai/lib/chai/utils/getName.js"),t.addProperty=require("chai/lib/chai/utils/addProperty.js"),t.addMethod=require("chai/lib/chai/utils/addMethod.js"),t.overwriteProperty=require("chai/lib/chai/utils/overwriteProperty.js"),t.overwriteMethod=require("chai/lib/chai/utils/overwriteMethod.js"),t.addChainableMethod=require("chai/lib/chai/utils/addChainableMethod.js"),t.overwriteChainableMethod=require("chai/lib/chai/utils/overwriteChainableMethod.js")}),require.register("chai/lib/chai/utils/inspect.js",function(t,e){function n(t,e,n){var i={showHidden:e,seen:[],stylize:function(t){return t}};return r(i,t,"undefined"==typeof n?2:n)}function r(e,n,p){if(n&&"function"==typeof n.inspect&&n.inspect!==t.inspect&&(!n.constructor||n.constructor.prototype!==n)){var b=n.inspect(p);return"string"!=typeof b&&(b=r(e,b,p)),b}var y=i(e,n);if(y)return y;if(m(n)){if("outerHTML"in n)return n.outerHTML;try{if(document.xmlVersion){var w=new XMLSerializer;return w.serializeToString(n)}var x="http://www.w3.org/1999/xhtml",j=document.createElementNS(x,"_");return j.appendChild(n.cloneNode(!1)),html=j.innerHTML.replace("><",">"+n.innerHTML+"<"),j.innerHTML="",html}catch(E){}}var T=v(n),k=e.showHidden?g(n):T;if(0===k.length||f(n)&&(1===k.length&&"stack"===k[0]||2===k.length&&"description"===k[0]&&"stack"===k[1])){if("function"==typeof n){var q=d(n),_=q?": "+q:"";return e.stylize("[Function"+_+"]","special")}if(l(n))return e.stylize(RegExp.prototype.toString.call(n),"regexp");if(h(n))return e.stylize(Date.prototype.toUTCString.call(n),"date");if(f(n))return o(n)}var O="",A=!1,S=["{","}"];if(c(n)&&(A=!0,S=["[","]"]),"function"==typeof n){var q=d(n),_=q?": "+q:"";O=" [Function"+_+"]"}if(l(n)&&(O=" "+RegExp.prototype.toString.call(n)),h(n)&&(O=" "+Date.prototype.toUTCString.call(n)),f(n))return o(n);if(0===k.length&&(!A||0==n.length))return S[0]+O+S[1];if(0>p)return l(n)?e.stylize(RegExp.prototype.toString.call(n),"regexp"):e.stylize("[Object]","special");e.seen.push(n);var M;return M=A?s(e,n,p,T,k):k.map(function(t){return a(e,n,p,T,t,A)}),e.seen.pop(),u(M,O,S)}function i(t,e){switch(typeof e){case"undefined":return t.stylize("undefined","undefined");case"string":var n="'"+JSON.stringify(e).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return t.stylize(n,"string");case"number":return 0===e&&1/e===-1/0?t.stylize("-0","number"):t.stylize(""+e,"number");case"boolean":return t.stylize(""+e,"boolean")}return null===e?t.stylize("null","null"):void 0}function o(t){return"["+Error.prototype.toString.call(t)+"]"}function s(t,e,n,r,i){for(var o=[],s=0,u=e.length;u>s;++s)o.push(Object.prototype.hasOwnProperty.call(e,String(s))?a(t,e,n,r,String(s),!0):"");return i.forEach(function(i){i.match(/^\d+$/)||o.push(a(t,e,n,r,i,!0))}),o}function a(t,e,n,i,o,s){var a,u;if(e.__lookupGetter__&&(e.__lookupGetter__(o)?u=e.__lookupSetter__(o)?t.stylize("[Getter/Setter]","special"):t.stylize("[Getter]","special"):e.__lookupSetter__(o)&&(u=t.stylize("[Setter]","special"))),i.indexOf(o)<0&&(a="["+o+"]"),u||(t.seen.indexOf(e[o])<0?(u=null===n?r(t,e[o],null):r(t,e[o],n-1),u.indexOf("\n")>-1&&(u=s?u.split("\n").map(function(t){return" "+t}).join("\n").substr(2):"\n"+u.split("\n").map(function(t){return" "+t}).join("\n"))):u=t.stylize("[Circular]","special")),"undefined"==typeof a){if(s&&o.match(/^\d+$/))return u;a=JSON.stringify(""+o),a.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=t.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=t.stylize(a,"string"))}return a+": "+u}function u(t,e,n){var r=0,i=t.reduce(function(t,e){return r++,e.indexOf("\n")>=0&&r++,t+e.length+1},0);return i>60?n[0]+(""===e?"":e+"\n ")+" "+t.join(",\n ")+" "+n[1]:n[0]+e+" "+t.join(", ")+" "+n[1]}function c(t){return Array.isArray(t)||"object"==typeof t&&"[object Array]"===p(t)}function l(t){return"object"==typeof t&&"[object RegExp]"===p(t)}function h(t){return"object"==typeof t&&"[object Date]"===p(t)}function f(t){return"object"==typeof t&&"[object Error]"===p(t)}function p(t){return Object.prototype.toString.call(t)}var d=require("chai/lib/chai/utils/getName.js"),g=require("chai/lib/chai/utils/getProperties.js"),v=require("chai/lib/chai/utils/getEnumerableProperties.js");e.exports=n;var m=function(t){return"object"==typeof HTMLElement?t instanceof HTMLElement:t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}}),require.register("chai/lib/chai/utils/objDisplay.js",function(t,e){var n=require("chai/lib/chai/utils/inspect.js"),r=require("chai/lib/chai/config.js");e.exports=function(t){var e=n(t),i=Object.prototype.toString.call(t);if(r.truncateThreshold&&e.length>=r.truncateThreshold){if("[object Function]"===i)return t.name&&""!==t.name?"[Function: "+t.name+"]":"[Function]";if("[object Array]"===i)return"[ Array("+t.length+") ]";if("[object Object]"===i){var o=Object.keys(t),s=o.length>2?o.splice(0,2).join(", ")+", ...":o.join(", ");return"{ Object ("+s+") }"}return e}return e}}),require.register("chai/lib/chai/utils/overwriteMethod.js",function(t,e){e.exports=function(t,e,n){var r=t[e],i=function(){return this};r&&"function"==typeof r&&(i=r),t[e]=function(){var t=n(i).apply(this,arguments);return void 0===t?this:t}}}),require.register("chai/lib/chai/utils/overwriteProperty.js",function(t,e){e.exports=function(t,e,n){var r=Object.getOwnPropertyDescriptor(t,e),i=function(){};r&&"function"==typeof r.get&&(i=r.get),Object.defineProperty(t,e,{get:function(){var t=n(i).call(this);return void 0===t?this:t},configurable:!0})}}),require.register("chai/lib/chai/utils/overwriteChainableMethod.js",function(t,e){e.exports=function(t,e,n,r){var i=t.__methods[e],o=i.chainingBehavior;i.chainingBehavior=function(){var t=r(o).call(this);return void 0===t?this:t};var s=i.method;i.method=function(){var t=n(s).apply(this,arguments);return void 0===t?this:t}}}),require.register("chai/lib/chai/utils/test.js",function(t,e){var n=require("chai/lib/chai/utils/flag.js");e.exports=function(t,e){var r=n(t,"negate"),i=e[0];return r?!i:i}}),require.register("chai/lib/chai/utils/transferFlags.js",function(t,e){e.exports=function(t,e,n){var r=t.__flags||(t.__flags=Object.create(null));e.__flags||(e.__flags=Object.create(null)),n=3===arguments.length?n:!0;for(var i in r)(n||"object"!==i&&"ssfi"!==i&&"message"!=i)&&(e.__flags[i]=r[i])}}),require.register("chai/lib/chai/utils/type.js",function(t,e){var n={"[object Arguments]":"arguments","[object Array]":"array","[object Date]":"date","[object Function]":"function","[object Number]":"number","[object RegExp]":"regexp","[object String]":"string"};e.exports=function(t){var e=Object.prototype.toString.call(t);return n[e]?n[e]:null===t?"null":void 0===t?"undefined":t===Object(t)?"object":typeof t}}),"object"==typeof exports?module.exports=require("chai"):"function"==typeof define&&define.amd?define("chai",[],function(){return require("chai")}):(this||window).chai=require("chai")}(),function(t){function e(t,e){return f.isUndefined(e)?""+e:!f.isNumber(e)||!isNaN(e)&&isFinite(e)?f.isFunction(e)||f.isRegExp(e)?e.toString():e:e.toString()}function n(t,e){return f.isString(t)?t.length=0;o--)if(u[o]!=c[o])return!1;for(o=u.length-1;o>=0;o--)if(i=u[o],!s(t[i],e[i]))return!1;return!0}function c(t,e){return t&&e?"[object RegExp]"==Object.prototype.toString.call(e)?e.test(t):t instanceof e?!0:e.call({},t)===!0?!0:!1:!1}function l(t,e,n,r){var o;f.isString(n)&&(r=n,n=null);try{e()}catch(s){o=s}if(r=(n&&n.name?" ("+n.name+").":".")+(r?" "+r:"."),t&&!o&&i(o,n,"Missing expected exception"+r),!t&&c(o,n)&&i(o,n,"Got unwanted exception"+r),t&&o&&n&&!c(o,n)||!t&&o)throw o}"undefined"==typeof t.exports&&(t.exports=t);var h=Object.create||function(t){function e(){}if(!t)throw Error("no type");return e.prototype=t,new e},f={inherits:function(t,e){t.super_=e,t.prototype=h(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})},isArray:function(t){return Array.isArray(t)},isBoolean:function(t){return"boolean"==typeof t},isNull:function(t){return null===t},isNullOrUndefined:function(t){return null==t},isNumber:function(t){return"number"==typeof t},isString:function(t){return"string"==typeof t},isSymbol:function(t){return"symbol"==typeof t},isUndefined:function(t){return void 0===t},isRegExp:function(t){return f.isObject(t)&&"[object RegExp]"===f.objectToString(t)},isObject:function(t){return"object"==typeof t&&null!==t},isDate:function(t){return f.isObject(t)&&"[object Date]"===f.objectToString(t)},isError:function(t){return isObject(t)&&("[object Error]"===objectToString(t)||t instanceof Error)},isFunction:function(t){return"function"==typeof t},isPrimitive:function(t){return null===t||"boolean"==typeof t||"number"==typeof t||"string"==typeof t||"symbol"==typeof t||"undefined"==typeof t},objectToString:function(t){return Object.prototype.toString.call(t)}},p=Array.prototype.slice,d=("function"==typeof Object.keys?Object.keys:function(t){var e=[];for(var n in t)e.push(n);return e},t.exports=o);d.AssertionError=function(t){this.name="AssertionError",this.actual=t.actual,this.expected=t.expected,this.operator=t.operator,t.message?(this.message=t.message,this.generatedMessage=!1):(this.message=r(this),this.generatedMessage=!0);var e=t.stackStartFunction||i;if(Error.captureStackTrace)Error.captureStackTrace(this,e);else try{this.stack=(new Error).stack.toString()}catch(n){}},f.inherits(d.AssertionError,Error),d.fail=i,d.ok=o,d.equal=function(t,e,n){t!=e&&i(t,e,n,"==",d.equal)},d.notEqual=function(t,e,n){t==e&&i(t,e,n,"!=",d.notEqual)},d.deepEqual=function(t,e,n){s(t,e)||i(t,e,n,"deepEqual",d.deepEqual)},d.notDeepEqual=function(t,e,n){s(t,e)&&i(t,e,n,"notDeepEqual",d.notDeepEqual)},d.strictEqual=function(t,e,n){t!==e&&i(t,e,n,"===",d.strictEqual)},d.notStrictEqual=function(t,e,n){t===e&&i(t,e,n,"!==",d.notStrictEqual)},d.throws=function(){l.apply(this,[!0].concat(p.call(arguments)))},d.doesNotThrow=function(){l.apply(this,[!1].concat(p.call(arguments)))},d.ifError=function(t){if(t)throw t},t.assert=t.exports,delete t.exports}(this);var div=document.createElement("div");div.id="mocha",document.body.appendChild(div);var g_quiet=process.env.quiet||!0;if("false"===g_quiet&&(g_quiet=!1),!g_quiet){var link=document.createElement("link");link.setAttribute("rel","stylesheet"),link.setAttribute("type","text/css"),link.setAttribute("href","../res/mocha.css"),document.getElementsByTagName("head")[0].appendChild(link)}var fs=require("fs"),path=require("path");mocha.setup({ui:"bdd"});var outputAsXML=function(){var t=process.env.out_dir;t||(t=fs.realpathSync("."),console.log("====Test results will be at: "+t));var e=0;if(window.XMLSerializer){var n=new XMLSerializer,r=process.cwd();r=r.substring(r.lastIndexOf(path.sep)+1);var i=path.join(t,r+".xml"),o=(document.getElementById("mocha-report"),document.getElementById("mocha")),s=n.serializeToString(o);s=decodeURIComponent(s),fs.writeFileSync(i,s)}var a=document.getElementById("mocha-stats"),u=a.getElementsByClassName("failures"),c=void 0,l="";return u&&u.length>0&&(c=u[0].getElementsByTagName("em"),c&&c.length>0&&(l=c[0].innerText,"0"!==l&&(e=1))),g_quiet&&process.exit(e),0};window.unitTestApplicationFailed=function(){describe("Manually verify the application",function(){it("Application should succeed",function(t){t("Application failed: "+appName)})})},window.unitTestApplicationSucceed=function(){describe("Manually verify the application",function(){it("Application should succeed",function(t){t()})})},window.unitTestApplicationTimeout=function(){describe("Manually verify the application",function(){it("Application should not timeout",function(t){t("Application timeout")})})},window.addEventListener("load",function(){mocha.run(),mocha.suite.afterAll(function(){outputAsXML()})}); \ No newline at end of file diff --git a/tests/automation/res/util.js b/tests/automation/res/util.js new file mode 100644 index 0000000000..9f0440571f --- /dev/null +++ b/tests/automation/res/util.js @@ -0,0 +1,98 @@ +var div = document.createElement('div'); +div.id = 'mocha'; +//div.style.visibility = 'hidden'; +document.body.appendChild(div); + +// useful when need to keep app stay on window: +// $ quiet=false nw +// +var g_quiet = process.env['quiet'] || true; +if (g_quiet === 'false') g_quiet = false; + +if (!g_quiet) { + var link = document.createElement('link'); + link.setAttribute('rel', 'stylesheet'); + link.setAttribute('type', 'text/css'); + link.setAttribute('href', '../res/mocha.css'); + document.getElementsByTagName('head')[0].appendChild(link); +} + +var fs = require('fs'); +var path = require('path'); + +mocha.setup({ui:'bdd'}); + +var outputAsXML = function() { + var outputDir = process.env['out_dir']; + if (!outputDir) { + outputDir = fs.realpathSync('.'); + console.log('====Test results will be at: ' + outputDir); + //return; + } + var ret = 0; + if (window.XMLSerializer) { + var xmlParser = new XMLSerializer(); + var appName = process.cwd(); + appName = appName.substring(appName.lastIndexOf(path.sep) + 1); + var outputPath = path.join(outputDir, appName + '.xml'); + var reportNode = document.getElementById('mocha-report'); + var mochaNode = document.getElementById('mocha'); + var data = xmlParser.serializeToString(mochaNode); //(reportNode); + //data = data.replace('/', '//'); + //data = data.replace('%20', ' '); + data = decodeURIComponent(data); + fs.writeFileSync(outputPath, data); + } + + // check failures + var stats = document.getElementById('mocha-stats'); + var failureNodes = stats.getElementsByClassName('failures'); + var failureNumNode = undefined; + var failures = ''; + + if (failureNodes && failureNodes.length > 0) { + failureNumNode = failureNodes[0].getElementsByTagName('em'); + if (failureNumNode && failureNumNode.length > 0) { + failures = failureNumNode[0].innerText; + if (failures !== '0') { + ret = 1; + } + } + } + + if (g_quiet) + process.exit(ret); + + return 0; +}; + +window.unitTestApplicationFailed = function() { + describe('Manually verify the application', function() { + it('Application should succeed', function(done){ + done('Application failed: ' + appName); + }); + }); +}; + +window.unitTestApplicationSucceed = function() { + describe('Manually verify the application', function() { + it('Application should succeed', function(done){ + done(); + }); + }); +}; + +window.unitTestApplicationTimeout = function() { + describe('Manually verify the application', function() { + it('Application should not timeout', function(done){ + done('Application timeout'); + }); + }); +}; + +window.addEventListener('load', function(){ + mocha.run(); + mocha.suite.afterAll(function(){ + outputAsXML(); + }); +}); diff --git a/tests/automation/run.sh b/tests/automation/run.sh new file mode 100755 index 0000000000..1f39745cfa --- /dev/null +++ b/tests/automation/run.sh @@ -0,0 +1,4 @@ +#!/bin/bash + +node mocha_test.js + diff --git a/tests/automation/sample/index.html b/tests/automation/sample/index.html new file mode 100644 index 0000000000..8f9c77e535 --- /dev/null +++ b/tests/automation/sample/index.html @@ -0,0 +1,18 @@ + + + + +hi + + + + + diff --git a/tests/automation/sample/mocha_test.js b/tests/automation/sample/mocha_test.js new file mode 100644 index 0000000000..2581ad091a --- /dev/null +++ b/tests/automation/sample/mocha_test.js @@ -0,0 +1,32 @@ +var assert = require('assert'); + +describe('sample-test', function() { + + beforeEach(function() { + console.log('before each'); + }); + + before(function() { + console.log('before'); + //assert.ok(false); + }); + + describe('#indexOf()', function() { // unit test group 1 + it('should return -1 when value is not presenttt', function() { // unit test 1.1 + assert.equal(-1, [1, 2, 3].indexOf(5)); + assert.equal(-1, [1, 2, 3].indexOf(6)); + assert.equal(1, [1, 2, 3].indexOf(2)); + }); + }); + + describe('#length', function() { // unit test group 2 + it('should return 3', function() { // unit test 2.1 + assert.equal(3, [1,2,3].length); + }); + it('should return 0', function() { // unit test 2.2 + assert.equal(0, ''.length); + }); + + }); + +}); diff --git a/tests/automation/sample/package.json b/tests/automation/sample/package.json new file mode 100644 index 0000000000..8748842da0 --- /dev/null +++ b/tests/automation/sample/package.json @@ -0,0 +1,4 @@ +{ +"name": "nw-#1236", +"main": "index.html" +} diff --git a/tests/automation/window/index.html b/tests/automation/window/index.html new file mode 100644 index 0000000000..f4cb6778bc --- /dev/null +++ b/tests/automation/window/index.html @@ -0,0 +1,59 @@ + + + + + Test Case for 'Window.focus' + + + +

          For now you should manually click the button to test the case

          + + + + + + + diff --git a/tests/automation/window/index1.html b/tests/automation/window/index1.html new file mode 100644 index 0000000000..0c6385bceb --- /dev/null +++ b/tests/automation/window/index1.html @@ -0,0 +1,19 @@ + + + + + new_win1 + + + +

          Please focus this before click the according button .

          + + diff --git a/tests/automation/window/index2.html b/tests/automation/window/index2.html new file mode 100644 index 0000000000..d4f09e42d1 --- /dev/null +++ b/tests/automation/window/index2.html @@ -0,0 +1,10 @@ + + + + + new_win2 + + +

          Please wait to be closed.

          + + diff --git a/tests/automation/window/mocha_test.js b/tests/automation/window/mocha_test.js new file mode 100644 index 0000000000..983cb6b705 --- /dev/null +++ b/tests/automation/window/mocha_test.js @@ -0,0 +1,30 @@ +var path = require('path'); +var assert = require('assert'); + +describe('window', function() { + this.timeout(0); + before(function(done) { + this.timeout(0); + + + var checkDone = function() { + if (test_done) { + done(); + } else { + setTimeout(function() {checkDone();}, 2000);; + } + }; + + checkDone(); + + }); + + describe('focus()', function() { + it('should focus on the window', function() { + for (var i = 0; i < 3; i++) { + console.log('win_c['+i+'] = '+ win_c[i]); + assert.notEqual(win_c[i], "0"); + } + }); + }); +}); diff --git a/tests/automation/window/package.json b/tests/automation/window/package.json new file mode 100644 index 0000000000..1d6d4d34f4 --- /dev/null +++ b/tests/automation/window/package.json @@ -0,0 +1,4 @@ +{ + "name": "nw-window-test", + "main": "index.html" +} From 85589775e8eca521caec8b70e81b277b55b564a2 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 26 Nov 2014 11:04:35 +0800 Subject: [PATCH 283/492] Fix #2671: act as node only when JS is provided --- src/shell_main_delegate.cc | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/shell_main_delegate.cc b/src/shell_main_delegate.cc index 7f149aec77..eb5827b988 100644 --- a/src/shell_main_delegate.cc +++ b/src/shell_main_delegate.cc @@ -136,7 +136,8 @@ bool ShellMainDelegate::BasicStartupComplete(int* exit_code) { if (args.size() > 0) { zip::ZipReader reader; FilePath fp(args[0]); - if (!command_line->HasSwitch(switches::kProcessType) && + if (fp.MatchesExtension(FILE_PATH_LITERAL(".js")) && + !command_line->HasSwitch(switches::kProcessType) && PathExists(fp) && !DirectoryExists(fp) && !reader.Open(fp)) { *exit_code = node::Start(command_line->argc0(), command_line->argv0()); return true; From 22e4cf6c0979392150408b8a5d4da65f30215344 Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 26 Nov 2014 13:18:55 +0800 Subject: [PATCH 284/492] bump version to 0.11.2 --- src/nw_version.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nw_version.h b/src/nw_version.h index cfb514b4ec..9b4bb1c031 100644 --- a/src/nw_version.h +++ b/src/nw_version.h @@ -24,7 +24,7 @@ #define NW_MAJOR_VERSION 0 #define NW_MINOR_VERSION 11 #define NW_PATCH_VERSION 2 -#define NW_VERSION_IS_RELEASE 0 +#define NW_VERSION_IS_RELEASE 1 #ifndef NW_STRINGIFY #define NW_STRINGIFY(n) NW_STRINGIFY_HELPER(n) From 75b7950f71c2f3c64f58c842ecbfeb6b5c6df1af Mon Sep 17 00:00:00 2001 From: Roger Date: Wed, 26 Nov 2014 21:18:47 +0800 Subject: [PATCH 285/492] [README] update for 0.11.2 --- CHANGELOG.md | 13 +++++++++++++ README.md | 8 ++++---- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fff02a6dd..2aca003671 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,16 @@ +0.11.2 / 11-26-2014 +=================== +- Support window transparency (#132, Thanks to Jefry Tedjokusumo) +- Fix: [Linux] broken window events (focus, blur, etc, #2631) +- Fix: memory leak on setting tray icon (#2666) +- Fix: child_process.fork() (#2664) +- Fix: bad Buffer created from strings from DOM (#1669, #2439) (Thank to Liu Cong) +- Fix: Segmentation fault by starting nw on command line with parameters #2671 +- Fix: crashes if http.request gets blocked with Little Snitch (mac only) #2585 +- Fix: Windows 7 64/32 - frame doesn't show #2657 +- Fix: AutoFill Crashes NodeWebkit #2653 +- Fix "Cancel Desktop Notification" for all platform. and implement it for win8 (toast notification) + 0.11.1 / 11-20-2014 =================== - add nwsnapshot diff --git a/README.md b/README.md index 408782318d..d4464605cb 100644 --- a/README.md +++ b/README.md @@ -21,11 +21,11 @@ It's created and developed in the Intel Open Source Technology Center. * Available on Linux, Mac OS X and Windows ## Downloads -* **v0.11.1:** (Nov 20, 2014, based off of Node v0.11.13, Chromium 38.0.2125.104): [release notes](https://groups.google.com/d/msg/node-webkit/zR_ZWxMvDqs/kYOC7sJ7XOUJ) +* **v0.11.2:** (Nov 26, 2014, based off of Node v0.11.13, Chromium 38.0.2125.104): [release notes](https://groups.google.com/d/msg/node-webkit/hpG-AgsATTI/Oc-qhC3rMnkJ) - * Linux: [32bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-linux-x64.tar.gz) - * Windows: [32bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-win-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-win-x64.zip) - * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.1/node-webkit-v0.11.1-osx-x64.zip) + * Linux: [32bit](http://dl.node-webkit.org/v0.11.2/node-webkit-v0.11.2-linux-ia32.tar.gz) / [64bit](http://dl.node-webkit.org/v0.11.2/node-webkit-v0.11.2-linux-x64.tar.gz) + * Windows: [32bit](http://dl.node-webkit.org/v0.11.2/node-webkit-v0.11.2-win-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.2/node-webkit-v0.11.2-win-x64.zip) + * Mac 10.7+: [32bit](http://dl.node-webkit.org/v0.11.2/node-webkit-v0.11.2-osx-ia32.zip) / [64bit](http://dl.node-webkit.org/v0.11.2/node-webkit-v0.11.2-osx-x64.zip) * **0.8.6:** (Apr 18, 2014, based off of Node v0.10.22, Chrome 30.0.1599.66) **If your native Node module works only with Node v0.10, then you should use node-webkit v0.8.x, which is also a maintained branch. [More info](https://groups.google.com/d/msg/node-webkit/2OJ1cEMPLlA/09BvpTagSA0J)** [release notes](https://groups.google.com/d/msg/node-webkit/CLPkgfV-i7s/hwkkQuJ1kngJ) From 5d97202bd6556a6a52d2d0e783007a0343699361 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Thu, 27 Nov 2014 13:33:23 +0800 Subject: [PATCH 286/492] [Automation] Add functions to create TCP server and create child process. - Provide a util function createTCPServer() to create TCP & socket server. The server object should be released at the end of current process. - Provide a util function spawnChildProcess() to spawn a child process by inputing an absolute path of the new process. --- tests/automation/res/mocha_util.js | 2 +- tests/automation/res/util.js | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/tests/automation/res/mocha_util.js b/tests/automation/res/mocha_util.js index f60c4d4658..9e0828fecf 100644 --- a/tests/automation/res/mocha_util.js +++ b/tests/automation/res/mocha_util.js @@ -1,3 +1,3 @@ !function(){function t(e){var n=t.resolve(e),r=t.modules[n];if(!r)throw new Error('failed to require "'+e+'"');return r.exports||(r.exports={},r.call(r.exports,r,r.exports,t.relative(n))),r.exports}function e(){for(var t=(new r).getTime();h.length&&(new r).getTime()-t<100;)h.shift()();l=h.length?i(e,0):null}t.modules={},t.resolve=function(e){var n=e,r=e+".js",i=e+"/index.js";return t.modules[r]&&r||t.modules[i]&&i||n},t.register=function(e,n){t.modules[e]=n},t.relative=function(e){return function(n){if("."!=n.charAt(0))return t(n);var r=e.split("/"),i=n.split("/");r.pop();for(var o=0;o/g,">"),e=e.replace(/"/g,""")}var r=function(t){this.ignoreWhitespace=t};r.prototype={diff:function(e,n){if(n===e)return[{value:n}];if(!n)return[{value:e,removed:!0}];if(!e)return[{value:n,added:!0}];n=this.tokenize(n),e=this.tokenize(e);var r=n.length,i=e.length,o=r+i,s=[{newPos:-1,components:[]}],a=this.extractCommon(s[0],n,e,0);if(s[0].newPos+1>=r&&a+1>=i)return s[0].components;for(var u=1;o>=u;u++)for(var c=-1*u;u>=c;c+=2){var l,h=s[c-1],f=s[c+1];a=(f?f.newPos:0)-c,h&&(s[c-1]=void 0);var p=h&&h.newPos+1=0&&i>a;if(p||d){!p||d&&h.newPos=r&&a+1>=i)return l.components;s[c]=l}else s[c]=void 0}},pushComponent:function(t,e,n,r){var i=t[t.length-1];i&&i.added===n&&i.removed===r?t[t.length-1]={value:this.join(i.value,e),added:n,removed:r}:t.push({value:e,added:n,removed:r})},extractCommon:function(t,e,n,r){for(var i=e.length,o=n.length,s=t.newPos,a=s-r;i>s+1&&o>a+1&&this.equals(e[s+1],n[a+1]);)s++,a++,this.pushComponent(t.components,e[s],void 0,void 0);return t.newPos=s,a},equals:function(t,e){var n=/\S/;return!this.ignoreWhitespace||n.test(t)||n.test(e)?t===e:!0},join:function(t,e){return t+e},tokenize:function(t){return t}};var i=new r,o=new r(!0),s=new r;o.tokenize=s.tokenize=function(t){return e(t.split(/(\s+|\b)/))};var a=new r(!0);a.tokenize=function(t){return e(t.split(/([{}:;,]|\s+)/))};var u=new r;return u.tokenize=function(t){return t.split(/^/m)},{Diff:r,diffChars:function(t,e){return i.diff(t,e)},diffWords:function(t,e){return o.diff(t,e)},diffWordsWithSpace:function(t,e){return s.diff(t,e)},diffLines:function(t,e){return u.diff(t,e)},diffCss:function(t,e){return a.diff(t,e)},createPatch:function(t,e,n,r,i){function o(t){return t.map(function(t){return" "+t})}function s(t,e,n){var r=c[c.length-2],i=e===c.length-2,o=e===c.length-3&&(n.added!==r.added||n.removed!==r.removed);/\n$/.test(n.value)||!i&&!o||t.push("\\ No newline at end of file")}var a=[];a.push("Index: "+t),a.push("==================================================================="),a.push("--- "+t+("undefined"==typeof r?"":" "+r)),a.push("+++ "+t+("undefined"==typeof i?"":" "+i));var c=u.diff(e,n);c[c.length-1].value||c.pop(),c.push({value:"",lines:[]});for(var l=0,h=0,f=[],p=1,d=1,g=0;g=0;s--){for(var c=r[s],l=0;l"):i.removed&&e.push(""),e.push(n(i.value)),i.added?e.push(""):i.removed&&e.push("")}return e.join("")},convertChangesToDMP:function(t){for(var e,n=[],r=0;ro;o++)if(r[o]===e||r[o].listener&&r[o].listener===e){i=o;break}if(0>i)return this;r.splice(i,1),r.length||delete this.$events[t]}else(r===e||r.listener&&r.listener===e)&&delete this.$events[t]}return this},r.prototype.removeAllListeners=function(t){return void 0===t?(this.$events={},this):(this.$events&&this.$events[t]&&(this.$events[t]=null),this)},r.prototype.listeners=function(t){return this.$events||(this.$events={}),this.$events[t]||(this.$events[t]=[]),n(this.$events[t])||(this.$events[t]=[this.$events[t]]),this.$events[t]},r.prototype.emit=function(t){if(!this.$events)return!1;var e=this.$events[t];if(!e)return!1;var r=[].slice.call(arguments,1);if("function"==typeof e)e.apply(this,r);else{if(!n(e))return!1;for(var i=e.slice(),o=0,s=i.length;s>o;o++)i[o].apply(this,r)}return!0}}),t.register("browser/fs.js",function(){}),t.register("browser/glob.js",function(){}),t.register("browser/path.js",function(){}),t.register("browser/progress.js",function(t){function e(){this.percent=0,this.size(0),this.fontSize(11),this.font("helvetica, arial, sans-serif")}t.exports=e,e.prototype.size=function(t){return this._size=t,this},e.prototype.text=function(t){return this._text=t,this},e.prototype.fontSize=function(t){return this._fontSize=t,this},e.prototype.font=function(t){return this._font=t,this},e.prototype.update=function(t){return this.percent=t,this},e.prototype.draw=function(t){try{var e=Math.min(this.percent,100),n=this._size,r=n/2,i=r,o=r,s=r-1,a=this._fontSize;t.font=a+"px "+this._font;var u=2*Math.PI*(e/100);t.clearRect(0,0,n,n),t.strokeStyle="#9f9f9f",t.beginPath(),t.arc(i,o,s,0,u,!1),t.stroke(),t.strokeStyle="#eee",t.beginPath(),t.arc(i,o,s-1,0,u,!0),t.stroke();var c=this._text||(0|e)+"%",l=t.measureText(c).width;t.fillText(c,i-l/2+1,o+a/2-1)}catch(h){}return this}}),t.register("browser/tty.js",function(t,e){e.isatty=function(){return!0},e.getWindowSize=function(){return"innerHeight"in n?[n.innerHeight,n.innerWidth]:[640,480]}}),t.register("context.js",function(t){function e(){}t.exports=e,e.prototype.runnable=function(t){return 0==arguments.length?this._runnable:(this.test=this._runnable=t,this)},e.prototype.timeout=function(t){return 0===arguments.length?this.runnable().timeout():(this.runnable().timeout(t),this)},e.prototype.enableTimeouts=function(t){return this.runnable().enableTimeouts(t),this},e.prototype.slow=function(t){return this.runnable().slow(t),this},e.prototype.inspect=function(){return JSON.stringify(this,function(t,e){return"_runnable"!=t&&"test"!=t?e:void 0},2)}}),t.register("hook.js",function(t,e,n){function r(t,e){o.call(this,t,e),this.type="hook"}function i(){}var o=n("./runnable");t.exports=r,i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r,r.prototype.error=function(t){if(0==arguments.length){var t=this._error;return this._error=null,t}this._error=t}}),t.register("interfaces/bdd.js",function(t,e,n){var r=n("../suite"),i=n("../test"),o=(n("../utils"),n("browser/escape-string-regexp"));t.exports=function(t){var e=[t];t.on("pre-require",function(t,n,s){t.before=function(t,n){e[0].beforeAll(t,n)},t.after=function(t,n){e[0].afterAll(t,n)},t.beforeEach=function(t,n){e[0].beforeEach(t,n)},t.afterEach=function(t,n){e[0].afterEach(t,n)},t.describe=t.context=function(t,i){var o=r.create(e[0],t);return o.file=n,e.unshift(o),i.call(o),e.shift(),o},t.xdescribe=t.xcontext=t.describe.skip=function(t,n){var i=r.create(e[0],t);i.pending=!0,e.unshift(i),n.call(i),e.shift()},t.describe.only=function(e,n){var r=t.describe(e,n);return s.grep(r.fullTitle()),r},t.it=t.specify=function(t,r){var o=e[0];o.pending&&(r=null);var s=new i(t,r);return s.file=n,o.addTest(s),s},t.it.only=function(e,n){var r=t.it(e,n),i="^"+o(r.fullTitle())+"$";return s.grep(new RegExp(i)),r},t.xit=t.xspecify=t.it.skip=function(e){t.it(e)}})}}),t.register("interfaces/exports.js",function(t,e,n){var r=n("../suite"),i=n("../test");t.exports=function(t){function e(t,o){var s;for(var a in t)if("function"==typeof t[a]){var u=t[a];switch(a){case"before":n[0].beforeAll(u);break;case"after":n[0].afterAll(u);break;case"beforeEach":n[0].beforeEach(u);break;case"afterEach":n[0].afterEach(u);break;default:var c=new i(a,u);c.file=o,n[0].addTest(c)}}else s=r.create(n[0],a),n.unshift(s),e(t[a]),n.shift()}var n=[t];t.on("require",e)}}),t.register("interfaces/index.js",function(t,e,n){e.bdd=n("./bdd"),e.tdd=n("./tdd"),e.qunit=n("./qunit"),e.exports=n("./exports")}),t.register("interfaces/qunit.js",function(t,e,n){{var r=n("../suite"),i=n("../test"),o=n("browser/escape-string-regexp");n("../utils")}t.exports=function(t){var e=[t];t.on("pre-require",function(t,n,s){t.before=function(t,n){e[0].beforeAll(t,n)},t.after=function(t,n){e[0].afterAll(t,n)},t.beforeEach=function(t,n){e[0].beforeEach(t,n)},t.afterEach=function(t,n){e[0].afterEach(t,n)},t.suite=function(t){e.length>1&&e.shift();var i=r.create(e[0],t);return i.file=n,e.unshift(i),i},t.suite.only=function(e,n){var r=t.suite(e,n);s.grep(r.fullTitle())},t.test=function(t,r){var o=new i(t,r);return o.file=n,e[0].addTest(o),o},t.test.only=function(e,n){var r=t.test(e,n),i="^"+o(r.fullTitle())+"$";s.grep(new RegExp(i))},t.test.skip=function(e){t.test(e)}})}}),t.register("interfaces/tdd.js",function(t,e,n){{var r=n("../suite"),i=n("../test"),o=n("browser/escape-string-regexp");n("../utils")}t.exports=function(t){var e=[t];t.on("pre-require",function(t,n,s){t.setup=function(t,n){e[0].beforeEach(t,n)},t.teardown=function(t,n){e[0].afterEach(t,n)},t.suiteSetup=function(t,n){e[0].beforeAll(t,n)},t.suiteTeardown=function(t,n){e[0].afterAll(t,n)},t.suite=function(t,i){var o=r.create(e[0],t);return o.file=n,e.unshift(o),i.call(o),e.shift(),o},t.suite.skip=function(t,n){var i=r.create(e[0],t);i.pending=!0,e.unshift(i),n.call(i),e.shift()},t.suite.only=function(e,n){var r=t.suite(e,n);s.grep(r.fullTitle())},t.test=function(t,r){var o=e[0];o.pending&&(r=null);var s=new i(t,r);return s.file=n,o.addTest(s),s},t.test.only=function(e,n){var r=t.test(e,n),i="^"+o(r.fullTitle())+"$";s.grep(new RegExp(i))},t.test.skip=function(e){t.test(e)}})}}),t.register("mocha.js",function(t,e,r){function i(t){return __dirname+"/../images/"+t+".png"}function s(t){t=t||{},this.files=[],this.options=t,this.grep(t.grep),this.suite=new e.Suite("",new e.Context),this.ui(t.ui),this.bail(t.bail),this.reporter(t.reporter),null!=t.timeout&&this.timeout(t.timeout),this.useColors(t.useColors),null!==t.enableTimeouts&&this.enableTimeouts(t.enableTimeouts),t.slow&&this.slow(t.slow),this.suite.on("pre-require",function(t){e.afterEach=t.afterEach||t.teardown,e.after=t.after||t.suiteTeardown,e.beforeEach=t.beforeEach||t.setup,e.before=t.before||t.suiteSetup,e.describe=t.describe||t.suite,e.it=t.it||t.test,e.setup=t.setup||t.beforeEach,e.suiteSetup=t.suiteSetup||t.before,e.suiteTeardown=t.suiteTeardown||t.after,e.suite=t.suite||t.describe,e.teardown=t.teardown||t.afterEach,e.test=t.test||t.it})}var a=r("browser/path"),u=r("browser/escape-string-regexp"),c=r("./utils");if(e=t.exports=s,"undefined"!=typeof o&&"function"==typeof o.cwd){var l=a.join,h=o.cwd();t.paths.push(h,l(h,"node_modules"))}e.utils=c,e.interfaces=r("./interfaces"),e.reporters=r("./reporters"),e.Runnable=r("./runnable"),e.Context=r("./context"),e.Runner=r("./runner"),e.Suite=r("./suite"),e.Hook=r("./hook"),e.Test=r("./test"),s.prototype.bail=function(t){return 0==arguments.length&&(t=!0),this.suite.bail(t),this},s.prototype.addFile=function(t){return this.files.push(t),this},s.prototype.reporter=function(t){if("function"==typeof t)this._reporter=t;else{t=t||"spec";var e;try{e=r("./reporters/"+t)}catch(n){}if(!e)try{e=r(t)}catch(n){}if(e||"teamcity"!==t||console.warn("The Teamcity reporter was moved to a package named mocha-teamcity-reporter (https://npmjs.org/package/mocha-teamcity-reporter)."),!e)throw new Error('invalid reporter "'+t+'"');this._reporter=e}return this},s.prototype.ui=function(t){if(t=t||"bdd",this._ui=e.interfaces[t],!this._ui)try{this._ui=r(t)}catch(n){}if(!this._ui)throw new Error('invalid interface "'+t+'"');return this._ui=this._ui(this.suite),this},s.prototype.loadFiles=function(t){var e=this,i=this.suite,o=this.files.length;this.files.forEach(function(s){s=a.resolve(s),i.emit("pre-require",n,s,e),i.emit("require",r(s),s,e),i.emit("post-require",n,s,e),--o||t&&t()})},s.prototype._growl=function(t,e){var n=r("growl");t.on("end",function(){var r=e.stats;if(r.failures){var o=r.failures+" of "+t.total+" tests failed";n(o,{name:"mocha",title:"Failed",image:i("error")})}else n(r.passes+" tests passed in "+r.duration+"ms",{name:"mocha",title:"Passed",image:i("ok")})})},s.prototype.grep=function(t){return this.options.grep="string"==typeof t?new RegExp(u(t)):t,this},s.prototype.invert=function(){return this.options.invert=!0,this},s.prototype.ignoreLeaks=function(t){return this.options.ignoreLeaks=!!t,this},s.prototype.checkLeaks=function(){return this.options.ignoreLeaks=!1,this},s.prototype.growl=function(){return this.options.growl=!0,this},s.prototype.globals=function(t){return this.options.globals=(this.options.globals||[]).concat(t),this},s.prototype.useColors=function(t){return this.options.useColors=arguments.length&&void 0!=t?t:!0,this},s.prototype.useInlineDiffs=function(t){return this.options.useInlineDiffs=arguments.length&&void 0!=t?t:!1,this},s.prototype.timeout=function(t){return this.suite.timeout(t),this},s.prototype.slow=function(t){return this.suite.slow(t),this},s.prototype.enableTimeouts=function(t){return this.suite.enableTimeouts(arguments.length&&void 0!==t?t:!0),this},s.prototype.asyncOnly=function(){return this.options.asyncOnly=!0,this},s.prototype.noHighlighting=function(){return this.options.noHighlighting=!0,this},s.prototype.run=function(t){this.files.length&&this.loadFiles();var n=this.suite,r=this.options;r.files=this.files;var i=new e.Runner(n),o=new this._reporter(i,r);return i.ignoreLeaks=!1!==r.ignoreLeaks,i.asyncOnly=r.asyncOnly,r.grep&&i.grep(r.grep,r.invert),r.globals&&i.globals(r.globals),r.growl&&this._growl(i,o),e.reporters.Base.useColors=r.useColors,e.reporters.Base.inlineDiffs=r.useInlineDiffs,i.run(t)}}),t.register("ms.js",function(t){function e(t){var e=/^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(t);if(e){var n=parseFloat(e[1]),r=(e[2]||"ms").toLowerCase();switch(r){case"years":case"year":case"y":return n*c;case"days":case"day":case"d":return n*u;case"hours":case"hour":case"h":return n*a;case"minutes":case"minute":case"m":return n*s;case"seconds":case"second":case"s":return n*o;case"ms":return n}}}function n(t){return t>=u?Math.round(t/u)+"d":t>=a?Math.round(t/a)+"h":t>=s?Math.round(t/s)+"m":t>=o?Math.round(t/o)+"s":t+"ms"}function r(t){return i(t,u,"day")||i(t,a,"hour")||i(t,s,"minute")||i(t,o,"second")||t+" ms"}function i(t,e,n){return e>t?void 0:1.5*e>t?Math.floor(t/e)+" "+n:Math.ceil(t/e)+" "+n+"s"}var o=1e3,s=60*o,a=60*s,u=24*a,c=365.25*u;t.exports=function(t,i){return i=i||{},"string"==typeof t?e(t):i["long"]?r(t):n(t)}}),t.register("reporters/base.js",function(t,e,r){function i(t){var e=this.stats={suites:0,tests:0,passes:0,pending:0,failures:0},n=this.failures=[];t&&(this.runner=t,t.stats=e,t.on("start",function(){e.start=new m}),t.on("suite",function(t){e.suites=e.suites||0,t.root||e.suites++}),t.on("test end",function(){e.tests=e.tests||0,e.tests++}),t.on("pass",function(t){e.passes=e.passes||0;var n=t.slow()/2;t.speed=t.duration>t.slow()?"slow":t.duration>n?"medium":"fast",e.passes++}),t.on("fail",function(t,r){e.failures=e.failures||0,e.failures++,t.err=r,n.push(t)}),t.on("end",function(){e.end=new m,e.duration=new m-e.start}),t.on("pending",function(){e.pending++}))}function s(t,e){return t=String(t),Array(e-t.length+1).join(" ")+t}function a(t,e){var n=c(t,"WordsWithSpace",e),r=n.split("\n");if(r.length>4){var i=String(r.length).length;n=r.map(function(t,e){return s(++e,i)+" | "+t}).join("\n")}return n="\n"+y("diff removed","actual")+" "+y("diff added","expected")+"\n\n"+n+"\n",n=n.replace(/^/gm," ")}function u(t,e){function n(t){return e&&(t=l(t)),"+"===t[0]?i+h("diff added",t):"-"===t[0]?i+h("diff removed",t):t.match(/\@\@/)?null:t.match(/\\ No newline/)?null:i+t}function r(t){return null!=t}var i=" ";msg=d.createPatch("string",t.actual,t.expected);var o=msg.split("\n").splice(4);return"\n "+h("diff added","+ expected")+" "+h("diff removed","- actual")+"\n\n"+o.map(n).filter(r).join("\n")}function c(t,e,n){var r=n?l(t.actual):t.actual,i=n?l(t.expected):t.expected;return d["diff"+e](r,i).map(function(t){return t.added?h("diff added",t.value):t.removed?h("diff removed",t.value):t.value}).join("")}function l(t){return t.replace(/\t/g,"").replace(/\r/g,"").replace(/\n/g,"\n")}function h(t,e){return e.split("\n").map(function(e){return y(t,e)}).join("\n")}function f(t,e){return t=Object.prototype.toString.call(t),e=Object.prototype.toString.call(e),t==e}var p=r("browser/tty"),d=r("browser/diff"),g=r("../ms"),v=r("../utils"),m=n.Date,b=(n.setTimeout,n.setInterval,n.clearTimeout,n.clearInterval,p.isatty(1)&&p.isatty(2));e=t.exports=i,e.useColors=b||void 0!==o.env.MOCHA_COLORS,e.inlineDiffs=!1,e.colors={pass:90,fail:31,"bright pass":92,"bright fail":91,"bright yellow":93,pending:36,suite:0,"error title":0,"error message":31,"error stack":90,checkmark:32,fast:90,medium:33,slow:31,green:32,light:90,"diff gutter":90,"diff added":42,"diff removed":41},e.symbols={ok:"✓",err:"✖",dot:"․"},"win32"==o.platform&&(e.symbols.ok="√",e.symbols.err="×",e.symbols.dot=".");var y=e.color=function(t,n){return e.useColors?"["+e.colors[t]+"m"+n+"":n};e.window={width:b?o.stdout.getWindowSize?o.stdout.getWindowSize(1)[0]:p.getWindowSize()[1]:75},e.cursor={hide:function(){b&&o.stdout.write("[?25l")},show:function(){b&&o.stdout.write("[?25h")},deleteLine:function(){b&&o.stdout.write("")},beginningOfLine:function(){b&&o.stdout.write("")},CR:function(){b?(e.cursor.deleteLine(),e.cursor.beginningOfLine()):o.stdout.write("\r")}},e.list=function(t){console.error(),t.forEach(function(t,n){var r=y("error title"," %s) %s:\n")+y("error message"," %s")+y("error stack","\n%s\n"),i=t.err,o=i.message||"",s=i.stack||o,c=s.indexOf(o)+o.length,l=s.slice(0,c),h=i.actual,p=i.expected,d=!0;if(i.uncaught&&(l="Uncaught "+l),i.showDiff&&f(h,p)&&(d=!1,i.actual=h=v.stringify(h),i.expected=p=v.stringify(p)),i.showDiff&&"string"==typeof h&&"string"==typeof p){r=y("error title"," %s) %s:\n%s")+y("error stack","\n%s\n");var g=o.match(/^([^:]+): expected/);l="\n "+y("error message",g?g[1]:l),l+=e.inlineDiffs?a(i,d):u(i,d)}s=s.slice(c?c+1:c).replace(/^/gm," "),console.error(r,n+1,t.fullTitle(),l,s)})},i.prototype.epilogue=function(){var t,e=this.stats;console.log(),t=y("bright pass"," ")+y("green"," %d passing")+y("light"," (%s)"),console.log(t,e.passes||0,g(e.duration)),e.pending&&(t=y("pending"," ")+y("pending"," %d pending"),console.log(t,e.pending)),e.failures&&(t=y("fail"," %d failing"),console.error(t,e.failures),i.list(this.failures),console.error()),console.log()}}),t.register("reporters/doc.js",function(t,e,n){function r(t){function e(){return Array(n).join(" ")}i.call(this,t);var n=(this.stats,t.total,2);t.on("suite",function(t){t.root||(++n,console.log('%s
          ',e()),++n,console.log("%s

          %s

          ",e(),o.escape(t.title)),console.log("%s
          ",e()))}),t.on("suite end",function(t){t.root||(console.log("%s
          ",e()),--n,console.log("%s
          ",e()),--n)}),t.on("pass",function(t){console.log("%s
          %s
          ",e(),o.escape(t.title));var n=o.escape(o.clean(t.fn.toString()));console.log("%s
          %s
          ",e(),n)}),t.on("fail",function(t,n){console.log('%s
          %s
          ',e(),o.escape(t.title));var r=o.escape(o.clean(t.fn.toString()));console.log('%s
          %s
          ',e(),r),console.log('%s
          %s
          ',e(),o.escape(n))})}var i=n("./base"),o=n("../utils");e=t.exports=r}),t.register("reporters/dot.js",function(t,e,n){function r(t){s.call(this,t);var e=this,n=(this.stats,.75*s.window.width|0),r=-1;t.on("start",function(){o.stdout.write("\n ")}),t.on("pending",function(){++r%n==0&&o.stdout.write("\n "),o.stdout.write(a("pending",s.symbols.dot))}),t.on("pass",function(t){++r%n==0&&o.stdout.write("\n "),o.stdout.write("slow"==t.speed?a("bright yellow",s.symbols.dot):a(t.speed,s.symbols.dot))}),t.on("fail",function(){++r%n==0&&o.stdout.write("\n "),o.stdout.write(a("fail",s.symbols.dot))}),t.on("end",function(){console.log(),e.epilogue()})}function i(){}var s=n("./base"),a=s.color;e=t.exports=r,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/html-cov.js",function(t,e,n){function r(t){var e=n("jade"),r=__dirname+"/templates/coverage.jade",u=a.readFileSync(r,"utf8"),c=e.compile(u,{filename:r}),l=this;s.call(this,t,!1),t.on("end",function(){o.stdout.write(c({cov:l.cov,coverageClass:i}))})}function i(t){return t>=75?"high":t>=50?"medium":t>=25?"low":"terrible"}var s=n("./json-cov"),a=n("browser/fs");e=t.exports=r}),t.register("reporters/html.js",function(t,e,r){function i(t){h.call(this,t);var e,n,r=this,i=this.stats,m=(t.total,s(v)),b=m.getElementsByTagName("li"),y=b[1].getElementsByTagName("em")[0],w=b[1].getElementsByTagName("a")[0],x=b[2].getElementsByTagName("em")[0],j=b[2].getElementsByTagName("a")[0],E=b[3].getElementsByTagName("em")[0],T=m.getElementsByTagName("canvas")[0],k=s('
            '),q=[k],_=document.getElementById("mocha");if(T.getContext){var O=window.devicePixelRatio||1;T.style.width=T.width,T.style.height=T.height,T.width*=O,T.height*=O,n=T.getContext("2d"),n.scale(O,O),e=new p}return _?(l(w,"click",function(){u();var t=/pass/.test(k.className)?"":" pass";k.className=k.className.replace(/fail|pass/g,"")+t,k.className.trim()&&a("test pass")}),l(j,"click",function(){u();var t=/fail/.test(k.className)?"":" fail";k.className=k.className.replace(/fail|pass/g,"")+t,k.className.trim()&&a("test fail")}),_.appendChild(m),_.appendChild(k),e&&e.size(40),t.on("suite",function(t){if(!t.root){var e=r.suiteURL(t),n=s('
          • %s

          • ',e,d(t.title));q[0].appendChild(n),q.unshift(document.createElement("ul")),n.appendChild(q[0])}}),t.on("suite end",function(t){t.root||q.shift()}),t.on("fail",function(e){"hook"==e.type&&t.emit("test end",e)}),void t.on("test end",function(t){var o=i.tests/this.total*100|0;e&&e.update(o).draw(n);var a=new g-i.start;if(c(y,i.passes),c(x,i.failures),c(E,(a/1e3).toFixed(2)),"passed"==t.state)var u=r.testURL(t),h=s('
          • %e%ems

          • ',t.speed,t.title,t.duration,u);else if(t.pending)var h=s('
          • %e

          • ',t.title);else{var h=s('
          • %e

          • ',t.title,encodeURIComponent(t.fullTitle())),p=t.err.stack||t.err.toString();~p.indexOf(t.err.message)||(p=t.err.message+"\n"+p),"[object Error]"==p&&(p=t.err.message),!t.err.stack&&t.err.sourceURL&&void 0!==t.err.line&&(p+="\n("+t.err.sourceURL+":"+t.err.line+")"),h.appendChild(s('
            %e
            ',p))}if(!t.pending){var d=h.getElementsByTagName("h2")[0];l(d,"click",function(){v.style.display="none"==v.style.display?"block":"none"});var v=s("
            %e
            ",f.clean(t.fn.toString()));h.appendChild(v),v.style.display="none"}q[0]&&q[0].appendChild(h)})):o("#mocha div missing, add it to your document")}function o(t){document.body.appendChild(s('
            %s
            ',t))}function s(t){var e=arguments,n=document.createElement("div"),r=1;return n.innerHTML=t.replace(/%([se])/g,function(t,n){switch(n){case"s":return String(e[r++]);case"e":return d(e[r++])}}),n.firstChild}function a(t){for(var e=document.getElementsByClassName("suite"),n=0;n0&&(e.coverage=e.hits/e.sloc*100),e}function a(t,e){var n={filename:t,coverage:0,hits:0,misses:0,sloc:0,source:{}};return e.source.forEach(function(t,r){r++,0===e[r]?(n.misses++,n.sloc++):void 0!==e[r]&&(n.hits++,n.sloc++),n.source[r]={source:t,coverage:void 0===e[r]?"":e[r]}}),n.coverage=n.hits/n.sloc*100,n}function u(t){return{title:t.title,fullTitle:t.fullTitle(),duration:t.duration}}var c=r("./base");e=t.exports=i}),t.register("reporters/json-stream.js",function(t,e,n){function r(t){s.call(this,t);var e=this,n=(this.stats,t.total);t.on("start",function(){console.log(JSON.stringify(["start",{total:n}]))}),t.on("pass",function(t){console.log(JSON.stringify(["pass",i(t)]))}),t.on("fail",function(t,e){t=i(t),t.err=e.message,console.log(JSON.stringify(["fail",t]))}),t.on("end",function(){o.stdout.write(JSON.stringify(["end",e.stats]))})}function i(t){return{title:t.title,fullTitle:t.fullTitle(),duration:t.duration}}{var s=n("./base");s.color}e=t.exports=r}),t.register("reporters/json.js",function(t,e,n){function r(t){var e=this;a.call(this,t);var n=[],r=[],s=[],u=[];t.on("test end",function(t){n.push(t)}),t.on("pass",function(t){u.push(t)}),t.on("fail",function(t){s.push(t)}),t.on("pending",function(t){r.push(t)}),t.on("end",function(){var a={stats:e.stats,tests:n.map(i),pending:r.map(i),failures:s.map(i),passes:u.map(i)};t.testResults=a,o.stdout.write(JSON.stringify(a,null,2))})}function i(t){return{title:t.title,fullTitle:t.fullTitle(),duration:t.duration,err:s(t.err||{})}}function s(t){var e={};return Object.getOwnPropertyNames(t).forEach(function(n){e[n]=t[n]},t),e}{var a=n("./base");a.cursor,a.color}e=t.exports=r}),t.register("reporters/landing.js",function(t,e,n){function r(t){function e(){var t=Array(r).join("-");return" "+u("runway",t)}s.call(this,t);var n=this,r=(this.stats,.75*s.window.width|0),i=t.total,c=o.stdout,l=u("plane","✈"),h=-1,f=0;t.on("start",function(){c.write("\n\n\n "),a.hide()}),t.on("test end",function(t){var n=-1==h?r*++f/i|0:h;"failed"==t.state&&(l=u("plane crash","✈"),h=n),c.write("["+(r+1)+"D"),c.write(e()),c.write("\n "),c.write(u("runway",Array(n).join("⋅"))),c.write(l),c.write(u("runway",Array(r-n).join("⋅")+"\n")),c.write(e()),c.write("")}),t.on("end",function(){a.show(),console.log(),n.epilogue()})}function i(){}var s=n("./base"),a=s.cursor,u=s.color;e=t.exports=r,s.colors.plane=0,s.colors["plane crash"]=31,s.colors.runway=90,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/list.js",function(t,e,n){function r(t){s.call(this,t);var e=this,n=(this.stats,0);t.on("start",function(){console.log()}),t.on("test",function(t){o.stdout.write(u("pass"," "+t.fullTitle()+": "))}),t.on("pending",function(t){var e=u("checkmark"," -")+u("pending"," %s");console.log(e,t.fullTitle())}),t.on("pass",function(t){var e=u("checkmark"," "+s.symbols.dot)+u("pass"," %s: ")+u(t.speed,"%dms");a.CR(),console.log(e,t.fullTitle(),t.duration)}),t.on("fail",function(t){a.CR(),console.log(u("fail"," %d) %s"),++n,t.fullTitle())}),t.on("end",e.epilogue.bind(e))}function i(){}var s=n("./base"),a=s.cursor,u=s.color;e=t.exports=r,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/markdown.js",function(t,e,n){function r(t){function e(t){return Array(u).join("#")+" "+t}function n(t,e){var r=e;return e=e[t.title]=e[t.title]||{suite:t},t.suites.forEach(function(t){n(t,e)}),r}function r(t,e){++e;var n,i="";for(var o in t)"suite"!=o&&(o&&(n=" - ["+o+"](#"+s.slug(t[o].suite.fullTitle())+")\n"),o&&(i+=Array(e).join(" ")+n),i+=r(t[o],e));return--e,i}function a(t){var e=n(t,{});return r(e,0)}i.call(this,t);var u=(this.stats,0),c="";a(t.suite),t.on("suite",function(t){++u;var n=s.slug(t.fullTitle());c+='\n',c+=e(t.title)+"\n"}),t.on("suite end",function(){--u}),t.on("pass",function(t){var e=s.clean(t.fn.toString());c+=t.title+".\n",c+="\n```js\n",c+=e+"\n",c+="```\n\n"}),t.on("end",function(){o.stdout.write("# TOC\n"),o.stdout.write(a(t.suite)),o.stdout.write(c) })}var i=n("./base"),s=n("../utils");e=t.exports=r}),t.register("reporters/min.js",function(t,e,n){function r(t){s.call(this,t),t.on("start",function(){o.stdout.write(""),o.stdout.write("")}),t.on("end",this.epilogue.bind(this))}function i(){}var s=n("./base");e=t.exports=r,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/nyan.js",function(t,e,n){function r(t){a.call(this,t);{var e=this,n=(this.stats,.75*a.window.width|0),r=(this.rainbowColors=e.generateColors(),this.colorIndex=0,this.numberOfLines=4,this.trajectories=[[],[],[],[]],this.nyanCatWidth=11);this.trajectoryWidthMax=n-r,this.scoreboardWidth=5,this.tick=0}t.on("start",function(){a.cursor.hide(),e.draw()}),t.on("pending",function(){e.draw()}),t.on("pass",function(){e.draw()}),t.on("fail",function(){e.draw()}),t.on("end",function(){a.cursor.show();for(var t=0;t=this.trajectoryWidthMax&&r.shift(),r.push(e)}},r.prototype.drawRainbow=function(){var t=this;this.trajectories.forEach(function(e){i("["+t.scoreboardWidth+"C"),i(e.join("")),i("\n")}),this.cursorUp(this.numberOfLines)},r.prototype.drawNyanCat=function(){var t=this,e=this.scoreboardWidth+this.trajectories[0].length,n="["+e+"C",r="";i(n),i("_,------,"),i("\n"),i(n),r=t.tick?" ":" ",i("_|"+r+"/\\_/\\ "),i("\n"),i(n),r=t.tick?"_":"__";var o=t.tick?"~":"^";i(o+"|"+r+this.face()+" "),i("\n"),i(n),r=t.tick?" ":" ",i(r+'"" "" '),i("\n"),this.cursorUp(this.numberOfLines)},r.prototype.face=function(){var t=this.stats;return t.failures?"( x .x)":t.pending?"( o .o)":t.passes?"( ^ .^)":"( - .-)"},r.prototype.cursorUp=function(t){i("["+t+"A")},r.prototype.cursorDown=function(t){i("["+t+"B")},r.prototype.generateColors=function(){for(var t=[],e=0;42>e;e++){var n=Math.floor(Math.PI/3),r=e*(1/6),i=Math.floor(3*Math.sin(r)+3),o=Math.floor(3*Math.sin(r+2*n)+3),s=Math.floor(3*Math.sin(r+4*n)+3);t.push(36*i+6*o+s+16)}return t},r.prototype.rainbowify=function(t){var e=this.rainbowColors[this.colorIndex%this.rainbowColors.length];return this.colorIndex+=1,"[38;5;"+e+"m"+t+""},s.prototype=a.prototype,r.prototype=new s,r.prototype.constructor=r}),t.register("reporters/progress.js",function(t,e,n){function r(t,e){s.call(this,t);var n=this,e=e||{},r=(this.stats,.5*s.window.width|0),i=t.total,c=0,l=(Math.max,-1);e.open=e.open||"[",e.complete=e.complete||"▬",e.incomplete=e.incomplete||s.symbols.dot,e.close=e.close||"]",e.verbose=!1,t.on("start",function(){console.log(),a.hide()}),t.on("test end",function(){c++;var t=c/i,n=r*t|0,s=r-n;(l!==n||e.verbose)&&(l=n,a.CR(),o.stdout.write(""),o.stdout.write(u("progress"," "+e.open)),o.stdout.write(Array(n).join(e.complete)),o.stdout.write(Array(s).join(e.incomplete)),o.stdout.write(u("progress",e.close)),e.verbose&&o.stdout.write(u("progress"," "+c+" of "+i)))}),t.on("end",function(){a.show(),console.log(),n.epilogue()})}function i(){}var s=n("./base"),a=s.cursor,u=s.color;e=t.exports=r,s.colors.progress=90,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/spec.js",function(t,e,n){function r(t){function e(){return Array(r).join(" ")}o.call(this,t);var n=this,r=(this.stats,0),i=0;t.on("start",function(){console.log()}),t.on("suite",function(t){++r,console.log(a("suite","%s%s"),e(),t.title)}),t.on("suite end",function(){--r,1==r&&console.log()}),t.on("pending",function(t){var n=e()+a("pending"," - %s");console.log(n,t.title)}),t.on("pass",function(t){if("fast"==t.speed){var n=e()+a("checkmark"," "+o.symbols.ok)+a("pass"," %s ");s.CR(),console.log(n,t.title)}else{var n=e()+a("checkmark"," "+o.symbols.ok)+a("pass"," %s ")+a(t.speed,"(%dms)");s.CR(),console.log(n,t.title,t.duration)}}),t.on("fail",function(t){s.CR(),console.log(e()+a("fail"," %d) %s"),++i,t.title)}),t.on("end",n.epilogue.bind(n))}function i(){}var o=n("./base"),s=o.cursor,a=o.color;e=t.exports=r,i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/tap.js",function(t,e,n){function r(t){o.call(this,t);var e=(this.stats,1),n=0,r=0;t.on("start",function(){var e=t.grepTotal(t.suite);console.log("%d..%d",1,e)}),t.on("test end",function(){++e}),t.on("pending",function(t){console.log("ok %d %s # SKIP -",e,i(t))}),t.on("pass",function(t){n++,console.log("ok %d %s",e,i(t))}),t.on("fail",function(t,n){r++,console.log("not ok %d %s",e,i(t)),n.stack&&console.log(n.stack.replace(/^/gm," "))}),t.on("end",function(){console.log("# tests "+(n+r)),console.log("# pass "+n),console.log("# fail "+r)})}function i(t){return t.fullTitle().replace(/#/g,"")}{var o=n("./base");o.cursor,o.color}e=t.exports=r}),t.register("reporters/xunit.js",function(t,e,r){function i(t){c.call(this,t);var e=this.stats,n=[];t.on("pending",function(t){n.push(t)}),t.on("pass",function(t){n.push(t)}),t.on("fail",function(t){n.push(t)}),t.on("end",function(){console.log(a("testsuite",{name:"Mocha Tests",tests:e.tests,failures:e.failures,errors:e.failures,skipped:e.tests-e.failures-e.passes,timestamp:(new f).toUTCString(),time:e.duration/1e3||0},!1)),n.forEach(s),console.log("")})}function o(){}function s(t){var e={classname:t.parent.fullTitle(),name:t.title,time:t.duration/1e3||0};if("failed"==t.state){var n=t.err;console.log(a("testcase",e,!1,a("failure",{},!1,u(h(n.message)+"\n"+n.stack))))}else console.log(t.pending?a("testcase",e,!1,a("skipped",{},!0)):a("testcase",e,!0))}function a(t,e,n,r){var i,o=n?"/>":">",s=[];for(var a in e)s.push(a+'="'+h(e[a])+'"');return i="<"+t+(s.length?" "+s.join(" "):"")+o,r&&(i+=r+""}{var c=r("./base"),l=r("../utils"),h=l.escape,f=n.Date;n.setTimeout,n.setInterval,n.clearTimeout,n.clearInterval}e=t.exports=i,o.prototype=c.prototype,i.prototype=new o,i.prototype.constructor=i}),t.register("runnable.js",function(t,e,r){function i(t,e){this.title=t,this.fn=e,this.async=e&&e.length,this.sync=!this.async,this._timeout=2e3,this._slow=75,this._enableTimeouts=!0,this.timedOut=!1,this._trace=new Error("done() called multiple times")}function o(){}var s=r("browser/events").EventEmitter,a=r("browser/debug")("mocha:runnable"),u=r("./ms"),c=n.Date,l=n.setTimeout,h=(n.setInterval,n.clearTimeout),f=(n.clearInterval,Object.prototype.toString);t.exports=i,o.prototype=s.prototype,i.prototype=new o,i.prototype.constructor=i,i.prototype.timeout=function(t){return 0==arguments.length?this._timeout:(0===t&&(this._enableTimeouts=!1),"string"==typeof t&&(t=u(t)),a("timeout %d",t),this._timeout=t,this.timer&&this.resetTimeout(),this)},i.prototype.slow=function(t){return 0===arguments.length?this._slow:("string"==typeof t&&(t=u(t)),a("timeout %d",t),this._slow=t,this)},i.prototype.enableTimeouts=function(t){return 0===arguments.length?this._enableTimeouts:(a("enableTimeouts %s",t),this._enableTimeouts=t,this)},i.prototype.fullTitle=function(){return this.parent.fullTitle()+" "+this.title},i.prototype.clearTimeout=function(){h(this.timer)},i.prototype.inspect=function(){return JSON.stringify(this,function(t,e){return"_"!=t[0]?"parent"==t?"#":"ctx"==t?"#":e:void 0},2)},i.prototype.resetTimeout=function(){var t=this,e=this.timeout()||1e9;this._enableTimeouts&&(this.clearTimeout(),this.timer=l(function(){t._enableTimeouts&&(t.callback(new Error("timeout of "+e+"ms exceeded")),t.timedOut=!0)},e))},i.prototype.globals=function(t){this._allowedGlobals=t},i.prototype.run=function(t){function e(t){o||(o=!0,s.emit("error",t||new Error("done() called multiple times; stacktrace may be inaccurate")))}function n(n){var r=s.timeout();if(!s.timedOut){if(i)return e(n||s._trace);s.clearTimeout(),s.duration=new c-a,i=!0,!n&&s.duration>r&&s._enableTimeouts&&(n=new Error("timeout of "+r+"ms exceeded")),t(n)}}function r(t){var e=t.call(u);e&&"function"==typeof e.then?(s.resetTimeout(),e.then(function(){n()},function(t){n(t||new Error("Promise rejected with no or falsy reason"))})):n()}var i,o,s=this,a=new c,u=this.ctx;if(u&&u.runnable&&u.runnable(this),this.callback=n,this.async){this.resetTimeout();try{this.fn.call(u,function(t){return t instanceof Error||"[object Error]"===f.call(t)?n(t):null!=t?n("[object Object]"===Object.prototype.toString.call(t)?new Error("done() invoked with non-Error: "+JSON.stringify(t)):new Error("done() invoked with non-Error: "+t)):void n()})}catch(l){n(l)}}else{if(this.asyncOnly)return n(new Error("--async-only option in use without declaring `done()`"));try{this.pending?n():r(this.fn)}catch(l){n(l)}}}}),t.register("runner.js",function(t,e,r){function i(t){var e=this;this._globals=[],this._abort=!1,this.suite=t,this.total=t.total(),this.failures=0,this.on("test end",function(t){e.checkGlobals(t)}),this.on("hook end",function(t){e.checkGlobals(t)}),this.grep(/.*/),this.globals(this.globalProps().concat(u()))}function s(){}function a(t,e){return f(e,function(e){if(/^d+/.test(e))return!1;if(n.navigator&&/^getInterface/.test(e))return!1;if(n.navigator&&/^\d+/.test(e))return!1;if(/^mocha-/.test(e))return!1;var r=f(t,function(t){return~t.indexOf("*")?0==e.indexOf(t.split("*")[0]):e==t});return 0==r.length&&(!n.navigator||"onerror"!==e)})}function u(){if("object"==typeof o&&"string"==typeof o.version){var t=o.version.split(".").reduce(function(t,e){return t<<8|e});if(2315>t)return["errno"]}return[]}var c=r("browser/events").EventEmitter,l=r("browser/debug")("mocha:runner"),h=(r("./test"),r("./utils")),f=h.filter,p=(h.keys,["setTimeout","clearTimeout","setInterval","clearInterval","XMLHttpRequest","Date"]);t.exports=i,i.immediately=n.setImmediate||o.nextTick,s.prototype=c.prototype,i.prototype=new s,i.prototype.constructor=i,i.prototype.grep=function(t,e){return l("grep %s",t),this._grep=t,this._invert=e,this.total=this.grepTotal(this.suite),this},i.prototype.grepTotal=function(t){var e=this,n=0;return t.eachTest(function(t){var r=e._grep.test(t.fullTitle());e._invert&&(r=!r),r&&n++}),n},i.prototype.globalProps=function(){for(var t=h.keys(n),e=0;e1?this.fail(t,new Error("global leaks detected: "+e.join(", "))):e.length&&this.fail(t,new Error("global leak detected: "+e[0])))}},i.prototype.fail=function(t,e){++this.failures,t.state="failed","string"==typeof e&&(e=new Error('the string "'+e+'" was thrown, throw an Error :)')),this.emit("fail",t,e)},i.prototype.failHook=function(t,e){this.fail(t,e),this.suite.bail()&&this.emit("end")},i.prototype.hook=function(t,e){function n(t){var i=o[t];return i?s.failures&&r.bail()?e():(s.currentRunnable=i,i.ctx.currentTest=s.test,s.emit("hook",i),i.on("error",function(t){s.failHook(i,t)}),void i.run(function(r){i.removeAllListeners("error");var o=i.error();return o&&s.fail(s.test,o),r?(s.failHook(i,r),e(r)):(s.emit("hook end",i),delete i.ctx.currentTest,void n(++t))})):e()}var r=this.suite,o=r["_"+t],s=this;i.immediately(function(){n(0)})},i.prototype.hooks=function(t,e,n){function r(s){return i.suite=s,s?void i.hook(t,function(t){if(t){var s=i.suite;return i.suite=o,n(t,s)}r(e.pop())}):(i.suite=o,n())}var i=this,o=this.suite;r(e.pop())},i.prototype.hookUp=function(t,e){var n=[this.suite].concat(this.parents()).reverse();this.hooks(t,n,e)},i.prototype.hookDown=function(t,e){var n=[this.suite].concat(this.parents());this.hooks(t,n,e)},i.prototype.parents=function(){for(var t=this.suite,e=[];t=t.parent;)e.push(t);return e},i.prototype.runTest=function(t){var e=this.test,n=this;this.asyncOnly&&(e.asyncOnly=!0);try{e.on("error",function(t){n.fail(e,t)}),e.run(t)}catch(r){t(r)}},i.prototype.runTests=function(t,e){function n(t,r,i){var s=o.suite;o.suite=i?r.parent:r,o.suite?o.hookUp("afterEach",function(t,i){return o.suite=s,t?n(t,i,!0):void e(r)}):(o.suite=s,e(r))}function r(a,u){if(o.failures&&t._bail)return e();if(o._abort)return e();if(a)return n(a,u,!0);if(i=s.shift(),!i)return e();var c=o._grep.test(i.fullTitle());return o._invert&&(c=!c),c?i.pending?(o.emit("pending",i),o.emit("test end",i),r()):(o.emit("test",o.test=i),void o.hookDown("beforeEach",function(t,e){return t?n(t,e,!1):(o.currentRunnable=o.test,void o.runTest(function(t){return i=o.test,t?(o.fail(i,t),o.emit("test end",i),o.hookUp("afterEach",r)):(i.state="passed",o.emit("pass",i),o.emit("test end",i),void o.hookUp("afterEach",r))}))})):r()}var i,o=this,s=t.tests.slice();this.next=r,r()},i.prototype.runSuite=function(t,e){function n(e){if(e)return e==t?r():r(e);if(o._abort)return r();var i=t.suites[s++];return i?void o.runSuite(i,n):r()}function r(n){o.suite=t,o.hook("afterAll",function(){o.emit("suite end",t),e(n)})}var i=this.grepTotal(t),o=this,s=0;return l("run suite %s",t.fullTitle()),i?(this.emit("suite",this.suite=t),void this.hook("beforeAll",function(e){return e?r():void o.runTests(t,n)})):e()},i.prototype.uncaught=function(t){t?l("uncaught exception %s",t!==function(){return this}.call(t)?t:t.message||t):(l("uncaught undefined exception"),t=new Error("Caught undefined error, did you throw without specifying what?")),t.uncaught=!0;var e=this.currentRunnable;if(e){var n=e.state;if(this.fail(e,t),e.clearTimeout(),!n)return"test"==e.type?(this.emit("test end",e),void this.hookUp("afterEach",this.next)):void this.emit("end")}},i.prototype.run=function(t){function e(t){n.uncaught(t)}var n=this,t=t||function(){};return l("start"),this.on("end",function(){l("end"),o.removeListener("uncaughtException",e),t(n.failures)}),this.emit("start"),this.runSuite(this.suite,function(){l("finished running"),n.emit("end")}),o.on("uncaughtException",e),this},i.prototype.abort=function(){l("aborting"),this._abort=!0}}),t.register("suite.js",function(t,e,n){function r(t,e){this.title=t;var n=function(){};n.prototype=e,this.ctx=new n,this.suites=[],this.tests=[],this.pending=!1,this._beforeEach=[],this._beforeAll=[],this._afterEach=[],this._afterAll=[],this.root=!t,this._timeout=2e3,this._enableTimeouts=!0,this._slow=75,this._bail=!1}function i(){}var o=n("browser/events").EventEmitter,s=n("browser/debug")("mocha:suite"),a=n("./ms"),u=n("./utils"),c=n("./hook");e=t.exports=r,e.create=function(t,e){var n=new r(e,t.ctx);return n.parent=t,t.pending&&(n.pending=!0),e=n.fullTitle(),t.addSuite(n),n},i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r,r.prototype.clone=function(){var t=new r(this.title);return s("clone"),t.ctx=this.ctx,t.timeout(this.timeout()),t.enableTimeouts(this.enableTimeouts()),t.slow(this.slow()),t.bail(this.bail()),t},r.prototype.timeout=function(t){return 0==arguments.length?this._timeout:(0===t&&(this._enableTimeouts=!1),"string"==typeof t&&(t=a(t)),s("timeout %d",t),this._timeout=parseInt(t,10),this)},r.prototype.enableTimeouts=function(t){return 0===arguments.length?this._enableTimeouts:(s("enableTimeouts %s",t),this._enableTimeouts=t,this)},r.prototype.slow=function(t){return 0===arguments.length?this._slow:("string"==typeof t&&(t=a(t)),s("slow %d",t),this._slow=t,this)},r.prototype.bail=function(t){return 0==arguments.length?this._bail:(s("bail %s",t),this._bail=t,this)},r.prototype.beforeAll=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"before all" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._beforeAll.push(n),this.emit("beforeAll",n),this},r.prototype.afterAll=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"after all" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._afterAll.push(n),this.emit("afterAll",n),this},r.prototype.beforeEach=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"before each" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._beforeEach.push(n),this.emit("beforeEach",n),this},r.prototype.afterEach=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"after each" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._afterEach.push(n),this.emit("afterEach",n),this},r.prototype.addSuite=function(t){return t.parent=this,t.timeout(this.timeout()),t.enableTimeouts(this.enableTimeouts()),t.slow(this.slow()),t.bail(this.bail()),this.suites.push(t),this.emit("suite",t),this},r.prototype.addTest=function(t){return t.parent=this,t.timeout(this.timeout()),t.enableTimeouts(this.enableTimeouts()),t.slow(this.slow()),t.ctx=this.ctx,this.tests.push(t),this.emit("test",t),this},r.prototype.fullTitle=function(){if(this.parent){var t=this.parent.fullTitle();if(t)return t+" "+this.title}return this.title},r.prototype.total=function(){return u.reduce(this.suites,function(t,e){return t+e.total()},0)+this.tests.length},r.prototype.eachTest=function(t){return u.forEach(this.tests,t),u.forEach(this.suites,function(e){e.eachTest(t)}),this}}),t.register("test.js",function(t,e,n){function r(t,e){o.call(this,t,e),this.pending=!e,this.type="test"}function i(){}var o=n("./runnable");t.exports=r,i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("utils.js",function(t,e,n){function r(t){return!~f.indexOf(t)}function i(t){return t.replace(//g,">").replace(/\/\/(.*)/gm,'//$1').replace(/('.*?')/gm,'$1').replace(/(\d+\.\d+)/gm,'$1').replace(/(\d+)/gm,'$1').replace(/\bnew[ \t]+(\w+)/gm,'new $1').replace(/\b(function|new|throw|return|var|if|else)\b/gm,'$1')}var o=n("browser/fs"),s=n("browser/path"),a=s.basename,u=o.existsSync||s.existsSync,c=n("browser/glob"),l=s.join,h=n("browser/debug")("mocha:watch"),f=["node_modules",".git"];e.escape=function(t){return String(t).replace(/&/g,"&").replace(/"/g,""").replace(//g,">")},e.forEach=function(t,e,n){for(var r=0,i=t.length;i>r;r++)e.call(n,t[r],r)},e.map=function(t,e,n){for(var r=[],i=0,o=t.length;o>i;i++)r.push(e.call(n,t[i],i));return r},e.indexOf=function(t,e,n){for(var r=n||0,i=t.length;i>r;r++)if(t[r]===e)return r;return-1},e.reduce=function(t,e,n){for(var r=n,i=0,o=t.length;o>i;i++)r=e(r,t[i],i,t);return r},e.filter=function(t,e){for(var n=[],r=0,i=t.length;i>r;r++){var o=t[r];e(o,r,t)&&n.push(o)}return n},e.keys=Object.keys||function(t){var e=[],n=Object.prototype.hasOwnProperty;for(var r in t)n.call(t,r)&&e.push(r);return e},e.watch=function(t,e){var n={interval:100};t.forEach(function(t){h("file %s",t),o.watchFile(t,n,function(n,r){r.mtime *{?/,"").replace(/\s+\}$/,"");var n=t.match(/^\n?( *)/)[1].length,r=t.match(/^\n?(\t*)/)[1].length,i=new RegExp("^\n?"+(r?" ":" ")+"{"+(r?r:n)+"}","gm");return t=t.replace(i,""),e.trim(t)},e.trim=function(t){return t.replace(/^\s+|\s+$/g,"")},e.parseQuery=function(t){return e.reduce(t.replace("?","").split("&"),function(t,e){var n=e.indexOf("="),r=e.slice(0,n),i=e.slice(++n);return t[r]=decodeURIComponent(i),t},{})},e.highlightTags=function(t){for(var e=document.getElementById("mocha").getElementsByTagName(t),n=0,r=e.length;r>n;++n)e[n].innerHTML=i(e[n].innerHTML)},e.stringify=function(t){return t instanceof RegExp?t.toString():JSON.stringify(e.canonicalize(t),null,2).replace(/,(\n|$)/g,"$1")},e.canonicalize=function(t,n){if(n=n||[],-1!==e.indexOf(n,t))return"[Circular]";var r;return"[object Array]"==={}.toString.call(t)?(n.push(t),r=e.map(t,function(t){return e.canonicalize(t,n)}),n.pop()):"object"==typeof t&&null!==t?(n.push(t),r={},e.forEach(e.keys(t).sort(),function(i){r[i]=e.canonicalize(t[i],n)}),n.pop()):r=t,r},e.lookupFiles=function p(t,e,n){var r=[],i=new RegExp("\\.("+e.join("|")+")$");if(!u(t)){if(!u(t+".js")){if(r=c.sync(t),!r.length)throw new Error("cannot resolve path (or pattern) '"+t+"'");return r}t+=".js"}try{var s=o.statSync(t);if(s.isFile())return t}catch(h){return}return o.readdirSync(t).forEach(function(s){s=l(t,s);try{var u=o.statSync(s);if(u.isDirectory())return void(n&&(r=r.concat(p(s,e,n))))}catch(c){return}u.isFile()&&i.test(s)&&"."!==a(s)[0]&&r.push(s)}),r}});var n=function(){return this}(),r=n.Date,i=n.setTimeout,o=(n.setInterval,n.clearTimeout,n.clearInterval,{});o.exit=function(){},o.stdout={};var s=[],a=n.onerror;o.removeListener=function(t,e){if("uncaughtException"==t){n.onerror=a?a:function(){};var r=u.utils.indexOf(s,e);-1!=r&&s.splice(r,1)}},o.on=function(t,e){"uncaughtException"==t&&(n.onerror=function(t,n,r){return e(new Error(t+" ("+n+":"+r+")")),!0},s.push(e))};var u=n.Mocha=t("mocha"),c=n.mocha=new u({reporter:"html"});c.suite.removeAllListeners("pre-require");var l,h=[];u.Runner.immediately=function(t){h.push(t),l||(l=i(e,0))},c.throwError=function(t){throw u.utils.forEach(s,function(e){e(t)}),t},c.ui=function(t){return u.prototype.ui.call(this,t),this.suite.emit("pre-require",n,null,this),this},c.setup=function(t){"string"==typeof t&&(t={ui:t});for(var e in t)this[e](t[e]);return this},c.run=function(t){var e=c.options;c.globals("location");var r=u.utils.parseQuery(n.location.search||"");return r.grep&&c.grep(r.grep),r.invert&&c.invert(),u.prototype.run.call(c,function(r){var i=n.document;i&&i.getElementById("mocha")&&e.noHighlighting!==!0&&u.utils.highlightTags("code"),t&&t(r)})},u.process=o}(),function(){function require(t){var e=require.modules[t];if(!e)throw new Error('failed to require "'+t+'"');return"exports"in e||"function"!=typeof e.definition||(e.client=e.component=!0,e.definition.call(this,e.exports={},e),delete e.definition),e.exports}require.loader="component",require.helper={},require.helper.semVerSort=function(t,e){for(var n=t.version.split("."),r=e.version.split("."),i=0;is?1:-1;var a=n[i].substr((""+o).length),u=r[i].substr((""+s).length);if(""===a&&""!==u)return 1;if(""!==a&&""===u)return-1;if(""!==a&&""!==u)return a>u?1:-1}return 0},require.latest=function(t,e){function n(t){throw new Error('failed to find latest module of "'+t+'"')}var r=/(.*)~(.*)@v?(\d+\.\d+\.\d+[^\/]*)$/,i=/(.*)~(.*)/;i.test(t)||n(t);for(var o=Object.keys(require.modules),s=[],a=[],u=0;u0){var f=s.sort(require.helper.semVerSort).pop().name;return e===!0?f:require(f)}var f=a.pop().name;return e===!0?f:require(f)},require.modules={},require.register=function(t,e){require.modules[t]={definition:e}},require.define=function(t,e){require.modules[t]={exports:e}},require.register("chaijs~assertion-error@1.0.0",function(t,e){function n(){function t(t,n){Object.keys(n).forEach(function(r){~e.indexOf(r)||(t[r]=n[r])})}var e=[].slice.call(arguments);return function(){for(var e=[].slice.call(arguments),n=0,r={};n=0;i--)if(l=o[i],!n(t[l],e[l],r))return!1;return!0}var p,d=require("chaijs~type-detect@0.1.1");try{p=require("buffer").Buffer}catch(g){p={},p.isBuffer=function(){return!1}}e.exports=n}),require.register("chai",function(t,e){e.exports=require("chai/lib/chai.js")}),require.register("chai/lib/chai.js",function(t,e){var n=[],t=e.exports={};t.version="1.10.0",t.AssertionError=require("chaijs~assertion-error@1.0.0");var r=require("chai/lib/chai/utils/index.js");t.use=function(t){return~n.indexOf(t)||(t(this,r),n.push(t)),this};var i=require("chai/lib/chai/config.js");t.config=i;var o=require("chai/lib/chai/assertion.js");t.use(o);var s=require("chai/lib/chai/core/assertions.js");t.use(s);var a=require("chai/lib/chai/interface/expect.js");t.use(a);var u=require("chai/lib/chai/interface/should.js");t.use(u);var c=require("chai/lib/chai/interface/assert.js");t.use(c)}),require.register("chai/lib/chai/assertion.js",function(t,e){var n=require("chai/lib/chai/config.js"),r=function(){};e.exports=function(t,e){function i(t,e,n){s(this,"ssfi",n||arguments.callee),s(this,"object",t),s(this,"message",e)}var o=t.AssertionError,s=e.flag;t.Assertion=i,Object.defineProperty(i,"includeStack",{get:function(){return console.warn("Assertion.includeStack is deprecated, use chai.config.includeStack instead."),n.includeStack},set:function(t){console.warn("Assertion.includeStack is deprecated, use chai.config.includeStack instead."),n.includeStack=t}}),Object.defineProperty(i,"showDiff",{get:function(){return console.warn("Assertion.showDiff is deprecated, use chai.config.showDiff instead."),n.showDiff},set:function(t){console.warn("Assertion.showDiff is deprecated, use chai.config.showDiff instead."),n.showDiff=t}}),i.addProperty=function(t,n){e.addProperty(this.prototype,t,n)},i.addMethod=function(t,n){e.addMethod(this.prototype,t,n)},i.addChainableMethod=function(t,n,r){e.addChainableMethod(this.prototype,t,n,r)},i.addChainableNoop=function(t,n){e.addChainableMethod(this.prototype,t,r,n)},i.overwriteProperty=function(t,n){e.overwriteProperty(this.prototype,t,n)},i.overwriteMethod=function(t,n){e.overwriteMethod(this.prototype,t,n)},i.overwriteChainableMethod=function(t,n,r){e.overwriteChainableMethod(this.prototype,t,n,r)},i.prototype.assert=function(t,r,i,a,u,c){var l=e.test(this,arguments);if(!0!==c&&(c=!1),!0!==n.showDiff&&(c=!1),!l){var r=e.getMessage(this,arguments),h=e.getActual(this,arguments);throw new o(r,{actual:h,expected:a,showDiff:c},n.includeStack?this.assert:s(this,"ssfi"))}},Object.defineProperty(i.prototype,"_obj",{get:function(){return s(this,"object")},set:function(t){s(this,"object",t)}})}}),require.register("chai/lib/chai/config.js",function(t,e){e.exports={includeStack:!1,showDiff:!0,truncateThreshold:40}}),require.register("chai/lib/chai/core/assertions.js",function(t,e){e.exports=function(t,e){function n(t,n){n&&w(this,"message",n),t=t.toLowerCase();var r=w(this,"object"),i=~["a","e","i","o","u"].indexOf(t.charAt(0))?"an ":"a ";this.assert(t===e.type(r),"expected #{this} to be "+i+t,"expected #{this} not to be "+i+t)}function r(){w(this,"contains",!0)}function i(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=!1;if("array"===e.type(r)&&"object"===e.type(t)){for(var o in r)if(e.eql(r[o],t)){i=!0;break}}else if("object"===e.type(t)){if(!w(this,"negate")){for(var s in t)new y(r).property(s,t[s]);return}var a={};for(var s in t)a[s]=r[s];i=e.eql(a,t)}else i=r&&~r.indexOf(t);this.assert(i,"expected #{this} to include "+e.inspect(t),"expected #{this} to not include "+e.inspect(t))}function o(){var t=w(this,"object"),e=Object.prototype.toString.call(t);this.assert("[object Arguments]"===e,"expected #{this} to be arguments but got "+e,"expected #{this} to not be arguments")}function s(t,e){e&&w(this,"message",e);var n=w(this,"object");return w(this,"deep")?this.eql(t):void this.assert(t===n,"expected #{this} to equal #{exp}","expected #{this} to not equal #{exp}",t,this._obj,!0)}function a(t,n){n&&w(this,"message",n),this.assert(e.eql(t,w(this,"object")),"expected #{this} to deeply equal #{exp}","expected #{this} to not deeply equal #{exp}",t,this._obj,!0)}function u(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(r>t,"expected #{this} to have a length above #{exp} but got #{act}","expected #{this} to not have a length above #{exp}",t,r)}else this.assert(n>t,"expected #{this} to be above "+t,"expected #{this} to be at most "+t)}function c(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(r>=t,"expected #{this} to have a length at least #{exp} but got #{act}","expected #{this} to have a length below #{exp}",t,r)}else this.assert(n>=t,"expected #{this} to be at least "+t,"expected #{this} to be below "+t)}function l(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(t>r,"expected #{this} to have a length below #{exp} but got #{act}","expected #{this} to not have a length below #{exp}",t,r) -}else this.assert(t>n,"expected #{this} to be below "+t,"expected #{this} to be at least "+t)}function h(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(t>=r,"expected #{this} to have a length at most #{exp} but got #{act}","expected #{this} to have a length above #{exp}",t,r)}else this.assert(t>=n,"expected #{this} to be at most "+t,"expected #{this} to be above "+t)}function f(t,n){n&&w(this,"message",n);var r=e.getName(t);this.assert(w(this,"object")instanceof t,"expected #{this} to be an instance of "+r,"expected #{this} to not be an instance of "+r)}function p(t,n){n&&w(this,"message",n);var r=w(this,"object");this.assert(r.hasOwnProperty(t),"expected #{this} to have own property "+e.inspect(t),"expected #{this} to not have own property "+e.inspect(t))}function d(){w(this,"doLength",!0)}function g(t,e){e&&w(this,"message",e);var n=w(this,"object");new y(n,e).to.have.property("length");var r=n.length;this.assert(r==t,"expected #{this} to have a length of #{exp} but got #{act}","expected #{this} to not have a length of #{act}",t,r)}function v(t){var n,r=w(this,"object"),i=!0;if(t=t instanceof Array?t:Array.prototype.slice.call(arguments),!t.length)throw new Error("keys required");var o=Object.keys(r),s=t,a=t.length;if(i=t.every(function(t){return~o.indexOf(t)}),w(this,"negate")||w(this,"contains")||(i=i&&t.length==o.length),a>1){t=t.map(function(t){return e.inspect(t)});var u=t.pop();n=t.join(", ")+", and "+u}else n=e.inspect(t[0]);n=(a>1?"keys ":"key ")+n,n=(w(this,"contains")?"contain ":"have ")+n,this.assert(i,"expected #{this} to "+n,"expected #{this} to not "+n,s.sort(),o.sort(),!0)}function m(t,n,r){r&&w(this,"message",r);var i=w(this,"object");new y(i,r).is.a("function");var o=!1,s=null,a=null,u=null;0===arguments.length?(n=null,t=null):t&&(t instanceof RegExp||"string"==typeof t)?(n=t,t=null):t&&t instanceof Error?(s=t,t=null,n=null):"function"==typeof t?(a=t.prototype.name||t.name,"Error"===a&&t!==Error&&(a=(new t).name)):t=null;try{i()}catch(c){if(s)return this.assert(c===s,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp}",s instanceof Error?s.toString():s,c instanceof Error?c.toString():c),w(this,"object",c),this;if(t&&(this.assert(c instanceof t,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp} but #{act} was thrown",a,c instanceof Error?c.toString():c),!n))return w(this,"object",c),this;var l="object"===e.type(c)&&"message"in c?c.message:""+c;if(null!=l&&n&&n instanceof RegExp)return this.assert(n.exec(l),"expected #{this} to throw error matching #{exp} but got #{act}","expected #{this} to throw error not matching #{exp}",n,l),w(this,"object",c),this;if(null!=l&&n&&"string"==typeof n)return this.assert(~l.indexOf(n),"expected #{this} to throw error including #{exp} but got #{act}","expected #{this} to throw error not including #{act}",n,l),w(this,"object",c),this;o=!0,u=c}var h="",f=null!==a?a:s?"#{exp}":"an error";o&&(h=" but #{act} was thrown"),this.assert(o===!0,"expected #{this} to throw "+f+h,"expected #{this} to not throw "+f+h,s instanceof Error?s.toString():s,u instanceof Error?u.toString():u),w(this,"object",u)}function b(t,e,n){return t.every(function(t){return n?e.some(function(e){return n(t,e)}):-1!==e.indexOf(t)})}var y=t.Assertion,w=(Object.prototype.toString,e.flag);["to","be","been","is","and","has","have","with","that","at","of","same"].forEach(function(t){y.addProperty(t,function(){return this})}),y.addProperty("not",function(){w(this,"negate",!0)}),y.addProperty("deep",function(){w(this,"deep",!0)}),y.addChainableMethod("an",n),y.addChainableMethod("a",n),y.addChainableMethod("include",i,r),y.addChainableMethod("contain",i,r),y.addChainableNoop("ok",function(){this.assert(w(this,"object"),"expected #{this} to be truthy","expected #{this} to be falsy")}),y.addChainableNoop("true",function(){this.assert(!0===w(this,"object"),"expected #{this} to be true","expected #{this} to be false",this.negate?!1:!0)}),y.addChainableNoop("false",function(){this.assert(!1===w(this,"object"),"expected #{this} to be false","expected #{this} to be true",this.negate?!0:!1)}),y.addChainableNoop("null",function(){this.assert(null===w(this,"object"),"expected #{this} to be null","expected #{this} not to be null")}),y.addChainableNoop("undefined",function(){this.assert(void 0===w(this,"object"),"expected #{this} to be undefined","expected #{this} not to be undefined")}),y.addChainableNoop("exist",function(){this.assert(null!=w(this,"object"),"expected #{this} to exist","expected #{this} to not exist")}),y.addChainableNoop("empty",function(){var t=w(this,"object"),e=t;Array.isArray(t)||"string"==typeof object?e=t.length:"object"==typeof t&&(e=Object.keys(t).length),this.assert(!e,"expected #{this} to be empty","expected #{this} not to be empty")}),y.addChainableNoop("arguments",o),y.addChainableNoop("Arguments",o),y.addMethod("equal",s),y.addMethod("equals",s),y.addMethod("eq",s),y.addMethod("eql",a),y.addMethod("eqls",a),y.addMethod("above",u),y.addMethod("gt",u),y.addMethod("greaterThan",u),y.addMethod("least",c),y.addMethod("gte",c),y.addMethod("below",l),y.addMethod("lt",l),y.addMethod("lessThan",l),y.addMethod("most",h),y.addMethod("lte",h),y.addMethod("within",function(t,e,n){n&&w(this,"message",n);var r=w(this,"object"),i=t+".."+e;if(w(this,"doLength")){new y(r,n).to.have.property("length");var o=r.length;this.assert(o>=t&&e>=o,"expected #{this} to have a length within "+i,"expected #{this} to not have a length within "+i)}else this.assert(r>=t&&e>=r,"expected #{this} to be within "+i,"expected #{this} to not be within "+i)}),y.addMethod("instanceof",f),y.addMethod("instanceOf",f),y.addMethod("property",function(t,n,r){r&&w(this,"message",r);var i=w(this,"deep")?"deep property ":"property ",o=w(this,"negate"),s=w(this,"object"),a=w(this,"deep")?e.getPathValue(t,s):s[t];if(o&&void 0!==n){if(void 0===a)throw r=null!=r?r+": ":"",new Error(r+e.inspect(s)+" has no "+i+e.inspect(t))}else this.assert(void 0!==a,"expected #{this} to have a "+i+e.inspect(t),"expected #{this} to not have "+i+e.inspect(t));void 0!==n&&this.assert(n===a,"expected #{this} to have a "+i+e.inspect(t)+" of #{exp}, but got #{act}","expected #{this} to not have a "+i+e.inspect(t)+" of #{act}",n,a),w(this,"object",a)}),y.addMethod("ownProperty",p),y.addMethod("haveOwnProperty",p),y.addChainableMethod("length",g,d),y.addMethod("lengthOf",g),y.addMethod("match",function(t,e){e&&w(this,"message",e);var n=w(this,"object");this.assert(t.exec(n),"expected #{this} to match "+t,"expected #{this} not to match "+t)}),y.addMethod("string",function(t,n){n&&w(this,"message",n);var r=w(this,"object");new y(r,n).is.a("string"),this.assert(~r.indexOf(t),"expected #{this} to contain "+e.inspect(t),"expected #{this} to not contain "+e.inspect(t))}),y.addMethod("keys",v),y.addMethod("key",v),y.addMethod("throw",m),y.addMethod("throws",m),y.addMethod("Throw",m),y.addMethod("respondTo",function(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=w(this,"itself"),o="function"!==e.type(r)||i?r[t]:r.prototype[t];this.assert("function"==typeof o,"expected #{this} to respond to "+e.inspect(t),"expected #{this} to not respond to "+e.inspect(t))}),y.addProperty("itself",function(){w(this,"itself",!0)}),y.addMethod("satisfy",function(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=t(r);this.assert(i,"expected #{this} to satisfy "+e.objDisplay(t),"expected #{this} to not satisfy"+e.objDisplay(t),this.negate?!1:!0,i)}),y.addMethod("closeTo",function(t,n,r){r&&w(this,"message",r);var i=w(this,"object");if(new y(i,r).is.a("number"),"number"!==e.type(t)||"number"!==e.type(n))throw new Error("the arguments to closeTo must be numbers");this.assert(Math.abs(i-t)<=n,"expected #{this} to be close to "+t+" +/- "+n,"expected #{this} not to be close to "+t+" +/- "+n)}),y.addMethod("members",function(t,n){n&&w(this,"message",n);var r=w(this,"object");new y(r).to.be.an("array"),new y(t).to.be.an("array");var i=w(this,"deep")?e.eql:void 0;return w(this,"contains")?this.assert(b(t,r,i),"expected #{this} to be a superset of #{act}","expected #{this} to not be a superset of #{act}",r,t):void this.assert(b(r,t,i)&&b(t,r,i),"expected #{this} to have the same members as #{act}","expected #{this} to not have the same members as #{act}",r,t)})}}),require.register("chai/lib/chai/interface/assert.js",function(exports,module){module.exports=function(chai,util){var Assertion=chai.Assertion,flag=util.flag,assert=chai.assert=function(t,e){var n=new Assertion(null,null,chai.assert);n.assert(t,e,"[ negation message unavailable ]")};assert.fail=function(t,e,n,r){throw n=n||"assert.fail()",new chai.AssertionError(n,{actual:t,expected:e,operator:r},assert.fail)},assert.ok=function(t,e){new Assertion(t,e).is.ok},assert.notOk=function(t,e){new Assertion(t,e).is.not.ok},assert.equal=function(t,e,n){var r=new Assertion(t,n,assert.equal);r.assert(e==flag(r,"object"),"expected #{this} to equal #{exp}","expected #{this} to not equal #{act}",e,t)},assert.notEqual=function(t,e,n){var r=new Assertion(t,n,assert.notEqual);r.assert(e!=flag(r,"object"),"expected #{this} to not equal #{exp}","expected #{this} to equal #{act}",e,t)},assert.strictEqual=function(t,e,n){new Assertion(t,n).to.equal(e)},assert.notStrictEqual=function(t,e,n){new Assertion(t,n).to.not.equal(e)},assert.deepEqual=function(t,e,n){new Assertion(t,n).to.eql(e)},assert.notDeepEqual=function(t,e,n){new Assertion(t,n).to.not.eql(e)},assert.isTrue=function(t,e){new Assertion(t,e).is["true"]},assert.isFalse=function(t,e){new Assertion(t,e).is["false"]},assert.isNull=function(t,e){new Assertion(t,e).to.equal(null)},assert.isNotNull=function(t,e){new Assertion(t,e).to.not.equal(null)},assert.isUndefined=function(t,e){new Assertion(t,e).to.equal(void 0)},assert.isDefined=function(t,e){new Assertion(t,e).to.not.equal(void 0)},assert.isFunction=function(t,e){new Assertion(t,e).to.be.a("function")},assert.isNotFunction=function(t,e){new Assertion(t,e).to.not.be.a("function")},assert.isObject=function(t,e){new Assertion(t,e).to.be.a("object")},assert.isNotObject=function(t,e){new Assertion(t,e).to.not.be.a("object")},assert.isArray=function(t,e){new Assertion(t,e).to.be.an("array")},assert.isNotArray=function(t,e){new Assertion(t,e).to.not.be.an("array")},assert.isString=function(t,e){new Assertion(t,e).to.be.a("string")},assert.isNotString=function(t,e){new Assertion(t,e).to.not.be.a("string")},assert.isNumber=function(t,e){new Assertion(t,e).to.be.a("number")},assert.isNotNumber=function(t,e){new Assertion(t,e).to.not.be.a("number")},assert.isBoolean=function(t,e){new Assertion(t,e).to.be.a("boolean")},assert.isNotBoolean=function(t,e){new Assertion(t,e).to.not.be.a("boolean")},assert.typeOf=function(t,e,n){new Assertion(t,n).to.be.a(e)},assert.notTypeOf=function(t,e,n){new Assertion(t,n).to.not.be.a(e)},assert.instanceOf=function(t,e,n){new Assertion(t,n).to.be.instanceOf(e)},assert.notInstanceOf=function(t,e,n){new Assertion(t,n).to.not.be.instanceOf(e)},assert.include=function(t,e,n){new Assertion(t,n,assert.include).include(e)},assert.notInclude=function(t,e,n){new Assertion(t,n,assert.notInclude).not.include(e)},assert.match=function(t,e,n){new Assertion(t,n).to.match(e)},assert.notMatch=function(t,e,n){new Assertion(t,n).to.not.match(e)},assert.property=function(t,e,n){new Assertion(t,n).to.have.property(e)},assert.notProperty=function(t,e,n){new Assertion(t,n).to.not.have.property(e)},assert.deepProperty=function(t,e,n){new Assertion(t,n).to.have.deep.property(e)},assert.notDeepProperty=function(t,e,n){new Assertion(t,n).to.not.have.deep.property(e)},assert.propertyVal=function(t,e,n,r){new Assertion(t,r).to.have.property(e,n)},assert.propertyNotVal=function(t,e,n,r){new Assertion(t,r).to.not.have.property(e,n)},assert.deepPropertyVal=function(t,e,n,r){new Assertion(t,r).to.have.deep.property(e,n)},assert.deepPropertyNotVal=function(t,e,n,r){new Assertion(t,r).to.not.have.deep.property(e,n)},assert.lengthOf=function(t,e,n){new Assertion(t,n).to.have.length(e)},assert.Throw=function(t,e,n,r){("string"==typeof e||e instanceof RegExp)&&(n=e,e=null);var i=new Assertion(t,r).to.Throw(e,n);return flag(i,"object")},assert.doesNotThrow=function(t,e,n){"string"==typeof e&&(n=e,e=null),new Assertion(t,n).to.not.Throw(e)},assert.operator=function(val,operator,val2,msg){if(!~["==","===",">",">=","<","<=","!=","!=="].indexOf(operator))throw new Error('Invalid operator "'+operator+'"');var test=new Assertion(eval(val+operator+val2),msg);test.assert(!0===flag(test,"object"),"expected "+util.inspect(val)+" to be "+operator+" "+util.inspect(val2),"expected "+util.inspect(val)+" to not be "+operator+" "+util.inspect(val2))},assert.closeTo=function(t,e,n,r){new Assertion(t,r).to.be.closeTo(e,n)},assert.sameMembers=function(t,e,n){new Assertion(t,n).to.have.same.members(e)},assert.includeMembers=function(t,e,n){new Assertion(t,n).to.include.members(e)},assert.ifError=function(t,e){new Assertion(t,e).to.not.be.ok},function t(e,n){return assert[n]=assert[e],t}("Throw","throw")("Throw","throws")}}),require.register("chai/lib/chai/interface/expect.js",function(t,e){e.exports=function(t){t.expect=function(e,n){return new t.Assertion(e,n)}}}),require.register("chai/lib/chai/interface/should.js",function(t,e){e.exports=function(t){function e(){function t(){return this instanceof String||this instanceof Number?new n(this.constructor(this),null,t):this instanceof Boolean?new n(1==this,null,t):new n(this,null,t)}function e(t){Object.defineProperty(this,"should",{value:t,enumerable:!0,configurable:!0,writable:!0})}Object.defineProperty(Object.prototype,"should",{set:e,get:t,configurable:!0});var r={};return r.equal=function(t,e,r){new n(t,r).to.equal(e)},r.Throw=function(t,e,r,i){new n(t,i).to.Throw(e,r)},r.exist=function(t,e){new n(t,e).to.exist},r.not={},r.not.equal=function(t,e,r){new n(t,r).to.not.equal(e)},r.not.Throw=function(t,e,r,i){new n(t,i).to.not.Throw(e,r)},r.not.exist=function(t,e){new n(t,e).to.not.exist},r["throw"]=r.Throw,r.not["throw"]=r.not.Throw,r}var n=t.Assertion;t.should=e,t.Should=e}}),require.register("chai/lib/chai/utils/addChainableMethod.js",function(t,e){var n=require("chai/lib/chai/utils/transferFlags.js"),r=require("chai/lib/chai/utils/flag.js"),i=require("chai/lib/chai/config.js"),o="__proto__"in Object,s=/^(?:length|name|arguments|caller)$/,a=Function.prototype.call,u=Function.prototype.apply;e.exports=function(t,e,c,l){"function"!=typeof l&&(l=function(){});var h={method:c,chainingBehavior:l};t.__methods||(t.__methods={}),t.__methods[e]=h,Object.defineProperty(t,e,{get:function(){h.chainingBehavior.call(this);var e=function f(){var t=r(this,"ssfi");t&&i.includeStack===!1&&r(this,"ssfi",f);var e=h.method.apply(this,arguments);return void 0===e?this:e};if(o){var c=e.__proto__=Object.create(this);c.call=a,c.apply=u}else{var l=Object.getOwnPropertyNames(t);l.forEach(function(n){if(!s.test(n)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r)}})}return n(this,e),e},configurable:!0})}}),require.register("chai/lib/chai/utils/addMethod.js",function(t,e){var n=require("chai/lib/chai/config.js"),r=require("chai/lib/chai/utils/flag.js");e.exports=function(t,e,i){t[e]=function(){var o=r(this,"ssfi");o&&n.includeStack===!1&&r(this,"ssfi",t[e]);var s=i.apply(this,arguments);return void 0===s?this:s}}}),require.register("chai/lib/chai/utils/addProperty.js",function(t,e){e.exports=function(t,e,n){Object.defineProperty(t,e,{get:function(){var t=n.call(this);return void 0===t?this:t},configurable:!0})}}),require.register("chai/lib/chai/utils/flag.js",function(t,e){e.exports=function(t,e,n){var r=t.__flags||(t.__flags=Object.create(null));return 3!==arguments.length?r[e]:void(r[e]=n)}}),require.register("chai/lib/chai/utils/getActual.js",function(t,e){e.exports=function(t,e){return e.length>4?e[4]:t._obj}}),require.register("chai/lib/chai/utils/getEnumerableProperties.js",function(t,e){e.exports=function(t){var e=[];for(var n in t)e.push(n);return e}}),require.register("chai/lib/chai/utils/getMessage.js",function(t,e){var n=require("chai/lib/chai/utils/flag.js"),r=require("chai/lib/chai/utils/getActual.js"),i=(require("chai/lib/chai/utils/inspect.js"),require("chai/lib/chai/utils/objDisplay.js"));e.exports=function(t,e){var o=n(t,"negate"),s=n(t,"object"),a=e[3],u=r(t,e),c=o?e[2]:e[1],l=n(t,"message");return"function"==typeof c&&(c=c()),c=c||"",c=c.replace(/#{this}/g,i(s)).replace(/#{act}/g,i(u)).replace(/#{exp}/g,i(a)),l?l+": "+c:c}}),require.register("chai/lib/chai/utils/getName.js",function(t,e){e.exports=function(t){if(t.name)return t.name;var e=/^\s?function ([^(]*)\(/.exec(t);return e&&e[1]?e[1]:""}}),require.register("chai/lib/chai/utils/getPathValue.js",function(t,e){function n(t){var e=t.replace(/\[/g,".["),n=e.match(/(\\\.|[^.]+?)+/g);return n.map(function(t){var e=/\[(\d+)\]$/,n=e.exec(t);return n?{i:parseFloat(n[1])}:{p:t}})}function r(t,e){for(var n,r=e,i=0,o=t.length;o>i;i++){var s=t[i];r?("undefined"!=typeof s.p?r=r[s.p]:"undefined"!=typeof s.i&&(r=r[s.i]),i==o-1&&(n=r)):n=void 0}return n}e.exports=function(t,e){var i=n(t);return r(i,e)}}),require.register("chai/lib/chai/utils/getProperties.js",function(t,e){e.exports=function(){function t(t){-1===e.indexOf(t)&&e.push(t)}for(var e=Object.getOwnPropertyNames(subject),n=Object.getPrototypeOf(subject);null!==n;)Object.getOwnPropertyNames(n).forEach(t),n=Object.getPrototypeOf(n);return e}}),require.register("chai/lib/chai/utils/index.js",function(t,e){var t=e.exports={};t.test=require("chai/lib/chai/utils/test.js"),t.type=require("chai/lib/chai/utils/type.js"),t.getMessage=require("chai/lib/chai/utils/getMessage.js"),t.getActual=require("chai/lib/chai/utils/getActual.js"),t.inspect=require("chai/lib/chai/utils/inspect.js"),t.objDisplay=require("chai/lib/chai/utils/objDisplay.js"),t.flag=require("chai/lib/chai/utils/flag.js"),t.transferFlags=require("chai/lib/chai/utils/transferFlags.js"),t.eql=require("chaijs~deep-eql@0.1.3"),t.getPathValue=require("chai/lib/chai/utils/getPathValue.js"),t.getName=require("chai/lib/chai/utils/getName.js"),t.addProperty=require("chai/lib/chai/utils/addProperty.js"),t.addMethod=require("chai/lib/chai/utils/addMethod.js"),t.overwriteProperty=require("chai/lib/chai/utils/overwriteProperty.js"),t.overwriteMethod=require("chai/lib/chai/utils/overwriteMethod.js"),t.addChainableMethod=require("chai/lib/chai/utils/addChainableMethod.js"),t.overwriteChainableMethod=require("chai/lib/chai/utils/overwriteChainableMethod.js")}),require.register("chai/lib/chai/utils/inspect.js",function(t,e){function n(t,e,n){var i={showHidden:e,seen:[],stylize:function(t){return t}};return r(i,t,"undefined"==typeof n?2:n)}function r(e,n,p){if(n&&"function"==typeof n.inspect&&n.inspect!==t.inspect&&(!n.constructor||n.constructor.prototype!==n)){var b=n.inspect(p);return"string"!=typeof b&&(b=r(e,b,p)),b}var y=i(e,n);if(y)return y;if(m(n)){if("outerHTML"in n)return n.outerHTML;try{if(document.xmlVersion){var w=new XMLSerializer;return w.serializeToString(n)}var x="http://www.w3.org/1999/xhtml",j=document.createElementNS(x,"_");return j.appendChild(n.cloneNode(!1)),html=j.innerHTML.replace("><",">"+n.innerHTML+"<"),j.innerHTML="",html}catch(E){}}var T=v(n),k=e.showHidden?g(n):T;if(0===k.length||f(n)&&(1===k.length&&"stack"===k[0]||2===k.length&&"description"===k[0]&&"stack"===k[1])){if("function"==typeof n){var q=d(n),_=q?": "+q:"";return e.stylize("[Function"+_+"]","special")}if(l(n))return e.stylize(RegExp.prototype.toString.call(n),"regexp");if(h(n))return e.stylize(Date.prototype.toUTCString.call(n),"date");if(f(n))return o(n)}var O="",A=!1,S=["{","}"];if(c(n)&&(A=!0,S=["[","]"]),"function"==typeof n){var q=d(n),_=q?": "+q:"";O=" [Function"+_+"]"}if(l(n)&&(O=" "+RegExp.prototype.toString.call(n)),h(n)&&(O=" "+Date.prototype.toUTCString.call(n)),f(n))return o(n);if(0===k.length&&(!A||0==n.length))return S[0]+O+S[1];if(0>p)return l(n)?e.stylize(RegExp.prototype.toString.call(n),"regexp"):e.stylize("[Object]","special");e.seen.push(n);var M;return M=A?s(e,n,p,T,k):k.map(function(t){return a(e,n,p,T,t,A)}),e.seen.pop(),u(M,O,S)}function i(t,e){switch(typeof e){case"undefined":return t.stylize("undefined","undefined");case"string":var n="'"+JSON.stringify(e).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return t.stylize(n,"string");case"number":return 0===e&&1/e===-1/0?t.stylize("-0","number"):t.stylize(""+e,"number");case"boolean":return t.stylize(""+e,"boolean")}return null===e?t.stylize("null","null"):void 0}function o(t){return"["+Error.prototype.toString.call(t)+"]"}function s(t,e,n,r,i){for(var o=[],s=0,u=e.length;u>s;++s)o.push(Object.prototype.hasOwnProperty.call(e,String(s))?a(t,e,n,r,String(s),!0):"");return i.forEach(function(i){i.match(/^\d+$/)||o.push(a(t,e,n,r,i,!0))}),o}function a(t,e,n,i,o,s){var a,u;if(e.__lookupGetter__&&(e.__lookupGetter__(o)?u=e.__lookupSetter__(o)?t.stylize("[Getter/Setter]","special"):t.stylize("[Getter]","special"):e.__lookupSetter__(o)&&(u=t.stylize("[Setter]","special"))),i.indexOf(o)<0&&(a="["+o+"]"),u||(t.seen.indexOf(e[o])<0?(u=null===n?r(t,e[o],null):r(t,e[o],n-1),u.indexOf("\n")>-1&&(u=s?u.split("\n").map(function(t){return" "+t}).join("\n").substr(2):"\n"+u.split("\n").map(function(t){return" "+t}).join("\n"))):u=t.stylize("[Circular]","special")),"undefined"==typeof a){if(s&&o.match(/^\d+$/))return u;a=JSON.stringify(""+o),a.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=t.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=t.stylize(a,"string"))}return a+": "+u}function u(t,e,n){var r=0,i=t.reduce(function(t,e){return r++,e.indexOf("\n")>=0&&r++,t+e.length+1},0);return i>60?n[0]+(""===e?"":e+"\n ")+" "+t.join(",\n ")+" "+n[1]:n[0]+e+" "+t.join(", ")+" "+n[1]}function c(t){return Array.isArray(t)||"object"==typeof t&&"[object Array]"===p(t)}function l(t){return"object"==typeof t&&"[object RegExp]"===p(t)}function h(t){return"object"==typeof t&&"[object Date]"===p(t)}function f(t){return"object"==typeof t&&"[object Error]"===p(t)}function p(t){return Object.prototype.toString.call(t)}var d=require("chai/lib/chai/utils/getName.js"),g=require("chai/lib/chai/utils/getProperties.js"),v=require("chai/lib/chai/utils/getEnumerableProperties.js");e.exports=n;var m=function(t){return"object"==typeof HTMLElement?t instanceof HTMLElement:t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}}),require.register("chai/lib/chai/utils/objDisplay.js",function(t,e){var n=require("chai/lib/chai/utils/inspect.js"),r=require("chai/lib/chai/config.js");e.exports=function(t){var e=n(t),i=Object.prototype.toString.call(t);if(r.truncateThreshold&&e.length>=r.truncateThreshold){if("[object Function]"===i)return t.name&&""!==t.name?"[Function: "+t.name+"]":"[Function]";if("[object Array]"===i)return"[ Array("+t.length+") ]";if("[object Object]"===i){var o=Object.keys(t),s=o.length>2?o.splice(0,2).join(", ")+", ...":o.join(", ");return"{ Object ("+s+") }"}return e}return e}}),require.register("chai/lib/chai/utils/overwriteMethod.js",function(t,e){e.exports=function(t,e,n){var r=t[e],i=function(){return this};r&&"function"==typeof r&&(i=r),t[e]=function(){var t=n(i).apply(this,arguments);return void 0===t?this:t}}}),require.register("chai/lib/chai/utils/overwriteProperty.js",function(t,e){e.exports=function(t,e,n){var r=Object.getOwnPropertyDescriptor(t,e),i=function(){};r&&"function"==typeof r.get&&(i=r.get),Object.defineProperty(t,e,{get:function(){var t=n(i).call(this);return void 0===t?this:t},configurable:!0})}}),require.register("chai/lib/chai/utils/overwriteChainableMethod.js",function(t,e){e.exports=function(t,e,n,r){var i=t.__methods[e],o=i.chainingBehavior;i.chainingBehavior=function(){var t=r(o).call(this);return void 0===t?this:t};var s=i.method;i.method=function(){var t=n(s).apply(this,arguments);return void 0===t?this:t}}}),require.register("chai/lib/chai/utils/test.js",function(t,e){var n=require("chai/lib/chai/utils/flag.js");e.exports=function(t,e){var r=n(t,"negate"),i=e[0];return r?!i:i}}),require.register("chai/lib/chai/utils/transferFlags.js",function(t,e){e.exports=function(t,e,n){var r=t.__flags||(t.__flags=Object.create(null));e.__flags||(e.__flags=Object.create(null)),n=3===arguments.length?n:!0;for(var i in r)(n||"object"!==i&&"ssfi"!==i&&"message"!=i)&&(e.__flags[i]=r[i])}}),require.register("chai/lib/chai/utils/type.js",function(t,e){var n={"[object Arguments]":"arguments","[object Array]":"array","[object Date]":"date","[object Function]":"function","[object Number]":"number","[object RegExp]":"regexp","[object String]":"string"};e.exports=function(t){var e=Object.prototype.toString.call(t);return n[e]?n[e]:null===t?"null":void 0===t?"undefined":t===Object(t)?"object":typeof t}}),"object"==typeof exports?module.exports=require("chai"):"function"==typeof define&&define.amd?define("chai",[],function(){return require("chai")}):(this||window).chai=require("chai")}(),function(t){function e(t,e){return f.isUndefined(e)?""+e:!f.isNumber(e)||!isNaN(e)&&isFinite(e)?f.isFunction(e)||f.isRegExp(e)?e.toString():e:e.toString()}function n(t,e){return f.isString(t)?t.length=0;o--)if(u[o]!=c[o])return!1;for(o=u.length-1;o>=0;o--)if(i=u[o],!s(t[i],e[i]))return!1;return!0}function c(t,e){return t&&e?"[object RegExp]"==Object.prototype.toString.call(e)?e.test(t):t instanceof e?!0:e.call({},t)===!0?!0:!1:!1}function l(t,e,n,r){var o;f.isString(n)&&(r=n,n=null);try{e()}catch(s){o=s}if(r=(n&&n.name?" ("+n.name+").":".")+(r?" "+r:"."),t&&!o&&i(o,n,"Missing expected exception"+r),!t&&c(o,n)&&i(o,n,"Got unwanted exception"+r),t&&o&&n&&!c(o,n)||!t&&o)throw o}"undefined"==typeof t.exports&&(t.exports=t);var h=Object.create||function(t){function e(){}if(!t)throw Error("no type");return e.prototype=t,new e},f={inherits:function(t,e){t.super_=e,t.prototype=h(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})},isArray:function(t){return Array.isArray(t)},isBoolean:function(t){return"boolean"==typeof t},isNull:function(t){return null===t},isNullOrUndefined:function(t){return null==t},isNumber:function(t){return"number"==typeof t},isString:function(t){return"string"==typeof t},isSymbol:function(t){return"symbol"==typeof t},isUndefined:function(t){return void 0===t},isRegExp:function(t){return f.isObject(t)&&"[object RegExp]"===f.objectToString(t)},isObject:function(t){return"object"==typeof t&&null!==t},isDate:function(t){return f.isObject(t)&&"[object Date]"===f.objectToString(t)},isError:function(t){return isObject(t)&&("[object Error]"===objectToString(t)||t instanceof Error)},isFunction:function(t){return"function"==typeof t},isPrimitive:function(t){return null===t||"boolean"==typeof t||"number"==typeof t||"string"==typeof t||"symbol"==typeof t||"undefined"==typeof t},objectToString:function(t){return Object.prototype.toString.call(t)}},p=Array.prototype.slice,d=("function"==typeof Object.keys?Object.keys:function(t){var e=[];for(var n in t)e.push(n);return e},t.exports=o);d.AssertionError=function(t){this.name="AssertionError",this.actual=t.actual,this.expected=t.expected,this.operator=t.operator,t.message?(this.message=t.message,this.generatedMessage=!1):(this.message=r(this),this.generatedMessage=!0);var e=t.stackStartFunction||i;if(Error.captureStackTrace)Error.captureStackTrace(this,e);else try{this.stack=(new Error).stack.toString()}catch(n){}},f.inherits(d.AssertionError,Error),d.fail=i,d.ok=o,d.equal=function(t,e,n){t!=e&&i(t,e,n,"==",d.equal)},d.notEqual=function(t,e,n){t==e&&i(t,e,n,"!=",d.notEqual)},d.deepEqual=function(t,e,n){s(t,e)||i(t,e,n,"deepEqual",d.deepEqual)},d.notDeepEqual=function(t,e,n){s(t,e)&&i(t,e,n,"notDeepEqual",d.notDeepEqual)},d.strictEqual=function(t,e,n){t!==e&&i(t,e,n,"===",d.strictEqual)},d.notStrictEqual=function(t,e,n){t===e&&i(t,e,n,"!==",d.notStrictEqual)},d.throws=function(){l.apply(this,[!0].concat(p.call(arguments)))},d.doesNotThrow=function(){l.apply(this,[!1].concat(p.call(arguments)))},d.ifError=function(t){if(t)throw t},t.assert=t.exports,delete t.exports}(this);var div=document.createElement("div");div.id="mocha",document.body.appendChild(div);var g_quiet=process.env.quiet||!0;if("false"===g_quiet&&(g_quiet=!1),!g_quiet){var link=document.createElement("link");link.setAttribute("rel","stylesheet"),link.setAttribute("type","text/css"),link.setAttribute("href","../res/mocha.css"),document.getElementsByTagName("head")[0].appendChild(link)}var fs=require("fs"),path=require("path");mocha.setup({ui:"bdd"});var outputAsXML=function(){var t=process.env.out_dir;t||(t=fs.realpathSync("."),console.log("====Test results will be at: "+t));var e=0;if(window.XMLSerializer){var n=new XMLSerializer,r=process.cwd();r=r.substring(r.lastIndexOf(path.sep)+1);var i=path.join(t,r+".xml"),o=(document.getElementById("mocha-report"),document.getElementById("mocha")),s=n.serializeToString(o);s=decodeURIComponent(s),fs.writeFileSync(i,s)}var a=document.getElementById("mocha-stats"),u=a.getElementsByClassName("failures"),c=void 0,l="";return u&&u.length>0&&(c=u[0].getElementsByTagName("em"),c&&c.length>0&&(l=c[0].innerText,"0"!==l&&(e=1))),g_quiet&&process.exit(e),0};window.unitTestApplicationFailed=function(){describe("Manually verify the application",function(){it("Application should succeed",function(t){t("Application failed: "+appName)})})},window.unitTestApplicationSucceed=function(){describe("Manually verify the application",function(){it("Application should succeed",function(t){t()})})},window.unitTestApplicationTimeout=function(){describe("Manually verify the application",function(){it("Application should not timeout",function(t){t("Application timeout")})})},window.addEventListener("load",function(){mocha.run(),mocha.suite.afterAll(function(){outputAsXML()})}); \ No newline at end of file +}else this.assert(t>n,"expected #{this} to be below "+t,"expected #{this} to be at least "+t)}function h(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(t>=r,"expected #{this} to have a length at most #{exp} but got #{act}","expected #{this} to have a length above #{exp}",t,r)}else this.assert(t>=n,"expected #{this} to be at most "+t,"expected #{this} to be above "+t)}function f(t,n){n&&w(this,"message",n);var r=e.getName(t);this.assert(w(this,"object")instanceof t,"expected #{this} to be an instance of "+r,"expected #{this} to not be an instance of "+r)}function p(t,n){n&&w(this,"message",n);var r=w(this,"object");this.assert(r.hasOwnProperty(t),"expected #{this} to have own property "+e.inspect(t),"expected #{this} to not have own property "+e.inspect(t))}function d(){w(this,"doLength",!0)}function g(t,e){e&&w(this,"message",e);var n=w(this,"object");new y(n,e).to.have.property("length");var r=n.length;this.assert(r==t,"expected #{this} to have a length of #{exp} but got #{act}","expected #{this} to not have a length of #{act}",t,r)}function v(t){var n,r=w(this,"object"),i=!0;if(t=t instanceof Array?t:Array.prototype.slice.call(arguments),!t.length)throw new Error("keys required");var o=Object.keys(r),s=t,a=t.length;if(i=t.every(function(t){return~o.indexOf(t)}),w(this,"negate")||w(this,"contains")||(i=i&&t.length==o.length),a>1){t=t.map(function(t){return e.inspect(t)});var u=t.pop();n=t.join(", ")+", and "+u}else n=e.inspect(t[0]);n=(a>1?"keys ":"key ")+n,n=(w(this,"contains")?"contain ":"have ")+n,this.assert(i,"expected #{this} to "+n,"expected #{this} to not "+n,s.sort(),o.sort(),!0)}function m(t,n,r){r&&w(this,"message",r);var i=w(this,"object");new y(i,r).is.a("function");var o=!1,s=null,a=null,u=null;0===arguments.length?(n=null,t=null):t&&(t instanceof RegExp||"string"==typeof t)?(n=t,t=null):t&&t instanceof Error?(s=t,t=null,n=null):"function"==typeof t?(a=t.prototype.name||t.name,"Error"===a&&t!==Error&&(a=(new t).name)):t=null;try{i()}catch(c){if(s)return this.assert(c===s,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp}",s instanceof Error?s.toString():s,c instanceof Error?c.toString():c),w(this,"object",c),this;if(t&&(this.assert(c instanceof t,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp} but #{act} was thrown",a,c instanceof Error?c.toString():c),!n))return w(this,"object",c),this;var l="object"===e.type(c)&&"message"in c?c.message:""+c;if(null!=l&&n&&n instanceof RegExp)return this.assert(n.exec(l),"expected #{this} to throw error matching #{exp} but got #{act}","expected #{this} to throw error not matching #{exp}",n,l),w(this,"object",c),this;if(null!=l&&n&&"string"==typeof n)return this.assert(~l.indexOf(n),"expected #{this} to throw error including #{exp} but got #{act}","expected #{this} to throw error not including #{act}",n,l),w(this,"object",c),this;o=!0,u=c}var h="",f=null!==a?a:s?"#{exp}":"an error";o&&(h=" but #{act} was thrown"),this.assert(o===!0,"expected #{this} to throw "+f+h,"expected #{this} to not throw "+f+h,s instanceof Error?s.toString():s,u instanceof Error?u.toString():u),w(this,"object",u)}function b(t,e,n){return t.every(function(t){return n?e.some(function(e){return n(t,e)}):-1!==e.indexOf(t)})}var y=t.Assertion,w=(Object.prototype.toString,e.flag);["to","be","been","is","and","has","have","with","that","at","of","same"].forEach(function(t){y.addProperty(t,function(){return this})}),y.addProperty("not",function(){w(this,"negate",!0)}),y.addProperty("deep",function(){w(this,"deep",!0)}),y.addChainableMethod("an",n),y.addChainableMethod("a",n),y.addChainableMethod("include",i,r),y.addChainableMethod("contain",i,r),y.addChainableNoop("ok",function(){this.assert(w(this,"object"),"expected #{this} to be truthy","expected #{this} to be falsy")}),y.addChainableNoop("true",function(){this.assert(!0===w(this,"object"),"expected #{this} to be true","expected #{this} to be false",this.negate?!1:!0)}),y.addChainableNoop("false",function(){this.assert(!1===w(this,"object"),"expected #{this} to be false","expected #{this} to be true",this.negate?!0:!1)}),y.addChainableNoop("null",function(){this.assert(null===w(this,"object"),"expected #{this} to be null","expected #{this} not to be null")}),y.addChainableNoop("undefined",function(){this.assert(void 0===w(this,"object"),"expected #{this} to be undefined","expected #{this} not to be undefined")}),y.addChainableNoop("exist",function(){this.assert(null!=w(this,"object"),"expected #{this} to exist","expected #{this} to not exist")}),y.addChainableNoop("empty",function(){var t=w(this,"object"),e=t;Array.isArray(t)||"string"==typeof object?e=t.length:"object"==typeof t&&(e=Object.keys(t).length),this.assert(!e,"expected #{this} to be empty","expected #{this} not to be empty")}),y.addChainableNoop("arguments",o),y.addChainableNoop("Arguments",o),y.addMethod("equal",s),y.addMethod("equals",s),y.addMethod("eq",s),y.addMethod("eql",a),y.addMethod("eqls",a),y.addMethod("above",u),y.addMethod("gt",u),y.addMethod("greaterThan",u),y.addMethod("least",c),y.addMethod("gte",c),y.addMethod("below",l),y.addMethod("lt",l),y.addMethod("lessThan",l),y.addMethod("most",h),y.addMethod("lte",h),y.addMethod("within",function(t,e,n){n&&w(this,"message",n);var r=w(this,"object"),i=t+".."+e;if(w(this,"doLength")){new y(r,n).to.have.property("length");var o=r.length;this.assert(o>=t&&e>=o,"expected #{this} to have a length within "+i,"expected #{this} to not have a length within "+i)}else this.assert(r>=t&&e>=r,"expected #{this} to be within "+i,"expected #{this} to not be within "+i)}),y.addMethod("instanceof",f),y.addMethod("instanceOf",f),y.addMethod("property",function(t,n,r){r&&w(this,"message",r);var i=w(this,"deep")?"deep property ":"property ",o=w(this,"negate"),s=w(this,"object"),a=w(this,"deep")?e.getPathValue(t,s):s[t];if(o&&void 0!==n){if(void 0===a)throw r=null!=r?r+": ":"",new Error(r+e.inspect(s)+" has no "+i+e.inspect(t))}else this.assert(void 0!==a,"expected #{this} to have a "+i+e.inspect(t),"expected #{this} to not have "+i+e.inspect(t));void 0!==n&&this.assert(n===a,"expected #{this} to have a "+i+e.inspect(t)+" of #{exp}, but got #{act}","expected #{this} to not have a "+i+e.inspect(t)+" of #{act}",n,a),w(this,"object",a)}),y.addMethod("ownProperty",p),y.addMethod("haveOwnProperty",p),y.addChainableMethod("length",g,d),y.addMethod("lengthOf",g),y.addMethod("match",function(t,e){e&&w(this,"message",e);var n=w(this,"object");this.assert(t.exec(n),"expected #{this} to match "+t,"expected #{this} not to match "+t)}),y.addMethod("string",function(t,n){n&&w(this,"message",n);var r=w(this,"object");new y(r,n).is.a("string"),this.assert(~r.indexOf(t),"expected #{this} to contain "+e.inspect(t),"expected #{this} to not contain "+e.inspect(t))}),y.addMethod("keys",v),y.addMethod("key",v),y.addMethod("throw",m),y.addMethod("throws",m),y.addMethod("Throw",m),y.addMethod("respondTo",function(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=w(this,"itself"),o="function"!==e.type(r)||i?r[t]:r.prototype[t];this.assert("function"==typeof o,"expected #{this} to respond to "+e.inspect(t),"expected #{this} to not respond to "+e.inspect(t))}),y.addProperty("itself",function(){w(this,"itself",!0)}),y.addMethod("satisfy",function(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=t(r);this.assert(i,"expected #{this} to satisfy "+e.objDisplay(t),"expected #{this} to not satisfy"+e.objDisplay(t),this.negate?!1:!0,i)}),y.addMethod("closeTo",function(t,n,r){r&&w(this,"message",r);var i=w(this,"object");if(new y(i,r).is.a("number"),"number"!==e.type(t)||"number"!==e.type(n))throw new Error("the arguments to closeTo must be numbers");this.assert(Math.abs(i-t)<=n,"expected #{this} to be close to "+t+" +/- "+n,"expected #{this} not to be close to "+t+" +/- "+n)}),y.addMethod("members",function(t,n){n&&w(this,"message",n);var r=w(this,"object");new y(r).to.be.an("array"),new y(t).to.be.an("array");var i=w(this,"deep")?e.eql:void 0;return w(this,"contains")?this.assert(b(t,r,i),"expected #{this} to be a superset of #{act}","expected #{this} to not be a superset of #{act}",r,t):void this.assert(b(r,t,i)&&b(t,r,i),"expected #{this} to have the same members as #{act}","expected #{this} to not have the same members as #{act}",r,t)})}}),require.register("chai/lib/chai/interface/assert.js",function(exports,module){module.exports=function(chai,util){var Assertion=chai.Assertion,flag=util.flag,assert=chai.assert=function(t,e){var n=new Assertion(null,null,chai.assert);n.assert(t,e,"[ negation message unavailable ]")};assert.fail=function(t,e,n,r){throw n=n||"assert.fail()",new chai.AssertionError(n,{actual:t,expected:e,operator:r},assert.fail)},assert.ok=function(t,e){new Assertion(t,e).is.ok},assert.notOk=function(t,e){new Assertion(t,e).is.not.ok},assert.equal=function(t,e,n){var r=new Assertion(t,n,assert.equal);r.assert(e==flag(r,"object"),"expected #{this} to equal #{exp}","expected #{this} to not equal #{act}",e,t)},assert.notEqual=function(t,e,n){var r=new Assertion(t,n,assert.notEqual);r.assert(e!=flag(r,"object"),"expected #{this} to not equal #{exp}","expected #{this} to equal #{act}",e,t)},assert.strictEqual=function(t,e,n){new Assertion(t,n).to.equal(e)},assert.notStrictEqual=function(t,e,n){new Assertion(t,n).to.not.equal(e)},assert.deepEqual=function(t,e,n){new Assertion(t,n).to.eql(e)},assert.notDeepEqual=function(t,e,n){new Assertion(t,n).to.not.eql(e)},assert.isTrue=function(t,e){new Assertion(t,e).is["true"]},assert.isFalse=function(t,e){new Assertion(t,e).is["false"]},assert.isNull=function(t,e){new Assertion(t,e).to.equal(null)},assert.isNotNull=function(t,e){new Assertion(t,e).to.not.equal(null)},assert.isUndefined=function(t,e){new Assertion(t,e).to.equal(void 0)},assert.isDefined=function(t,e){new Assertion(t,e).to.not.equal(void 0)},assert.isFunction=function(t,e){new Assertion(t,e).to.be.a("function")},assert.isNotFunction=function(t,e){new Assertion(t,e).to.not.be.a("function")},assert.isObject=function(t,e){new Assertion(t,e).to.be.a("object")},assert.isNotObject=function(t,e){new Assertion(t,e).to.not.be.a("object")},assert.isArray=function(t,e){new Assertion(t,e).to.be.an("array")},assert.isNotArray=function(t,e){new Assertion(t,e).to.not.be.an("array")},assert.isString=function(t,e){new Assertion(t,e).to.be.a("string")},assert.isNotString=function(t,e){new Assertion(t,e).to.not.be.a("string")},assert.isNumber=function(t,e){new Assertion(t,e).to.be.a("number")},assert.isNotNumber=function(t,e){new Assertion(t,e).to.not.be.a("number")},assert.isBoolean=function(t,e){new Assertion(t,e).to.be.a("boolean")},assert.isNotBoolean=function(t,e){new Assertion(t,e).to.not.be.a("boolean")},assert.typeOf=function(t,e,n){new Assertion(t,n).to.be.a(e)},assert.notTypeOf=function(t,e,n){new Assertion(t,n).to.not.be.a(e)},assert.instanceOf=function(t,e,n){new Assertion(t,n).to.be.instanceOf(e)},assert.notInstanceOf=function(t,e,n){new Assertion(t,n).to.not.be.instanceOf(e)},assert.include=function(t,e,n){new Assertion(t,n,assert.include).include(e)},assert.notInclude=function(t,e,n){new Assertion(t,n,assert.notInclude).not.include(e)},assert.match=function(t,e,n){new Assertion(t,n).to.match(e)},assert.notMatch=function(t,e,n){new Assertion(t,n).to.not.match(e)},assert.property=function(t,e,n){new Assertion(t,n).to.have.property(e)},assert.notProperty=function(t,e,n){new Assertion(t,n).to.not.have.property(e)},assert.deepProperty=function(t,e,n){new Assertion(t,n).to.have.deep.property(e)},assert.notDeepProperty=function(t,e,n){new Assertion(t,n).to.not.have.deep.property(e)},assert.propertyVal=function(t,e,n,r){new Assertion(t,r).to.have.property(e,n)},assert.propertyNotVal=function(t,e,n,r){new Assertion(t,r).to.not.have.property(e,n)},assert.deepPropertyVal=function(t,e,n,r){new Assertion(t,r).to.have.deep.property(e,n)},assert.deepPropertyNotVal=function(t,e,n,r){new Assertion(t,r).to.not.have.deep.property(e,n)},assert.lengthOf=function(t,e,n){new Assertion(t,n).to.have.length(e)},assert.Throw=function(t,e,n,r){("string"==typeof e||e instanceof RegExp)&&(n=e,e=null);var i=new Assertion(t,r).to.Throw(e,n);return flag(i,"object")},assert.doesNotThrow=function(t,e,n){"string"==typeof e&&(n=e,e=null),new Assertion(t,n).to.not.Throw(e)},assert.operator=function(val,operator,val2,msg){if(!~["==","===",">",">=","<","<=","!=","!=="].indexOf(operator))throw new Error('Invalid operator "'+operator+'"');var test=new Assertion(eval(val+operator+val2),msg);test.assert(!0===flag(test,"object"),"expected "+util.inspect(val)+" to be "+operator+" "+util.inspect(val2),"expected "+util.inspect(val)+" to not be "+operator+" "+util.inspect(val2))},assert.closeTo=function(t,e,n,r){new Assertion(t,r).to.be.closeTo(e,n)},assert.sameMembers=function(t,e,n){new Assertion(t,n).to.have.same.members(e)},assert.includeMembers=function(t,e,n){new Assertion(t,n).to.include.members(e)},assert.ifError=function(t,e){new Assertion(t,e).to.not.be.ok},function t(e,n){return assert[n]=assert[e],t}("Throw","throw")("Throw","throws")}}),require.register("chai/lib/chai/interface/expect.js",function(t,e){e.exports=function(t){t.expect=function(e,n){return new t.Assertion(e,n)}}}),require.register("chai/lib/chai/interface/should.js",function(t,e){e.exports=function(t){function e(){function t(){return this instanceof String||this instanceof Number?new n(this.constructor(this),null,t):this instanceof Boolean?new n(1==this,null,t):new n(this,null,t)}function e(t){Object.defineProperty(this,"should",{value:t,enumerable:!0,configurable:!0,writable:!0})}Object.defineProperty(Object.prototype,"should",{set:e,get:t,configurable:!0});var r={};return r.equal=function(t,e,r){new n(t,r).to.equal(e)},r.Throw=function(t,e,r,i){new n(t,i).to.Throw(e,r)},r.exist=function(t,e){new n(t,e).to.exist},r.not={},r.not.equal=function(t,e,r){new n(t,r).to.not.equal(e)},r.not.Throw=function(t,e,r,i){new n(t,i).to.not.Throw(e,r)},r.not.exist=function(t,e){new n(t,e).to.not.exist},r["throw"]=r.Throw,r.not["throw"]=r.not.Throw,r}var n=t.Assertion;t.should=e,t.Should=e}}),require.register("chai/lib/chai/utils/addChainableMethod.js",function(t,e){var n=require("chai/lib/chai/utils/transferFlags.js"),r=require("chai/lib/chai/utils/flag.js"),i=require("chai/lib/chai/config.js"),o="__proto__"in Object,s=/^(?:length|name|arguments|caller)$/,a=Function.prototype.call,u=Function.prototype.apply;e.exports=function(t,e,c,l){"function"!=typeof l&&(l=function(){});var h={method:c,chainingBehavior:l};t.__methods||(t.__methods={}),t.__methods[e]=h,Object.defineProperty(t,e,{get:function(){h.chainingBehavior.call(this);var e=function f(){var t=r(this,"ssfi");t&&i.includeStack===!1&&r(this,"ssfi",f);var e=h.method.apply(this,arguments);return void 0===e?this:e};if(o){var c=e.__proto__=Object.create(this);c.call=a,c.apply=u}else{var l=Object.getOwnPropertyNames(t);l.forEach(function(n){if(!s.test(n)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r)}})}return n(this,e),e},configurable:!0})}}),require.register("chai/lib/chai/utils/addMethod.js",function(t,e){var n=require("chai/lib/chai/config.js"),r=require("chai/lib/chai/utils/flag.js");e.exports=function(t,e,i){t[e]=function(){var o=r(this,"ssfi");o&&n.includeStack===!1&&r(this,"ssfi",t[e]);var s=i.apply(this,arguments);return void 0===s?this:s}}}),require.register("chai/lib/chai/utils/addProperty.js",function(t,e){e.exports=function(t,e,n){Object.defineProperty(t,e,{get:function(){var t=n.call(this);return void 0===t?this:t},configurable:!0})}}),require.register("chai/lib/chai/utils/flag.js",function(t,e){e.exports=function(t,e,n){var r=t.__flags||(t.__flags=Object.create(null));return 3!==arguments.length?r[e]:void(r[e]=n)}}),require.register("chai/lib/chai/utils/getActual.js",function(t,e){e.exports=function(t,e){return e.length>4?e[4]:t._obj}}),require.register("chai/lib/chai/utils/getEnumerableProperties.js",function(t,e){e.exports=function(t){var e=[];for(var n in t)e.push(n);return e}}),require.register("chai/lib/chai/utils/getMessage.js",function(t,e){var n=require("chai/lib/chai/utils/flag.js"),r=require("chai/lib/chai/utils/getActual.js"),i=(require("chai/lib/chai/utils/inspect.js"),require("chai/lib/chai/utils/objDisplay.js"));e.exports=function(t,e){var o=n(t,"negate"),s=n(t,"object"),a=e[3],u=r(t,e),c=o?e[2]:e[1],l=n(t,"message");return"function"==typeof c&&(c=c()),c=c||"",c=c.replace(/#{this}/g,i(s)).replace(/#{act}/g,i(u)).replace(/#{exp}/g,i(a)),l?l+": "+c:c}}),require.register("chai/lib/chai/utils/getName.js",function(t,e){e.exports=function(t){if(t.name)return t.name;var e=/^\s?function ([^(]*)\(/.exec(t);return e&&e[1]?e[1]:""}}),require.register("chai/lib/chai/utils/getPathValue.js",function(t,e){function n(t){var e=t.replace(/\[/g,".["),n=e.match(/(\\\.|[^.]+?)+/g);return n.map(function(t){var e=/\[(\d+)\]$/,n=e.exec(t);return n?{i:parseFloat(n[1])}:{p:t}})}function r(t,e){for(var n,r=e,i=0,o=t.length;o>i;i++){var s=t[i];r?("undefined"!=typeof s.p?r=r[s.p]:"undefined"!=typeof s.i&&(r=r[s.i]),i==o-1&&(n=r)):n=void 0}return n}e.exports=function(t,e){var i=n(t);return r(i,e)}}),require.register("chai/lib/chai/utils/getProperties.js",function(t,e){e.exports=function(){function t(t){-1===e.indexOf(t)&&e.push(t)}for(var e=Object.getOwnPropertyNames(subject),n=Object.getPrototypeOf(subject);null!==n;)Object.getOwnPropertyNames(n).forEach(t),n=Object.getPrototypeOf(n);return e}}),require.register("chai/lib/chai/utils/index.js",function(t,e){var t=e.exports={};t.test=require("chai/lib/chai/utils/test.js"),t.type=require("chai/lib/chai/utils/type.js"),t.getMessage=require("chai/lib/chai/utils/getMessage.js"),t.getActual=require("chai/lib/chai/utils/getActual.js"),t.inspect=require("chai/lib/chai/utils/inspect.js"),t.objDisplay=require("chai/lib/chai/utils/objDisplay.js"),t.flag=require("chai/lib/chai/utils/flag.js"),t.transferFlags=require("chai/lib/chai/utils/transferFlags.js"),t.eql=require("chaijs~deep-eql@0.1.3"),t.getPathValue=require("chai/lib/chai/utils/getPathValue.js"),t.getName=require("chai/lib/chai/utils/getName.js"),t.addProperty=require("chai/lib/chai/utils/addProperty.js"),t.addMethod=require("chai/lib/chai/utils/addMethod.js"),t.overwriteProperty=require("chai/lib/chai/utils/overwriteProperty.js"),t.overwriteMethod=require("chai/lib/chai/utils/overwriteMethod.js"),t.addChainableMethod=require("chai/lib/chai/utils/addChainableMethod.js"),t.overwriteChainableMethod=require("chai/lib/chai/utils/overwriteChainableMethod.js")}),require.register("chai/lib/chai/utils/inspect.js",function(t,e){function n(t,e,n){var i={showHidden:e,seen:[],stylize:function(t){return t}};return r(i,t,"undefined"==typeof n?2:n)}function r(e,n,p){if(n&&"function"==typeof n.inspect&&n.inspect!==t.inspect&&(!n.constructor||n.constructor.prototype!==n)){var b=n.inspect(p);return"string"!=typeof b&&(b=r(e,b,p)),b}var y=i(e,n);if(y)return y;if(m(n)){if("outerHTML"in n)return n.outerHTML;try{if(document.xmlVersion){var w=new XMLSerializer;return w.serializeToString(n)}var x="http://www.w3.org/1999/xhtml",j=document.createElementNS(x,"_");return j.appendChild(n.cloneNode(!1)),html=j.innerHTML.replace("><",">"+n.innerHTML+"<"),j.innerHTML="",html}catch(E){}}var T=v(n),k=e.showHidden?g(n):T;if(0===k.length||f(n)&&(1===k.length&&"stack"===k[0]||2===k.length&&"description"===k[0]&&"stack"===k[1])){if("function"==typeof n){var q=d(n),_=q?": "+q:"";return e.stylize("[Function"+_+"]","special")}if(l(n))return e.stylize(RegExp.prototype.toString.call(n),"regexp");if(h(n))return e.stylize(Date.prototype.toUTCString.call(n),"date");if(f(n))return o(n)}var O="",A=!1,S=["{","}"];if(c(n)&&(A=!0,S=["[","]"]),"function"==typeof n){var q=d(n),_=q?": "+q:"";O=" [Function"+_+"]"}if(l(n)&&(O=" "+RegExp.prototype.toString.call(n)),h(n)&&(O=" "+Date.prototype.toUTCString.call(n)),f(n))return o(n);if(0===k.length&&(!A||0==n.length))return S[0]+O+S[1];if(0>p)return l(n)?e.stylize(RegExp.prototype.toString.call(n),"regexp"):e.stylize("[Object]","special");e.seen.push(n);var M;return M=A?s(e,n,p,T,k):k.map(function(t){return a(e,n,p,T,t,A)}),e.seen.pop(),u(M,O,S)}function i(t,e){switch(typeof e){case"undefined":return t.stylize("undefined","undefined");case"string":var n="'"+JSON.stringify(e).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return t.stylize(n,"string");case"number":return 0===e&&1/e===-1/0?t.stylize("-0","number"):t.stylize(""+e,"number");case"boolean":return t.stylize(""+e,"boolean")}return null===e?t.stylize("null","null"):void 0}function o(t){return"["+Error.prototype.toString.call(t)+"]"}function s(t,e,n,r,i){for(var o=[],s=0,u=e.length;u>s;++s)o.push(Object.prototype.hasOwnProperty.call(e,String(s))?a(t,e,n,r,String(s),!0):"");return i.forEach(function(i){i.match(/^\d+$/)||o.push(a(t,e,n,r,i,!0))}),o}function a(t,e,n,i,o,s){var a,u;if(e.__lookupGetter__&&(e.__lookupGetter__(o)?u=e.__lookupSetter__(o)?t.stylize("[Getter/Setter]","special"):t.stylize("[Getter]","special"):e.__lookupSetter__(o)&&(u=t.stylize("[Setter]","special"))),i.indexOf(o)<0&&(a="["+o+"]"),u||(t.seen.indexOf(e[o])<0?(u=null===n?r(t,e[o],null):r(t,e[o],n-1),u.indexOf("\n")>-1&&(u=s?u.split("\n").map(function(t){return" "+t}).join("\n").substr(2):"\n"+u.split("\n").map(function(t){return" "+t}).join("\n"))):u=t.stylize("[Circular]","special")),"undefined"==typeof a){if(s&&o.match(/^\d+$/))return u;a=JSON.stringify(""+o),a.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=t.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=t.stylize(a,"string"))}return a+": "+u}function u(t,e,n){var r=0,i=t.reduce(function(t,e){return r++,e.indexOf("\n")>=0&&r++,t+e.length+1},0);return i>60?n[0]+(""===e?"":e+"\n ")+" "+t.join(",\n ")+" "+n[1]:n[0]+e+" "+t.join(", ")+" "+n[1]}function c(t){return Array.isArray(t)||"object"==typeof t&&"[object Array]"===p(t)}function l(t){return"object"==typeof t&&"[object RegExp]"===p(t)}function h(t){return"object"==typeof t&&"[object Date]"===p(t)}function f(t){return"object"==typeof t&&"[object Error]"===p(t)}function p(t){return Object.prototype.toString.call(t)}var d=require("chai/lib/chai/utils/getName.js"),g=require("chai/lib/chai/utils/getProperties.js"),v=require("chai/lib/chai/utils/getEnumerableProperties.js");e.exports=n;var m=function(t){return"object"==typeof HTMLElement?t instanceof HTMLElement:t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}}),require.register("chai/lib/chai/utils/objDisplay.js",function(t,e){var n=require("chai/lib/chai/utils/inspect.js"),r=require("chai/lib/chai/config.js");e.exports=function(t){var e=n(t),i=Object.prototype.toString.call(t);if(r.truncateThreshold&&e.length>=r.truncateThreshold){if("[object Function]"===i)return t.name&&""!==t.name?"[Function: "+t.name+"]":"[Function]";if("[object Array]"===i)return"[ Array("+t.length+") ]";if("[object Object]"===i){var o=Object.keys(t),s=o.length>2?o.splice(0,2).join(", ")+", ...":o.join(", ");return"{ Object ("+s+") }"}return e}return e}}),require.register("chai/lib/chai/utils/overwriteMethod.js",function(t,e){e.exports=function(t,e,n){var r=t[e],i=function(){return this};r&&"function"==typeof r&&(i=r),t[e]=function(){var t=n(i).apply(this,arguments);return void 0===t?this:t}}}),require.register("chai/lib/chai/utils/overwriteProperty.js",function(t,e){e.exports=function(t,e,n){var r=Object.getOwnPropertyDescriptor(t,e),i=function(){};r&&"function"==typeof r.get&&(i=r.get),Object.defineProperty(t,e,{get:function(){var t=n(i).call(this);return void 0===t?this:t},configurable:!0})}}),require.register("chai/lib/chai/utils/overwriteChainableMethod.js",function(t,e){e.exports=function(t,e,n,r){var i=t.__methods[e],o=i.chainingBehavior;i.chainingBehavior=function(){var t=r(o).call(this);return void 0===t?this:t};var s=i.method;i.method=function(){var t=n(s).apply(this,arguments);return void 0===t?this:t}}}),require.register("chai/lib/chai/utils/test.js",function(t,e){var n=require("chai/lib/chai/utils/flag.js");e.exports=function(t,e){var r=n(t,"negate"),i=e[0];return r?!i:i}}),require.register("chai/lib/chai/utils/transferFlags.js",function(t,e){e.exports=function(t,e,n){var r=t.__flags||(t.__flags=Object.create(null));e.__flags||(e.__flags=Object.create(null)),n=3===arguments.length?n:!0;for(var i in r)(n||"object"!==i&&"ssfi"!==i&&"message"!=i)&&(e.__flags[i]=r[i])}}),require.register("chai/lib/chai/utils/type.js",function(t,e){var n={"[object Arguments]":"arguments","[object Array]":"array","[object Date]":"date","[object Function]":"function","[object Number]":"number","[object RegExp]":"regexp","[object String]":"string"};e.exports=function(t){var e=Object.prototype.toString.call(t);return n[e]?n[e]:null===t?"null":void 0===t?"undefined":t===Object(t)?"object":typeof t}}),"object"==typeof exports?module.exports=require("chai"):"function"==typeof define&&define.amd?define("chai",[],function(){return require("chai")}):(this||window).chai=require("chai")}(),function(t){function e(t,e){return f.isUndefined(e)?""+e:!f.isNumber(e)||!isNaN(e)&&isFinite(e)?f.isFunction(e)||f.isRegExp(e)?e.toString():e:e.toString()}function n(t,e){return f.isString(t)?t.length=0;o--)if(u[o]!=c[o])return!1;for(o=u.length-1;o>=0;o--)if(i=u[o],!s(t[i],e[i]))return!1;return!0}function c(t,e){return t&&e?"[object RegExp]"==Object.prototype.toString.call(e)?e.test(t):t instanceof e?!0:e.call({},t)===!0?!0:!1:!1}function l(t,e,n,r){var o;f.isString(n)&&(r=n,n=null);try{e()}catch(s){o=s}if(r=(n&&n.name?" ("+n.name+").":".")+(r?" "+r:"."),t&&!o&&i(o,n,"Missing expected exception"+r),!t&&c(o,n)&&i(o,n,"Got unwanted exception"+r),t&&o&&n&&!c(o,n)||!t&&o)throw o}"undefined"==typeof t.exports&&(t.exports=t);var h=Object.create||function(t){function e(){}if(!t)throw Error("no type");return e.prototype=t,new e},f={inherits:function(t,e){t.super_=e,t.prototype=h(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})},isArray:function(t){return Array.isArray(t)},isBoolean:function(t){return"boolean"==typeof t},isNull:function(t){return null===t},isNullOrUndefined:function(t){return null==t},isNumber:function(t){return"number"==typeof t},isString:function(t){return"string"==typeof t},isSymbol:function(t){return"symbol"==typeof t},isUndefined:function(t){return void 0===t},isRegExp:function(t){return f.isObject(t)&&"[object RegExp]"===f.objectToString(t)},isObject:function(t){return"object"==typeof t&&null!==t},isDate:function(t){return f.isObject(t)&&"[object Date]"===f.objectToString(t)},isError:function(t){return isObject(t)&&("[object Error]"===objectToString(t)||t instanceof Error)},isFunction:function(t){return"function"==typeof t},isPrimitive:function(t){return null===t||"boolean"==typeof t||"number"==typeof t||"string"==typeof t||"symbol"==typeof t||"undefined"==typeof t},objectToString:function(t){return Object.prototype.toString.call(t)}},p=Array.prototype.slice,d=("function"==typeof Object.keys?Object.keys:function(t){var e=[];for(var n in t)e.push(n);return e},t.exports=o);d.AssertionError=function(t){this.name="AssertionError",this.actual=t.actual,this.expected=t.expected,this.operator=t.operator,t.message?(this.message=t.message,this.generatedMessage=!1):(this.message=r(this),this.generatedMessage=!0);var e=t.stackStartFunction||i;if(Error.captureStackTrace)Error.captureStackTrace(this,e);else try{this.stack=(new Error).stack.toString()}catch(n){}},f.inherits(d.AssertionError,Error),d.fail=i,d.ok=o,d.equal=function(t,e,n){t!=e&&i(t,e,n,"==",d.equal)},d.notEqual=function(t,e,n){t==e&&i(t,e,n,"!=",d.notEqual)},d.deepEqual=function(t,e,n){s(t,e)||i(t,e,n,"deepEqual",d.deepEqual)},d.notDeepEqual=function(t,e,n){s(t,e)&&i(t,e,n,"notDeepEqual",d.notDeepEqual)},d.strictEqual=function(t,e,n){t!==e&&i(t,e,n,"===",d.strictEqual)},d.notStrictEqual=function(t,e,n){t===e&&i(t,e,n,"!==",d.notStrictEqual)},d.throws=function(){l.apply(this,[!0].concat(p.call(arguments)))},d.doesNotThrow=function(){l.apply(this,[!1].concat(p.call(arguments)))},d.ifError=function(t){if(t)throw t},t.assert=t.exports,delete t.exports}(this);var div=document.createElement("div");div.id="mocha",document.body.appendChild(div);var g_quiet=process.env.quiet||!0;if("false"===g_quiet&&(g_quiet=!1),!g_quiet){var link=document.createElement("link");link.setAttribute("rel","stylesheet"),link.setAttribute("type","text/css"),link.setAttribute("href","../res/mocha.css"),document.getElementsByTagName("head")[0].appendChild(link)}var fs=require("fs"),path=require("path"),net=require("net"),spawn=require("child_process").spawn,createTCPServer=function(t,e){var n=net.createServer();return e&&(process.exit=function(){n.close(),process.quit()}),t=t||13013,n.on("error",function(t){console.error("Failed to launch TCP server: "+t.code)}),n.listen(t),n},spawnChildProcess=function(t){var e=spawn(process.execPath,[t]);return e};mocha.setup({ui:"bdd"});var outputAsXML=function(){var t=process.env.out_dir;t||(t=fs.realpathSync("."),console.log("====Test results will be at: "+t));var e=0;if(window.XMLSerializer){var n=new XMLSerializer,r=process.cwd();r=r.substring(r.lastIndexOf(path.sep)+1);var i=path.join(t,r+".xml"),o=(document.getElementById("mocha-report"),document.getElementById("mocha")),s=n.serializeToString(o);s=decodeURIComponent(s),fs.writeFileSync(i,s)}var a=document.getElementById("mocha-stats"),u=a.getElementsByClassName("failures"),c=void 0,l="";return u&&u.length>0&&(c=u[0].getElementsByTagName("em"),c&&c.length>0&&(l=c[0].innerText,"0"!==l&&(e=1))),g_quiet&&process.exit(e),0};window.unitTestApplicationFailed=function(){describe("Manually verify the application",function(){it("Application should succeed",function(t){t("Application failed: "+appName)})})},window.unitTestApplicationSucceed=function(){describe("Manually verify the application",function(){it("Application should succeed",function(t){t()})})},window.unitTestApplicationTimeout=function(){describe("Manually verify the application",function(){it("Application should not timeout",function(t){t("Application timeout")})})},window.addEventListener("load",function(){mocha.run(),mocha.suite.afterAll(function(){outputAsXML()})}); \ No newline at end of file diff --git a/tests/automation/res/util.js b/tests/automation/res/util.js index 9f0440571f..127aa82ffa 100644 --- a/tests/automation/res/util.js +++ b/tests/automation/res/util.js @@ -19,6 +19,29 @@ if (!g_quiet) { var fs = require('fs'); var path = require('path'); +var net = require('net'); +var spawn = require('child_process').spawn; + +var createTCPServer = function(port, autoClose) { + var server = net.createServer(); + if (autoClose) { + process.exit = function() { + server.close(); + process.quit(); + }; + } + port = port || 13013; + server.on('error', function(e) { + console.error('Failed to launch TCP server: '+ e.code); + }); + server.listen(port); + return server; +}; + +var spawnChildProcess = function(appPath) { + var child = spawn(process.execPath, [appPath]); + return child; +}; mocha.setup({ui:'bdd'}); From 0db26019332a2cdfa3f96f30b916de2aba458d5c Mon Sep 17 00:00:00 2001 From: yejingfu Date: Thu, 27 Nov 2014 13:55:11 +0800 Subject: [PATCH 287/492] [Automation] Add test case "app-single-instance". --- .../app-single-instance/app/index.html | 22 ++++++++++ .../app-single-instance/app/package.json | 5 +++ .../automation/app-single-instance/index.html | 11 +++++ .../app-single-instance/mocha_test.js | 42 +++++++++++++++++++ .../app-single-instance/package.json | 4 ++ 5 files changed, 84 insertions(+) create mode 100644 tests/automation/app-single-instance/app/index.html create mode 100644 tests/automation/app-single-instance/app/package.json create mode 100644 tests/automation/app-single-instance/index.html create mode 100644 tests/automation/app-single-instance/mocha_test.js create mode 100644 tests/automation/app-single-instance/package.json diff --git a/tests/automation/app-single-instance/app/index.html b/tests/automation/app-single-instance/app/index.html new file mode 100644 index 0000000000..95bbaf1f1f --- /dev/null +++ b/tests/automation/app-single-instance/app/index.html @@ -0,0 +1,22 @@ + + + + APP Single Instance + + +
            + + + \ No newline at end of file diff --git a/tests/automation/app-single-instance/app/package.json b/tests/automation/app-single-instance/app/package.json new file mode 100644 index 0000000000..cb2c05e819 --- /dev/null +++ b/tests/automation/app-single-instance/app/package.json @@ -0,0 +1,5 @@ +{ + "name":"ASI", + "main":"index.html", + "single-instance":true +} \ No newline at end of file diff --git a/tests/automation/app-single-instance/index.html b/tests/automation/app-single-instance/index.html new file mode 100644 index 0000000000..e0a9858acc --- /dev/null +++ b/tests/automation/app-single-instance/index.html @@ -0,0 +1,11 @@ + + + + +Test app single instance + + + + + + diff --git a/tests/automation/app-single-instance/mocha_test.js b/tests/automation/app-single-instance/mocha_test.js new file mode 100644 index 0000000000..4b8bad82b0 --- /dev/null +++ b/tests/automation/app-single-instance/mocha_test.js @@ -0,0 +1,42 @@ +var assert = require('assert'); +var path = require('path'); +var global = require('../globals'); + +describe('Single Instance APP', function() { + + var count = 0; + var onConnection = function(socket) { + socket.on('data', function(data) { + count += 1; + }); + }; + + var server = undefined; + + before(function(done) { + server = createTCPServer(13013); + server.on('connection', onConnection); + + var appPath = path.join(global.tests_dir, 'app'); + var child_1 = spawnChildProcess(appPath); + var child_2 = spawnChildProcess(appPath); + var child_3 = spawnChildProcess(appPath); + setTimeout(function() { + child_1.kill(); + child_2.kill(); + child_3.kill(); + done(); + }, 1000); + }); + + after(function() { + if (server) { + server.removeListener('connection',onConnection); + server.close(); + } + }); + + it('app should be single instance', function() { + assert.equal(count,1); + }); +}); diff --git a/tests/automation/app-single-instance/package.json b/tests/automation/app-single-instance/package.json new file mode 100644 index 0000000000..9c8363e52c --- /dev/null +++ b/tests/automation/app-single-instance/package.json @@ -0,0 +1,4 @@ +{ +"name": "app_single_instance_wrapper", +"main": "index.html" +} From 6bf28ca3c55932c78c7715a7f42f397678829ba6 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Thu, 27 Nov 2014 15:34:11 +0800 Subject: [PATCH 288/492] Add start_app test case --- tests/automation/start_app/index.html | 12 ++ .../automation/start_app/internal/index.html | 16 ++ .../start_app/internal/package.json | 8 + tests/automation/start_app/mocha_test.js | 138 ++++++++++++++++++ tests/automation/start_app/package.json | 5 + tests/automation/start_app/script.js | 91 ++++++++++++ tests/automation/start_app/zip.py | 15 ++ 7 files changed, 285 insertions(+) create mode 100644 tests/automation/start_app/index.html create mode 100644 tests/automation/start_app/internal/index.html create mode 100644 tests/automation/start_app/internal/package.json create mode 100644 tests/automation/start_app/mocha_test.js create mode 100644 tests/automation/start_app/package.json create mode 100644 tests/automation/start_app/script.js create mode 100644 tests/automation/start_app/zip.py diff --git a/tests/automation/start_app/index.html b/tests/automation/start_app/index.html new file mode 100644 index 0000000000..e7d0082e15 --- /dev/null +++ b/tests/automation/start_app/index.html @@ -0,0 +1,12 @@ + + + Hello World + + +

            Start app test

            + + + + + + diff --git a/tests/automation/start_app/internal/index.html b/tests/automation/start_app/internal/index.html new file mode 100644 index 0000000000..043908786a --- /dev/null +++ b/tests/automation/start_app/internal/index.html @@ -0,0 +1,16 @@ + + + Hello World + + + +

            this is node-webkit

            + + + diff --git a/tests/automation/start_app/internal/package.json b/tests/automation/start_app/internal/package.json new file mode 100644 index 0000000000..cc5dc359a1 --- /dev/null +++ b/tests/automation/start_app/internal/package.json @@ -0,0 +1,8 @@ +{ + "name": "nw-demo", + "version": "0.1.0", + "main": "index.html", + "window": { + "show": false + } +} diff --git a/tests/automation/start_app/mocha_test.js b/tests/automation/start_app/mocha_test.js new file mode 100644 index 0000000000..f8a0132516 --- /dev/null +++ b/tests/automation/start_app/mocha_test.js @@ -0,0 +1,138 @@ +var spawn = require('child_process').spawn; +var exec = require('child_process').exec; +var path = require('path'); +var net = require('net'); +var os = require('os'); +var fs = require('fs-extra'); +var curDir = require('fs').realpathSync('.'); +var func = require(path.join(curDir, 'script.js')); +var execPath = path.join(curDir, func.getExecPath()); + +describe('Startup', function() { +describe('different method of starting app (long-to-run)', function() { + + before(function(done){ + this.timeout(10000); + func.copyExecFiles(function() { + func.copySourceFiles('internal'); + func.zipSourceFiles(function() { + func.makeExecuableFile(); + done(); + }); + }); + + }); + + after(function(done) { + setTimeout(function() { + fs.remove(path.join(curDir, 'tmp-nw'), function (er) { + if (er) { + console.log('Failed to remove the temporary folder tmp-nw: ' + er); + throw er; + } + done(); + }) + }, 1000); + }) + + it('start from nw that package.json in the same folder', function(done) { + this.timeout(0); + var result = false; + + if (os.platform() == 'darwin') { + //mac don't have this method + done(); + return; + } + + var app = spawn(execPath); + app.on('exit', function() { + result = true; + done(); + }); + + setTimeout(function() { + if (!result) { + done('timeout'); + app.kill(); + } + }, 10000); + + }) + + it('start from app.nw', function(done) { + this.timeout(0); + var result = false; + + var app = spawn(execPath, [path.join(curDir, 'tmp-nw', 'app.nw')]); + app.on('exit', function() { + result = true; + done(); + }); + setTimeout(function() { + if (!result) { + done('timeout'); + app.kill(); + } + }, 10000); + + }) + + it('start from folder contains `../`', function(done) { + this.timeout(0); + var result = false; + var app = spawn(execPath, [path.join(curDir, '..', '..', 'tmp-nw')]); + + + app.on('exit', function() { + result = true; + done(); + }); + + setTimeout(function() { + if (!result) { + done('timeout'); + app.kill(); + } + }, 10000); + }) + + it('start from an executable file app.exe', function(done) { + this.timeout(0); + var result = false; + function launch(appPath) { + var app = spawn(appPath); + app.on('exit', function() { + result = true; + done(); + }); + + setTimeout(function() { + if (!result) { + done('timeout'); + app.kill(); + } + }, 10000); + } + + if (os.platform() == 'win32') { + launch(path.join(curDir, 'tmp-nw', 'app.exe')); + } + if (os.platform() == 'linux') { + launch(path.join(curDir, 'tmp-nw', 'app')); + } + if (os.platform() == 'darwin') { + var app_path = curDir + 'tmp-nw/node-webkit.app/Contents/Resources/app.nw'; + fs.mkdir(app_path, function(err) { + if(err && err.code !== 'EEXIST') throw err + fs.copy(path.join(curDir, 'tmp-nw', 'internal', 'index.html'), path.join(app_path, 'index.html')); + fs.copy(path.join(curDir, 'tmp-nw', 'internal', 'package.json'), path.join(app_path, 'package.json'), function() { + launch(app_path); + }); + }); + } + + }) + +}) +}) diff --git a/tests/automation/start_app/package.json b/tests/automation/start_app/package.json new file mode 100644 index 0000000000..15ea52e629 --- /dev/null +++ b/tests/automation/start_app/package.json @@ -0,0 +1,5 @@ +{ + "name": "start_app_wrapper", + "version": "0.1.0", + "main": "index.html" +} diff --git a/tests/automation/start_app/script.js b/tests/automation/start_app/script.js new file mode 100644 index 0000000000..9ad4d05d7f --- /dev/null +++ b/tests/automation/start_app/script.js @@ -0,0 +1,91 @@ +var path = require('path'); +var os = require('os'); +var fsextra = require('fs-extra'); +var cp = require('child_process'); +var exec = cp.exec; +var sqawn = cp.sqawn; +var global = {}; +global.tests_dir = fsextra.realpathSync('.'); + +var required_file_win_linux = fsextra.readdirSync(path.dirname(process.execPath)); +var required_file_win = required_file_win_linux; +var required_file_linux = required_file_win_linux; + +var required_file_macox = [ + 'node-webkit.app' +]; + +var source_file = ['index.html', 'package.json']; + +var exec_root = path.dirname(process.execPath); +var required_file; +if (os.platform() == 'win32') { + required_file = required_file_win; +} +if (os.platform() == 'linux') { + required_file = required_file_linux; +} +if (os.platform() == 'darwin') { + required_file = required_file_macox; + if (~exec_root.indexOf("Helper.app")) + exec_root = path.join(exec_root, '..', '..', '..') + exec_root = path.normalize( + path.join(exec_root, '..', '..', '..')); +} + + + +exports.getExecPath = function() { + if (os.platform() == 'win32') { + return path.join('tmp-nw', 'nw.exe'); + } + if (os.platform() == 'linux') { + return path.join('tmp-nw', 'nw'); + } + if (os.platform() == 'darwin') { + return path.join('tmp-nw', 'node-webkit.app', 'Contents', 'MacOS', 'node-webkit'); + } + +} + +function copyExecFiles(done) { + fsextra.mkdir('tmp-nw', function(err) { + if(err && err.code !== 'EEXIST') throw err; + var files_done = 0; + for (var i in required_file) { + var src_file = path.join(exec_root, required_file[i]); + var dst_file = path.join('tmp-nw', required_file[i]); + fsextra.copySync(src_file, dst_file); + } + done(); + }); + +} + +exports.copySourceFiles = function(folder) { + if (folder == undefined) + folder = 'start_app'; + fsextra.createReadStream(global.tests_dir + '/' + folder + '/index.html').pipe( + fsextra.createWriteStream('tmp-nw/index.html')); + fsextra.createReadStream(global.tests_dir + '/' + folder + '/package.json').pipe( + fsextra.createWriteStream('tmp-nw/package.json')); + +} + +exports.zipSourceFiles = function(callback) { + exec('python '+path.join(global.tests_dir, 'zip.py')); + setTimeout(callback, 2000); +} + +exports.makeExecuableFile = function() { + if (os.platform() == 'win32') { + cp.exec('copy /b nw.exe+app.nw app.exe', {cwd: './tmp-nw/'}); + } + if (os.platform() == 'linux') { + cp.exec('cat nw app.nw > app && chmod +x app', {cwd: './tmp-nw/'}); + } + +} + + +exports.copyExecFiles = copyExecFiles; diff --git a/tests/automation/start_app/zip.py b/tests/automation/start_app/zip.py new file mode 100644 index 0000000000..1db9d99c1f --- /dev/null +++ b/tests/automation/start_app/zip.py @@ -0,0 +1,15 @@ +import zipfile +import os +print 'Python----by Jingfu' +curDir = os.path.dirname(os.path.abspath(__file__)) +zip = zipfile.ZipFile(os.path.join(curDir, 'tmp-nw', 'app.nw'), 'w', + compression=zipfile.ZIP_DEFLATED) + +source_file = ['index.html', 'package.json'] + +for file in source_file: + path = os.path.join(curDir, 'tmp-nw', file) + zip.write(path, file) + +zip.close(); + From caafed0b75bfe55704b9a423246a6fd33ec52c07 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Thu, 27 Nov 2014 16:17:20 +0800 Subject: [PATCH 289/492] Add buff_from_string test case --- tests/automation/buff_from_string/index.html | 19 ++++ .../buff_from_string/internal/index.html | 37 ++++++ .../buff_from_string/internal/package.json | 5 + .../buff_from_string/internal/test.py | 55 +++++++++ .../automation/buff_from_string/mocha_test.js | 107 ++++++++++++++++++ .../automation/buff_from_string/package.json | 5 + 6 files changed, 228 insertions(+) create mode 100644 tests/automation/buff_from_string/index.html create mode 100644 tests/automation/buff_from_string/internal/index.html create mode 100644 tests/automation/buff_from_string/internal/package.json create mode 100755 tests/automation/buff_from_string/internal/test.py create mode 100644 tests/automation/buff_from_string/mocha_test.js create mode 100644 tests/automation/buff_from_string/package.json diff --git a/tests/automation/buff_from_string/index.html b/tests/automation/buff_from_string/index.html new file mode 100644 index 0000000000..334a50e52e --- /dev/null +++ b/tests/automation/buff_from_string/index.html @@ -0,0 +1,19 @@ + + + + + + Buffer from string + + +

            Buffer from string

            + + + + + + + + + + diff --git a/tests/automation/buff_from_string/internal/index.html b/tests/automation/buff_from_string/internal/index.html new file mode 100644 index 0000000000..4034f877ee --- /dev/null +++ b/tests/automation/buff_from_string/internal/index.html @@ -0,0 +1,37 @@ + + + + + + Test -- Buffer from string + + +

            We are using node.js + . +

            +

            Message: + +

            +

            + +

            + + + + + diff --git a/tests/automation/buff_from_string/internal/package.json b/tests/automation/buff_from_string/internal/package.json new file mode 100644 index 0000000000..61a9047ed4 --- /dev/null +++ b/tests/automation/buff_from_string/internal/package.json @@ -0,0 +1,5 @@ +{ + "name":"buff_from_string", + "main":"index.html", + "dependencies":{} +} diff --git a/tests/automation/buff_from_string/internal/test.py b/tests/automation/buff_from_string/internal/test.py new file mode 100755 index 0000000000..5c9f9d149d --- /dev/null +++ b/tests/automation/buff_from_string/internal/test.py @@ -0,0 +1,55 @@ +#!/usr/bin/env python + +from selenium import webdriver +import os +import traceback +import time +from selenium import webdriver +from platform import platform +import socket +from sys import argv + +port = 13013 +if len(argv) >= 2: + port = int(argv[1]) + + +path = os.path +dirname = path.abspath(path.dirname(__file__)) +chromedriver_path = path.join(dirname,"chromedriver2_server") + +nw = webdriver.Chrome(chromedriver_path,service_args=[dirname]) +input_element = nw.find_element_by_id("message") +input_element.send_keys("hello world") + +send_button = nw.find_element_by_id("send-message-btn") +send_button.click() + +time.sleep(1) +results = nw.execute_script('return JSON.stringify(results);') + +connection = socket.create_connection(("localhost",port)) +connection.sendall(results) +connection.close() + +def kill_process_tree(pid): + machine_type = platform() + if "Linux" in machine_type or "Darwin" in machine_type: + import psutil + parent = psutil.Process(spid) + for child in parent.get_children(recursive=True): + child.kill() + parent.kill() + return + elif 'Windows' in machine_type: + import subprocess + dev_null = open(os.devnull,"wb") + subprocess.Popen(['taskkill', '/F', '/T', '/PID', str(pid)],stdout=dev_null,stderr=dev_null) + return + else: + # print "Unknow OS type" + return + +time.sleep(2) +spid = nw.service.process.pid +kill_process_tree(spid) \ No newline at end of file diff --git a/tests/automation/buff_from_string/mocha_test.js b/tests/automation/buff_from_string/mocha_test.js new file mode 100644 index 0000000000..28c71a2ba3 --- /dev/null +++ b/tests/automation/buff_from_string/mocha_test.js @@ -0,0 +1,107 @@ +var assert = require('assert'); +var spawn = require('child_process').spawn; +var fs = require('fs-extra'); +var path = require('path'); +var curDir = fs.realpathSync('.'); +var func = require(path.join(curDir, '..', 'start_app', 'script.js')); + +var is_chromedriver_exists = false; + +describe("buff_from_string", function() { + var results = []; + var onConnection = function(socket) { + socket.on('data', function(data) { + results = JSON.parse(data.toString()); + }); + }; + + var server = undefined; + var tmpnwPath = path.join(curDir, 'tmp-nw'); + + before(function(done) { + this.timeout(0); + + server = createTCPServer(13013); + server.on('connection', onConnection); + + if (is_chromedriver_exists) { + func.copyExecFiles(function() { + var src_files = [ + path.join(curDir, 'internal', 'index.html'), + path.join(curDir, 'internal', 'package.json'), + path.join(curDir, 'internal', 'test.py') + ]; + var dst_files = [ + path.join(curDir, 'tmp-nw', 'index.html'), + path.join(curDir, 'tmp-nw', 'package.json'), + path.join(curDir, 'tmp-nw', 'test.py') + ]; + + if (process.platform == 'win32'){ + src_files.push(path.join(curDir, 'chromedriver2_server.exe')); + dst_files.push(path.join(curDir, 'tmp-nw', 'chromedriver2_server.exe')); + } else { + src_files.push(path.join(curDir, 'chromedriver2_server')); + dst_files.push(path.join(curDir, 'tmp-nw', 'chromedriver2_server')); + } + + for (var i=0;i Date: Fri, 28 Nov 2014 13:03:41 +0800 Subject: [PATCH 290/492] Modify the method names of asserting test case result. Provide new function to assert test result: assertRunningResult() --- tests/automation/res/mocha_util.js | 2 +- tests/automation/res/util.js | 41 ++++++++++++++++-------------- 2 files changed, 23 insertions(+), 20 deletions(-) diff --git a/tests/automation/res/mocha_util.js b/tests/automation/res/mocha_util.js index 9e0828fecf..eab1459caa 100644 --- a/tests/automation/res/mocha_util.js +++ b/tests/automation/res/mocha_util.js @@ -1,3 +1,3 @@ !function(){function t(e){var n=t.resolve(e),r=t.modules[n];if(!r)throw new Error('failed to require "'+e+'"');return r.exports||(r.exports={},r.call(r.exports,r,r.exports,t.relative(n))),r.exports}function e(){for(var t=(new r).getTime();h.length&&(new r).getTime()-t<100;)h.shift()();l=h.length?i(e,0):null}t.modules={},t.resolve=function(e){var n=e,r=e+".js",i=e+"/index.js";return t.modules[r]&&r||t.modules[i]&&i||n},t.register=function(e,n){t.modules[e]=n},t.relative=function(e){return function(n){if("."!=n.charAt(0))return t(n);var r=e.split("/"),i=n.split("/");r.pop();for(var o=0;o/g,">"),e=e.replace(/"/g,""")}var r=function(t){this.ignoreWhitespace=t};r.prototype={diff:function(e,n){if(n===e)return[{value:n}];if(!n)return[{value:e,removed:!0}];if(!e)return[{value:n,added:!0}];n=this.tokenize(n),e=this.tokenize(e);var r=n.length,i=e.length,o=r+i,s=[{newPos:-1,components:[]}],a=this.extractCommon(s[0],n,e,0);if(s[0].newPos+1>=r&&a+1>=i)return s[0].components;for(var u=1;o>=u;u++)for(var c=-1*u;u>=c;c+=2){var l,h=s[c-1],f=s[c+1];a=(f?f.newPos:0)-c,h&&(s[c-1]=void 0);var p=h&&h.newPos+1=0&&i>a;if(p||d){!p||d&&h.newPos=r&&a+1>=i)return l.components;s[c]=l}else s[c]=void 0}},pushComponent:function(t,e,n,r){var i=t[t.length-1];i&&i.added===n&&i.removed===r?t[t.length-1]={value:this.join(i.value,e),added:n,removed:r}:t.push({value:e,added:n,removed:r})},extractCommon:function(t,e,n,r){for(var i=e.length,o=n.length,s=t.newPos,a=s-r;i>s+1&&o>a+1&&this.equals(e[s+1],n[a+1]);)s++,a++,this.pushComponent(t.components,e[s],void 0,void 0);return t.newPos=s,a},equals:function(t,e){var n=/\S/;return!this.ignoreWhitespace||n.test(t)||n.test(e)?t===e:!0},join:function(t,e){return t+e},tokenize:function(t){return t}};var i=new r,o=new r(!0),s=new r;o.tokenize=s.tokenize=function(t){return e(t.split(/(\s+|\b)/))};var a=new r(!0);a.tokenize=function(t){return e(t.split(/([{}:;,]|\s+)/))};var u=new r;return u.tokenize=function(t){return t.split(/^/m)},{Diff:r,diffChars:function(t,e){return i.diff(t,e)},diffWords:function(t,e){return o.diff(t,e)},diffWordsWithSpace:function(t,e){return s.diff(t,e)},diffLines:function(t,e){return u.diff(t,e)},diffCss:function(t,e){return a.diff(t,e)},createPatch:function(t,e,n,r,i){function o(t){return t.map(function(t){return" "+t})}function s(t,e,n){var r=c[c.length-2],i=e===c.length-2,o=e===c.length-3&&(n.added!==r.added||n.removed!==r.removed);/\n$/.test(n.value)||!i&&!o||t.push("\\ No newline at end of file")}var a=[];a.push("Index: "+t),a.push("==================================================================="),a.push("--- "+t+("undefined"==typeof r?"":" "+r)),a.push("+++ "+t+("undefined"==typeof i?"":" "+i));var c=u.diff(e,n);c[c.length-1].value||c.pop(),c.push({value:"",lines:[]});for(var l=0,h=0,f=[],p=1,d=1,g=0;g=0;s--){for(var c=r[s],l=0;l"):i.removed&&e.push(""),e.push(n(i.value)),i.added?e.push(""):i.removed&&e.push("")}return e.join("")},convertChangesToDMP:function(t){for(var e,n=[],r=0;ro;o++)if(r[o]===e||r[o].listener&&r[o].listener===e){i=o;break}if(0>i)return this;r.splice(i,1),r.length||delete this.$events[t]}else(r===e||r.listener&&r.listener===e)&&delete this.$events[t]}return this},r.prototype.removeAllListeners=function(t){return void 0===t?(this.$events={},this):(this.$events&&this.$events[t]&&(this.$events[t]=null),this)},r.prototype.listeners=function(t){return this.$events||(this.$events={}),this.$events[t]||(this.$events[t]=[]),n(this.$events[t])||(this.$events[t]=[this.$events[t]]),this.$events[t]},r.prototype.emit=function(t){if(!this.$events)return!1;var e=this.$events[t];if(!e)return!1;var r=[].slice.call(arguments,1);if("function"==typeof e)e.apply(this,r);else{if(!n(e))return!1;for(var i=e.slice(),o=0,s=i.length;s>o;o++)i[o].apply(this,r)}return!0}}),t.register("browser/fs.js",function(){}),t.register("browser/glob.js",function(){}),t.register("browser/path.js",function(){}),t.register("browser/progress.js",function(t){function e(){this.percent=0,this.size(0),this.fontSize(11),this.font("helvetica, arial, sans-serif")}t.exports=e,e.prototype.size=function(t){return this._size=t,this},e.prototype.text=function(t){return this._text=t,this},e.prototype.fontSize=function(t){return this._fontSize=t,this},e.prototype.font=function(t){return this._font=t,this},e.prototype.update=function(t){return this.percent=t,this},e.prototype.draw=function(t){try{var e=Math.min(this.percent,100),n=this._size,r=n/2,i=r,o=r,s=r-1,a=this._fontSize;t.font=a+"px "+this._font;var u=2*Math.PI*(e/100);t.clearRect(0,0,n,n),t.strokeStyle="#9f9f9f",t.beginPath(),t.arc(i,o,s,0,u,!1),t.stroke(),t.strokeStyle="#eee",t.beginPath(),t.arc(i,o,s-1,0,u,!0),t.stroke();var c=this._text||(0|e)+"%",l=t.measureText(c).width;t.fillText(c,i-l/2+1,o+a/2-1)}catch(h){}return this}}),t.register("browser/tty.js",function(t,e){e.isatty=function(){return!0},e.getWindowSize=function(){return"innerHeight"in n?[n.innerHeight,n.innerWidth]:[640,480]}}),t.register("context.js",function(t){function e(){}t.exports=e,e.prototype.runnable=function(t){return 0==arguments.length?this._runnable:(this.test=this._runnable=t,this)},e.prototype.timeout=function(t){return 0===arguments.length?this.runnable().timeout():(this.runnable().timeout(t),this)},e.prototype.enableTimeouts=function(t){return this.runnable().enableTimeouts(t),this},e.prototype.slow=function(t){return this.runnable().slow(t),this},e.prototype.inspect=function(){return JSON.stringify(this,function(t,e){return"_runnable"!=t&&"test"!=t?e:void 0},2)}}),t.register("hook.js",function(t,e,n){function r(t,e){o.call(this,t,e),this.type="hook"}function i(){}var o=n("./runnable");t.exports=r,i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r,r.prototype.error=function(t){if(0==arguments.length){var t=this._error;return this._error=null,t}this._error=t}}),t.register("interfaces/bdd.js",function(t,e,n){var r=n("../suite"),i=n("../test"),o=(n("../utils"),n("browser/escape-string-regexp"));t.exports=function(t){var e=[t];t.on("pre-require",function(t,n,s){t.before=function(t,n){e[0].beforeAll(t,n)},t.after=function(t,n){e[0].afterAll(t,n)},t.beforeEach=function(t,n){e[0].beforeEach(t,n)},t.afterEach=function(t,n){e[0].afterEach(t,n)},t.describe=t.context=function(t,i){var o=r.create(e[0],t);return o.file=n,e.unshift(o),i.call(o),e.shift(),o},t.xdescribe=t.xcontext=t.describe.skip=function(t,n){var i=r.create(e[0],t);i.pending=!0,e.unshift(i),n.call(i),e.shift()},t.describe.only=function(e,n){var r=t.describe(e,n);return s.grep(r.fullTitle()),r},t.it=t.specify=function(t,r){var o=e[0];o.pending&&(r=null);var s=new i(t,r);return s.file=n,o.addTest(s),s},t.it.only=function(e,n){var r=t.it(e,n),i="^"+o(r.fullTitle())+"$";return s.grep(new RegExp(i)),r},t.xit=t.xspecify=t.it.skip=function(e){t.it(e)}})}}),t.register("interfaces/exports.js",function(t,e,n){var r=n("../suite"),i=n("../test");t.exports=function(t){function e(t,o){var s;for(var a in t)if("function"==typeof t[a]){var u=t[a];switch(a){case"before":n[0].beforeAll(u);break;case"after":n[0].afterAll(u);break;case"beforeEach":n[0].beforeEach(u);break;case"afterEach":n[0].afterEach(u);break;default:var c=new i(a,u);c.file=o,n[0].addTest(c)}}else s=r.create(n[0],a),n.unshift(s),e(t[a]),n.shift()}var n=[t];t.on("require",e)}}),t.register("interfaces/index.js",function(t,e,n){e.bdd=n("./bdd"),e.tdd=n("./tdd"),e.qunit=n("./qunit"),e.exports=n("./exports")}),t.register("interfaces/qunit.js",function(t,e,n){{var r=n("../suite"),i=n("../test"),o=n("browser/escape-string-regexp");n("../utils")}t.exports=function(t){var e=[t];t.on("pre-require",function(t,n,s){t.before=function(t,n){e[0].beforeAll(t,n)},t.after=function(t,n){e[0].afterAll(t,n)},t.beforeEach=function(t,n){e[0].beforeEach(t,n)},t.afterEach=function(t,n){e[0].afterEach(t,n)},t.suite=function(t){e.length>1&&e.shift();var i=r.create(e[0],t);return i.file=n,e.unshift(i),i},t.suite.only=function(e,n){var r=t.suite(e,n);s.grep(r.fullTitle())},t.test=function(t,r){var o=new i(t,r);return o.file=n,e[0].addTest(o),o},t.test.only=function(e,n){var r=t.test(e,n),i="^"+o(r.fullTitle())+"$";s.grep(new RegExp(i))},t.test.skip=function(e){t.test(e)}})}}),t.register("interfaces/tdd.js",function(t,e,n){{var r=n("../suite"),i=n("../test"),o=n("browser/escape-string-regexp");n("../utils")}t.exports=function(t){var e=[t];t.on("pre-require",function(t,n,s){t.setup=function(t,n){e[0].beforeEach(t,n)},t.teardown=function(t,n){e[0].afterEach(t,n)},t.suiteSetup=function(t,n){e[0].beforeAll(t,n)},t.suiteTeardown=function(t,n){e[0].afterAll(t,n)},t.suite=function(t,i){var o=r.create(e[0],t);return o.file=n,e.unshift(o),i.call(o),e.shift(),o},t.suite.skip=function(t,n){var i=r.create(e[0],t);i.pending=!0,e.unshift(i),n.call(i),e.shift()},t.suite.only=function(e,n){var r=t.suite(e,n);s.grep(r.fullTitle())},t.test=function(t,r){var o=e[0];o.pending&&(r=null);var s=new i(t,r);return s.file=n,o.addTest(s),s},t.test.only=function(e,n){var r=t.test(e,n),i="^"+o(r.fullTitle())+"$";s.grep(new RegExp(i))},t.test.skip=function(e){t.test(e)}})}}),t.register("mocha.js",function(t,e,r){function i(t){return __dirname+"/../images/"+t+".png"}function s(t){t=t||{},this.files=[],this.options=t,this.grep(t.grep),this.suite=new e.Suite("",new e.Context),this.ui(t.ui),this.bail(t.bail),this.reporter(t.reporter),null!=t.timeout&&this.timeout(t.timeout),this.useColors(t.useColors),null!==t.enableTimeouts&&this.enableTimeouts(t.enableTimeouts),t.slow&&this.slow(t.slow),this.suite.on("pre-require",function(t){e.afterEach=t.afterEach||t.teardown,e.after=t.after||t.suiteTeardown,e.beforeEach=t.beforeEach||t.setup,e.before=t.before||t.suiteSetup,e.describe=t.describe||t.suite,e.it=t.it||t.test,e.setup=t.setup||t.beforeEach,e.suiteSetup=t.suiteSetup||t.before,e.suiteTeardown=t.suiteTeardown||t.after,e.suite=t.suite||t.describe,e.teardown=t.teardown||t.afterEach,e.test=t.test||t.it})}var a=r("browser/path"),u=r("browser/escape-string-regexp"),c=r("./utils");if(e=t.exports=s,"undefined"!=typeof o&&"function"==typeof o.cwd){var l=a.join,h=o.cwd();t.paths.push(h,l(h,"node_modules"))}e.utils=c,e.interfaces=r("./interfaces"),e.reporters=r("./reporters"),e.Runnable=r("./runnable"),e.Context=r("./context"),e.Runner=r("./runner"),e.Suite=r("./suite"),e.Hook=r("./hook"),e.Test=r("./test"),s.prototype.bail=function(t){return 0==arguments.length&&(t=!0),this.suite.bail(t),this},s.prototype.addFile=function(t){return this.files.push(t),this},s.prototype.reporter=function(t){if("function"==typeof t)this._reporter=t;else{t=t||"spec";var e;try{e=r("./reporters/"+t)}catch(n){}if(!e)try{e=r(t)}catch(n){}if(e||"teamcity"!==t||console.warn("The Teamcity reporter was moved to a package named mocha-teamcity-reporter (https://npmjs.org/package/mocha-teamcity-reporter)."),!e)throw new Error('invalid reporter "'+t+'"');this._reporter=e}return this},s.prototype.ui=function(t){if(t=t||"bdd",this._ui=e.interfaces[t],!this._ui)try{this._ui=r(t)}catch(n){}if(!this._ui)throw new Error('invalid interface "'+t+'"');return this._ui=this._ui(this.suite),this},s.prototype.loadFiles=function(t){var e=this,i=this.suite,o=this.files.length;this.files.forEach(function(s){s=a.resolve(s),i.emit("pre-require",n,s,e),i.emit("require",r(s),s,e),i.emit("post-require",n,s,e),--o||t&&t()})},s.prototype._growl=function(t,e){var n=r("growl");t.on("end",function(){var r=e.stats;if(r.failures){var o=r.failures+" of "+t.total+" tests failed";n(o,{name:"mocha",title:"Failed",image:i("error")})}else n(r.passes+" tests passed in "+r.duration+"ms",{name:"mocha",title:"Passed",image:i("ok")})})},s.prototype.grep=function(t){return this.options.grep="string"==typeof t?new RegExp(u(t)):t,this},s.prototype.invert=function(){return this.options.invert=!0,this},s.prototype.ignoreLeaks=function(t){return this.options.ignoreLeaks=!!t,this},s.prototype.checkLeaks=function(){return this.options.ignoreLeaks=!1,this},s.prototype.growl=function(){return this.options.growl=!0,this},s.prototype.globals=function(t){return this.options.globals=(this.options.globals||[]).concat(t),this},s.prototype.useColors=function(t){return this.options.useColors=arguments.length&&void 0!=t?t:!0,this},s.prototype.useInlineDiffs=function(t){return this.options.useInlineDiffs=arguments.length&&void 0!=t?t:!1,this},s.prototype.timeout=function(t){return this.suite.timeout(t),this},s.prototype.slow=function(t){return this.suite.slow(t),this},s.prototype.enableTimeouts=function(t){return this.suite.enableTimeouts(arguments.length&&void 0!==t?t:!0),this},s.prototype.asyncOnly=function(){return this.options.asyncOnly=!0,this},s.prototype.noHighlighting=function(){return this.options.noHighlighting=!0,this},s.prototype.run=function(t){this.files.length&&this.loadFiles();var n=this.suite,r=this.options;r.files=this.files;var i=new e.Runner(n),o=new this._reporter(i,r);return i.ignoreLeaks=!1!==r.ignoreLeaks,i.asyncOnly=r.asyncOnly,r.grep&&i.grep(r.grep,r.invert),r.globals&&i.globals(r.globals),r.growl&&this._growl(i,o),e.reporters.Base.useColors=r.useColors,e.reporters.Base.inlineDiffs=r.useInlineDiffs,i.run(t)}}),t.register("ms.js",function(t){function e(t){var e=/^((?:\d+)?\.?\d+) *(ms|seconds?|s|minutes?|m|hours?|h|days?|d|years?|y)?$/i.exec(t);if(e){var n=parseFloat(e[1]),r=(e[2]||"ms").toLowerCase();switch(r){case"years":case"year":case"y":return n*c;case"days":case"day":case"d":return n*u;case"hours":case"hour":case"h":return n*a;case"minutes":case"minute":case"m":return n*s;case"seconds":case"second":case"s":return n*o;case"ms":return n}}}function n(t){return t>=u?Math.round(t/u)+"d":t>=a?Math.round(t/a)+"h":t>=s?Math.round(t/s)+"m":t>=o?Math.round(t/o)+"s":t+"ms"}function r(t){return i(t,u,"day")||i(t,a,"hour")||i(t,s,"minute")||i(t,o,"second")||t+" ms"}function i(t,e,n){return e>t?void 0:1.5*e>t?Math.floor(t/e)+" "+n:Math.ceil(t/e)+" "+n+"s"}var o=1e3,s=60*o,a=60*s,u=24*a,c=365.25*u;t.exports=function(t,i){return i=i||{},"string"==typeof t?e(t):i["long"]?r(t):n(t)}}),t.register("reporters/base.js",function(t,e,r){function i(t){var e=this.stats={suites:0,tests:0,passes:0,pending:0,failures:0},n=this.failures=[];t&&(this.runner=t,t.stats=e,t.on("start",function(){e.start=new m}),t.on("suite",function(t){e.suites=e.suites||0,t.root||e.suites++}),t.on("test end",function(){e.tests=e.tests||0,e.tests++}),t.on("pass",function(t){e.passes=e.passes||0;var n=t.slow()/2;t.speed=t.duration>t.slow()?"slow":t.duration>n?"medium":"fast",e.passes++}),t.on("fail",function(t,r){e.failures=e.failures||0,e.failures++,t.err=r,n.push(t)}),t.on("end",function(){e.end=new m,e.duration=new m-e.start}),t.on("pending",function(){e.pending++}))}function s(t,e){return t=String(t),Array(e-t.length+1).join(" ")+t}function a(t,e){var n=c(t,"WordsWithSpace",e),r=n.split("\n");if(r.length>4){var i=String(r.length).length;n=r.map(function(t,e){return s(++e,i)+" | "+t}).join("\n")}return n="\n"+y("diff removed","actual")+" "+y("diff added","expected")+"\n\n"+n+"\n",n=n.replace(/^/gm," ")}function u(t,e){function n(t){return e&&(t=l(t)),"+"===t[0]?i+h("diff added",t):"-"===t[0]?i+h("diff removed",t):t.match(/\@\@/)?null:t.match(/\\ No newline/)?null:i+t}function r(t){return null!=t}var i=" ";msg=d.createPatch("string",t.actual,t.expected);var o=msg.split("\n").splice(4);return"\n "+h("diff added","+ expected")+" "+h("diff removed","- actual")+"\n\n"+o.map(n).filter(r).join("\n")}function c(t,e,n){var r=n?l(t.actual):t.actual,i=n?l(t.expected):t.expected;return d["diff"+e](r,i).map(function(t){return t.added?h("diff added",t.value):t.removed?h("diff removed",t.value):t.value}).join("")}function l(t){return t.replace(/\t/g,"").replace(/\r/g,"").replace(/\n/g,"\n")}function h(t,e){return e.split("\n").map(function(e){return y(t,e)}).join("\n")}function f(t,e){return t=Object.prototype.toString.call(t),e=Object.prototype.toString.call(e),t==e}var p=r("browser/tty"),d=r("browser/diff"),g=r("../ms"),v=r("../utils"),m=n.Date,b=(n.setTimeout,n.setInterval,n.clearTimeout,n.clearInterval,p.isatty(1)&&p.isatty(2));e=t.exports=i,e.useColors=b||void 0!==o.env.MOCHA_COLORS,e.inlineDiffs=!1,e.colors={pass:90,fail:31,"bright pass":92,"bright fail":91,"bright yellow":93,pending:36,suite:0,"error title":0,"error message":31,"error stack":90,checkmark:32,fast:90,medium:33,slow:31,green:32,light:90,"diff gutter":90,"diff added":42,"diff removed":41},e.symbols={ok:"✓",err:"✖",dot:"․"},"win32"==o.platform&&(e.symbols.ok="√",e.symbols.err="×",e.symbols.dot=".");var y=e.color=function(t,n){return e.useColors?"["+e.colors[t]+"m"+n+"":n};e.window={width:b?o.stdout.getWindowSize?o.stdout.getWindowSize(1)[0]:p.getWindowSize()[1]:75},e.cursor={hide:function(){b&&o.stdout.write("[?25l")},show:function(){b&&o.stdout.write("[?25h")},deleteLine:function(){b&&o.stdout.write("")},beginningOfLine:function(){b&&o.stdout.write("")},CR:function(){b?(e.cursor.deleteLine(),e.cursor.beginningOfLine()):o.stdout.write("\r")}},e.list=function(t){console.error(),t.forEach(function(t,n){var r=y("error title"," %s) %s:\n")+y("error message"," %s")+y("error stack","\n%s\n"),i=t.err,o=i.message||"",s=i.stack||o,c=s.indexOf(o)+o.length,l=s.slice(0,c),h=i.actual,p=i.expected,d=!0;if(i.uncaught&&(l="Uncaught "+l),i.showDiff&&f(h,p)&&(d=!1,i.actual=h=v.stringify(h),i.expected=p=v.stringify(p)),i.showDiff&&"string"==typeof h&&"string"==typeof p){r=y("error title"," %s) %s:\n%s")+y("error stack","\n%s\n");var g=o.match(/^([^:]+): expected/);l="\n "+y("error message",g?g[1]:l),l+=e.inlineDiffs?a(i,d):u(i,d)}s=s.slice(c?c+1:c).replace(/^/gm," "),console.error(r,n+1,t.fullTitle(),l,s)})},i.prototype.epilogue=function(){var t,e=this.stats;console.log(),t=y("bright pass"," ")+y("green"," %d passing")+y("light"," (%s)"),console.log(t,e.passes||0,g(e.duration)),e.pending&&(t=y("pending"," ")+y("pending"," %d pending"),console.log(t,e.pending)),e.failures&&(t=y("fail"," %d failing"),console.error(t,e.failures),i.list(this.failures),console.error()),console.log()}}),t.register("reporters/doc.js",function(t,e,n){function r(t){function e(){return Array(n).join(" ")}i.call(this,t);var n=(this.stats,t.total,2);t.on("suite",function(t){t.root||(++n,console.log('%s
            ',e()),++n,console.log("%s

            %s

            ",e(),o.escape(t.title)),console.log("%s
            ",e()))}),t.on("suite end",function(t){t.root||(console.log("%s
            ",e()),--n,console.log("%s
            ",e()),--n)}),t.on("pass",function(t){console.log("%s
            %s
            ",e(),o.escape(t.title));var n=o.escape(o.clean(t.fn.toString()));console.log("%s
            %s
            ",e(),n)}),t.on("fail",function(t,n){console.log('%s
            %s
            ',e(),o.escape(t.title));var r=o.escape(o.clean(t.fn.toString()));console.log('%s
            %s
            ',e(),r),console.log('%s
            %s
            ',e(),o.escape(n))})}var i=n("./base"),o=n("../utils");e=t.exports=r}),t.register("reporters/dot.js",function(t,e,n){function r(t){s.call(this,t);var e=this,n=(this.stats,.75*s.window.width|0),r=-1;t.on("start",function(){o.stdout.write("\n ")}),t.on("pending",function(){++r%n==0&&o.stdout.write("\n "),o.stdout.write(a("pending",s.symbols.dot))}),t.on("pass",function(t){++r%n==0&&o.stdout.write("\n "),o.stdout.write("slow"==t.speed?a("bright yellow",s.symbols.dot):a(t.speed,s.symbols.dot))}),t.on("fail",function(){++r%n==0&&o.stdout.write("\n "),o.stdout.write(a("fail",s.symbols.dot))}),t.on("end",function(){console.log(),e.epilogue()})}function i(){}var s=n("./base"),a=s.color;e=t.exports=r,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/html-cov.js",function(t,e,n){function r(t){var e=n("jade"),r=__dirname+"/templates/coverage.jade",u=a.readFileSync(r,"utf8"),c=e.compile(u,{filename:r}),l=this;s.call(this,t,!1),t.on("end",function(){o.stdout.write(c({cov:l.cov,coverageClass:i}))})}function i(t){return t>=75?"high":t>=50?"medium":t>=25?"low":"terrible"}var s=n("./json-cov"),a=n("browser/fs");e=t.exports=r}),t.register("reporters/html.js",function(t,e,r){function i(t){h.call(this,t);var e,n,r=this,i=this.stats,m=(t.total,s(v)),b=m.getElementsByTagName("li"),y=b[1].getElementsByTagName("em")[0],w=b[1].getElementsByTagName("a")[0],x=b[2].getElementsByTagName("em")[0],j=b[2].getElementsByTagName("a")[0],E=b[3].getElementsByTagName("em")[0],T=m.getElementsByTagName("canvas")[0],k=s('
              '),q=[k],_=document.getElementById("mocha");if(T.getContext){var O=window.devicePixelRatio||1;T.style.width=T.width,T.style.height=T.height,T.width*=O,T.height*=O,n=T.getContext("2d"),n.scale(O,O),e=new p}return _?(l(w,"click",function(){u();var t=/pass/.test(k.className)?"":" pass";k.className=k.className.replace(/fail|pass/g,"")+t,k.className.trim()&&a("test pass")}),l(j,"click",function(){u();var t=/fail/.test(k.className)?"":" fail";k.className=k.className.replace(/fail|pass/g,"")+t,k.className.trim()&&a("test fail")}),_.appendChild(m),_.appendChild(k),e&&e.size(40),t.on("suite",function(t){if(!t.root){var e=r.suiteURL(t),n=s('
            • %s

            • ',e,d(t.title));q[0].appendChild(n),q.unshift(document.createElement("ul")),n.appendChild(q[0])}}),t.on("suite end",function(t){t.root||q.shift()}),t.on("fail",function(e){"hook"==e.type&&t.emit("test end",e)}),void t.on("test end",function(t){var o=i.tests/this.total*100|0;e&&e.update(o).draw(n);var a=new g-i.start;if(c(y,i.passes),c(x,i.failures),c(E,(a/1e3).toFixed(2)),"passed"==t.state)var u=r.testURL(t),h=s('
            • %e%ems

            • ',t.speed,t.title,t.duration,u);else if(t.pending)var h=s('
            • %e

            • ',t.title);else{var h=s('
            • %e

            • ',t.title,encodeURIComponent(t.fullTitle())),p=t.err.stack||t.err.toString();~p.indexOf(t.err.message)||(p=t.err.message+"\n"+p),"[object Error]"==p&&(p=t.err.message),!t.err.stack&&t.err.sourceURL&&void 0!==t.err.line&&(p+="\n("+t.err.sourceURL+":"+t.err.line+")"),h.appendChild(s('
              %e
              ',p))}if(!t.pending){var d=h.getElementsByTagName("h2")[0];l(d,"click",function(){v.style.display="none"==v.style.display?"block":"none"});var v=s("
              %e
              ",f.clean(t.fn.toString()));h.appendChild(v),v.style.display="none"}q[0]&&q[0].appendChild(h)})):o("#mocha div missing, add it to your document")}function o(t){document.body.appendChild(s('
              %s
              ',t))}function s(t){var e=arguments,n=document.createElement("div"),r=1;return n.innerHTML=t.replace(/%([se])/g,function(t,n){switch(n){case"s":return String(e[r++]);case"e":return d(e[r++])}}),n.firstChild}function a(t){for(var e=document.getElementsByClassName("suite"),n=0;n0&&(e.coverage=e.hits/e.sloc*100),e}function a(t,e){var n={filename:t,coverage:0,hits:0,misses:0,sloc:0,source:{}};return e.source.forEach(function(t,r){r++,0===e[r]?(n.misses++,n.sloc++):void 0!==e[r]&&(n.hits++,n.sloc++),n.source[r]={source:t,coverage:void 0===e[r]?"":e[r]}}),n.coverage=n.hits/n.sloc*100,n}function u(t){return{title:t.title,fullTitle:t.fullTitle(),duration:t.duration}}var c=r("./base");e=t.exports=i}),t.register("reporters/json-stream.js",function(t,e,n){function r(t){s.call(this,t);var e=this,n=(this.stats,t.total);t.on("start",function(){console.log(JSON.stringify(["start",{total:n}]))}),t.on("pass",function(t){console.log(JSON.stringify(["pass",i(t)]))}),t.on("fail",function(t,e){t=i(t),t.err=e.message,console.log(JSON.stringify(["fail",t]))}),t.on("end",function(){o.stdout.write(JSON.stringify(["end",e.stats]))})}function i(t){return{title:t.title,fullTitle:t.fullTitle(),duration:t.duration}}{var s=n("./base");s.color}e=t.exports=r}),t.register("reporters/json.js",function(t,e,n){function r(t){var e=this;a.call(this,t);var n=[],r=[],s=[],u=[];t.on("test end",function(t){n.push(t)}),t.on("pass",function(t){u.push(t)}),t.on("fail",function(t){s.push(t)}),t.on("pending",function(t){r.push(t)}),t.on("end",function(){var a={stats:e.stats,tests:n.map(i),pending:r.map(i),failures:s.map(i),passes:u.map(i)};t.testResults=a,o.stdout.write(JSON.stringify(a,null,2))})}function i(t){return{title:t.title,fullTitle:t.fullTitle(),duration:t.duration,err:s(t.err||{})}}function s(t){var e={};return Object.getOwnPropertyNames(t).forEach(function(n){e[n]=t[n]},t),e}{var a=n("./base");a.cursor,a.color}e=t.exports=r}),t.register("reporters/landing.js",function(t,e,n){function r(t){function e(){var t=Array(r).join("-");return" "+u("runway",t)}s.call(this,t);var n=this,r=(this.stats,.75*s.window.width|0),i=t.total,c=o.stdout,l=u("plane","✈"),h=-1,f=0;t.on("start",function(){c.write("\n\n\n "),a.hide()}),t.on("test end",function(t){var n=-1==h?r*++f/i|0:h;"failed"==t.state&&(l=u("plane crash","✈"),h=n),c.write("["+(r+1)+"D"),c.write(e()),c.write("\n "),c.write(u("runway",Array(n).join("⋅"))),c.write(l),c.write(u("runway",Array(r-n).join("⋅")+"\n")),c.write(e()),c.write("")}),t.on("end",function(){a.show(),console.log(),n.epilogue()})}function i(){}var s=n("./base"),a=s.cursor,u=s.color;e=t.exports=r,s.colors.plane=0,s.colors["plane crash"]=31,s.colors.runway=90,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/list.js",function(t,e,n){function r(t){s.call(this,t);var e=this,n=(this.stats,0);t.on("start",function(){console.log()}),t.on("test",function(t){o.stdout.write(u("pass"," "+t.fullTitle()+": "))}),t.on("pending",function(t){var e=u("checkmark"," -")+u("pending"," %s");console.log(e,t.fullTitle())}),t.on("pass",function(t){var e=u("checkmark"," "+s.symbols.dot)+u("pass"," %s: ")+u(t.speed,"%dms");a.CR(),console.log(e,t.fullTitle(),t.duration)}),t.on("fail",function(t){a.CR(),console.log(u("fail"," %d) %s"),++n,t.fullTitle())}),t.on("end",e.epilogue.bind(e))}function i(){}var s=n("./base"),a=s.cursor,u=s.color;e=t.exports=r,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/markdown.js",function(t,e,n){function r(t){function e(t){return Array(u).join("#")+" "+t}function n(t,e){var r=e;return e=e[t.title]=e[t.title]||{suite:t},t.suites.forEach(function(t){n(t,e)}),r}function r(t,e){++e;var n,i="";for(var o in t)"suite"!=o&&(o&&(n=" - ["+o+"](#"+s.slug(t[o].suite.fullTitle())+")\n"),o&&(i+=Array(e).join(" ")+n),i+=r(t[o],e));return--e,i}function a(t){var e=n(t,{});return r(e,0)}i.call(this,t);var u=(this.stats,0),c="";a(t.suite),t.on("suite",function(t){++u;var n=s.slug(t.fullTitle());c+='\n',c+=e(t.title)+"\n"}),t.on("suite end",function(){--u}),t.on("pass",function(t){var e=s.clean(t.fn.toString());c+=t.title+".\n",c+="\n```js\n",c+=e+"\n",c+="```\n\n"}),t.on("end",function(){o.stdout.write("# TOC\n"),o.stdout.write(a(t.suite)),o.stdout.write(c) })}var i=n("./base"),s=n("../utils");e=t.exports=r}),t.register("reporters/min.js",function(t,e,n){function r(t){s.call(this,t),t.on("start",function(){o.stdout.write(""),o.stdout.write("")}),t.on("end",this.epilogue.bind(this))}function i(){}var s=n("./base");e=t.exports=r,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/nyan.js",function(t,e,n){function r(t){a.call(this,t);{var e=this,n=(this.stats,.75*a.window.width|0),r=(this.rainbowColors=e.generateColors(),this.colorIndex=0,this.numberOfLines=4,this.trajectories=[[],[],[],[]],this.nyanCatWidth=11);this.trajectoryWidthMax=n-r,this.scoreboardWidth=5,this.tick=0}t.on("start",function(){a.cursor.hide(),e.draw()}),t.on("pending",function(){e.draw()}),t.on("pass",function(){e.draw()}),t.on("fail",function(){e.draw()}),t.on("end",function(){a.cursor.show();for(var t=0;t=this.trajectoryWidthMax&&r.shift(),r.push(e)}},r.prototype.drawRainbow=function(){var t=this;this.trajectories.forEach(function(e){i("["+t.scoreboardWidth+"C"),i(e.join("")),i("\n")}),this.cursorUp(this.numberOfLines)},r.prototype.drawNyanCat=function(){var t=this,e=this.scoreboardWidth+this.trajectories[0].length,n="["+e+"C",r="";i(n),i("_,------,"),i("\n"),i(n),r=t.tick?" ":" ",i("_|"+r+"/\\_/\\ "),i("\n"),i(n),r=t.tick?"_":"__";var o=t.tick?"~":"^";i(o+"|"+r+this.face()+" "),i("\n"),i(n),r=t.tick?" ":" ",i(r+'"" "" '),i("\n"),this.cursorUp(this.numberOfLines)},r.prototype.face=function(){var t=this.stats;return t.failures?"( x .x)":t.pending?"( o .o)":t.passes?"( ^ .^)":"( - .-)"},r.prototype.cursorUp=function(t){i("["+t+"A")},r.prototype.cursorDown=function(t){i("["+t+"B")},r.prototype.generateColors=function(){for(var t=[],e=0;42>e;e++){var n=Math.floor(Math.PI/3),r=e*(1/6),i=Math.floor(3*Math.sin(r)+3),o=Math.floor(3*Math.sin(r+2*n)+3),s=Math.floor(3*Math.sin(r+4*n)+3);t.push(36*i+6*o+s+16)}return t},r.prototype.rainbowify=function(t){var e=this.rainbowColors[this.colorIndex%this.rainbowColors.length];return this.colorIndex+=1,"[38;5;"+e+"m"+t+""},s.prototype=a.prototype,r.prototype=new s,r.prototype.constructor=r}),t.register("reporters/progress.js",function(t,e,n){function r(t,e){s.call(this,t);var n=this,e=e||{},r=(this.stats,.5*s.window.width|0),i=t.total,c=0,l=(Math.max,-1);e.open=e.open||"[",e.complete=e.complete||"▬",e.incomplete=e.incomplete||s.symbols.dot,e.close=e.close||"]",e.verbose=!1,t.on("start",function(){console.log(),a.hide()}),t.on("test end",function(){c++;var t=c/i,n=r*t|0,s=r-n;(l!==n||e.verbose)&&(l=n,a.CR(),o.stdout.write(""),o.stdout.write(u("progress"," "+e.open)),o.stdout.write(Array(n).join(e.complete)),o.stdout.write(Array(s).join(e.incomplete)),o.stdout.write(u("progress",e.close)),e.verbose&&o.stdout.write(u("progress"," "+c+" of "+i)))}),t.on("end",function(){a.show(),console.log(),n.epilogue()})}function i(){}var s=n("./base"),a=s.cursor,u=s.color;e=t.exports=r,s.colors.progress=90,i.prototype=s.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/spec.js",function(t,e,n){function r(t){function e(){return Array(r).join(" ")}o.call(this,t);var n=this,r=(this.stats,0),i=0;t.on("start",function(){console.log()}),t.on("suite",function(t){++r,console.log(a("suite","%s%s"),e(),t.title)}),t.on("suite end",function(){--r,1==r&&console.log()}),t.on("pending",function(t){var n=e()+a("pending"," - %s");console.log(n,t.title)}),t.on("pass",function(t){if("fast"==t.speed){var n=e()+a("checkmark"," "+o.symbols.ok)+a("pass"," %s ");s.CR(),console.log(n,t.title)}else{var n=e()+a("checkmark"," "+o.symbols.ok)+a("pass"," %s ")+a(t.speed,"(%dms)");s.CR(),console.log(n,t.title,t.duration)}}),t.on("fail",function(t){s.CR(),console.log(e()+a("fail"," %d) %s"),++i,t.title)}),t.on("end",n.epilogue.bind(n))}function i(){}var o=n("./base"),s=o.cursor,a=o.color;e=t.exports=r,i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("reporters/tap.js",function(t,e,n){function r(t){o.call(this,t);var e=(this.stats,1),n=0,r=0;t.on("start",function(){var e=t.grepTotal(t.suite);console.log("%d..%d",1,e)}),t.on("test end",function(){++e}),t.on("pending",function(t){console.log("ok %d %s # SKIP -",e,i(t))}),t.on("pass",function(t){n++,console.log("ok %d %s",e,i(t))}),t.on("fail",function(t,n){r++,console.log("not ok %d %s",e,i(t)),n.stack&&console.log(n.stack.replace(/^/gm," "))}),t.on("end",function(){console.log("# tests "+(n+r)),console.log("# pass "+n),console.log("# fail "+r)})}function i(t){return t.fullTitle().replace(/#/g,"")}{var o=n("./base");o.cursor,o.color}e=t.exports=r}),t.register("reporters/xunit.js",function(t,e,r){function i(t){c.call(this,t);var e=this.stats,n=[];t.on("pending",function(t){n.push(t)}),t.on("pass",function(t){n.push(t)}),t.on("fail",function(t){n.push(t)}),t.on("end",function(){console.log(a("testsuite",{name:"Mocha Tests",tests:e.tests,failures:e.failures,errors:e.failures,skipped:e.tests-e.failures-e.passes,timestamp:(new f).toUTCString(),time:e.duration/1e3||0},!1)),n.forEach(s),console.log("")})}function o(){}function s(t){var e={classname:t.parent.fullTitle(),name:t.title,time:t.duration/1e3||0};if("failed"==t.state){var n=t.err;console.log(a("testcase",e,!1,a("failure",{},!1,u(h(n.message)+"\n"+n.stack))))}else console.log(t.pending?a("testcase",e,!1,a("skipped",{},!0)):a("testcase",e,!0))}function a(t,e,n,r){var i,o=n?"/>":">",s=[];for(var a in e)s.push(a+'="'+h(e[a])+'"');return i="<"+t+(s.length?" "+s.join(" "):"")+o,r&&(i+=r+""}{var c=r("./base"),l=r("../utils"),h=l.escape,f=n.Date;n.setTimeout,n.setInterval,n.clearTimeout,n.clearInterval}e=t.exports=i,o.prototype=c.prototype,i.prototype=new o,i.prototype.constructor=i}),t.register("runnable.js",function(t,e,r){function i(t,e){this.title=t,this.fn=e,this.async=e&&e.length,this.sync=!this.async,this._timeout=2e3,this._slow=75,this._enableTimeouts=!0,this.timedOut=!1,this._trace=new Error("done() called multiple times")}function o(){}var s=r("browser/events").EventEmitter,a=r("browser/debug")("mocha:runnable"),u=r("./ms"),c=n.Date,l=n.setTimeout,h=(n.setInterval,n.clearTimeout),f=(n.clearInterval,Object.prototype.toString);t.exports=i,o.prototype=s.prototype,i.prototype=new o,i.prototype.constructor=i,i.prototype.timeout=function(t){return 0==arguments.length?this._timeout:(0===t&&(this._enableTimeouts=!1),"string"==typeof t&&(t=u(t)),a("timeout %d",t),this._timeout=t,this.timer&&this.resetTimeout(),this)},i.prototype.slow=function(t){return 0===arguments.length?this._slow:("string"==typeof t&&(t=u(t)),a("timeout %d",t),this._slow=t,this)},i.prototype.enableTimeouts=function(t){return 0===arguments.length?this._enableTimeouts:(a("enableTimeouts %s",t),this._enableTimeouts=t,this)},i.prototype.fullTitle=function(){return this.parent.fullTitle()+" "+this.title},i.prototype.clearTimeout=function(){h(this.timer)},i.prototype.inspect=function(){return JSON.stringify(this,function(t,e){return"_"!=t[0]?"parent"==t?"#":"ctx"==t?"#":e:void 0},2)},i.prototype.resetTimeout=function(){var t=this,e=this.timeout()||1e9;this._enableTimeouts&&(this.clearTimeout(),this.timer=l(function(){t._enableTimeouts&&(t.callback(new Error("timeout of "+e+"ms exceeded")),t.timedOut=!0)},e))},i.prototype.globals=function(t){this._allowedGlobals=t},i.prototype.run=function(t){function e(t){o||(o=!0,s.emit("error",t||new Error("done() called multiple times; stacktrace may be inaccurate")))}function n(n){var r=s.timeout();if(!s.timedOut){if(i)return e(n||s._trace);s.clearTimeout(),s.duration=new c-a,i=!0,!n&&s.duration>r&&s._enableTimeouts&&(n=new Error("timeout of "+r+"ms exceeded")),t(n)}}function r(t){var e=t.call(u);e&&"function"==typeof e.then?(s.resetTimeout(),e.then(function(){n()},function(t){n(t||new Error("Promise rejected with no or falsy reason"))})):n()}var i,o,s=this,a=new c,u=this.ctx;if(u&&u.runnable&&u.runnable(this),this.callback=n,this.async){this.resetTimeout();try{this.fn.call(u,function(t){return t instanceof Error||"[object Error]"===f.call(t)?n(t):null!=t?n("[object Object]"===Object.prototype.toString.call(t)?new Error("done() invoked with non-Error: "+JSON.stringify(t)):new Error("done() invoked with non-Error: "+t)):void n()})}catch(l){n(l)}}else{if(this.asyncOnly)return n(new Error("--async-only option in use without declaring `done()`"));try{this.pending?n():r(this.fn)}catch(l){n(l)}}}}),t.register("runner.js",function(t,e,r){function i(t){var e=this;this._globals=[],this._abort=!1,this.suite=t,this.total=t.total(),this.failures=0,this.on("test end",function(t){e.checkGlobals(t)}),this.on("hook end",function(t){e.checkGlobals(t)}),this.grep(/.*/),this.globals(this.globalProps().concat(u()))}function s(){}function a(t,e){return f(e,function(e){if(/^d+/.test(e))return!1;if(n.navigator&&/^getInterface/.test(e))return!1;if(n.navigator&&/^\d+/.test(e))return!1;if(/^mocha-/.test(e))return!1;var r=f(t,function(t){return~t.indexOf("*")?0==e.indexOf(t.split("*")[0]):e==t});return 0==r.length&&(!n.navigator||"onerror"!==e)})}function u(){if("object"==typeof o&&"string"==typeof o.version){var t=o.version.split(".").reduce(function(t,e){return t<<8|e});if(2315>t)return["errno"]}return[]}var c=r("browser/events").EventEmitter,l=r("browser/debug")("mocha:runner"),h=(r("./test"),r("./utils")),f=h.filter,p=(h.keys,["setTimeout","clearTimeout","setInterval","clearInterval","XMLHttpRequest","Date"]);t.exports=i,i.immediately=n.setImmediate||o.nextTick,s.prototype=c.prototype,i.prototype=new s,i.prototype.constructor=i,i.prototype.grep=function(t,e){return l("grep %s",t),this._grep=t,this._invert=e,this.total=this.grepTotal(this.suite),this},i.prototype.grepTotal=function(t){var e=this,n=0;return t.eachTest(function(t){var r=e._grep.test(t.fullTitle());e._invert&&(r=!r),r&&n++}),n},i.prototype.globalProps=function(){for(var t=h.keys(n),e=0;e1?this.fail(t,new Error("global leaks detected: "+e.join(", "))):e.length&&this.fail(t,new Error("global leak detected: "+e[0])))}},i.prototype.fail=function(t,e){++this.failures,t.state="failed","string"==typeof e&&(e=new Error('the string "'+e+'" was thrown, throw an Error :)')),this.emit("fail",t,e)},i.prototype.failHook=function(t,e){this.fail(t,e),this.suite.bail()&&this.emit("end")},i.prototype.hook=function(t,e){function n(t){var i=o[t];return i?s.failures&&r.bail()?e():(s.currentRunnable=i,i.ctx.currentTest=s.test,s.emit("hook",i),i.on("error",function(t){s.failHook(i,t)}),void i.run(function(r){i.removeAllListeners("error");var o=i.error();return o&&s.fail(s.test,o),r?(s.failHook(i,r),e(r)):(s.emit("hook end",i),delete i.ctx.currentTest,void n(++t))})):e()}var r=this.suite,o=r["_"+t],s=this;i.immediately(function(){n(0)})},i.prototype.hooks=function(t,e,n){function r(s){return i.suite=s,s?void i.hook(t,function(t){if(t){var s=i.suite;return i.suite=o,n(t,s)}r(e.pop())}):(i.suite=o,n())}var i=this,o=this.suite;r(e.pop())},i.prototype.hookUp=function(t,e){var n=[this.suite].concat(this.parents()).reverse();this.hooks(t,n,e)},i.prototype.hookDown=function(t,e){var n=[this.suite].concat(this.parents());this.hooks(t,n,e)},i.prototype.parents=function(){for(var t=this.suite,e=[];t=t.parent;)e.push(t);return e},i.prototype.runTest=function(t){var e=this.test,n=this;this.asyncOnly&&(e.asyncOnly=!0);try{e.on("error",function(t){n.fail(e,t)}),e.run(t)}catch(r){t(r)}},i.prototype.runTests=function(t,e){function n(t,r,i){var s=o.suite;o.suite=i?r.parent:r,o.suite?o.hookUp("afterEach",function(t,i){return o.suite=s,t?n(t,i,!0):void e(r)}):(o.suite=s,e(r))}function r(a,u){if(o.failures&&t._bail)return e();if(o._abort)return e();if(a)return n(a,u,!0);if(i=s.shift(),!i)return e();var c=o._grep.test(i.fullTitle());return o._invert&&(c=!c),c?i.pending?(o.emit("pending",i),o.emit("test end",i),r()):(o.emit("test",o.test=i),void o.hookDown("beforeEach",function(t,e){return t?n(t,e,!1):(o.currentRunnable=o.test,void o.runTest(function(t){return i=o.test,t?(o.fail(i,t),o.emit("test end",i),o.hookUp("afterEach",r)):(i.state="passed",o.emit("pass",i),o.emit("test end",i),void o.hookUp("afterEach",r))}))})):r()}var i,o=this,s=t.tests.slice();this.next=r,r()},i.prototype.runSuite=function(t,e){function n(e){if(e)return e==t?r():r(e);if(o._abort)return r();var i=t.suites[s++];return i?void o.runSuite(i,n):r()}function r(n){o.suite=t,o.hook("afterAll",function(){o.emit("suite end",t),e(n)})}var i=this.grepTotal(t),o=this,s=0;return l("run suite %s",t.fullTitle()),i?(this.emit("suite",this.suite=t),void this.hook("beforeAll",function(e){return e?r():void o.runTests(t,n)})):e()},i.prototype.uncaught=function(t){t?l("uncaught exception %s",t!==function(){return this}.call(t)?t:t.message||t):(l("uncaught undefined exception"),t=new Error("Caught undefined error, did you throw without specifying what?")),t.uncaught=!0;var e=this.currentRunnable;if(e){var n=e.state;if(this.fail(e,t),e.clearTimeout(),!n)return"test"==e.type?(this.emit("test end",e),void this.hookUp("afterEach",this.next)):void this.emit("end")}},i.prototype.run=function(t){function e(t){n.uncaught(t)}var n=this,t=t||function(){};return l("start"),this.on("end",function(){l("end"),o.removeListener("uncaughtException",e),t(n.failures)}),this.emit("start"),this.runSuite(this.suite,function(){l("finished running"),n.emit("end")}),o.on("uncaughtException",e),this},i.prototype.abort=function(){l("aborting"),this._abort=!0}}),t.register("suite.js",function(t,e,n){function r(t,e){this.title=t;var n=function(){};n.prototype=e,this.ctx=new n,this.suites=[],this.tests=[],this.pending=!1,this._beforeEach=[],this._beforeAll=[],this._afterEach=[],this._afterAll=[],this.root=!t,this._timeout=2e3,this._enableTimeouts=!0,this._slow=75,this._bail=!1}function i(){}var o=n("browser/events").EventEmitter,s=n("browser/debug")("mocha:suite"),a=n("./ms"),u=n("./utils"),c=n("./hook");e=t.exports=r,e.create=function(t,e){var n=new r(e,t.ctx);return n.parent=t,t.pending&&(n.pending=!0),e=n.fullTitle(),t.addSuite(n),n},i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r,r.prototype.clone=function(){var t=new r(this.title);return s("clone"),t.ctx=this.ctx,t.timeout(this.timeout()),t.enableTimeouts(this.enableTimeouts()),t.slow(this.slow()),t.bail(this.bail()),t},r.prototype.timeout=function(t){return 0==arguments.length?this._timeout:(0===t&&(this._enableTimeouts=!1),"string"==typeof t&&(t=a(t)),s("timeout %d",t),this._timeout=parseInt(t,10),this)},r.prototype.enableTimeouts=function(t){return 0===arguments.length?this._enableTimeouts:(s("enableTimeouts %s",t),this._enableTimeouts=t,this)},r.prototype.slow=function(t){return 0===arguments.length?this._slow:("string"==typeof t&&(t=a(t)),s("slow %d",t),this._slow=t,this)},r.prototype.bail=function(t){return 0==arguments.length?this._bail:(s("bail %s",t),this._bail=t,this)},r.prototype.beforeAll=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"before all" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._beforeAll.push(n),this.emit("beforeAll",n),this},r.prototype.afterAll=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"after all" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._afterAll.push(n),this.emit("afterAll",n),this},r.prototype.beforeEach=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"before each" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._beforeEach.push(n),this.emit("beforeEach",n),this},r.prototype.afterEach=function(t,e){if(this.pending)return this;"function"==typeof t&&(e=t,t=e.name),t='"after each" hook'+(t?": "+t:"");var n=new c(t,e);return n.parent=this,n.timeout(this.timeout()),n.enableTimeouts(this.enableTimeouts()),n.slow(this.slow()),n.ctx=this.ctx,this._afterEach.push(n),this.emit("afterEach",n),this},r.prototype.addSuite=function(t){return t.parent=this,t.timeout(this.timeout()),t.enableTimeouts(this.enableTimeouts()),t.slow(this.slow()),t.bail(this.bail()),this.suites.push(t),this.emit("suite",t),this},r.prototype.addTest=function(t){return t.parent=this,t.timeout(this.timeout()),t.enableTimeouts(this.enableTimeouts()),t.slow(this.slow()),t.ctx=this.ctx,this.tests.push(t),this.emit("test",t),this},r.prototype.fullTitle=function(){if(this.parent){var t=this.parent.fullTitle();if(t)return t+" "+this.title}return this.title},r.prototype.total=function(){return u.reduce(this.suites,function(t,e){return t+e.total()},0)+this.tests.length},r.prototype.eachTest=function(t){return u.forEach(this.tests,t),u.forEach(this.suites,function(e){e.eachTest(t)}),this}}),t.register("test.js",function(t,e,n){function r(t,e){o.call(this,t,e),this.pending=!e,this.type="test"}function i(){}var o=n("./runnable");t.exports=r,i.prototype=o.prototype,r.prototype=new i,r.prototype.constructor=r}),t.register("utils.js",function(t,e,n){function r(t){return!~f.indexOf(t)}function i(t){return t.replace(//g,">").replace(/\/\/(.*)/gm,'//$1').replace(/('.*?')/gm,'$1').replace(/(\d+\.\d+)/gm,'$1').replace(/(\d+)/gm,'$1').replace(/\bnew[ \t]+(\w+)/gm,'new $1').replace(/\b(function|new|throw|return|var|if|else)\b/gm,'$1')}var o=n("browser/fs"),s=n("browser/path"),a=s.basename,u=o.existsSync||s.existsSync,c=n("browser/glob"),l=s.join,h=n("browser/debug")("mocha:watch"),f=["node_modules",".git"];e.escape=function(t){return String(t).replace(/&/g,"&").replace(/"/g,""").replace(//g,">")},e.forEach=function(t,e,n){for(var r=0,i=t.length;i>r;r++)e.call(n,t[r],r)},e.map=function(t,e,n){for(var r=[],i=0,o=t.length;o>i;i++)r.push(e.call(n,t[i],i));return r},e.indexOf=function(t,e,n){for(var r=n||0,i=t.length;i>r;r++)if(t[r]===e)return r;return-1},e.reduce=function(t,e,n){for(var r=n,i=0,o=t.length;o>i;i++)r=e(r,t[i],i,t);return r},e.filter=function(t,e){for(var n=[],r=0,i=t.length;i>r;r++){var o=t[r];e(o,r,t)&&n.push(o)}return n},e.keys=Object.keys||function(t){var e=[],n=Object.prototype.hasOwnProperty;for(var r in t)n.call(t,r)&&e.push(r);return e},e.watch=function(t,e){var n={interval:100};t.forEach(function(t){h("file %s",t),o.watchFile(t,n,function(n,r){r.mtime *{?/,"").replace(/\s+\}$/,"");var n=t.match(/^\n?( *)/)[1].length,r=t.match(/^\n?(\t*)/)[1].length,i=new RegExp("^\n?"+(r?" ":" ")+"{"+(r?r:n)+"}","gm");return t=t.replace(i,""),e.trim(t)},e.trim=function(t){return t.replace(/^\s+|\s+$/g,"")},e.parseQuery=function(t){return e.reduce(t.replace("?","").split("&"),function(t,e){var n=e.indexOf("="),r=e.slice(0,n),i=e.slice(++n);return t[r]=decodeURIComponent(i),t},{})},e.highlightTags=function(t){for(var e=document.getElementById("mocha").getElementsByTagName(t),n=0,r=e.length;r>n;++n)e[n].innerHTML=i(e[n].innerHTML)},e.stringify=function(t){return t instanceof RegExp?t.toString():JSON.stringify(e.canonicalize(t),null,2).replace(/,(\n|$)/g,"$1")},e.canonicalize=function(t,n){if(n=n||[],-1!==e.indexOf(n,t))return"[Circular]";var r;return"[object Array]"==={}.toString.call(t)?(n.push(t),r=e.map(t,function(t){return e.canonicalize(t,n)}),n.pop()):"object"==typeof t&&null!==t?(n.push(t),r={},e.forEach(e.keys(t).sort(),function(i){r[i]=e.canonicalize(t[i],n)}),n.pop()):r=t,r},e.lookupFiles=function p(t,e,n){var r=[],i=new RegExp("\\.("+e.join("|")+")$");if(!u(t)){if(!u(t+".js")){if(r=c.sync(t),!r.length)throw new Error("cannot resolve path (or pattern) '"+t+"'");return r}t+=".js"}try{var s=o.statSync(t);if(s.isFile())return t}catch(h){return}return o.readdirSync(t).forEach(function(s){s=l(t,s);try{var u=o.statSync(s);if(u.isDirectory())return void(n&&(r=r.concat(p(s,e,n))))}catch(c){return}u.isFile()&&i.test(s)&&"."!==a(s)[0]&&r.push(s)}),r}});var n=function(){return this}(),r=n.Date,i=n.setTimeout,o=(n.setInterval,n.clearTimeout,n.clearInterval,{});o.exit=function(){},o.stdout={};var s=[],a=n.onerror;o.removeListener=function(t,e){if("uncaughtException"==t){n.onerror=a?a:function(){};var r=u.utils.indexOf(s,e);-1!=r&&s.splice(r,1)}},o.on=function(t,e){"uncaughtException"==t&&(n.onerror=function(t,n,r){return e(new Error(t+" ("+n+":"+r+")")),!0},s.push(e))};var u=n.Mocha=t("mocha"),c=n.mocha=new u({reporter:"html"});c.suite.removeAllListeners("pre-require");var l,h=[];u.Runner.immediately=function(t){h.push(t),l||(l=i(e,0))},c.throwError=function(t){throw u.utils.forEach(s,function(e){e(t)}),t},c.ui=function(t){return u.prototype.ui.call(this,t),this.suite.emit("pre-require",n,null,this),this},c.setup=function(t){"string"==typeof t&&(t={ui:t});for(var e in t)this[e](t[e]);return this},c.run=function(t){var e=c.options;c.globals("location");var r=u.utils.parseQuery(n.location.search||"");return r.grep&&c.grep(r.grep),r.invert&&c.invert(),u.prototype.run.call(c,function(r){var i=n.document;i&&i.getElementById("mocha")&&e.noHighlighting!==!0&&u.utils.highlightTags("code"),t&&t(r)})},u.process=o}(),function(){function require(t){var e=require.modules[t];if(!e)throw new Error('failed to require "'+t+'"');return"exports"in e||"function"!=typeof e.definition||(e.client=e.component=!0,e.definition.call(this,e.exports={},e),delete e.definition),e.exports}require.loader="component",require.helper={},require.helper.semVerSort=function(t,e){for(var n=t.version.split("."),r=e.version.split("."),i=0;is?1:-1;var a=n[i].substr((""+o).length),u=r[i].substr((""+s).length);if(""===a&&""!==u)return 1;if(""!==a&&""===u)return-1;if(""!==a&&""!==u)return a>u?1:-1}return 0},require.latest=function(t,e){function n(t){throw new Error('failed to find latest module of "'+t+'"')}var r=/(.*)~(.*)@v?(\d+\.\d+\.\d+[^\/]*)$/,i=/(.*)~(.*)/;i.test(t)||n(t);for(var o=Object.keys(require.modules),s=[],a=[],u=0;u0){var f=s.sort(require.helper.semVerSort).pop().name;return e===!0?f:require(f)}var f=a.pop().name;return e===!0?f:require(f)},require.modules={},require.register=function(t,e){require.modules[t]={definition:e}},require.define=function(t,e){require.modules[t]={exports:e}},require.register("chaijs~assertion-error@1.0.0",function(t,e){function n(){function t(t,n){Object.keys(n).forEach(function(r){~e.indexOf(r)||(t[r]=n[r])})}var e=[].slice.call(arguments);return function(){for(var e=[].slice.call(arguments),n=0,r={};n=0;i--)if(l=o[i],!n(t[l],e[l],r))return!1;return!0}var p,d=require("chaijs~type-detect@0.1.1");try{p=require("buffer").Buffer}catch(g){p={},p.isBuffer=function(){return!1}}e.exports=n}),require.register("chai",function(t,e){e.exports=require("chai/lib/chai.js")}),require.register("chai/lib/chai.js",function(t,e){var n=[],t=e.exports={};t.version="1.10.0",t.AssertionError=require("chaijs~assertion-error@1.0.0");var r=require("chai/lib/chai/utils/index.js");t.use=function(t){return~n.indexOf(t)||(t(this,r),n.push(t)),this};var i=require("chai/lib/chai/config.js");t.config=i;var o=require("chai/lib/chai/assertion.js");t.use(o);var s=require("chai/lib/chai/core/assertions.js");t.use(s);var a=require("chai/lib/chai/interface/expect.js");t.use(a);var u=require("chai/lib/chai/interface/should.js");t.use(u);var c=require("chai/lib/chai/interface/assert.js");t.use(c)}),require.register("chai/lib/chai/assertion.js",function(t,e){var n=require("chai/lib/chai/config.js"),r=function(){};e.exports=function(t,e){function i(t,e,n){s(this,"ssfi",n||arguments.callee),s(this,"object",t),s(this,"message",e)}var o=t.AssertionError,s=e.flag;t.Assertion=i,Object.defineProperty(i,"includeStack",{get:function(){return console.warn("Assertion.includeStack is deprecated, use chai.config.includeStack instead."),n.includeStack},set:function(t){console.warn("Assertion.includeStack is deprecated, use chai.config.includeStack instead."),n.includeStack=t}}),Object.defineProperty(i,"showDiff",{get:function(){return console.warn("Assertion.showDiff is deprecated, use chai.config.showDiff instead."),n.showDiff},set:function(t){console.warn("Assertion.showDiff is deprecated, use chai.config.showDiff instead."),n.showDiff=t}}),i.addProperty=function(t,n){e.addProperty(this.prototype,t,n)},i.addMethod=function(t,n){e.addMethod(this.prototype,t,n)},i.addChainableMethod=function(t,n,r){e.addChainableMethod(this.prototype,t,n,r)},i.addChainableNoop=function(t,n){e.addChainableMethod(this.prototype,t,r,n)},i.overwriteProperty=function(t,n){e.overwriteProperty(this.prototype,t,n)},i.overwriteMethod=function(t,n){e.overwriteMethod(this.prototype,t,n)},i.overwriteChainableMethod=function(t,n,r){e.overwriteChainableMethod(this.prototype,t,n,r)},i.prototype.assert=function(t,r,i,a,u,c){var l=e.test(this,arguments);if(!0!==c&&(c=!1),!0!==n.showDiff&&(c=!1),!l){var r=e.getMessage(this,arguments),h=e.getActual(this,arguments);throw new o(r,{actual:h,expected:a,showDiff:c},n.includeStack?this.assert:s(this,"ssfi"))}},Object.defineProperty(i.prototype,"_obj",{get:function(){return s(this,"object")},set:function(t){s(this,"object",t)}})}}),require.register("chai/lib/chai/config.js",function(t,e){e.exports={includeStack:!1,showDiff:!0,truncateThreshold:40}}),require.register("chai/lib/chai/core/assertions.js",function(t,e){e.exports=function(t,e){function n(t,n){n&&w(this,"message",n),t=t.toLowerCase();var r=w(this,"object"),i=~["a","e","i","o","u"].indexOf(t.charAt(0))?"an ":"a ";this.assert(t===e.type(r),"expected #{this} to be "+i+t,"expected #{this} not to be "+i+t)}function r(){w(this,"contains",!0)}function i(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=!1;if("array"===e.type(r)&&"object"===e.type(t)){for(var o in r)if(e.eql(r[o],t)){i=!0;break}}else if("object"===e.type(t)){if(!w(this,"negate")){for(var s in t)new y(r).property(s,t[s]);return}var a={};for(var s in t)a[s]=r[s];i=e.eql(a,t)}else i=r&&~r.indexOf(t);this.assert(i,"expected #{this} to include "+e.inspect(t),"expected #{this} to not include "+e.inspect(t))}function o(){var t=w(this,"object"),e=Object.prototype.toString.call(t);this.assert("[object Arguments]"===e,"expected #{this} to be arguments but got "+e,"expected #{this} to not be arguments")}function s(t,e){e&&w(this,"message",e);var n=w(this,"object");return w(this,"deep")?this.eql(t):void this.assert(t===n,"expected #{this} to equal #{exp}","expected #{this} to not equal #{exp}",t,this._obj,!0)}function a(t,n){n&&w(this,"message",n),this.assert(e.eql(t,w(this,"object")),"expected #{this} to deeply equal #{exp}","expected #{this} to not deeply equal #{exp}",t,this._obj,!0)}function u(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(r>t,"expected #{this} to have a length above #{exp} but got #{act}","expected #{this} to not have a length above #{exp}",t,r)}else this.assert(n>t,"expected #{this} to be above "+t,"expected #{this} to be at most "+t)}function c(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(r>=t,"expected #{this} to have a length at least #{exp} but got #{act}","expected #{this} to have a length below #{exp}",t,r)}else this.assert(n>=t,"expected #{this} to be at least "+t,"expected #{this} to be below "+t)}function l(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(t>r,"expected #{this} to have a length below #{exp} but got #{act}","expected #{this} to not have a length below #{exp}",t,r) -}else this.assert(t>n,"expected #{this} to be below "+t,"expected #{this} to be at least "+t)}function h(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(t>=r,"expected #{this} to have a length at most #{exp} but got #{act}","expected #{this} to have a length above #{exp}",t,r)}else this.assert(t>=n,"expected #{this} to be at most "+t,"expected #{this} to be above "+t)}function f(t,n){n&&w(this,"message",n);var r=e.getName(t);this.assert(w(this,"object")instanceof t,"expected #{this} to be an instance of "+r,"expected #{this} to not be an instance of "+r)}function p(t,n){n&&w(this,"message",n);var r=w(this,"object");this.assert(r.hasOwnProperty(t),"expected #{this} to have own property "+e.inspect(t),"expected #{this} to not have own property "+e.inspect(t))}function d(){w(this,"doLength",!0)}function g(t,e){e&&w(this,"message",e);var n=w(this,"object");new y(n,e).to.have.property("length");var r=n.length;this.assert(r==t,"expected #{this} to have a length of #{exp} but got #{act}","expected #{this} to not have a length of #{act}",t,r)}function v(t){var n,r=w(this,"object"),i=!0;if(t=t instanceof Array?t:Array.prototype.slice.call(arguments),!t.length)throw new Error("keys required");var o=Object.keys(r),s=t,a=t.length;if(i=t.every(function(t){return~o.indexOf(t)}),w(this,"negate")||w(this,"contains")||(i=i&&t.length==o.length),a>1){t=t.map(function(t){return e.inspect(t)});var u=t.pop();n=t.join(", ")+", and "+u}else n=e.inspect(t[0]);n=(a>1?"keys ":"key ")+n,n=(w(this,"contains")?"contain ":"have ")+n,this.assert(i,"expected #{this} to "+n,"expected #{this} to not "+n,s.sort(),o.sort(),!0)}function m(t,n,r){r&&w(this,"message",r);var i=w(this,"object");new y(i,r).is.a("function");var o=!1,s=null,a=null,u=null;0===arguments.length?(n=null,t=null):t&&(t instanceof RegExp||"string"==typeof t)?(n=t,t=null):t&&t instanceof Error?(s=t,t=null,n=null):"function"==typeof t?(a=t.prototype.name||t.name,"Error"===a&&t!==Error&&(a=(new t).name)):t=null;try{i()}catch(c){if(s)return this.assert(c===s,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp}",s instanceof Error?s.toString():s,c instanceof Error?c.toString():c),w(this,"object",c),this;if(t&&(this.assert(c instanceof t,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp} but #{act} was thrown",a,c instanceof Error?c.toString():c),!n))return w(this,"object",c),this;var l="object"===e.type(c)&&"message"in c?c.message:""+c;if(null!=l&&n&&n instanceof RegExp)return this.assert(n.exec(l),"expected #{this} to throw error matching #{exp} but got #{act}","expected #{this} to throw error not matching #{exp}",n,l),w(this,"object",c),this;if(null!=l&&n&&"string"==typeof n)return this.assert(~l.indexOf(n),"expected #{this} to throw error including #{exp} but got #{act}","expected #{this} to throw error not including #{act}",n,l),w(this,"object",c),this;o=!0,u=c}var h="",f=null!==a?a:s?"#{exp}":"an error";o&&(h=" but #{act} was thrown"),this.assert(o===!0,"expected #{this} to throw "+f+h,"expected #{this} to not throw "+f+h,s instanceof Error?s.toString():s,u instanceof Error?u.toString():u),w(this,"object",u)}function b(t,e,n){return t.every(function(t){return n?e.some(function(e){return n(t,e)}):-1!==e.indexOf(t)})}var y=t.Assertion,w=(Object.prototype.toString,e.flag);["to","be","been","is","and","has","have","with","that","at","of","same"].forEach(function(t){y.addProperty(t,function(){return this})}),y.addProperty("not",function(){w(this,"negate",!0)}),y.addProperty("deep",function(){w(this,"deep",!0)}),y.addChainableMethod("an",n),y.addChainableMethod("a",n),y.addChainableMethod("include",i,r),y.addChainableMethod("contain",i,r),y.addChainableNoop("ok",function(){this.assert(w(this,"object"),"expected #{this} to be truthy","expected #{this} to be falsy")}),y.addChainableNoop("true",function(){this.assert(!0===w(this,"object"),"expected #{this} to be true","expected #{this} to be false",this.negate?!1:!0)}),y.addChainableNoop("false",function(){this.assert(!1===w(this,"object"),"expected #{this} to be false","expected #{this} to be true",this.negate?!0:!1)}),y.addChainableNoop("null",function(){this.assert(null===w(this,"object"),"expected #{this} to be null","expected #{this} not to be null")}),y.addChainableNoop("undefined",function(){this.assert(void 0===w(this,"object"),"expected #{this} to be undefined","expected #{this} not to be undefined")}),y.addChainableNoop("exist",function(){this.assert(null!=w(this,"object"),"expected #{this} to exist","expected #{this} to not exist")}),y.addChainableNoop("empty",function(){var t=w(this,"object"),e=t;Array.isArray(t)||"string"==typeof object?e=t.length:"object"==typeof t&&(e=Object.keys(t).length),this.assert(!e,"expected #{this} to be empty","expected #{this} not to be empty")}),y.addChainableNoop("arguments",o),y.addChainableNoop("Arguments",o),y.addMethod("equal",s),y.addMethod("equals",s),y.addMethod("eq",s),y.addMethod("eql",a),y.addMethod("eqls",a),y.addMethod("above",u),y.addMethod("gt",u),y.addMethod("greaterThan",u),y.addMethod("least",c),y.addMethod("gte",c),y.addMethod("below",l),y.addMethod("lt",l),y.addMethod("lessThan",l),y.addMethod("most",h),y.addMethod("lte",h),y.addMethod("within",function(t,e,n){n&&w(this,"message",n);var r=w(this,"object"),i=t+".."+e;if(w(this,"doLength")){new y(r,n).to.have.property("length");var o=r.length;this.assert(o>=t&&e>=o,"expected #{this} to have a length within "+i,"expected #{this} to not have a length within "+i)}else this.assert(r>=t&&e>=r,"expected #{this} to be within "+i,"expected #{this} to not be within "+i)}),y.addMethod("instanceof",f),y.addMethod("instanceOf",f),y.addMethod("property",function(t,n,r){r&&w(this,"message",r);var i=w(this,"deep")?"deep property ":"property ",o=w(this,"negate"),s=w(this,"object"),a=w(this,"deep")?e.getPathValue(t,s):s[t];if(o&&void 0!==n){if(void 0===a)throw r=null!=r?r+": ":"",new Error(r+e.inspect(s)+" has no "+i+e.inspect(t))}else this.assert(void 0!==a,"expected #{this} to have a "+i+e.inspect(t),"expected #{this} to not have "+i+e.inspect(t));void 0!==n&&this.assert(n===a,"expected #{this} to have a "+i+e.inspect(t)+" of #{exp}, but got #{act}","expected #{this} to not have a "+i+e.inspect(t)+" of #{act}",n,a),w(this,"object",a)}),y.addMethod("ownProperty",p),y.addMethod("haveOwnProperty",p),y.addChainableMethod("length",g,d),y.addMethod("lengthOf",g),y.addMethod("match",function(t,e){e&&w(this,"message",e);var n=w(this,"object");this.assert(t.exec(n),"expected #{this} to match "+t,"expected #{this} not to match "+t)}),y.addMethod("string",function(t,n){n&&w(this,"message",n);var r=w(this,"object");new y(r,n).is.a("string"),this.assert(~r.indexOf(t),"expected #{this} to contain "+e.inspect(t),"expected #{this} to not contain "+e.inspect(t))}),y.addMethod("keys",v),y.addMethod("key",v),y.addMethod("throw",m),y.addMethod("throws",m),y.addMethod("Throw",m),y.addMethod("respondTo",function(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=w(this,"itself"),o="function"!==e.type(r)||i?r[t]:r.prototype[t];this.assert("function"==typeof o,"expected #{this} to respond to "+e.inspect(t),"expected #{this} to not respond to "+e.inspect(t))}),y.addProperty("itself",function(){w(this,"itself",!0)}),y.addMethod("satisfy",function(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=t(r);this.assert(i,"expected #{this} to satisfy "+e.objDisplay(t),"expected #{this} to not satisfy"+e.objDisplay(t),this.negate?!1:!0,i)}),y.addMethod("closeTo",function(t,n,r){r&&w(this,"message",r);var i=w(this,"object");if(new y(i,r).is.a("number"),"number"!==e.type(t)||"number"!==e.type(n))throw new Error("the arguments to closeTo must be numbers");this.assert(Math.abs(i-t)<=n,"expected #{this} to be close to "+t+" +/- "+n,"expected #{this} not to be close to "+t+" +/- "+n)}),y.addMethod("members",function(t,n){n&&w(this,"message",n);var r=w(this,"object");new y(r).to.be.an("array"),new y(t).to.be.an("array");var i=w(this,"deep")?e.eql:void 0;return w(this,"contains")?this.assert(b(t,r,i),"expected #{this} to be a superset of #{act}","expected #{this} to not be a superset of #{act}",r,t):void this.assert(b(r,t,i)&&b(t,r,i),"expected #{this} to have the same members as #{act}","expected #{this} to not have the same members as #{act}",r,t)})}}),require.register("chai/lib/chai/interface/assert.js",function(exports,module){module.exports=function(chai,util){var Assertion=chai.Assertion,flag=util.flag,assert=chai.assert=function(t,e){var n=new Assertion(null,null,chai.assert);n.assert(t,e,"[ negation message unavailable ]")};assert.fail=function(t,e,n,r){throw n=n||"assert.fail()",new chai.AssertionError(n,{actual:t,expected:e,operator:r},assert.fail)},assert.ok=function(t,e){new Assertion(t,e).is.ok},assert.notOk=function(t,e){new Assertion(t,e).is.not.ok},assert.equal=function(t,e,n){var r=new Assertion(t,n,assert.equal);r.assert(e==flag(r,"object"),"expected #{this} to equal #{exp}","expected #{this} to not equal #{act}",e,t)},assert.notEqual=function(t,e,n){var r=new Assertion(t,n,assert.notEqual);r.assert(e!=flag(r,"object"),"expected #{this} to not equal #{exp}","expected #{this} to equal #{act}",e,t)},assert.strictEqual=function(t,e,n){new Assertion(t,n).to.equal(e)},assert.notStrictEqual=function(t,e,n){new Assertion(t,n).to.not.equal(e)},assert.deepEqual=function(t,e,n){new Assertion(t,n).to.eql(e)},assert.notDeepEqual=function(t,e,n){new Assertion(t,n).to.not.eql(e)},assert.isTrue=function(t,e){new Assertion(t,e).is["true"]},assert.isFalse=function(t,e){new Assertion(t,e).is["false"]},assert.isNull=function(t,e){new Assertion(t,e).to.equal(null)},assert.isNotNull=function(t,e){new Assertion(t,e).to.not.equal(null)},assert.isUndefined=function(t,e){new Assertion(t,e).to.equal(void 0)},assert.isDefined=function(t,e){new Assertion(t,e).to.not.equal(void 0)},assert.isFunction=function(t,e){new Assertion(t,e).to.be.a("function")},assert.isNotFunction=function(t,e){new Assertion(t,e).to.not.be.a("function")},assert.isObject=function(t,e){new Assertion(t,e).to.be.a("object")},assert.isNotObject=function(t,e){new Assertion(t,e).to.not.be.a("object")},assert.isArray=function(t,e){new Assertion(t,e).to.be.an("array")},assert.isNotArray=function(t,e){new Assertion(t,e).to.not.be.an("array")},assert.isString=function(t,e){new Assertion(t,e).to.be.a("string")},assert.isNotString=function(t,e){new Assertion(t,e).to.not.be.a("string")},assert.isNumber=function(t,e){new Assertion(t,e).to.be.a("number")},assert.isNotNumber=function(t,e){new Assertion(t,e).to.not.be.a("number")},assert.isBoolean=function(t,e){new Assertion(t,e).to.be.a("boolean")},assert.isNotBoolean=function(t,e){new Assertion(t,e).to.not.be.a("boolean")},assert.typeOf=function(t,e,n){new Assertion(t,n).to.be.a(e)},assert.notTypeOf=function(t,e,n){new Assertion(t,n).to.not.be.a(e)},assert.instanceOf=function(t,e,n){new Assertion(t,n).to.be.instanceOf(e)},assert.notInstanceOf=function(t,e,n){new Assertion(t,n).to.not.be.instanceOf(e)},assert.include=function(t,e,n){new Assertion(t,n,assert.include).include(e)},assert.notInclude=function(t,e,n){new Assertion(t,n,assert.notInclude).not.include(e)},assert.match=function(t,e,n){new Assertion(t,n).to.match(e)},assert.notMatch=function(t,e,n){new Assertion(t,n).to.not.match(e)},assert.property=function(t,e,n){new Assertion(t,n).to.have.property(e)},assert.notProperty=function(t,e,n){new Assertion(t,n).to.not.have.property(e)},assert.deepProperty=function(t,e,n){new Assertion(t,n).to.have.deep.property(e)},assert.notDeepProperty=function(t,e,n){new Assertion(t,n).to.not.have.deep.property(e)},assert.propertyVal=function(t,e,n,r){new Assertion(t,r).to.have.property(e,n)},assert.propertyNotVal=function(t,e,n,r){new Assertion(t,r).to.not.have.property(e,n)},assert.deepPropertyVal=function(t,e,n,r){new Assertion(t,r).to.have.deep.property(e,n)},assert.deepPropertyNotVal=function(t,e,n,r){new Assertion(t,r).to.not.have.deep.property(e,n)},assert.lengthOf=function(t,e,n){new Assertion(t,n).to.have.length(e)},assert.Throw=function(t,e,n,r){("string"==typeof e||e instanceof RegExp)&&(n=e,e=null);var i=new Assertion(t,r).to.Throw(e,n);return flag(i,"object")},assert.doesNotThrow=function(t,e,n){"string"==typeof e&&(n=e,e=null),new Assertion(t,n).to.not.Throw(e)},assert.operator=function(val,operator,val2,msg){if(!~["==","===",">",">=","<","<=","!=","!=="].indexOf(operator))throw new Error('Invalid operator "'+operator+'"');var test=new Assertion(eval(val+operator+val2),msg);test.assert(!0===flag(test,"object"),"expected "+util.inspect(val)+" to be "+operator+" "+util.inspect(val2),"expected "+util.inspect(val)+" to not be "+operator+" "+util.inspect(val2))},assert.closeTo=function(t,e,n,r){new Assertion(t,r).to.be.closeTo(e,n)},assert.sameMembers=function(t,e,n){new Assertion(t,n).to.have.same.members(e)},assert.includeMembers=function(t,e,n){new Assertion(t,n).to.include.members(e)},assert.ifError=function(t,e){new Assertion(t,e).to.not.be.ok},function t(e,n){return assert[n]=assert[e],t}("Throw","throw")("Throw","throws")}}),require.register("chai/lib/chai/interface/expect.js",function(t,e){e.exports=function(t){t.expect=function(e,n){return new t.Assertion(e,n)}}}),require.register("chai/lib/chai/interface/should.js",function(t,e){e.exports=function(t){function e(){function t(){return this instanceof String||this instanceof Number?new n(this.constructor(this),null,t):this instanceof Boolean?new n(1==this,null,t):new n(this,null,t)}function e(t){Object.defineProperty(this,"should",{value:t,enumerable:!0,configurable:!0,writable:!0})}Object.defineProperty(Object.prototype,"should",{set:e,get:t,configurable:!0});var r={};return r.equal=function(t,e,r){new n(t,r).to.equal(e)},r.Throw=function(t,e,r,i){new n(t,i).to.Throw(e,r)},r.exist=function(t,e){new n(t,e).to.exist},r.not={},r.not.equal=function(t,e,r){new n(t,r).to.not.equal(e)},r.not.Throw=function(t,e,r,i){new n(t,i).to.not.Throw(e,r)},r.not.exist=function(t,e){new n(t,e).to.not.exist},r["throw"]=r.Throw,r.not["throw"]=r.not.Throw,r}var n=t.Assertion;t.should=e,t.Should=e}}),require.register("chai/lib/chai/utils/addChainableMethod.js",function(t,e){var n=require("chai/lib/chai/utils/transferFlags.js"),r=require("chai/lib/chai/utils/flag.js"),i=require("chai/lib/chai/config.js"),o="__proto__"in Object,s=/^(?:length|name|arguments|caller)$/,a=Function.prototype.call,u=Function.prototype.apply;e.exports=function(t,e,c,l){"function"!=typeof l&&(l=function(){});var h={method:c,chainingBehavior:l};t.__methods||(t.__methods={}),t.__methods[e]=h,Object.defineProperty(t,e,{get:function(){h.chainingBehavior.call(this);var e=function f(){var t=r(this,"ssfi");t&&i.includeStack===!1&&r(this,"ssfi",f);var e=h.method.apply(this,arguments);return void 0===e?this:e};if(o){var c=e.__proto__=Object.create(this);c.call=a,c.apply=u}else{var l=Object.getOwnPropertyNames(t);l.forEach(function(n){if(!s.test(n)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r)}})}return n(this,e),e},configurable:!0})}}),require.register("chai/lib/chai/utils/addMethod.js",function(t,e){var n=require("chai/lib/chai/config.js"),r=require("chai/lib/chai/utils/flag.js");e.exports=function(t,e,i){t[e]=function(){var o=r(this,"ssfi");o&&n.includeStack===!1&&r(this,"ssfi",t[e]);var s=i.apply(this,arguments);return void 0===s?this:s}}}),require.register("chai/lib/chai/utils/addProperty.js",function(t,e){e.exports=function(t,e,n){Object.defineProperty(t,e,{get:function(){var t=n.call(this);return void 0===t?this:t},configurable:!0})}}),require.register("chai/lib/chai/utils/flag.js",function(t,e){e.exports=function(t,e,n){var r=t.__flags||(t.__flags=Object.create(null));return 3!==arguments.length?r[e]:void(r[e]=n)}}),require.register("chai/lib/chai/utils/getActual.js",function(t,e){e.exports=function(t,e){return e.length>4?e[4]:t._obj}}),require.register("chai/lib/chai/utils/getEnumerableProperties.js",function(t,e){e.exports=function(t){var e=[];for(var n in t)e.push(n);return e}}),require.register("chai/lib/chai/utils/getMessage.js",function(t,e){var n=require("chai/lib/chai/utils/flag.js"),r=require("chai/lib/chai/utils/getActual.js"),i=(require("chai/lib/chai/utils/inspect.js"),require("chai/lib/chai/utils/objDisplay.js"));e.exports=function(t,e){var o=n(t,"negate"),s=n(t,"object"),a=e[3],u=r(t,e),c=o?e[2]:e[1],l=n(t,"message");return"function"==typeof c&&(c=c()),c=c||"",c=c.replace(/#{this}/g,i(s)).replace(/#{act}/g,i(u)).replace(/#{exp}/g,i(a)),l?l+": "+c:c}}),require.register("chai/lib/chai/utils/getName.js",function(t,e){e.exports=function(t){if(t.name)return t.name;var e=/^\s?function ([^(]*)\(/.exec(t);return e&&e[1]?e[1]:""}}),require.register("chai/lib/chai/utils/getPathValue.js",function(t,e){function n(t){var e=t.replace(/\[/g,".["),n=e.match(/(\\\.|[^.]+?)+/g);return n.map(function(t){var e=/\[(\d+)\]$/,n=e.exec(t);return n?{i:parseFloat(n[1])}:{p:t}})}function r(t,e){for(var n,r=e,i=0,o=t.length;o>i;i++){var s=t[i];r?("undefined"!=typeof s.p?r=r[s.p]:"undefined"!=typeof s.i&&(r=r[s.i]),i==o-1&&(n=r)):n=void 0}return n}e.exports=function(t,e){var i=n(t);return r(i,e)}}),require.register("chai/lib/chai/utils/getProperties.js",function(t,e){e.exports=function(){function t(t){-1===e.indexOf(t)&&e.push(t)}for(var e=Object.getOwnPropertyNames(subject),n=Object.getPrototypeOf(subject);null!==n;)Object.getOwnPropertyNames(n).forEach(t),n=Object.getPrototypeOf(n);return e}}),require.register("chai/lib/chai/utils/index.js",function(t,e){var t=e.exports={};t.test=require("chai/lib/chai/utils/test.js"),t.type=require("chai/lib/chai/utils/type.js"),t.getMessage=require("chai/lib/chai/utils/getMessage.js"),t.getActual=require("chai/lib/chai/utils/getActual.js"),t.inspect=require("chai/lib/chai/utils/inspect.js"),t.objDisplay=require("chai/lib/chai/utils/objDisplay.js"),t.flag=require("chai/lib/chai/utils/flag.js"),t.transferFlags=require("chai/lib/chai/utils/transferFlags.js"),t.eql=require("chaijs~deep-eql@0.1.3"),t.getPathValue=require("chai/lib/chai/utils/getPathValue.js"),t.getName=require("chai/lib/chai/utils/getName.js"),t.addProperty=require("chai/lib/chai/utils/addProperty.js"),t.addMethod=require("chai/lib/chai/utils/addMethod.js"),t.overwriteProperty=require("chai/lib/chai/utils/overwriteProperty.js"),t.overwriteMethod=require("chai/lib/chai/utils/overwriteMethod.js"),t.addChainableMethod=require("chai/lib/chai/utils/addChainableMethod.js"),t.overwriteChainableMethod=require("chai/lib/chai/utils/overwriteChainableMethod.js")}),require.register("chai/lib/chai/utils/inspect.js",function(t,e){function n(t,e,n){var i={showHidden:e,seen:[],stylize:function(t){return t}};return r(i,t,"undefined"==typeof n?2:n)}function r(e,n,p){if(n&&"function"==typeof n.inspect&&n.inspect!==t.inspect&&(!n.constructor||n.constructor.prototype!==n)){var b=n.inspect(p);return"string"!=typeof b&&(b=r(e,b,p)),b}var y=i(e,n);if(y)return y;if(m(n)){if("outerHTML"in n)return n.outerHTML;try{if(document.xmlVersion){var w=new XMLSerializer;return w.serializeToString(n)}var x="http://www.w3.org/1999/xhtml",j=document.createElementNS(x,"_");return j.appendChild(n.cloneNode(!1)),html=j.innerHTML.replace("><",">"+n.innerHTML+"<"),j.innerHTML="",html}catch(E){}}var T=v(n),k=e.showHidden?g(n):T;if(0===k.length||f(n)&&(1===k.length&&"stack"===k[0]||2===k.length&&"description"===k[0]&&"stack"===k[1])){if("function"==typeof n){var q=d(n),_=q?": "+q:"";return e.stylize("[Function"+_+"]","special")}if(l(n))return e.stylize(RegExp.prototype.toString.call(n),"regexp");if(h(n))return e.stylize(Date.prototype.toUTCString.call(n),"date");if(f(n))return o(n)}var O="",A=!1,S=["{","}"];if(c(n)&&(A=!0,S=["[","]"]),"function"==typeof n){var q=d(n),_=q?": "+q:"";O=" [Function"+_+"]"}if(l(n)&&(O=" "+RegExp.prototype.toString.call(n)),h(n)&&(O=" "+Date.prototype.toUTCString.call(n)),f(n))return o(n);if(0===k.length&&(!A||0==n.length))return S[0]+O+S[1];if(0>p)return l(n)?e.stylize(RegExp.prototype.toString.call(n),"regexp"):e.stylize("[Object]","special");e.seen.push(n);var M;return M=A?s(e,n,p,T,k):k.map(function(t){return a(e,n,p,T,t,A)}),e.seen.pop(),u(M,O,S)}function i(t,e){switch(typeof e){case"undefined":return t.stylize("undefined","undefined");case"string":var n="'"+JSON.stringify(e).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return t.stylize(n,"string");case"number":return 0===e&&1/e===-1/0?t.stylize("-0","number"):t.stylize(""+e,"number");case"boolean":return t.stylize(""+e,"boolean")}return null===e?t.stylize("null","null"):void 0}function o(t){return"["+Error.prototype.toString.call(t)+"]"}function s(t,e,n,r,i){for(var o=[],s=0,u=e.length;u>s;++s)o.push(Object.prototype.hasOwnProperty.call(e,String(s))?a(t,e,n,r,String(s),!0):"");return i.forEach(function(i){i.match(/^\d+$/)||o.push(a(t,e,n,r,i,!0))}),o}function a(t,e,n,i,o,s){var a,u;if(e.__lookupGetter__&&(e.__lookupGetter__(o)?u=e.__lookupSetter__(o)?t.stylize("[Getter/Setter]","special"):t.stylize("[Getter]","special"):e.__lookupSetter__(o)&&(u=t.stylize("[Setter]","special"))),i.indexOf(o)<0&&(a="["+o+"]"),u||(t.seen.indexOf(e[o])<0?(u=null===n?r(t,e[o],null):r(t,e[o],n-1),u.indexOf("\n")>-1&&(u=s?u.split("\n").map(function(t){return" "+t}).join("\n").substr(2):"\n"+u.split("\n").map(function(t){return" "+t}).join("\n"))):u=t.stylize("[Circular]","special")),"undefined"==typeof a){if(s&&o.match(/^\d+$/))return u;a=JSON.stringify(""+o),a.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=t.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=t.stylize(a,"string"))}return a+": "+u}function u(t,e,n){var r=0,i=t.reduce(function(t,e){return r++,e.indexOf("\n")>=0&&r++,t+e.length+1},0);return i>60?n[0]+(""===e?"":e+"\n ")+" "+t.join(",\n ")+" "+n[1]:n[0]+e+" "+t.join(", ")+" "+n[1]}function c(t){return Array.isArray(t)||"object"==typeof t&&"[object Array]"===p(t)}function l(t){return"object"==typeof t&&"[object RegExp]"===p(t)}function h(t){return"object"==typeof t&&"[object Date]"===p(t)}function f(t){return"object"==typeof t&&"[object Error]"===p(t)}function p(t){return Object.prototype.toString.call(t)}var d=require("chai/lib/chai/utils/getName.js"),g=require("chai/lib/chai/utils/getProperties.js"),v=require("chai/lib/chai/utils/getEnumerableProperties.js");e.exports=n;var m=function(t){return"object"==typeof HTMLElement?t instanceof HTMLElement:t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}}),require.register("chai/lib/chai/utils/objDisplay.js",function(t,e){var n=require("chai/lib/chai/utils/inspect.js"),r=require("chai/lib/chai/config.js");e.exports=function(t){var e=n(t),i=Object.prototype.toString.call(t);if(r.truncateThreshold&&e.length>=r.truncateThreshold){if("[object Function]"===i)return t.name&&""!==t.name?"[Function: "+t.name+"]":"[Function]";if("[object Array]"===i)return"[ Array("+t.length+") ]";if("[object Object]"===i){var o=Object.keys(t),s=o.length>2?o.splice(0,2).join(", ")+", ...":o.join(", ");return"{ Object ("+s+") }"}return e}return e}}),require.register("chai/lib/chai/utils/overwriteMethod.js",function(t,e){e.exports=function(t,e,n){var r=t[e],i=function(){return this};r&&"function"==typeof r&&(i=r),t[e]=function(){var t=n(i).apply(this,arguments);return void 0===t?this:t}}}),require.register("chai/lib/chai/utils/overwriteProperty.js",function(t,e){e.exports=function(t,e,n){var r=Object.getOwnPropertyDescriptor(t,e),i=function(){};r&&"function"==typeof r.get&&(i=r.get),Object.defineProperty(t,e,{get:function(){var t=n(i).call(this);return void 0===t?this:t},configurable:!0})}}),require.register("chai/lib/chai/utils/overwriteChainableMethod.js",function(t,e){e.exports=function(t,e,n,r){var i=t.__methods[e],o=i.chainingBehavior;i.chainingBehavior=function(){var t=r(o).call(this);return void 0===t?this:t};var s=i.method;i.method=function(){var t=n(s).apply(this,arguments);return void 0===t?this:t}}}),require.register("chai/lib/chai/utils/test.js",function(t,e){var n=require("chai/lib/chai/utils/flag.js");e.exports=function(t,e){var r=n(t,"negate"),i=e[0];return r?!i:i}}),require.register("chai/lib/chai/utils/transferFlags.js",function(t,e){e.exports=function(t,e,n){var r=t.__flags||(t.__flags=Object.create(null));e.__flags||(e.__flags=Object.create(null)),n=3===arguments.length?n:!0;for(var i in r)(n||"object"!==i&&"ssfi"!==i&&"message"!=i)&&(e.__flags[i]=r[i])}}),require.register("chai/lib/chai/utils/type.js",function(t,e){var n={"[object Arguments]":"arguments","[object Array]":"array","[object Date]":"date","[object Function]":"function","[object Number]":"number","[object RegExp]":"regexp","[object String]":"string"};e.exports=function(t){var e=Object.prototype.toString.call(t);return n[e]?n[e]:null===t?"null":void 0===t?"undefined":t===Object(t)?"object":typeof t}}),"object"==typeof exports?module.exports=require("chai"):"function"==typeof define&&define.amd?define("chai",[],function(){return require("chai")}):(this||window).chai=require("chai")}(),function(t){function e(t,e){return f.isUndefined(e)?""+e:!f.isNumber(e)||!isNaN(e)&&isFinite(e)?f.isFunction(e)||f.isRegExp(e)?e.toString():e:e.toString()}function n(t,e){return f.isString(t)?t.length=0;o--)if(u[o]!=c[o])return!1;for(o=u.length-1;o>=0;o--)if(i=u[o],!s(t[i],e[i]))return!1;return!0}function c(t,e){return t&&e?"[object RegExp]"==Object.prototype.toString.call(e)?e.test(t):t instanceof e?!0:e.call({},t)===!0?!0:!1:!1}function l(t,e,n,r){var o;f.isString(n)&&(r=n,n=null);try{e()}catch(s){o=s}if(r=(n&&n.name?" ("+n.name+").":".")+(r?" "+r:"."),t&&!o&&i(o,n,"Missing expected exception"+r),!t&&c(o,n)&&i(o,n,"Got unwanted exception"+r),t&&o&&n&&!c(o,n)||!t&&o)throw o}"undefined"==typeof t.exports&&(t.exports=t);var h=Object.create||function(t){function e(){}if(!t)throw Error("no type");return e.prototype=t,new e},f={inherits:function(t,e){t.super_=e,t.prototype=h(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})},isArray:function(t){return Array.isArray(t)},isBoolean:function(t){return"boolean"==typeof t},isNull:function(t){return null===t},isNullOrUndefined:function(t){return null==t},isNumber:function(t){return"number"==typeof t},isString:function(t){return"string"==typeof t},isSymbol:function(t){return"symbol"==typeof t},isUndefined:function(t){return void 0===t},isRegExp:function(t){return f.isObject(t)&&"[object RegExp]"===f.objectToString(t)},isObject:function(t){return"object"==typeof t&&null!==t},isDate:function(t){return f.isObject(t)&&"[object Date]"===f.objectToString(t)},isError:function(t){return isObject(t)&&("[object Error]"===objectToString(t)||t instanceof Error)},isFunction:function(t){return"function"==typeof t},isPrimitive:function(t){return null===t||"boolean"==typeof t||"number"==typeof t||"string"==typeof t||"symbol"==typeof t||"undefined"==typeof t},objectToString:function(t){return Object.prototype.toString.call(t)}},p=Array.prototype.slice,d=("function"==typeof Object.keys?Object.keys:function(t){var e=[];for(var n in t)e.push(n);return e},t.exports=o);d.AssertionError=function(t){this.name="AssertionError",this.actual=t.actual,this.expected=t.expected,this.operator=t.operator,t.message?(this.message=t.message,this.generatedMessage=!1):(this.message=r(this),this.generatedMessage=!0);var e=t.stackStartFunction||i;if(Error.captureStackTrace)Error.captureStackTrace(this,e);else try{this.stack=(new Error).stack.toString()}catch(n){}},f.inherits(d.AssertionError,Error),d.fail=i,d.ok=o,d.equal=function(t,e,n){t!=e&&i(t,e,n,"==",d.equal)},d.notEqual=function(t,e,n){t==e&&i(t,e,n,"!=",d.notEqual)},d.deepEqual=function(t,e,n){s(t,e)||i(t,e,n,"deepEqual",d.deepEqual)},d.notDeepEqual=function(t,e,n){s(t,e)&&i(t,e,n,"notDeepEqual",d.notDeepEqual)},d.strictEqual=function(t,e,n){t!==e&&i(t,e,n,"===",d.strictEqual)},d.notStrictEqual=function(t,e,n){t===e&&i(t,e,n,"!==",d.notStrictEqual)},d.throws=function(){l.apply(this,[!0].concat(p.call(arguments)))},d.doesNotThrow=function(){l.apply(this,[!1].concat(p.call(arguments)))},d.ifError=function(t){if(t)throw t},t.assert=t.exports,delete t.exports}(this);var div=document.createElement("div");div.id="mocha",document.body.appendChild(div);var g_quiet=process.env.quiet||!0;if("false"===g_quiet&&(g_quiet=!1),!g_quiet){var link=document.createElement("link");link.setAttribute("rel","stylesheet"),link.setAttribute("type","text/css"),link.setAttribute("href","../res/mocha.css"),document.getElementsByTagName("head")[0].appendChild(link)}var fs=require("fs"),path=require("path"),net=require("net"),spawn=require("child_process").spawn,createTCPServer=function(t,e){var n=net.createServer();return e&&(process.exit=function(){n.close(),process.quit()}),t=t||13013,n.on("error",function(t){console.error("Failed to launch TCP server: "+t.code)}),n.listen(t),n},spawnChildProcess=function(t){var e=spawn(process.execPath,[t]);return e};mocha.setup({ui:"bdd"});var outputAsXML=function(){var t=process.env.out_dir;t||(t=fs.realpathSync("."),console.log("====Test results will be at: "+t));var e=0;if(window.XMLSerializer){var n=new XMLSerializer,r=process.cwd();r=r.substring(r.lastIndexOf(path.sep)+1);var i=path.join(t,r+".xml"),o=(document.getElementById("mocha-report"),document.getElementById("mocha")),s=n.serializeToString(o);s=decodeURIComponent(s),fs.writeFileSync(i,s)}var a=document.getElementById("mocha-stats"),u=a.getElementsByClassName("failures"),c=void 0,l="";return u&&u.length>0&&(c=u[0].getElementsByTagName("em"),c&&c.length>0&&(l=c[0].innerText,"0"!==l&&(e=1))),g_quiet&&process.exit(e),0};window.unitTestApplicationFailed=function(){describe("Manually verify the application",function(){it("Application should succeed",function(t){t("Application failed: "+appName)})})},window.unitTestApplicationSucceed=function(){describe("Manually verify the application",function(){it("Application should succeed",function(t){t()})})},window.unitTestApplicationTimeout=function(){describe("Manually verify the application",function(){it("Application should not timeout",function(t){t("Application timeout")})})},window.addEventListener("load",function(){mocha.run(),mocha.suite.afterAll(function(){outputAsXML()})}); \ No newline at end of file +}else this.assert(t>n,"expected #{this} to be below "+t,"expected #{this} to be at least "+t)}function h(t,e){e&&w(this,"message",e);var n=w(this,"object");if(w(this,"doLength")){new y(n,e).to.have.property("length");var r=n.length;this.assert(t>=r,"expected #{this} to have a length at most #{exp} but got #{act}","expected #{this} to have a length above #{exp}",t,r)}else this.assert(t>=n,"expected #{this} to be at most "+t,"expected #{this} to be above "+t)}function f(t,n){n&&w(this,"message",n);var r=e.getName(t);this.assert(w(this,"object")instanceof t,"expected #{this} to be an instance of "+r,"expected #{this} to not be an instance of "+r)}function p(t,n){n&&w(this,"message",n);var r=w(this,"object");this.assert(r.hasOwnProperty(t),"expected #{this} to have own property "+e.inspect(t),"expected #{this} to not have own property "+e.inspect(t))}function d(){w(this,"doLength",!0)}function g(t,e){e&&w(this,"message",e);var n=w(this,"object");new y(n,e).to.have.property("length");var r=n.length;this.assert(r==t,"expected #{this} to have a length of #{exp} but got #{act}","expected #{this} to not have a length of #{act}",t,r)}function v(t){var n,r=w(this,"object"),i=!0;if(t=t instanceof Array?t:Array.prototype.slice.call(arguments),!t.length)throw new Error("keys required");var o=Object.keys(r),s=t,a=t.length;if(i=t.every(function(t){return~o.indexOf(t)}),w(this,"negate")||w(this,"contains")||(i=i&&t.length==o.length),a>1){t=t.map(function(t){return e.inspect(t)});var u=t.pop();n=t.join(", ")+", and "+u}else n=e.inspect(t[0]);n=(a>1?"keys ":"key ")+n,n=(w(this,"contains")?"contain ":"have ")+n,this.assert(i,"expected #{this} to "+n,"expected #{this} to not "+n,s.sort(),o.sort(),!0)}function m(t,n,r){r&&w(this,"message",r);var i=w(this,"object");new y(i,r).is.a("function");var o=!1,s=null,a=null,u=null;0===arguments.length?(n=null,t=null):t&&(t instanceof RegExp||"string"==typeof t)?(n=t,t=null):t&&t instanceof Error?(s=t,t=null,n=null):"function"==typeof t?(a=t.prototype.name||t.name,"Error"===a&&t!==Error&&(a=(new t).name)):t=null;try{i()}catch(c){if(s)return this.assert(c===s,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp}",s instanceof Error?s.toString():s,c instanceof Error?c.toString():c),w(this,"object",c),this;if(t&&(this.assert(c instanceof t,"expected #{this} to throw #{exp} but #{act} was thrown","expected #{this} to not throw #{exp} but #{act} was thrown",a,c instanceof Error?c.toString():c),!n))return w(this,"object",c),this;var l="object"===e.type(c)&&"message"in c?c.message:""+c;if(null!=l&&n&&n instanceof RegExp)return this.assert(n.exec(l),"expected #{this} to throw error matching #{exp} but got #{act}","expected #{this} to throw error not matching #{exp}",n,l),w(this,"object",c),this;if(null!=l&&n&&"string"==typeof n)return this.assert(~l.indexOf(n),"expected #{this} to throw error including #{exp} but got #{act}","expected #{this} to throw error not including #{act}",n,l),w(this,"object",c),this;o=!0,u=c}var h="",f=null!==a?a:s?"#{exp}":"an error";o&&(h=" but #{act} was thrown"),this.assert(o===!0,"expected #{this} to throw "+f+h,"expected #{this} to not throw "+f+h,s instanceof Error?s.toString():s,u instanceof Error?u.toString():u),w(this,"object",u)}function b(t,e,n){return t.every(function(t){return n?e.some(function(e){return n(t,e)}):-1!==e.indexOf(t)})}var y=t.Assertion,w=(Object.prototype.toString,e.flag);["to","be","been","is","and","has","have","with","that","at","of","same"].forEach(function(t){y.addProperty(t,function(){return this})}),y.addProperty("not",function(){w(this,"negate",!0)}),y.addProperty("deep",function(){w(this,"deep",!0)}),y.addChainableMethod("an",n),y.addChainableMethod("a",n),y.addChainableMethod("include",i,r),y.addChainableMethod("contain",i,r),y.addChainableNoop("ok",function(){this.assert(w(this,"object"),"expected #{this} to be truthy","expected #{this} to be falsy")}),y.addChainableNoop("true",function(){this.assert(!0===w(this,"object"),"expected #{this} to be true","expected #{this} to be false",this.negate?!1:!0)}),y.addChainableNoop("false",function(){this.assert(!1===w(this,"object"),"expected #{this} to be false","expected #{this} to be true",this.negate?!0:!1)}),y.addChainableNoop("null",function(){this.assert(null===w(this,"object"),"expected #{this} to be null","expected #{this} not to be null")}),y.addChainableNoop("undefined",function(){this.assert(void 0===w(this,"object"),"expected #{this} to be undefined","expected #{this} not to be undefined")}),y.addChainableNoop("exist",function(){this.assert(null!=w(this,"object"),"expected #{this} to exist","expected #{this} to not exist")}),y.addChainableNoop("empty",function(){var t=w(this,"object"),e=t;Array.isArray(t)||"string"==typeof object?e=t.length:"object"==typeof t&&(e=Object.keys(t).length),this.assert(!e,"expected #{this} to be empty","expected #{this} not to be empty")}),y.addChainableNoop("arguments",o),y.addChainableNoop("Arguments",o),y.addMethod("equal",s),y.addMethod("equals",s),y.addMethod("eq",s),y.addMethod("eql",a),y.addMethod("eqls",a),y.addMethod("above",u),y.addMethod("gt",u),y.addMethod("greaterThan",u),y.addMethod("least",c),y.addMethod("gte",c),y.addMethod("below",l),y.addMethod("lt",l),y.addMethod("lessThan",l),y.addMethod("most",h),y.addMethod("lte",h),y.addMethod("within",function(t,e,n){n&&w(this,"message",n);var r=w(this,"object"),i=t+".."+e;if(w(this,"doLength")){new y(r,n).to.have.property("length");var o=r.length;this.assert(o>=t&&e>=o,"expected #{this} to have a length within "+i,"expected #{this} to not have a length within "+i)}else this.assert(r>=t&&e>=r,"expected #{this} to be within "+i,"expected #{this} to not be within "+i)}),y.addMethod("instanceof",f),y.addMethod("instanceOf",f),y.addMethod("property",function(t,n,r){r&&w(this,"message",r);var i=w(this,"deep")?"deep property ":"property ",o=w(this,"negate"),s=w(this,"object"),a=w(this,"deep")?e.getPathValue(t,s):s[t];if(o&&void 0!==n){if(void 0===a)throw r=null!=r?r+": ":"",new Error(r+e.inspect(s)+" has no "+i+e.inspect(t))}else this.assert(void 0!==a,"expected #{this} to have a "+i+e.inspect(t),"expected #{this} to not have "+i+e.inspect(t));void 0!==n&&this.assert(n===a,"expected #{this} to have a "+i+e.inspect(t)+" of #{exp}, but got #{act}","expected #{this} to not have a "+i+e.inspect(t)+" of #{act}",n,a),w(this,"object",a)}),y.addMethod("ownProperty",p),y.addMethod("haveOwnProperty",p),y.addChainableMethod("length",g,d),y.addMethod("lengthOf",g),y.addMethod("match",function(t,e){e&&w(this,"message",e);var n=w(this,"object");this.assert(t.exec(n),"expected #{this} to match "+t,"expected #{this} not to match "+t)}),y.addMethod("string",function(t,n){n&&w(this,"message",n);var r=w(this,"object");new y(r,n).is.a("string"),this.assert(~r.indexOf(t),"expected #{this} to contain "+e.inspect(t),"expected #{this} to not contain "+e.inspect(t))}),y.addMethod("keys",v),y.addMethod("key",v),y.addMethod("throw",m),y.addMethod("throws",m),y.addMethod("Throw",m),y.addMethod("respondTo",function(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=w(this,"itself"),o="function"!==e.type(r)||i?r[t]:r.prototype[t];this.assert("function"==typeof o,"expected #{this} to respond to "+e.inspect(t),"expected #{this} to not respond to "+e.inspect(t))}),y.addProperty("itself",function(){w(this,"itself",!0)}),y.addMethod("satisfy",function(t,n){n&&w(this,"message",n);var r=w(this,"object"),i=t(r);this.assert(i,"expected #{this} to satisfy "+e.objDisplay(t),"expected #{this} to not satisfy"+e.objDisplay(t),this.negate?!1:!0,i)}),y.addMethod("closeTo",function(t,n,r){r&&w(this,"message",r);var i=w(this,"object");if(new y(i,r).is.a("number"),"number"!==e.type(t)||"number"!==e.type(n))throw new Error("the arguments to closeTo must be numbers");this.assert(Math.abs(i-t)<=n,"expected #{this} to be close to "+t+" +/- "+n,"expected #{this} not to be close to "+t+" +/- "+n)}),y.addMethod("members",function(t,n){n&&w(this,"message",n);var r=w(this,"object");new y(r).to.be.an("array"),new y(t).to.be.an("array");var i=w(this,"deep")?e.eql:void 0;return w(this,"contains")?this.assert(b(t,r,i),"expected #{this} to be a superset of #{act}","expected #{this} to not be a superset of #{act}",r,t):void this.assert(b(r,t,i)&&b(t,r,i),"expected #{this} to have the same members as #{act}","expected #{this} to not have the same members as #{act}",r,t)})}}),require.register("chai/lib/chai/interface/assert.js",function(exports,module){module.exports=function(chai,util){var Assertion=chai.Assertion,flag=util.flag,assert=chai.assert=function(t,e){var n=new Assertion(null,null,chai.assert);n.assert(t,e,"[ negation message unavailable ]")};assert.fail=function(t,e,n,r){throw n=n||"assert.fail()",new chai.AssertionError(n,{actual:t,expected:e,operator:r},assert.fail)},assert.ok=function(t,e){new Assertion(t,e).is.ok},assert.notOk=function(t,e){new Assertion(t,e).is.not.ok},assert.equal=function(t,e,n){var r=new Assertion(t,n,assert.equal);r.assert(e==flag(r,"object"),"expected #{this} to equal #{exp}","expected #{this} to not equal #{act}",e,t)},assert.notEqual=function(t,e,n){var r=new Assertion(t,n,assert.notEqual);r.assert(e!=flag(r,"object"),"expected #{this} to not equal #{exp}","expected #{this} to equal #{act}",e,t)},assert.strictEqual=function(t,e,n){new Assertion(t,n).to.equal(e)},assert.notStrictEqual=function(t,e,n){new Assertion(t,n).to.not.equal(e)},assert.deepEqual=function(t,e,n){new Assertion(t,n).to.eql(e)},assert.notDeepEqual=function(t,e,n){new Assertion(t,n).to.not.eql(e)},assert.isTrue=function(t,e){new Assertion(t,e).is["true"]},assert.isFalse=function(t,e){new Assertion(t,e).is["false"]},assert.isNull=function(t,e){new Assertion(t,e).to.equal(null)},assert.isNotNull=function(t,e){new Assertion(t,e).to.not.equal(null)},assert.isUndefined=function(t,e){new Assertion(t,e).to.equal(void 0)},assert.isDefined=function(t,e){new Assertion(t,e).to.not.equal(void 0)},assert.isFunction=function(t,e){new Assertion(t,e).to.be.a("function")},assert.isNotFunction=function(t,e){new Assertion(t,e).to.not.be.a("function")},assert.isObject=function(t,e){new Assertion(t,e).to.be.a("object")},assert.isNotObject=function(t,e){new Assertion(t,e).to.not.be.a("object")},assert.isArray=function(t,e){new Assertion(t,e).to.be.an("array")},assert.isNotArray=function(t,e){new Assertion(t,e).to.not.be.an("array")},assert.isString=function(t,e){new Assertion(t,e).to.be.a("string")},assert.isNotString=function(t,e){new Assertion(t,e).to.not.be.a("string")},assert.isNumber=function(t,e){new Assertion(t,e).to.be.a("number")},assert.isNotNumber=function(t,e){new Assertion(t,e).to.not.be.a("number")},assert.isBoolean=function(t,e){new Assertion(t,e).to.be.a("boolean")},assert.isNotBoolean=function(t,e){new Assertion(t,e).to.not.be.a("boolean")},assert.typeOf=function(t,e,n){new Assertion(t,n).to.be.a(e)},assert.notTypeOf=function(t,e,n){new Assertion(t,n).to.not.be.a(e)},assert.instanceOf=function(t,e,n){new Assertion(t,n).to.be.instanceOf(e)},assert.notInstanceOf=function(t,e,n){new Assertion(t,n).to.not.be.instanceOf(e)},assert.include=function(t,e,n){new Assertion(t,n,assert.include).include(e)},assert.notInclude=function(t,e,n){new Assertion(t,n,assert.notInclude).not.include(e)},assert.match=function(t,e,n){new Assertion(t,n).to.match(e)},assert.notMatch=function(t,e,n){new Assertion(t,n).to.not.match(e)},assert.property=function(t,e,n){new Assertion(t,n).to.have.property(e)},assert.notProperty=function(t,e,n){new Assertion(t,n).to.not.have.property(e)},assert.deepProperty=function(t,e,n){new Assertion(t,n).to.have.deep.property(e)},assert.notDeepProperty=function(t,e,n){new Assertion(t,n).to.not.have.deep.property(e)},assert.propertyVal=function(t,e,n,r){new Assertion(t,r).to.have.property(e,n)},assert.propertyNotVal=function(t,e,n,r){new Assertion(t,r).to.not.have.property(e,n)},assert.deepPropertyVal=function(t,e,n,r){new Assertion(t,r).to.have.deep.property(e,n)},assert.deepPropertyNotVal=function(t,e,n,r){new Assertion(t,r).to.not.have.deep.property(e,n)},assert.lengthOf=function(t,e,n){new Assertion(t,n).to.have.length(e)},assert.Throw=function(t,e,n,r){("string"==typeof e||e instanceof RegExp)&&(n=e,e=null);var i=new Assertion(t,r).to.Throw(e,n);return flag(i,"object")},assert.doesNotThrow=function(t,e,n){"string"==typeof e&&(n=e,e=null),new Assertion(t,n).to.not.Throw(e)},assert.operator=function(val,operator,val2,msg){if(!~["==","===",">",">=","<","<=","!=","!=="].indexOf(operator))throw new Error('Invalid operator "'+operator+'"');var test=new Assertion(eval(val+operator+val2),msg);test.assert(!0===flag(test,"object"),"expected "+util.inspect(val)+" to be "+operator+" "+util.inspect(val2),"expected "+util.inspect(val)+" to not be "+operator+" "+util.inspect(val2))},assert.closeTo=function(t,e,n,r){new Assertion(t,r).to.be.closeTo(e,n)},assert.sameMembers=function(t,e,n){new Assertion(t,n).to.have.same.members(e)},assert.includeMembers=function(t,e,n){new Assertion(t,n).to.include.members(e)},assert.ifError=function(t,e){new Assertion(t,e).to.not.be.ok},function t(e,n){return assert[n]=assert[e],t}("Throw","throw")("Throw","throws")}}),require.register("chai/lib/chai/interface/expect.js",function(t,e){e.exports=function(t){t.expect=function(e,n){return new t.Assertion(e,n)}}}),require.register("chai/lib/chai/interface/should.js",function(t,e){e.exports=function(t){function e(){function t(){return this instanceof String||this instanceof Number?new n(this.constructor(this),null,t):this instanceof Boolean?new n(1==this,null,t):new n(this,null,t)}function e(t){Object.defineProperty(this,"should",{value:t,enumerable:!0,configurable:!0,writable:!0})}Object.defineProperty(Object.prototype,"should",{set:e,get:t,configurable:!0});var r={};return r.equal=function(t,e,r){new n(t,r).to.equal(e)},r.Throw=function(t,e,r,i){new n(t,i).to.Throw(e,r)},r.exist=function(t,e){new n(t,e).to.exist},r.not={},r.not.equal=function(t,e,r){new n(t,r).to.not.equal(e)},r.not.Throw=function(t,e,r,i){new n(t,i).to.not.Throw(e,r)},r.not.exist=function(t,e){new n(t,e).to.not.exist},r["throw"]=r.Throw,r.not["throw"]=r.not.Throw,r}var n=t.Assertion;t.should=e,t.Should=e}}),require.register("chai/lib/chai/utils/addChainableMethod.js",function(t,e){var n=require("chai/lib/chai/utils/transferFlags.js"),r=require("chai/lib/chai/utils/flag.js"),i=require("chai/lib/chai/config.js"),o="__proto__"in Object,s=/^(?:length|name|arguments|caller)$/,a=Function.prototype.call,u=Function.prototype.apply;e.exports=function(t,e,c,l){"function"!=typeof l&&(l=function(){});var h={method:c,chainingBehavior:l};t.__methods||(t.__methods={}),t.__methods[e]=h,Object.defineProperty(t,e,{get:function(){h.chainingBehavior.call(this);var e=function f(){var t=r(this,"ssfi");t&&i.includeStack===!1&&r(this,"ssfi",f);var e=h.method.apply(this,arguments);return void 0===e?this:e};if(o){var c=e.__proto__=Object.create(this);c.call=a,c.apply=u}else{var l=Object.getOwnPropertyNames(t);l.forEach(function(n){if(!s.test(n)){var r=Object.getOwnPropertyDescriptor(t,n);Object.defineProperty(e,n,r)}})}return n(this,e),e},configurable:!0})}}),require.register("chai/lib/chai/utils/addMethod.js",function(t,e){var n=require("chai/lib/chai/config.js"),r=require("chai/lib/chai/utils/flag.js");e.exports=function(t,e,i){t[e]=function(){var o=r(this,"ssfi");o&&n.includeStack===!1&&r(this,"ssfi",t[e]);var s=i.apply(this,arguments);return void 0===s?this:s}}}),require.register("chai/lib/chai/utils/addProperty.js",function(t,e){e.exports=function(t,e,n){Object.defineProperty(t,e,{get:function(){var t=n.call(this);return void 0===t?this:t},configurable:!0})}}),require.register("chai/lib/chai/utils/flag.js",function(t,e){e.exports=function(t,e,n){var r=t.__flags||(t.__flags=Object.create(null));return 3!==arguments.length?r[e]:void(r[e]=n)}}),require.register("chai/lib/chai/utils/getActual.js",function(t,e){e.exports=function(t,e){return e.length>4?e[4]:t._obj}}),require.register("chai/lib/chai/utils/getEnumerableProperties.js",function(t,e){e.exports=function(t){var e=[];for(var n in t)e.push(n);return e}}),require.register("chai/lib/chai/utils/getMessage.js",function(t,e){var n=require("chai/lib/chai/utils/flag.js"),r=require("chai/lib/chai/utils/getActual.js"),i=(require("chai/lib/chai/utils/inspect.js"),require("chai/lib/chai/utils/objDisplay.js"));e.exports=function(t,e){var o=n(t,"negate"),s=n(t,"object"),a=e[3],u=r(t,e),c=o?e[2]:e[1],l=n(t,"message");return"function"==typeof c&&(c=c()),c=c||"",c=c.replace(/#{this}/g,i(s)).replace(/#{act}/g,i(u)).replace(/#{exp}/g,i(a)),l?l+": "+c:c}}),require.register("chai/lib/chai/utils/getName.js",function(t,e){e.exports=function(t){if(t.name)return t.name;var e=/^\s?function ([^(]*)\(/.exec(t);return e&&e[1]?e[1]:""}}),require.register("chai/lib/chai/utils/getPathValue.js",function(t,e){function n(t){var e=t.replace(/\[/g,".["),n=e.match(/(\\\.|[^.]+?)+/g);return n.map(function(t){var e=/\[(\d+)\]$/,n=e.exec(t);return n?{i:parseFloat(n[1])}:{p:t}})}function r(t,e){for(var n,r=e,i=0,o=t.length;o>i;i++){var s=t[i];r?("undefined"!=typeof s.p?r=r[s.p]:"undefined"!=typeof s.i&&(r=r[s.i]),i==o-1&&(n=r)):n=void 0}return n}e.exports=function(t,e){var i=n(t);return r(i,e)}}),require.register("chai/lib/chai/utils/getProperties.js",function(t,e){e.exports=function(){function t(t){-1===e.indexOf(t)&&e.push(t)}for(var e=Object.getOwnPropertyNames(subject),n=Object.getPrototypeOf(subject);null!==n;)Object.getOwnPropertyNames(n).forEach(t),n=Object.getPrototypeOf(n);return e}}),require.register("chai/lib/chai/utils/index.js",function(t,e){var t=e.exports={};t.test=require("chai/lib/chai/utils/test.js"),t.type=require("chai/lib/chai/utils/type.js"),t.getMessage=require("chai/lib/chai/utils/getMessage.js"),t.getActual=require("chai/lib/chai/utils/getActual.js"),t.inspect=require("chai/lib/chai/utils/inspect.js"),t.objDisplay=require("chai/lib/chai/utils/objDisplay.js"),t.flag=require("chai/lib/chai/utils/flag.js"),t.transferFlags=require("chai/lib/chai/utils/transferFlags.js"),t.eql=require("chaijs~deep-eql@0.1.3"),t.getPathValue=require("chai/lib/chai/utils/getPathValue.js"),t.getName=require("chai/lib/chai/utils/getName.js"),t.addProperty=require("chai/lib/chai/utils/addProperty.js"),t.addMethod=require("chai/lib/chai/utils/addMethod.js"),t.overwriteProperty=require("chai/lib/chai/utils/overwriteProperty.js"),t.overwriteMethod=require("chai/lib/chai/utils/overwriteMethod.js"),t.addChainableMethod=require("chai/lib/chai/utils/addChainableMethod.js"),t.overwriteChainableMethod=require("chai/lib/chai/utils/overwriteChainableMethod.js")}),require.register("chai/lib/chai/utils/inspect.js",function(t,e){function n(t,e,n){var i={showHidden:e,seen:[],stylize:function(t){return t}};return r(i,t,"undefined"==typeof n?2:n)}function r(e,n,p){if(n&&"function"==typeof n.inspect&&n.inspect!==t.inspect&&(!n.constructor||n.constructor.prototype!==n)){var b=n.inspect(p);return"string"!=typeof b&&(b=r(e,b,p)),b}var y=i(e,n);if(y)return y;if(m(n)){if("outerHTML"in n)return n.outerHTML;try{if(document.xmlVersion){var w=new XMLSerializer;return w.serializeToString(n)}var x="http://www.w3.org/1999/xhtml",j=document.createElementNS(x,"_");return j.appendChild(n.cloneNode(!1)),html=j.innerHTML.replace("><",">"+n.innerHTML+"<"),j.innerHTML="",html}catch(E){}}var T=v(n),k=e.showHidden?g(n):T;if(0===k.length||f(n)&&(1===k.length&&"stack"===k[0]||2===k.length&&"description"===k[0]&&"stack"===k[1])){if("function"==typeof n){var q=d(n),_=q?": "+q:"";return e.stylize("[Function"+_+"]","special")}if(l(n))return e.stylize(RegExp.prototype.toString.call(n),"regexp");if(h(n))return e.stylize(Date.prototype.toUTCString.call(n),"date");if(f(n))return o(n)}var O="",S=!1,A=["{","}"];if(c(n)&&(S=!0,A=["[","]"]),"function"==typeof n){var q=d(n),_=q?": "+q:"";O=" [Function"+_+"]"}if(l(n)&&(O=" "+RegExp.prototype.toString.call(n)),h(n)&&(O=" "+Date.prototype.toUTCString.call(n)),f(n))return o(n);if(0===k.length&&(!S||0==n.length))return A[0]+O+A[1];if(0>p)return l(n)?e.stylize(RegExp.prototype.toString.call(n),"regexp"):e.stylize("[Object]","special");e.seen.push(n);var M;return M=S?s(e,n,p,T,k):k.map(function(t){return a(e,n,p,T,t,S)}),e.seen.pop(),u(M,O,A)}function i(t,e){switch(typeof e){case"undefined":return t.stylize("undefined","undefined");case"string":var n="'"+JSON.stringify(e).replace(/^"|"$/g,"").replace(/'/g,"\\'").replace(/\\"/g,'"')+"'";return t.stylize(n,"string");case"number":return 0===e&&1/e===-1/0?t.stylize("-0","number"):t.stylize(""+e,"number");case"boolean":return t.stylize(""+e,"boolean")}return null===e?t.stylize("null","null"):void 0}function o(t){return"["+Error.prototype.toString.call(t)+"]"}function s(t,e,n,r,i){for(var o=[],s=0,u=e.length;u>s;++s)o.push(Object.prototype.hasOwnProperty.call(e,String(s))?a(t,e,n,r,String(s),!0):"");return i.forEach(function(i){i.match(/^\d+$/)||o.push(a(t,e,n,r,i,!0))}),o}function a(t,e,n,i,o,s){var a,u;if(e.__lookupGetter__&&(e.__lookupGetter__(o)?u=e.__lookupSetter__(o)?t.stylize("[Getter/Setter]","special"):t.stylize("[Getter]","special"):e.__lookupSetter__(o)&&(u=t.stylize("[Setter]","special"))),i.indexOf(o)<0&&(a="["+o+"]"),u||(t.seen.indexOf(e[o])<0?(u=null===n?r(t,e[o],null):r(t,e[o],n-1),u.indexOf("\n")>-1&&(u=s?u.split("\n").map(function(t){return" "+t}).join("\n").substr(2):"\n"+u.split("\n").map(function(t){return" "+t}).join("\n"))):u=t.stylize("[Circular]","special")),"undefined"==typeof a){if(s&&o.match(/^\d+$/))return u;a=JSON.stringify(""+o),a.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)?(a=a.substr(1,a.length-2),a=t.stylize(a,"name")):(a=a.replace(/'/g,"\\'").replace(/\\"/g,'"').replace(/(^"|"$)/g,"'"),a=t.stylize(a,"string"))}return a+": "+u}function u(t,e,n){var r=0,i=t.reduce(function(t,e){return r++,e.indexOf("\n")>=0&&r++,t+e.length+1},0);return i>60?n[0]+(""===e?"":e+"\n ")+" "+t.join(",\n ")+" "+n[1]:n[0]+e+" "+t.join(", ")+" "+n[1]}function c(t){return Array.isArray(t)||"object"==typeof t&&"[object Array]"===p(t)}function l(t){return"object"==typeof t&&"[object RegExp]"===p(t)}function h(t){return"object"==typeof t&&"[object Date]"===p(t)}function f(t){return"object"==typeof t&&"[object Error]"===p(t)}function p(t){return Object.prototype.toString.call(t)}var d=require("chai/lib/chai/utils/getName.js"),g=require("chai/lib/chai/utils/getProperties.js"),v=require("chai/lib/chai/utils/getEnumerableProperties.js");e.exports=n;var m=function(t){return"object"==typeof HTMLElement?t instanceof HTMLElement:t&&"object"==typeof t&&1===t.nodeType&&"string"==typeof t.nodeName}}),require.register("chai/lib/chai/utils/objDisplay.js",function(t,e){var n=require("chai/lib/chai/utils/inspect.js"),r=require("chai/lib/chai/config.js");e.exports=function(t){var e=n(t),i=Object.prototype.toString.call(t);if(r.truncateThreshold&&e.length>=r.truncateThreshold){if("[object Function]"===i)return t.name&&""!==t.name?"[Function: "+t.name+"]":"[Function]";if("[object Array]"===i)return"[ Array("+t.length+") ]";if("[object Object]"===i){var o=Object.keys(t),s=o.length>2?o.splice(0,2).join(", ")+", ...":o.join(", ");return"{ Object ("+s+") }"}return e}return e}}),require.register("chai/lib/chai/utils/overwriteMethod.js",function(t,e){e.exports=function(t,e,n){var r=t[e],i=function(){return this};r&&"function"==typeof r&&(i=r),t[e]=function(){var t=n(i).apply(this,arguments);return void 0===t?this:t}}}),require.register("chai/lib/chai/utils/overwriteProperty.js",function(t,e){e.exports=function(t,e,n){var r=Object.getOwnPropertyDescriptor(t,e),i=function(){};r&&"function"==typeof r.get&&(i=r.get),Object.defineProperty(t,e,{get:function(){var t=n(i).call(this);return void 0===t?this:t},configurable:!0})}}),require.register("chai/lib/chai/utils/overwriteChainableMethod.js",function(t,e){e.exports=function(t,e,n,r){var i=t.__methods[e],o=i.chainingBehavior;i.chainingBehavior=function(){var t=r(o).call(this);return void 0===t?this:t};var s=i.method;i.method=function(){var t=n(s).apply(this,arguments);return void 0===t?this:t}}}),require.register("chai/lib/chai/utils/test.js",function(t,e){var n=require("chai/lib/chai/utils/flag.js");e.exports=function(t,e){var r=n(t,"negate"),i=e[0];return r?!i:i}}),require.register("chai/lib/chai/utils/transferFlags.js",function(t,e){e.exports=function(t,e,n){var r=t.__flags||(t.__flags=Object.create(null));e.__flags||(e.__flags=Object.create(null)),n=3===arguments.length?n:!0;for(var i in r)(n||"object"!==i&&"ssfi"!==i&&"message"!=i)&&(e.__flags[i]=r[i])}}),require.register("chai/lib/chai/utils/type.js",function(t,e){var n={"[object Arguments]":"arguments","[object Array]":"array","[object Date]":"date","[object Function]":"function","[object Number]":"number","[object RegExp]":"regexp","[object String]":"string"};e.exports=function(t){var e=Object.prototype.toString.call(t);return n[e]?n[e]:null===t?"null":void 0===t?"undefined":t===Object(t)?"object":typeof t}}),"object"==typeof exports?module.exports=require("chai"):"function"==typeof define&&define.amd?define("chai",[],function(){return require("chai")}):(this||window).chai=require("chai")}(),function(t){function e(t,e){return f.isUndefined(e)?""+e:!f.isNumber(e)||!isNaN(e)&&isFinite(e)?f.isFunction(e)||f.isRegExp(e)?e.toString():e:e.toString()}function n(t,e){return f.isString(t)?t.length=0;o--)if(u[o]!=c[o])return!1;for(o=u.length-1;o>=0;o--)if(i=u[o],!s(t[i],e[i]))return!1;return!0}function c(t,e){return t&&e?"[object RegExp]"==Object.prototype.toString.call(e)?e.test(t):t instanceof e?!0:e.call({},t)===!0?!0:!1:!1}function l(t,e,n,r){var o;f.isString(n)&&(r=n,n=null);try{e()}catch(s){o=s}if(r=(n&&n.name?" ("+n.name+").":".")+(r?" "+r:"."),t&&!o&&i(o,n,"Missing expected exception"+r),!t&&c(o,n)&&i(o,n,"Got unwanted exception"+r),t&&o&&n&&!c(o,n)||!t&&o)throw o}"undefined"==typeof t.exports&&(t.exports=t);var h=Object.create||function(t){function e(){}if(!t)throw Error("no type");return e.prototype=t,new e},f={inherits:function(t,e){t.super_=e,t.prototype=h(e.prototype,{constructor:{value:t,enumerable:!1,writable:!0,configurable:!0}})},isArray:function(t){return Array.isArray(t)},isBoolean:function(t){return"boolean"==typeof t},isNull:function(t){return null===t},isNullOrUndefined:function(t){return null==t},isNumber:function(t){return"number"==typeof t},isString:function(t){return"string"==typeof t},isSymbol:function(t){return"symbol"==typeof t},isUndefined:function(t){return void 0===t},isRegExp:function(t){return f.isObject(t)&&"[object RegExp]"===f.objectToString(t)},isObject:function(t){return"object"==typeof t&&null!==t},isDate:function(t){return f.isObject(t)&&"[object Date]"===f.objectToString(t)},isError:function(t){return isObject(t)&&("[object Error]"===objectToString(t)||t instanceof Error)},isFunction:function(t){return"function"==typeof t},isPrimitive:function(t){return null===t||"boolean"==typeof t||"number"==typeof t||"string"==typeof t||"symbol"==typeof t||"undefined"==typeof t},objectToString:function(t){return Object.prototype.toString.call(t)}},p=Array.prototype.slice,d=("function"==typeof Object.keys?Object.keys:function(t){var e=[];for(var n in t)e.push(n);return e},t.exports=o);d.AssertionError=function(t){this.name="AssertionError",this.actual=t.actual,this.expected=t.expected,this.operator=t.operator,t.message?(this.message=t.message,this.generatedMessage=!1):(this.message=r(this),this.generatedMessage=!0);var e=t.stackStartFunction||i;if(Error.captureStackTrace)Error.captureStackTrace(this,e);else try{this.stack=(new Error).stack.toString()}catch(n){}},f.inherits(d.AssertionError,Error),d.fail=i,d.ok=o,d.equal=function(t,e,n){t!=e&&i(t,e,n,"==",d.equal)},d.notEqual=function(t,e,n){t==e&&i(t,e,n,"!=",d.notEqual)},d.deepEqual=function(t,e,n){s(t,e)||i(t,e,n,"deepEqual",d.deepEqual)},d.notDeepEqual=function(t,e,n){s(t,e)&&i(t,e,n,"notDeepEqual",d.notDeepEqual)},d.strictEqual=function(t,e,n){t!==e&&i(t,e,n,"===",d.strictEqual)},d.notStrictEqual=function(t,e,n){t===e&&i(t,e,n,"!==",d.notStrictEqual)},d.throws=function(){l.apply(this,[!0].concat(p.call(arguments)))},d.doesNotThrow=function(){l.apply(this,[!1].concat(p.call(arguments)))},d.ifError=function(t){if(t)throw t},t.assert=t.exports,delete t.exports}(this);var div=document.createElement("div");div.id="mocha",document.body.appendChild(div);var g_quiet=process.env.quiet||!0;if("false"===g_quiet&&(g_quiet=!1),!g_quiet){var link=document.createElement("link");link.setAttribute("rel","stylesheet"),link.setAttribute("type","text/css"),link.setAttribute("href","../res/mocha.css"),document.getElementsByTagName("head")[0].appendChild(link)}var fs=require("fs"),path=require("path"),net=require("net"),spawn=require("child_process").spawn,createTCPServer=function(t,e){var n=net.createServer();return e&&(process.exit=function(){n.close(),process.quit()}),t=t||13013,n.on("error",function(t){console.error("Failed to launch TCP server: "+t.code)}),n.listen(t),n},connectToTCPServer=function(t,e,n){t=t||13013;var r=net.connect({port:t});return r.setEncoding("utf8"),e&&r.write(JSON.stringify(e)),n||(r.end(),r=void 0),r},spawnChildProcess=function(t){var e=spawn(process.execPath,[t]);return e};mocha.setup({ui:"bdd"});var outputAsXML=function(){var t=process.env.out_dir;t||(t=fs.realpathSync("."),console.log("====Test results will be at: "+t));var e=0;if(window.XMLSerializer){var n=new XMLSerializer,r=process.cwd();r=r.substring(r.lastIndexOf(path.sep)+1);var i=path.join(t,r+".xml"),o=(document.getElementById("mocha-report"),document.getElementById("mocha")),s=n.serializeToString(o);s=decodeURIComponent(s),fs.writeFileSync(i,s)}var a=document.getElementById("mocha-stats"),u=a.getElementsByClassName("failures"),c=void 0,l="";return u&&u.length>0&&(c=u[0].getElementsByTagName("em"),c&&c.length>0&&(l=c[0].innerText,"0"!==l&&(e=1))),g_quiet&&process.exit(e),0};window.assertRunningResult=function(t,e){describe("Assert test running result",function(){it("the test should succeed",function(n){t?n():n("Assertion failed: "+e)})})},window.addEventListener("load",function(){mocha.run(),mocha.suite.afterAll(function(){outputAsXML()})}); \ No newline at end of file diff --git a/tests/automation/res/util.js b/tests/automation/res/util.js index 127aa82ffa..c916bd17e4 100644 --- a/tests/automation/res/util.js +++ b/tests/automation/res/util.js @@ -38,6 +38,20 @@ var createTCPServer = function(port, autoClose) { return server; }; +var connectToTCPServer = function(port, data, keepOpen) { + port = port || 13013; + var socket = net.connect({port: port}); + socket.setEncoding('utf8'); + if (data) { + socket.write(JSON.stringify(data)); + } + if (!keepOpen) { + socket.end(); + socket = undefined; + } + return socket; +}; + var spawnChildProcess = function(appPath) { var child = spawn(process.execPath, [appPath]); return child; @@ -89,26 +103,15 @@ var outputAsXML = function() { return 0; }; -window.unitTestApplicationFailed = function() { - describe('Manually verify the application', function() { - it('Application should succeed', function(done){ - done('Application failed: ' + appName); - }); - }); -}; - -window.unitTestApplicationSucceed = function() { - describe('Manually verify the application', function() { - it('Application should succeed', function(done){ - done(); - }); - }); -}; +window.assertRunningResult = function(result, errMsg) { -window.unitTestApplicationTimeout = function() { - describe('Manually verify the application', function() { - it('Application should not timeout', function(done){ - done('Application timeout'); + describe('Assert test running result', function() { + it('the test should succeed', function(done){ + if (result) { + done(); + } else { + done('Assertion failed: ' + errMsg); + } }); }); }; From 2edd79686996a655f738bf5cf4fb32b6680aad06 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Fri, 28 Nov 2014 13:10:15 +0800 Subject: [PATCH 291/492] Add new test case "call_require_with_node-main_set" --- tests/automation/.gitignore | 2 ++ .../index.html | 30 +++++++++++++++++++ .../call_require_with_node-main_set/index.js | 0 .../node_modules/test/index.js | 0 .../node_modules/test/package.json | 4 +++ .../package.json | 5 ++++ 6 files changed, 41 insertions(+) create mode 100644 tests/automation/call_require_with_node-main_set/index.html create mode 100644 tests/automation/call_require_with_node-main_set/index.js create mode 100644 tests/automation/call_require_with_node-main_set/node_modules/test/index.js create mode 100644 tests/automation/call_require_with_node-main_set/node_modules/test/package.json create mode 100644 tests/automation/call_require_with_node-main_set/package.json diff --git a/tests/automation/.gitignore b/tests/automation/.gitignore index eb9a4456d9..fdcf63a2db 100644 --- a/tests/automation/.gitignore +++ b/tests/automation/.gitignore @@ -1,3 +1,5 @@ node_modules output/ +!call_require_with_node-main_set/node_modules/ + diff --git a/tests/automation/call_require_with_node-main_set/index.html b/tests/automation/call_require_with_node-main_set/index.html new file mode 100644 index 0000000000..f14bb34f99 --- /dev/null +++ b/tests/automation/call_require_with_node-main_set/index.html @@ -0,0 +1,30 @@ + + + + +

              Test require()

              + + + + + + + + diff --git a/tests/automation/call_require_with_node-main_set/index.js b/tests/automation/call_require_with_node-main_set/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/automation/call_require_with_node-main_set/node_modules/test/index.js b/tests/automation/call_require_with_node-main_set/node_modules/test/index.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/automation/call_require_with_node-main_set/node_modules/test/package.json b/tests/automation/call_require_with_node-main_set/node_modules/test/package.json new file mode 100644 index 0000000000..f50d7198fd --- /dev/null +++ b/tests/automation/call_require_with_node-main_set/node_modules/test/package.json @@ -0,0 +1,4 @@ +{ + "name": "test", + "main": "index.js" +} diff --git a/tests/automation/call_require_with_node-main_set/package.json b/tests/automation/call_require_with_node-main_set/package.json new file mode 100644 index 0000000000..2b598748f1 --- /dev/null +++ b/tests/automation/call_require_with_node-main_set/package.json @@ -0,0 +1,5 @@ +{ + "name": "node-main", + "main": "index.html", + "node-main": "index.js" +} From d0122c8e43e98f5dffed8b27072bd8b7c4280b10 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Fri, 28 Nov 2014 14:24:22 +0800 Subject: [PATCH 292/492] Add new test case "calls_across_window" --- .../automation/calls_across_window/index.html | 11 ++ .../calls_across_window/internal/index.html | 121 ++++++++++++++++++ .../calls_across_window/internal/package.json | 4 + .../calls_across_window/internal/test.html | 32 +++++ .../calls_across_window/mocha_test.js | 59 +++++++++ .../calls_across_window/package.json | 4 + 6 files changed, 231 insertions(+) create mode 100644 tests/automation/calls_across_window/index.html create mode 100644 tests/automation/calls_across_window/internal/index.html create mode 100644 tests/automation/calls_across_window/internal/package.json create mode 100644 tests/automation/calls_across_window/internal/test.html create mode 100644 tests/automation/calls_across_window/mocha_test.js create mode 100644 tests/automation/calls_across_window/package.json diff --git a/tests/automation/calls_across_window/index.html b/tests/automation/calls_across_window/index.html new file mode 100644 index 0000000000..409ebdd38e --- /dev/null +++ b/tests/automation/calls_across_window/index.html @@ -0,0 +1,11 @@ + + +Test call across window + + +

              Test call across window

              + + + + + diff --git a/tests/automation/calls_across_window/internal/index.html b/tests/automation/calls_across_window/internal/index.html new file mode 100644 index 0000000000..890ad63698 --- /dev/null +++ b/tests/automation/calls_across_window/internal/index.html @@ -0,0 +1,121 @@ + + + + + + + + +
              + + + + + diff --git a/tests/automation/calls_across_window/internal/package.json b/tests/automation/calls_across_window/internal/package.json new file mode 100644 index 0000000000..59f6f7a921 --- /dev/null +++ b/tests/automation/calls_across_window/internal/package.json @@ -0,0 +1,4 @@ +{ + "name": "nw-test", + "main": "index.html" +} diff --git a/tests/automation/calls_across_window/internal/test.html b/tests/automation/calls_across_window/internal/test.html new file mode 100644 index 0000000000..9eb8ca8e97 --- /dev/null +++ b/tests/automation/calls_across_window/internal/test.html @@ -0,0 +1,32 @@ + + + + + + +
              + +

              + + diff --git a/tests/automation/calls_across_window/mocha_test.js b/tests/automation/calls_across_window/mocha_test.js new file mode 100644 index 0000000000..d4e536dc52 --- /dev/null +++ b/tests/automation/calls_across_window/mocha_test.js @@ -0,0 +1,59 @@ +var fs = require('fs'); +var path = require('path'); +var global = {tests_dir: fs.realpathSync('.')}; + +describe('AppTest', function(){ + describe('call across window', function(){ + var child; + var server; + var exec_argv; + var socket; + + before(function(done){ + this.timeout(0); + server = createTCPServer(13013); + server.on('connection', function(theSocket) { + socket = theSocket; + socket.setEncoding('utf8'); + done(); + }); + exec_argv = path.join(global.tests_dir, 'internal'); + child = spawnChildProcess(exec_argv); + }); + + after(function(done){ + this.timeout(0); + child.kill(); + server.close(); + done(); + }); + + afterEach(function(){ + socket.removeAllListeners('data'); + }); + + it ('nw window function call', function(done) { + socket.on('data', function(data) { + if (data == 'ok') { + done(); + } else { + done(data); + } + }); + socket.write('newWindow'); + }); + + it ('brower window function call', function(done) { + socket.on('data', function(data) { + if (data == 'ok') { + done(); + } else { + done(data); + } + }); + socket.write('newBrowserWindow'); + }); + }); +}); + + diff --git a/tests/automation/calls_across_window/package.json b/tests/automation/calls_across_window/package.json new file mode 100644 index 0000000000..de96b12e22 --- /dev/null +++ b/tests/automation/calls_across_window/package.json @@ -0,0 +1,4 @@ +{ +"name": "call_cross_window_wrapper", +"main": "index.html" +} From 95e2a16332a8d9617adf2f1cf92760f62b282424 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Fri, 28 Nov 2014 14:45:08 +0800 Subject: [PATCH 293/492] Add new test case "chromedriver2_server" --- .../chromedriver2_server_test.py | 26 ++++++++ .../chromedriver2_server/index.html | 11 ++++ .../chromedriver2_server/mocha_test.js | 61 +++++++++++++++++++ .../chromedriver2_server/package.json | 4 ++ 4 files changed, 102 insertions(+) create mode 100644 tests/automation/chromedriver2_server/chromedriver2_server_test.py create mode 100644 tests/automation/chromedriver2_server/index.html create mode 100644 tests/automation/chromedriver2_server/mocha_test.js create mode 100644 tests/automation/chromedriver2_server/package.json diff --git a/tests/automation/chromedriver2_server/chromedriver2_server_test.py b/tests/automation/chromedriver2_server/chromedriver2_server_test.py new file mode 100644 index 0000000000..52eeb0be29 --- /dev/null +++ b/tests/automation/chromedriver2_server/chromedriver2_server_test.py @@ -0,0 +1,26 @@ +import traceback +import time +import os +from selenium import webdriver + +#path = os.getcwd(); +#path = os.path.join(path, 'tmp-nw', 'chromedriver2_server'); +path = '/home/owen-cloud/Desktop/kevin/node-webkit/tests/tmp-nw/chromedriver2_server'; + +try: + driver = webdriver.Chrome(path); + driver.get('http://www.google.com'); + assert driver.title == 'Google' + + time.sleep(5) # Let the user actually see something! + search_box = driver.find_element_by_name('q') + search_box.send_keys('ChromeDriver') + search_box.submit() + time.sleep(5) # Let the user actually see something! + assert driver.title[0:12] == 'ChromeDriver' + driver.quit() +except: + driver.quit(); + traceback.print_exc() +else: + print 'pass' diff --git a/tests/automation/chromedriver2_server/index.html b/tests/automation/chromedriver2_server/index.html new file mode 100644 index 0000000000..1a9a8cb41d --- /dev/null +++ b/tests/automation/chromedriver2_server/index.html @@ -0,0 +1,11 @@ + + +Test chrome driver server + + +

              Test chrome driver server

              + + + + + diff --git a/tests/automation/chromedriver2_server/mocha_test.js b/tests/automation/chromedriver2_server/mocha_test.js new file mode 100644 index 0000000000..d778f71687 --- /dev/null +++ b/tests/automation/chromedriver2_server/mocha_test.js @@ -0,0 +1,61 @@ +var assert = require('assert'); +var exec = require('child_process').exec; +var fs = require('fs-extra'); +var path = require('path'); +var curDir = fs.realpathSync('.'); +var func = require(path.join(curDir, '..', 'start_app', 'script.js')); +var is_chromedriver_exists = false; +var result = []; +var tmpnwPath = path.join(curDir, 'tmp-nw'); + +describe('chromedriver2_server', function() { + this.timeout(0); + + before(function(done) { + var srcFile; + var dstFile; + if (process.platform == 'win32'){ + srcFile = path.join(curDir, 'chromedriver2_server.exe'); + dstFile = path.join(curDir, 'tmp-nw', 'chromedriver2_server.exe'); + } else { + srcFile = path.join(curDir, 'chromedriver2_server'); + dstFile = path.join(curDir, 'tmp-nw', 'chromedriver2_server'); + } + if (!fs.existsSync(srcFile)) { + is_chromedriver_exists = false; + done(); + } else { + func.copyExecFiles(function() { + fs.copySync(srcFile, dstFile); + exec('python ' + path.join(curDir, 'chromedriver2_server_test.py'), + function (error, stdout, stderr) { + result.push(error); + result.push(stdout); + result.push(stderr); + done(); + }); // exec + }); // copyExecfiles + } + + }); + + after(function () { + if (fs.existsSync(tmpnwPath)) { + fs.removeSync(tmpnwPath); + } + }); + + it('should work' ,function(done) { + if (!is_chromedriver_exists) { + done('chromedrier2_server does not exist'); + } else { + assert.equal(result[0], null); + assert.equal(result[1], 'pass\n'); + assert.equal(result[2], ''); + done(); + } + }); + +}); + + diff --git a/tests/automation/chromedriver2_server/package.json b/tests/automation/chromedriver2_server/package.json new file mode 100644 index 0000000000..8570c43eb9 --- /dev/null +++ b/tests/automation/chromedriver2_server/package.json @@ -0,0 +1,4 @@ +{ +"name": "chromedriver2_server_wrapper", +"main": "index.html" +} From 4aa7e038bf2c8f80849c057bbf218c23f6fd0ee0 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Fri, 28 Nov 2014 15:46:10 +0800 Subject: [PATCH 294/492] Fix minor bug and add new test case "console" --- tests/automation/buff_from_string/index.html | 5 +- .../automation/buff_from_string/package.json | 5 +- tests/automation/config.json | 2 +- tests/automation/console/index.html | 15 ++ tests/automation/console/internal/index.html | 94 +++++++++++++ .../automation/console/internal/package.json | 4 + tests/automation/console/mocha_test.js | 132 ++++++++++++++++++ tests/automation/console/package.json | 4 + 8 files changed, 253 insertions(+), 8 deletions(-) create mode 100644 tests/automation/console/index.html create mode 100644 tests/automation/console/internal/index.html create mode 100644 tests/automation/console/internal/package.json create mode 100644 tests/automation/console/mocha_test.js create mode 100644 tests/automation/console/package.json diff --git a/tests/automation/buff_from_string/index.html b/tests/automation/buff_from_string/index.html index 334a50e52e..e05147115e 100644 --- a/tests/automation/buff_from_string/index.html +++ b/tests/automation/buff_from_string/index.html @@ -8,10 +8,7 @@

              Buffer from string

              - - - - + diff --git a/tests/automation/buff_from_string/package.json b/tests/automation/buff_from_string/package.json index 113d160a54..4eccc658ae 100644 --- a/tests/automation/buff_from_string/package.json +++ b/tests/automation/buff_from_string/package.json @@ -1,5 +1,4 @@ { "name":"test", - "main":"index.html", - "dependencies":{} -} \ No newline at end of file + "main":"index.html" +} diff --git a/tests/automation/config.json b/tests/automation/config.json index 98b7c1eb69..3129838263 100644 --- a/tests/automation/config.json +++ b/tests/automation/config.json @@ -1,7 +1,7 @@ { "format": "xunit-file", "exclude": ["node_modules", "output", "internal", "res", "app", - "document_cookies", "menu", "menu_item", "shortcut"], + "document_cookies", "menu", "menu_item", "shortcut", "console"], "single": "", "timeout": "5000", "slow": "200", diff --git a/tests/automation/console/index.html b/tests/automation/console/index.html new file mode 100644 index 0000000000..d22f7ba617 --- /dev/null +++ b/tests/automation/console/index.html @@ -0,0 +1,15 @@ + + + + + Console test + + +

              Console test

              + + + + + + + diff --git a/tests/automation/console/internal/index.html b/tests/automation/console/internal/index.html new file mode 100644 index 0000000000..1fd95c72f0 --- /dev/null +++ b/tests/automation/console/internal/index.html @@ -0,0 +1,94 @@ + + + + + Test Case for 'console.log' + + +

              Please wait to be closed.

              + + + diff --git a/tests/automation/console/internal/package.json b/tests/automation/console/internal/package.json new file mode 100644 index 0000000000..085e140394 --- /dev/null +++ b/tests/automation/console/internal/package.json @@ -0,0 +1,4 @@ +{ + "name": "nw-console-test", + "main": "index.html" +} diff --git a/tests/automation/console/mocha_test.js b/tests/automation/console/mocha_test.js new file mode 100644 index 0000000000..17ec39a5c0 --- /dev/null +++ b/tests/automation/console/mocha_test.js @@ -0,0 +1,132 @@ +var path = require('path'); +var assert = require('assert'); +var fs = require('fs'); +var curDir = fs.realpathSync('.'); + +var results; +var expected = new Array( + 'New York', + '18', + 'true', + 'false', + '
              Array[3]
                ', + '
                Object
                  ', + 'undefined', + 'null', + 'Node count: 2 Done', + 'Sam', + '100', + '2', + '12.23', + '
                  1. <!DOCTYPE html>
                  ', + '
                  1. <!DOCTYPE html>
                  ', + '
                  <!DOCTYPE html>
                    ', + ' Sam has 100 points and 2 pencils.He carrys 12.23 kg of water', + 'Sam has 100 points and 2 pencils.He carrys 12.23 kg of water.
                    1. <!DOCTYPE html>
                    <!DOCTYPE html>
                      '); + + +describe('console.log', function() { + + var child, server; + + before(function(done) { + this.timeout(0); + + child = spawnChildProcess(path.join(curDir, 'internal')); + + server = createTCPServer(13013); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + results = JSON.parse(data); + done(); + }); + }); + + }); + + after(function(done){ + this.timeout(0); + child.kill(); + server.close(); + done(); + }); + + describe('output data types', function() { + it('should display string correctly', function() { + assert.equal(results[0], expected[0]); + }); + + it('should display number correctly', function() { + assert.equal(results[1], expected[1]); + }); + + it('should display boolean correctly', function() { + assert.equal(results[2], expected[2]); + assert.equal(results[3], expected[3]); + }); + + it('should display array correctly', function() { + assert.equal(results[4], expected[4]); + }); + + it('should display object correctly', function() { + assert.equal(results[5], expected[5]); + }); + + it('should display undefined correctly', function() { + assert.equal(results[6], expected[6]); + }); + + it('should display null correctly', function() { + assert.equal(results[7], expected[7]); + }); + }); + + + describe('concatenate expressions', function() { + it('should display string correctly', function() { + assert.equal(results[8], expected[8]); + }); + }); + + describe('format output', function() { + it('should display correctly with %s', function() { + assert.equal(results[9], expected[9]); + }); + + it('should display correctly with %d', function() { + assert.equal(results[10], expected[10]); + }); + + it('should display correcty with %i', function() { + assert.equal(results[11], expected[11]); + }); + + it('should display correcty with %f', function() { + assert.equal(results[12], expected[12]); + }); + + it('should display correcty object', function() { + assert.equal(results[13], expected[13]); + }); + + it('should display correcty with %o', function() { + assert.equal(results[14], expected[14]); + }); + + it('should display correcty with %O', function() { + assert.equal(results[15], expected[15]); + }); + + it('should display correcty with %c', function() { + assert.equal(results[16], expected[16]); + }); + + it('should display correcty with all formats', function() { + assert.equal(results[17], expected[17]); + }); + }) +}); + + diff --git a/tests/automation/console/package.json b/tests/automation/console/package.json new file mode 100644 index 0000000000..6c239d47d2 --- /dev/null +++ b/tests/automation/console/package.json @@ -0,0 +1,4 @@ +{ + "name":"console_wrapper", + "main":"index.html" +} From 2542d7f275ff8f05c13b8fe982ac35a96a519660 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Fri, 28 Nov 2014 16:21:32 +0800 Subject: [PATCH 295/492] Add new test case chromium-args --- tests/automation/chromium-args/index.html | 15 ++++ .../chromium-args/internal/index.html | 22 +++++ .../chromium-args/internal/package1.json | 9 ++ .../chromium-args/internal/package2.json | 9 ++ tests/automation/chromium-args/mocha_test.js | 85 +++++++++++++++++++ tests/automation/chromium-args/package.json | 4 + 6 files changed, 144 insertions(+) create mode 100644 tests/automation/chromium-args/index.html create mode 100644 tests/automation/chromium-args/internal/index.html create mode 100644 tests/automation/chromium-args/internal/package1.json create mode 100644 tests/automation/chromium-args/internal/package2.json create mode 100644 tests/automation/chromium-args/mocha_test.js create mode 100644 tests/automation/chromium-args/package.json diff --git a/tests/automation/chromium-args/index.html b/tests/automation/chromium-args/index.html new file mode 100644 index 0000000000..2e5ba2f6f8 --- /dev/null +++ b/tests/automation/chromium-args/index.html @@ -0,0 +1,15 @@ + + + + + test chromium args + + +

                      Test chromium args

                      + + + + + + + diff --git a/tests/automation/chromium-args/internal/index.html b/tests/automation/chromium-args/internal/index.html new file mode 100644 index 0000000000..e54e4e94b5 --- /dev/null +++ b/tests/automation/chromium-args/internal/index.html @@ -0,0 +1,22 @@ + + + + test case for chromium-args + + +

                      Hello World!

                      + + + diff --git a/tests/automation/chromium-args/internal/package1.json b/tests/automation/chromium-args/internal/package1.json new file mode 100644 index 0000000000..ae0e1396da --- /dev/null +++ b/tests/automation/chromium-args/internal/package1.json @@ -0,0 +1,9 @@ +{ + "name": "nw-chromium-args", + "main": "index.html", + "window": { + "show": false + }, + "chromium-args": "--disable-javascript" + +} diff --git a/tests/automation/chromium-args/internal/package2.json b/tests/automation/chromium-args/internal/package2.json new file mode 100644 index 0000000000..d1f533f2a9 --- /dev/null +++ b/tests/automation/chromium-args/internal/package2.json @@ -0,0 +1,9 @@ +{ + "name": "nw-chromium-args", + "main": "index.html", + "window": { + "show": false + }, + "chromium-args": "--app=http://www.baidu.com" + +} diff --git a/tests/automation/chromium-args/mocha_test.js b/tests/automation/chromium-args/mocha_test.js new file mode 100644 index 0000000000..2ece78f593 --- /dev/null +++ b/tests/automation/chromium-args/mocha_test.js @@ -0,0 +1,85 @@ +var assert = require('assert'); +var cp = require('child_process'); +var fs = require('fs'); +var fs_extra = require('fs-extra'); +var curDir = fs.realpathSync('.'); +var exec_path = process.execPath; +var app_path = path.join(curDir, 'internal'); + +describe('chromium-args', function() { + + + describe('--disable-javascript', function() { + + var child; + + before(function(done) { + this.timeout(0); + fs_extra.copy(path.join(app_path, 'package1.json'), path.join(app_path, 'package.json'), function (err) { + if (err) { + throw err; + } + child = spawnChildProcess(path.join(curDir, 'internal')); + }); + + setTimeout(function(){done();}, 2500); + }); + + after(function() { + if (child) + child.kill(); + fs.unlink(path.join(app_path, 'hi'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + fs.unlink(path.join(app_path, 'package.json'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + }); + + it('javascript should not be executed', function() { + var result = fs.existsSync(path.join(app_path, 'hi')); + assert.equal(result, false); + }); + + }); + + + describe('--app=url', function() { + var result2 = false; + + var child, server; + + before(function(done) { + this.timeout(0); + fs_extra.copy(path.join(app_path, 'package2.json'), path.join(app_path, 'package.json'), function (err) { + if (err) { + throw err; + } + + server = createTCPServer(13013); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + result2 = data; + done(); + }); + }); + + child = spawnChildProcess(path.join(curDir, 'internal')); + + }); + }); + + after(function(done) { + this.timeout(0); + child.kill(); + server.close(); + fs.unlink(path.join(app_path, 'package.json'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + fs.unlink(path.join(app_path, 'hi'), function(err) {if(err && err.code !== 'ENOENT') throw err}); + done(); + }); + + it('website should be the url', function() { + assert.equal(result2, true); + }); + + + }); + +}); diff --git a/tests/automation/chromium-args/package.json b/tests/automation/chromium-args/package.json new file mode 100644 index 0000000000..a556d2f655 --- /dev/null +++ b/tests/automation/chromium-args/package.json @@ -0,0 +1,4 @@ +{ + "name":"chromium-args_wrapper", + "main":"index.html" +} From 6680b5ebb252733707c55ddcc13b3805702e9082 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 11:06:26 +0800 Subject: [PATCH 296/492] Add new test case "cookie_api" --- tests/automation/cookies_api/index.html | 15 ++ .../cookies_api/internal/index.html | 128 ++++++++++++++++ .../cookies_api/internal/package.json | 4 + tests/automation/cookies_api/mocha_test.js | 144 ++++++++++++++++++ tests/automation/cookies_api/package.json | 4 + 5 files changed, 295 insertions(+) create mode 100644 tests/automation/cookies_api/index.html create mode 100644 tests/automation/cookies_api/internal/index.html create mode 100644 tests/automation/cookies_api/internal/package.json create mode 100644 tests/automation/cookies_api/mocha_test.js create mode 100644 tests/automation/cookies_api/package.json diff --git a/tests/automation/cookies_api/index.html b/tests/automation/cookies_api/index.html new file mode 100644 index 0000000000..60894e6495 --- /dev/null +++ b/tests/automation/cookies_api/index.html @@ -0,0 +1,15 @@ + + + + + Cookie api test + + +

                      cookie api test

                      + + + + + + + diff --git a/tests/automation/cookies_api/internal/index.html b/tests/automation/cookies_api/internal/index.html new file mode 100644 index 0000000000..32a7c785ac --- /dev/null +++ b/tests/automation/cookies_api/internal/index.html @@ -0,0 +1,128 @@ + + + + TEST CASE FOR COOKIES API + + +

                      Hello World!

                      + We are using node.js + + + diff --git a/tests/automation/cookies_api/internal/package.json b/tests/automation/cookies_api/internal/package.json new file mode 100644 index 0000000000..7578686d40 --- /dev/null +++ b/tests/automation/cookies_api/internal/package.json @@ -0,0 +1,4 @@ +{ + "name": "nw1", + "main": "index.html" +} diff --git a/tests/automation/cookies_api/mocha_test.js b/tests/automation/cookies_api/mocha_test.js new file mode 100644 index 0000000000..eeb279fc6b --- /dev/null +++ b/tests/automation/cookies_api/mocha_test.js @@ -0,0 +1,144 @@ +var path = require('path'); +var assert = require('assert'); +var spawn = require('child_process').spawn; +var fs = require('fs'); +var curDir = fs.realpathSync('.'); + +var changed; + +describe('Window.cookies', function() { + + var server; + + var spawnChild = function(action) { + return spawn(process.execPath, [path.join(curDir, 'internal'), action]); + }; + + before(function(done){ + server = createTCPServer(13013); + done(); + }); + + after(function(done) { + this.timeout(0); + server.close(); + done(); + }); + +//// 1 + describe("get, getAll", function() { + + var child; + var results; + + before(function(done) { + this.timeout(0); + child = spawnChild(1); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + results = JSON.parse(data); + child.kill(); + done(); + }); + }); + }); + + after(function() { + server.removeAllListeners('connection'); + }); + + it('should get cookies', function() { + assert.equal(results[0], true); + assert.equal(results[1], true); + }); + }); + + +/////////// 2 + describe("set", function() { + describe("set lang en", function() { + before(function(done) { + this.timeout(0); + child = spawnChild(2); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + results = JSON.parse(data); + changed = results[1]; + child.kill(); + done(); + }); + }); + }); + + after(function() { + server.removeAllListeners('connection'); + }); + + it('should get cookies', function() { + assert.equal(results[0], true); + }) + }); + + describe("set lang zh", function() { + before(function(done) { + this.timeout(0); + child = spawnChild(3); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + results = JSON.parse(data); + changed = results[1]; + child.kill(); + done(); + }); + }); + }); + + after(function() { + server.removeAllListeners('connection'); + }); + + it('should get cookies', function() { + assert.equal(results[0], true); + }) + }); + + }); + +//// 3, + describe('remove', function() { + before(function(done) { + this.timeout(0); + child = spawnChild(3); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + results = JSON.parse(data); + changed = results[1]; + child.kill(); + done(); + }); + }); + }); + + after(function() { + server.removeAllListeners('connection'); + }); + + it('should remove lang', function() { + assert.equal(results[1], false); + }); + }); + +///////// 4, + describe('onChanged', function() { + it('should be called when changed', function() { + assert.equal(changed, true); + }) + }); + + +}); + diff --git a/tests/automation/cookies_api/package.json b/tests/automation/cookies_api/package.json new file mode 100644 index 0000000000..a4157547c7 --- /dev/null +++ b/tests/automation/cookies_api/package.json @@ -0,0 +1,4 @@ +{ + "name":"cookie_api_wrapper", + "main":"index.html" +} From 407d069db74984ba97b4958af4bf4a3089c06ce9 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 11:07:19 +0800 Subject: [PATCH 297/492] Add new test "crash_dump" --- tests/automation/crash_dump/index.html | 15 +++ .../automation/crash_dump/internal/index.html | 29 +++++ .../crash_dump/internal/index1.html | 19 +++ .../crash_dump/internal/index2.html | 19 +++ .../crash_dump/internal/package.json | 4 + tests/automation/crash_dump/mocha_test.js | 112 ++++++++++++++++++ tests/automation/crash_dump/package.json | 4 + 7 files changed, 202 insertions(+) create mode 100644 tests/automation/crash_dump/index.html create mode 100644 tests/automation/crash_dump/internal/index.html create mode 100644 tests/automation/crash_dump/internal/index1.html create mode 100644 tests/automation/crash_dump/internal/index2.html create mode 100644 tests/automation/crash_dump/internal/package.json create mode 100644 tests/automation/crash_dump/mocha_test.js create mode 100644 tests/automation/crash_dump/package.json diff --git a/tests/automation/crash_dump/index.html b/tests/automation/crash_dump/index.html new file mode 100644 index 0000000000..84b14d54a0 --- /dev/null +++ b/tests/automation/crash_dump/index.html @@ -0,0 +1,15 @@ + + + + + Crash dump test + + +

                      Crash dump test

                      + + + + + + + diff --git a/tests/automation/crash_dump/internal/index.html b/tests/automation/crash_dump/internal/index.html new file mode 100644 index 0000000000..96f6403568 --- /dev/null +++ b/tests/automation/crash_dump/internal/index.html @@ -0,0 +1,29 @@ + + + + Test case for crash dump! + + +

                      Hello World!

                      + We are using node.js + + + diff --git a/tests/automation/crash_dump/internal/index1.html b/tests/automation/crash_dump/internal/index1.html new file mode 100644 index 0000000000..8ce42356ee --- /dev/null +++ b/tests/automation/crash_dump/internal/index1.html @@ -0,0 +1,19 @@ + + + + Test case for crash dump browser! + + +

                      Hello World!

                      + We are using node.js + + + diff --git a/tests/automation/crash_dump/internal/index2.html b/tests/automation/crash_dump/internal/index2.html new file mode 100644 index 0000000000..30ed9fa20a --- /dev/null +++ b/tests/automation/crash_dump/internal/index2.html @@ -0,0 +1,19 @@ + + + + Test case for crash dump render! + + +

                      Hello World!

                      + We are using node.js + + + diff --git a/tests/automation/crash_dump/internal/package.json b/tests/automation/crash_dump/internal/package.json new file mode 100644 index 0000000000..3842f972c4 --- /dev/null +++ b/tests/automation/crash_dump/internal/package.json @@ -0,0 +1,4 @@ +{ + "name": "crash_dump_test", + "main": "index.html" +} \ No newline at end of file diff --git a/tests/automation/crash_dump/mocha_test.js b/tests/automation/crash_dump/mocha_test.js new file mode 100644 index 0000000000..5939393fe6 --- /dev/null +++ b/tests/automation/crash_dump/mocha_test.js @@ -0,0 +1,112 @@ +var path = require('path'); +var assert = require('assert'); +var fs = require('fs'); +var fs_extra = require('fs-extra'); +var curDir = fs.realpathSync('.'); +var tmpDir = path.join(curDir, 'internal', 'tmp'); + +var results; + +describe('crash dump', function() { + + var spawnChild = function(action) { + return spawn(process.execPath, [path.join(curDir, 'internal'), action]); + }; + + var server; + + before(function(done) { + if (!fs.existsSync(tmpDir)) + fs.mkdirSync(tmpDir); + server = createTCPServer(13013); + done(); + }); + + after(function () { + server.close(); + fs_extra.remove(tmpDir, function (er) { + if (er) throw er; + }); + }); + +////////// 1 + + describe('crashBrowser()', function() { + before(function(done) { + this.timeout(0); + var child = spawnChild(0); + + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + setTimeout(function() { + results = fs.readdirSync(tmpDir); + //child.kill(); + done(); + }, 2000); + }); + }); + + }); + + after(function() { + server.removeAllListeners('connection'); + }); + + it('should work fine', function() { + assert.equal(results.length, 1); + var r = results[0].indexOf("dmp"); + assert.notEqual(r, -1); + }); + + }); + + +///// 2 + + describe('crashRenderer()', function() { + before(function(done) { + this.timeout(0); + var child = spawnChild(1); + + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + setTimeout(function() { + results = fs.readdirSync(tmpDir); + //child.kill(); + done(); + }, 2000); + }); + }); + }); + + after(function() { + server.removeAllListeners('connection'); + }); + + it('should work fine', function() { + assert.equal(results.length, 2); + var r = results[1].indexOf("dmp"); + assert.notEqual(r, -1); + }); + }); + +//// 3, + describe('App.setCrashDumpDir(dir)', function() { + before(function(done) { + this.timeout(0); + results = fs.readdirSync(tmpDir); + done(); + }); + + it('should work fine', function() { + assert.equal(results.length, 2); + }); + }); + + +}); + + + diff --git a/tests/automation/crash_dump/package.json b/tests/automation/crash_dump/package.json new file mode 100644 index 0000000000..68be4da35c --- /dev/null +++ b/tests/automation/crash_dump/package.json @@ -0,0 +1,4 @@ +{ + "name":"crash_dump_wrapper", + "main":"index.html" +} From 588c4487f9b14ae7cab46cfed95a3445ffff1311 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 11:08:05 +0800 Subject: [PATCH 298/492] add new test case "crashonreload" --- tests/automation/crashonreload/index.html | 15 +++++++++++ .../crashonreload/internal/index.html | 21 +++++++++++++++ .../crashonreload/internal/package.json | 4 +++ .../crashonreload/internal/test.html | 9 +++++++ tests/automation/crashonreload/mocha_test.js | 26 +++++++++++++++++++ tests/automation/crashonreload/package.json | 4 +++ 6 files changed, 79 insertions(+) create mode 100644 tests/automation/crashonreload/index.html create mode 100644 tests/automation/crashonreload/internal/index.html create mode 100644 tests/automation/crashonreload/internal/package.json create mode 100644 tests/automation/crashonreload/internal/test.html create mode 100644 tests/automation/crashonreload/mocha_test.js create mode 100644 tests/automation/crashonreload/package.json diff --git a/tests/automation/crashonreload/index.html b/tests/automation/crashonreload/index.html new file mode 100644 index 0000000000..58c3cfb44f --- /dev/null +++ b/tests/automation/crashonreload/index.html @@ -0,0 +1,15 @@ + + + + + Crash on reload test + + +

                      Crash on reload test

                      + + + + + + + diff --git a/tests/automation/crashonreload/internal/index.html b/tests/automation/crashonreload/internal/index.html new file mode 100644 index 0000000000..97d5bd432b --- /dev/null +++ b/tests/automation/crashonreload/internal/index.html @@ -0,0 +1,21 @@ + + + +test dev tools + + +hello world + + + + diff --git a/tests/automation/crashonreload/internal/package.json b/tests/automation/crashonreload/internal/package.json new file mode 100644 index 0000000000..c04044da00 --- /dev/null +++ b/tests/automation/crashonreload/internal/package.json @@ -0,0 +1,4 @@ +{ + "name":"dev tools", + "main":"index.html" +} \ No newline at end of file diff --git a/tests/automation/crashonreload/internal/test.html b/tests/automation/crashonreload/internal/test.html new file mode 100644 index 0000000000..c72e1692d8 --- /dev/null +++ b/tests/automation/crashonreload/internal/test.html @@ -0,0 +1,9 @@ + + + +test dev tools + + +hello world + + \ No newline at end of file diff --git a/tests/automation/crashonreload/mocha_test.js b/tests/automation/crashonreload/mocha_test.js new file mode 100644 index 0000000000..925297a6f4 --- /dev/null +++ b/tests/automation/crashonreload/mocha_test.js @@ -0,0 +1,26 @@ +var spawn = require('child_process').spawn; +var path = require('path'); +var fs = require('fs'); +var curDir = fs.realpathSync('.'); + +describe('crash on reload',function(){ + it('nw should not crash when reloading with devtool opened',function(done){ + this.timeout(0); + var result = false; + + var child = spawnChildProcess(path.join(curDir, 'internal')); + child.on('exit', function (code){ + if (code != 0) + return done('nw crashes'); + result = true; + done(); + }); + + setTimeout(function(){ + if (!result) { + child.kill(); + done(); + } + }, 7500); + }); +}); diff --git a/tests/automation/crashonreload/package.json b/tests/automation/crashonreload/package.json new file mode 100644 index 0000000000..afb89973c8 --- /dev/null +++ b/tests/automation/crashonreload/package.json @@ -0,0 +1,4 @@ +{ + "name":"crash_onreload_wrapper", + "main":"index.html" +} From db35c6956b35df5351c5f98ad0b2a668a538a5f7 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 11:09:06 +0800 Subject: [PATCH 299/492] add new test case "datapath" --- .../datapath/datacash-path/index.html | 19 ++++ .../datapath/datacash-path/package.json | 5 + tests/automation/datapath/datacash/index.html | 21 ++++ .../automation/datapath/datacash/package.json | 5 + .../datapath/datapath-cash/index.html | 19 ++++ .../datapath/datapath-cash/package.json | 5 + tests/automation/datapath/datapath/index.html | 19 ++++ .../automation/datapath/datapath/package.json | 5 + tests/automation/datapath/index.html | 15 +++ tests/automation/datapath/mocha_test.js | 97 +++++++++++++++++++ tests/automation/datapath/package.json | 4 + 11 files changed, 214 insertions(+) create mode 100644 tests/automation/datapath/datacash-path/index.html create mode 100644 tests/automation/datapath/datacash-path/package.json create mode 100644 tests/automation/datapath/datacash/index.html create mode 100644 tests/automation/datapath/datacash/package.json create mode 100644 tests/automation/datapath/datapath-cash/index.html create mode 100644 tests/automation/datapath/datapath-cash/package.json create mode 100644 tests/automation/datapath/datapath/index.html create mode 100644 tests/automation/datapath/datapath/package.json create mode 100644 tests/automation/datapath/index.html create mode 100644 tests/automation/datapath/mocha_test.js create mode 100644 tests/automation/datapath/package.json diff --git a/tests/automation/datapath/datacash-path/index.html b/tests/automation/datapath/datacash-path/index.html new file mode 100644 index 0000000000..3f67831e2a --- /dev/null +++ b/tests/automation/datapath/datacash-path/index.html @@ -0,0 +1,19 @@ + + +testing data path + + +

                      Testing data path

                      +the data path should be set as + + + diff --git a/tests/automation/datapath/datacash-path/package.json b/tests/automation/datapath/datacash-path/package.json new file mode 100644 index 0000000000..56305d8d64 --- /dev/null +++ b/tests/automation/datapath/datacash-path/package.json @@ -0,0 +1,5 @@ +{ + "name": "data path", + "main": "index.html", + "chromium-args": "--data-path='./data-cash/dataPath/'" +} diff --git a/tests/automation/datapath/datacash/index.html b/tests/automation/datapath/datacash/index.html new file mode 100644 index 0000000000..332964515e --- /dev/null +++ b/tests/automation/datapath/datacash/index.html @@ -0,0 +1,21 @@ + + +testing data path + + +

                      Testing data path

                      +the data path should be set as + + + diff --git a/tests/automation/datapath/datacash/package.json b/tests/automation/datapath/datacash/package.json new file mode 100644 index 0000000000..3551a65874 --- /dev/null +++ b/tests/automation/datapath/datacash/package.json @@ -0,0 +1,5 @@ +{ + "name": "data path", + "main": "index.html", + "chromium-args": "--data-path='./data-cash/'" +} diff --git a/tests/automation/datapath/datapath-cash/index.html b/tests/automation/datapath/datapath-cash/index.html new file mode 100644 index 0000000000..3f67831e2a --- /dev/null +++ b/tests/automation/datapath/datapath-cash/index.html @@ -0,0 +1,19 @@ + + +testing data path + + +

                      Testing data path

                      +the data path should be set as + + + diff --git a/tests/automation/datapath/datapath-cash/package.json b/tests/automation/datapath/datapath-cash/package.json new file mode 100644 index 0000000000..93f8b5f9d6 --- /dev/null +++ b/tests/automation/datapath/datapath-cash/package.json @@ -0,0 +1,5 @@ +{ + "name": "data path", + "main": "index.html", + "chromium-args": "--data-path='./dataPath/data-cash/'" +} diff --git a/tests/automation/datapath/datapath/index.html b/tests/automation/datapath/datapath/index.html new file mode 100644 index 0000000000..3f67831e2a --- /dev/null +++ b/tests/automation/datapath/datapath/index.html @@ -0,0 +1,19 @@ + + +testing data path + + +

                      Testing data path

                      +the data path should be set as + + + diff --git a/tests/automation/datapath/datapath/package.json b/tests/automation/datapath/datapath/package.json new file mode 100644 index 0000000000..7843ddcba3 --- /dev/null +++ b/tests/automation/datapath/datapath/package.json @@ -0,0 +1,5 @@ +{ + "name": "data path", + "main": "index.html", + "chromium-args": "--data-path='./dataPath/'" +} diff --git a/tests/automation/datapath/index.html b/tests/automation/datapath/index.html new file mode 100644 index 0000000000..2fbfa231bb --- /dev/null +++ b/tests/automation/datapath/index.html @@ -0,0 +1,15 @@ + + + + + Data path test + + +

                      Data path test

                      + + + + + + + diff --git a/tests/automation/datapath/mocha_test.js b/tests/automation/datapath/mocha_test.js new file mode 100644 index 0000000000..c367ff4abd --- /dev/null +++ b/tests/automation/datapath/mocha_test.js @@ -0,0 +1,97 @@ +var path = require('path'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + + +describe('data-path', function() { + + var server; + + before(function(done){ + this.timeout(0); + if (!fs.existsSync(path.join(curDir, 'data-cash'))) + fs.mkdirsSync(path.join(curDir, 'data-cash')); + if (!fs.existsSync(path.join(curDir, 'dataPath'))) + fs.mkdirsSync(path.join(curDir, 'dataPath')); + if (!fs.existsSync(path.join(curDir, 'dataPath', 'data-cash'))) + fs.mkdirsSync(path.join(curDir, 'dataPath', 'data-cash')); + if (!fs.existsSync(path.join(curDir, 'data-cash', 'dataPath'))) + fs.mkdirsSync(path.join(curDir, 'data-cash', 'dataPath')); + + server = createTCPServer(13013); + + done(); + }); + + after(function() { + setTimeout(function() { + server.close(); + fs.remove(path.join(curDir, 'data-cash')); + fs.remove(path.join(curDir, 'dataPath')); + fs.remove(path.join(curDir, 'dataPath', 'data-cash')); + fs.remove(path.join(curDir, 'data-cash', 'dataPath')); + }, 1000); + }); + + + it('setting datapath as ./data-cash/ should pass', + function(done) { + this.timeout(0); + var child = spawnChildProcess(path.join(curDir, 'datacash')); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + child.kill(); + server.removeAllListeners('connection'); + done(); + });}); + }); + + it('setting datapath as ./dataPath/ should pass', + function(done) { + this.timeout(0); + + var child = spawnChildProcess(path.join(curDir, 'datapath')); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + child.kill(); + server.removeAllListeners('connection'); + done(); + });}); + }); + + it('setting datapath as ./dataPath/data-cash/ should pass', + function(done) { + this.timeout(0); + var child = spawnChildProcess(path.join(curDir, 'datapath-cash')); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + child.kill(); + server.removeAllListeners('connection'); + done(); + });}); + + }); + + it('setting datapath as ./data-cash/dataPath/ should pass', + function(done) { + this.timeout(0); + + var child = spawnChildProcess(path.join(curDir, 'datacash-path')); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + child.kill(); + server.removeAllListeners('connection'); + done(); + });}); + + }); + + +}); + + + diff --git a/tests/automation/datapath/package.json b/tests/automation/datapath/package.json new file mode 100644 index 0000000000..6351f0b9fe --- /dev/null +++ b/tests/automation/datapath/package.json @@ -0,0 +1,4 @@ +{ + "name":"datapath_wrapper", + "main":"index.html" +} From 2cb35a7a373a77fcce934e2680fc795ee68ab475 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 12:23:40 +0800 Subject: [PATCH 300/492] add new test case "document_cookies" --- .../document_cookies/app/index.html | 54 +++++++++++ .../document_cookies/app/package.json | 7 ++ .../document_cookies/file/index.html | 54 +++++++++++ .../document_cookies/file/package.json | 7 ++ tests/automation/document_cookies/index.html | 15 +++ .../automation/document_cookies/mocha_test.js | 95 +++++++++++++++++++ .../automation/document_cookies/package.json | 4 + 7 files changed, 236 insertions(+) create mode 100644 tests/automation/document_cookies/app/index.html create mode 100644 tests/automation/document_cookies/app/package.json create mode 100644 tests/automation/document_cookies/file/index.html create mode 100644 tests/automation/document_cookies/file/package.json create mode 100644 tests/automation/document_cookies/index.html create mode 100644 tests/automation/document_cookies/mocha_test.js create mode 100644 tests/automation/document_cookies/package.json diff --git a/tests/automation/document_cookies/app/index.html b/tests/automation/document_cookies/app/index.html new file mode 100644 index 0000000000..3efd0d79e6 --- /dev/null +++ b/tests/automation/document_cookies/app/index.html @@ -0,0 +1,54 @@ + + + + + + + + diff --git a/tests/automation/document_cookies/app/package.json b/tests/automation/document_cookies/app/package.json new file mode 100644 index 0000000000..4a73bfc451 --- /dev/null +++ b/tests/automation/document_cookies/app/package.json @@ -0,0 +1,7 @@ +{ + "name": "nw", + "main": "app://whatever/index.html", + "window": { + "show": false + } +} diff --git a/tests/automation/document_cookies/file/index.html b/tests/automation/document_cookies/file/index.html new file mode 100644 index 0000000000..3efd0d79e6 --- /dev/null +++ b/tests/automation/document_cookies/file/index.html @@ -0,0 +1,54 @@ + + + + + + + + diff --git a/tests/automation/document_cookies/file/package.json b/tests/automation/document_cookies/file/package.json new file mode 100644 index 0000000000..18d312afa6 --- /dev/null +++ b/tests/automation/document_cookies/file/package.json @@ -0,0 +1,7 @@ +{ + "name": "nw", + "main": "index.html", + "window": { + "show": false + } +} diff --git a/tests/automation/document_cookies/index.html b/tests/automation/document_cookies/index.html new file mode 100644 index 0000000000..12d7d8c6c2 --- /dev/null +++ b/tests/automation/document_cookies/index.html @@ -0,0 +1,15 @@ + + + + + Document cookie test + + +

                      Document cookie test

                      + + + + + + + diff --git a/tests/automation/document_cookies/mocha_test.js b/tests/automation/document_cookies/mocha_test.js new file mode 100644 index 0000000000..0984aa7900 --- /dev/null +++ b/tests/automation/document_cookies/mocha_test.js @@ -0,0 +1,95 @@ +var path = require('path'); +var assert = require('assert'); +var gui = require('nw.gui'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); +var results = new Array(); +describe('document.cookies', function() { + +var server; + + before(function(done) { + server = createTCPServer(13013); + results.push('dump'); // should be remove when the first test case is ready + done(); + }); + + after(function () { + server.close(); + }); + +/* + describe('http', function() { + before(function(done) { + this.timeout(0); + var url = "http://127.0.0.1:8123/document_cookies.html"; + var win = gui.Window.open(url); + + setTimeout(function() { + results.push(win.window.msg.textContent); + done(); + win.window.close(); + }, 1000); + }); + it('should be set', function() { + assert.equal(results[0], '123'); + }); + }); +*/ + + describe('file', function() { + before(function(done) { + this.timeout(0); + var child = spawnChildProcess(path.join(curDir, 'file')); + + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + setTimeout(function() { + results.push(data); + child.kill(); + //done(); + }, 2000); + }); + }); + setTimeout(done, 3000); + }); + + after(function() { + server.removeAllListeners('connection'); + }); + + it ('should be set', function() { + assert.equal(results[1], '123'); + }); + }); + + describe('app', function() { + before(function(done) { + this.timeout(0); + var child = spawnChildProcess(path.join(curDir, 'app')); + + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + setTimeout(function() { + results.push(data); + child.kill(); + //done(); + }, 2000); + }); + }); + + setTimeout(done, 3000); + }); + + after(function() { + server.removeAllListeners('connection'); + }); + + it ('should be set', function() { + assert.equal(results[2], '123'); + }); + }); + +}); diff --git a/tests/automation/document_cookies/package.json b/tests/automation/document_cookies/package.json new file mode 100644 index 0000000000..196d53596c --- /dev/null +++ b/tests/automation/document_cookies/package.json @@ -0,0 +1,4 @@ +{ + "name":"documentcookie_wrapper", + "main":"index.html" +} From 972211803c89f36f438280cc2b8a0dc3fbc75b47 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 12:24:15 +0800 Subject: [PATCH 301/492] add new test case "fast_open_and_close_devtools" --- .../fast_open_and_close_devtools/index.html | 16 ++++++++++++++ .../internal/index.html | 17 +++++++++++++++ .../internal/package.json | 4 ++++ .../mocha_test.js | 21 +++++++++++++++++++ .../fast_open_and_close_devtools/package.json | 4 ++++ 5 files changed, 62 insertions(+) create mode 100644 tests/automation/fast_open_and_close_devtools/index.html create mode 100644 tests/automation/fast_open_and_close_devtools/internal/index.html create mode 100644 tests/automation/fast_open_and_close_devtools/internal/package.json create mode 100644 tests/automation/fast_open_and_close_devtools/mocha_test.js create mode 100644 tests/automation/fast_open_and_close_devtools/package.json diff --git a/tests/automation/fast_open_and_close_devtools/index.html b/tests/automation/fast_open_and_close_devtools/index.html new file mode 100644 index 0000000000..7fac4bbbd3 --- /dev/null +++ b/tests/automation/fast_open_and_close_devtools/index.html @@ -0,0 +1,16 @@ + + + + + Fast open and close devtools test + + +

                      Fast open and close devtools test

                      + + + + + + + + diff --git a/tests/automation/fast_open_and_close_devtools/internal/index.html b/tests/automation/fast_open_and_close_devtools/internal/index.html new file mode 100644 index 0000000000..8a54574ce4 --- /dev/null +++ b/tests/automation/fast_open_and_close_devtools/internal/index.html @@ -0,0 +1,17 @@ + + + + + Test Case For Fast Open&Close Devtools Crashes + + + + + diff --git a/tests/automation/fast_open_and_close_devtools/internal/package.json b/tests/automation/fast_open_and_close_devtools/internal/package.json new file mode 100644 index 0000000000..fedeac13b7 --- /dev/null +++ b/tests/automation/fast_open_and_close_devtools/internal/package.json @@ -0,0 +1,4 @@ +{ + "name": "nw", + "main": "index.html" +} diff --git a/tests/automation/fast_open_and_close_devtools/mocha_test.js b/tests/automation/fast_open_and_close_devtools/mocha_test.js new file mode 100644 index 0000000000..2b57063cea --- /dev/null +++ b/tests/automation/fast_open_and_close_devtools/mocha_test.js @@ -0,0 +1,21 @@ +var path = require('path'); +var assert = require('assert'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + +var result = false; +describe('Fast open&close devtools from #1391', function() { + before(function(done) { + this.timeout(0); + var app = spawnChildProcess(path.join(curDir, 'internal')); + app.on('exit', function(code) { + if (code != null) + result = true; + done(); + }); + }); + + it('should not crash', function() { + assert.equal(result, true); + }); +}); diff --git a/tests/automation/fast_open_and_close_devtools/package.json b/tests/automation/fast_open_and_close_devtools/package.json new file mode 100644 index 0000000000..09772c3904 --- /dev/null +++ b/tests/automation/fast_open_and_close_devtools/package.json @@ -0,0 +1,4 @@ +{ + "name":"fast_open_and_close_devtools_wrapper", + "main":"index.html" +} From 0194cf45ce8965b9adfa5f03587a26a0fa80a7ef Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 12:24:39 +0800 Subject: [PATCH 302/492] add new test case "filevalue" --- tests/automation/filevalue/index.html | 16 +++++++ .../automation/filevalue/internal/index.html | 36 ++++++++++++++++ .../filevalue/internal/package.json | 4 ++ tests/automation/filevalue/internal/testfile | 0 tests/automation/filevalue/mocha_test.js | 43 +++++++++++++++++++ tests/automation/filevalue/package.json | 4 ++ 6 files changed, 103 insertions(+) create mode 100644 tests/automation/filevalue/index.html create mode 100644 tests/automation/filevalue/internal/index.html create mode 100644 tests/automation/filevalue/internal/package.json create mode 100644 tests/automation/filevalue/internal/testfile create mode 100644 tests/automation/filevalue/mocha_test.js create mode 100644 tests/automation/filevalue/package.json diff --git a/tests/automation/filevalue/index.html b/tests/automation/filevalue/index.html new file mode 100644 index 0000000000..e6c61c7b2a --- /dev/null +++ b/tests/automation/filevalue/index.html @@ -0,0 +1,16 @@ + + + + + file value test + + +

                      File value test

                      + + + + + + + + diff --git a/tests/automation/filevalue/internal/index.html b/tests/automation/filevalue/internal/index.html new file mode 100644 index 0000000000..f13e4c01a2 --- /dev/null +++ b/tests/automation/filevalue/internal/index.html @@ -0,0 +1,36 @@ + + + + + test setting file input value + + + + + + + diff --git a/tests/automation/filevalue/internal/package.json b/tests/automation/filevalue/internal/package.json new file mode 100644 index 0000000000..602dd5d3e4 --- /dev/null +++ b/tests/automation/filevalue/internal/package.json @@ -0,0 +1,4 @@ +{ + "name":"nw-file-input-value", + "main":"index.html" +} \ No newline at end of file diff --git a/tests/automation/filevalue/internal/testfile b/tests/automation/filevalue/internal/testfile new file mode 100644 index 0000000000..e69de29bb2 diff --git a/tests/automation/filevalue/mocha_test.js b/tests/automation/filevalue/mocha_test.js new file mode 100644 index 0000000000..9994fa8aed --- /dev/null +++ b/tests/automation/filevalue/mocha_test.js @@ -0,0 +1,43 @@ + +var path = require('path'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + +describe('file input',function(){ + describe('set value',function(){ + + var server; + + before(function(done) { + server = createTCPServer(13013); + done(); + }); + + after(function () { + server.close(); + }); + + it('the value should be set without exception',function(done){ + this.timeout(0); + var child = spawnChildProcess(path.join(curDir, 'internal')); + + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + setTimeout(function() { + child.kill(); + if (data == 'mytestfile') + done(); + else + done('the value of the file input is not set correctly'); + }, 2000); + }); + }); + + }); + + }); + +}); + + diff --git a/tests/automation/filevalue/package.json b/tests/automation/filevalue/package.json new file mode 100644 index 0000000000..88c0905e3c --- /dev/null +++ b/tests/automation/filevalue/package.json @@ -0,0 +1,4 @@ +{ + "name":"filevalue_wrapper", + "main":"index.html" +} From 4fc7a4d8a816c69dc25f8438d05a11608e578c18 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 12:25:27 +0800 Subject: [PATCH 303/492] add new test case "inject-js" --- tests/automation/inject-js/index.html | 16 ++++++ tests/automation/inject-js/internal/end.js | 2 + .../automation/inject-js/internal/index.html | 19 +++++++ .../inject-js/internal/package.json | 6 +++ tests/automation/inject-js/internal/start.js | 6 +++ tests/automation/inject-js/mocha_test.js | 53 +++++++++++++++++++ tests/automation/inject-js/package.json | 4 ++ 7 files changed, 106 insertions(+) create mode 100644 tests/automation/inject-js/index.html create mode 100644 tests/automation/inject-js/internal/end.js create mode 100644 tests/automation/inject-js/internal/index.html create mode 100644 tests/automation/inject-js/internal/package.json create mode 100644 tests/automation/inject-js/internal/start.js create mode 100644 tests/automation/inject-js/mocha_test.js create mode 100644 tests/automation/inject-js/package.json diff --git a/tests/automation/inject-js/index.html b/tests/automation/inject-js/index.html new file mode 100644 index 0000000000..d2395f274d --- /dev/null +++ b/tests/automation/inject-js/index.html @@ -0,0 +1,16 @@ + + + + + Inject js test + + +

                      Inject js test

                      + + + + + + + + diff --git a/tests/automation/inject-js/internal/end.js b/tests/automation/inject-js/internal/end.js new file mode 100644 index 0000000000..613f42bcdb --- /dev/null +++ b/tests/automation/inject-js/internal/end.js @@ -0,0 +1,2 @@ +var result = result ||[]; +result.push('inject-js-end'); \ No newline at end of file diff --git a/tests/automation/inject-js/internal/index.html b/tests/automation/inject-js/internal/index.html new file mode 100644 index 0000000000..354175ced9 --- /dev/null +++ b/tests/automation/inject-js/internal/index.html @@ -0,0 +1,19 @@ + + + + + + + + + + diff --git a/tests/automation/inject-js/internal/package.json b/tests/automation/inject-js/internal/package.json new file mode 100644 index 0000000000..d36df79c46 --- /dev/null +++ b/tests/automation/inject-js/internal/package.json @@ -0,0 +1,6 @@ +{ + "name":"nw_1403514049", + "main":"index.html", + "inject-js-end":"./end.js", + "inject-js-start":"./start.js" +} \ No newline at end of file diff --git a/tests/automation/inject-js/internal/start.js b/tests/automation/inject-js/internal/start.js new file mode 100644 index 0000000000..5dd62d1045 --- /dev/null +++ b/tests/automation/inject-js/internal/start.js @@ -0,0 +1,6 @@ +var result = result ||[]; +result.push('inject-js-start'); + +window.onload = function(){ + result.push('onload') +}; \ No newline at end of file diff --git a/tests/automation/inject-js/mocha_test.js b/tests/automation/inject-js/mocha_test.js new file mode 100644 index 0000000000..951c075b2e --- /dev/null +++ b/tests/automation/inject-js/mocha_test.js @@ -0,0 +1,53 @@ +var path = require('path'); +var assert = require('assert'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + + +describe('inject-js',function(){ + + var server, child, result; + + before(function(done) { + server = createTCPServer(13013); + child = spawnChildProcess(path.join(curDir, 'internal')); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + result = JSON.parse(data); + child.kill(); + done(); + }); + }); + + }); + + after(function () { + server.close(); + }); + + + it('result.length should equal 4',function(done){ + assert.notEqual(result,null); + assert.equal(result.length,4); + done(); + }); + it('inject-js-start should run first',function(done){ + assert.equal(result[0],'inject-js-start'); + done(); + }); + it('document script should run after inject-js-start',function(done){ + assert.equal(result[1],'script-start'); + done(); + }); + it('inject-js-end should before window.onload',function(done){ + assert.equal(result[2],'inject-js-end'); + done(); + }); + it('inject-js-start should run last',function(done){ + assert.equal(result[3],'onload'); + done(); + }); +}); + + diff --git a/tests/automation/inject-js/package.json b/tests/automation/inject-js/package.json new file mode 100644 index 0000000000..2d328d1b95 --- /dev/null +++ b/tests/automation/inject-js/package.json @@ -0,0 +1,4 @@ +{ + "name":"injectjs_wrapper", + "main":"index.html" +} From 030b7ab94f380e8e3e730175549091081227318b Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 12:49:59 +0800 Subject: [PATCH 304/492] add new test case "loaded_event" --- tests/automation/loaded_event/index.html | 16 +++++++ .../loaded_event/internal/index.html | 44 +++++++++++++++++ .../loaded_event/internal/package.json | 4 ++ .../loaded_event/internal/popup.html | 12 +++++ tests/automation/loaded_event/mocha_test.js | 47 +++++++++++++++++++ tests/automation/loaded_event/package.json | 4 ++ 6 files changed, 127 insertions(+) create mode 100644 tests/automation/loaded_event/index.html create mode 100644 tests/automation/loaded_event/internal/index.html create mode 100644 tests/automation/loaded_event/internal/package.json create mode 100644 tests/automation/loaded_event/internal/popup.html create mode 100644 tests/automation/loaded_event/mocha_test.js create mode 100644 tests/automation/loaded_event/package.json diff --git a/tests/automation/loaded_event/index.html b/tests/automation/loaded_event/index.html new file mode 100644 index 0000000000..d31b76187a --- /dev/null +++ b/tests/automation/loaded_event/index.html @@ -0,0 +1,16 @@ + + + + + loaded_event test + + +

                      Loaded event test

                      + + + + + + + + diff --git a/tests/automation/loaded_event/internal/index.html b/tests/automation/loaded_event/internal/index.html new file mode 100644 index 0000000000..132bd7454e --- /dev/null +++ b/tests/automation/loaded_event/internal/index.html @@ -0,0 +1,44 @@ + + + + + + + + + + diff --git a/tests/automation/loaded_event/internal/package.json b/tests/automation/loaded_event/internal/package.json new file mode 100644 index 0000000000..7cd4843f99 --- /dev/null +++ b/tests/automation/loaded_event/internal/package.json @@ -0,0 +1,4 @@ +{ + "name": "nw-demo", + "main": "index.html" +} diff --git a/tests/automation/loaded_event/internal/popup.html b/tests/automation/loaded_event/internal/popup.html new file mode 100644 index 0000000000..c032c597e7 --- /dev/null +++ b/tests/automation/loaded_event/internal/popup.html @@ -0,0 +1,12 @@ + + + + + + + + + \ No newline at end of file diff --git a/tests/automation/loaded_event/mocha_test.js b/tests/automation/loaded_event/mocha_test.js new file mode 100644 index 0000000000..571fa4c71d --- /dev/null +++ b/tests/automation/loaded_event/mocha_test.js @@ -0,0 +1,47 @@ +var path = require('path'); +var assert = require('assert'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + +describe('loaded event', function() { + + var server, child, result = false; + + before(function(done) { + server = createTCPServer(13013); + done(); + }); + + after(function () { + server.close(); + }); + + it('loaded event can been fired', + function(done) { + this.timeout(0); + + child = spawnChildProcess(path.join(curDir, 'internal')); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + result = true; + child.kill(); + done(); + }); + }); + + setTimeout(function(){ + if (!result) { + child.close(); + //child.app.kill(); + //child.removeConnection(); + done('loaded evenet does not been fired'); + } + }, 3000); + //child.app.stderr.on('data', function(d){ console.log ('app' + d);}); + + }) + + +}) + diff --git a/tests/automation/loaded_event/package.json b/tests/automation/loaded_event/package.json new file mode 100644 index 0000000000..beccf58ec0 --- /dev/null +++ b/tests/automation/loaded_event/package.json @@ -0,0 +1,4 @@ +{ + "name":"loaded_event_wrapper", + "main":"index.html" +} From be2731076ed8b3f679090d1dca087ba03ea0baeb Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 12:50:39 +0800 Subject: [PATCH 305/492] add new test case "menu" --- tests/automation/menu/index.html | 16 ++++++ tests/automation/menu/mocha_test.js | 83 +++++++++++++++++++++++++++++ tests/automation/menu/package.json | 4 ++ 3 files changed, 103 insertions(+) create mode 100644 tests/automation/menu/index.html create mode 100644 tests/automation/menu/mocha_test.js create mode 100644 tests/automation/menu/package.json diff --git a/tests/automation/menu/index.html b/tests/automation/menu/index.html new file mode 100644 index 0000000000..121999a48b --- /dev/null +++ b/tests/automation/menu/index.html @@ -0,0 +1,16 @@ + + + + + Menu test + + +

                      Menu test

                      + + + + + + + + diff --git a/tests/automation/menu/mocha_test.js b/tests/automation/menu/mocha_test.js new file mode 100644 index 0000000000..780846e5ad --- /dev/null +++ b/tests/automation/menu/mocha_test.js @@ -0,0 +1,83 @@ +var gui = require('nw.gui'); +var assert = require('assert'); + + +describe('Menu', function(){ + + describe('#append()', function(){ + it('should append a value', function(){ + var menu = new gui.Menu(); + menu.append(new gui.MenuItem({ label:'Item 1'})); + assert.equal(menu.items[0].label, 'Item 1'); + }) + + }) + + describe('#.length', function(){ + it('should return correct value', function(){ + var menu = new gui.Menu(); + menu.append(new gui.MenuItem({label : 'Item 1'})); + menu.append(new gui.MenuItem({label : 'Item 2'})); + assert.equal(menu.items.length, 2); + }) + }) + + describe('#insert()', function(){ + var menu = new gui.Menu(); + + it('should adject .length', function(){ + menu.append(new gui.MenuItem({label : 'Item 1'})); + menu.append(new gui.MenuItem({label : 'Item 2'})); + menu.insert(new gui.MenuItem({label : 'Item 0'}), 1); + assert.equal(menu.items.length, 3); + }) + + it('new value should be added in', function(){ + assert.equal(menu.items[1].label, 'Item 0'); + }) + + it('the origin value', function(){ + assert.equal(menu.items[2].label, 'Item 2'); + }) + }) + + describe('#removeAt()', function(){ + var menu = new gui.Menu(); + it('should adject .length', function(){ + menu.append(new gui.MenuItem({label : 'Item 0'})); + menu.append(new gui.MenuItem({label : 'Item 1'})); + menu.append(new gui.MenuItem({label : 'Item 2'})); + menu.removeAt(1); + assert.equal(menu.items.length, 2); + }); + + it('the next value', function(){ + assert.equal(menu.items[1].label, 'Item 2'); + }) + }) + + describe('#remove()', function(){ + var menu = new gui.Menu(); + menu.append(new gui.MenuItem({label : 'Item 0'})); + menu.append(new gui.MenuItem({label : 'Item 1'})); + var removedItem = new gui.MenuItem({label : 'Item Deleted'}); + menu.insert(removedItem, 1); + it('before delete', function(){ + assert.equal(menu.items.length, 3); + assert.equal(menu.items[1].label, 'Item Deleted'); + }) + + it('after delete', function(){ + menu.remove(removedItem); + assert.equal(menu.items.length, 2); + assert.equal(menu.items[1].label, 'Item 1'); + + }) + }) + + describe('#popup(), not implentment',function(){ + }) + +}) + + diff --git a/tests/automation/menu/package.json b/tests/automation/menu/package.json new file mode 100644 index 0000000000..899ddeef90 --- /dev/null +++ b/tests/automation/menu/package.json @@ -0,0 +1,4 @@ +{ + "name":"Menu_wrapper", + "main":"index.html" +} From 057b1cb32b04c68bc015103d9deb2d13b6866778 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 12:51:15 +0800 Subject: [PATCH 306/492] add new test case "menu_item" --- tests/automation/menu_item/icon1.png | Bin 0 -> 983 bytes tests/automation/menu_item/index.html | 16 +++ tests/automation/menu_item/mocha_test.js | 148 +++++++++++++++++++++++ tests/automation/menu_item/package.json | 4 + 4 files changed, 168 insertions(+) create mode 100644 tests/automation/menu_item/icon1.png create mode 100644 tests/automation/menu_item/index.html create mode 100644 tests/automation/menu_item/mocha_test.js create mode 100644 tests/automation/menu_item/package.json diff --git a/tests/automation/menu_item/icon1.png b/tests/automation/menu_item/icon1.png new file mode 100644 index 0000000000000000000000000000000000000000..010fc2dd2b32c0095d734c9072214337800b3af7 GIT binary patch literal 983 zcmV;|11S87P)G2Zo-)>>rTiMdzB}?^9G=2zEc&BEfcomM3paOhlJfU?Czk(v(AMQaN-+ zKu?3KazbY?pj@kkTq#HJ_q_Ln%JG^0*n?aNh}213kH-hbLRVpA&h=TBUlankmn<+SwIj>R4no2-Yie#Mq=FC^T6iCE=MQ0N^HUe3sb5biwaRL%R z+d)tJ>Y!@ta}E*4s(5Z!u_q<*Gpy8DfjeTOE(p(@{=1CK*RPASWPR+WQ?0&0x` z=?VwV88Ccmaqu~De4M9 + + + + Menu item test + + +

                      Menu item test

                      + + + + + + + + diff --git a/tests/automation/menu_item/mocha_test.js b/tests/automation/menu_item/mocha_test.js new file mode 100644 index 0000000000..fcac27477d --- /dev/null +++ b/tests/automation/menu_item/mocha_test.js @@ -0,0 +1,148 @@ +var gui = require('nw.gui'); +var assert = require('assert'); + +describe('MenuItem', function(){ + var menu; + beforeEach(function(){ + menu = new gui.Menu(); + }) + + describe('.type', function(){ + + it('should be separator', function(){ + menu.append(new gui.MenuItem({ label : 'Item 1', type : 'separator' })); + assert.equal(menu.items.length, 1); + assert.equal(menu.items[0].type, 'separator'); + }) + + it('should be normal', function(){ + menu.append(new gui.MenuItem({ label : 'Item 1' })); + assert.equal(menu.items.length, 1); + assert.equal(menu.items[0].type, 'normal'); + }) + + it('should be checkbox', function(){ + menu.append(new gui.MenuItem({ label : 'Item 1', type : 'checkbox' })); + assert.equal(menu.items.length, 1); + assert.equal(menu.items[0].type, 'checkbox'); + }) + + }) + + describe('.label', function(){ + it('set label', function(){ + menu.append(new gui.MenuItem({ label : 'Item 1'})); + assert.equal(menu.items.length, 1); + assert.equal(menu.items[0].label, 'Item 1'); + + }) + + it('after change',function(){ + menu.append(new gui.MenuItem({ label : 'Item 1'})); + assert.equal(menu.items.length, 1); + menu.items[0].label = 'Item Mama'; + assert.equal(menu.items[0].label, 'Item Mama'); + }) + + }) + + describe('.icon', function(){ + it('set menu icon', function(){ + menu.append(new gui.MenuItem({ label : 'Item icon' })); + assert.equal(menu.items.length, 1); + menu.items[0].icon = 'icon1.png'; + assert.equal(menu.items[0].icon, 'icon1.png'); + + }) + + it('clear menu icon', function(){ + menu.append(new gui.MenuItem({ label : 'Item icon' })); + menu.items[0].icon = 'icon1.png'; + menu.items[0].icon = ''; + assert.equal(menu.items[0].icon, ''); + }) + }) + + describe('.tooltip', function(){ + it('set tooltip', function(){ + menu.append(new gui.MenuItem({ label : 'Item 0', tooltip : 'tooltip' })); + assert.equal(menu.items[0].tooltip, 'tooltip'); + }) + + it('change tooltip', function(){ + menu.append(new gui.MenuItem({ label : 'Item 0', tooltip : 'tooltip' })); + menu.items[0].tooltip = ''; + assert.equal(menu.items[0].tooltip, ''); + }) + }) + + + describe('.checked', function(){ + it('set enabled', function(){ + menu.append(new gui.MenuItem({ type : 'checkbox', label : 'Item 0', checked : true })); + assert.equal(menu.items[0].checked, true); + }) + + it('change checked', function(){ + menu.append(new gui.MenuItem({ type : 'checkbox', label : 'Item 0', checked: true })); + menu.items[0].checked = false; + assert.equal(menu.items[0].checked, false); + + }) + }) + + + describe('.enabled', function(){ + it('set enabled', function(){ + menu.append(new gui.MenuItem({ type : 'checkbox', label : 'Item 0', enabled : true })); + assert.equal(menu.items[0].enabled, true); + }) + + it('change enabled', function(){ + menu.append(new gui.MenuItem({ type : 'checkbox', label : 'Item 0', enabled : true })); + menu.items[0].enabled = false; + assert.equal(menu.items[0].enabled, false); + + }) + }) + + describe('.submenu', function(){ + it('set submenu', function(){ + var submenu = new gui.Menu(); + submenu.append(new gui.MenuItem({ type: 'checkbox', label: 'Sub 1', checked: true, enabled: false })); + submenu.append(new gui.MenuItem({ type: 'checkbox', label: 'Sub 2', checked: true, enabled: false })); + submenu.append(new gui.MenuItem({ type: 'checkbox', label: 'Sub 3', checked: true, enabled: false })); + submenu.append(new gui.MenuItem({ type: 'checkbox', label: 'Sub 4', checked: true, enabled: false })); + menu.append(new gui.MenuItem({ label: 'I have submenu', submenu: submenu })); + + assert.equal(menu.items.length, 1); + assert.equal(menu.items[0].label, 'I have submenu'); + assert.equal(menu.items[0].submenu, submenu); + assert.equal(submenu.items.length, 4); + }) + }) + + describe('#click()', function(){ + + var menu_item = new gui.MenuItem({label : 'item 1'}); + + + it('before click',function(){ + assert.equal(menu_item.label, 'item 1'); + }) + + it('after click',function(done){ + menu_item.on('click', function(){ + menu_item.label = '2'; + assert.equal(menu_item.label, '2'); + done(); + }) + menu_item.emit('click'); + + }) + + + + }) + +}) diff --git a/tests/automation/menu_item/package.json b/tests/automation/menu_item/package.json new file mode 100644 index 0000000000..b4e9a364b2 --- /dev/null +++ b/tests/automation/menu_item/package.json @@ -0,0 +1,4 @@ +{ + "name":"Menu_item_wrapper", + "main":"index.html" +} From 0250217161528b2a105650e03a410d564875ff48 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 12:51:48 +0800 Subject: [PATCH 307/492] add new test case "new-instance" --- tests/automation/new-instance/index.html | 16 ++++++ .../new-instance/internal/index.html | 33 ++++++++++++ .../new-instance/internal/package.json | 4 ++ .../new-instance/internal/popup.html | 21 ++++++++ tests/automation/new-instance/mocha_test.js | 51 +++++++++++++++++++ tests/automation/new-instance/package.json | 4 ++ 6 files changed, 129 insertions(+) create mode 100644 tests/automation/new-instance/index.html create mode 100644 tests/automation/new-instance/internal/index.html create mode 100644 tests/automation/new-instance/internal/package.json create mode 100644 tests/automation/new-instance/internal/popup.html create mode 100644 tests/automation/new-instance/mocha_test.js create mode 100644 tests/automation/new-instance/package.json diff --git a/tests/automation/new-instance/index.html b/tests/automation/new-instance/index.html new file mode 100644 index 0000000000..a3fe74b68f --- /dev/null +++ b/tests/automation/new-instance/index.html @@ -0,0 +1,16 @@ + + + + + New Instance test + + +

                      New Instance test

                      + + + + + + + + diff --git a/tests/automation/new-instance/internal/index.html b/tests/automation/new-instance/internal/index.html new file mode 100644 index 0000000000..6ee8e7dec4 --- /dev/null +++ b/tests/automation/new-instance/internal/index.html @@ -0,0 +1,33 @@ + + + + +The pid of main page is: + +
                      +The pid of new-instance page is: + + + + + + diff --git a/tests/automation/new-instance/internal/package.json b/tests/automation/new-instance/internal/package.json new file mode 100644 index 0000000000..7cd4843f99 --- /dev/null +++ b/tests/automation/new-instance/internal/package.json @@ -0,0 +1,4 @@ +{ + "name": "nw-demo", + "main": "index.html" +} diff --git a/tests/automation/new-instance/internal/popup.html b/tests/automation/new-instance/internal/popup.html new file mode 100644 index 0000000000..b76e8af321 --- /dev/null +++ b/tests/automation/new-instance/internal/popup.html @@ -0,0 +1,21 @@ + + + + +The pid of page is: + + + + + + diff --git a/tests/automation/new-instance/mocha_test.js b/tests/automation/new-instance/mocha_test.js new file mode 100644 index 0000000000..efc6a1783f --- /dev/null +++ b/tests/automation/new-instance/mocha_test.js @@ -0,0 +1,51 @@ +var path = require('path'); +var assert = require('assert'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + +describe('new-instance', function() { + var server, child, result = false; + + before(function(done) { + server = createTCPServer(13013); + done(); + }); + + after(function () { + server.close(); + }); + + it('new window has different pid', function(done) { + this.timeout(0); + var result = false; + var times = 0; + var pid1, pid2; + + child = spawnChildProcess(path.join(curDir, 'internal')); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + if (times == 0) { + pid1 = data; + times += 1; + } else { + pid2 = data; + + if (pid1 != pid2) { + done(); + } else { + done('they are in the same process'); + } + child.kill(); + } + + }); + }); + + + }); + + +}); + + diff --git a/tests/automation/new-instance/package.json b/tests/automation/new-instance/package.json new file mode 100644 index 0000000000..da9799222d --- /dev/null +++ b/tests/automation/new-instance/package.json @@ -0,0 +1,4 @@ +{ + "name":"New_instance_wrapper", + "main":"index.html" +} From 20b19a45bf04fbc7965e58deeb7e9240258cd751 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 13:39:41 +0800 Subject: [PATCH 308/492] add new test case "node-main" --- tests/automation/node-main/index.html | 16 ++++ tests/automation/node-main/mocha_test.js | 98 ++++++++++++++++++++++++ tests/automation/node-main/package.json | 4 + 3 files changed, 118 insertions(+) create mode 100644 tests/automation/node-main/index.html create mode 100644 tests/automation/node-main/mocha_test.js create mode 100644 tests/automation/node-main/package.json diff --git a/tests/automation/node-main/index.html b/tests/automation/node-main/index.html new file mode 100644 index 0000000000..8b479f5b7d --- /dev/null +++ b/tests/automation/node-main/index.html @@ -0,0 +1,16 @@ + + + + + node main test + + +

                      Node main test

                      + + + + + + + + diff --git a/tests/automation/node-main/mocha_test.js b/tests/automation/node-main/mocha_test.js new file mode 100644 index 0000000000..befaedcf6e --- /dev/null +++ b/tests/automation/node-main/mocha_test.js @@ -0,0 +1,98 @@ +var path = require('path'); +var assert = require('assert'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + +describe('node-main', function() { + + var server; + + before(function(done) { + server = createTCPServer(13013); + done(); + }); + + after(function () { + server.close(); + }); + + describe('create http server in node-main', function() { + it('nw should not close by itself after show devtool', + function(done) { + this.timeout(0); + var result = false; + + var child = spawnChildProcess(path.join(curDir, '..', 'show_devtool_after_http_server_created_in_node_main')); + + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + result = JSON.parse(data); + child.kill(); + if (result.success) done(); + else done('error'); + result = true; + server.removeAllListeners('connection'); + }); + }); + + + setTimeout(function(){ + if (!result) { + done('nw close by itself') + } + }, 3000); + //child.app.stderr.on('data', function(d){ console.log ('app' + d);}); + + }); + }); + + + + describe('call require() in app', function() { + it('nw should can require modules', function(done){ + this.timeout(0); + var result = false; + var child = spawnChildProcess(path.join(curDir, '..', 'call_require_with_node-main_set')); + + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + result = JSON.parse(data); + child.kill(); + if (result.ok) done(); + else done('error:'+result.error); + result = true; + server.removeAllListeners('connection'); + }); + }); + + }); + }); + + describe('reference node-main module',function(){ + it('nw should be able to reference node-main module',function(done){ + this.timeout(0); + + var result = false; + var child = spawnChildProcess(path.join(curDir, '..', 'reference-node-main')); + + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + result = JSON.parse(data); + child.kill(); + assert.equal(result,true); + done(); + server.removeAllListeners('connection'); + }); + }); + + }); + }); + + + +}); + + diff --git a/tests/automation/node-main/package.json b/tests/automation/node-main/package.json new file mode 100644 index 0000000000..918bb25bc8 --- /dev/null +++ b/tests/automation/node-main/package.json @@ -0,0 +1,4 @@ +{ + "name":"Node_main_wrapper", + "main":"index.html" +} From aaf5000b154971c81bf38c14ac82c0636aa6ffb6 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 13:50:57 +0800 Subject: [PATCH 309/492] add new test case "node-remote" --- tests/automation/node-remote/index.html | 93 ++++++++++++++++++++++ tests/automation/node-remote/mocha_test.js | 70 ++++++++++++++++ tests/automation/node-remote/package.json | 8 ++ 3 files changed, 171 insertions(+) create mode 100644 tests/automation/node-remote/index.html create mode 100644 tests/automation/node-remote/mocha_test.js create mode 100644 tests/automation/node-remote/package.json diff --git a/tests/automation/node-remote/index.html b/tests/automation/node-remote/index.html new file mode 100644 index 0000000000..4ec84c0284 --- /dev/null +++ b/tests/automation/node-remote/index.html @@ -0,0 +1,93 @@ + + + + + + + +
                      + Can remote page + http://127.0.0.1:8123/node_remote_test.html + call Node: + +
                      + +
                      + Can remote page + http://127.0.0.1:8124/node_remote_test.html + call Node: + +
                      + + + diff --git a/tests/automation/node-remote/mocha_test.js b/tests/automation/node-remote/mocha_test.js new file mode 100644 index 0000000000..737c129899 --- /dev/null +++ b/tests/automation/node-remote/mocha_test.js @@ -0,0 +1,70 @@ +var spawn = require('child_process').spawn; +var path = require('path'); +var net = require('net'); +var server = global.server; +var cb; + +describe('node-remote', function() { + describe('enable remote site http://127.0.0.1:8123/', function() { + var app; + var exec_argv; + var socket; + before(function(done) { + //this.timeout(0); + exec_argv = [path.join(global.tests_dir, 'node-remote'), + '--port', + global.port]; + + if (global.auto) exec_argv.push('--auto'); + + server.on('connection', cb = function(s){ + socket = s; + s.setEncoding('utf8'); + done(); + socket.on('error', function(e) { + console.log(e); + }); + }); + app = spawn(process.execPath, exec_argv); + }) + + after(function(done) { + this.timeout(0); + app.kill(); + server.removeListener('connection', cb); + done(); + }) + + afterEach(function(){ + socket.removeAllListeners('data'); + }) + + it('http://127.0.0.1:8123/node_remote_test.html should be able call Node', + function(done) { + this.timeout(0); + socket.on('data', function(data) { + if (data == 'ok'){ + done(); + } else { + done(data); + } + + }); + socket.write('8123'); + }) + + it('http://127.0.0.1:8124/node_remote_test.html should not be able call Node', + function(done) { + this.timeout(0); + socket.on('data', function(data) { + if (data == 'ok'){ + done('should not call node'); + } else { + done(); + } + + }); + socket.write('8124'); + }) + }) +}) diff --git a/tests/automation/node-remote/package.json b/tests/automation/node-remote/package.json new file mode 100644 index 0000000000..e79fa87ac3 --- /dev/null +++ b/tests/automation/node-remote/package.json @@ -0,0 +1,8 @@ +{ + "name": "nw-demo", + "main": "index.html", + "user-agent": "%name-a-b", + "node-remote": "127.0.0.1:8123", + "version": "1.0", + "window": { "show" : false } +} From d4d3b194ed712c12be1bd12657d5b899e615fe5e Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 13:51:33 +0800 Subject: [PATCH 310/492] add new test caset "node" --- tests/automation/node/index.html | 16 ++ tests/automation/node/message_channel_test.js | 7 + tests/automation/node/mocha_test.js | 249 ++++++++++++++++++ tests/automation/node/module1.js | 3 + tests/automation/node/package.json | 4 + tests/automation/node/test.tar | Bin 0 -> 2048 bytes 6 files changed, 279 insertions(+) create mode 100644 tests/automation/node/index.html create mode 100644 tests/automation/node/message_channel_test.js create mode 100644 tests/automation/node/mocha_test.js create mode 100644 tests/automation/node/module1.js create mode 100644 tests/automation/node/package.json create mode 100644 tests/automation/node/test.tar diff --git a/tests/automation/node/index.html b/tests/automation/node/index.html new file mode 100644 index 0000000000..a454c5e92f --- /dev/null +++ b/tests/automation/node/index.html @@ -0,0 +1,16 @@ + + + + + node test + + +

                      Node test

                      + + + + + + + + diff --git a/tests/automation/node/message_channel_test.js b/tests/automation/node/message_channel_test.js new file mode 100644 index 0000000000..2aac0a92a1 --- /dev/null +++ b/tests/automation/node/message_channel_test.js @@ -0,0 +1,7 @@ +exports.run = function(done) { + var mc = new window.MessageChannel() + mc.port1.onmessage = function(m) { + done(); + } + mc.port2.postMessage("HELLO"); +} diff --git a/tests/automation/node/mocha_test.js b/tests/automation/node/mocha_test.js new file mode 100644 index 0000000000..d9d8034d12 --- /dev/null +++ b/tests/automation/node/mocha_test.js @@ -0,0 +1,249 @@ +var path = require('path'); +var assert = require('assert'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + + +/// 1 +describe('require', function() { + describe('type', function() { + it('is function', function() { + assert.equal(typeof global.require, 'function'); + }); + }); + + describe('members', function() { + it('have resolve', function() { + assert.equal(typeof global.require.resolve, 'function'); + }); + + it('have main', function() { + assert.equal(typeof global.require.main, 'object'); + }); + + it('have extensions', function() { + assert.equal(typeof global.require.extensions, 'object'); + }); + + it('have registerExtension', function() { + assert.equal(typeof global.require.registerExtension, 'function'); + }); + + it('have cache', function() { + assert.equal(typeof global.require.cache, 'object'); + }); + }); +}); + +////////////////// 2 +/* +describe('node', function() { + + var mocha_callback = null; + before(function() { + mocha_callback = process.listeners('uncaughtException')[1]; + process.removeListener('uncaughtException', mocha_callback); + }); + after(function(){ + process.on('uncaughtException',mocha_callback); + }) + + describe('process', function() { + it('uncaughtException should have a default listener', function() { + assert.equal(process.listeners('uncaughtException').length, 1); + }); + + it('throwing uncaughtException should not show error page when having listener', function(done) { + var empty = function(e) { + process.removeListener('uncaughtException', empty); + done(); + }; + process.on('uncaughtException', empty); + process.nextTick(function() { + throw new String('If you see this then uncaughtException test failed'); + }); + }); + }); +}); +*/ +////////////// 3 + +describe('module', function() { + describe('javascript modules', function() { + var path = require('path'); + + it('require by path', function() { + var module1_path = path.join(curDir, 'module1.js'); + assert.equal(require(module1_path).test(), 'module1'); + }); + + it('simple file module', function() { + var module3_path = path.join(curDir, 'node_modules', 'module3'); + assert.equal(require(module3_path).test(), 'module3'); + }); + + it('space in path', function() { + var module4_path = path.join(curDir, 'node_modules', 'module4 space'); + assert.equal(require(module4_path).test(), 'module4'); + }); + }); + + describe('built-in modules', function() { + var fs = require('fs'); + var http = require('http'); + var path = require('path'); + var exec = require('child_process').exec; + + it('execute child process', function(done) { + var child = exec('echo echo back', function (error, stdout, stderr) { + assert.equal(error, null); + assert.equal(stdout, process.platform == 'win32' ? 'echo back\r\n' : 'echo back\n'); + assert.equal(stderr, ''); + done(); + }); + }); + + it('Buffer', function() { + assert.equal(String(Buffer('test')), 'test'); + }); +/* + it('http server and client', function(done) { + var server = http.createServer(function (req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('hello'); + }).listen(10086); + process.nextTick(function() { + var count = 0; + for (var i = 0; i < 5; ++i) { + http.get("http://127.0.0.1:10086", function(res) { + var data = ''; + res.on('end', function(e) { + if (data == 'hello') + ++count; + }).on('data', function(chunk) { + data += chunk; + }); + }).on('error', function() { + assert.equal(true, false); + }); + } + setTimeout(function() { + assert.equal(count, 5); + server.close(); + done(); + }, 50); + }); + }); +*/ + }); + +/* + describe('native modules (long-to-run)', function() { + it('bignum should work on posix environment', function() { + if (process.platform != 'win32') { + var bignum = require('./node_modules/bignum'); + assert.equal(bignum('782910138827292261791972728324982').sub('182373273283402171237474774728373').div(8), '75067108192986261319312244199576'); + } + }); + + it('native modules without handle scope', function() { + require('./node_modules/nw_test_loop_without_handle'); + }); + + it('native modules should work', function() { + var nativeModules = new Array("dtrace-provider", "ref", "lame"); + for (var i = 0; i < nativeModules.length; i++) + assert.equal((typeof require(nativeModules[i])), "object"); + }); + }); +*/ + +}); + +////////////////////// 4 + +describe('performance', function() { + describe('timers', function() { + it('setTimeout in webkit and node.js should be accurate', function(done) { + var flag1, flag2; + global.setTimeout(function() { flag1 = true; }, 10); + window.setTimeout(function() { flag2 = true; }, 10); + + setTimeout(function() { + assert.equal(flag1, true); + assert.equal(flag2, true); + done(); + }, 50); + }); + + it('setInterval int webkit and node.js should be accurate', function(done) { + var count1 = 0; + var count2 = 0;; + global.setInterval(function() { ++count1; }, 10); + window.setInterval(function() { ++count2; }, 10); + + setTimeout(function() { + assert.equal(count1 > 3, true); + assert.equal(count2 > 3, true); + done(); + }, 50); + }); + }); + + describe('IO', function() { + var fs = require('fs'); + var path = require('path'); + var exec = require('child_process').exec; + var tar = require('tar'); + + it('file reading should be quick even when we have a child process running', function(done) { + this.timeout(100); + exec('sleep 1000', function () { }); + var mochaPath = path.join(curDir, 'mocha_test.js'); + fs.readFile(mochaPath, 'utf8', function(err, data) { + done(); + }); + }); + + it('untar a file should be quick', function(done) { + this.timeout(100); + var testPath = path.join(curDir, 'test.tar'); + fs.createReadStream(testPath) + .pipe(tar.Extract({ path: 'ddtmp' })) + .on('error', function (er) { + assert.equal(false, true); + }) + .on('end', function () { + var content = fs.readFileSync('ddtmp/text', 'utf8'); + assert.equal(content, 'I love luyao\n'); + fs.unlinkSync('ddtmp/text'); + fs.rmdirSync('ddtmp'); + done(); + }); + }); + }); +}); + +///////////////////////////// 5 + +describe('browser', function() { + describe('security', function() { + it('cross domain call in file:// should succeed', function(done) { + window.$.get('http://baidu.com', function(data, status) { + assert.equal(status, 'success'); + assert.notEqual(data, null); + done(); + }); + }); + }); + + describe('render crashes', function() { + it('MessageChannel should not crash', function(done) { + var testPath = path.join(curDir, 'message_channel_test'); + var test = require(testPath); + test.run(done); // force to run in node context. + }); + }); +}); + + diff --git a/tests/automation/node/module1.js b/tests/automation/node/module1.js new file mode 100644 index 0000000000..fe1099f65c --- /dev/null +++ b/tests/automation/node/module1.js @@ -0,0 +1,3 @@ +exports.test = function() { + return "module1"; +} diff --git a/tests/automation/node/package.json b/tests/automation/node/package.json new file mode 100644 index 0000000000..9244205ca5 --- /dev/null +++ b/tests/automation/node/package.json @@ -0,0 +1,4 @@ +{ + "name":"Node_wrapper", + "main":"index.html" +} diff --git a/tests/automation/node/test.tar b/tests/automation/node/test.tar new file mode 100644 index 0000000000000000000000000000000000000000..e087c9cff2854334314b3e0eb0dbd7aee6bc95f4 GIT binary patch literal 2048 zcmXR(tterjF)%PNFf%bxU;xtQW~N};zzD(z3ITzkse+-Afr**9p}Db^#m8GTOmIiqa2q2yV(L)4yD&*vsr7Gl Date: Mon, 1 Dec 2014 13:52:30 +0800 Subject: [PATCH 311/492] add new test case "nwfaketop" --- tests/automation/nwfaketop/index.html | 16 ++++++ .../automation/nwfaketop/internal/index.html | 49 +++++++++++++++++++ .../nwfaketop/internal/package.json | 11 +++++ tests/automation/nwfaketop/mocha_test.js | 44 +++++++++++++++++ tests/automation/nwfaketop/package.json | 4 ++ 5 files changed, 124 insertions(+) create mode 100644 tests/automation/nwfaketop/index.html create mode 100644 tests/automation/nwfaketop/internal/index.html create mode 100644 tests/automation/nwfaketop/internal/package.json create mode 100644 tests/automation/nwfaketop/mocha_test.js create mode 100644 tests/automation/nwfaketop/package.json diff --git a/tests/automation/nwfaketop/index.html b/tests/automation/nwfaketop/index.html new file mode 100644 index 0000000000..4467ca12fb --- /dev/null +++ b/tests/automation/nwfaketop/index.html @@ -0,0 +1,16 @@ + + + + + nwfaketop test + + +

                      nw fake top test

                      + + + + + + + + diff --git a/tests/automation/nwfaketop/internal/index.html b/tests/automation/nwfaketop/internal/index.html new file mode 100644 index 0000000000..314bf5f9e2 --- /dev/null +++ b/tests/automation/nwfaketop/internal/index.html @@ -0,0 +1,49 @@ + + + + + test + + + + + + + + diff --git a/tests/automation/nwfaketop/internal/package.json b/tests/automation/nwfaketop/internal/package.json new file mode 100644 index 0000000000..b2bc1566ae --- /dev/null +++ b/tests/automation/nwfaketop/internal/package.json @@ -0,0 +1,11 @@ +{ + "name": "nwfaketop", + "main": "index.html", + "window": { + "width": 600, + "height": 400, + "position": "center", + "toolbar": true, + "resizable": true + } +} \ No newline at end of file diff --git a/tests/automation/nwfaketop/mocha_test.js b/tests/automation/nwfaketop/mocha_test.js new file mode 100644 index 0000000000..fb32f30701 --- /dev/null +++ b/tests/automation/nwfaketop/mocha_test.js @@ -0,0 +1,44 @@ +var path = require('path'); +var assert = require('assert'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + + +describe('nwfaketop',function(){ + + var child, server, result; + + before(function(done){ + this.timeout(0); + server = createTCPServer(13013); + child = spawnChildProcess(path.join(curDir, 'internal')); + + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + result = JSON.parse(data+''); + done(); + }); + }); + + }); + + after(function(done){ + server.close(); + child.kill(); + done(); + }); + + it("nwfaketop attribute set",function(done){ + assert(result[0],true); + done(); + }); + it("nwfaketop attribute default",function(done){ + assert(result[1],true); + done(); + }); + + +}); + + diff --git a/tests/automation/nwfaketop/package.json b/tests/automation/nwfaketop/package.json new file mode 100644 index 0000000000..0877473e9c --- /dev/null +++ b/tests/automation/nwfaketop/package.json @@ -0,0 +1,4 @@ +{ + "name":"nwfaketop_wrapper", + "main":"index.html" +} From 3c20248d0f2c72e300e91f87ffb8465611523e0b Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 13:53:12 +0800 Subject: [PATCH 312/492] add new test case "reference-node-main" --- .../automation/reference-node-main/index.html | 53 +++++++++++++++++++ tests/automation/reference-node-main/index.js | 24 +++++++++ .../reference-node-main/package.json | 6 +++ 3 files changed, 83 insertions(+) create mode 100644 tests/automation/reference-node-main/index.html create mode 100644 tests/automation/reference-node-main/index.js create mode 100644 tests/automation/reference-node-main/package.json diff --git a/tests/automation/reference-node-main/index.html b/tests/automation/reference-node-main/index.html new file mode 100644 index 0000000000..e8fedb870d --- /dev/null +++ b/tests/automation/reference-node-main/index.html @@ -0,0 +1,53 @@ + + + + + test + + + + + + diff --git a/tests/automation/reference-node-main/index.js b/tests/automation/reference-node-main/index.js new file mode 100644 index 0000000000..04b94f07a4 --- /dev/null +++ b/tests/automation/reference-node-main/index.js @@ -0,0 +1,24 @@ +exports.message = "hello world"; +exports.port = 10000; +exports.ready = false; + +var server = require('net').createServer(); +server.on('connection',function(socket){ + socket.on('data',function(data){ + socket.write(data); + }); +}); + +server.on('error',function(){ + try{ + server.close(); + }catch(e){ + exports.port += 1; + setTimeout(function(){ + server.listen(exports.port); + },0); + } +}); +server.listen(exports.port,function(){ + exports.ready = true; +}); diff --git a/tests/automation/reference-node-main/package.json b/tests/automation/reference-node-main/package.json new file mode 100644 index 0000000000..486c567b08 --- /dev/null +++ b/tests/automation/reference-node-main/package.json @@ -0,0 +1,6 @@ +{ + "name":"nw_1403596464", + "main":"index.html", + "dependencies":{}, + "node-main":"./index.js" +} \ No newline at end of file From 175219af7e15a966529a0c7ed12d88ecc818aa4e Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 13:53:55 +0800 Subject: [PATCH 313/492] add new test case "show_devtool_after_http_server_created_in_node_main" --- .../index.html | 49 +++++++++++++++++++ .../main.js | 7 +++ .../package.json | 14 ++++++ 3 files changed, 70 insertions(+) create mode 100644 tests/automation/show_devtool_after_http_server_created_in_node_main/index.html create mode 100644 tests/automation/show_devtool_after_http_server_created_in_node_main/main.js create mode 100644 tests/automation/show_devtool_after_http_server_created_in_node_main/package.json diff --git a/tests/automation/show_devtool_after_http_server_created_in_node_main/index.html b/tests/automation/show_devtool_after_http_server_created_in_node_main/index.html new file mode 100644 index 0000000000..46a598e9c2 --- /dev/null +++ b/tests/automation/show_devtool_after_http_server_created_in_node_main/index.html @@ -0,0 +1,49 @@ + + + + + +

                      nw rocks !

                      +

                      after launch devtool, nw should not close by itself.

                      + + + + diff --git a/tests/automation/show_devtool_after_http_server_created_in_node_main/main.js b/tests/automation/show_devtool_after_http_server_created_in_node_main/main.js new file mode 100644 index 0000000000..ce28ff5e7a --- /dev/null +++ b/tests/automation/show_devtool_after_http_server_created_in_node_main/main.js @@ -0,0 +1,7 @@ +var http = require('http'); +http.createServer(function (req, res) { + res.writeHead(200, {'Content-Type': 'text/plain'}); + res.end('Hello World\n'); +}).listen(11337, '127.0.0.1'); + +console.log('Server running at http://127.0.0.1:1337/'); diff --git a/tests/automation/show_devtool_after_http_server_created_in_node_main/package.json b/tests/automation/show_devtool_after_http_server_created_in_node_main/package.json new file mode 100644 index 0000000000..d88d875b8e --- /dev/null +++ b/tests/automation/show_devtool_after_http_server_created_in_node_main/package.json @@ -0,0 +1,14 @@ +{ + "name": "server", + "description": "server", + "version": "0.1", + "nodejs":true, + "node-main": "main.js", + "main": "index.html", + "window": { + "show": true, + "toolbar": true, + "fullscreen":false + + } +} From 8b3084591e5941a5805703787647568e8a84cd00 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 13:54:57 +0800 Subject: [PATCH 314/492] fix minor bug about call_require_with_node-main_set --- .../call_require_with_node-main_set/index.html | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/tests/automation/call_require_with_node-main_set/index.html b/tests/automation/call_require_with_node-main_set/index.html index f14bb34f99..e8b05ac607 100644 --- a/tests/automation/call_require_with_node-main_set/index.html +++ b/tests/automation/call_require_with_node-main_set/index.html @@ -4,7 +4,7 @@

                      Test require()

                      - + From 6ec2f4681888de1999a26149c02fa582326a2ae4 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 13:55:42 +0800 Subject: [PATCH 315/492] exclude some test cases from batch running list --- tests/automation/config.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/automation/config.json b/tests/automation/config.json index 3129838263..69e0d89089 100644 --- a/tests/automation/config.json +++ b/tests/automation/config.json @@ -1,7 +1,7 @@ { "format": "xunit-file", - "exclude": ["node_modules", "output", "internal", "res", "app", - "document_cookies", "menu", "menu_item", "shortcut", "console"], + "exclude": ["node_modules", "output", "internal", "res", "app", "node-remote", + "call_require_with_node-main_set", "show_devtool_after_http_server_created_in_node_main", "reference-node-main"], "single": "", "timeout": "5000", "slow": "200", From 89ded47a46e7bb70e9ad24b4669d62f85a87a510 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 14:33:12 +0800 Subject: [PATCH 316/492] add new test case "nw_fork" --- tests/automation/nw_fork/index.html | 16 ++++++ .../nw_fork/internal/fork_module.js | 3 ++ tests/automation/nw_fork/internal/index.html | 49 +++++++++++++++++++ .../automation/nw_fork/internal/package.json | 5 ++ tests/automation/nw_fork/mocha_test.js | 44 +++++++++++++++++ tests/automation/nw_fork/package.json | 4 ++ 6 files changed, 121 insertions(+) create mode 100644 tests/automation/nw_fork/index.html create mode 100644 tests/automation/nw_fork/internal/fork_module.js create mode 100644 tests/automation/nw_fork/internal/index.html create mode 100644 tests/automation/nw_fork/internal/package.json create mode 100644 tests/automation/nw_fork/mocha_test.js create mode 100644 tests/automation/nw_fork/package.json diff --git a/tests/automation/nw_fork/index.html b/tests/automation/nw_fork/index.html new file mode 100644 index 0000000000..702d3ff73a --- /dev/null +++ b/tests/automation/nw_fork/index.html @@ -0,0 +1,16 @@ + + + + + nw_fork test + + +

                      nw fork test

                      + + + + + + + + diff --git a/tests/automation/nw_fork/internal/fork_module.js b/tests/automation/nw_fork/internal/fork_module.js new file mode 100644 index 0000000000..f1c84094e2 --- /dev/null +++ b/tests/automation/nw_fork/internal/fork_module.js @@ -0,0 +1,3 @@ +process.on("message",function(m){ + process.send(m); +}); \ No newline at end of file diff --git a/tests/automation/nw_fork/internal/index.html b/tests/automation/nw_fork/internal/index.html new file mode 100644 index 0000000000..472f6ee8b9 --- /dev/null +++ b/tests/automation/nw_fork/internal/index.html @@ -0,0 +1,49 @@ + + + + + test + + +

                      it works!

                      + + + diff --git a/tests/automation/nw_fork/internal/package.json b/tests/automation/nw_fork/internal/package.json new file mode 100644 index 0000000000..113d160a54 --- /dev/null +++ b/tests/automation/nw_fork/internal/package.json @@ -0,0 +1,5 @@ +{ + "name":"test", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file diff --git a/tests/automation/nw_fork/mocha_test.js b/tests/automation/nw_fork/mocha_test.js new file mode 100644 index 0000000000..ab15291924 --- /dev/null +++ b/tests/automation/nw_fork/mocha_test.js @@ -0,0 +1,44 @@ +var path = require('path'); +var assert = require('assert'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + +var result = false; +describe('fork()',function(){ + + var child, server, result; + + before(function(done){ + this.timeout(0); + server = createTCPServer(13013); + child = spawnChildProcess(path.join(curDir, 'internal')); + + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + result = JSON.parse(data+''); + }); + }); + + child.on('exit',function(){ + done(); + }); + + + }); + + after(function(done){ + server.close(); + child.kill(); + done(); + }); + + + + it("child_process.fork() should have a workaround solution",function(done){ + assert.equal(result,true); + done(); + }); + +}); + diff --git a/tests/automation/nw_fork/package.json b/tests/automation/nw_fork/package.json new file mode 100644 index 0000000000..8e09dc9cf9 --- /dev/null +++ b/tests/automation/nw_fork/package.json @@ -0,0 +1,4 @@ +{ + "name":"nwfork_wrapper", + "main":"index.html" +} From 1a0fa60e578c788d8e56280ef4f064fe3e7fbf77 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Mon, 1 Dec 2014 14:33:50 +0800 Subject: [PATCH 317/492] add new test case "nw-in-mem" --- tests/automation/nw-in-mem/index.html | 16 +++ tests/automation/nw-in-mem/mocha_test.js | 42 +++++++ tests/automation/nw-in-mem/package.json | 4 + tests/automation/nw-in-mem/package/c2.png | Bin 0 -> 29833 bytes .../automation/nw-in-mem/package/c2runtime.js | 2 + .../nw-in-mem/package/evening_fall_harp.ogg | Bin 0 -> 2056918 bytes .../automation/nw-in-mem/package/icon-114.png | Bin 0 -> 25223 bytes .../automation/nw-in-mem/package/icon-128.png | Bin 0 -> 33382 bytes .../automation/nw-in-mem/package/icon-16.png | Bin 0 -> 1041 bytes .../automation/nw-in-mem/package/icon-32.png | Bin 0 -> 2967 bytes tests/automation/nw-in-mem/package/index.html | 107 ++++++++++++++++++ .../nw-in-mem/package/jquery-2.0.0.min.js | 6 + .../nw-in-mem/package/loading-logo.png | Bin 0 -> 9375 bytes tests/automation/nw-in-mem/package/nw.png | Bin 0 -> 2403 bytes .../automation/nw-in-mem/package/package.json | 17 +++ 15 files changed, 194 insertions(+) create mode 100644 tests/automation/nw-in-mem/index.html create mode 100644 tests/automation/nw-in-mem/mocha_test.js create mode 100644 tests/automation/nw-in-mem/package.json create mode 100644 tests/automation/nw-in-mem/package/c2.png create mode 100644 tests/automation/nw-in-mem/package/c2runtime.js create mode 100644 tests/automation/nw-in-mem/package/evening_fall_harp.ogg create mode 100644 tests/automation/nw-in-mem/package/icon-114.png create mode 100644 tests/automation/nw-in-mem/package/icon-128.png create mode 100644 tests/automation/nw-in-mem/package/icon-16.png create mode 100644 tests/automation/nw-in-mem/package/icon-32.png create mode 100644 tests/automation/nw-in-mem/package/index.html create mode 100644 tests/automation/nw-in-mem/package/jquery-2.0.0.min.js create mode 100644 tests/automation/nw-in-mem/package/loading-logo.png create mode 100644 tests/automation/nw-in-mem/package/nw.png create mode 100644 tests/automation/nw-in-mem/package/package.json diff --git a/tests/automation/nw-in-mem/index.html b/tests/automation/nw-in-mem/index.html new file mode 100644 index 0000000000..a894d0e6c6 --- /dev/null +++ b/tests/automation/nw-in-mem/index.html @@ -0,0 +1,16 @@ + + + + + nw_in_mem test + + +

                      nw in men test

                      + + + + + + + + diff --git a/tests/automation/nw-in-mem/mocha_test.js b/tests/automation/nw-in-mem/mocha_test.js new file mode 100644 index 0000000000..91c87bd3ef --- /dev/null +++ b/tests/automation/nw-in-mem/mocha_test.js @@ -0,0 +1,42 @@ +var os = require('os'); +var path = require('path'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + +var exec = require('child_process').exec; +var spawn = require('child_process').spawn; + +describe('nw in memory after quiting',function(){ + + it('nw.exe should not be in memory after gui.App.quit is called on windows',function(done){ + this.timeout(0); + if(os.platform() == "win32") { + var app = spawn(process.execPath, [path.join(curDir,'package')]) + app.on('close',function(){ + var nwname = "nw.exe"; + var nwcount = 0; + setTimeout(function() { + exec("tasklist", function(err, stdout, stderr) { + if(err){ return console.log(err); } + stdout.split('\n').filter(function(line){ + var p=line.trim().split(/\s+/),pname=p[0]; + if(pname.toLowerCase().indexOf(nwname)>=0) + nwcount++; + }); + + if(nwcount == 2) + done(); + else if(nwcount > 2) + done('nw.exe is still in memory after the quit of app'); + }) + }, 500); + }); + } + else + done(); + }); + + +}); + + diff --git a/tests/automation/nw-in-mem/package.json b/tests/automation/nw-in-mem/package.json new file mode 100644 index 0000000000..c0251d7820 --- /dev/null +++ b/tests/automation/nw-in-mem/package.json @@ -0,0 +1,4 @@ +{ + "name":"nw_in_mem_wrapper", + "main":"index.html" +} diff --git a/tests/automation/nw-in-mem/package/c2.png b/tests/automation/nw-in-mem/package/c2.png new file mode 100644 index 0000000000000000000000000000000000000000..ba48f98d2cf218683de3587a1bcd2ebc783092c9 GIT binary patch literal 29833 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 z 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 Aga7~l literal 0 HcmV?d00001 diff --git a/tests/automation/nw-in-mem/package/c2runtime.js b/tests/automation/nw-in-mem/package/c2runtime.js new file mode 100644 index 0000000000..1ffdea04c2 --- /dev/null +++ b/tests/automation/nw-in-mem/package/c2runtime.js @@ -0,0 +1,2 @@ + +var cr={plugins_:{},behaviors:{}};"function"!==typeof Object.getPrototypeOf&&(Object.getPrototypeOf="object"===typeof"test".__proto__?function(a){return a.__proto__}:function(a){return a.constructor.prototype});(function(){function a(a,p){this.x=a;this.y=p;cr.seal(this)}function b(a,p,g,u){this.set(a,p,g,u);cr.seal(this)}function d(){this.bly=this.blx=this.bry=this.brx=this.try_=this.trx=this.tly=this.tlx=0;cr.seal(this)}function e(){this.items={};this.item_count=0;this.values_cache=[];this.cache_valid=!0;cr.seal(this)}function f(){this.sum=this.t=this.y=this.c=0;cr.seal(this)}function h(a){this.pts_cache=[];this.set_pts(a);cr.seal(this)}cr.logexport=function(a){window.console&&window.console.log&&window.console.log(a)};cr.seal=function(a){return a};cr.freeze=function(a){return a};cr.is_undefined=function(a){return"undefined"===typeof a};cr.is_number=function(a){return"number"===typeof a};cr.is_string=function(a){return"string"===typeof a};cr.isPOT=function(a){return 0a?-a:a};cr.max=function(a,p){return a>p?a:p};cr.min=function(a,p){return acr.max(c,s)||cr.max(p,u)cr.max(k,m))return!1;var f=c-a+s-g,b=k-p+m-u;a=g-a;p=u-p;c=s-c;k=m-k;m=cr.abs(p*c-k*a);a=a*b-p*f;return cr.abs(c*b-k*f)<=m&&cr.abs(a)<=m};b.prototype.set=function(a,p,g,u){this.left=a;this.top=p;this.right=g;this.bottom=u};b.prototype.width=function(){return this.right-this.left};b.prototype.height=function(){return this.bottom-this.top};b.prototype.offset=function(a,p){this.left+=a;this.top+=p;this.right+=a;this.bottom+=p;return this};b.prototype.intersects_rect=function(a){return!(a.rightthis.right||a.top>this.bottom)};b.prototype.contains_pt=function(a,p){return a>=this.left&&a<=this.right&&p>=this.top&&p<=this.bottom};cr.rect=b;d.prototype.set_from_rect=function(a){this.tlx=a.left;this.tly=a.top;this.trx=a.right;this.try_=a.top;this.brx=a.right;this.bry=a.bottom;this.blx=a.left;this.bly=a.bottom};d.prototype.set_from_rotated_rect=function(a,p){if(0===p)this.set_from_rect(a);else{var g=Math.sin(p),u=Math.cos(p),c=a.left*g,k=a.top*g,s=a.right*g,g=a.bottom*g,m=a.left*u,f=a.top*u,b=a.right*u,u=a.bottom*u;this.tlx=m-k;this.tly=f+c;this.trx=b-k;this.try_=f+s;this.brx=b-g;this.bry=u+s;this.blx=m-g;this.bly=u+c}};d.prototype.offset=function(a,p){this.tlx+=a;this.tly+=p;this.trx+=a;this.try_+=p;this.brx+=a;this.bry+=p;this.blx+=a;this.bly+=p;return this};d.prototype.bounding_box=function(a){a.left=cr.min(cr.min(this.tlx,this.trx),cr.min(this.brx,this.blx));a.top=cr.min(cr.min(this.tly,this.try_),cr.min(this.bry,this.bly));a.right=cr.max(cr.max(this.tlx,this.trx),cr.max(this.brx,this.blx));a.bottom=cr.max(cr.max(this.tly,this.try_),cr.max(this.bry,this.bly))};d.prototype.contains_pt=function(a,p){var g=this.trx-this.tlx,u=this.try_-this.tly,c=this.brx-this.tlx,k=this.bry-this.tly,s=a-this.tlx,m=p-this.tly,f=g*g+u*u,b=g*c+u*k,u=g*s+u*m,l=c*c+k*k,d=c*s+k*m,e=1/(f*l-b*b),g=(l*u-b*d)*e,f=(f*d-b*u)*e;if(0<=g&&0g+f)return!0;g=this.blx-this.tlx;u=this.bly-this.tly;f=g*g+u*u;b=g*c+u*k;u=g*s+u*m;e=1/(f*l-b*b);g=(l*u-b*d)*e;f=(f*d-b*u)*e;return 0<=g&&0g+f};d.prototype.at=function(a,p){switch(a){case 0:return p?this.tlx:this.tly;case 1:return p?this.trx:this.try_;case 2:return p?this.brx:this.bry;case 3:return p?this.blx:this.bly;case 4:return p?this.tlx:this.tly;default:return p?this.tlx:this.tly}};d.prototype.midX=function(){return(this.tlx+this.trx+this.brx+this.blx)/4};d.prototype.midY=function(){return(this.tly+this.try_+this.bry+this.bly)/4};d.prototype.intersects_segment=function(a,p,g,u){if(this.contains_pt(a,p)||this.contains_pt(g,u))return!0;var c,k,s,m,f;for(f=0;4>f;f++)if(c=this.at(f,!0),k=this.at(f,!1),s=this.at(f+1,!0),m=this.at(f+1,!1),cr.segments_intersect(a,p,g,u,c,k,s,m))return!0;return!1};d.prototype.intersects_quad=function(a){var p=a.midX(),g=a.midY();if(this.contains_pt(p,g))return!0;p=this.midX();g=this.midY();if(a.contains_pt(p,g))return!0;var u,c,k,s,m,f,b,l;for(b=0;4>b;b++)for(l=0;4>l;l++)if(p=this.at(b,!0),g=this.at(b,!1),u=this.at(b+1,!0),c=this.at(b+1,!1),k=a.at(l,!0),s=a.at(l,!1),m=a.at(l+1,!0),f=a.at(l+1,!1),cr.segments_intersect(p,g,u,c,k,s,m,f))return!0;return!1};cr.quad=d;cr.RGB=function(a,p,g){return Math.max(Math.min(a,255),0)|Math.max(Math.min(p,255),0)<<8|Math.max(Math.min(g,255),0)<<16};cr.GetRValue=function(a){return a&255};cr.GetGValue=function(a){return(a&65280)>>8};cr.GetBValue=function(a){return(a&16711680)>>16};cr.shallowCopy=function(a,p,g){for(var u in p)p.hasOwnProperty(u)&&(a[u]=p[u]);return a};cr.arrayRemove=function(a,p){var g,u;p=cr.floor(p);if(!(0>p||p>=a.length))if(0===p)a.shift();else if(p===a.length-1)a.pop();else{g=p;for(u=a.length-1;gg?g:a};cr.to_radians=function(a){return a/(180/cr.PI)};cr.to_degrees=function(a){return a*(180/cr.PI)};cr.clamp_angle_degrees=function(a){a%=360;0>a&&(a+=360);return a};cr.clamp_angle=function(a){a%=2*cr.PI;0>a&&(a+=2*cr.PI);return a};cr.to_clamped_degrees=function(a){return cr.clamp_angle_degrees(cr.to_degrees(a))};cr.to_clamped_radians=function(a){return cr.clamp_angle(cr.to_radians(a))};cr.angleTo=function(a,p,g,u){return Math.atan2(u-p,g-a)};cr.angleDiff=function(a,p){if(a===p)return 0;var g=Math.sin(a),u=Math.cos(a),c=Math.sin(p),k=Math.cos(p),g=g*c+u*k;return 1<=g?0:-1>=g?cr.PI:Math.acos(g)};cr.angleRotate=function(a,p,g){var u=Math.sin(a),c=Math.cos(a),k=Math.sin(p),s=Math.cos(p);return Math.acos(u*k+c*s)>g?0=u*c-g*k};cr.rotatePtAround=function(a,p,g,u,c,k){if(0===g)return k?a:p;var s=Math.sin(g);g=Math.cos(g);a-=u;p-=c;var m=a*s;a=a*g-p*s;p=p*g+m;return k?a+u:p+c};cr.distanceTo=function(a,p,g,u){a=g-a;p=u-p;return Math.sqrt(a*a+p*p)};cr.xor=function(a,p){return!a!==!p};cr.lerp=function(a,p,g){return a+(p-a)*g};cr.hasAnyOwnProperty=function(a){for(var p in a)if(a.hasOwnProperty(p))return!0;return!1};cr.wipe=function(a){for(var p in a)a.hasOwnProperty(p)&&delete a[p]};var k=+new Date;cr.performance_now=function(){if("undefined"!==typeof window.performance){var a=window.performance;if("undefined"!==typeof a.now)return a.now();if("undefined"!==typeof a.webkitNow)return a.webkitNow();if("undefined"!==typeof a.msNow)return a.msNow()}return Date.now()-k};e.prototype.contains=function(a){return this.items.hasOwnProperty(a.toString())};e.prototype.add=function(a){var p=a.toString();this.items.hasOwnProperty(p)||(this.items[p]=a,this.item_count++,this.cache_valid=!1);return this};e.prototype.remove=function(a){a=a.toString();this.items.hasOwnProperty(a)&&(delete this.items[a],this.item_count--,this.cache_valid=!1);return this};e.prototype.clear=function(){cr.wipe(this.items);this.item_count=0;this.values_cache.length=0;this.cache_valid=!0;return this};e.prototype.isEmpty=function(){return 0===this.item_count};e.prototype.count=function(){return this.item_count};e.prototype.update_cache=function(){if(!this.cache_valid){this.values_cache.length=this.item_count;var a,p=0;for(a in this.items)this.items.hasOwnProperty(a)&&(this.values_cache[p++]=this.items[a]);this.cache_valid=!0}};e.prototype.values=function(){this.update_cache();return this.values_cache.slice(0)};e.prototype.valuesRef=function(){this.update_cache();return this.values_cache};cr.ObjectSet=e;f.prototype.add=function(a){this.y=a-this.c;this.t=this.sum+this.y;this.c=this.t-this.sum-this.y;this.sum=this.t};f.prototype.reset=function(){this.sum=this.t=this.y=this.c=0};cr.KahanAdder=f;cr.regexp_escape=function(a){return a.replace(/[-[\]{}()*+?.,\\^$|#\s]/g,"\\$&")};h.prototype.set_pts=function(a){this.pts_array=a;this.pts_count=a.length/2;this.pts_cache.length=a.length;this.cache_height=this.cache_width=-1;this.cache_angle=0};h.prototype.is_empty=function(){return!this.pts_array.length};h.prototype.set_from_quad=function(a,p,g,u,c){this.pts_cache.length=8;this.pts_count=4;var k=this.pts_cache;k[0]=a.tlx-p;k[1]=a.tly-g;k[2]=a.trx-p;k[3]=a.try_-g;k[4]=a.brx-p;k[5]=a.bry-g;k[6]=a.blx-p;k[7]=a.bly-g;this.cache_width=u;this.cache_height=c};h.prototype.set_from_poly=function(a){this.pts_count=a.pts_count;cr.shallowAssignArray(this.pts_cache,a.pts_cache)};h.prototype.cache_poly=function(a,p,g){if(this.cache_width!==a||this.cache_height!==p||this.cache_angle!==g){this.cache_width=a;this.cache_height=p;this.cache_angle=g;var u,c,k,s=0,m=1,f=this.pts_array,b=this.pts_cache;0!==g&&(s=Math.sin(g),m=Math.cos(g));g=0;for(u=this.pts_count;gf&&(f=c),kl&&(l=k);c=m-110;var b=b-101,f=f+131,l=l+120,d,e,r=0,h=0;for(u=0;u=a||11<=a?"source-over":c[a-1]};cr.setGLBlend=function(a,p,g){if(g)switch(a.srcBlend=g.ONE,a.destBlend=g.ONE_MINUS_SRC_ALPHA,p){case 1:a.srcBlend=g.ONE;a.destBlend=g.ONE;break;case 3:a.srcBlend=g.ONE;a.destBlend=g.ZERO;break;case 4:a.srcBlend=g.ONE_MINUS_DST_ALPHA;a.destBlend=g.ONE;break;case 5:a.srcBlend=g.DST_ALPHA;a.destBlend=g.ZERO;break;case 6:a.srcBlend=g.ZERO;a.destBlend=g.SRC_ALPHA;break;case 7:a.srcBlend=g.ONE_MINUS_DST_ALPHA;a.destBlend=g.ZERO;break;case 8:a.srcBlend=g.ZERO;a.destBlend=g.ONE_MINUS_SRC_ALPHA;break;case 9:a.srcBlend=g.DST_ALPHA;a.destBlend=g.ONE_MINUS_SRC_ALPHA;break;case 10:a.srcBlend=g.ONE_MINUS_DST_ALPHA,a.destBlend=g.SRC_ALPHA}};cr.round6dp=function(a){return Math.round(1E6*a)/1E6};var r={usage:"search",sensitivity:"accent"},n=!!"a".localeCompare,l=n&&0==="a".localeCompare("A",void 0,r),q=n&&0!=="a".localeCompare("\u00e1",void 0,r),v=n&&l&&q;cr.equals_nocase=function(a,p){return"string"!==typeof a||"string"!==typeof p||a.length!==p.length?!1:a===p?!0:v?0===a.localeCompare(p,void 0,r):a.toLowerCase()===p.toLowerCase()}})();var MatrixArray="undefined"!==typeof Float32Array?Float32Array:Array,glMatrixArrayType=MatrixArray,vec3={},mat3={},mat4={},quat4={};vec3.create=function(a){var b=new MatrixArray(3);a&&(b[0]=a[0],b[1]=a[1],b[2]=a[2]);return b};vec3.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];return b};vec3.add=function(a,b,d){if(!d||a===d)return a[0]+=b[0],a[1]+=b[1],a[2]+=b[2],a;d[0]=a[0]+b[0];d[1]=a[1]+b[1];d[2]=a[2]+b[2];return d};vec3.subtract=function(a,b,d){if(!d||a===d)return a[0]-=b[0],a[1]-=b[1],a[2]-=b[2],a;d[0]=a[0]-b[0];d[1]=a[1]-b[1];d[2]=a[2]-b[2];return d};vec3.negate=function(a,b){b||(b=a);b[0]=-a[0];b[1]=-a[1];b[2]=-a[2];return b};vec3.scale=function(a,b,d){if(!d||a===d)return a[0]*=b,a[1]*=b,a[2]*=b,a;d[0]=a[0]*b;d[1]=a[1]*b;d[2]=a[2]*b;return d};vec3.normalize=function(a,b){b||(b=a);var d=a[0],e=a[1],f=a[2],h=Math.sqrt(d*d+e*e+f*f);if(h){if(1===h)return b[0]=d,b[1]=e,b[2]=f,b}else return b[0]=0,b[1]=0,b[2]=0,b;h=1/h;b[0]=d*h;b[1]=e*h;b[2]=f*h;return b};vec3.cross=function(a,b,d){d||(d=a);var e=a[0],f=a[1];a=a[2];var h=b[0],k=b[1];b=b[2];d[0]=f*b-a*k;d[1]=a*h-e*b;d[2]=e*k-f*h;return d};vec3.length=function(a){var b=a[0],d=a[1];a=a[2];return Math.sqrt(b*b+d*d+a*a)};vec3.dot=function(a,b){return a[0]*b[0]+a[1]*b[1]+a[2]*b[2]};vec3.direction=function(a,b,d){d||(d=a);var e=a[0]-b[0],f=a[1]-b[1];a=a[2]-b[2];b=Math.sqrt(e*e+f*f+a*a);if(!b)return d[0]=0,d[1]=0,d[2]=0,d;b=1/b;d[0]=e*b;d[1]=f*b;d[2]=a*b;return d};vec3.lerp=function(a,b,d,e){e||(e=a);e[0]=a[0]+d*(b[0]-a[0]);e[1]=a[1]+d*(b[1]-a[1]);e[2]=a[2]+d*(b[2]-a[2]);return e};vec3.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+"]"};mat3.create=function(a){var b=new MatrixArray(9);a&&(b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8]);return b};mat3.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];return b};mat3.identity=function(a){a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=1;a[5]=0;a[6]=0;a[7]=0;a[8]=1;return a};mat3.transpose=function(a,b){if(!b||a===b){var d=a[1],e=a[2],f=a[5];a[1]=a[3];a[2]=a[6];a[3]=d;a[5]=a[7];a[6]=e;a[7]=f;return a}b[0]=a[0];b[1]=a[3];b[2]=a[6];b[3]=a[1];b[4]=a[4];b[5]=a[7];b[6]=a[2];b[7]=a[5];b[8]=a[8];return b};mat3.toMat4=function(a,b){b||(b=mat4.create());b[15]=1;b[14]=0;b[13]=0;b[12]=0;b[11]=0;b[10]=a[8];b[9]=a[7];b[8]=a[6];b[7]=0;b[6]=a[5];b[5]=a[4];b[4]=a[3];b[3]=0;b[2]=a[2];b[1]=a[1];b[0]=a[0];return b};mat3.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+"]"};mat4.create=function(a){var b=new MatrixArray(16);a&&(b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3],b[4]=a[4],b[5]=a[5],b[6]=a[6],b[7]=a[7],b[8]=a[8],b[9]=a[9],b[10]=a[10],b[11]=a[11],b[12]=a[12],b[13]=a[13],b[14]=a[14],b[15]=a[15]);return b};mat4.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];b[13]=a[13];b[14]=a[14];b[15]=a[15];return b};mat4.identity=function(a){a[0]=1;a[1]=0;a[2]=0;a[3]=0;a[4]=0;a[5]=1;a[6]=0;a[7]=0;a[8]=0;a[9]=0;a[10]=1;a[11]=0;a[12]=0;a[13]=0;a[14]=0;a[15]=1;return a};mat4.transpose=function(a,b){if(!b||a===b){var d=a[1],e=a[2],f=a[3],h=a[6],k=a[7],c=a[11];a[1]=a[4];a[2]=a[8];a[3]=a[12];a[4]=d;a[6]=a[9];a[7]=a[13];a[8]=e;a[9]=h;a[11]=a[14];a[12]=f;a[13]=k;a[14]=c;return a}b[0]=a[0];b[1]=a[4];b[2]=a[8];b[3]=a[12];b[4]=a[1];b[5]=a[5];b[6]=a[9];b[7]=a[13];b[8]=a[2];b[9]=a[6];b[10]=a[10];b[11]=a[14];b[12]=a[3];b[13]=a[7];b[14]=a[11];b[15]=a[15];return b};mat4.determinant=function(a){var b=a[0],d=a[1],e=a[2],f=a[3],h=a[4],k=a[5],c=a[6],r=a[7],n=a[8],l=a[9],q=a[10],v=a[11],t=a[12],p=a[13],g=a[14];a=a[15];return t*l*c*f-n*p*c*f-t*k*q*f+h*p*q*f+n*k*g*f-h*l*g*f-t*l*e*r+n*p*e*r+t*d*q*r-b*p*q*r-n*d*g*r+b*l*g*r+t*k*e*v-h*p*e*v-t*d*c*v+b*p*c*v+h*d*g*v-b*k*g*v-n*k*e*a+h*l*e*a+n*d*c*a-b*l*c*a-h*d*q*a+b*k*q*a};mat4.inverse=function(a,b){b||(b=a);var d=a[0],e=a[1],f=a[2],h=a[3],k=a[4],c=a[5],r=a[6],n=a[7],l=a[8],q=a[9],v=a[10],t=a[11],p=a[12],g=a[13],u=a[14],D=a[15],B=d*c-e*k,s=d*r-f*k,m=d*n-h*k,P=e*r-f*c,x=e*n-h*c,z=f*n-h*r,G=l*g-q*p,C=l*u-v*p,F=l*D-t*p,y=q*u-v*g,H=q*D-t*g,Q=v*D-t*u,w=1/(B*Q-s*H+m*y+P*F-x*C+z*G);b[0]=(c*Q-r*H+n*y)*w;b[1]=(-e*Q+f*H-h*y)*w;b[2]=(g*z-u*x+D*P)*w;b[3]=(-q*z+v*x-t*P)*w;b[4]=(-k*Q+r*F-n*C)*w;b[5]=(d*Q-f*F+h*C)*w;b[6]=(-p*z+u*m-D*s)*w;b[7]=(l*z-v*m+t*s)*w;b[8]=(k*H-c*F+n*G)*w;b[9]=(-d*H+e*F-h*G)*w;b[10]=(p*x-g*m+D*B)*w;b[11]=(-l*x+q*m-t*B)*w;b[12]=(-k*y+c*C-r*G)*w;b[13]=(d*y-e*C+f*G)*w;b[14]=(-p*P+g*s-u*B)*w;b[15]=(l*P-q*s+v*B)*w;return b};mat4.toRotationMat=function(a,b){b||(b=mat4.create());b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];b[5]=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=0;b[13]=0;b[14]=0;b[15]=1;return b};mat4.toMat3=function(a,b){b||(b=mat3.create());b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[4];b[4]=a[5];b[5]=a[6];b[6]=a[8];b[7]=a[9];b[8]=a[10];return b};mat4.toInverseMat3=function(a,b){var d=a[0],e=a[1],f=a[2],h=a[4],k=a[5],c=a[6],r=a[8],n=a[9],l=a[10],q=l*k-c*n,v=-l*h+c*r,t=n*h-k*r,p=d*q+e*v+f*t;if(!p)return null;p=1/p;b||(b=mat3.create());b[0]=q*p;b[1]=(-l*e+f*n)*p;b[2]=(c*e-f*k)*p;b[3]=v*p;b[4]=(l*d-f*r)*p;b[5]=(-c*d+f*h)*p;b[6]=t*p;b[7]=(-n*d+e*r)*p;b[8]=(k*d-e*h)*p;return b};mat4.multiply=function(a,b,d){d||(d=a);var e=a[0],f=a[1],h=a[2],k=a[3],c=a[4],r=a[5],n=a[6],l=a[7],q=a[8],v=a[9],t=a[10],p=a[11],g=a[12],u=a[13],D=a[14];a=a[15];var B=b[0],s=b[1],m=b[2],P=b[3],x=b[4],z=b[5],G=b[6],C=b[7],F=b[8],y=b[9],H=b[10],Q=b[11],w=b[12],N=b[13],R=b[14];b=b[15];d[0]=B*e+s*c+m*q+P*g;d[1]=B*f+s*r+m*v+P*u;d[2]=B*h+s*n+m*t+P*D;d[3]=B*k+s*l+m*p+P*a;d[4]=x*e+z*c+G*q+C*g;d[5]=x*f+z*r+G*v+C*u;d[6]=x*h+z*n+G*t+C*D;d[7]=x*k+z*l+G*p+C*a;d[8]=F*e+y*c+H*q+Q*g;d[9]=F*f+y*r+H*v+Q*u;d[10]=F*h+y*n+H*t+Q*D;d[11]=F*k+y*l+H*p+Q*a;d[12]=w*e+N*c+R*q+b*g;d[13]=w*f+N*r+R*v+b*u;d[14]=w*h+N*n+R*t+b*D;d[15]=w*k+N*l+R*p+b*a;return d};mat4.multiplyVec3=function(a,b,d){d||(d=b);var e=b[0],f=b[1];b=b[2];d[0]=a[0]*e+a[4]*f+a[8]*b+a[12];d[1]=a[1]*e+a[5]*f+a[9]*b+a[13];d[2]=a[2]*e+a[6]*f+a[10]*b+a[14];return d};mat4.multiplyVec4=function(a,b,d){d||(d=b);var e=b[0],f=b[1],h=b[2];b=b[3];d[0]=a[0]*e+a[4]*f+a[8]*h+a[12]*b;d[1]=a[1]*e+a[5]*f+a[9]*h+a[13]*b;d[2]=a[2]*e+a[6]*f+a[10]*h+a[14]*b;d[3]=a[3]*e+a[7]*f+a[11]*h+a[15]*b;return d};mat4.translate=function(a,b,d){var e=b[0],f=b[1];b=b[2];var h,k,c,r,n,l,q,v,t,p,g,u;if(!d||a===d)return a[12]=a[0]*e+a[4]*f+a[8]*b+a[12],a[13]=a[1]*e+a[5]*f+a[9]*b+a[13],a[14]=a[2]*e+a[6]*f+a[10]*b+a[14],a[15]=a[3]*e+a[7]*f+a[11]*b+a[15],a;h=a[0];k=a[1];c=a[2];r=a[3];n=a[4];l=a[5];q=a[6];v=a[7];t=a[8];p=a[9];g=a[10];u=a[11];d[0]=h;d[1]=k;d[2]=c;d[3]=r;d[4]=n;d[5]=l;d[6]=q;d[7]=v;d[8]=t;d[9]=p;d[10]=g;d[11]=u;d[12]=h*e+n*f+t*b+a[12];d[13]=k*e+l*f+p*b+a[13];d[14]=c*e+q*f+g*b+a[14];d[15]=r*e+v*f+u*b+a[15];return d};mat4.scale=function(a,b,d){var e=b[0],f=b[1];b=b[2];if(!d||a===d)return a[0]*=e,a[1]*=e,a[2]*=e,a[3]*=e,a[4]*=f,a[5]*=f,a[6]*=f,a[7]*=f,a[8]*=b,a[9]*=b,a[10]*=b,a[11]*=b,a;d[0]=a[0]*e;d[1]=a[1]*e;d[2]=a[2]*e;d[3]=a[3]*e;d[4]=a[4]*f;d[5]=a[5]*f;d[6]=a[6]*f;d[7]=a[7]*f;d[8]=a[8]*b;d[9]=a[9]*b;d[10]=a[10]*b;d[11]=a[11]*b;d[12]=a[12];d[13]=a[13];d[14]=a[14];d[15]=a[15];return d};mat4.rotate=function(a,b,d,e){var f=d[0],h=d[1];d=d[2];var k=Math.sqrt(f*f+h*h+d*d),c,r,n,l,q,v,t,p,g,u,D,B,s,m,P,x,z,G,C,F;if(!k)return null;1!==k&&(k=1/k,f*=k,h*=k,d*=k);c=Math.sin(b);r=Math.cos(b);n=1-r;b=a[0];k=a[1];l=a[2];q=a[3];v=a[4];t=a[5];p=a[6];g=a[7];u=a[8];D=a[9];B=a[10];s=a[11];m=f*f*n+r;P=h*f*n+d*c;x=d*f*n-h*c;z=f*h*n-d*c;G=h*h*n+r;C=d*h*n+f*c;F=f*d*n+h*c;f=h*d*n-f*c;h=d*d*n+r;e?a!==e&&(e[12]=a[12],e[13]=a[13],e[14]=a[14],e[15]=a[15]):e=a;e[0]=b*m+v*P+u*x;e[1]=k*m+t*P+D*x;e[2]=l*m+p*P+B*x;e[3]=q*m+g*P+s*x;e[4]=b*z+v*G+u*C;e[5]=k*z+t*G+D*C;e[6]=l*z+p*G+B*C;e[7]=q*z+g*G+s*C;e[8]=b*F+v*f+u*h;e[9]=k*F+t*f+D*h;e[10]=l*F+p*f+B*h;e[11]=q*F+g*f+s*h;return e};mat4.rotateX=function(a,b,d){var e=Math.sin(b);b=Math.cos(b);var f=a[4],h=a[5],k=a[6],c=a[7],r=a[8],n=a[9],l=a[10],q=a[11];d?a!==d&&(d[0]=a[0],d[1]=a[1],d[2]=a[2],d[3]=a[3],d[12]=a[12],d[13]=a[13],d[14]=a[14],d[15]=a[15]):d=a;d[4]=f*b+r*e;d[5]=h*b+n*e;d[6]=k*b+l*e;d[7]=c*b+q*e;d[8]=f*-e+r*b;d[9]=h*-e+n*b;d[10]=k*-e+l*b;d[11]=c*-e+q*b;return d};mat4.rotateY=function(a,b,d){var e=Math.sin(b);b=Math.cos(b);var f=a[0],h=a[1],k=a[2],c=a[3],r=a[8],n=a[9],l=a[10],q=a[11];d?a!==d&&(d[4]=a[4],d[5]=a[5],d[6]=a[6],d[7]=a[7],d[12]=a[12],d[13]=a[13],d[14]=a[14],d[15]=a[15]):d=a;d[0]=f*b+r*-e;d[1]=h*b+n*-e;d[2]=k*b+l*-e;d[3]=c*b+q*-e;d[8]=f*e+r*b;d[9]=h*e+n*b;d[10]=k*e+l*b;d[11]=c*e+q*b;return d};mat4.rotateZ=function(a,b,d){var e=Math.sin(b);b=Math.cos(b);var f=a[0],h=a[1],k=a[2],c=a[3],r=a[4],n=a[5],l=a[6],q=a[7];d?a!==d&&(d[8]=a[8],d[9]=a[9],d[10]=a[10],d[11]=a[11],d[12]=a[12],d[13]=a[13],d[14]=a[14],d[15]=a[15]):d=a;d[0]=f*b+r*e;d[1]=h*b+n*e;d[2]=k*b+l*e;d[3]=c*b+q*e;d[4]=f*-e+r*b;d[5]=h*-e+n*b;d[6]=k*-e+l*b;d[7]=c*-e+q*b;return d};mat4.frustum=function(a,b,d,e,f,h,k){k||(k=mat4.create());var c=b-a,r=e-d,n=h-f;k[0]=2*f/c;k[1]=0;k[2]=0;k[3]=0;k[4]=0;k[5]=2*f/r;k[6]=0;k[7]=0;k[8]=(b+a)/c;k[9]=(e+d)/r;k[10]=-(h+f)/n;k[11]=-1;k[12]=0;k[13]=0;k[14]=-(2*h*f)/n;k[15]=0;return k};mat4.perspective=function(a,b,d,e,f){a=d*Math.tan(a*Math.PI/360);b*=a;return mat4.frustum(-b,b,-a,a,d,e,f)};mat4.ortho=function(a,b,d,e,f,h,k){k||(k=mat4.create());var c=b-a,r=e-d,n=h-f;k[0]=2/c;k[1]=0;k[2]=0;k[3]=0;k[4]=0;k[5]=2/r;k[6]=0;k[7]=0;k[8]=0;k[9]=0;k[10]=-2/n;k[11]=0;k[12]=-(a+b)/c;k[13]=-(e+d)/r;k[14]=-(h+f)/n;k[15]=1;return k};mat4.lookAt=function(a,b,d,e){e||(e=mat4.create());var f,h,k,c,r,n,l,q,v=a[0],t=a[1];a=a[2];h=d[0];k=d[1];f=d[2];d=b[1];n=b[2];if(v===b[0]&&t===d&&a===n)return mat4.identity(e);d=v-b[0];n=t-b[1];l=a-b[2];q=1/Math.sqrt(d*d+n*n+l*l);d*=q;n*=q;l*=q;b=k*l-f*n;f=f*d-h*l;h=h*n-k*d;(q=Math.sqrt(b*b+f*f+h*h))?(q=1/q,b*=q,f*=q,h*=q):h=f=b=0;k=n*h-l*f;c=l*b-d*h;r=d*f-n*b;(q=Math.sqrt(k*k+c*c+r*r))?(q=1/q,k*=q,c*=q,r*=q):r=c=k=0;e[0]=b;e[1]=k;e[2]=d;e[3]=0;e[4]=f;e[5]=c;e[6]=n;e[7]=0;e[8]=h;e[9]=r;e[10]=l;e[11]=0;e[12]=-(b*v+f*t+h*a);e[13]=-(k*v+c*t+r*a);e[14]=-(d*v+n*t+l*a);e[15]=1;return e};mat4.fromRotationTranslation=function(a,b,d){d||(d=mat4.create());var e=a[0],f=a[1],h=a[2],k=a[3],c=e+e,r=f+f,n=h+h;a=e*c;var l=e*r,e=e*n,q=f*r,f=f*n,h=h*n,c=c*k,r=r*k,k=k*n;d[0]=1-(q+h);d[1]=l+k;d[2]=e-r;d[3]=0;d[4]=l-k;d[5]=1-(a+h);d[6]=f+c;d[7]=0;d[8]=e+r;d[9]=f-c;d[10]=1-(a+q);d[11]=0;d[12]=b[0];d[13]=b[1];d[14]=b[2];d[15]=1;return d};mat4.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+", "+a[4]+", "+a[5]+", "+a[6]+", "+a[7]+", "+a[8]+", "+a[9]+", "+a[10]+", "+a[11]+", "+a[12]+", "+a[13]+", "+a[14]+", "+a[15]+"]"};quat4.create=function(a){var b=new MatrixArray(4);a&&(b[0]=a[0],b[1]=a[1],b[2]=a[2],b[3]=a[3]);return b};quat4.set=function(a,b){b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];return b};quat4.calculateW=function(a,b){var d=a[0],e=a[1],f=a[2];if(!b||a===b)return a[3]=-Math.sqrt(Math.abs(1-d*d-e*e-f*f)),a;b[0]=d;b[1]=e;b[2]=f;b[3]=-Math.sqrt(Math.abs(1-d*d-e*e-f*f));return b};quat4.inverse=function(a,b){if(!b||a===b)return a[0]*=-1,a[1]*=-1,a[2]*=-1,a;b[0]=-a[0];b[1]=-a[1];b[2]=-a[2];b[3]=a[3];return b};quat4.length=function(a){var b=a[0],d=a[1],e=a[2];a=a[3];return Math.sqrt(b*b+d*d+e*e+a*a)};quat4.normalize=function(a,b){b||(b=a);var d=a[0],e=a[1],f=a[2],h=a[3],k=Math.sqrt(d*d+e*e+f*f+h*h);if(0===k)return b[0]=0,b[1]=0,b[2]=0,b[3]=0,b;k=1/k;b[0]=d*k;b[1]=e*k;b[2]=f*k;b[3]=h*k;return b};quat4.multiply=function(a,b,d){d||(d=a);var e=a[0],f=a[1],h=a[2];a=a[3];var k=b[0],c=b[1],r=b[2];b=b[3];d[0]=e*b+a*k+f*r-h*c;d[1]=f*b+a*c+h*k-e*r;d[2]=h*b+a*r+e*c-f*k;d[3]=a*b-e*k-f*c-h*r;return d};quat4.multiplyVec3=function(a,b,d){d||(d=b);var e=b[0],f=b[1],h=b[2];b=a[0];var k=a[1],c=a[2];a=a[3];var r=a*e+k*h-c*f,n=a*f+c*e-b*h,l=a*h+b*f-k*e,e=-b*e-k*f-c*h;d[0]=r*a+e*-b+n*-c-l*-k;d[1]=n*a+e*-k+l*-b-r*-c;d[2]=l*a+e*-c+r*-k-n*-b;return d};quat4.toMat3=function(a,b){b||(b=mat3.create());var d=a[0],e=a[1],f=a[2],h=a[3],k=d+d,c=e+e,r=f+f,n=d*k,l=d*c,d=d*r,q=e*c,e=e*r,f=f*r,k=k*h,c=c*h,h=h*r;b[0]=1-(q+f);b[1]=l+h;b[2]=d-c;b[3]=l-h;b[4]=1-(n+f);b[5]=e+k;b[6]=d+c;b[7]=e-k;b[8]=1-(n+q);return b};quat4.toMat4=function(a,b){b||(b=mat4.create());var d=a[0],e=a[1],f=a[2],h=a[3],k=d+d,c=e+e,r=f+f,n=d*k,l=d*c,d=d*r,q=e*c,e=e*r,f=f*r,k=k*h,c=c*h,h=h*r;b[0]=1-(q+f);b[1]=l+h;b[2]=d-c;b[3]=0;b[4]=l-h;b[5]=1-(n+f);b[6]=e+k;b[7]=0;b[8]=d+c;b[9]=e-k;b[10]=1-(n+q);b[11]=0;b[12]=0;b[13]=0;b[14]=0;b[15]=1;return b};quat4.slerp=function(a,b,d,e){e||(e=a);var f=a[0]*b[0]+a[1]*b[1]+a[2]*b[2]+a[3]*b[3],h,k;if(1<=Math.abs(f))return e!==a&&(e[0]=a[0],e[1]=a[1],e[2]=a[2],e[3]=a[3]),e;h=Math.acos(f);k=Math.sqrt(1-f*f);if(0.001>Math.abs(k))return e[0]=0.5*a[0]+0.5*b[0],e[1]=0.5*a[1]+0.5*b[1],e[2]=0.5*a[2]+0.5*b[2],e[3]=0.5*a[3]+0.5*b[3],e;f=Math.sin((1-d)*h)/k;d=Math.sin(d*h)/k;e[0]=a[0]*f+b[0]*d;e[1]=a[1]*f+b[1]*d;e[2]=a[2]*f+b[2]*d;e[3]=a[3]*f+b[3]*d;return e};quat4.str=function(a){return"["+a[0]+", "+a[1]+", "+a[2]+", "+a[3]+"]"};(function(){function a(a,c){this.height=this.width=0;this.cam=vec3.create([0,0,100]);this.look=vec3.create([0,0,0]);this.up=vec3.create([0,1,0]);this.worldScale=vec3.create([1,1,1]);this.matP=mat4.create();this.matMV=mat4.create();this.lastMV=mat4.create();this.currentMV=mat4.create();this.gl=a;this.initState()}function b(a,c,f){this.gl=a;this.shaderProgram=c;this.name=f;this.locAPos=a.getAttribLocation(c,"aPos");this.locATex=a.getAttribLocation(c,"aTex");this.locMatP=a.getUniformLocation(c,"matP");this.locMatMV=a.getUniformLocation(c,"matMV");this.locOpacity=a.getUniformLocation(c,"opacity");this.locSamplerFront=a.getUniformLocation(c,"samplerFront");this.locSamplerBack=a.getUniformLocation(c,"samplerBack");this.locDestStart=a.getUniformLocation(c,"destStart");this.locDestEnd=a.getUniformLocation(c,"destEnd");this.locSeconds=a.getUniformLocation(c,"seconds");this.locPixelWidth=a.getUniformLocation(c,"pixelWidth");this.locPixelHeight=a.getUniformLocation(c,"pixelHeight");this.locLayerScale=a.getUniformLocation(c,"layerScale");this.locOpacity&&a.uniform1f(this.locOpacity,1);this.locSamplerFront&&a.uniform1i(this.locSamplerFront,0);this.locSamplerBack&&a.uniform1i(this.locSamplerBack,1);this.locDestStart&&a.uniform2f(this.locDestStart,0,0);this.locDestEnd&&a.uniform2f(this.locDestEnd,1,1);this.hasCurrentMatMV=!1}function d(a,c){this.type=a;this.glwrap=c;this.gl=c.gl;this.indexCount=this.startIndex=this.opacityParam=0;this.mat4param=this.texParam=null;this.shaderParams=[];cr.seal(this)}function e(a){--a;for(var c=1;32>c;c<<=1)a|=a>>c;return a+1}a.prototype.initState=function(){var a=this.gl,c;this.lastOpacity=1;this.lastTexture=null;this.currentOpacity=1;a.clearColor(0,0,0,0);a.clear(a.COLOR_BUFFER_BIT);a.enable(a.BLEND);a.blendFunc(a.ONE,a.ONE_MINUS_SRC_ALPHA);a.disable(a.CULL_FACE);a.disable(a.DEPTH_TEST);this.maxTextureSize=a.getParameter(a.MAX_TEXTURE_SIZE);this.lastSrcBlend=a.ONE;this.lastDestBlend=a.ONE_MINUS_SRC_ALPHA;this.pointBuffer=a.createBuffer();a.bindBuffer(a.ARRAY_BUFFER,this.pointBuffer);this.vertexBuffers=Array(4);this.texcoordBuffers=Array(4);for(c=0;4>c;c++)this.vertexBuffers[c]=a.createBuffer(),a.bindBuffer(a.ARRAY_BUFFER,this.vertexBuffers[c]),this.texcoordBuffers[c]=a.createBuffer(),a.bindBuffer(a.ARRAY_BUFFER,this.texcoordBuffers[c]);this.curBuffer=0;this.indexBuffer=a.createBuffer();a.bindBuffer(a.ELEMENT_ARRAY_BUFFER,this.indexBuffer);this.vertexData=new Float32Array(16E3);this.texcoordData=new Float32Array(16E3);this.pointData=new Float32Array(32E3);for(var f=new Uint16Array(12E3),b=c=0;12E3>c;)f[c++]=b,f[c++]=b+1,f[c++]=b+2,f[c++]=b,f[c++]=b+2,f[c++]=b+3,b+=4;a.bufferData(a.ELEMENT_ARRAY_BUFFER,f,a.STATIC_DRAW);this.pointPtr=this.vertexPtr=0;this.shaderPrograms=[];c=this.createShaderProgram({src:"varying mediump vec2 vTex;\nuniform lowp float opacity;\nuniform lowp sampler2D samplerFront;\nvoid main(void) {\n\tgl_FragColor = texture2D(samplerFront, vTex);\n\tgl_FragColor *= opacity;\n}"},"attribute highp vec2 aPos;\nattribute mediump vec2 aTex;\nvarying mediump vec2 vTex;\nuniform highp mat4 matP;\nuniform highp mat4 matMV;\nvoid main(void) {\n\tgl_Position = matP * matMV * vec4(aPos.x, aPos.y, 0.0, 1.0);\n\tvTex = aTex;\n}","");this.shaderPrograms.push(c);c=this.createShaderProgram({src:"uniform mediump sampler2D samplerFront;\nvarying lowp float opacity;\nvoid main(void) {\n\tgl_FragColor = texture2D(samplerFront, gl_PointCoord);\n\tgl_FragColor *= opacity;\n}"},"attribute vec4 aPos;\nvarying float opacity;\nuniform mat4 matP;\nuniform mat4 matMV;\nvoid main(void) {\n\tgl_Position = matP * matMV * vec4(aPos.x, aPos.y, 0.0, 1.0);\n\tgl_PointSize = aPos.z;\n\topacity = aPos.w;\n}","");this.shaderPrograms.push(c);for(var l in cr.shaders)cr.shaders.hasOwnProperty(l)&&this.shaderPrograms.push(this.createShaderProgram(cr.shaders[l],"attribute highp vec2 aPos;\nattribute mediump vec2 aTex;\nvarying mediump vec2 vTex;\nuniform highp mat4 matP;\nuniform highp mat4 matMV;\nvoid main(void) {\n\tgl_Position = matP * matMV * vec4(aPos.x, aPos.y, 0.0, 1.0);\n\tvTex = aTex;\n}",l));a.activeTexture(a.TEXTURE0);a.bindTexture(a.TEXTURE_2D,null);this.batch=[];this.batchPtr=0;this.hasPointBatchTop=this.hasQuadBatchTop=!1;this.currentProgram=this.lastProgram=-1;this.currentShader=null;this.fbo=a.createFramebuffer();this.renderToTex=null;this.tmpVec3=vec3.create([0,0,0]);a=a.getParameter(a.ALIASED_POINT_SIZE_RANGE);this.minPointSize=a[0];this.maxPointSize=a[1];this.switchProgram(0);cr.seal(this)};a.prototype.createShaderProgram=function(a,c,f){var d=this.gl,l=d.createShader(d.FRAGMENT_SHADER);d.shaderSource(l,a.src);d.compileShader(l);if(!d.getShaderParameter(l,d.COMPILE_STATUS))return d.deleteShader(l),null;var e=d.createShader(d.VERTEX_SHADER);d.shaderSource(e,c);d.compileShader(e);if(!d.getShaderParameter(e,d.COMPILE_STATUS))return d.deleteShader(l),d.deleteShader(e),null;c=d.createProgram();d.attachShader(c,l);d.attachShader(c,e);d.linkProgram(c);if(!d.getProgramParameter(c,d.LINK_STATUS))return d.deleteShader(l),d.deleteShader(e),d.deleteProgram(c),null;d.useProgram(c);d.validateProgram(c);d.deleteShader(l);d.deleteShader(e);f=new b(d,c,f);f.extendBoxHorizontal=a.extendBoxHorizontal||0;f.extendBoxVertical=a.extendBoxVertical||0;f.crossSampling=!!a.crossSampling;f.animated=!!a.animated;f.parameters=a.parameters||[];a=0;for(l=f.parameters.length;ac;c++)if(this.lastMV[c]!==this.matMV[c]){a=!0;break}a&&(a=this.pushBatch(),a.type=5,a.mat4param?mat4.set(this.matMV,a.mat4param):a.mat4param=mat4.create(this.matMV),mat4.set(this.matMV,this.lastMV),this.hasPointBatchTop=this.hasQuadBatchTop=!1)};d.prototype.doSetTexture=function(){this.gl.bindTexture(this.gl.TEXTURE_2D,this.texParam)};d.prototype.doSetOpacity=function(){var a=this.opacityParam,c=this.glwrap;c.currentOpacity=a;c=c.currentShader;c.locOpacity&&this.gl.uniform1f(c.locOpacity,a)};d.prototype.doQuad=function(){this.gl.drawElements(this.gl.TRIANGLES,this.indexCount,this.gl.UNSIGNED_SHORT,2*this.startIndex)};d.prototype.doSetBlend=function(){this.gl.blendFunc(this.startIndex,this.indexCount)};d.prototype.doUpdateModelView=function(){var a,c,f,b=this.glwrap.shaderPrograms,l=this.glwrap.currentProgram;a=0;for(c=b.length;a"===c.name)&&a.vertexAttribPointer(c.locAPos,4,a.FLOAT,!1,0,0));if(0"!==c.name)&&a.vertexAttribPointer(c.locAPos,2,a.FLOAT,!1,0,0);a.bindBuffer(a.ARRAY_BUFFER,this.texcoordBuffers[this.curBuffer]);a.bufferData(a.ARRAY_BUFFER,this.texcoordData.subarray(0,this.vertexPtr),a.STREAM_DRAW);c&&(0<=c.locATex&&""!==c.name)&&a.vertexAttribPointer(c.locATex,2,a.FLOAT,!1,0,0)}for(var f,a=0,c=this.batchPtr;am?(m*=g,5===e?(e=m/this.original_width,1e&&(e=1/Math.ceil(1/e)),m=this.original_width*e,d=this.original_height*e,b=(a-m)/2,s=(g-d)/2,a=m,g=d):(b=(a-m)/2,a=m)):(d=a/m,5===e?(e=d/this.original_height,1e&&(e=1/Math.ceil(1/e)),m=this.original_width*e,d=this.original_height*e,b=(a-m)/2,s=(g-d)/2,a=m):s=(g-d)/2,g=d),l&&!this.isNodeWebkit&&(s=b=0),b=Math.floor(b),s=Math.floor(s),a=Math.floor(a),g=Math.floor(g)):this.isNodeWebkit&&(this.isNodeFullscreen&&0===this.fullscreen_mode_set)&&(b=Math.floor((a-this.original_width)/2),s=Math.floor((g-this.original_height)/2),a=this.original_width,g=this.original_height);this.isRetina&&(this.isiPad&&1=s)s=5E4;a+=s;this.wait_for_textures[c].complete||this.wait_for_textures[c].loaded?g+=s:f=!1}this.progress=0==a?0:g/a;return f};a.prototype.go=function(){if(this.ctx||this.glwrap){var a=this.ctx||this.overlay_ctx;this.overlay_canvas&&this.positionOverlayCanvas();this.progress=0;this.last_progress=-1;if(this.areAllTexturesLoaded())this.go_textures_done();else{var g=Date.now()-this.start_time,c=1;this.isTizen&&(c=this.devicePixelRatio);if(a){if(3!==this.loaderstyle&&500<=g&&this.last_progress!=this.progress){a.clearRect(0,0,this.width,this.height);var g=this.width/(2*c),c=this.height/(2*c),f=0===this.loaderstyle&&this.loaderlogo.complete,b=40,s=0,m=80;f&&(m=this.loaderlogo.width,b=m/2,s=this.loaderlogo.height/2,a.drawImage(this.loaderlogo,cr.floor(g-b),cr.floor(c-s)));1>=this.loaderstyle?(c+=s+(f?12:0),g=cr.floor(g-b)+0.5,c=cr.floor(c)+0.5,a.fillStyle="DodgerBlue",a.fillRect(g,c,Math.floor(m*this.progress),6),a.strokeStyle="black",a.strokeRect(g,c,m,6),a.strokeStyle="white",a.strokeRect(g-1,c-1,m+2,8)):2===this.loaderstyle&&(a.font="12pt Arial",a.fillStyle="#999",a.textBaseLine="middle",f=Math.round(100*this.progress)+"%",b=a.measureText?a.measureText(f):null,a.fillText(f,g-(b?b.width:0)/2,c))}this.last_progress=this.progress}setTimeout(function(a){return function(){a.go()}}(this),100)}}};a.prototype.go_textures_done=function(){this.overlay_canvas&&(this.canvas.parentNode.removeChild(this.overlay_canvas),this.overlay_canvas=this.overlay_ctx=null);this.start_time=Date.now();this.last_fps_time=cr.performance_now();var a,g,c;if(this.uses_loader_layout)for(a=0,g=this.types_by_index.length;aa||2===this.fullscreen_mode&&gg||2===f&&ca++;)this.doChangeLayout(this.changelayout);a=0;for(g=this.eventsheets_by_index.length;ag.deadCache.length&&g.deadCache.push(a);g.stale_iids=!0}this.deathRow.isEmpty()||(this.redraw=!0);this.deathRow.clear();this.isInClearDeathRow=!1};a.prototype.createInstance=function(a,g,c,f){if(a.is_family){var b=cr.floor(Math.random()*a.members.length);return this.createInstance(a.members[b],g,c,f)}return a.default_instance?this.createInstanceFromInit(a.default_instance,g,!1,c,f,!1):null};var r=[];a.prototype.createInstanceFromInit=function(a,g,c,f,b,s){var m,d,e,l;if(!a)return null;var h=this.types_by_index[a[1]],k=h.plugin.is_world;if(this.isloading&&k&&!h.isOnLoaderLayout||k&&!this.glwrap&&11===a[0][11])return null;var t=g;k||(g=null);var q;h.deadCache.length?(q=h.deadCache.pop(),q.recycled=!0,h.plugin.Instance.call(q,h)):(q=new h.plugin.Instance(h),q.recycled=!1);q.uid=c&&!s?a[2]:this.next_uid++;this.objectsByUid[q.uid.toString()]=q;q.puid=this.next_puid++;q.iid=0;q.get_iid=cr.inst_get_iid;h.stale_iids=!0;e=a[3];if(q.recycled)cr.wipe(q.extra);else{q.extra={};if("undefined"!==typeof cr_is_preview)for(q.instance_var_names=[],q.instance_var_names.length=e.length,m=0,d=e.length;ma&&(a=0);a>=this.running_layout.layers.length&&(a=this.running_layout.layers.length-1);return this.running_layout.layers[a]};a.prototype.getLayer=function(a){return cr.is_number(a)?this.getLayerByNumber(a):this.getLayerByName(a.toString())};a.prototype.clearSol=function(a){var g,c;g=0;for(c=a.length;gk;k++)if(t=e-k*n,a.x=c+Math.cos(t)*m,a.y=f+Math.sin(t)*m,a.set_bbox_changed(),!this.testOverlap(a,h)&&(h=b?null:this.testOverlapSolid(a),!h)){q=t;break}36===k&&(q=cr.clamp_angle(e+cr.PI));h=l;for(k=1;36>k;k++)if(t=e+k*n,a.x=c+Math.cos(t)*m,a.y=f+Math.sin(t)*m,a.set_bbox_changed(),!this.testOverlap(a,h)&&(h=b?null:this.testOverlapSolid(a),!h)){r=t;break}36===k&&(r=cr.clamp_angle(e+cr.PI));a.x=d;a.y=s;a.set_bbox_changed();if(r===q)return r;a=cr.angleDiff(r,q)/2;a=cr.angleClockwise(r,q)?cr.clamp_angle(q+a+cr.PI):cr.clamp_angle(r+a);q=Math.cos(e);e=Math.sin(e);r=Math.cos(a);a=Math.sin(a);c=q*r+e*a;return cr.angleTo(0,0,q-2*c*r,e-2*c*a)};var v=[],t=-1;a.prototype.trigger=function(a,c,f){if(!this.running_layout)return!1;var b=this.running_layout.event_sheet;if(!b)return!1;t++;t===v.length?v.push(new cr.ObjectSet):v[t].clear();a=this.triggerOnSheet(a,c,b,f);t--;return a};a.prototype.triggerOnSheet=function(a,c,f,b){var d=v[t];if(d.contains(f))return!1;d.add(f);var d=f.includes.valuesRef(),s=!1,m,e,l;m=0;for(e=d.length;m=this.localvar_stack.length&&this.localvar_stack.push([])};a.prototype.popLocalVarStack=function(){this.localvar_stack_index--};a.prototype.getCurrentLocalVarStack=function(){return this.localvar_stack[this.localvar_stack_index]};a.prototype.pushEventStack=function(a){this.event_stack_index++;this.event_stack_index>=this.event_stack.length&&this.event_stack.push(new cr.eventStackFrame);var c=this.getCurrentEventStack();c.reset(a);return c};a.prototype.popEventStack=function(){this.event_stack_index--};a.prototype.getCurrentEventStack=function(){return this.event_stack[this.event_stack_index]};a.prototype.pushLoopStack=function(a){this.loop_stack_index++;this.loop_stack_index>=this.loop_stack.length&&this.loop_stack.push(cr.seal({name:a,index:0,stopped:!1}));var c=this.getCurrentLoop();c.name=a;c.index=0;c.stopped=!1;return c};a.prototype.popLoopStack=function(){this.loop_stack_index--};a.prototype.getCurrentLoop=function(){return this.loop_stack[this.loop_stack_index]};a.prototype.getEventVariableByName=function(a,c){for(var f,b,d,s,m,e;c;){f=0;for(b=c.subevents.length;fe||e>=a.instance_vars.length||(a.instance_vars[e]=b[f]));if(d.is_world){e=c.w;a.layer.sid!==e.l&&(b=a.layer,a.layer=this.running_layout.getLayerBySid(e.l),a.layer?(a.layer.instances.push(a),a.layer.zindices_stale=!0,cr.arrayFindRemove(b.instances,a),b.zindices_stale=!0):(a.layer=b,this.DestroyInstance(a)));a.x=e.x;a.y=e.y;a.width=e.w;a.height=e.h;a.zindex=e.zi;a.angle=e.hasOwnProperty("a")?e.a:0;a.opacity=e.hasOwnProperty("o")?e.o:1;a.hotspotX=e.hasOwnProperty("hX")?e.hX:0.5;a.hotspotY=e.hasOwnProperty("hY")?e.hY:0.5;a.visible=e.hasOwnProperty("v")?e.v:!0;a.collisionsEnabled=e.hasOwnProperty("ce")?e.ce:!0;a.my_timescale=e.hasOwnProperty("mts")?e.mts:-1;a.blend_mode=e.hasOwnProperty("bm")?e.bm:0;a.compositeOp=cr.effectToCompositeOp(a.blend_mode);this.gl&&cr.setGLBlend(a,a.blend_mode,this.gl);a.set_bbox_changed();if(e.hasOwnProperty("fx"))for(b=0,d=e.fx.length;bm||(a.active_effect_flags[m]=e.fx[b].active,a.effect_params[m]=e.fx[b].params);a.updateActiveEffects()}if(l=c.behs)for(f in l)l.hasOwnProperty(f)&&(e=this.getBehaviorIndexBySid(a,parseInt(f,10)),0>e||a.behavior_insts[e].loadFromJSON(l[f]));c.data&&a.loadFromJSON(c.data)};cr.runtime=a;cr.createRuntime=function(c){return new a(document.getElementById(c))};cr.createDCRuntime=function(c,f){return new a({dc:!0,width:c,height:f})};window.cr_createRuntime=cr.createRuntime;window.cr_createDCRuntime=cr.createDCRuntime;window.createCocoonJSRuntime=function(){window.c2cocoonjs=!0;var c=document.createElement("screencanvas")||document.createElement("canvas");document.body.appendChild(c);c=new a(c);window.c2runtime=c;window.addEventListener("orientationchange",function(){window.c2runtime.setSize(window.innerWidth,window.innerHeight)});window.c2runtime.setSize(window.innerWidth,window.innerHeight);return c}})();window.cr_getC2Runtime=function(){var a=document.getElementById("c2canvas");return a?a.c2runtime:window.c2runtime?window.c2runtime:null};window.cr_sizeCanvas=function(a,b){if(0!==a&&0!==b){var d=window.cr_getC2Runtime();d&&d.setSize(a,b)}};window.cr_setSuspended=function(a){var b=window.cr_getC2Runtime();b&&b.setSuspended(a)};(function(){function a(a,b){this.runtime=a;this.event_sheet=null;this.scrollX=this.runtime.original_width/2;this.scrollY=this.runtime.original_height/2;this.scale=1;this.angle=0;this.first_visit=!0;this.name=b[0];this.width=b[1];this.height=b[2];this.unbounded_scrolling=b[3];this.sheetname=b[4];this.sid=b[5];var d=b[6],c,e;this.layers=[];this.initial_types=[];c=0;for(e=d.length;c=this.layers.length&&(q=this.layers.length-1);n.layer=this.layers[q];n.layer.instances.push(n);n.layer.zindices_stale=!0}e.length=0;this.boundScrolling();a=0;for(k=this.layers.length;ak?n.siblings.push(l.instances[k]):l.default_instance&&(r=this.runtime.createInstanceFromInit(l.default_instance,n.layer,!0,n.x,n.y,!0),this.runtime.ClearDeathRow(),l.updateIIDs(),n.siblings.push(r),e.push(r)));a=0;for(k=this.initial_nonworld.length;a=this.active_effect_types.length?(1===this.active_effect_types.length?(b=this.active_effect_types[0].index,a.switchProgram(this.active_effect_types[0].shaderindex),a.setProgramParameters(null,1/this.runtime.width,1/this.runtime.height,0,0,1,1,this.scale,this.effect_params[b]),a.programIsAnimated(this.active_effect_types[0].shaderindex)&&(this.runtime.redraw=!0)):a.switchProgram(0),a.setRenderingToTexture(null),a.setOpacity(1),a.setTexture(this.runtime.layout_tex),a.setAlphaBlend(),a.resetModelView(),a.updateModelView(),b=this.runtime.width/2,d=this.runtime.height/2,a.quad(-b,d,b,d,b,-d,-b,-d),a.setTexture(null)):this.renderEffectChain(a,null,null,null));a.present()};a.prototype.getRenderTarget=function(){return 0this.width-b&&(a=this.width-b);athis.height-b&&(a=this.height-b);aG&&(G=0);0>F&&(F=0);H>B&&(H=B);w>s&&(w=s);0>C&&(C=0);0>y&&(y=0);Q>B&&(Q=B);N>s&&(N=s);x.left=G/B;x.top=1-F/s;x.right=H/B;x.bottom=1-w/s}else x.left=z.left=0,x.top=z.top=0,x.right=z.right=1,x.bottom=z.bottom=1;R=d&&((d.angle||W)&&a.programUsesDest(e[0].shaderindex)||0!==t||0!==R||1!==d.opacity||d.type.plugin.must_predraw)||b&&!d&&1!==b.opacity;a.setAlphaBlend();if(R){l[g]||(l[g]=a.createEmptyTexture(B,s,this.runtime.linearSampling));if(l[g].c2width!==B||l[g].c2height!==s)a.deleteTexture(l[g]),l[g]=a.createEmptyTexture(B,s,this.runtime.linearSampling);a.switchProgram(0);a.setRenderingToTexture(l[g]);D=N-y;a.clearRect(C,s-y-D,Q-C,D);d?d.drawGL(a):(a.setTexture(this.runtime.layer_tex),a.setOpacity(b.opacity),a.resetModelView(),a.translate(-m,-P),a.updateModelView(),a.quadTex(G,w,H,w,H,F,G,F,x));z.left=z.top=0;z.right=z.bottom=1;d&&(p=x.top,x.top=x.bottom,x.bottom=p);g=1;u=0}a.setOpacity(1);t=e.length-1;var W=a.programUsesCrossSampling(e[t].shaderindex),U=0;q=0;for(v=e.length;qthis.viewRight||l.top>this.viewBottom)||(d.globalCompositeOperation=n.compositeOp,n.draw(d)));d.restore();this.render_offscreen&&(a.globalCompositeOperation=this.compositeOp,a.globalAlpha=this.opacity,a.drawImage(b,0,0))};b.prototype.rotateViewport=function(a,b,d){var c=this.getScale();this.viewLeft=a;this.viewTop=b;this.viewRight=a+this.runtime.width*(1/c);this.viewBottom=b+this.runtime.height*(1/c);a=this.getAngle();0!==a&&(d&&(d.translate(this.runtime.width/2,this.runtime.height/2),d.rotate(-a),d.translate(this.runtime.width/-2,this.runtime.height/-2)),this.tmprect.set(this.viewLeft,this.viewTop,this.viewRight,this.viewBottom),this.tmprect.offset((this.viewLeft+this.viewRight)/-2,(this.viewTop+this.viewBottom)/-2),this.tmpquad.set_from_rotated_rect(this.tmprect,a),this.tmpquad.bounding_box(this.tmprect),this.tmprect.offset((this.viewLeft+this.viewRight)/2,(this.viewTop+this.viewBottom)/2),this.viewLeft=this.tmprect.left,this.viewTop=this.tmprect.top,this.viewRight=this.tmprect.right,this.viewBottom=this.tmprect.bottom)};b.prototype.drawGL=function(a){var b=this.runtime.width,d=this.runtime.height,c=0,e=0;if(this.render_offscreen=this.forceOwnTexture||1!==this.opacity||0this.viewRight||c.top>this.viewBottom)))if(v.uses_shaders)if(c=v.active_effect_types[0].shaderindex,e=v.active_effect_types[0].index,1!==v.active_effect_types.length||a.programUsesCrossSampling(c)||a.programExtendsBox(c)||(v.angle||v.layer.getAngle())&&a.programUsesDest(c)||1!==v.opacity||v.type.plugin.must_predraw)this.layout.renderEffectChain(a,this,v,this.render_offscreen?this.runtime.layer_tex:this.layout.getRenderTarget()),a.resetModelView(),a.scale(n,n),a.rotateZ(-this.getAngle()),a.translate((this.viewLeft+this.viewRight)/-2,(this.viewTop+this.viewBottom)/-2),a.updateModelView();else{a.switchProgram(c);a.setBlend(v.srcBlend,v.destBlend);a.programIsAnimated(c)&&(this.runtime.redraw=!0);var t=0,p=0,g=0,u=0;a.programUsesDest(c)&&(c=v.bbox,t=this.layerToCanvas(c.left,c.top,!0),p=this.layerToCanvas(c.left,c.top,!1),g=this.layerToCanvas(c.right,c.bottom,!0),c=this.layerToCanvas(c.right,c.bottom,!1),t/=b,p=1-p/d,g/=b,u=1-c/d);a.setProgramParameters(this.render_offscreen?this.runtime.layer_tex:this.layout.getRenderTarget(),1/v.width,1/v.height,t,p,g,u,this.getScale(),v.effect_params[e]);v.drawGL(a)}else a.switchProgram(0),a.setBlend(v.srcBlend,v.destBlend),v.drawGL(a);this.render_offscreen&&(c=this.active_effect_types.length?this.active_effect_types[0].shaderindex:0,e=this.active_effect_types.length?this.active_effect_types[0].index:0,0===this.active_effect_types.length||1===this.active_effect_types.length&&!a.programUsesCrossSampling(c)&&1===this.opacity?(1===this.active_effect_types.length?(a.switchProgram(c),a.setProgramParameters(this.layout.getRenderTarget(),1/this.runtime.width,1/this.runtime.height,0,0,1,1,this.getScale(),this.effect_params[e]),a.programIsAnimated(c)&&(this.runtime.redraw=!0)):a.switchProgram(0),a.setRenderingToTexture(this.layout.getRenderTarget()),a.setOpacity(this.opacity),a.setTexture(this.runtime.layer_tex),a.setBlend(this.srcBlend,this.destBlend),a.resetModelView(),a.updateModelView(),b=this.runtime.width/2,d=this.runtime.height/2,a.quad(-b,d,b,d,b,-d,-b,-d),a.setTexture(null)):this.layout.renderEffectChain(a,this,null,this.layout.getRenderTarget()))};b.prototype.canvasToLayer=function(a,b,d){var c=this.runtime.devicePixelRatio;this.runtime.isRetina&&0c[1].index&&(d=c[0],c[0]=c[1],c[1]=d):2=t.length&&(t.length=c.length+1);t[c.length]||(t[c.length]=[]);m=t[c.length];d=0;for(e=m.length;d=c.length&&(c.length=this.localIndex+1),c[this.localIndex]=a):this.data=a};l.prototype.getValue=function(){var a=this.runtime.getCurrentLocalVarStack();return!this.parent||this.is_static||!a||this.is_constant?this.data:this.localIndex>=a.length||"undefined"===typeof a[this.localIndex]?this.initial:a[this.localIndex]};l.prototype.run=function(){!this.parent||(this.is_static||this.is_constant)||this.setValue(this.initial)};cr.eventvariable=l;q.prototype.toString=function(){return"include:"+this.include_sheet.toString()};q.prototype.postInit=function(){this.include_sheet=this.runtime.eventsheets[this.include_sheet_name];this.sheet.includes.add(this);this.solModifiers=d(this.solModifiers)};q.prototype.run=function(){this.parent&&this.runtime.pushCleanSol(this.runtime.types_by_index);this.include_sheet.hasRun||this.include_sheet.run();this.parent&&this.runtime.popSol(this.runtime.types_by_index)};q.prototype.isActive=function(){for(var a=this.parent;a;){if(a.group&&!this.runtime.activeGroups[a.group_name.toLowerCase()])return!1;a=a.parent}return!0};cr.eventinclude=q;v.prototype.reset=function(a){this.current_event=a;this.actindex=this.cndindex=0;this.temp_parents_arr.length=0;this.else_branch_ran=this.last_event_true=!1};v.prototype.isModifierAfterCnds=function(){return this.current_event.solWriterAfterCnds?!0:this.cndindex=this.type&&(this.first=new cr.expNode(a,b[1]),this.second=new cr.expNode(a,b[2]));if(f){var h,k;h=0;for(k=f.length;hb&&(b+=f.length);f=f[b];-1b&&(b+=f.length);f=f[b].instance_vars[this.varindex];cr.is_string(f)?a.set_string(f):a.set_float(f);this.owner.popTempValue();return}this.owner.popTempValue()}b%=f.length;0>b&&(b+=f.length);f=f[b];b=0;this.object_type.is_family&&(b=f.type.family_var_map[this.object_type.family_index]);f=f.instance_vars[this.varindex+b];cr.is_string(f)?a.set_string(f):a.set_float(f)};a.prototype.eval_int=function(a){a.type=cr.exptype.Integer;a.data=this.value};a.prototype.eval_float=function(a){a.type=cr.exptype.Float;a.data=this.value};a.prototype.eval_string=function(a){a.type=cr.exptype.String;a.data=this.value};a.prototype.eval_unaryminus=function(a){this.first.get(a);a.is_number()&&(a.data=-a.data)};a.prototype.eval_add=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.is_number()&&b.is_number()&&(a.data+=b.data,b.is_float()&&a.make_float());this.owner.popTempValue()};a.prototype.eval_subtract=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.is_number()&&b.is_number()&&(a.data-=b.data,b.is_float()&&a.make_float());this.owner.popTempValue()};a.prototype.eval_multiply=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.is_number()&&b.is_number()&&(a.data*=b.data,b.is_float()&&a.make_float());this.owner.popTempValue()};a.prototype.eval_divide=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.is_number()&&b.is_number()&&(a.data/=b.data,a.make_float());this.owner.popTempValue()};a.prototype.eval_mod=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.is_number()&&b.is_number()&&(a.data%=b.data,b.is_float()&&a.make_float());this.owner.popTempValue()};a.prototype.eval_power=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.is_number()&&b.is_number()&&(a.data=Math.pow(a.data,b.data),b.is_float()&&a.make_float());this.owner.popTempValue()};a.prototype.eval_and=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.is_number()?b.is_string()?a.set_string(a.data.toString()+b.data):a.data&&b.data?a.set_int(1):a.set_int(0):a.is_string()&&(b.is_string()?a.data+=b.data:a.data+=(Math.round(1E10*b.data)/1E10).toString());this.owner.popTempValue()};a.prototype.eval_or=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.is_number()&&b.is_number()&&(a.data||b.data?a.set_int(1):a.set_int(0));this.owner.popTempValue()};a.prototype.eval_conditional=function(a){this.first.get(a);a.data?this.second.get(a):this.third.get(a)};a.prototype.eval_equal=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.set_int(a.data===b.data?1:0);this.owner.popTempValue()};a.prototype.eval_notequal=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.set_int(a.data!==b.data?1:0);this.owner.popTempValue()};a.prototype.eval_less=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.set_int(a.datab.data?1:0);this.owner.popTempValue()};a.prototype.eval_greaterequal=function(a){this.first.get(a);var b=this.owner.pushTempValue();this.second.get(b);a.set_int(a.data>=b.data?1:0);this.owner.popTempValue()};a.prototype.eval_eventvar_exp=function(a){var b=this.eventvar.getValue();cr.is_number(b)?a.set_float(b):a.set_string(b)};cr.expNode=a;b.prototype.is_int=function(){return this.type===cr.exptype.Integer};b.prototype.is_float=function(){return this.type===cr.exptype.Float};b.prototype.is_number=function(){return this.type===cr.exptype.Integer||this.type===cr.exptype.Float};b.prototype.is_string=function(){return this.type===cr.exptype.String};b.prototype.make_int=function(){this.is_int()||(this.is_float()?this.data=Math.floor(this.data):this.is_string()&&(this.data=parseInt(this.data,10)),this.type=cr.exptype.Integer)};b.prototype.make_float=function(){this.is_float()||(this.is_string()&&(this.data=parseFloat(this.data)),this.type=cr.exptype.Float)};b.prototype.make_string=function(){this.is_string()||(this.data=this.data.toString(),this.type=cr.exptype.String)};b.prototype.set_int=function(a){this.type=cr.exptype.Integer;this.data=Math.floor(a)};b.prototype.set_float=function(a){this.type=cr.exptype.Float;this.data=a};b.prototype.set_string=function(a){this.type=cr.exptype.String;this.data=a};b.prototype.set_any=function(a){cr.is_number(a)?(this.type=cr.exptype.Float,this.data=a):cr.is_string(a)?(this.type=cr.exptype.String,this.data=a.toString()):(this.type=cr.exptype.Integer,this.data=0)};cr.expvalue=b;cr.exptype={Integer:0,Float:1,String:2}})();cr.system_object=function(a){this.runtime=a;this.waits=[]};cr.system_object.prototype.saveToJSON=function(){var a={},b,d,e,f,h,k,c,r;a.waits=[];var n=a.waits,l;b=0;for(d=this.waits.length;bd?1:0}function d(a,b){n&&a===l&&b===q||(n=RegExp(a,b),l=a,q=b);n.lastIndex=0;return n}function e(){}function f(){}function h(a,b,c){if(a!==u||b!==D||c!==B){var e=d(b,c);g=a.match(e);u=a;D=b;B=c}}var k=cr.system_object.prototype;a.prototype.EveryTick=function(){return!0};a.prototype.OnLayoutStart=function(){return!0};a.prototype.OnLayoutEnd=function(){return!0};a.prototype.Compare=function(a,b,c){return cr.do_cmp(a,b,c)};a.prototype.CompareTime=function(a,b){var c=this.runtime.kahanTime.sum;if(0===a){var d=this.runtime.getCurrentCondition();return!d.extra.CompareTime_executed&&c>=b?d.extra.CompareTime_executed=!0:!1}return cr.do_cmp(c,a,b)};a.prototype.LayerVisible=function(a){return a?a.visible:!1};a.prototype.LayerCmpOpacity=function(a,b,c){return a?cr.do_cmp(100*a.opacity,b,c):!1};a.prototype.Repeat=function(a){var b=this.runtime.getCurrentEventStack(),c=b.current_event,d=b.isModifierAfterCnds(),b=this.runtime.pushLoopStack();if(d)for(d=0;d=c&&!a.stopped;--b)this.runtime.pushCopySol(e.solModifiers),a.index=b,e.retrigger(),this.runtime.popSol(e.solModifiers);else for(;b>=c&&!a.stopped;--b)a.index=b,e.retrigger();else if(d)for(;b<=c&&!a.stopped;++b)this.runtime.pushCopySol(e.solModifiers),a.index=b,e.retrigger(),this.runtime.popSol(e.solModifiers);else for(;b<=c&&!a.stopped;++b)a.index=b,e.retrigger();this.runtime.popLoopStack();return!1};var c=[],r=-1;a.prototype.ForEach=function(a){var b=a.getCurrentSol();r++;c.length===r&&c.push([]);var d=c[r];cr.shallowAssignArray(d,b.getObjects());var e=this.runtime.getCurrentEventStack(),f=e.current_event,g=e.isModifierAfterCnds(),e=this.runtime.pushLoopStack(),l,t,p,q,h,k,n=a.is_contained;if(g)for(g=0,l=d.length;g=c+e?(b.extra.Every_lastTime=c+e,d>=b.extra.Every_lastTime+e&&(b.extra.Every_lastTime=d),b.extra.Every_seconds=a,!0):!1};a.prototype.PickNth=function(a,b){if(!a)return!1;var c=a.getCurrentSol(),d=c.getObjects();b=cr.floor(b);if(0>b||b>=d.length)return!1;c.pick_one(d[b]);a.applySolToContainer();return!0};a.prototype.PickRandom=function(a){if(!a)return!1;var b=a.getCurrentSol(),c=b.getObjects(),d=cr.floor(Math.random()*c.length);if(d>=c.length)return!1;b.pick_one(c[d]);a.applySolToContainer();return!0};a.prototype.CompareVar=function(a,b,c){return cr.do_cmp(a.getValue(),b,c)};a.prototype.IsGroupActive=function(a){return this.runtime.activeGroups[a.toLowerCase()]};a.prototype.IsPreview=function(){return"undefined"!==typeof cr_is_preview};a.prototype.PickAll=function(a){if(!a||!a.instances.length)return!1;a.getCurrentSol().select_all=!0;a.applySolToContainer();return!0};a.prototype.IsMobile=function(){return this.runtime.isMobile};a.prototype.CompareBetween=function(a,b,c){return a>=b&&a<=c};a.prototype.Else=function(){var a=this.runtime.getCurrentEventStack();return a.else_branch_ran?!1:!a.last_event_true};a.prototype.OnLoadFinished=function(){return!0};a.prototype.OnCanvasSnapshot=function(){return!0};a.prototype.EffectsSupported=function(){return!!this.runtime.glwrap};a.prototype.OnSaveComplete=function(){return!0};a.prototype.OnLoadComplete=function(){return!0};a.prototype.OnLoadFailed=function(){return!0};a.prototype.ObjectUIDExists=function(a){return!!this.runtime.getObjectByUID(a)};a.prototype.IsOnPlatform=function(a){var b=this.runtime;switch(a){case 0:return!b.isDomFree&&!b.isNodeWebkit&&!b.isPhoneGap&&!b.isWindows8App&&!b.isWindowsPhone8&&!b.isBlackberry10;case 1:return b.isiOS;case 2:return b.isAndroid;case 3:return b.isWindows8App;case 4:return b.isWindowsPhone8;case 5:return b.isBlackberry10;case 6:return b.isTizen;case 7:return b.isNodeWebkit;case 8:return b.isCocoonJs;case 9:return b.isPhoneGap;case 10:return b.isArcade;case 11:return b.isNodeWebkit;default:return!1}};var n=null,l="",q="";a.prototype.RegexTest=function(a,b,c){return d(b,c).test(a)};var v=[];a.prototype.PickOverlappingPoint=function(a,b,c){if(!a)return!1;var d=a.getCurrentSol(),e=d.getObjects(),f=this.runtime.getCurrentEventStack().current_event.orblock,g=this.runtime.getCurrentCondition(),l,t;d.select_all?(cr.shallowAssignArray(v,e),d.else_instances.length=0,d.select_all=!1,d.instances.length=0):f?(cr.shallowAssignArray(v,d.else_instances),d.else_instances.length=0):(cr.shallowAssignArray(v,e),d.instances.length=0);e=0;for(f=v.length;ea&&(a=0);this.runtime.timescale=a};e.prototype.SetObjectTimescale=function(a,b){var c=b;0>c&&(c=0);if(a){var d=a.getCurrentSol().getObjects(),e,f;e=0;for(f=d.length;ea)){var b,c,d,e=this.runtime.getCurrentEventStack(),f;f=t.length?t.pop():{sols:{},solModifiers:[]};f.deleteme=!1;f.time=this.runtime.kahanTime.sum+a;f.ev=e.current_event;f.actindex=e.actindex+1;a=0;for(b=this.runtime.types_by_index.length;athis.runtime.loop_stack_index||(this.runtime.getCurrentLoop().stopped=!0)};e.prototype.GoToLayoutByName=function(a){if(!this.runtime.isloading&&!this.runtime.changelayout)for(var b in this.runtime.layouts)if(this.runtime.layouts.hasOwnProperty(b)&&cr.equals_nocase(b,a)){this.runtime.changelayout=this.runtime.layouts[b];break}};e.prototype.RestartLayout=function(a){if(!this.runtime.isloading&&!this.runtime.changelayout&&this.runtime.running_layout){this.runtime.changelayout=this.runtime.running_layout;var b,c;a=0;for(b=this.runtime.allGroups.length;a=a||0>=b||this.runtime.setSize(a,b)};e.prototype.SetLayoutEffectEnabled=function(a,b){if(this.runtime.running_layout&&this.runtime.glwrap){var c=this.runtime.running_layout.getEffectByName(b);if(c){var d=1===a;c.active!=d&&(c.active=d,this.runtime.running_layout.updateActiveEffects(),this.runtime.redraw=!0)}}};e.prototype.SetLayerEffectEnabled=function(a,b,c){a&&this.runtime.glwrap&&(c=a.getEffectByName(c))&&(b=1===b,c.active!=b&&(c.active=b,a.updateActiveEffects(),this.runtime.redraw=!0))};e.prototype.SetLayoutEffectParam=function(a,b,c){if(this.runtime.running_layout&&this.runtime.glwrap&&(a=this.runtime.running_layout.getEffectByName(a))){var d=this.runtime.running_layout.effect_params[a.index];b=Math.floor(b);0>b||b>=d.length||(1===this.runtime.glwrap.getProgramParameterType(a.shaderindex,b)&&(c/=100),d[b]!==c&&(d[b]=c,a.active&&(this.runtime.redraw=!0)))}};e.prototype.SetLayerEffectParam=function(a,b,c,d){a&&this.runtime.glwrap&&(b=a.getEffectByName(b))&&(a=a.effect_params[b.index],c=Math.floor(c),0>c||c>=a.length||(1===this.runtime.glwrap.getProgramParameterType(b.shaderindex,c)&&(d/=100),a[c]!==d&&(a[c]=d,b.active&&(this.runtime.redraw=!0))))};e.prototype.SaveState=function(a){this.runtime.saveToSlot=a};e.prototype.LoadState=function(a){this.runtime.loadFromSlot=a};e.prototype.LoadStateJSON=function(a){this.runtime.loadFromJson=a};k.acts=new e;f.prototype["int"]=function(a,b){cr.is_string(b)?(a.set_int(parseInt(b,10)),isNaN(a.data)&&(a.data=0)):a.set_int(b)};f.prototype["float"]=function(a,b){cr.is_string(b)?(a.set_float(parseFloat(b)),isNaN(a.data)&&(a.data=0)):a.set_float(b)};f.prototype.str=function(a,b){cr.is_string(b)?a.set_string(b):a.set_string(b.toString())};f.prototype.len=function(a,b){a.set_int(b.length||0)};f.prototype.random=function(a,b,c){void 0===c?a.set_float(Math.random()*b):a.set_float(Math.random()*(c-b)+b)};f.prototype.sqrt=function(a,b){a.set_float(Math.sqrt(b))};f.prototype.abs=function(a,b){a.set_float(Math.abs(b))};f.prototype.round=function(a,b){a.set_int(Math.round(b))};f.prototype.floor=function(a,b){a.set_int(Math.floor(b))};f.prototype.ceil=function(a,b){a.set_int(Math.ceil(b))};f.prototype.sin=function(a,b){a.set_float(Math.sin(cr.to_radians(b)))};f.prototype.cos=function(a,b){a.set_float(Math.cos(cr.to_radians(b)))};f.prototype.tan=function(a,b){a.set_float(Math.tan(cr.to_radians(b)))};f.prototype.asin=function(a,b){a.set_float(cr.to_degrees(Math.asin(b)))};f.prototype.acos=function(a,b){a.set_float(cr.to_degrees(Math.acos(b)))};f.prototype.atan=function(a,b){a.set_float(cr.to_degrees(Math.atan(b)))};f.prototype.exp=function(a,b){a.set_float(Math.exp(b))};f.prototype.ln=function(a,b){a.set_float(Math.log(b))};f.prototype.log10=function(a,b){a.set_float(Math.log(b)/Math.LN10)};f.prototype.max=function(a){var b=arguments[1],c,d;c=2;for(d=arguments.length;carguments[c]&&(b=arguments[c]);a.set_float(b)};f.prototype.dt=function(a){a.set_float(this.runtime.dt)};f.prototype.timescale=function(a){a.set_float(this.runtime.timescale)};f.prototype.wallclocktime=function(a){a.set_float((Date.now()-this.runtime.start_time)/1E3)};f.prototype.time=function(a){a.set_float(this.runtime.kahanTime.sum)};f.prototype.tickcount=function(a){a.set_int(this.runtime.tickcount)};f.prototype.objectcount=function(a){a.set_int(this.runtime.objectcount)};f.prototype.fps=function(a){a.set_int(this.runtime.fps)};f.prototype.loopindex=function(a,b){var c,d,e;if(this.runtime.loop_stack.length)if(b){d=0;for(e=this.runtime.loop_stack.length;dd?a.set_float(d):a.set_float(b)};f.prototype.layerscale=function(a,b){var c=this.runtime.getLayer(b);c?a.set_float(c.scale):a.set_float(0)};f.prototype.layeropacity=function(a,b){var c=this.runtime.getLayer(b);c?a.set_float(100*c.opacity):a.set_float(0)};f.prototype.layerscalerate=function(a,b){var c=this.runtime.getLayer(b);c?a.set_float(c.zoomRate):a.set_float(0)};f.prototype.layerparallaxx=function(a,b){var c=this.runtime.getLayer(b);c?a.set_float(100*c.parallaxX):a.set_float(0)};f.prototype.layerparallaxy=function(a,b){var c=this.runtime.getLayer(b);c?a.set_float(100*c.parallaxY):a.set_float(0)};f.prototype.layoutscale=function(a){this.runtime.running_layout?a.set_float(this.runtime.running_layout.scale):a.set_float(0)};f.prototype.layoutangle=function(a){a.set_float(cr.to_degrees(this.runtime.running_layout.angle))};f.prototype.layerangle=function(a,b){var c=this.runtime.getLayer(b);c?a.set_float(cr.to_degrees(c.angle)):a.set_float(0)};f.prototype.layoutwidth=function(a){a.set_int(this.runtime.running_layout.width)};f.prototype.layoutheight=function(a){a.set_int(this.runtime.running_layout.height)};f.prototype.find=function(a,b,c){cr.is_string(b)&&cr.is_string(c)?a.set_int(b.search(RegExp(cr.regexp_escape(c),"i"))):a.set_int(-1)};f.prototype.left=function(a,b,c){a.set_string(cr.is_string(b)?b.substr(0,c):"")};f.prototype.right=function(a,b,c){a.set_string(cr.is_string(b)?b.substr(b.length-c):"")};f.prototype.mid=function(a,b,c,d){a.set_string(cr.is_string(b)?b.substr(c,d):"")};f.prototype.tokenat=function(a,b,c,d){cr.is_string(b)&&cr.is_string(d)?(b=b.split(d),c=cr.floor(c),0>c||c>=b.length?a.set_string(""):a.set_string(b[c])):a.set_string("")};f.prototype.tokencount=function(a,b,c){cr.is_string(b)&&b.length?a.set_int(b.split(c).length):a.set_int(0)};f.prototype.replace=function(a,b,c,d){cr.is_string(b)&&cr.is_string(c)&&cr.is_string(d)?a.set_string(b.replace(RegExp(cr.regexp_escape(c),"gi"),d)):a.set_string(cr.is_string(b)?b:"")};f.prototype.trim=function(a,b){a.set_string(cr.is_string(b)?b.trim():"")};f.prototype.pi=function(a){a.set_float(cr.PI)};f.prototype.layoutname=function(a){this.runtime.running_layout?a.set_string(this.runtime.running_layout.name):a.set_string("")};f.prototype.renderer=function(a){a.set_string(this.runtime.gl?"webgl":"canvas2d")};f.prototype.anglediff=function(a,b,c){a.set_float(cr.to_degrees(cr.angleDiff(cr.to_radians(b),cr.to_radians(c))))};f.prototype.choose=function(a){var b=cr.floor(Math.random()*(arguments.length-1));a.set_any(arguments[b+1])};f.prototype.rgb=function(a,b,c,d){a.set_int(cr.RGB(b,c,d))};f.prototype.projectversion=function(a){a.set_string(this.runtime.versionstr)};f.prototype.anglelerp=function(a,b,c,d){b=cr.to_radians(b);c=cr.to_radians(c);var e=cr.angleDiff(b,c);cr.angleClockwise(c,b)?a.set_float(cr.to_clamped_degrees(b+e*d)):a.set_float(cr.to_clamped_degrees(b-e*d))};f.prototype.anglerotate=function(a,b,c,d){b=cr.to_radians(b);c=cr.to_radians(c);d=cr.to_radians(d);a.set_float(cr.to_clamped_degrees(cr.angleRotate(b,c,d)))};f.prototype.zeropad=function(a,b,c){var d=0>b?"-":"";0>b&&(b=-b);c-=b.toString().length;for(var e=0;ef||f>=g.length?a.set_string(""):a.set_string(g[f])};f.prototype.infinity=function(a){a.set_float(Infinity)};k.exps=new f;k.runWaits=function(){var a,b,c,d,e,f,g=this.runtime.getCurrentEventStack();a=0;for(c=this.waits.length;athis.runtime.kahanTime.sum)){g.current_event=d.ev;g.actindex=d.actindex;g.cndindex=0;for(b in d.sols)d.sols.hasOwnProperty(b)&&(e=this.runtime.types_by_index[parseInt(b,10)].getCurrentSol(),f=d.sols[b],e.select_all=f.sa,cr.shallowAssignArray(e.instances,f.insts),e=f,e.insts.length=0,p.push(e));d.ev.resume_actions_and_subevents();this.runtime.clearSol(d.solModifiers);d.deleteme=!0}b=a=0;for(c=this.waits.length;aa.viewRight||b.top>a.viewBottom)},r.IsOutsideLayout=function(){this.update_bbox();var a=this.bbox,b=this.runtime.running_layout;return 0>a.right||0>a.bottom||a.left>b.width||a.top>b.height},r.PickDistance=function(a,b,c){var d=this.getCurrentSol(),e=d.getObjects();if(!e.length)return!1;var f=e[0],h=f,k=cr.distanceTo(f.x,f.y,b,c),n,r,m;n=1;for(r=e.length;nk)k=m,h=f;d.pick_one(h);return!0},n.SetX=function(a){this.x!==a&&(this.x=a,this.set_bbox_changed())},n.SetY=function(a){this.y!==a&&(this.y=a,this.set_bbox_changed())},n.SetPos=function(a,b){if(this.x!==a||this.y!==b)this.x=a,this.y=b,this.set_bbox_changed()},n.SetPosToObject=function(a,b){var c=a.getPairedInstance(this);if(c){var d;c.getImagePoint?(d=c.getImagePoint(b,!0),c=c.getImagePoint(b,!1)):(d=c.x,c=c.y);if(this.x!==d||this.y!==c)this.x=d,this.y=c,this.set_bbox_changed()}},n.MoveForward=function(a){0!==a&&(this.x+=Math.cos(this.angle)*a,this.y+=Math.sin(this.angle)*a,this.set_bbox_changed())},n.MoveAtAngle=function(a,b){0!==b&&(this.x+=Math.cos(cr.to_radians(a))*b,this.y+=Math.sin(cr.to_radians(a))*b,this.set_bbox_changed())},b.X=function(a){a.set_float(this.x)},b.Y=function(a){a.set_float(this.y)},b.dt=function(a){a.set_float(this.runtime.getDt(this))});f&&(r.CompareWidth=function(a,b){return cr.do_cmp(this.width,a,b)},r.CompareHeight=function(a,b){return cr.do_cmp(this.height,a,b)},n.SetWidth=function(a){this.width!==a&&(this.width=a,this.set_bbox_changed())},n.SetHeight=function(a){this.height!==a&&(this.height=a,this.set_bbox_changed())},n.SetSize=function(a,b){if(this.width!==a||this.height!==b)this.width=a,this.height=b,this.set_bbox_changed()},b.Width=function(a){a.set_float(this.width)},b.Height=function(a){a.set_float(this.height)},b.BBoxLeft=function(a){this.update_bbox();a.set_float(this.bbox.left)},b.BBoxTop=function(a){this.update_bbox();a.set_float(this.bbox.top)},b.BBoxRight=function(a){this.update_bbox();a.set_float(this.bbox.right)},b.BBoxBottom=function(a){this.update_bbox();a.set_float(this.bbox.bottom)});h&&(r.AngleWithin=function(a,b){return cr.angleDiff(this.angle,cr.to_radians(b))<=cr.to_radians(a)},r.IsClockwiseFrom=function(a){return cr.angleClockwise(this.angle,cr.to_radians(a))},r.IsBetweenAngles=function(a,b){var c=cr.to_clamped_radians(a),d=cr.to_clamped_radians(b),e=cr.clamp_angle(this.angle);return cr.angleClockwise(d,c)?cr.angleClockwise(e,c)&&!cr.angleClockwise(e,d):!(!cr.angleClockwise(e,c)&&cr.angleClockwise(e,d))},n.SetAngle=function(a){a=cr.to_radians(cr.clamp_angle_degrees(a));isNaN(a)||this.angle===a||(this.angle=a,this.set_bbox_changed())},n.RotateClockwise=function(a){0===a||isNaN(a)||(this.angle+=cr.to_radians(a),this.angle=cr.clamp_angle(this.angle),this.set_bbox_changed())},n.RotateCounterclockwise=function(a){0===a||isNaN(a)||(this.angle-=cr.to_radians(a),this.angle=cr.clamp_angle(this.angle),this.set_bbox_changed())},n.RotateTowardAngle=function(a,b){var c=cr.angleRotate(this.angle,cr.to_radians(b),cr.to_radians(a));isNaN(c)||this.angle===c||(this.angle=c,this.set_bbox_changed())},n.RotateTowardPosition=function(a,b,c){b=Math.atan2(c-this.y,b-this.x);a=cr.angleRotate(this.angle,b,cr.to_radians(a));isNaN(a)||this.angle===a||(this.angle=a,this.set_bbox_changed())},n.SetTowardPosition=function(a,b){var c=Math.atan2(b-this.y,a-this.x);isNaN(c)||this.angle===c||(this.angle=c,this.set_bbox_changed())},b.Angle=function(a){a.set_float(cr.to_clamped_degrees(this.angle))});d||(r.CompareInstanceVar=function(a,b,c){return cr.do_cmp(this.instance_vars[a],b,c)},r.IsBoolInstanceVarSet=function(a){return this.instance_vars[a]},r.PickInstVarHiLow=function(a,b){var c=this.getCurrentSol(),d=c.getObjects();if(!d.length)return!1;var e=d[0],f=e,h=e.instance_vars[b],k,n,r;k=1;for(n=d.length;kh)h=r,f=e;c.pick_one(f);return!0},r.PickByUID=function(a){var b,c,d,e,f;if(this.runtime.getCurrentCondition().inverted){f=this.getCurrentSol();if(f.select_all)for(f.select_all=!1,f.instances.length=0,f.else_instances.length=0,d=this.instances,b=0,c=d.length;ba?a=0:1e.layer.index||d.layer.index===e.layer.index&&d.get_zindex()>e.get_zindex())e=d}else if(d.layer.indexc)){var d=1===a;this.active_effect_flags[c]!==d&&(this.active_effect_flags[c]=d,this.updateActiveEffects(),this.runtime.redraw=!0)}}},n.SetEffectParam=function(a,b,c){if(this.runtime.glwrap){var d=this.type.getEffectIndexByName(a);0>d||(a=this.type.effect_types[d],d=this.effect_params[d],b=Math.floor(b),0>b||b>=d.length||(1===this.runtime.glwrap.getProgramParameterType(a.shaderindex,b)&&(c/=100),d[b]!==c&&(d[b]=c,a.active&&(this.runtime.redraw=!0))))}})};cr.set_bbox_changed=function(){this.bbox_changed=!0;this.runtime.redraw=!0;var a,b;a=0;for(b=this.bbox_changed_callbacks.length;athis.bbox.right&&(a=this.bbox.left,this.bbox.left=this.bbox.right,this.bbox.right=a);this.bbox.top>this.bbox.bottom&&(a=this.bbox.top,this.bbox.top=this.bbox.bottom,this.bbox.bottom=a);this.bbox_changed=!1}};cr.inst_contains_pt=function(a,b){return this.bbox.contains_pt(a,b)&&this.bquad.contains_pt(a,b)?this.collision_poly&&!this.collision_poly.is_empty()?(this.collision_poly.cache_poly(this.width,this.height,this.angle),this.collision_poly.contains_pt(a-this.x,b-this.y)):!0:!1};cr.inst_get_iid=function(){this.type.updateIIDs();return this.iid};cr.inst_get_zindex=function(){this.layer.updateZIndices();return this.zindex};cr.inst_updateActiveEffects=function(){this.active_effect_types.length=0;var a,b;a=0;for(b=this.active_effect_flags.length;ad;case 5:return a>=d;default:return!1}};cr.shaders={};cr.shaders.warpripple={src:"varying mediump vec2 vTex;\nuniform lowp sampler2D samplerFront;\nuniform mediump float seconds;\nuniform mediump float pixelWidth;\nuniform mediump float layerScale;\nuniform mediump float freq;\nuniform mediump float amp;\nuniform mediump float speed;\nconst mediump float PI = 3.1415926;\nvoid main(void)\n{\nmediump vec2 p = vTex;\nmediump vec2 tex = vTex * 2.0 - 1.0;\nmediump float d = length(tex);\nmediump float a = atan(tex.y, tex.x);\nd += sin((d * 2.0 * PI) * freq / layerScale / (pixelWidth * 750.0) + (seconds * speed)) * amp * (pixelWidth * 750.0) * layerScale;\ntex.x = cos(a) * d;\ntex.y = sin(a) * d;\ntex = (tex + 1.0) / 2.0;\ngl_FragColor = texture2D(samplerFront, tex);\n}",extendBoxHorizontal:50,extendBoxVertical:50,crossSampling:!1,animated:!0,parameters:[["freq",0,0],["amp",0,1],["speed",0,0]]};cr.plugins_.Audio=function(a){this.runtime=a};(function(){function a(a){a=Math.pow(10,a/20);0>a&&(a=0);1a&&(a=0);1b&&(b=0);1c&&(c=0);1b&&(b=0),1b&&(b=0);1b&&(b=0);1b&&(b=0);1b&&(b=0);1a&&(a=0.01);this.preGain.gain.value=a;this.postGain.gain.value=Math.pow(1/a,0.6)*b};D.prototype.shape=function(a,b,c){var d=1.05*c*b-b;c=0>a?-1:1;a=0>a?-a:a;b=af;++f)e=f/32768,e=this.shape(e,c,d),this.curve[32768+f]=e,this.curve[32768-f-1]=-e};D.prototype.connectTo=function(a){this.wetNode.disconnect();this.wetNode.connect(a);this.dryNode.disconnect();this.dryNode.connect(a)};D.prototype.remove=function(){this.inputNode.disconnect();this.preGain.disconnect();this.waveShaper.disconnect();this.postGain.disconnect();this.wetNode.disconnect();this.dryNode.disconnect()};D.prototype.getInputNode=function(){return this.inputNode};D.prototype.setParam=function(a,b,c,d){switch(a){case 0:b/=100,0>b&&(b=0),1e&&(e=-e),this.peakthis.speeds.length||this.speeds.shift(),this.speeds.push(a),this.lastX=this.obj.x,this.lastY=this.obj.y)};m.prototype.getSpeed=function(){if(!this.speeds.length)return 0;var a,b,c=0;a=0;for(b=this.speeds.length;athis.buffer.bufferObject.duration:this.instanceObject.ended;case V:return this.pgended;case aa:!0}return!0};x.prototype.canBeRecycled=function(){return this.fresh||this.stopped?!0:this.hasEnded()};x.prototype.setPannerEnabled=function(a){J===E&&(!this.pannerEnabled&&a?(this.pannerNode||(this.pannerNode=I.createPanner(),this.pannerNode.panningModel="number"===typeof this.pannerNode.panningModel?ha:["equalpower","HRTF","soundfield"][ha],this.pannerNode.distanceModel="number"===typeof this.pannerNode.distanceModel?ia:["linear","inverse","exponential"][ia],this.pannerNode.refDistance=ka,this.pannerNode.maxDistance=la,this.pannerNode.rolloffFactor=ma),this.gainNode.disconnect(),this.gainNode.connect(this.pannerNode),this.pannerNode.connect(d(this.tag)),this.pannerEnabled=!0):this.pannerEnabled&&!a&&(this.pannerNode.disconnect(),this.gainNode.disconnect(),this.gainNode.connect(d(this.tag)),this.pannerEnabled=!1))};x.prototype.setPan=function(a,b,c,d,e,f){this.pannerEnabled&&J===E&&(this.pannerNode.setPosition(a,b,0),this.pannerNode.setOrientation(Math.cos(cr.to_radians(c)),Math.sin(cr.to_radians(c)),0),this.pannerNode.coneInnerAngle=d,this.pannerNode.coneOuterAngle=e,this.pannerNode.coneOuterGain=f,this.panX=a,this.panY=b,this.panAngle=c,this.panConeInner=d,this.panConeOuter=e,this.panConeOuterGain=f)};x.prototype.setObject=function(a){this.pannerEnabled&&J===E&&(this.objectTracker||(this.objectTracker=new m),this.objectTracker.setObject(a))};x.prototype.tick=function(a){if(this.pannerEnabled&&J===E&&this.objectTracker&&this.objectTracker.hasObject()&&this.isPlaying()){this.objectTracker.tick(a);a=this.objectTracker.obj;var b=cr.rotatePtAround(a.x,a.y,-a.layer.getAngle(),Z,$,!0),c=cr.rotatePtAround(a.x,a.y,-a.layer.getAngle(),Z,$,!1);this.pannerNode.setPosition(b,c,0);b=0;"undefined"!==typeof this.objectTracker.obj.angle&&(b=a.angle-a.layer.getAngle(),this.pannerNode.setOrientation(Math.cos(b),Math.sin(b),0));this.pannerNode.setVelocity(this.objectTracker.getVelocityX(),this.objectTracker.getVelocityY(),0)}};x.prototype.play=function(a,b,c){var d=this.instanceObject;this.looping=a;this.volume=b;c=c||0;switch(this.myapi){case S:1!==d.playbackRate&&(d.playbackRate=1);d.volume!==b*Y&&(d.volume=b*Y);d.loop!==a&&(d.loop=a);d.muted&&(d.muted=!1);if(d.currentTime!==c)try{d.currentTime=c}catch(e){}this.instanceObject.play();break;case E:this.muted=!1;this.mutevol=1;if(this.buffer.myapi===E)this.fresh||(this.instanceObject=I.createBufferSource(),this.instanceObject.buffer=this.buffer.bufferObject,this.instanceObject.connect(this.gainNode)),this.instanceObject.loop=a,this.gainNode.gain.value=b*Y,0===c?h(this.instanceObject):k(this.instanceObject,c,this.getDuration());else{1!==d.playbackRate&&(d.playbackRate=1);d.loop!==a&&(d.loop=a);this.gainNode.gain.value=b*Y;if(d.currentTime!==c)try{d.currentTime=c}catch(f){}d.play()}break;case V:(!this.fresh&&this.stopped||0!==c)&&d.seekTo(c);d.play();this.pgended=!1;break;case aa:N.isDirectCanvas?AppMobi.context.playSound(this.src):AppMobi.player.playSound(this.src)}this.playbackRate=1;this.startTime=N.kahanTime.sum-c;this.is_paused=this.stopped=this.fresh=!1};x.prototype.stop=function(){switch(this.myapi){case S:this.instanceObject.paused||this.instanceObject.pause();break;case E:this.buffer.myapi===E?c(this.instanceObject):this.instanceObject.paused||this.instanceObject.pause();break;case V:this.instanceObject.stop()}this.stopped=!0;this.is_paused=!1};x.prototype.pause=function(){if(!(this.fresh||this.stopped||this.hasEnded()||this.is_paused)){switch(this.myapi){case S:this.instanceObject.paused||this.instanceObject.pause();break;case E:this.buffer.myapi===E?(this.resume_position=this.getPlaybackTime(),this.looping&&(this.resume_position%=this.getDuration()),c(this.instanceObject)):this.instanceObject.paused||this.instanceObject.pause();break;case V:this.instanceObject.pause()}this.is_paused=!0}};x.prototype.resume=function(){if(!this.fresh&&!this.stopped&&!this.hasEnded()&&this.is_paused){switch(this.myapi){case S:this.instanceObject.play();break;case E:this.buffer.myapi===E?(this.instanceObject=I.createBufferSource(),this.instanceObject.buffer=this.buffer.bufferObject,this.instanceObject.connect(this.gainNode),this.instanceObject.loop=this.looping,this.gainNode.gain.value=Y*this.volume*this.mutevol,this.startTime=N.kahanTime.sum-this.resume_position,k(this.instanceObject,this.resume_position,this.getDuration())):this.instanceObject.play();break;case V:this.instanceObject.play()}this.is_paused=!1}};x.prototype.seek=function(a){if(!(this.fresh||this.stopped||this.hasEnded()))switch(this.myapi){case S:try{this.instanceObject.currentTime=a}catch(b){}break;case E:if(this.buffer.myapi===E)this.is_paused?this.resume_position=a:(this.pause(),this.resume_position=a,this.resume());else try{this.instanceObject.currentTime=a}catch(c){}}};x.prototype.reconnect=function(a){this.myapi===E&&(this.pannerEnabled?(this.pannerNode.disconnect(),this.pannerNode.connect(a)):(this.gainNode.disconnect(),this.gainNode.connect(a)))};x.prototype.getDuration=function(){switch(this.myapi){case S:if("undefined"!==typeof this.instanceObject.duration)return this.instanceObject.duration;break;case E:return this.buffer.bufferObject.duration;case V:return this.instanceObject.getDuration()}return 0};x.prototype.getPlaybackTime=function(){var a=this.getDuration(),b=0;switch(this.myapi){case S:"undefined"!==typeof this.instanceObject.currentTime&&(b=this.instanceObject.currentTime);break;case E:if(this.buffer.myapi===E){if(this.is_paused)return this.resume_position;b=N.kahanTime.sum-this.startTime}else"undefined"!==typeof this.instanceObject.currentTime&&(b=this.instanceObject.currentTime)}!this.looping&&b>a&&(b=a);return b};x.prototype.isPlaying=function(){return!this.is_paused&&!this.fresh&&!this.stopped&&!this.hasEnded()};x.prototype.setVolume=function(a){this.volume=a;this.updateVolume()};x.prototype.updateVolume=function(){var a=this.volume*Y;switch(this.myapi){case S:this.instanceObject.volume&&this.instanceObject.volume!==a&&(this.instanceObject.volume=a);break;case E:this.gainNode.gain.value=a*this.mutevol}};x.prototype.getVolume=function(){return this.volume};x.prototype.doSetMuted=function(a){switch(this.myapi){case S:this.instanceObject.muted!==!!a&&(this.instanceObject.muted=!!a);break;case E:this.mutevol=a?0:1,this.gainNode.gain.value=Y*this.volume*this.mutevol}};x.prototype.setMuted=function(a){this.is_muted=!!a;this.doSetMuted(this.is_muted||this.is_silent)};x.prototype.setSilent=function(a){this.is_silent=!!a;this.doSetMuted(this.is_muted||this.is_silent)};x.prototype.setLooping=function(a){this.looping=a;switch(this.myapi){case S:this.instanceObject.loop!==!!a&&(this.instanceObject.loop=!!a);break;case E:this.instanceObject.loop!==!!a&&(this.instanceObject.loop=!!a)}};x.prototype.setPlaybackRate=function(a){this.playbackRate=a;this.updatePlaybackRate()};x.prototype.updatePlaybackRate=function(){var a=this.playbackRate;if(1===fa&&!this.is_music||2===fa)a*=N.timescale;switch(this.myapi){case S:this.instanceObject.playbackRate!==a&&(this.instanceObject.playbackRate=a);break;case E:this.buffer.myapi===E?this.instanceObject.playbackRate.value!==a&&(this.instanceObject.playbackRate.value=a):this.instanceObject.playbackRate!==a&&(this.instanceObject.playbackRate=a)}};x.prototype.setSuspended=function(a){switch(this.myapi){case S:a?this.isPlaying()?(this.instanceObject.pause(),this.resume_me=!0):this.resume_me=!1:this.resume_me&&this.instanceObject.play();break;case E:a?this.isPlaying()?(this.buffer.myapi===E?(this.resume_position=this.getPlaybackTime(),this.looping&&(this.resume_position%=this.getDuration()),c(this.instanceObject)):this.instanceObject.pause(),this.resume_me=!0):this.resume_me=!1:this.resume_me&&(this.buffer.myapi===E?(this.instanceObject=I.createBufferSource(),this.instanceObject.buffer=this.buffer.bufferObject,this.instanceObject.connect(this.gainNode),this.instanceObject.loop=this.looping,this.gainNode.gain.value=Y*this.volume*this.mutevol,this.startTime=N.kahanTime.sum-this.resume_position,k(this.instanceObject,this.resume_position,this.getDuration())):this.instanceObject.play());break;case V:a?this.isPlaying()?(this.instanceObject.pause(),this.resume_me=!0):this.resume_me=!1:this.resume_me&&this.instanceObject.play()}};w.Instance=function(a){this.type=a;N=this.runtime=a.runtime;R=this;this.listenerTracker=null;this.listenerZ=-600;I=null;"undefined"!==typeof AudioContext?(J=E,I=new AudioContext):"undefined"!==typeof webkitAudioContext&&(J=E,I=new webkitAudioContext);this.runtime.isiOS&&J===E&&document.addEventListener("touchstart",function(){if(!na){var a=I.createBuffer(1,1,22050),b=I.createBufferSource();b.buffer=a;b.connect(I.destination);h(b);na=!0}},!0);J!==E&&(this.runtime.isPhoneGap?J=V:this.runtime.isAppMobi&&(J=aa));J===V&&(U=location.href,a=U.lastIndexOf("/"),-1"!==b&&(a.playTagWhenReady=b,a.loopWhenReady=d,a.volumeWhenReady=e),null;l=new x(a,b);K.push(l);return l};var M=[];F.prototype.OnEnded=function(a){return cr.equals_nocase(W,a)};F.prototype.PreloadsComplete=function(){var a,b;a=0;for(b=da.length;a",b,!1)}};y.prototype.PreloadByName=function(a,b){if(!T){var c=1===a,d=this.runtime.files_subfolder+b.toLowerCase()+(X?".ogg":".m4a");J===aa?this.runtime.isDirectCanvas?AppMobi.context.loadSound(d):AppMobi.player.loadSound(d):J!==V&&this.getAudioInstance(d,"",c,!1)}};y.prototype.SetPlaybackRate=function(a,b){z(a);0>b&&(b=0);var c,d;c=0;for(d=M.length;cb||b>=ja.length)||(a=a.toLowerCase(),g/=100,0>g&&(g=0),1e&&(e=0),1f&&(f=0),1g&&(g=0),1d&&(d=0);1c&&(c=0),1c&&(c=0),1f&&(f=0),1b||b>=a.length||a[b].setParam(c,d,e,f)))};y.prototype.SetListenerObject=function(a){a&&J===E&&(a=a.getFirstPicked())&&(this.listenerTracker.setObject(a),Z=a.x,$=a.y)};y.prototype.SetListenerZ=function(a){this.listenerZ=a};w.acts=new y;H.prototype.Duration=function(a,b){z(b);M.length?a.set_float(M[0].getDuration()):a.set_float(0)};H.prototype.PlaybackTime=function(a,b){z(b);M.length?a.set_float(M[0].getPlaybackTime()):a.set_float(0)};H.prototype.Volume=function(a,c){z(c);if(M.length){var d=M[0].getVolume();a.set_float(b(d))}else a.set_float(0)};H.prototype.MasterVolume=function(a){a.set_float(Y)};H.prototype.EffectCount=function(a,b){b=b.toLowerCase();var c=null;L.hasOwnProperty(b)&&(c=L[b]);a.set_int(c?c.length:0)};H.prototype.AnalyserFreqBinCount=function(a,b,c){b=b.toLowerCase();c=Math.floor(c);b=Q(b,c);a.set_int(b?b.node.frequencyBinCount:0)};H.prototype.AnalyserFreqBinAt=function(a,b,c,d){b=b.toLowerCase();c=Math.floor(c);d=Math.floor(d);(b=Q(b,c))?0>d||d>=b.node.frequencyBinCount?a.set_float(0):a.set_float(b.freqBins[d]):a.set_float(0)};H.prototype.AnalyserPeakLevel=function(a,b,c){b=b.toLowerCase();c=Math.floor(c);(b=Q(b,c))?a.set_float(b.peak):a.set_float(0)};H.prototype.AnalyserRMSLevel=function(a,b,c){b=b.toLowerCase();c=Math.floor(c);(b=Q(b,c))?a.set_float(b.rms):a.set_float(0)};w.exps=new H})();cr.plugins_.Browser=function(a){this.runtime=a};(function(){function a(){}function b(){}function d(){"undefined"!==typeof jQuery&&k.setSize(jQuery(window).width(),jQuery(window).height())}function e(){}var f=cr.plugins_.Browser.prototype;f.Type=function(a){this.plugin=a;this.runtime=a.runtime};f.Type.prototype.onCreate=function(){};f.Instance=function(a){this.type=a;this.runtime=a.runtime};f.Instance.prototype.onCreate=function(){var a=this;window.addEventListener("resize",function(){a.runtime.trigger(cr.plugins_.Browser.prototype.cnds.OnResize,a)});"undefined"!==typeof navigator.onLine&&(window.addEventListener("online",function(){a.runtime.trigger(cr.plugins_.Browser.prototype.cnds.OnOnline,a)}),window.addEventListener("offline",function(){a.runtime.trigger(cr.plugins_.Browser.prototype.cnds.OnOffline,a)}));"undefined"!==typeof window.applicationCache&&(window.applicationCache.addEventListener("updateready",function(){a.runtime.loadingprogress=1;a.runtime.trigger(cr.plugins_.Browser.prototype.cnds.OnUpdateReady,a)}),window.applicationCache.addEventListener("progress",function(b){a.runtime.loadingprogress=b.loaded/b.total}));this.runtime.isDirectCanvas||(document.addEventListener("appMobi.device.update.available",function(){a.runtime.trigger(cr.plugins_.Browser.prototype.cnds.OnUpdateReady,a)}),document.addEventListener("menubutton",function(){a.runtime.trigger(cr.plugins_.Browser.prototype.cnds.OnMenuButton,a)}),document.addEventListener("searchbutton",function(){a.runtime.trigger(cr.plugins_.Browser.prototype.cnds.OnSearchButton,a)}));this.runtime.addSuspendCallback(function(b){b?a.runtime.trigger(cr.plugins_.Browser.prototype.cnds.OnPageHidden,a):a.runtime.trigger(cr.plugins_.Browser.prototype.cnds.OnPageVisible,a)});this.is_arcade="undefined"!==typeof window.is_scirra_arcade;this.fullscreenOldMarginCss=""};a.prototype.CookiesEnabled=function(){return navigator?navigator.cookieEnabled:!1};a.prototype.IsOnline=function(){return navigator?navigator.onLine:!1};a.prototype.HasJava=function(){return navigator?navigator.javaEnabled():!1};a.prototype.OnOnline=function(){return!0};a.prototype.OnOffline=function(){return!0};a.prototype.IsDownloadingUpdate=function(){return"undefined"===typeof window.applicationCache?!1:window.applicationCache.status===window.applicationCache.DOWNLOADING};a.prototype.OnUpdateReady=function(){return!0};a.prototype.PageVisible=function(){return!this.runtime.isSuspended};a.prototype.OnPageVisible=function(){return!0};a.prototype.OnPageHidden=function(){return!0};a.prototype.OnResize=function(){return!0};a.prototype.IsFullscreen=function(){return!!(document.mozFullScreen||document.webkitIsFullScreen||document.fullScreen||this.runtime.isNodeFullscreen)};a.prototype.OnMenuButton=function(){return!0};a.prototype.OnSearchButton=function(){return!0};a.prototype.IsMetered=function(){var a=navigator.connection||navigator.mozConnection||navigator.webkitConnection;return a?a.metered:!1};a.prototype.IsCharging=function(){var a=navigator.battery||navigator.mozBattery||navigator.webkitBattery;return a?a.charging:!0};f.cnds=new a;b.prototype.Alert=function(a){this.runtime.isDomFree||alert(a.toString())};b.prototype.Close=function(){this.runtime.isCocoonJs?CocoonJS.App.forceToFinish():this.runtime.isNodeWebkit?window.nwgui.App.quit():this.is_arcade||this.runtime.isDomFree||window.close()};b.prototype.Focus=function(){this.runtime.isNodeWebkit?window.nwgui.Window.get().focus():this.is_arcade||this.runtime.isDomFree||window.focus()};b.prototype.Blur=function(){this.runtime.isNodeWebkit?window.nwgui.Window.get().blur():this.is_arcade||this.runtime.isDomFree||window.blur()};b.prototype.GoBack=function(){this.is_arcade||(this.runtime.isDomFree||!window.back)||window.back()};b.prototype.GoForward=function(){this.is_arcade||(this.runtime.isDomFree||!window.forward)||window.forward()};b.prototype.GoHome=function(){this.is_arcade||(this.runtime.isDomFree||!window.home)||window.home()};b.prototype.GoToURL=function(a){this.runtime.isCocoonJs?CocoonJS.App.openURL(a):this.is_arcade||this.runtime.isDomFree||(window.location=a)};b.prototype.GoToURLWindow=function(a,b){this.runtime.isCocoonJs?CocoonJS.App.openURL(a):this.is_arcade||this.runtime.isDomFree||window.open(a,b)};b.prototype.Reload=function(){this.is_arcade||this.runtime.isDomFree||window.location.reload()};var h=!0,k=null;b.prototype.RequestFullScreen=function(a){this.runtime.isDomFree?cr.logexport("[Construct 2] Requesting fullscreen is not supported on this platform - the request has been ignored"):(2<=a&&(a+=1),6===a&&(a=2),this.runtime.isNodeWebkit?this.runtime.isNodeFullscreen||(window.nwgui.Window.get().enterFullscreen(),this.runtime.isNodeFullscreen=!0):document.mozFullScreen||(document.webkitIsFullScreen||document.fullScreen)||(this.fullscreenOldMarginCss=jQuery(this.runtime.canvasdiv).css("margin"),jQuery(this.runtime.canvasdiv).css("margin","0"),window.c2resizestretchmode=0a||a>=this.keyMap.length?!1:this.keyMap[a]};a.prototype.OnKeyCode=function(a){return a===this.triggerKey};a.prototype.OnKeyCodeReleased=function(a){return a===this.triggerKey};e.cnds=new a;e.acts=new function(){};b.prototype.LastKeyCode=function(a){a.set_int(this.triggerKey)};b.prototype.StringFromKeyCode=function(a,b){a.set_string(d(b))};e.exps=new b})();cr.plugins_.NodeWebkit=function(a){this.runtime=a};(function(){function a(){}function b(){}function d(){}var e=!1,f=null,h=null,k=null,c="",r="",n="\\",l=[],q="",v="",t=cr.plugins_.NodeWebkit.prototype;t.Type=function(a){this.plugin=a;this.runtime=a.runtime};t.Type.prototype.onCreate=function(){};t.Instance=function(a){this.type=a;this.runtime=a.runtime};var p=t.Instance.prototype;p.onCreate=function(){e=this.runtime.isNodeWebkit;var a=this;e&&(f=require("path"),h=require("fs"),k=require("child_process"),"win32"!==process.platform&&(n="/"),c=f.dirname(process.execPath)+n,r=(process.env.HOME||process.env.HOMEPATH||process.env.USERPROFILE)+n,window.ondrop=function(b){b.preventDefault();for(var c=0;cb||b>=l.length?a.set_string(""):a.set_string(l[b])};d.prototype.DroppedFile=function(a){a.set_string(q)};d.prototype.ChosenPath=function(a){a.set_string(v)};t.exps=new d})();cr.plugins_.Particles=function(a){this.runtime=a};(function(){function a(a){this.owner=a;this.active=!1;this.angle=this.speed=this.y=this.x=0;this.opacity=1;this.age=this.gs=this.size=this.grow=0;cr.seal(this)}function b(){}function d(){}function e(){}var f=cr.plugins_.Particles.prototype;f.Type=function(a){this.plugin=a;this.runtime=a.runtime};var h=f.Type.prototype;h.onCreate=function(){this.is_family||(this.texture_img=new Image,this.texture_img.src=this.texture_file,this.texture_img.cr_filesize=this.texture_filesize,this.webGL_texture=null,this.runtime.wait_for_textures.push(this.texture_img))};h.onLostWebGLContext=function(){this.is_family||(this.webGL_texture=null)};h.onRestoreWebGLContext=function(){this.is_family||!this.instances.length||this.webGL_texture||(this.webGL_texture=this.runtime.glwrap.loadTexture(this.texture_img,!0,this.runtime.linearSampling,this.texture_pixelformat))};h.loadTextures=function(){this.is_family||(this.webGL_texture||!this.runtime.glwrap)||(this.webGL_texture=this.runtime.glwrap.loadTexture(this.texture_img,!0,this.runtime.linearSampling,this.texture_pixelformat))};h.unloadTextures=function(){this.is_family||(this.instances.length||!this.webGL_texture)||(this.runtime.glwrap.deleteTexture(this.webGL_texture),this.webGL_texture=null)};h.preloadCanvas2D=function(a){a.drawImage(this.texture_img,0,0)};a.prototype.init=function(){var a=this.owner;this.x=a.x-a.xrandom/2+Math.random()*a.xrandom;this.y=a.y-a.yrandom/2+Math.random()*a.yrandom;this.speed=a.initspeed-a.speedrandom/2+Math.random()*a.speedrandom;this.angle=a.angle-a.spraycone/2+Math.random()*a.spraycone;this.opacity=a.initopacity;this.size=a.initsize-a.sizerandom/2+Math.random()*a.sizerandom;this.grow=a.growrate-a.growrandom/2+Math.random()*a.growrandom;this.age=this.gs=0};a.prototype.tick=function(a){var b=this.owner;this.x+=Math.cos(this.angle)*this.speed*a;this.y+=Math.sin(this.angle)*this.speed*a;this.y+=this.gs*a;this.speed+=b.acc*a;this.size+=this.grow*a;this.gs+=b.g*a;this.age+=a;1>this.size?this.active=!1:(0!==b.lifeanglerandom&&(this.angle+=Math.random()*b.lifeanglerandom*a-b.lifeanglerandom*a/2),0!==b.lifespeedrandom&&(this.speed+=Math.random()*b.lifespeedrandom*a-b.lifespeedrandom*a/2),0!==b.lifeopacityrandom&&(this.opacity+=Math.random()*b.lifeopacityrandom*a-b.lifeopacityrandom*a/2,0>this.opacity?this.opacity=0:1=b.destroymode&&this.age>=b.timeout&&(this.active=!1),2===b.destroymode&&0>=this.speed&&(this.active=!1))};a.prototype.draw=function(a){var b=this.owner.opacity*this.opacity;if(0!==b){0===this.owner.destroymode&&(b*=1-this.age/this.owner.timeout);a.globalAlpha=b;var b=this.x-this.size/2,d=this.y-this.size/2;this.owner.runtime.pixel_rounding&&(b=b+0.5|0,d=d+0.5|0);a.drawImage(this.owner.type.texture_img,b,d,this.size,this.size)}};a.prototype.drawGL=function(a){var b=this.owner.opacity*this.opacity;0===this.owner.destroymode&&(b*=1-this.age/this.owner.timeout);var d=this.size,e=d*this.owner.particlescale,f=this.x-d/2,h=this.y-d/2;this.owner.runtime.pixel_rounding&&(f=f+0.5|0,h=h+0.5|0);1>e||0===b||(ea.maxPointSize?(a.setOpacity(b),a.quad(f,h,f+d,h,f+d,h+d,f,h+d)):a.point(this.x,this.y,e,b))};a.prototype.left=function(){return this.x-this.size/2};a.prototype.right=function(){return this.x+this.size/2};a.prototype.top=function(){return this.y-this.size/2};a.prototype.bottom=function(){return this.y+this.size/2};f.Instance=function(a){this.type=a;this.runtime=a.runtime};var h=f.Instance.prototype,k=[];h.onCreate=function(){var a=this.properties;this.rate=a[0];this.spraycone=cr.to_radians(a[1]);this.spraytype=a[2];this.spraying=!0;this.initspeed=a[3];this.initsize=a[4];this.initopacity=a[5]/100;this.growrate=a[6];this.xrandom=a[7];this.yrandom=a[8];this.speedrandom=a[9];this.sizerandom=a[10];this.growrandom=a[11];this.acc=a[12];this.g=a[13];this.lifeanglerandom=a[14];this.lifespeedrandom=a[15];this.lifeopacityrandom=a[16];this.destroymode=a[17];this.timeout=a[18];this.particleCreateCounter=0;this.particlescale=1;this.particleBoxLeft=this.x;this.particleBoxTop=this.y;this.particleBoxRight=this.x;this.particleBoxBottom=this.y;this.add_bbox_changed_callback(function(a){a.bbox.set(a.particleBoxLeft,a.particleBoxTop,a.particleBoxRight,a.particleBoxBottom);a.bquad.set_from_rect(a.bbox);a.bbox_changed=!1});this.recycled||(this.particles=[]);this.runtime.tickMe(this);this.type.loadTextures();if(1===this.spraytype)for(a=0;athis.particleBoxRight&&(this.particleBoxRight=e.right()),e.top()this.particleBoxBottom&&(this.particleBoxBottom=e.bottom()),f++):k.push(e);this.particles.length=f;this.set_bbox_changed();this.first_tick=!1;1===this.spraytype&&0===this.particles.length&&this.runtime.DestroyInstance(this)};h.draw=function(a){var b,d,e,f=this.layer;b=0;for(d=this.particles.length;b=f.viewLeft&&(e.bottom()>=f.viewTop&&e.left()<=f.viewRight&&e.top()<=f.viewBottom)&&e.draw(a)};h.drawGL=function(a){this.particlescale=this.layer.getScale();a.setTexture(this.type.webGL_texture);var b,d,e,f=this.layer;b=0;for(d=this.particles.length;b=f.viewLeft&&(e.bottom()>=f.viewTop&&e.left()<=f.viewRight&&e.top()<=f.viewBottom)&&e.drawGL(a)};b.prototype.IsSpraying=function(){return this.spraying};f.cnds=new b;d.prototype.SetSpraying=function(a){this.spraying=0!==a};d.prototype.SetEffect=function(a){this.compositeOp=cr.effectToCompositeOp(a);cr.setGLBlend(this,a,this.runtime.gl);this.runtime.redraw=!0};d.prototype.SetRate=function(a){this.rate=a;var b;if(1===this.spraytype&&this.first_tick)if(athis.particles.length)for(a-=this.particles.length,b=0;ba.viewRight||b.top>a.viewBottom)this.runtime.glwrap.deleteTexture(this.mytex),this.mycanvas=this.myctx=this.mytex=null}};k.onDestroy=function(){this.mycanvas=this.myctx=null;this.runtime.glwrap&&this.mytex&&this.runtime.glwrap.deleteTexture(this.mytex);this.mytex=null};k.updateFont=function(){this.font=this.fontstyle+" "+this.ptSize.toString()+"pt "+this.facename;this.text_changed=!0;this.runtime.redraw=!0};k.draw=function(a,b){a.font=this.font;a.textBaseline="top";a.fillStyle=this.color;a.globalAlpha=b?1:this.opacity;var c=1;b&&(c=this.layer.getScale(),a.save(),a.scale(c,c));if(this.text_changed||this.width!==this.lastwrapwidth)this.type.plugin.WordWrap(this.text,this.lines,a,this.width,this.wrapbyword),this.text_changed=!1,this.lastwrapwidth=this.width;this.update_bbox();var c=b?0:this.bquad.tlx,d=b?0:this.bquad.tly;this.runtime.pixel_rounding&&(c=c+0.5|0,d=d+0.5|0);0===this.angle||b||(a.save(),a.translate(c,d),a.rotate(this.angle),d=c=0);var e=d+this.height,f=this.pxHeight,f=f+this.line_height_offset*this.runtime.devicePixelRatio,h,k;1===this.valign?d+=Math.max(this.height/2-this.lines.length*f/2,0):2===this.valign&&(d+=Math.max(this.height-this.lines.length*f-2,0));for(k=0;k=e-f);k++);(0!==this.angle||b)&&a.restore();this.last_render_tick=this.runtime.tickcount};k.drawGL=function(a){if(!(1>this.width||1>this.height)){var b=this.text_changed||this.need_text_redraw;this.need_text_redraw=!1;var c=this.layer.getScale(),d=this.layer.getAngle(),e=this.rcTex,f=c*this.width,h=c*this.height,k=Math.ceil(f),n=Math.ceil(h),s=this.runtime.width/2,m=this.runtime.height/2;this.myctx||(this.mycanvas=document.createElement("canvas"),this.mycanvas.width=k,this.mycanvas.height=n,this.lastwidth=k,this.lastheight=n,b=!0,this.myctx=this.mycanvas.getContext("2d"));if(k!==this.lastwidth||n!==this.lastheight)this.mycanvas.width=k,this.mycanvas.height=n,this.mytex&&(a.deleteTexture(this.mytex),this.mytex=null),b=!0;b&&(this.myctx.clearRect(0,0,k,n),this.draw(this.myctx,!0),this.mytex||(this.mytex=a.createEmptyTexture(k,n,this.runtime.linearSampling,this.runtime.isMobile)),a.videoToTexture(this.mycanvas,this.mytex,this.runtime.isMobile));this.lastwidth=k;this.lastheight=n;a.setTexture(this.mytex);a.setOpacity(this.opacity);a.resetModelView();a.translate(-s,-m);a.updateModelView();var r=this.bquad,b=this.layer.layerToCanvas(r.tlx,r.tly,!0),s=this.layer.layerToCanvas(r.tlx,r.tly,!1),m=this.layer.layerToCanvas(r.trx,r.try_,!0),x=this.layer.layerToCanvas(r.trx,r.try_,!1),z=this.layer.layerToCanvas(r.brx,r.bry,!0),G=this.layer.layerToCanvas(r.brx,r.bry,!1),C=this.layer.layerToCanvas(r.blx,r.bly,!0),r=this.layer.layerToCanvas(r.blx,r.bly,!1);if(this.runtime.pixel_rounding||0===this.angle&&0===d)var F=(b+0.5|0)-b,y=(s+0.5|0)-s,b=b+F,s=s+y,m=m+F,x=x+y,z=z+F,G=G+y,C=C+F,r=r+y;0===this.angle&&0===d?(m=b+k,x=s,z=m,G=s+n,C=b,r=G,e.right=1,e.bottom=1):(e.right=f/k,e.bottom=h/n);a.quadTex(b,s,m,x,z,G,C,r,e);a.resetModelView();a.scale(c,c);a.rotateZ(-this.layer.getAngle());a.translate((this.layer.viewLeft+this.layer.viewRight)/-2,(this.layer.viewTop+this.layer.viewBottom)/-2);a.updateModelView();this.last_render_tick=this.runtime.tickcount}};var r=[];h.TokeniseWords=function(a){r.length=0;for(var b="",c,d=0;d=f)b(d);else{if(100>=c.length&&-1===c.indexOf("\n")){var g=e.measureText(c).width;if(g<=f){b(d);d.push(a());d[0].text=c;d[0].width=g;return}}this.WrapText(c,d,e,f,h)}else b(d)};h.WrapText=function(b,c,d,e,f){f&&(this.TokeniseWords(b),b=r);var g="",h,k,B,s=0;for(B=0;B=c.length&&c.push(a()),k=c[s],k.text=g,k.width=d.measureText(g).width,s++,g=""):(h=g,g+=b[B],k=d.measureText(g).width,k>=e&&(s>=c.length&&c.push(a()),k=c[s],k.text=h,k.width=d.measureText(h).width,s++,g=b[B],f||" "!==g||(g="")));g.length&&(s>=c.length&&c.push(a()),k=c[s],k.text=g,k.width=d.measureText(g).width,s++);for(B=s;Ba&&(a=Math.round(1E10*a)/1E10);a=a.toString();this.text!==a&&(this.text=a,this.text_changed=!0,this.runtime.redraw=!0)};e.prototype.AppendText=function(a){cr.is_number(a)&&(a=Math.round(1E10*a)/1E10);if(a=a.toString())this.text+=a,this.text_changed=!0,this.runtime.redraw=!0};e.prototype.SetFontFace=function(a,b){var c="";switch(b){case 1:c="bold";break;case 2:c="italic";break;case 3:c="bold italic"}if(a!==this.facename||c!==this.fontstyle)this.facename=a,this.fontstyle=c,this.updateFont()};e.prototype.SetFontSize=function(a){this.ptSize!==a&&(this.ptSize=a,this.pxHeight=Math.ceil(96*(this.ptSize/72))+4,this.updateFont())};e.prototype.SetFontColor=function(a){a="rgb("+cr.GetRValue(a).toString()+","+cr.GetGValue(a).toString()+","+cr.GetBValue(a).toString()+")";a!==this.color&&(this.color=a,this.need_text_redraw=!0,this.runtime.redraw=!0)};e.prototype.SetWebFont=function(a,b){if(this.runtime.isDomFree)cr.logexport("[Construct 2] Text plugin: 'Set web font' not supported on this platform - the action has been ignored");else{var d=this,e=function(){d.runtime.redraw=!0;d.text_changed=!0};if(c.hasOwnProperty(b)){var f="'"+a+"'";if(this.facename!==f)for(this.facename=f,this.updateFont(),f=1;10>f;f++)setTimeout(e,100*f),setTimeout(e,1E3*f)}else for(f=document.createElement("link"),f.href=b,f.rel="stylesheet",f.type="text/css",f.onload=e,document.getElementsByTagName("head")[0].appendChild(f),c[b]=!0,this.facename="'"+a+"'",this.updateFont(),f=1;10>f;f++)setTimeout(e,100*f),setTimeout(e,1E3*f)}};e.prototype.SetEffect=function(a){this.compositeOp=cr.effectToCompositeOp(a);cr.setGLBlend(this,a,this.runtime.gl);this.runtime.redraw=!0};h.acts=new e;f.prototype.Text=function(a){a.set_string(this.text)};f.prototype.FaceName=function(a){a.set_string(this.facename)};f.prototype.FaceSize=function(a){a.set_int(this.ptSize)};f.prototype.TextWidth=function(a){var b=0,c,d,e;c=0;for(d=this.lines.length;cc-b.time||(b.lasttime=b.time,b.lastx=b.x,b.lasty=b.y,b.time=c,b.x=a.pageX-d.left,b.y=a.pageY-d.top)}}};h.onPointerStart=function(a){if(a.pointerType!==a.MSPOINTER_TYPE_MOUSE){a.preventDefault&&a.preventDefault();var b=this.runtime.isDomFree?k:jQuery(this.runtime.canvas).offset(),c=a.pageX-b.left,b=a.pageY-b.top,d=cr.performance_now();this.trigger_index=this.touches.length;this.trigger_id=a.pointerId;this.touches.push({time:d,x:c,y:b,lasttime:d,lastx:c,lasty:b,id:a.pointerId,startindex:this.trigger_index});this.runtime.trigger(cr.plugins_.Touch.prototype.cnds.OnNthTouchStart,this);this.runtime.trigger(cr.plugins_.Touch.prototype.cnds.OnTouchStart,this);this.curTouchX=c;this.curTouchY=b;this.runtime.trigger(cr.plugins_.Touch.prototype.cnds.OnTouchObject,this)}};h.onPointerEnd=function(a){a.pointerType!==a.MSPOINTER_TYPE_MOUSE&&(a.preventDefault&&a.preventDefault(),a=this.findTouch(a.pointerId),this.trigger_index=0<=a?this.touches[a].startindex:-1,this.trigger_id=0<=a?this.touches[a].id:-1,this.runtime.trigger(cr.plugins_.Touch.prototype.cnds.OnNthTouchEnd,this),this.runtime.trigger(cr.plugins_.Touch.prototype.cnds.OnTouchEnd,this),0<=a&&this.touches.splice(a,1))};h.onTouchMove=function(a){a.preventDefault&&a.preventDefault();var b=cr.performance_now(),c,d,e,f;c=0;for(d=a.changedTouches.length;cb-f.time||(f.lasttime=f.time,f.lastx=f.x,f.lasty=f.y,f.time=b,f.x=e.pageX-h.left,f.y=e.pageY-h.top)}};h.onTouchStart=function(a){a.preventDefault&&a.preventDefault();var b=this.runtime.isDomFree?k:jQuery(this.runtime.canvas).offset(),c=cr.performance_now(),d,e,f,h;d=0;for(e=a.changedTouches.length;da||a>=this.touches.length)return!1;var d=this.touches[a];a=cr.distanceTo(d.x,d.y,d.lastx,d.lasty);var d=(d.time-d.lasttime)/1E3,e=0;0=a+1};f.cnds=new d;e.prototype.TouchCount=function(a){a.set_int(this.touches.length)};e.prototype.X=function(a,b){if(this.touches.length){var c,d,e,f,h;cr.is_undefined(b)?(c=this.runtime.getLayerByNumber(0),d=c.scale,e=c.zoomRate,f=c.parallaxX,h=c.angle,c.scale=this.runtime.running_layout.scale,c.zoomRate=1,c.parallaxX=1,c.angle=this.runtime.running_layout.angle,a.set_float(c.canvasToLayer(this.touches[0].x,this.touches[0].y,!0)),c.scale=d,c.zoomRate=e,c.parallaxX=f,c.angle=h):(c=cr.is_number(b)?this.runtime.getLayerByNumber(b):this.runtime.getLayerByName(b))?a.set_float(c.canvasToLayer(this.touches[0].x,this.touches[0].y,!0)):a.set_float(0)}else a.set_float(0)};e.prototype.XAt=function(a,b,c){b=Math.floor(b);if(0>b||b>=this.touches.length)a.set_float(0);else{var d,e,f,h;cr.is_undefined(c)?(c=this.runtime.getLayerByNumber(0),d=c.scale,e=c.zoomRate,f=c.parallaxX,h=c.angle,c.scale=this.runtime.running_layout.scale,c.zoomRate=1,c.parallaxX=1,c.angle=this.runtime.running_layout.angle,a.set_float(c.canvasToLayer(this.touches[b].x,this.touches[b].y,!0)),c.scale=d,c.zoomRate=e,c.parallaxX=f,c.angle=h):(c=cr.is_number(c)?this.runtime.getLayerByNumber(c):this.runtime.getLayerByName(c))?a.set_float(c.canvasToLayer(this.touches[b].x,this.touches[b].y,!0)):a.set_float(0)}};e.prototype.XForID=function(a,b,c){b=this.findTouch(b);if(0>b)a.set_float(0);else{b=this.touches[b];var d,e,f,h;cr.is_undefined(c)?(c=this.runtime.getLayerByNumber(0),d=c.scale,e=c.zoomRate,f=c.parallaxX,h=c.angle,c.scale=this.runtime.running_layout.scale,c.zoomRate=1,c.parallaxX=1,c.angle=this.runtime.running_layout.angle,a.set_float(c.canvasToLayer(b.x,b.y,!0)),c.scale=d,c.zoomRate=e,c.parallaxX=f,c.angle=h):(c=cr.is_number(c)?this.runtime.getLayerByNumber(c):this.runtime.getLayerByName(c))?a.set_float(c.canvasToLayer(b.x,b.y,!0)):a.set_float(0)}};e.prototype.Y=function(a,b){if(this.touches.length){var c,d,e,f,h;cr.is_undefined(b)?(c=this.runtime.getLayerByNumber(0),d=c.scale,e=c.zoomRate,f=c.parallaxY,h=c.angle,c.scale=this.runtime.running_layout.scale,c.zoomRate=1,c.parallaxY=1,c.angle=this.runtime.running_layout.angle,a.set_float(c.canvasToLayer(this.touches[0].x,this.touches[0].y,!1)),c.scale=d,c.zoomRate=e,c.parallaxY=f,c.angle=h):(c=cr.is_number(b)?this.runtime.getLayerByNumber(b):this.runtime.getLayerByName(b))?a.set_float(c.canvasToLayer(this.touches[0].x,this.touches[0].y,!1)):a.set_float(0)}else a.set_float(0)};e.prototype.YAt=function(a,b,c){b=Math.floor(b);if(0>b||b>=this.touches.length)a.set_float(0);else{var d,e,f,h;cr.is_undefined(c)?(c=this.runtime.getLayerByNumber(0),d=c.scale,e=c.zoomRate,f=c.parallaxY,h=c.angle,c.scale=this.runtime.running_layout.scale,c.zoomRate=1,c.parallaxY=1,c.angle=this.runtime.running_layout.angle,a.set_float(c.canvasToLayer(this.touches[b].x,this.touches[b].y,!1)),c.scale=d,c.zoomRate=e,c.parallaxY=f,c.angle=h):(c=cr.is_number(c)?this.runtime.getLayerByNumber(c):this.runtime.getLayerByName(c))?a.set_float(c.canvasToLayer(this.touches[b].x,this.touches[b].y,!1)):a.set_float(0)}};e.prototype.YForID=function(a,b,c){b=this.findTouch(b);if(0>b)a.set_float(0);else{b=this.touches[b];var d,e,f,h;cr.is_undefined(c)?(c=this.runtime.getLayerByNumber(0),d=c.scale,e=c.zoomRate,f=c.parallaxY,h=c.angle,c.scale=this.runtime.running_layout.scale,c.zoomRate=1,c.parallaxY=1,c.angle=this.runtime.running_layout.angle,a.set_float(c.canvasToLayer(b.x,b.y,!1)),c.scale=d,c.zoomRate=e,c.parallaxY=f,c.angle=h):(c=cr.is_number(c)?this.runtime.getLayerByNumber(c):this.runtime.getLayerByName(c))?a.set_float(c.canvasToLayer(b.x,b.y,!1)):a.set_float(0)}};e.prototype.AbsoluteX=function(a){this.touches.length?a.set_float(this.touches[0].x):a.set_float(0)};e.prototype.AbsoluteXAt=function(a,b){b=Math.floor(b);0>b||b>=this.touches.length?a.set_float(0):a.set_float(this.touches[b].x)};e.prototype.AbsoluteXForID=function(a,b){var c=this.findTouch(b);0>c?a.set_float(0):a.set_float(this.touches[c].x)};e.prototype.AbsoluteY=function(a){this.touches.length?a.set_float(this.touches[0].y):a.set_float(0)};e.prototype.AbsoluteYAt=function(a,b){b=Math.floor(b);0>b||b>=this.touches.length?a.set_float(0):a.set_float(this.touches[b].y)};e.prototype.AbsoluteYForID=function(a,b){var c=this.findTouch(b);0>c?a.set_float(0):a.set_float(this.touches[c].y)};e.prototype.SpeedAt=function(a,b){b=Math.floor(b);if(0>b||b>=this.touches.length)a.set_float(0);else{var c=this.touches[b],d=cr.distanceTo(c.x,c.y,c.lastx,c.lasty),c=(c.time-c.lasttime)/1E3;0===c?a.set_float(0):a.set_float(d/c)}};e.prototype.SpeedForID=function(a,b){var c=this.findTouch(b);if(0>c)a.set_float(0);else{var d=this.touches[c],c=cr.distanceTo(d.x,d.y,d.lastx,d.lasty),d=(d.time-d.lasttime)/1E3;0===d?a.set_float(0):a.set_float(c/d)}};e.prototype.AngleAt=function(a,b){b=Math.floor(b);if(0>b||b>=this.touches.length)a.set_float(0);else{var c=this.touches[b];a.set_float(cr.to_degrees(cr.angleTo(c.lastx,c.lasty,c.x,c.y)))}};e.prototype.AngleForID=function(a,b){var c=this.findTouch(b);0>c?a.set_float(0):(c=this.touches[c],a.set_float(cr.to_degrees(cr.angleTo(c.lastx,c.lasty,c.x,c.y))))};e.prototype.Alpha=function(a){a.set_float(this.getAlpha())};e.prototype.Beta=function(a){a.set_float(this.getBeta())};e.prototype.Gamma=function(a){a.set_float(this.getGamma())};e.prototype.AccelerationXWithG=function(a){a.set_float(this.acc_g_x)};e.prototype.AccelerationYWithG=function(a){a.set_float(this.acc_g_y)};e.prototype.AccelerationZWithG=function(a){a.set_float(this.acc_g_z)};e.prototype.AccelerationX=function(a){a.set_float(this.acc_x)};e.prototype.AccelerationY=function(a){a.set_float(this.acc_y)};e.prototype.AccelerationZ=function(a){a.set_float(this.acc_z)};e.prototype.TouchIndex=function(a){a.set_int(this.trigger_index)};e.prototype.TouchID=function(a){a.set_float(this.trigger_id)};f.exps=new e})();cr.getProjectModel=function(){return[null,"Loader",[[cr.plugins_.Browser,!0,!1,!1,!1,!1,!1,!1,!1,!1],[cr.plugins_.Audio,!0,!1,!1,!1,!1,!1,!1,!1,!1],[cr.plugins_.Keyboard,!0,!1,!1,!1,!1,!1,!1,!1,!1],[cr.plugins_.NodeWebkit,!0,!1,!1,!1,!1,!1,!1,!1,!1],[cr.plugins_.Particles,!1,!0,!0,!1,!0,!0,!0,!0,!0],[cr.plugins_.Text,!1,!0,!0,!0,!0,!0,!0,!0,!1],[cr.plugins_.Touch,!0,!1,!1,!1,!1,!1,!1,!1,!1]],[["t0",cr.plugins_.Browser,!1,[],0,0,null,null,[],!1,!1,0xe7508259f1049,[],[]],["t1",cr.plugins_.Keyboard,!1,[],0,0,null,null,[],!1,!1,8268562079040081,[],[]],["t2",cr.plugins_.Particles,!1,[],0,0,["c2.png",29833,0],null,[],!1,!1,723074460476516,[]],["t3",cr.plugins_.Audio,!1,[],0,0,null,null,[],!1,!1,0x87d7a273e6e76,[],[0,1,1,600,600,1E4,1,5E3,1]],["t4",cr.plugins_.NodeWebkit,!1,[],0,0,null,null,[],!1,!1,0x418c17d077bfa,[],[]],["t5",cr.plugins_.Particles,!1,[],0,0,["nw.png",2403,0],null,[],!1,!1,7413958693205721,[]],["t6",cr.plugins_.Text,!1,[],0,0,null,null,[],!1,!1,0xadbe7ef820faf,[]],["t7",cr.plugins_.Touch,!1,[],0,0,null,null,[],!1,!1,4854103537132793,[],[1]]],[],[["Loader",800,600,!1,"Loader_events",9256725879576544,[["Loader",0,8771806647801429,!0,[0,0,0],!1,1,1,1,!1,1,0,0,[],[]]],[],[]],["Veille",800,600,!1,"Veille_events",306290045656015,[["Veille",0,0x9c56068fd6acc,!0,[0,0,0],!1,1,1,1,!1,1,1,0,[[[400,-75,0,32,320,0,1.5708,1,0,0.5,0,0,[]],2,1,[],[],[5,120,0,250,40,0,-2,40,0,0,8,0,-150,100,2,800,2,0,5]],[[400,700,0,32,320,0,-1.5708,1,0,0.5,0,0,[]],5,7,[],[],[5,120,0,250,40,0,-2,40,0,0,8,0,-150,-100,2,800,2,0,5]],[[579,30,0,200,540,0,0,0.5,0,0,1,0,[]],6,4,[],[],["",1,"bold 12pt Arial","rgb(255,255,255)",1,1,0,0,0]]],[["warpripple","WarpRipple",[1,0.01,-5]]]]],[],[]],["Exit",800,600,!1,"Exit_events",6113943557441396,[["Exit",0,0xb124a9f08ea67,!0,[0,0,0],!1,1,1,1,!1,1,0,0,[],[]]],[],[]]],[["Loader_events",[[1,"NumVeille",0,-2,!1,!1,8964089995488567],[1,"NWfile",1,"",!1,!1,0xe4fbfc76f13ab],[0,null,!1,0x4dfd65888a214,[[-1,cr.system_object.prototype.cnds.OnLayoutStart,null,1,!1,!1,!1,9184290607372780]],[[0,cr.plugins_.Browser.prototype.acts.RequestFullScreen,null,7636186985065621,[[3,5]]]]],[0,null,!1,0x5bb13aa690f60,[[-1,cr.system_object.prototype.cnds.OnLoadFinished,null,1,!1,!1,!1,0x82e0442152500]],[[-1,cr.system_object.prototype.acts.Wait,null,9840344659686878,[[0,[1,0.01]]]],[-1,cr.system_object.prototype.acts.GoToLayout,null,0x5200955dfe05a,[[6,"Veille"]]]]]]],["Veille_events",[[1,"RMS",0,0,!1,!1,8272711222301935],[1,"Restart",0,0,!1,!1,5338948241480027],[0,null,!1,9883295321069700,[[-1,cr.system_object.prototype.cnds.OnLayoutStart,null,1,!1,!1,!1,0xd39cedc82dd33]],[[3,cr.plugins_.Audio.prototype.acts.PlayByName,null,5202980257560176,[[3,1],[1,[2,"Evening_Fall_Harp"]],[3,0],[0,[0,0]],[1,[2,""]]]],[2,cr.plugins_.Particles.prototype.acts.SetRate,null,0xc15240e82c978,[[0,[0,5]]]],[5,cr.plugins_.Particles.prototype.acts.SetRate,null,0x6ff8687e80572,[[0,[0,5]]]],[2,cr.plugins_.Particles.prototype.acts.SetSpraying,null,5500294466648475,[[3,1]]],[5,cr.plugins_.Particles.prototype.acts.SetSpraying,null,4830535051445549,[[3,1]]]]],[0,[!1,"Start"],!1,5670715518694284,[[-1,cr.system_object.prototype.cnds.IsGroupActive,null,0,!1,!1,!1,5670715518694284,[[1,[2,"Start"]]]]],[],[[0,null,!1,8365481790965971,[[-1,cr.system_object.prototype.cnds.Compare,null,0,!1,!1,!1,681938087295472,[[7,[19,cr.system_object.prototype.exps.layeropacity,[[2,"Veille"]]]],[8,0],[7,[0,100]]]]],[[-1,cr.system_object.prototype.acts.SetGroupActive,null,0x939cfc17f135c,[[1,[2,"Start"]],[3,0]]]]],[0,null,!1,0xaccce4249a717,[[-1,cr.system_object.prototype.cnds.Else,null,0,!1,!1,!1,9645145373693224],[-1,cr.system_object.prototype.cnds.EveryTick,null,0,!1,!1,!1,0xc1f6300af58e8]],[[-1,cr.system_object.prototype.acts.SetLayerOpacity,null,0x50fa048c371f6,[[5,[2,"Veille"]],[0,[4,[19,cr.system_object.prototype.exps.layeropacity,[[2,"Veille"]]],[0,1]]]]],[2,cr.plugins_.Particles.prototype.acts.SetInitOpacity,null,0xa82f69b81a210,[[0,[5,[19,cr.system_object.prototype.exps.layeropacity,[[2,"Veille"]]],[0,10]]]]],[5,cr.plugins_.Particles.prototype.acts.SetInitOpacity,null,9087421245893464,[[0,[5,[19,cr.system_object.prototype.exps.layeropacity,[[2,"Veille"]]],[0,10]]]]]]]]],[0,[!1,"Body"],!1,7028360535295121,[[-1,cr.system_object.prototype.cnds.IsGroupActive,null,0,!1,!1,!1,7028360535295121,[[1,[2,"Body"]]]]],[],[[0,null,!1,0x51e8a6e11ca45,[[1,cr.plugins_.Keyboard.prototype.cnds.OnKey,null,1,!1,!1,!1,0xaf5a5a8d1a494,[[9,13]]]],[],[[0,null,!1,6545261610976676,[[6,cr.plugins_.Text.prototype.cnds.IsVisible,null,0,!1,!0,!1,57733252997832]],[[6,cr.plugins_.Text.prototype.acts.SetVisible,null,0x8bbeaf0a9536a,[[3,1]]]]],[0,null,!1,7903978118133453,[[-1,cr.system_object.prototype.cnds.Else,null,0,!1,!1,!1,7093124615072028]],[[6,cr.plugins_.Text.prototype.acts.SetVisible,null,9016231935903996,[[3,0]]]]]]],[0,null,!1,0xc3a65bf4f2a22,[[-1,cr.system_object.prototype.cnds.Every,null,0,!1,!1,!1,7317966506217073,[[0,[1,1]]]]],[[2,cr.plugins_.Particles.prototype.acts.SetRate,null,8632633260751814,[[0,[19,cr.system_object.prototype.exps.clamp,[[18,[16,[7,[4,[20,2,cr.plugins_.Particles.prototype.exps.Rate,!1,null],[20,2,cr.plugins_.Particles.prototype.exps.ParticleCount,!1,null]],[7,[19,cr.system_object.prototype.exps.fps],[0,25]]],[19,cr.system_object.prototype.exps.fps]],[5,[20,2,cr.plugins_.Particles.prototype.exps.Rate,!1,null],[19,cr.system_object.prototype.exps.random,[[0,1],[0,2]]]],[4,[20,2,cr.plugins_.Particles.prototype.exps.Rate,!1,null],[19,cr.system_object.prototype.exps.random,[[0,1],[0,2]]]]],[0,5],[0,25]]]]]],[5,cr.plugins_.Particles.prototype.acts.SetRate,null,6062215411365679,[[0,[19,cr.system_object.prototype.exps.clamp,[[18,[16,[7,[4,[20,5,cr.plugins_.Particles.prototype.exps.Rate,!1,null],[20,5,cr.plugins_.Particles.prototype.exps.ParticleCount,!1,null]],[7,[19,cr.system_object.prototype.exps.fps],[0,25]]],[19,cr.system_object.prototype.exps.fps]],[5,[20,5,cr.plugins_.Particles.prototype.exps.Rate,!1,null],[19,cr.system_object.prototype.exps.random,[[0,1],[0,2]]]],[4,[20,5,cr.plugins_.Particles.prototype.exps.Rate,!1,null],[19,cr.system_object.prototype.exps.random,[[0,1],[0,2]]]]],[0,5],[0,25]]]]]],[6,cr.plugins_.Text.prototype.acts.SetText,null,9405966255769602,[[7,[10,[10,[10,[10,[10,[10,[10,[10,[10,[10,[10,[10,[10,[10,[10,[10,[10,[2,"#"],[20,2,cr.plugins_.Particles.prototype.exps.ParticleCount,!1,null]],[2," +"]],[19,cr.system_object.prototype.exps["int"],[[20,2,cr.plugins_.Particles.prototype.exps.Rate,!1,null]]]],[2,"/sec"]],[19,cr.system_object.prototype.exps.newline]],[19,cr.system_object.prototype.exps.newline]],[2,"FPS:"]],[19,cr.system_object.prototype.exps.fps]],[2," RMS:"]],[7,[19,cr.system_object.prototype.exps.floor,[[6,[23,"RMS"],[0,100]]]],[0,100]]],[19,cr.system_object.prototype.exps.newline]],[19,cr.system_object.prototype.exps.newline]],[2,"#"]],[20,5,cr.plugins_.Particles.prototype.exps.ParticleCount,!1,null]],[2," +"]],[19,cr.system_object.prototype.exps["int"],[[20,5,cr.plugins_.Particles.prototype.exps.Rate,!1,null]]]],[2,"/sec"]]]]]]],[0,null,!1,0x928915e9cd3bb,[[-1,cr.system_object.prototype.cnds.EveryTick,null,0,!1,!1,!1,6917607399799475],[3,cr.plugins_.Audio.prototype.cnds.AdvancedAudioSupported,null,0,!1,!1,!1,9849462572130356]],[[-1,cr.system_object.prototype.acts.SetVar,null,9168531653053006,[[11,"RMS"],[7,[20,3,cr.plugins_.Audio.prototype.exps.AnalyserRMSLevel,!1,null,[[2,"a"],[0,0]]]]]],[2,cr.plugins_.Particles.prototype.acts.SetGravity,null,0xcf6eb9b13cfb,[[0,[6,[23,"RMS"],[1,-2.1]]]]],[5,cr.plugins_.Particles.prototype.acts.SetGravity,null,8351761715539176,[[0,[6,[23,"RMS"],[1,2.1]]]]]]],[0,null,!1,8242976808981609,[[-1,cr.system_object.prototype.cnds.Compare,null,0,!1,!1,!1,5987721542830278,[[7,[19,cr.system_object.prototype.exps.time]],[8,5],[7,[0,140]]]],[-1,cr.system_object.prototype.cnds.CompareVar,null,0,!1,!1,!1,8881592830623784,[[11,"Restart"],[8,0],[7,[0,0]]]]],[[-1,cr.system_object.prototype.acts.SetVar,null,8871831640987063,[[11,"Restart"],[7,[0,1]]]]]],[0,null,!0,0xf980861b0c5a4,[[1,cr.plugins_.Keyboard.prototype.cnds.OnKey,null,1,!1,!1,!1,7240018894178457,[[9,27]]],[7,cr.plugins_.Touch.prototype.cnds.IsInTouch,null,0,!1,!1,!1,0xe41159773516],[-1,cr.system_object.prototype.cnds.CompareVar,null,0,!1,!1,!1,0xa522af7e93f2e,[[11,"Restart"],[8,0],[7,[0,1]]]]],[[-1,cr.system_object.prototype.acts.SetVar,null,0x9f9a93e787142,[[11,"Restart"],[7,[3,[23,"Restart"]]]]],[-1,cr.system_object.prototype.acts.SetGroupActive,null,4593935824136996,[[1,[2,"Start"]],[3,0]]],[-1,cr.system_object.prototype.acts.SetGroupActive,null,7749099240835881,[[1,[2,"Body"]],[3,0]]],[2,cr.plugins_.Particles.prototype.acts.SetSpraying,null,6865126891265061,[[3,0]]],[5,cr.plugins_.Particles.prototype.acts.SetSpraying,null,0x44b2c5ab55ee5,[[3,0]]],[-1,cr.system_object.prototype.acts.SetGroupActive,null,9864700388762392,[[1,[2,"End"]],[3,1]]]]]]],[0,[!1,"End"],!1,0x7309bde3e92e,[[-1,cr.system_object.prototype.cnds.IsGroupActive,null,0,!1,!1,!1,0x7309bde3e92e,[[1,[2,"End"]]]]],[],[[0,null,!1,0x7321b49aa09e1,[[-1,cr.system_object.prototype.cnds.Compare,null,0,!1,!1,!1,4511261893892535,[[7,[19,cr.system_object.prototype.exps.layeropacity,[[2,"Veille"]]]],[8,0],[7,[0,0]]]]],[[-1,cr.system_object.prototype.acts.SetGroupActive,null,4772013783097554,[[1,[2,"End"]],[3,0]]],[3,cr.plugins_.Audio.prototype.acts.StopAll,null,832829439830883]],[[0,null,!1,7259102832799663,[[-1,cr.system_object.prototype.cnds.CompareVar,null,0,!1,!1,!1,0x5012013f72140,[[11,"Restart"],[8,0],[7,[0,0]]]]],[[-1,cr.system_object.prototype.acts.GoToLayoutByName,null,0xe7d6f7283c74b,[[1,[2,"exit"]]]]]],[0,null,!1,8363975973112161,[[-1,cr.system_object.prototype.cnds.Else,null,0,!1,!1,!1,0x60cf0d437e8dc]],[[3,cr.plugins_.Audio.prototype.acts.StopAll,null,5893738282654444],[0,cr.plugins_.Browser.prototype.acts.Reload,null,0x62cf4bced8610]]]]],[0,null,!1,7218792687155007,[[-1,cr.system_object.prototype.cnds.Else,null,0,!1,!1,!1,7503399522701357],[-1,cr.system_object.prototype.cnds.EveryTick,null,0,!1,!1,!1,5378603673816071]],[[-1,cr.system_object.prototype.acts.SetLayerOpacity,null,0xccdd38cda519a,[[5,[2,"Veille"]],[0,[5,[19,cr.system_object.prototype.exps.layeropacity,[[2,"Veille"]]],[0,1]]]]],[3,cr.plugins_.Audio.prototype.acts.SetVolume,null,5245460560361351,[[1,[2,"a"]],[0,[5,[20,3,cr.plugins_.Audio.prototype.exps.Volume,!1,null,[[2,"a"]]],[1,0.25]]]]]]]]],[0,null,!1,0xf82f8373efea5,[[7,cr.plugins_.Touch.prototype.cnds.IsInTouch,null,0,!1,!1,!1,0xb4decc1bcddd3]],[[-1,cr.system_object.prototype.acts.GoToLayoutByName,null,0x59bbef9fef967,[[1,[2,"exit"]]]]]]]],["Exit_events",[[0,null,!1,0xe7e976c27bdd5,[[-1,cr.system_object.prototype.cnds.OnLayoutStart,null,1,!1,!1,!1,7777797351584432]],[[-1,cr.system_object.prototype.acts.Wait,null,5810891606874927,[[0,[1,0.01]]]],[0,cr.plugins_.Browser.prototype.acts.Close,null,82255096705349]]]]]],"",!0,800,600,2,!0,!0,!1,"1.1",0,!0,3,!0,8,!1,[]]}; \ No newline at end of file diff --git a/tests/automation/nw-in-mem/package/evening_fall_harp.ogg b/tests/automation/nw-in-mem/package/evening_fall_harp.ogg new file mode 100644 index 0000000000000000000000000000000000000000..003803ce2e4d8a64f8e57b5a668f34f847c57bf9 GIT binary patch literal 2056918 zcmeFYc|29$`!~GyIUMs45@k3-#>_;fgM>0uA%)CCnWr)w6;VQDOh_R@BFcP988f8} zm7x%lc^=QR4xjJ${{DW?{krex^}1irfA?zJ?Y-98Ypv^A*YIA~TF1cA(FCBtKPk+7 z{~@P)QWD`p{M@~+ID3<_P^Sw2sp7d``7L5V`tsk2^d$n{RKw-#4~!B2TSD)*#0e{y zIeR#X8F)Ej-JGwS-)kSMgO!qyI3Xb?B}EA~XBNjh6=-EYvX2)6>*9HBolHX6t^{!`{c<)=3OLv69N% zJp#R)VMExf_TJt$j`qs1J6RS|H^!zqCZ@_~?fsmuVfAcmb?x2ls9^pnHB-&KO8cK* z^>FvL_xi8Z=wLN1O?_icWqo^pteT@eLcULCDOD`~aLbPdJM)>2@WOCxQ*$?r?ZD^W>#_ zQ42rMx=Ah7jJ>5RHT5h(|K!y3r!go02)^!8r#b%m^BG;qujg%xYcZFCygL*o(*L

                      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


                      +t9nqDVAP}9_4 z7SG34AUu1&Y4|Qi;nB@UF8xa zE%akokL5^bN1hRz&HvaSfB%(^JD~83i;GN`1iCUwKgt{LFZ7pPTS?{ds1eJL!-D3U zUQYUTC&=r9kyh*#j+<27Gbd0Nr?b7_#ay5Eae$+xX;0@Suq7M9F{)uN6x!fAtn(nD zm{V(_v~8yF@uLR(qz{kNZ*FoEEw z0tx)V@WZNiKI{GnV_JNml_WJ@mH+DH`G<<_?{(donb-aeKb&KA-tLphoni|q>d$m_nt8G^l14roO;%I9fF$=TJrLQ}!q>n$-iV*L* z$<+FDnYR@4!0hozgAjzN2Kt{V`INtOEIHw}@w;ekMVptgS+c1mdZ#R!23;*YT!s_| z;lfi67du@op{0B*=Joa3-NE;nd=?r6+k1Z=$AJgRX51QVC@KezGY~iV>^;fNhq(oO zUOcw^;!B5$bWBIyfGboYM94HmCSZF2xUlBX+TChVDA2%B;onJz?dF%h+u&Q^eNV7 zyQ9}fM_z=w+!xQQmDgJfNSv%%_KMfS(Wa$ zgEr-l?z8ddebv4+et&nANDND@FPwgFOa|`WSbrQ$HUvo)ItRNDBl5I|vS&zGg&AdJQKK5}I zy?S~BXN%-=#!;Kg>af4tUM1%1X5n>YFO{6`;g z5F0i|bdqyY?j!ri*4*&U`k$q-^}i}AM2&N2&t5a$f3v>|f#x^RiHC?Z*L{`he1=`V z``p7qS4WbLuP^$7kaQV+Hm-u>Js!sE@ILL!7AN29-pR~$%yD&gZ<($O zxF<%I1dyh~_lYvxs3+H3ANvdU_C#85_Ey7RFZsOmLl4uT5w-N70vcf)LsKRq3=#lw zUoIU9s0zpvm65lk?=Lzu>-;0A{_Zg>oUHh3kl&3J9xF*KvPXDpB7dGe>9rvtXl>WL<0qa@b^EtAFtt=UpMDb$pjboz=kDb<#diWm^I)S598fI!om9Iw|FtJ^PgT!cW{>HVRRN zX8~M=O(uZZ^5)F@nRSQy#P7ln^A3vZv_b}3UfoKl{ZPaEOz(7W5v_7@rIxBfX$Ai{ zV+*!XXud-(3=eqMc>R|y5rYM4XG;&EZ03QkKhag(!;Gqg;Q#5%k(O*#jx;p<44w(( z;r52gWr~Azf@zy}cXrAtZ9W(yENR3}qI6Dh3cdc73%8%KqT z?BGeBz54J6u3-AzM%^GPK}( zfN4}^MwY71lNX~L5tnZ_Dm$z#SCxGt`^oKl$eo!>6;cC1(hraOZ07q5N(VZ$Do_8` z+-0ZuZ_TF}D@FFl*gEvd^1TgH-Fsq4>Vy@^L;MZdGTjU(Bq@xK)4Q`@tv6;twa8Lm zq{!Z-X-@3KNO4`oRA;aABt2NGY7LyQ%zgZ}Q%$JA7i9&W>(8mkadP&Qj)zQqu?3M@ zs=!{bI~C>z0L8cF9xCzX=lermrcfRe!BX;>T`s| z2dF~CQw^ha-n+}?s*s_!C(9HI<-!*HhH!b~r&#bu4t6=bZgMP;uirkm>EcAb6+HO2 zft~>>(SA-mxnOsv!kk=EUnZrfM%#CRS_R~$^9re=Amri%e;97f%Oo*g$h=L2V*RjPyip$w`O666G$~cTt+mi?izqOrGDvxhSz4G1 z#~pZu=&R1uBcD0bR{e;8I*Md|{jK}I@k4X?V?Ius!e*o8?@z*NiT)s!JNFUTT)tM*+xSl0ng=@caWWEqQ)nR4qjXdp5P_N7 z^`#Z(KX2M^iEDj)L*f$|i^is7=(JfXtA8KTen@rI1yQo!-Y>UPef!U6X**jmbo9EWLFe1rzL{rQJC2HB$T_P;IMJ~2)hfTfHOT+&Oqbx@D^bB^gIKTui(o(nsJg34 zq6}|bW0yJj_rZ1V=^61;odW_B0gDUMOw~Qu5h_@DmX-$?FrNii#j!X77hIB*$1pC3DeI=d+uc6!^%ho!3PLXlw>?kq36^BZjZz zj|Q^Q&bRAx@!_Byl`|o2N*A*EqEE)NI3+LShHZkd-HksSRg(jl%p;Oa%}Yh6fU&bV z9O>F77YLROR^q~LjMCBtauJS#qtS-_%y(=s23AlpB34ALT7^E3msxQn6K=Xc;3Q)0ESs{1@`o8FyN zrj_YftSO_!cGZ8Ak5kSMtMUYF&^jgyvxrW9AqP5Jl=QS|0Et&Fu_3+WaQ>8YuOfX? z@n>BarkSbV?#KF^jnz>#i)5}2kq;nTIt0N21>sA=_U~m3P!`wWv0r4IdZOV76-t)r zj+lF>B7`I1ks07YR5@?zxP_miv7F_&fxIDBS3My1c{2`7B(zsY1l}dnfCXBmY?FS4 zuv@AOJW#VdV@bx~93#sH>2pDBtk&>)5nBkmcD7na{0D1}joIJq`19olh!uG6963o_p}`2+V0PAk#Ac;mdTFmut;{&&vRgsR?>(LhV+ zRmFDl78!X*r}~&bw#sOfR;oKRlP6tPY%w1i$2H(U%yJd^5Vl{WBj@f&nmq7wX9C)g*_iL ziYymGadR0!OKdVQL2rIILhte8=BbF^Me)3M)ye#U0gMkC_kuDi_X181+b?a(D8CCX zpY&jc+GfSC8C~=&U%xer|2U1DJyGX8K5gH4|B1`f=FRlg@kh>W=E9I} z!`~)#MOk&;8t=B$W>D&R>UrbrkMWe`1hxQW-G)1ZJ%PD9bE0>El4O?n-|udJ`xJX$ zyYKT2f1v7SuGKr=veO&E6Mq~J;!Q0|ocD|v!v1PM`WRDS8E7M(CMcfy$+k=NwqcX0 z?e?Ytg$SI^$W1pDv?39!bXYmdE9;$|GngQFIN1e ze?0xPyqWG7zl48MBxq4L==#u2<|x7^xt!=J`msX_e_Aqm<{m>`l6d1DwhK1@N4};^ znJ9|%*&y(?oKbQ;){c|v^UW<>zZx4bQls_!cTeTeiM{Y@v=Dz*GE1>kfM4b9kh_Ij z0&9cF{z>;!O>5$)G8QJlTHE|@`))pbc5N)*Ox$$C<=UWTON$PJJe}Ip(*-NCrh`6r zOxjxv->%gCcs$uT=~p@#&?#}_v0I=D28!tYHhJ}wqj*TW`|gw9qz|=E1d^vx_pUj< zO>>aPgCrh%qqoyDcFXzelCJv-HYK}v%DQ^mgl2TUJ-sGU6nKB~NuYf|(q59$o^5gB zBd?Z*K%UdFBQUMnQ>^cns*_w;{5Na$kk=W`E02<&THkk+KCE(Pnf8L9D*wXf?txqD zL=qX2vmIMDTS2zZ0B}ByOXbDtG;|Oc>|TU%UnCvME=Vl8Pi0;zcJDqo$iITf{x;5r znZmg4N1rOHFWH7YjJRyFp>U^j;a2nFN>1`y_t$17EO=C8=2B|Wqavebe?UC%bg1jm z-pIErk}V3ZuV29Giz6|@o%`bGc@wFai!8wFtg+aW!p{BJ1eV<*=gE^V*v-cOu~1 zYSBjTznpj+CSGAKF3`8o1`Ei^%$vf?){qH zZp7lDhc{hqtWN8+y*g@sY*$d_`(A}|Ml#@S9_B8PK_~?ISnnHFRW+8aGQvRSmN6@O zGw|L~5T0sg+7d_0fCnkXI8LSYUG24A_o@)Zi*eyD8FwitU8d(c7#`*6{g>PkiUhy~T9S1wUyEO7o_y zN1tS59V&nD-iB6)1J}j4zh$s*8vIG7acP2QU?m&DWVA;SwElsubQ-DnZXu|z?$hT} zxj1!;N$Ai&hGA4|;ih8|6Brwks_4ExN#@Hz2}nI3OFNt^-+V&u-0bwZFTSrKexkBw zEudh|pYI-}!i=-m;P$c-@8rG2XDOR+AC}jpMPpc9P%ivid!@<=#;ZZPEh^4}pmNIO zf2ta!?EepCz(Ii4E%x2Rp8E#->ie4eMEFYywwNgH%Rqrq0#w=nw3dgupMOws5W*f{ zI&x6M`E3)R)KMyUZ4GTRP~BPl$t(nDMC70xh|d15#5VNeXaM21*`rgjm6S}I^E-Al zu;q!6q%lt)^LpZU1OJRG!J@ZBuoBA+$mUc51!J-Q_Oi>~uJExSXgi5yu-V+SIJAam zw2E5i)vjE&8XB}>{Izv`Q|2byB#mMD#SP^_B(G>!oW2wu^FN;z;k;%331L;icJ)N6 ztbg)$G%E4caG)RZ`FrEYhhF+59}eaEceK|%xu@RqSFTCNjGOaSb00d{^!Ka@e@Fgj zIGV`&^BAuZsDtJGKurzS$E?S}HzzcpSa6cTFzri&TKs_|5XkTO?yLm0V-?m*&0g(M z_d1*X_R{>CsPKrx+Aufk=}v#T=pQ@@idTg^{LS-pX>8ZM;GGTB*B+`eP0r9mW&pK= zzvNl01Qd`>^>np@=^uCvQ7r>>1Onf1=M$+*c6ZL}wP+Ki0mG?mpUg9IBn+|YM*s~M zAVIfv!UpR00PN(~>A`g_sXv&P2oz_ixOjmE)-|0yqb1U*A1lQFo=C?D?@JBK{~)Uj zyatL_YDzlW9?D;nIo23S_3NbVozm3(0sR2F{c*Y0TV@y9 zlB>BphgXE--i05(LP>&=MV{U)PQk?eGlJeT4MXCm28tG%rW*>Ns-k;0d@=eIkxVjl zq$^OMoZ+YI-E;j1Ru+{Uq5}0Yx+HakXea$>zQ=ctdrdh#sP@HgUS!U`J`|&>+^-jK zS8>wYkm$6Wk>jEe;gpe1By4ZQ6SW)c+i{`?WdSX-(x7W1lYgYr+y`#L0P zn~(DA&5NFp5D5$ff!O#a|I20l*B30LmA%8&21zR@ z`G^R|opyRKl$X=u3%;q+@^va2*&iNYP;dJQ7*=+DDtq7nmBK5l(v*i_qOgTm6HnDT=uFY}&?88Id7|U~hh2(&AS?>#6 zkZ^l%)&>!7dDHfpj>$Li>Lq6!~8c9lU)&q&U(DHp{|xOlFo|#8cPcv(LG! za`t=?ie8`L()%w>oaGey8)AQZ5OAhns%$sZXlHh}=B! zi8$)0v9eONfBG8Wg0SF|fEUj{9zTGL$%Zg6HOl_%x0haJPSJ^YoDpl%QJmq1AK)`G9dR4pgM`ydSI5@CbX{y{O}@q7 zratS7o&1Q@IWVijqif;F_Dw`?mp+T1=Ad&A z`Yd2{R<#OyW~&y?A#OqRsS603FuwHZzmz5oW`kjmb4+1${kabV?*&SEvzP0FHNvz~ zbQW7ua4VzpG((4vo@{649my|@;jctrax8kv+TL!8fW(8 zG0xQd%E!xq)mGj%>Ia_nX!MP}%aQ8=%insdnuP%?oml;=Gv*kxG>>aP2FXDIlz@jP zNU#Mvimauds+{Z0o49gHib%u|r)3kmgO@#MBNuh_#yqgPF{SC*34ZTN$>B4R19R9R zdp@&2$h4IS(RHFiYdZt3YQUM#U}S2Ec>UtA2sNNgP;j6JFvq3hc@|r8r>gkGm2KYQ zzs+aEwo}@z%;rCqmpwgMb;z^uc$a~-q!FcQf&GQTXk z-e7{NZKSd_o*Q#ywkl^&a77)Qh5)!adsJR|(3j}i&_ds#WH!9FC7~U>z&)z^hsLU; zoDW*>ITg_1A00{FYKsVwPOE&wR?PIm5dfmhEw2we%wE-I{@?r*aFy~Qy*K7mQZG(^=T=b@b_DCiXCBsACfQj3kKvTa})BICRXk$6R?D*Y1>H{XaM~nK%&#_ z92h14K^I_N;DGgqYj9BP^|r=Wgz=U(8l8Lxg@k)nxEgT>l_uq;6}F@@oH^6ql=d;x zRCjVeg=Ox5I@d#KR4uM#dF_Ffuv}(=%dK&ntP%Q62c!`2G)dc(3|b~T(7TiQ)JNMY z8b(E}@IOYkwQ>1`VY#V!S*PVU5-MWY0Og!hiz;4nzJ73K-2=(l^Wo!XdYbu>W%m?` zT>u0CO2aifd-3vPyNQou(izMrKW+uoe9KkV%ol8XT`Dm*+c$Xb%80-?ut9(eYA-3$ z{U`yW`|ATaP**QJTQeh)MpXdx5g{~49Z(@$x@qX>ivXn$MgGv$38bl!2E#08Sn?V^ z^+?nB$-;`^&k>_~>HoMGL+pq?4_$%7OSOA5?FVZOq`h6xhH`Wq zhA;1i>=f5i;_{nryHO~6l>CMUyv*4jf}X(KPzG8ppd0!&1k5;Xh2K%^G^7xYkw-dgVHfi zCsG;oT%gf3LqMp<&K(TtB+z|21n!<+r}&~iVFW(|x}yoa*ERy34U^VP=CSlT{p77D z>=!VXe%|JVPUF>T3*br)Rwkdez;7isn`&Ib2a9`C-0Pz?x%8}FbjMF;O{t~Mnq56* zu<_dFo&xofDGl6}fD3F!WSryq@KJga8uP}TjM9`Vl+a>21E}w;TIbk-O~ZtSd|#pG z&}9h6FEsaKC00hjUt63cWy5r!$|TbxeZzau7SQN0@q_4=AIqEWYYp_2U_rH@^o~Cs zwv$7v+apc)F~Dt3O#Vx36FXU$82EHBpo!^E?uWsIaVo5Tg~gR{x!v!t^Nn-&y@EHR zHi^y~u74OCw7ttU$?;*6rka+&LCK3TbYt}hECRPFcDqf4hwB0?^=}b069bGu4+-7l z4zfUQo?xOQsx4=4xip?U_!JPks_3V_UFf>gavdrOL?9cVTPBG?svWU#_+`$Opnph; zg5e4)9-Z}9`iXs2wR-H}r&{%`m5~KN>}Y1}jl26+*-4D``l~!e=Ptj^FW2N1(?v5L z=e&vicYx20$l3%d4djB!!(CQ_7mn7|NaBbv<#i`WO(fAWC`7jDs&XJWJ^z(~qSJdb zw$@54H-rFC*9wUk5$e^4jhR_M?BFAfEJR?H7krs39&N8#X6jsP$qABwaIjD<^*a1- zR1RkQHRf<&z-mmYrDwf^Q#tEKSTfCeg)Nu&1#fX1HopKhT4ZV`^8RMA0zbjmG)bGx9Zi8;d z0P*e+`G;o&4j=f!=EDhwu~Tv1SdnHPk!-CuM0}_@JD?vL-CWNRBByr&;Smj~$_9F{ z)vJKZGYPna6P=Vhe;0~65$XxSjiDZXhs6MU2wf^9riV|Ov00tOfdwemoGLb_UaCBc z<}h0DH>fJS1p|nPI6X&1AuI{;J=lC??|S!icKuc|+@6jHuQojF=v%GKEP5zYJzPh| zR{LEF-Of^3gJX|`{_fc1KWV!Su4!nV7p%c#AoS6=o+IRhDQi<*W^EQY2XHK&Q99{M zFZ!ps9~o|h-`B`ana@vPycm%W_kY18eb8DW1ao0gl6?110aUWF$K+sTP$)&%yn)BO zB){9F`(>Lr%@3~=nWE%eTQn!lMX#A=ugkSahz-G)4wCvVlRi~R11f;>Jved?AyS8v zd6S3&*Y|0_#vxC#y%2;|sg4btC2mV@-*%X3f^Ls_j<{Hr$toM9x_Y4WL+7c1E-X`~ z1hrKU;JQcgT$34RzYzJfuz=YA3;_i1NAcH0qps5zl-hwRE54=4YuoK5zvTV?XvQ2( zpS{paQv0QR$txJn5gRj&C29jMM)N=u@QhJ`=HE8++U{0H7+c>kY;}?j#jB8~9c#M2 z8XWa+2cXM$FPJe_AD?tsZr6&Ozko0&aCBU=st*f$^W2LbZl>J@Df8*7LVy>A2^N35 zMsAQhI?!}Pr}^p6oY^eBT-Etv7Z+&N zQdX|5^FH=*CHE$$dGr&@qJ(M!*}*beV1x-%j6HcBtRLuB350ay444{tOI#-6z{*AI zFSEyfFth36oA=(uBpgHu#QzmYjQ!gH|5`}s;FqN+MAi>;!PXIuf9)d3+Vs-!{-J&Q zegAzMh%<<}Y9pvLkbrye6CrEt2Msv;1>QhuCgU(%a-rDuWmCt;zR@(&Z$9A)h6iMm z?~5^}&fWgtydfD6)2V9^qm?>J-c>vQud#h0LGCgckq<29;-Y$01r8+89O;N&3fIDM z|AX_d=nlqvPW4XgzHhi}FF5w99!GLdj}dgPlq5iZ_zS{Ump6cIO~im&D^FZu!WJt) zptoK>M61GzgU|JPe`D*V>-(A(iG^ul4@~*p+D1ti1N%$Di+dMD%;8%@>#m=1v}=Ih zY95ATH@^w~Ob8dTfLj;5MHYf?vhZxO00L$G=xM{Slz}XFkoFs||E~Pcy&OzoZuXb} zEa*CVJgpGiuyo_^k_KelgX0bu4qybG*R!Q$?=Vmfb}TF~+PTcix@F~#bj}L_-^8uq z`SrHvYKgKg%mcerP$ZBN`uWg+uQzam#-KN-uKy5)R;r0ONd|W>d72%*61Xgm#w9&_ zI6gIKD?gpUvK2QFulw!kRgq(7ny*CO^MNJk=sLE`_i+&B#BqS%`PigJPYCR{fJ90N z_`0mJlWqv=iEQ)>O2haKoCQoqX+ zr&g3-F;WXY7=nZXllz=kz&OwbL*dD@Y+aH->-Y7Izk9+Tt=_$}6L_f~NQPbnndkAu zeqHlvw6c11_BX2N-PKg2^R-PSX5~tnCU(SgDsC-$_KcAwg&`M#&JEX zocOccy;t%=KCMp+Lx@|KRSnZxV3~AZ{Y(bBmZ^sVi{-Jz{(~yVt7+Mj@skJ&>&YWI zCswnT(iD19P6wT#z(7QyEJyyT+Da0#r5;DqwOV~hv2iJxCbwwNgItU6Am9P9G)+6z z7Azh`DD)n%OcmJo4CG1V(MY)nvy6GBq-1o_SJ2>h-|vT(Ex0;`*jFD@Ne z`L9rHR6F54AdIZ)z@?qpg#&Oolm_N!g>v^tKjo2Wh4XiW>!qXDCT%zUVG9TsLZ1PDwm8n?3_edEdM^u>meLG=i7Mk(Fo1`m zQh!SGi2F(K>2}(tEg16sVRl@IUZ1o#>bwpY3dFt9nY}&?;0HwTwuHBUf?5LX&B+De z>TuSFJ&y-gYdvg!$_!_xv0MpONhP{?WWj8k2&x59$#*!Q;RM*J!4n*z6c)$A_XmmW z6I5FU?)5W!h4voB{ggE!o4+!jIl?r`aYBx&I+_fw1jc}WTG17z{`MjuXyFTKXIADG zwC(?{2Pw>UH*B9S756Dh`AWp5l4ZP@pSY?Xvd*#yd0POfgnOv;Z<-JqKt%|*+28+| zLuK#g{i>L6gy54#yh#Ma`Q2$9C|-4X z(yQA92j6VyXv(s~fGxhKZVd`ugh|hfFBu*)IabXQB5;2byc=BC@id7X%q z{Yaan*8tsFn<-G6cz(299z9Dxlzu;?c?U8-4#SU@*na`Q5jq?aZ?P4TcnN*a7>}3> zu1Z;AIHZ^+ubAw?od74=0H4rs5}0q4A%FIuQzStG@ldBMCAK|5b^H2J`hn52M*5*b ze!qN%)J9D6R4!|8B*{?)29UvXKoq)S@Eq7a3EtKE2oF)%c6reKyD5yi>TK;MdtHjF zZzO!ud8C*fck9fNM`4b(n(4$+kE<}8O!Oj^`G>TrBlR%vx*#)tRY+n>6^5GLD3ISy z64+*{CwPr#&Uj2(N0-hLIIaaVnQrSoopP5cPdj*QFw|7l*63()71KQO{IXjcBo4>s z0lM(Q{XK1j?!AWwAx(L}uy`?S5&=|n7{1fmgKUO(u6ypkK?qR^l*A=p5M{{%T;StM zI5C3ki?HfwWz(#a>1ECD~59Vou`QU0!#Wg%y~e2WkrX%_yMw2 zq2mdA*wEIu==eK5mVb`~h!=i4Mn3r7d3JPDuw(%#{2GB?N!4nOF(XKX_Gel9Npb-6 zBe`7B9nsfm8F!!vt-L%lX<5dq0b+>-(wC2xAD8I=rt~=9KL3>~^eDe2(kRJiVTG~d zW2gLhya!~7*j{O4A(*(Xx#PRU!Hh5>M7%yjVxy0b9&ZH~%zYk*d!edhvaZ9Y9(u9V ziPmi*HQBs+fE`TJLLllHHZZ>=XWV6yJD@k``=^IdSl+>MN=}RO^+B(QFyV3$Iz|V` zr-{@>z`7uEs0TIfQds(1z zvoVaGL9ddXcD_O^$v8eHVqvJJTotuH(_yJ13hpn1zuyF@gaqv#B*fk#3#@WleQ~m@ zd%?UI9-=35G%|0_XF2zU_`>z@4wgV3r2yW-jGrJ{atYnq@`Z~6j{DUBATtLrXeMRn z%Q{e-JD!}LK~!9Usb}rxjP$X$<%e(5R=0W2Hh#0=e&%FZ$zx`HzCL~6ro`UWu~%s! zOjs~*@|hoTz(o#NEjzT;YVW;i!iB<)gJTrVZ0J)l!vR7_nKV*0YR zBGoH~yO`dal9J+ib|>7qY;i=Db95`@uFAsW3*I(=6)vq-=4+ZHQB5fulponLTXT#U zKi;)pDR_Y$y&15#T&+nig?00_>7QaKa!h#mH=%NBj%>+WC5{XYnw^`Q3pc-Ont#1y zD@dajG=jzf#cjd4AgA~o1$=)?#SJkVizfR0tiijxJ3Afyh(xWGk4ja=tSEA!z2a&^3M5V+6NDP zD*t$A{w5GX-MIWDrG}ek70oRL`jbnuv}bbb`~$9-aed1we}72;GV)w`+rGQ(PIFMq z7E0S`1z+#L9UN!M?gwk#D>S_;%o+BLL06>;X2sQg2=}(K(M2ETzFinZLuTc$)GWpg zMleJ($SU_``18!N6m2|mW>_j-sPHz2vA}_8Av(`oWA#HvyBpU(mOa4cnpKpB;5xBG zi@IM%sd=v*uUPvkAFninVt$eFfjJqaP_Ejgfc(g7wdKNf?dw!lGz?C^mhnFKmrUKn za3--ni8^xuRH3_W?q*%N3KC!Kc}!pW(w)oNO3qR#SDzDGuxgoFY5mk;F_j>oecS1} z;`P`ggVb4Egk!P#yDwk4S0mwsbzItau64?8bAtGE(;~Aj!=Xbb40ApNbmQ+YiUgGL zluJ|_RQo({utR&?3RXC!%m#pYYS`42on(>y^tEWSbu=ivJB!075l6-@r$}ijV3xXl zTe%jd(V3fV91~cht0xx^5C+zEL9M+g@dv?n7DMs)rL|ED=nT!xJWAeruP{KDK|{b5 zSkbZqRwFcTZJxFm9@4(Y5EbhTY@EYYOfEZG8ak_)O@zH8unDy9yG1Qc|nH2}|*v^fM7&Hc`rbyF< zmo*l)Qk=eU;LwU|R#_O#_*e4TD{~k6ZcOif=6UWlQ@Pu6UKv(_w=T*Q$A!H4u@*mb zwSrt|i1M923y`YlZ2|=?jK+BH=JKcXW8?=!V1%ta`eg&;GdaD=c8tT@Umd&~UuBd! zW;V0E7Q`=Z<&+kDnKymn^#XEgxJevSaPK%rT}5bf4Wc>gvJOA9V&NvVeIT08iQR z0It}9d$pXV&6Tox)b?eBzljk2n!jp;b5%KZxAF$|`*J2F?Q&&RbH z^L_*;%QLBm9eH;Fx0PD^SN0VSh%w?WPwzVV zZ_?uq9b&>B+B%Ze5&C_`={%KJJNlaEBhVc5wqqu@7$s?Jn|*Ae2QGsrk~4RDk$`q+ zX$5~0;5VAN@)3~rw`X`g5Mal@xWF0eaynmNK9IwL%#ZeXz~}NI0+spTP0sm#kKO_@ zY3i(fQg%_6knebi?oD1}ob$+~uAs(h-nZ~bL2$CZAu;_e63j<4Vj%>iyNey?yBpYG zMR(wjdA6qj6(BJlB-vQJe?w1z-!{Asa;>0Iei&Ka$7}fPxyR5L()a2}TH(_^;*~Dl zM5c*nhSxi1I106Pl2hBSmKASf;;f0AWj zwjdep7$gnkoNda;^rN+7J$ss`%%hn;O6&0AW(tFm^L=;D z*#Uta{uFS13~58d^*@9|=)Wi`944m_g#nb#3S!(BAYbBGkW+?uiYQ4GCW=7L1Pzh; zkVtZ{sasqpiox{_ZTIjIB|}7{)$GqAJ+FL@V3hV{2gO~Fd&*q9?C)r4T5sQ~_R5)p zLyxSE0TrvebJCU-4Y#*L`cku+yWYT@#l}}o>(R`>jg1StRL#4pk7(Mh-%_iE8u@8g ztF?v(3q?K5ViplwmDka zs}l?N_8ejZRm9I z0D(l1P#jz|SAD;Nbw}c#!@wawX5H^uc_P! zAtkrWOCE2c zgHDd;&zr(FYGB6?n}RWWdIY5ED|CPGVg2~4DbQ#1i^F# zvZJKA3k4d+l3FizGv>A*>(<=$F+&Udd< z<48bp&Q9PAT{k(l>I)LBni=?%hQQ+m>P0W!b4fi%%1%m(Q|!INk3o3X-?h z@$^{#Za;%}+oux=)0BvMM23XQOhq9cMI-mT!T1wPVm(&3qih4+FH36<8kDJa?CjpS zzk2nw5?gi73cF2}{)xmU=3#5^{+MNR_3BD?lSpV#;q~`@V-a8PtX92pC`y(7*Bb2Z{a> zijG>YLXh=z!v#AhpATXL5T*R^$}1e?c3rnD5V%0z4^XE8XWh5`FFd@u|LJB7u!#M->x@2=GNe9*H6Wl!oqxhZ#tl` z@wL}V=^MK^NRaxla=IT*01FLi?jF7*>Q~HX^fCw@u4h89f}^+r_Y2N>l*kYB8f+OJ zfg?7mI^+cYn~X-l4sQyN2Z#Gj_Ai=|1W!ixEBGUruEDYofQ0)J5;ZF>fI zx?897PhA+Ruwo;BdX40Hwm45X>8ucH)mmb$=3I)~*0nI5+{7Wf`)idy<)1C+s-GJ5 zi?iM=TmNnq=(m3D;+iq`XC*ra4n@D5WBV?mFu=kFg_pM>wLA|L?S(Ku?>W0=-Z*Wi ziVuHDJK7!dF*DP&A!F>^w#+*q!zAjb zEy;S4;Ph~m1;H>4u+vAFjItT0LsIKq7*Ptl2>-r4hcP=!aeW zizuP{g3D5?*RXK0*Kz9)buq(wn^dN>Z4lrRw3nD#NV8DPjrO$Dc@^g7mz|?f2{-Tt%i)@?ig{{mdJb-W`=<$ znEp`N6mPOA<6ZwiV8UJZ6~{r5WwcLF-herDB|cKQqy$D>kB~yO(nP!#e3tUFP(}?R z{UmP`4EnTCz!(x#fx6@O*4NuA@h#L)-R`ZtIG5+raLnsLF{iYzMni+2e>uSO6%7M> z?C&&W&41IucMwB{G}xN^Iy_9?)c>|f1j9B$ET$tIK>}7SSNSwmXQIZt#|Ux~8X%qf z6a##fxCjo)vj7{h{bBVjX58z`Wt(a7SIu2fj6CneO1=Sx$KRaBk5~kwLgBx?JuUEd zz|U2rx9z!XcAu@zSxH=vd@lkQIUjoU2isjm?3ET0n)J#M8bMnMUWo>u zZ4rBu{vRfWAEKw)T~pb{r;jq-?%z0r26Ug^n57~8pEM{wgJHMuTNeQ8>sv`RFZBqM z5$?Dfpg`PY%oPy_w{`QKj{5S@BDUl=JXu01UzLg2){>dZ&Kfi(?Ny%#M|=}Pxzrhm zB?mH^6GenmamaXruc(X(`G;bVAD%l%VgH`%YF}!kd4@B8xPWjYOH~~u{_`ED3-(`6 zSLKr8o@B# zZ;hzr{6IZKk^nfL_T*P6?YJFswZVZsfs|PeZQ7ym1azm~S$ zab1_f4v$pZ6<)kw=){nq(QO9w&{&A&a@l=zX2(2`mCpAI{$)ZbMGpj&x0RV5T;N=F zcYxsBML86B@{^Zz==+@}%;VXg@0~F8{n)pNmDCVjTb(KfUC(OqI~j^v7aKV`$eW=~ zm)D&5eY6oZJ_m-#$l_96ICGdv2Daletu>TL;2JQ{sCP6#NQu|+yB6QF?GxXVhl-22 z;&(ou*?72e@}|=#*^TzES@6EWsmJ~(eQvqb{iXrP{=EyT^-1vU_&Cu9xJJI&7YD=2ol*>+Jr3l-Sa@*Eea58rt3c=8y9rk4Q z>9vial@m0xCAbDuDh<}q1gwlXs+wcK01IB%zS?W-MH!N>KtoS)J zcuNDz@RPCe-Ow5&KI_CJHIwIg3MUW8S__3v>tEYFx5MqpECfSk{QhUh=DmGljRgeX z#y5EKiL`)Q95^3tXTEYmQa|m-3Zi+u#Qtp*mPzp8H?{lobssAlj6S1=Q=~KwDm1@D z4v_;PiP%3wN4cx$PSK!=cW)Qq64tz8# zH~LWETaYkJ9)0Avb{|$={9$md>6@ys#1hTNQ?B1q@C6W=QWSb4vafU{qG`* zaZ^yf+cwBa?F(5E@K2ylR{jsK#PVh`fyUG-|m@)_)Y8n3sQ zkFPyX&3QZX=Z}%j z5WDKs+oC8AX@So zTK44K$H%uOv9)=*n=W=KXuwCDq?d6s;Kb|RDTmtk(n@{sof9>Cb8fU7t zCrRv;x_hQpaF=8Ne*q!fO5hf49#XD*`)J6fr*Ez1qgmSF^xtCSoQ8E*^(^=5hZlld zO?UjA#49~6l7gpmc^AQzi?6Yoh^U5x6Tr^2_69qO{zd8S00jz@Pl%kzG!Oj`Kc|t~ z5+etc7fsKaevmeh=1E}$`CC$MlD?|`)UxZ-GrH-OI>vra``^!=8xGbWVTX4j5yjW{ zjMOps+>W+_qy8<0oioey3ZH4X8~Gvk1R9K*rzkfXRR=OcXro_CG!x>g6M1IdzZ(Ea z7dd?Uo%*zS61+<%ERh9|ntSPn2o6YR(%@pA&m^hh9A)Cq;Psp}+dvzEjXGAKqxqI= z7pbG${vLH1eAbb%q0m(&2};=HYrDy~9DizC+bXvA>BHQ{R3Pn&AX!0J z(VP$VN@Juk?R;}G&`zfCuHh05ZVKLLy0Z_JG~~{jx#kz8#G>H=*l2CicrPYMwLsC# zreyZ@;hmwuWmAXCYdnFX;*S4?D($nv5 zL{8rgcEAea1RD$)wlD4<+cD@^wes?eGMg?<@*FX#e|_MvGq`=}dfGfi*bBRh@Z&c> zc-p7by!+nGvsHOShoDO63Cv}eZqWHJiUnBoZ2dk;if2@9ZGcCAj8hKfUtCR=t&Ht; zcx$7F0Gky%9X6Dpw$Xj!tn0Hr6us4o@|oSiUB!m_2_Qbht#w1E-QUd z)YUI3q1eH}$8LcT1}j9?7-}>obU^AW;d>!c`)d~HHzvuSpFOOfMaDfH%Px0Ie^zx-qlq$S%(@jyL3+wi%-7kWnNc>yibDjcL0Rjf1^ksq-4LsiYRc7fN%UCNCLTJ z$LallIvMovd#~K@J*Ks-t;NN~?VZJinc2zl4Whe+Ws{G0>o}wBGgdhxqfVV*{^^Ro z>c@8oG~AM_$bVTl)tRXsUC>q}_}(W@;(z;syHi!}WH@>vZ_Kyzqq>(Vcjn>x(WWep z4Pcbh1hZL4I?A1BKveI*?5V?IhHAa(SDCx322QucyK8zmgb~_QVGD20s~x!u(~jtN z4kxm)w)!<^7$7ht<{;Gv1xV<({CeEu&K1$#S^)@2a*MH_kf}xout;l)suD9_M81~i z632`RcHfP$+kC*vkyOa_(G3w90rf@)j?GQZ8tZW+;RF;nWIp*a}Rje2gcN{`Ab0pS>H9C=v^s^)*a>%s3Vsy#` z{=zWrc;Rb4aNi_`al7b#zZ>(-kqu2A9TDtPaQ5OBF)yVN3Frqz1eX!16+Yu6GQ2~- zE&!#2G2OBw%^`K-Hw($5JNhX<@92b}XeKqr1GZ16_*_11af-1v8{r8Kc~JzyZ$Q8B zxGo!kyE^q=OB#V&yJeBLfJ=`P;`WYPS&I`Yef+}a=Fsn=WhZ&!y@zb49&MI_z&)3n z7KLTkiIO$tR#;@kBQ>L(bP}wC!!#qA>WzspzMfjbYyBl8%vmHN$Me__pJ|B{J2HFM z`EHsy2&g-dH*l+w)WP~f@bHV(--iz<6sc|Suxe}-GWg`WbWC}`e@_mU{a(k2^z9Iy zafW`CG~^rE*sC8qGjee}d#S>|{7VP0U#OlDWO$Ltv}d^tONwfobmY#nUwI!=o9ug~ zQ)9~Cdb(#NaY-GWU%hV8dkKA6W1r)Twp@?VISQ0%z$GCQ+p69e1Xw&guwdk%&4JO1 z!FpN0Bld&=N`pkUB8e$N{77u7d>)V7RY&8r%hj$rSa}7D{*BnlZ4v$ z0V442e)kcvu;OL{lYfshHT_79Wm|I5!({&#?^YcWxk7F7j8A;I{rrYV`91ZfuD3+F!4K&=vdv^-{I5` ztdd8FS;Qb795v3#+ZOxw8NUsT)1{ZGHP7Bsdgju7=w+in*Kn|*vfs2=XHCcr4+Sjr zb7yHQi}KH!iJ(wDKz`X-LMYW+Voa6z?uW}ikMEp$ zm!z84&Y8sQZuD6UmXGXKyL~;k*G54DBAIL@1AiYOvW`}>Z~X~l$Kxff__1ff*46v@ zMfseYyz(gNbmXSUFYKB{-3*%!L=Ki~77-Z#{cJ9AQJl#;OVj*dqV?dX(oOlMV0=m1 z;on$GnS{@xDuLloEq6LhlT^|jC@fyz2MzIaJh)G&=+&C9DhTrDqJtuyb66Zl=J1Yc zde0aZX@3G-WU+Xf_R=8NPF8V~qKeN8Vs`yfG!_9#g;2MLa@}`H+0WRnazPxdrWZ;poN}J%i0G81&d6H+4{Ziu zI_#0_VYcvyC6~s&M{YJsb!~Ub7WZI49AM=v6=%Av#6QiTh@Z&$*4+wXB6jwg575=>)J1%Fipw`2^-8?ty7|8~V zJCu#0t{X&bkNLZ!;80EcY7K@NjbGi?CXb4s>r85b{Q>Gf3p3nSrqU1UCh~Icq`QTi zjT-8r9>sSuw*IZy8Pi_B_JW+y6QRhR(@jFo38)8xPv`4mBO01JfWqN?HQ-te}{y+a2FJ@9M?k6eo(n{UOjjdL5NWxtx#>T`}_db zy#K94%Z}4yM+Aq|i$x2aSbqBzt&>8_znc3f^vDt9`FE13qR8(hiIg%P7Y|YsK1+*% zA zf#Tz57wVhyCTel(Ljx1b1hD zMdO=6a~}PSr7Y^Sb%whwSpO@7^6I{^3ec{7SEW|z$V7B7;<~H1mrx(cL6w7~#=C=q zHj1?LtR5?4PLZs?Phi@PYjt1`*jLCRcXD-=r~-DGpCzfvUP(d;ata|o_%0jHp}AA; z^q^MH9hC1o(=)QubK_RKC6dpB9r`-fm7!b$pzMmx;-^jHMMa-zy&yg^6{1iV9VYTDR{~ zTuiQ$l7M4t_)v6z{m?Z}qY>N|74I0Dj)gLhSHHEPf#K0}2ba~1&_XeF%Bkz>hgzT@;+k?z$tA{?pQJPZH>gko1I?XjcTW+B9VL&@1!XcIKL=ulrW_y_R87uz0}Y$ZhX zG1(LuZH_EPruda>gs3s!=sToi>r)DcL#hDa+>*FMHzI zyE$!ULiC_qLJVn#z+6)r8b5%_-FqI&DFi_%f|~}aV%LH)GYgS_+*t^TT$S*ZR(w^P zcq#t-IJd2l*Um6>3x7zIB!3!m(ktnLW{Qs;&82a%vO* zK1aiVK9{-Cx_)C5^^9^ldh}P4$hI)QGJZC$FET9D@wVL^c=Ll3{wCiDK zz4X6lTVt(M%xwxHd1}q^@B|pU*%llXAG z`W*%*s?#+|C7dta`aDXc{30Q1s~+$*$yR1oRa2+^+X;w!vijdRkHj{YR>gq4u_S#V z1n#cm&WpN}nKDD4yqaC!d2nLi<;K($QO56+LVjKeQrEq5ezLa#DrWSc?QTor7D|vc zvRTM;kT;1ny)$ZM24D3!f~Z}dIf?jNFW4e`z3t3O&5>hIiGR$Qcd5M7=CIX(7d=88 zyT46EpfUc1py1Z?v^>vcfuLt({&!fT{$6ko-su*eo6l{1d`8Xl%E2F1XYw!A#Uvm@ z@$He=kB29GR)Cm)wj)!j@td5-lsK{#*((+}>Wvbsz>p>hzneVDyIDQj>ocEM;`C3b zxI>vZ@)KT36u^1QlE$9ZB9{4O!-M_v+94`s&L;U;c zeGOP7luCst^PnkI(UUGDNa9q{;NuCmSD)(iAfq2sJAZ64hd#jHzE_dFbJ*A|{VmV) zR*xw;TB#@V?u^Il0wLkD>nb$txmq68uS4eloHsHw;blpug(?f+1ZzbO&$Cz2FC8wZ zkV1b+DEoD1M#hvqBYk8uWYC4h%RpO^lrVVR&Iw~ew%O{HjXzZh3(>(1B zVC5-xcZ_+yR9})GKm00dQf0uLXl^%pqQ0JL>4M9`n(cnyG*Ut8-QSa*x61ZEHgeQu zZEN&Pqegu~4)^v_QNvGx<%)X9;?mbTY%v{rCm>V-cYD66dpqfJ4K+BhMQrf=nmBvH zC1aI@%J7iEK)PVw_iXtX&n4m))gc#7P-Den@GIzD>(+B6mNnDnCa=JwCfV&~sax9R zk0t`@Z9_}nlP~r)hw5J$yYxKNzlLybY%CdYkE1~kNAx$@Qu_s9-gv3?>ylrteyz3|X~`*^blPQE*%+s$4EJ#ma}q3z8%J5>j&nU;yIFZxzYKc|>^?Qw?f zTweAo;291Y)UaqSP7d1n-f!%+{Pvmp)r0IlCc{6sLaoz>C7ppcphywT08^k-bh@2DxQ8ly7B#HMCYKz#iHqoLRD82({kUpsEQ)z)Zca$B;8}xvRk9Q*BW*a9Bw90sQx8ImMvB5;DJEGYEU@k#nC8mF z*$Wi8?gJ2G7U6)XV9cxu0N2TwF=mkedS3=I-P`0M z+sAHE-ac4&et+PWe{cAKr8=G7?6hwzaaQc8kBaeG-}v2rNS~zvn9YQNlwofGGdNFf z=Pkt_Do}b7_}hjZ-9~{Z^v4An;uI>Cq2B8U<_VII@@v3t ze*ddvQzuo_SZ|NIcw_{7tbZNWyh6BVB4^Z>H>Xs|72iSPwVZQn_TK8t-CUbktr%2b zweUl$Vv?M)d>o37v8H;4)++hrtORE;NB-rjKd#uUX;qcM?mS)pxTyAxF4pMCym-V~ z(~_zMP+GT8%ws!oHs7fPQ7ln>XsXr^um+zM6+gcVA41_~2l(bH2-o$eg#wh0b`D+h zI08SKtA;939a!`#ap2@D$|USQr}cJq$z;3VcK>?cPdNE24Rw|0n$YjZS_=~F?hm@q zVnq`83Oo{Auyd0G`HB~hCr9aLZ8jxn{%B|olg}5@rYiSZ3hrZ$D(iI`8dOQio}oGY z>|X05IM)H{UVwJ%eae4C<^;%1%z3X)Mi2*(V28f+F0sSyzxm;D;Wme5^Q8@5XK+hq zM}uKXi2WlHyBGXri-?Y2;$Y+t4{o34x6Jj6)6`%Dx>H@=@=Zg<2oZmmho^iS8m?83 zPvrjo#)sRLq|0&iX3J_7((N%w%U!K#6nUe~6|M7m;~nqNCo&uCB`UC}QZ5-4O{cz! zt2E|pFel8iIv})VTMrTtl$5Z0Yd1xUX8m3MNqV4-BAU`+osZL+K+n_IEI@sBCaoD3T8r7N?#v$Uo{n$p=P$7Q)T8v z7GK5kU5Few=^xA)@5~|lVMfqXLkmBD^d91hN+j@f@6m;w0R*_Ku(e?)fAg0HJj03G z?Zg#9fRW(rR)C6|aNz@GU81GEwn~%fu?H_~S7+SuHR|9w+qeZVHUVH9jxeFJ50>eZ z0x~422(VWFYOoM+%%i53Zt=Tb{z@o^Y8`mL+5;ma@v5h{q@U4SD*22*ViUrGjwG&g zfzi=QA1e`9Qd}RZt7JpBP*t_Pe1H5*j0 z>fJ(Hd!_V30qLY|9@kS1O0LZVy5Uq%9dl;4AarxwK5T{@A@Mf9x+JTJkxliP6OtC- z*xzg)k8`20dlFeVw>y2HrpCGyH^a`$3`_BwMrDEpFDN2o(hK}r;EF!3bH;gox@@u&+cv1!Z@8-h$8jNM`~$x3CiE(6_>*H z0x|hRGPH`!qG8v5rdCAqP-TXbIysqOxlvC{nLj@_ab!JV6XI05qThtVr+BCrK8$Qv zsAiAT;5VqLxL4-!^X{)@p5(GNj~%JyIx!v+gJv}Fgq3udvqCd_+2w|iv=4_U%8BF`zxhth?dp|d;uA`Z2i=hE|Bd^n98CPe}KjkDEu&V+FDTYmSoY^(oV9<9lq z=#>dA)Q{{|*10l!kg#$|Jm#j+8K)FKKSk|}2NXo{<>v=wuGl3856A~HL;>BulZA}` zE;M96-SdJBvFn#4MoG`8|I-0(YlWVq$|QtDcA^(Z9njv~|u z!kMhD(mqh*K#m1(HF3zKe&K$g^ULOP@^sbejb#shGX*l&tnK|!85F+4c|GG+(^i{b zj_+0lyYMjk{b)yCPmaAXC;l{cpdFOqR8W0Q)oK;CoT(nY2yLh+jPyGA5&toJ|IT?J zx-?0OZan8&iw1{@ByxGJ?l(hNcrTz9KhA&Y(lh1tD62^x z7MXFZ@LT>t@D7$`9m+Zgq=kM6o5(7?5b#C${Xqt4!RrRWVEK`R{b4N1&-G|=82Wm6 z9H$(|(-C+!Sel1_Khg4%jQ(DwgWNfie-_be#feDBrhUIXgId`nuDnEa#DbNgIBQij z8sIiVkxFXVFY|v3)(B@KbZ|PAw-E5NJS~%Z&^&-vNMm`{Lo) z8wLD_DZW(jy&!YaSFL>lm)*cb7EZbb@7#5{$KK_uiuR;-N^NUc+0`?*W+NnQY3wh1 zI{k3gfup5z`Nxa6I?$guKEVVnw{T;3s!{ZUX_swr`KKSQ0-qC3)lLPG+gBfG@3_=R zUFfT#HQw6{fCFWZw{k7p`JWoe6mFR9FO_EjN%9~Kz>1e+(!-9QiNw6a zHEOSrKOKl;=|EBh8A^_N^cK*KBa(Rjoe@rpiQ2wT`cSOodIa+Ah^w_9O5n$L()h`; zqFDc1`~zrBO)i16y^jZ}ABZsGpK$s=%h=OIJGXlL!`RD zT9i_{eu}QFPN}n!^`j)e4Cb3GQ<q$V_hQ>nsVAwxnTS&m ziokh`f^BYUOn#@seOHt|Ef)C^+=xGr;f_S(Cc5+iYC0$@TQp=FY68CR7+R5LJN<|n zi%1PXHN7hv-n0_<(m5ycfiC6bgP9!3=EHGxGOwWsNpk^JXKo;WSvQlwMZPPo|JLWx^l82`Hta$?QE9{g#WE3#v!=Jg6m zg$7HCRBB_X+@7u=znpJvqBVKOl|KYuM-x8{cSiP1!{Uf759SOn|7z6+HAH%vmH?~$ z+K}~@$yo!k7r>t-+!RRIJ-sTWI{mA#qopAHRCGGPsRj0xpdNVUw2=u(!U$(@TRM?0 z19ew}lptylU?J=7nUgk?Rd%w(>Mn{L5`-|(mz7ayZx$iak`g;c^OJ+-kE~jvhdJwT zkO6xJqVC@tHlw*HI;pS%nqM1iIZwh)#4Qfrb;I2pWCh-~mgC3B@U1_T5ozh^kUM+S zR<>(B`I^L(eO~r`c!Rvrfe~fx8 z%K7ApW>+$jybz@&OG@&%SzP3lF=ald{^zF#U3l*4q!If8*OY6+F;$8|XS%F4zDd(R zk8l63r0JkKa!&rHV>en$f?AohxxEsLCeyOGqnS!SOhW^{)rwhwC~}@}X#J;~BnW4= z$W0X?O3J_PzkMbaX09Gckbc*7`qTLS)i&ySa|v(O7dZnq{c;M^Y4w#`67)3ojPYWW zI6ZKR6!%r4wght;S1a}WH1iJz3=RYl9`C-QfJrNeDiR45QI3JX0?43mI->L*4e5kX-E!r&adbFm@86~kp zv9IoX8h^>yj}%8z1SM3qvJZ!mP^=Opqjorzz9EYkF^gP>}VXesL0e7Vb=S*#L$ZsA=71xlqb9}fAGK* z7dXMm)L{Rm{E5a)!!2i=P$~D+K+UR*h1vDF0ab}J`xla`atjyOkT}SAXBph$t}(^; zQ4=vdMt&cFoDcNJ5l03Sw=G*21&KXUpZgl$hNxnw$__aqf7&4j=jTs2}s z#yrj7PeX$a@7d=k$ns9fViv@nBFQ+!U&<6>N<5$J^RlgKz)_e7&3G7Jis(`jrff;`ikAh zxT)9gudd59NvU%)+c|#1?$Ga!RG%7}z4aY_LZThNK#d-#^yZ_sLY+8^uJbvF;bFkF zX_pM=-xFgJ1F7IN4YmwLwQ`0DK*isDSgS7Kq0fQy@%rY+>zpG^j>H*; zB!5Lxx3XVh&KhJ{i)o}b&)`{6JdqbzRgwp|w+|!-WQ8697vv3-~CTRTuMW`Ti#@uss$9kbiWe zMudHsDE#Y>{&f3J(Qb&BlJNRbaN>k2zPys+TJF04vVbR_gag=pa`a~Aen>59H+Dbh zVY<2J0n&u!FLf9(JAjs8s3k;+c`A*46uz0vWu9Ro4_dzrp!i?JuB)gjlY@Zzi+on% z0^hL6L~B&irBD5D#^yQ4=-~9O;i|2=PuK82gO8YN8Y!e%#}LM+J*q1}g7ubQok-xA z!yIgHE`SvefZN%3cnbHZsW68$dA~EFB5q3L!}8108#!K_L(AuREV#$}ZS|BWQb`+uj&g0i~}<@@TAl0u-!j|F=__8m{e)jf;)z^Y#lG)QtAQ z+s$FgTm(Tfe7waZLX<(&7K8ET2$N=B(QWN_xS7sU@NTZ}N{bebYo-()TIS6xfm>Ay z{WYM&Uw|$@)HK!q_v@0$ak)halL`~FE7Bjo42aV1IT6pJFN^1R|b<(=F*wpwhSd)PAY_N6e;rbsm^ zcys=xtsM=#NCh)xNTy@5@}Er1 zzx`1XNjiFRo_cx1_cWsUXgiixdX3g@#pvJ!;i(n^$CeLVXsfJFVlPR)R0&7=qf;;Y z?iIvu?+7?2jd#9Du0Pv(rT0v)mYLn$v!%$`S>_#8`HS-&IjPpsi<>T2?H_#4b+-L; zFAY&DO5T5a^C#XPjRT0(m zBS+Lm^zJ`vtvdMo_lNi-EMy}J10I)uXaoH;(m9F zs$bjp!^H+XqQ<);#`fMjcH1spBz1-;$|;Zd^Wp8l6Ph4gs*Oz+0{;fAOznJRP>NgNB{mx2d^7*0j<{TeY)Z@#RUfs+j-sDeC{U3owyBK3g;A)GoQu$_asqrgCU zKUj!xsr=58(iB3Kf4^(3G{@F3=zEtf_w!H&!Ca9@ixV8UIDemmD^6T)<>|LwU09|G z1!Fy}++l2_Z#_hFx`I>HD6sc426Shxi*w>~DE`P882Rbl#&PD{aYA6DTwKcDgrexF zZP)VCU2ha`#i7k!AV%I7KVP~e^R1Cf04HI8Q)6RFtT2rm@jHE`M-JTDq{8@$6Es-A5&}ir{4x}e{w2Q`Yy!h?j-I^wWq&z=(F7tL|Md#U2nei=$Ret;X2-( z{`ctPbSdJ~Jzn#8iJ0jB3=a5gV;dyH(yx=La%Xu8i#*u0J(R~Ebs*w~2M!vLn8#{> zfW+Q;c5Tw@R(}55-rs+7NN~8m-HVF)@321>U!>*A?Wdnmug>#MBf+_xGc8zHSgL!G z(v+TFo$n!D)NM%#iN#3V<`0#NQi^m#vPoRMOVTIv8BKuxG}qc?y4Q<?wGI&lTNT zRgs@tQ+Onq&r##4`uHT%V;7Kb4+!#eoJU`!+i>|F0*V|tKYPpWj2psYu_Y_$$VTEy z#4ziyxfPIFQ24NA!M5p75|P`>a`A?q`&~FGdyXcadheeC`+GH*J8wTgiCJz43Spk_ z4?-hMj>$C~Q9(-PIOE0KLZkAp{7ZMhQjmLguf|xkalzYz`C}RU z46N{K-eJb3?EoBU=b+jkL2X{^o-i%RXL~Gr?enQU`GKwM)fO^atLg17j_xezeq|Wo z*r;9)+WT9-pWooAaI93iD?AWiJvQs$uIfF$b1H0 z7^xc^PQxm`gk_fYDqMOuNTYL6NCHo;Ax+)0_ageyaC572h@ya=rn08cdIx8hB$N|@ zSE&@RUtwiuRe*uW$`&MSAGPJkNKq7-&_7wpLt3BH@J@bGz<>B{$4ck?#T6vJ1$wcU z>t6=zQ822E>pPd5pY-~}8O}ctIfM)M#%3#;DEB-~WWIM|mKoI(yvwqM*ii*Pi(mSY zsfn&+ zX!-G0WE%N6&0gpF@U!RT|FrGkZVYOJZ+v?n^YrmeM&PuwR2tElUj93tFUuu8n1gook; z$IPcO1n*d8DB<;0)a>gW%c@T$qaXW6iWz09#8PJFoa8||#rr4tx9l=fs(TAg?XO^Z zg;RuIJ&FRjY6nT^hOO?FyE;T%crSP~cK1pQw`{wMOhrfNhfuecOQ}#P6Tiy8SY_0N z;qttSY)9gMufIt~6*CdY70q>6ultA{Zx+B$mfiWGB>el+cl@T*!nqqCezOsKQ`{+I z3H7e^!Nnt0b8R{dxRJA4yax6i6F=`_$R%0>NojapZtqd>WAmdHYyTLUfA^29Upy1` zO20JKNBpW439gDul!3xN3XwsELHZ%EmF8^+-pSMg>IuFo{N6GSMpDB76}mv$t()NN zL{`*e$+M_GJSEY;5oXR_JUA zWr$=FTWlNJ8njqKw%z+*oJ-*2(Ems}%9v^MQT zztBQBf=B8WFjo9r#Yatpz28q7qd6I%_@3%cG@h+M^)b6)?u*A+f2LGeZ=Ss@TH0#; z@wDLSu)9A|@`Va>HZF{_u}>f5WW@%=_herc0n}GKmed1sAN53KQ{hS}i+f#_P67x@0%IYE8aEK_rt0^htXOd8 z6gZFI=EsYzSwD^Vw*kQYm#7F^Hvjprt_@dFn6+~?pC1WbfF+ZA;_nh4?3tRe0?jTC zKtldvX(#&+0M9J0}Z%EcXucq{Kz%Dmg&I|r4K z@UQn;kgitllprWdWobOTbC$d~gK_&Ub<$nA1#d;^QyMLW&)%Jy_8yhh)2$g2HuG@^ z%&^s0cB7tPk5jO}`lTsI@l$#<7aWi?>gL)q+HHAY!_@(4RQXL~P}2YgV#khidAkc; zEV9_<-o{q>XFDVd&3_mmF!*yFtH3k&TMIf&?poUeVwfWCyKLTDE&!)$d!l8`V>{#s z?EgLg*R|pImliOCRwQvNZ+%{kewT0h7rC|OSHgfrPU7=L*RjNISlon*EtMM`lcI_+DM0Hiaeoy-?& zNwyYg^XEwj0r{x!+(5mYJ?Z-WG{+N}pz8BAV{i5AY|Lfn9yy4wtW}Ol7vl8uYoPq# zDJnOZ851C-Dl}%XWu~6%T>8{K&l!hq_E`0Iqs1n1n_Jqx1W~sEnDiZ|y#s;1LLeE0 zv?KNPPbhuC{or66(9`{&&|*#9te*%erBzRZR8y!6m|JN6Wkikhqr=r5tWtry;bcO% z%RLFotcVCQzA#0xY5ui8_u%AOQH0dbjIocKlwhn*q}E*GZd+foRbgP#pD2NHP|5)+ z6$|9PxF3)fx!lzI=yEFy5oyAx%<4sbhp!FsH}3|N3qgy~hE}(u9A}f)w%$LLJ8i0# zHbNq+B|}E&;#X&9`CAuA;tTe;)dN**$rd2qhCW!~U@$-R<)wyr$m+<=cC2^yso~=IPwNdU5)ySxWVp z>YwR#61`S>;dd_=(@fEx$>(IaB+EeJ#=y`jyFKfCdGC&{p6?m?v{rlGv$ zEtw42$)%-!if_`>0bHV8eho7Dq=dWeL8c+v+S+zYZ4whpFRxK?;*fR*Ez^ttN7Z}4 zQyIShht-1{@>f{t6HSU*1a)T%eC`jxU>BPDqTtcr|&Elyo$I zu9$Q*xW;~z#QX5wyLWy~5@1x=TvMeWXSOys2QI>G2vfAJ8g^9R%#@2FZ|U|(n_{WG z9bBW{cJ~*s2RqWyk%KS@3p;m2yC*om3ptD2b?c9rwYm^jE4XtL@M8ZwuwOb*_H=_07uQhaoVR zZywbU+jx2CgUP9qSk|#WFNUPQrEdEEuDtDV5|+T;_amPX-b@XxQ~hJT@T04JrFy=4 z?Q7cAN2@!>?F9CGUIwTJC~OO{J`BxRj_@z}S{ssT-)xM?^6S)ygHB`U}j>{glnmI&f=aBA~ z?k>_JXXX+%@WBwmU@hQjmrq~S#776ifP7B>C5R66jy}GD zLEn7C-czzIOmufCeSrFcrcdempsJhkP@xqa{osB?p?ODBdfywe;IAXs?2q)S^mAz` z9#`V8vervY(>IN%sj--u2=_~ z`#7GRtGjH{@?&pI zdE7JYJ7B+o>Q3H+pgvg&48c4^C$NV(&1{y1`W5p6f*%WVxqD4nDE17>fgo*ZDFcCV zv!*Zh^LTy60L-|WAf^SzB{JhX1mLTH=d$7Hd|9XM27ihuF$St6*?aMGRvD!wSoL=C z%TgKV^U8wqXYBd|M1P!3VBv1yhX;;BiXMzeaR@B413$+gjsuE;0UhCJg&seRA*cm0 z5bgkBn}LM8cK=*-fUtDC?egJkvDW2UoV56o- zM1XB>r|KRWC{lpCGSlNHKLlf?d895_9Hu2^+(gjEiV4CfK&ZSkfB!Y71Co?+Dj8OW z7X87%R2(>IwANfoELh5ob zHBv7)Q3vkS8!30#ma@18sRj#eKuZZCn|1<1NvL! z7j!?I63e;yA3B1sk^KEM$lT}ZbwJ#Z<%jV%2r9JzSz%*A0ko|Aft3(=%Z|00dOSAm z$ju;jc@fwH63o%nNKC#clv!=oa{W@Dm^~n=jEUIiglvX zZ~G9upZUJR)aT-3EEUx-K3^WYd&ma||C;3H;bOK1fh~|`ea42(t?kZ-Xpl5nO#y=c zh4%ZJDKq>ko8blE%JsSs8c{;s?GN8J}*GKJlpNCf>%Ec7{Pbm5#KQ3~JDSAIV~$0$_Fm^Qw0!UY#v#%TjE2fD z;&VgY@i8CcE+^MuV^QQpQ})PR|CPQ87!RC1(zQ@zJ%<9gP4bQ?_?8+J z#SU^M5|EvcP!wR17D%n!b+!a;){c(+BI(%tAuD!G%Y75ZoKglHQ#)3O1$R? zgk^V6^1eT8R4Z)WQI968*y#CkYFi0X`Fc@?nri$gMi;hmUUk~rbUk;70!&*ek8r-J zJOxo@7FAd%U{lSJI7idNK)Jex0w{KW-u6E?#f$$i^>EbxhNC=81$dnUF`*P3)g&MK z1bR7|URD6|(j_neg{KPpIO?mU2lt7Z6A2BZykQtp&|MQ&1R>WB_~VM-LwP_(1xdG7 zk;OhdVrn_GcmH`qCCJX4FFpK4M#YsVe`=Z^`{yc z06#j-_jDY-z=y9FG}A>dDyKjAOfTy)z`1d!QKi5AR)O*8U7TjW{~ooGU-L?wVo`EG z3fM%a#Mg8Q9*Z`M2@54pAIglSOGbk}G<9i_+aGFwD6^M*vO`S=7@;$aEcZ<5!0$eNdhs)o6AZ>3qS?Ay9 z3{TQL{6BVsYQvTeQfwG8!}vHx+snMK;F|ak{s!JnBvqQFpz~!=O(G}=v_XR^2Eb$O zF9EqNmmLswZg)@^>aikElbsJAhs6w3tKOZakX$EPijq1NYK&BNUV7V9FDWZLXNuF! za-CULk^M}cGq@`UA013_*4<3L-P2V)GWY>Sul0ppwKTvv7tr9Z((~T*{sQ~y(?r6I z({fDU2^j}Xo~y$!RyJ<#^=lR|GmfC}0;5I}BnW`mV(w(&1m7QHF2~wsTpxN|#pPG9 z0O?dW6l?{uGypF|ED)KolOh9MMMXznDH4fL-FEN*WFP>>t>7AY)qbE#EJ+dfjQHno zaK?YxyReh;&|Hou^4s+QmBr(H?w-@(XFpzTZ-Zw(f#j<_4Q4*yN{sZ0|?hd z4fm!4j*_Fi!Jm~!&opSLwN6jvFTjV6e$3x<(iIThFi+l!iyW#P2NcM8-|ZE8a!AL} zB2z(Hsw`&k?t}+AKnC!!P4WW^KuVv@9aKW0z=P5Zs+Jo-AYqLOKCFROmD!7CZWy8= zpd6{ix=P+bv$p|&<2H$~%nAfjXklg+t$rM1Slncv<);yM)0r$CQmZ4`^KVZmGEL+D z51SbRoz0I-;M4V?XU^h4aFA)Eu;*%I^nVnB#&_de>!4%skHlkG9t^+&Gl(uZ2PKhg z>g$^z+V+v9q(#jxWE|F|m+TA2L=;VqN?+f+>vyEs+bYb_Zq?$QR`|VikB3%F}3BJ{T1G9IaAgV)y{GE7eprNG=U73|zR;DZ*6MtP>cobW} zFc_FAP+NWu#=pq}7e6?2{S%a&LqD3k0M6d3Hq`4j7ktnM-PMk~6^$zHi*{1Ko`j7h zMd^yPkjINvR#z;{rZCC3!}~)53&--*Mhx$-!F$doK26k;Bug77OqhGi_yypFvy(amJnV9rUSw{$*1=YaxDdxF>=i0YAP1z8rZYJT``|5JFN^iNbD z6dpj00XVrgEx7ji_SyFZ;9v}iQKR{7zu2@1+y0BhL03bB^OV{qybanR~s#jv!6_GzKZ zSx}9`HMO-ax!$(6)7cJuni{@ofr8pPa==Fq2omr3;HUi<#_*`FmzU)&xuq|_EPl`C zZgObsmp|t>9d9YjlOI(WgHvxn!Khr+K;RwbP;cXo53ueW9jElV7yjKiOL6Bq=fGG5>Yoz<+wO&76u6M+w6kQIgNH2H#Rb3t9OTX+aWL$QE|Nxm zik(3dqzXavdyj^={Kxin%(Kc`!_N*^hpNHDh<`;JwAs+rD@~$+@WjVo1;sI#a>M8J z=>xLBMai}qqDm}0Ip$0OJXTSld<+o31^B;!{ohsR&$(d{hFEnySltc_%<@;Szwz@5 z-2aNWDfq1FHTniS2;@%dcdwCT0%vVc7(*3iBq@IK1M)e^SJIw0Nqx9I=u7a)>ySdO znxi(7jBqP_V(<7km`?{bd~U*v&+Y4|qrB(_9ig{#0R|kGOgZn|`No8&x;(VTDmtA> zp@H71x=l$yg7X&7d1Rg#FQZ!)YcRC4S;PkAh%wyqGcH2R&ge+xAA$N~~erK#`sJOfr=Qu(`r+_4!tDS?*&R z8jOF50_Z1POBfg>f7Ym?!AKwjXk!QCYg4xHmAsc9kw=5jt9CUbF!rSO|#A|ulDAEaUNiN zGk|yG6PX~;K;5xjgoUz!vheDLW$$(Zz8lD%qxik+c9M=rFXib144r6G7tc(3Jl&kX z^s_^S1>n`4({C7`^xPn8<)S6lyO2tvTcJ~j$$V%J1GW8g(Fg8QTdX_+C)N?68A;?? zJE(DFe}^HB?U&o;HF}3sR7)G0^+Zj~%mg*cNmM0knD4OsAIUy*2r&u_R7X>OHNbVQ zbaCAMub^UX4p2%&JoD$d>j1L60@aHW9AdO*g#!4Y^6m9(-Er}$z3ERRI1&IRF%6zQ z`^BdvU%ChKm3MVz=o@K{2XQXs)bGjs4s4pxE+G08z7k&hy_XymDh4}$NM9q_n=*pcYQGYJ)Di{rUA#w*sWd=TS$p)^ z&cO$dvHFm1w=`N0`{8MlYy;qk0>C4GFsUdZ|M~}T5|Ga)2-5(LVHHRc3h|2m?Vz?H zw(l~`6`|pp*S)C67H60q*GOv%N{{|ed_!Z(9GTqg?m;6{M4BR|=bVR||1k?7UR4uf zcA3uHw}tzsiu_>AoQsDG5jqaetqDI=K*;5ekYSz`6A>gz?ADnV!VcAyCGD@Qv_=Yx z`g;4&X^OaZqu9+B3Ka(q!nK!(h_7Yo;PZEf`bx^!5OVHIhwj3P5EnN2MFSRzdNdZa zpAv#rl+xU`O<*p(gXJQ)!7%MV@?nNXV1^xpD17-DuOa{~P*O)PHYp!6lU zif+ zJi`Y?cQ$Iv%0J$0V|kP0^M8%ZWS}#->j7|bC-k&H5@+FW$DFidUeuvHB zeIOA`f>gxtOb#e%w}$(lmVh)qW3~fpsG`cbyk72VhJQoQ`2AD+T3U^H6WhBBQzs+jb@%j#v+Bw$v)i;TW;*D9)=u@_*2o}0 zvZk}tOl9!6+lX?huIGP%%vv@cwr|~3xj)#Lv|uI{@kW7ytJ?u=v6r1 z;h@CKx&8kW5ahtels%sc!TmNsFlrC+ODJjI1hK!m$FFKEK%AzF#@ zDPQ38uH(>#`IN!sG!Qi{J?0c>XUmoQ5}vYP zW$HqQsqa}Kju{HE@${jJbKYG~P>e82(Ox$i4yFA0{S-lXUDESU*KE^JEzWZ{0Wuot zI-o11*kK%(k7AxO^G3XZbX_9nTMKeQ6Y_C#1pNS&#zFvM7-N=JBbG%4V1xei!!P6k z8S;ADBrXH$e-qW2`OWR^U(+Y9UQ;{rq)_~_q)N3!Vtk{s{bMiA-yx|iGxz^zbF5W$ z`=N<vblMcco~Iq(est`MD~w+xJ~1=Uob@*DJ`cmiX?0M0OZQ+0$*6PweRZun)e z>N0dv@F~B~+YDJ}&7VJap*O%`P1>c8*=H)>9a_h(~azfi74q%K$G~(v!><(^yCG&t4u&S!w4;;f=!DvOyp>_Y#bwSjZ{K>NqAe0>H3Jj%;W zVumoB)kOs`z-^{VQFi=;>BVh0omjga>1X`(_NwE{!_U%Iqm%<(bx}8i!pN{#DDT(` zFSfZjbG$IFsZHtoYT`&t{alP+(7wf6ch~7~#Yz6Z@vR_u zEYh!#I!Xm}toKa8lz^PJ7ufK<_y0D5*>3O?5Pk~=(UVi@L6VIn+@rpB`*f^~3R5P_ z$GXrUgP;=o`9?hV(3Hi@p@{hPo78Za&DK)?&dv;<>hODLF(bDt-BMo|7<^EF$O9A; zZ!ui|1zDy2YB&xH=e-5qeXkADo*F>|e*Da)6&47XQ-9YHW(8eu;fA#>% zKMqFGU?X9pe#k8|`6mEhnr>rxkJbh}MGVDVD)g+RZ2F$HJ3F1BXkc!U-z!}T80ksO zWqVx&PZKSiy!6AsN+?Yj00+X(#}km65^uBMts=v5>aJ!Oa$*h{z&hv@S#7sI8-b zfd`I{MQe__HB)UJuW=~C?cV&mm5)LMWZvA=n~L=`{e-2FkSt3iy-Q8ulqN-ll8SkK zQu#oojJ~G!qb)v*JGEgdL=zta1l=ZtXz_%!SR|R zDS>U2cPHgz=bUKX;@jfcAww4-@DYzD3h}KcO)BD{+W`L5FEnr~C&ZCAT)$&HS_#2o z9XJ58>G=!9He-nRC;AmeBwY%kO4MSHv!JjBBIr^-b79h1<@aMt&*_JWQYF~Mw~t4q z+W4<_2;cXvkdb2B`60|lB*QfxzEd{#GKf%JRWHg0;qNF3XqpR_whRc6cHX`w18QNu zHGkFQhM|f#`%Ua?LUibb8>#4Qm=ko2s+}d?+k#xsax&Zcg%;nNp0>SEWt_nF7+TceRT==J^}Cu zjyKrx#hOI)@tP7jgu)-rDbD-VANHsfk8(q4tp{u|gQ6;a(#YMJ3#<2zzEgQnu@}ZQ z@-y+1_U>N3JlDnR2Q!85(w$3bFX&83<%+`|`}Nsmp0}x=?iTi6>;Z*$K6nTJnjQ{v zFuJd9GIQO9vo}>ChQft?t$lSkxk3rfu8`apfnV?lifBMv4Wz(kuS&PnSz2x=)Qw(H z_%wH~$^@xZ9h?jJuMRqAqKADzpwWSTv$0tHy}!;MrynZGeF_mk!M=g9x_r?`Cwv%x zj(B%&?Y>$^$cb?9;l^ZGs05l4AyYyT&T9>I=fn2dVU2yO3XG?$T;5|Mk+ z@&*6_UZ}l!Fl?Y$gd2wC&j(B0M1wJmJ`dp6VP7S2m+U(|z{ARvh*N^V4m#6dZ*)YD zT+>t08CuvtnsHDpRm%Wa5h-#6Xt)8wIFPc|5og%IYFpi2Wad-!VnVAUj^Rc3{IgeX zd#`3>R5m*Za+h72FAJ&gUA=Ig6<_kfi9yY=NFfuRI-7UW`SCqvA-*kz9L$ANr z*xjmuofL5fmb_CU@mNGGYItsv;y3DmGCuUcX9=`yQxII1k48R7P{sibU>d-VR_q4& zprBPUv1l|A%E*$?LJs8i^q$V~L0_`~mQPPHCQ3DbM+2NF z;bt6qK^o|@3B#GF^Z|;Pu;mw0$nmJV*TDU~#8c1Y05RdYG<#+#G%nJAl}UOF;jf*C zHE=Nv&fDGkb-7n+CrB>28YSPYdg-=@_OFcmnkVtjlK-Oo|Jg%_!1!wZ{_+tRi)$*g zy4$n&M-m3JsTS^kvp|pcaT@B$G#^k7u3-fh8>^#YT7dDAFo;G-W%#$=XHafw706--MjPR=5}Z)iZ;11to> z9H%2#LR1BCj}3E9=p0HYn;Q_g?zYCe?fwk82k!u=kXWOQK}5SwU8^=Eu?8Gtqttwq zzn>e-UNg21)~s8t%W7rx^Tx=)v8AF&n|TVf&XI+V%k=qAn#m5JkX$-CJ5NIF`M5^z zktlm1rRNhmJm+;^kDc8%ifkC|SBtFS*yi2K(51p={N3%VX4)mF7MQ8CLW3PhD~Y`o zWk%_g{k~l+k*WM%aTU1r_+>ql_JJ(}*Y&maU4?`bJZFP$IIcto;BUevC`P;jKk_XZ z$_DbC?b@UG4!cSy+W^v1r$ToOuQ9Xri&OQPUduNUS(3oX4cTvz`)4<|NB%rSnGfT9 zBfcuIRaQEsSeQFw^DvOxaSJht)zUVLN&=+(pT7vM?(oV2&U=|JvngCyq3>NYOwr%P z2Pi?BTmEsdgH1?BluirAD)N~*caa=&^Xhb@*${Fm%r}RY# znTvr0MFfhNPcH)qD~B733+Dz~vaqK_%sD`dFbv4jTA#ixK-K^)z=AU&D4-e_!fpO= zP5#A1-DxUw%;u}i5B+8+kyy~)#WS{*?fbGzJkQfjKFO(7CU*-=M{lNYV)#Etv{ z58pn5K|;;<2Gw87Gy%wpx*jLEDbx0yE-|_5Q7c*kf`Q9tW;F5YyxMe>A;A9v5)(eq zo8YgU`{soJwU2k8%TEroQ#{IPde%XBw5?_9Ywot7PAB?wo!7 z1!q!ouw~xA(VeO9cdi}9baoL17{k^oM*-A4*9Dk$GQG<*(>oxEDCdeXz%q`tA-}2S zpeZQ<&^DpXzV@kCMdJe;c#@03;h(6FdkoJQ3SjBjKzJgc*K9MD$E6XB557RCWd~G>p zpTEi~W6gU{x_hH)%)w-EOSUd(<$=)WFX2x*w#&4Sb>T}3dVFuK^Y7o9Q*=5&5l2qU zu3qWNG31Xr$3ib{dLK^p-Q1d8e6E5bqH&fK36{Hen9Io>ri1FfqQGekCEjVRv&4tU zH;xf%JSru7c{05F_6>a$9##b@f1r8(CI`LpIppoHmwE1x$7NVFoLCuBFU3I~Q(yp6 zW7PNUZYY_A=!|=~E*Bzi7!ssGVr;q6`8Zzy!?=xAWB1`O=D3i1r0aENWfc&6MDppg z_Y+&M;$AlUspZwZDhv{Ey=_irxOuSi{zVW301^Iz3+fME6?7q6mz7Wc!g%f<4h#T- z{A|C7EmR+E(MS!n7>E~8cObM!5Z(uaB79}=OJIekp+<>g=mY(5qGqDp&klKIQ*X@O zDzvy6Syrp8dFPv_LWzekMf#7$3s$UMXe$~U5XTYddbQC;6Be-&?@Hv+kyq{)=vZCC z(=ZqVOf*4TZJ|f5TAF}jJcD|UHpT)D>a?cR3%{g+F&HP)*!ftG&8;Ed3wrjb^I9;j z`f_*Px&CD%qJ;X&@?~cr2eCl8$OmRl@N|imkJmdHdjE){TB*hf-dOKdL*}Z`N74 z^4{O3WT2wH$E)L+d-O!;$Dq2D2_ACa`MNKRG~aP);zm+U^DoS{QrHp|H9-p*;u@A0 zv{l8A0irkyDn{2cAgL*=1^B;Q$>-PJG0o5%O+q`Lw&MOL&kF)wLRH1x_`tqv65hi`TZjEWf_C`vzgg8`^NYpCWC*Bw=>U; z1Cu9UPbCUi?z{gz%*# zx_aCqkRy+`au{|lkXgxd16{az*ILsWPw%Dg7UywMYdh+oJWxvOXP!81kBv?P;`mu| zJdmMB;^MD9#Ue;A|J#)leXi>j7zmzu_=I^-nuXb9033@PU2|_LA2HGw_a=7(YQ(#r>J zA(UwuwYB>ePfuW&$OJE^`i&mKH7ltGzu_td25f#LT8QW^qCxz{16pRCj!7!(q|`OD zNt@mh0~}D`cNsh_^n!(Fs&Eo<icZd?MF-Rsj;!7*8u~QfjWlX`7ui0uRQ(n zSF)Mk;l+3D!!{5|uLB3=Qi!(qI0vfd=z!-?h^}N>BJO}xQ2YCDPSI7DVZYP1Ki`WP z4(xR}C}RZviNtak_h7_To2yWPn`)%C?1Q5@+uiUqo~<`bzOq@lJz-9dJ<(`$ykR6u zrD}5Reu9I$2Os%2uay%<7U_}C?6qp74oybu!|u^GHqBg|_lw3CnV(J?i)BSy*R`8` zTaFQ57x9`FI13%Z*VcQY4n-IPu9y~ zGZ*Kuk2|X_2YG8&9buwL9{gXz%?hf~%c{x305q16)i4FnqL&0(|@hQ}7$|_~PA{XhZ-3hZ>q;h3Cb^<~(A0_LXDUbDf&=(H2*SzC7Zd zU0ex$7&K}BS+SPy{ow_Ew;GX4V!+Y%{pfh@A@6P_5o(zESbHQ3AU2+-J2i^c?KX50 zf4x7fIa&H2mCgj8UjEBXJKX)us1}NU1KS-JC;-*_ zOChy1Nd#9gRe6Th(&!&V*b^>y0?EUhrIMR1z<$tQG$V?(Ws?Z(NOeY zjnBS0*!m_i2ssn5E{4BW7@2|FQL`{`T~E39GgWWGb(_Eid25R|$;-{wa@d4{3r2md ztG{}PefdUJth|aaNyNxAWP#On^{)!MGf5q-#ws61H}UkkB5;75;k36GmxIP#U!iyQ zK}6FLBg%`kKnh~?DjCekMnj%66#7KYfvidy#yL)jE5Zh+Zgj=S7&|^TC7VV8+KgZcVV@G=g*7F>okx)q8a~7VUH4s! zsbByrDrA*sbgwTRJcaxFyu)l%KUQ$<3lTZ{c9bO_GjhA9+(wDrrhA+7A+yH>%Do0n z`N+?lrcOtkN1HAlu@$gqf%_Hv`vYK0Wf-bT<3i3rg7{pkx{p6&3Ko5S_@DqiqH`~J zVyylBOKx<_slq7BJTs^#$pEVhObuSvGC4YQ4EF{Nm{-s(imgy|y}(YVZH|qiDBbw% z5BSd*$SXjtcR%JH>Gt9^-ekZ1vk4c^F=zXIxv{ajs$-k~+Wxil(mydKnuo#H?(C|; zIl8dPZ~JEt^bIBcwzlc2c@z4-Ff$*hzJoQs7O#T3!_M+^x+dbj81LKv9&U!GK8}l3_)=vz&(P!CCAc^M1UA&^bjHRFisT&EvJw_Xu3^UvBZ)%Ok_ThZV5U zdL7D&0MV2qAd0AZ5?oTCVT}8))fN46Ihkyg`DnxkkA2?`-NXVvh+jecjr~eZwJ0iW zZW9og_a+)e!~m0UpKU)OU<2@;LmzbYIAe7473$2zNTVGp^2a~D!9RLiF+uU3?!928 zV?aBnfVjC5Y>A+K_97UO^>$1<;v7-`U4|{XU4=7;OL1e4AI%lzNk{WNjO=zmuOBBE z(jOq3JxU*eI(SKh>g&H}d^7>#L;(vTIDU^Bx_F8?!GBz>IkCo;{kx-i{x&RQcwz*3 z#PYsPMcs_W{E1ho9*t+N@c4c89GI-B%Biv*exh;ruRs2U1_p5@VJOfp3r^X|@z4*D9s8P3=@2DsbBU*2yg55Ai+wLBRyZ;T60iUuyy6dkG_55jg&a9eA@gkK)Sb!H&u?(Y_6~_h$L`BU3 z7zLu_>pC0r)#uh^=4J{$xhJSeFmlHIa`o-#s1IKr|B$=&LGEg>gtAo8rOOIv1d1N@ z^9Fe^f3QOdqE^#T6!pf7{I#0YQXSV&UZX0hjNl2riR`I*lJC|U8q~L9q;8cQ zn02JIbFzJ^ zpf+SIk>+CG+_a|G)gIgKJvZ7Mc&fE9@M>yq8^7!(RV172_T%=C5l4aItSBuQ&saTu z`q*}}8m0g%h@)5=t$`VN41%nCdH0@{r(PNdhf*KC?`FIdJiSsoYD}nva8HJ#ZRB9$ zS45C8jmEKw$=71JqqjKAML>2=o6UaCm;ee0REVZQ`!n$VpL=Tk{MSc%RTh>WX|f4P zR?_=fJT9*Gn+|9FTfD8je;5{F!yNA-YHlYt2s5gXx=03m4p$E=X)*qn25Gx9VCd3P zzR{M^a?zsdMM;3vUK%%F?LRBC=_bFCgpwx8l9N^K(c*2thi|`$4J)efd)(vfws?#v z-j}+z&5_kd;`|~nkv+n5E>Q4*v{;aN_~E#Pui|shKhJN$pbZev*jsLX#Z5#g@M^!| z9SqUI-l_S3lT^>u?dr{KV4z!<2;){~+h&)&-W6|bRTBTm5>40OxuWB-XnPEN)}GC} zexr2$Dqfx9J{f5HQLd4lQa)?QW@{~v~%_fN+j6Wfa!e4jIuYI{<6xebB~%YtFzA4 zto8mFQz$v#6ZmBhOMb%E-4cSJ+~i_H4CG$S3gEEz%P1g2PEJ^3pwK0P0Q;Gh>+*n} z9^4nH3(B(xULlx)y8IBT2LkurhMoSFvuUx}MT!nU&W&a=sczc-2JZ}i^|b3V zU0Y+exQWj+xJP0{x(O~FH6kHW|j zla8;AD@VO60ex{98lYuv!P!475e*)@%yghvV4E)-$E$mB)CjVUH8lj>kGU6=mmmJa zrJ2R`e004l1#g&YYT4P*n4%+1OhNFe5PK_t?|~^@FWBog(@M4&pbpKjLuazM3;vY; z2af3A;UgCXACP1EMyT@h(PM7>kS)rwEjs8G_n;`<^`@;4~6KG#3F1>HXLis=tnSH&n}O0 z-~@?dB6&1$mM12tqqC`3arrCS?OQC>2?~}J=ilvy{ zDSov7$2Te{K#WJ0zM7T%eZ>dg9;>LF=KMv36&W+TnjObMnpwL|A4d>+rN-~24cfp+ z1nl^GVb1!co!67OSIwo)x3zwQ{dVmje%&B@rOM-?YD`A~hkHO}DSmxgtfWOL>laC% z(r2qTp%&@MDs+uO1A5@`@=>o2Y*+A+BJTM5f@3rQjYu2|avC@B`fLh7`bTW0^s~!c z;;r1YREDuc%O&tCaIpPD4;$OKM0N-n5GjW?<(@6;y`X@GqkP4_`AR!Sa;z_m6f*>j z?n`WG6(7O=eY>4|?I@yS(;PR|xKH=B$hvKnrIdsrh;m^p;K9=3H3F~oZ{dc^v>D~J z-tLi+ooUy#2r72x;(rdJC#?8x-kFhSk#^!T#Zuv^bU%WXAOd-s-Hq<&tVOUKgDNp% z1-W_uz4d6kn^w6i)(tn`bdLYsezMZB6Mp$HWP0V#lI$oNBsP0<0cA%T2g`~Z)Cd`L zdpN$zG_*@0!Qy>Z@UU6}x=pSZbMh<{BsQZ&Lj`uIoMVl81N0Q&_D-}Jfxq(E$*PZ$ zta`7U${J>3C+BkSP@NA5u;@{Dy+HeK3-1?sfoOQ{$zrl)HD~ljH1*N$pk!|dhzEX%?FQhMF~ zAE*n$bH^$!vH+L)=l6DQQv3X221`xos28PhdW7QxuKzwf_^n2f&3WprO1DndQl(I; zQ1xOiXhGbi8QV4#NR+{vEN-$(wPdq6bmg>Mzs-1T6GUOx)p4OSDHSbEzTl6-&a*Zzy(Dy*$+G{58%gNRm3k3j{w67t?K5 z2Wdg9VBs_W-M`iHw{?JGEz8?}ZL~KxxEbP60%u#j6Q4MyAwmhmVh0Ne6K04OLX-f~ z`RXN{9ekOIm|q&eHcnWoKZ6BN(9yvwW=$wukcT`T0S0rgL>`zK`EZ?ce^Hvz8So-n z`18#x>r7@_EoM{3x3r&V$){=&p3sGEavyZj(efx3&;g(KDS(3kWPi&C3es{Tp;@xXsKj=!>v*N^fJ7m&q_2zG=NYH9MDeB&d=|x&by4XwUI$< zx3qL%s3>B~7t;en2Yhxm2U*B7Dm6@AA%($hT$|HLb}o0;2Z#0MuW#gs>fOEFvNM>%M%V297@zi%nX1~{8+#mskf7pE(4OVA1$hf4p-QGEd|ISJ!2b@Qv?@);- z10o#sRO*C6t|^YWpJLgXc_NK0Y}SV5OJxkZlg5{0F8+P9O1 zpv`i}R#sS%h24ty22Dxz(|d6pttVS#+XqX<4%V+XuJ}g(4e2HQ?{&Rru8PhoPPX>{ z(3gHiIu$US5i--PuP?n`mbyH6Pwi9Txcszg{(e##mLao`(ITD%Ld*J8yx&+fQ$O;+1tO4+!F#6^vjGw{Ix_Yq?GyA-Y<5?5@v{ zxW@0R<}q(DgK;XU?dh%$G`nH(gob$71T;Y_+h^+#LVfCAq(e7Fn=x_Of_Kc-Fd;fa zn6;%>-^Fia)M1ay?stLcEan(PWJp&;oc)MblOHTdgqF>7d%V4&wU6pxAY3Iy}&G2%ImOXuGB5rz7-cT@7i2D-b4{smbCAApIq{lm>3SD zVyCu7O%Bxe74Y?C^G^yej8xF!V}7I{*>%A>3T^O-+C`eGn{j*f&H_qjc?5W28CFV&o9WJ zP3R)8P$#6up#vC()#i-s6Ev4)}HVOcQ@teOCtRxr{Ad0n=l zj?`(Wl6xif$*5T@xqD~%#O{_#WB6udV=?&)`v-`G#40p0qOL;u#%)@zIew!SD!l#F zx;3(;ckvjAvOk6)OHxBohB`5NavpQ|7tfSx`lc!&byY5^m&`!2MyXnniekj_B~ej) zfds6W30FXo=Rz?Kb^GLYwGK!_Vm_$C8rYpffPvfJ5`VPJp<~5n40V42HYK2SrFAt^ zoK44680#-mJdZGKlIL|#D82AA_;^hKeftHY+owLXuEw-b;{kqbzZXaa`7vu8?6kD+ z6toDwGqvvK2RtVGlc#dv6$Vbac1D#?TBonvP_IoU2ZD?vtifSMNkKCo60~4s{7swE zMFJfno+;li5*B{S&|Ga@Yj<%?hN0!Az(qTM8O6n;G)jWJ}w%C+SpoPummhYw}|1Z z#9zwDua^2Z|1AXp?*r+hnU+VoUH4|2S~)bqXSasxVf0T*obhAMtK>^LoM1FoD=8rdiTzq=Vs<_>QY-%KkI;ej zd}tr=*~O^GyRY@#4t;t5u}GeYLb-)bXm##S?l+I=LjIbz7Z@0z6Rz;b1yu{9lxUHC zGQ}@cw0d&Ir(k&g?^;^YMzfN(>AM-G7V>p9`9!xUhL0l3dc>@7tC-8nv@%5yqy*OH z^GTDRY&Pe{Ya(TruO31zPx=4% zx1vakr%fmnyWSRGgIz~4JvcL0Vy`G+-_28L1lHBzPoI9b2&<$W5Flb*_&(fsTEV%8TBKKK6yGN0v<$i%)+) zu!okifh2mdZW|8oY$R9AqXkyK$9z%4b%V%}7{Z}M`sV+)v5;14Dgo&+is?E(!*rBK0Bl|3}ny$5Z|N|M$Ju-m8$k%MN98tw==K*_kCfdtDMjRw*L0WMw9s zTV&7d?46No@9{hI>HB*<9;rX>&3T>kIqJ{+V-`aXvQX;JbDSx<8Irx$vy{4rlE+~y+#MIQl*k)H;2 zBCu%aME3ptTbg`g-_$;&SQ>w=CM`jgcRldt#(Pa@%)VaD;Zctf3_6H%c;0&j^id#5 ztD7p>Rv0`n=2uW_b-TP(dj*lEK!5>e9VYmmspG^`zuFvF{^yQ{_FZ>hknXLsdP;ZV zq#Sv|I=LIJ-9cCS#B(E1c+MxbNu#k_@d!MikQ50q2tHAFpEZ=LI4KZPpQkRHVJWk} zpmsKVGJ~66g3kYcKu-FbGIEwOd!(ypzu2i-IG%Mm`}VgD85~@*Y!g8~_ODWu+86rd zR|sc*)k*-ZK~%oBJcI-dzi^mJkc0Q(G-Mn+rbH7r{V}Sc`CA#c=v_Or^J|tqF}k02 zLG`9$R*w8%Wnw+>QQ%+OF`&(1~7L-s+a>~ik(saJkPq6$VaS-K! zsBX`{*W=XG(}6?r`XDX@CPy~ZcMWA9)(+U6 zSL_fEs6S$crg+de3Qs%OJQ7Gw=N5lurhWzSZ+jrAue^b$jD?i75$>yQ5>qVgx)Ncd zSTr1Qu*Hvv-2MAcz2k`h@{Eu>C}g?xBh(1Bo7EbCN5<^P5IFT1C)fMKoMF83*D-qI zlEJW{Mc=yjabXd+p2WKi)abNS*EbDb^HP>5bbpe>9a8OtNv@0gAJ>wm17nzz)VkHRmi@i%3`y6)R&U` z`HPEOR_;Ayp1Dc3=GEUvpRG|uo)G#^I1>7<=68hvNqO6=T5z;-X0zv}^Q>ddaU6fl ztDG2f)8gW;Q<+I4TOoXi7sV*~)sOop=v9KCwvAR1P8g07jv)O9-`eGp%Fq@Rx>^5S9tzX0z4#SH@T)31=@&IY7gsKI?7*Qd4d& zc8_6Kp+hS#Xll+{NKSe=^XNtEWhqgmAKMU_6pI2!>zylCuYPX(>hq?)7xxw^mOx%k zp_Bnr$w4%B=F(()rdm6_fTvfaEmfK(UVF8@eqHWmD1pv8I@`cm!+wZML4VTihN!TL;gvJT`r5JT!K8)F9Rn zu|oy*W}jc13$op!M_%`LbD*Ncd`sXvgsd}(sD{32UA63f(O@7AX$twM5J2?KX9$t2 z@f(i@E^TP%WqGSz!@*z9WkAyPT8Sym~5TSbG%zi#-uk}j5f;Ow|?sMQg@ zbU!WtJha%T<0P#+;1GkyN(vAk!w{f98q5sPWT)(qcz=1*)sc__N2yZk*AX^96t-Q| z?0ZLu;S*Po|edBlNG zoNGU-j!JU$c*l*T#nxTGm?h&oB@0-nWH#++Ufo}wa}WW69H%opNV5waNc1CAw`_`~ zS4%4!R3#BMZRi~2g6QtZ?;t|=b(zx()7 z++p3@UB@9yvS0cAdVV_0Fn_QcL`Js)Z34cv1PEL~XN-Uz@@ug5b>+QI|6oXA_#v>| z&Ph<<%K~BHU7{!tnQLTyTStZ+{h?ju%PfTZa#gx^)_(ZexB+7+P>KAlE+Z=JqI#eD zn3vf}PQnyd<{#Wvw}QIP9fw~T;hehep@`p5-I zYRX~LW9*;~{^%a6EhPf!tfp}OJfC# z;ktYRsh-c$90;f1-?+Hl-qo^AJz=!`V*a_nB)kBY__apHMa5#4RBh4fC;Bxjh*Ug~ z<*Y=?UA``7xP)d2zp}zS@W-4KIXivHe(w@oM0>X2+Q!W>ssTz;6ECyaF(Z=<0+<+f zZTowDi#I84R}Q)313Tbx%PsMuw=c6Rxy;8y?1|24JCoHEEp2U*Fvjz@W6Yf5#3a6o zZLI(F!^@G7+7mhL`jI8Ynzwf@%y&jE_z|ukdeoBZ#~Rn;9=545#PAB&gSaVQ5jvd^d1N;UYgs4B&xaGmhF?o>^^!4|dfRI}{ zK96<-lDVcx*!$61?9frOm8?9206@RJ6P{wSy-bAu#5-x5NqxO8k15Z|#&eg?*q4SG zelAI8ZtWm6g~~=iUmLjc+mP55i*i9Ntt9F>w*h0|&|XJjLs>W%eAluomNPvlXFFEO zjeBJHb((2W4?K>NGq-3iR3cCVJ~ik+uc#s18%~z!y&Zp6Ii(xT|G0&gXAyW?xTd<1 zhh$_|BUM?{-Vb{7U~X@VuO=VW+jf?URKDwt#yYMRkT|yo zDdU`OY5K}1&3ECr^*6U7eQJMxF6oA2wfQPF$wL;zJ8#Y)tk~@*bl1?1XC(bv0=QxP zBTE3T;R5oAp&F}183+0+7-P_3K3&;Inegt&dLQ^KZ zYphPI!%(D#6WsKNL|a=P0V z3&-p5ZB0$+&&YIWin^SxFl6ABG9Mx1h!ETwdxSFo3Ygx1a~|N~ZK(4jyC>QgwasxthnO?Fs4NK!HG<~i0=85|dx#htA$LA)Fg zYTP|3`Z>i5tT;BWAN`#nYl-RrCns?{o}7rhpKi(#2byw8JOg$v=(9~bZ-@fc?z8&3 z=n^ZBaN3Q)z_NLfV~ew7aS_S>Ci)9G-t$7cN@;vA!=q2KfnIA2TZH8X|K$t(TytPI z^FBEav3OOzs*?t-JKMi|Vx;K&(^?^LI0zoJON6&>42u>hk@9&^I3Yq35a?F9I>xU+ z=jk^3K@;`S&vamBgIGgJ~qTuZHXK`X_{0ewT(Sb2&}`) zr(Hzs5*SeQ4cY@sYQJ*YiBosl;UZD|-R)RN%LxN*m}dVL6!WGMP50=DO>b4fBXxy<%fuIlG^2z-L|^He?&t5#?AT9`~q%( zt9}w8R6&5s2hj#7yW`?4SD%?K66PJHkHnq^hS?f+HJGH(vqoLw`uXkRemY-SKOK!Q zbFYMUEj*x}!_22a)C`0F*(AV=8W*@kbL`FZZWfJ4pjqP>>Mvy)EgB3p69i;bRlQQzmJk!*JL#3(cUkKnL%QOJYk~moJY)>?kj7Y914O@37Y$8gV+>>`Q28G-pK6J^IAb z^a6NELGlVL;S(sknIonKhKH9cfJ4#YI2Tui$rLKq?$9{*4@?R2+xget5}T~C>euPD zzSw8`dnFg!Ng$Ks%}(pFNtjWQSjkkG^^V;C>aqZYn;m?*@(d?4V1ZUDM*85Ad_?bc z6(~&O61sw(goCVWF_#RAvCGqI9sVYv)MoH_nuTAbBAuGPhzj~?XGJY7v_EpBoOd!b zVFN@K55pWoi`k z->-VI7H@4zMZQL^9fNX~W-s)a_qPsHiYe7E&X#BfE<9cu1;zjI8UJ$e*WB23|MAo- zcw4(%3k&G+=gwIu+-q2Gm`dyEN3?^DOL2SCma6>^xV0eDNOI_J>DdKF=Mnoc&ZPbK-2v?$2% z=j(PHQc;q4OemSgep2U!tZsGEK!P&ZNAr>>LU{X)$0ovmFC~bh&;P;|G_HT5U8`w{ zZJN!lX*W-r&I0Yk!dXR$pctQ>+~sj@$+R1zUOu}u+ZJ+tR%Gvd{pw$MZ3tLMZ|cz# zf!YG0uUqb*P<8b1nHLoO94=+)_jy>H(L_%DrzS3nhST$BJY_FBopJvZbBE9Em9X}A zHItsLHBdvSGsiGCSik!U@51ux`+KwDMLhxQSqzNGK>f1P=#da?vD1 zhPFNGiF%Bmm+CtgT6gDrqQ5voZ1!=7nNQ9mPxSuH!c#$wzi|-x^g{NXbi2@py|#cWH-(-C%I|ADy4-E2j6xu>Yx2I0O?PEnF@x@N zYdmXZW7jlFOv%lC*J@YAEZU+LRr9k!eRq4i3yW|k50qpF{>eYL_@OE8-G&}VP-*}{ z25vA&6Z}EP4qZfMpFCsQn|yx2;;YfvO!G6YZ)%h>!fo%P8`phYPo@0}yH{rNCzQ5S zUmMy@ITeJCg)I?1yW#skhEb;!#4(K;!^tNy>ArY(r0g-pcSOotxph#&I8$yUbWpY* zH=Gt}YG?BtvQ&{UJ5giz$1brvS+qTrU#dd-%si0P=CPl> zS;EV+_=fmd`lBI?9NCc6kc-aePVD;kF`{oo1XrVssVau*YM+Bdk!Zo|1AN zj=W^R46Ex+w|9}TI{4QeP#+w)r&*Vd4z^u1K2{w8iK$9e;(jcJA%egl`1^Xkj8w(- zqNp_oGfp9aaJA)A_wo;n(4j%lsqQ6Yd}VTh=s8+GA)$`jB$6}c5qhw}N>pcnKrzuD zbmpSqEgjwNPlT?ayg_q?PW({3+oTdFq^V@0H|R&5m^k9s#Uj64SXj?Qtf+W@&)AYv z8-^UjhRaw5(~V5X3Ji_Y%_kO6i+H{Cw7XOK?Wup&;X%xOrs?Lsf&JriA>dt3^gBB_ zVq|+X$2CRCRl&o*h3B+P;?(4)PabP^{mqC|?o+@Bpfn@O-)oFA^~?)=vQO^lX?VUK z$73Q$xo4wgBZ5z>TKS9KpY?4~BXz*%U)fmL=%YRDa9qAO8g7$4FD!%EtYtz)67geWq@Kr1O7)2gm;p zJkWw)LHJY6>eAW0Gj7lmfp@ZZhB)2ZKG`_hUYcOEe$rsN_dGZB^<=E)m(s+_PfYG( zruR1URmesCX)uYLE+LVt)brpWib&!l3D~pXRabCTXy{8sg93^u#CA8e*anRL%ohR4 zrw2ZNteE{b_03!}Y1h4uW0UMy&xttbz)VNmH@bM8m;_JbK-~_S-gTbJB6NHsm1}xZ76dNpzZ->vHC1^ zkL!h$r0`mptg5JeN8Ptw@7uR@nnn8;@rBMc#rce|qT#cBSIFrJKh!xCa4^0qhTa;I z^fa&WfuT2!2_Q0pONzx*L~@_F!RG;)Js6aM-Up1pRy_ewl?bRm+WTS1L4~XhnEZrN zBcqjPeI>WDYv)bCoL8-|s|f`Y8CZUizHR(_`o(q|i41&bv>~}h;in0kat`}*-!p#y zBiACE#RXkI;YA5LsHI`~9V1;e>(2g->^|*0nu_Nk%aW8;Gy4_T(83?acY$ro=j9A% zL)F$uqH2q8ZZ(O1xQK}7Wg7EE9YoMJktpQT^OG3TCxpnR`)^H5)YBK8my1Gkemc6B zq5MvDvo?n-C>2x-=&eG8U|+O|ew| z#E2p0GDnk(-T`{t{mh3b>SKS%=~&bU8w%q+w~H>Q=ad3UO`SwUmP?|X{1UMtOH#;_ z6uM#O+m1j-7H6p9w5kuW2u1Bmi0O8OC3YDCR zX38K`6|~AANw&(?KAj!`AQwTJr)pVQ#MtpM_&tuo#*Y$9tcxI&YB=WT=){XIo0ozD zhzdRKWU6#d#iKup85=s6XVgYSH-}9`Im@KjcIYq4(!gLnbjFY@F4SCrjb?HPkd?eV zRgIAplT0Cvs#k^3??4aQe{|wOz+7`2wTRzB3e(K{gAXyn+vOm*c6b>qdv34WAaJHr z_C1Ooiy;3uY<-_>yi~3Y(!Dw^x9M}ACW-oQxSR55F`;8wQ{8CmAj-1Z$~e@e(rRa%eekz z!I&Ls#d$1?P3g}JYY7VX>}u#|ocNIX4&-y0>&F z_Y|@{*sn~+@mr1!FM5+(56sUd-RqBAbY?`dDf6UYLq(vg(EH9*#5s10(Glyn7lipH z|M<_|uw-XDF)d8qaE6*vo5!L2S{V8%9FLi^#GBwT_7Hg|!S62kWudE6Q{JRWNXv{# zkTXCn7Hb(bS(6A#TjK zi8#l}_lmKy;B?Wzgb3vev_L?n(S^Ik&?{4Tdq{7%`E)b%{NFnbM178?g zVd_XDB>CDOB031){)sckupcXm4lOrc zjL%BjE+!c-vz;{@)+y8#Xitmzz+k3!7uHZ#!-MO)^l6KcO0;gT4#Fm*X+U+l+0|t| zqkZ$D!e;ldel+PuHaxt;4F|>Sqn%G0=;A zxQ5|nU}lx={|<+K=l-d$$S2s7abCZv-OVZ3VG){$FddJ-nszle8ruk8d*b!;MSf=U zI#~=DM$1iTJ^0jm0n1~;SmCZa!oUDRy6Dw`Tu&I0{8!9;cEF9yI{!A1F-^vqI2#Z5 z7JfrH@VnQc%;tNfUuOBAA0ziRqxO{>-s&CZ@5SQ#4jZm(Ber^F{ zth-zE9%rhP^Y2EW*3U*i#w-2ldCSYhY*M!~2CHg^e&0O2kpoaW_8IY@{>t5B%g5ds zL$vt*Q49QROf>=-?{@L_>K}S!WGB}pzd9!0-O+QHNV+|;4@%;AnjTwK?_y+6{LM|e zbWxv!&_?xoL=IA7C{cqhV=obJOzjPN?AOfr5->;)GMji}Eky-+nQFtKFs?!RU^O!` zBKm~2e1q==xrE>qKx#~07$dJK3^SE3 z=jSk%MzlA}Uq_D*$jyCHQ^dIdB&U6Mxilj9@9a_DvryysTaShwV~Jgkar^ts5wIC| zxKVf460C(03mTLArhs?TRB!*j7`xI99)mn+*?`+(S^thLfhNbVo?)MYv#ul;E52GK zowE&x6&C6uEUHW9s7-a!4|i75fl}9*s5$v`osfkXkIa+*rhT@DRXyaGq5QJW-G$7h56n?pK&+E z2-)I%T*E^~9xKPI3q2(*hCz>2?euOVpj3+^5NxUm%%hR@`l_#NO-Q1Hk4aR9(ttJc zB5Z720Sis%0Y_Sc-cP|jV+cz0G6rS?IO@=eJ%M5|?^P8k?C+6o4Q~+-XS!~Ag&eXN zT-UjkTml)9s_haynztm$Y1Rc!#A}zWjfhI?O82cGbk$fr~18t z^)UEN$F(u4iolV@t^m2YFGTU|d(Q(hTB}~==6PYTN-97I)jT%s6^{ME?}R-pbya;PLcSi z#WVLG_>3sGu>6Zl1KiQ)J5i2#Pw!MW4>=%z)t?X{$GDK&R>YtgQ>rl(7dmwfA^KJx zZsd9^#=Mk+$Vz$6n~s0)_GDdixq{xA>x~C;uxXypc85=1x&&M2o7+#o!sA%dav|dD zFw5kIv8O-r$yyJo<+Y#c0Y@S21<3;nC->p^tvc$D%mA4F$u7lmV#=+0ZJ$=0CJ({E z&-b5SreiM6&8+~54#{g!b_5nQwV-+)7tfId*Az%Nj%l~RbN5FpQT?R@h{)@+V#l+- zWX{5~FZwgPs8}ytsBGjeOFa)r;feD z5Wnx0IF*kXCQW$_#*4b4MPIte@lYK?3x^c0SZRMdRO8gt=AcfbvgELoyW}-M?4+lw z3m+3j)>+Bl0-8$3S_+4;Ui3u)Ul7Aa=;mU(nB!crL(Y?M%H4Z6ST6Dc5eUw+lLu|V z4W?l3shRPy$LJ;={;$Ko&MaWwZ2BE!T6a`wA;rR8TDYLDAhl#)x&@$iUa!MQr$~M3 ziRN+a!?Q_ES~tCO#qaMvcreTzokY)b`l2>ogSV`7^ z8Z;R!b5C*q-h-u;loTA*v0ySvN}ybB;V>*_lDW}QL%=UB@YMm&xQvrr)W4opHJl-r zGuS$YMSb5hwOI~I&eT#+xl&23XaT%LJ8*dqxzA_4Hsrk>oac7o1>Zj>q@W1`mW8tGT|IAPOr z$qK&nV*A%zYrE-ayWyW_A*=+b1Q1UlnpDS? zDmBHRzr2E<*?$mtsk4Ltw)76uh?mdxxyFlA{YS|%XGBKE+7(a88Y6pbu-RSQgy`=I( zhj{$G!Lzh@n_LvmSYU7v+&ZJ!J_sLzlhWYm1H>Dsl^C)uDCdzAgX-xZl&AEZAw{Ty z^#6he^?y~)d9}iMTMu86jyToi+`vTNukpT~!Ntj*#@?ac{-zNb>oJlsj0WdxB?Axk zy3JuyA&Vxf;T113&Ya0u?+orHCh+YkTdCe?Lf{6336|@de_pL9lI49 z^2L?Hf=GVovXVkrfi1BE>$fiLe4B4tCoYM@zxxFCWNdK~KcHsJO437n>=U=}rmoNk z58_JV%Ne|F+sAluYY;m9biQ6D0`|4%On-g1zuIUohdRLs033)k{2sKT!TJ7_!;(WG z>-*v>(33r8WDP`aauR{$ggtFm`1}f_8_^=SkNvK+G#Fa4(}HD#e>3R zh7CQOVA{9D6Gx7T#$^?3zSNPdw=X<1{m8}x5e)1nH89J5I||I=-Jr>g`kx9*o1}sL z{Np(Gd0TK~?KFkqDxbC9Ek@|-t)@kY7WK6l=W4fGr6vJ#tybmc#u@{1La{L2Ii9pB-kEt2=Ob(G1mz6A{%yEmX< zPrTgoe26S5Vs2{-2`enbgL8gcSXdZELg5``T1A+)T!-l!*Vvm@BSrWR1_8jP-hxN4irGA}Z#<210LXCBiQERXTG@3q`{{hDA#_L~-=+hy@GP8!p zTl$3%&N}%bo5N*dOh=VadbZ?}c?yhx0A*EJAi4wf8ywK>CLNykqh$CZN zV_CR2PH_3)>_wv}AG6T8MjoYZHkKK1sYKxHsQ@^iJaCgne#}x^_r))$wxY zvc1?%d+&hJRIcy%&|)xGG`n9mq3xwn{YNMvdStqtG_sKj<;D5C>A57Ma?Ll&-}x0n zdBX-az18{KIT>-5p!Skizn%eiQb5Uy(*PWf;w}HqOVDt+n#$=E9;ByLU%_)GQ?Yq2 zmSbDddpyCnPE*2C@wmQ6ZmkdPvdyFqlNWxuNEXmzYNy9NWLT#|8cku!s5g}C5?Rdu zyLlw@?~tAcJ1gNyrV|Q@rwy0xb+Q~G`L0xY*1Xw>SLb{SX%d7H5)kY!&A&jB$(4!s zb|Axa_6nvSP^F0+6#6j?%E(SVAwm9HJQ|B1`=Qfv_TXku5Pacl(Nx^XomuXDIn?7=$|Xh9<1WNXGq5 zDIOFq{NZVkDGsLXPCxSEish^v1!B0~(M#Ab3!xusr0=ZU!5<^j1YEhku?YK~^B-3| z@e?0!CH--@#~C_GBEEi&BAC=vhJo)erM}wtNweNAOp1HWnN5Cu#wwZpDoc!?u1jc) z93hJ&-=qD-#%Mi=`;cX_BarTo@|eBrV{Ih1=D|J+MlA!8ZKZUyA*3!bRyjGA;Fwf`XaFP!69?xOxzJmEE|A`r3DDl2g-fAN>BN}O4#fZ z=;`TvG7-yi`O%44K#O?rr+qSZExdHi7DGI!M;tCEj}CPjx8!V?A8L`PgVTmxwv0BA zzLAsZ?#qRsix}Hkc(V{SB_*)jgOdSE4VMqPW1VS>giX?0a4r;M?hbi1@M=MtYI}t2 z249q!VwAtwd=%5f zair79>PPz=0$I=49GHgEMj{!3Og15{)Cg181JAFILlAOhT`*hWy4tyW(=wOS5KP7~ z2ff61c^7v@d;W+p{5DU^@zvKy6uv{}KSh8)1JQwrSb?A%!=Tf>x3u^qkIgFSy(s@<3pv?}OKOWb+3t}? zZLianhqA#^%L7ilsSNTJxPx$GG_Ph(at0&2jD3rT#hxRAj`C2~=a`v4suDig@}s@_ zk&1(r70FRD75@-6Mk^xryex8>vDdfFuzR1cs-OU)(t>(~`Vc3cTyH(#p+Sm%|JHYW zMxy+P;@mv3F+o)ofY6iIBrTLyO_%289RXH#t}MFuxRjC`E7-1UPu)pyruD5-xVGs$ z^P-XS>ei|kLdE(XDY#pqC#kON^j~q_tgI(e{}Vs{fjvfwj#(_@7HD;HqvZazB+*8i zchM}G*2l#-F!=uU=QwR+ia5V-&5z!?>%X4nT(;muS+aqK$+D~V*-M_V`sA!Oyu0*~4&Q*N$PrnknhcoBXEe>qR&Z&V-MR z)00157-0(YCva-4LAR%u4uCfOOFcCBM3_C?xxn%4n?1)n6UMpT#04U-g_w+QN=SFj=kQOHt;R}HBL(dJ1OxYPoFe&kH`SP;{3K}=2^RqgF0Qb0E>77>#D{A zvm)Nac^QEux}d2jGI6EacoTb2 zv_SE@eFg758aV^od42Z@FAyC2*yNy;3B8~t%hI2M|B`9rE-ON+qoAfw>d!` zS0w~dk_Y4BbPjMbXc5N3^0d6mffnX`#!S-MaZM;{dao~ZO^T6nxelNJALw--!9k!4 z`WSU(Qx(c}fJ(CGaHcY#>}z0E1w7|w5h}k%6b7O}PaNPTR>`6jxAzH()ix)uTN7E* z?xiO&JTH>;8u5?l$8PB*P-KFp?!iqutI7iUd{AGm=v$X^(ErC^(a4ItK(pZ6rQZQA z{(G&Qf~ltUW5}M3OY%g0p8B(&2{@}MlrBd?yA!Ija9x-6G`|wqa*ya_W?Jc8* z9?+!$20qFtIb*y+YXDf=avSKVu2{xF<>ygc*o&@vXFS+X&+Y~*aGN*%K@S90hV5mX z%95XkWM4eZB-01jKOZx<3jt5$AKC7*f#l~G=W9Py3U508erJuWReRSBgTW-2YJ5N5 z6-jS3wcCTrHl8W2W?gkeerPMxt?Sj|h2rF#{u01N1UT z@i+BTo$Egjd|4hLFi4@<>U*Tm+B_;q{Dal4n!n{inea&V*|&F4AR+?Ujj#;=V*-S# zI8aNzJ0z8bZxJw!^{K)Mk_R~_7(Y0Zujt@wvUOSpxvTd05SeFJ?pv;#!_4@qFekP< zL;Jpkl=qxbT|F%V<=ThC9^X`FzBO`|GN7;#o?~7%AovXxovi9zIBri zZBY)(oPjkTfQ62%`zD&g#XnV-x3KlOu2a%0sy` znWkrK=1tOjPtlDtuXaln{HPjCR8pFI`o2?aRRAP6&4bY*n~`iSaPcmPIe4yv?O5U% z)96m9GMlsKc$M0EskVN&`i;6&O46?91M!MQ-^|m~7rrQ7!_&})+TS7QbkfWec_U$d zh`e`o2kY*XJgL$u^bPs=F3&fwUGq>P=APmNyeTaMwecgqEvwN8Q%vm>1bRE*U=Ko$ zgC>8dXE`{dV)^uJNK}zADi&}U>t)3Wf~p>up;nzC&^L` z_>gh~PuRg#lv*Ui!KIwdS9S0rp62-)6*2KV6K9GUH6Nzv(=Ab@L0gU)|=Bzv;Znm+-MtmD6np;<@#eBeIET*+f1HO-v4Bu%g&+2(@f8 zDl^gUa0=di5j)N6@g)sri_|swqv|a<*uf61_h4J1)wxBXnmckX^Pl}V->IRlMa);V zwB;qVR#DQpJJ6kPZpwMJj}VM?CjR`PLCJz%t8<1d3(lzJ3eQsTR(NsFC2#uSC1-c* zdN%**xca}hNBJ-&I;sEwl>Q}3=nGKj0vfUwr-nu+KF7R@Iyl*N!s#1|ZOD|8%7>RI zY5UBO1ToL<<{X^fUBPfSJNkzyiJ&AILvbh;y4*zY{Ye^9Al6}=-uDoKJX#c$Udrvt zC5y1U@8*#J@I9v_9HzWp4Qoj9rH;OFYm65}#CSQs|4|Kj<3P;ijOW_csl58A7lx|h z&QTSrq|8<5Ds$_5S)AzLFWW2o$)dc6(x-pfos@^~AdD=V|+FPkb z>ISqK`}s5Oe=I?ecPEzT$tL_>rw-e)fzmzW0oR1j)2N#z_J7RRlQxKON=i4)HHIc; zc5ZrM6`vg^KV=z*X?l*2U=2OwfY?2F32aFhLTs5)iXs9W>oJglHZ@iZk=<7?u_VjP zORbbBBZ+D6C-oZsiOefeD6vk|5{OexsYTW~Gjmo10L=s(2^N2N2fJr`7&E8>0xIFz z(b;8I(ql>TwIFtjCbpw(VvZGucMKaiQE-0<^@C-^Z2?+>C8J`ACv*NqITmQ|tl4=_ zjy~-Z>fgh{&pMdAsY=vo^uS8&YOM-4A0xIeXC?r%^C$o4V&kXx_;aS^Z@LJ^$9-%Y z=SY9vwx8CjHCf|j4k6Yt@mZ71Js1r{|5FX76dflA8?D36Nd)>7wtgp{$YcePOPPkG`k#z#>WLQWpcxU zJ{hd*gboJrQYz+XVPCrz@W=IsvZkh2?Q5R)>PjxIL^j5N#2hiH+x zkRq(rJEBWQBxayA%RDzX41*UZ=_lo1_4sdkRV+TS>qtLXd0DX?0&NbW0Y@r(k!8~%yttet*kefH^X8U?c09jvPnAeCzT zfDUv`%;vJ@_)<=oXb<5eh_`MiBA_xHQhan(Hvlpg#cb;i2s-NNSpA@F9(wn~4dXxQ zUjob?l&|D1uz#(7VC8}Uaiar7OU>*#k^zZr=3{Ov@&bLhX+oDPE5(2JW>5tb0Ha)L(*3*wWZi+!oI zrL|*`<=HCCa`p7Eo~15$OI{pq*oP%dYZx2z5N0o@+AM(-mP5BPC~(t6C5RCJYZ(4Q8C*bXRTl1F9cjL-CO1I0(KV2ib)l>Z1jFmV&=#Oo+%8vFN*j9a6WMH^Z$@_{9~tZdg)3QqM0v_iQNA(MSx29Dg~qMY&& zb9A9}5cS*6KLpr6)yW!()HEm$*gL^I9c<`uRWO%5JzVv7dMI^;G~*g5mF?-)5TzEJ z`$~uM^pS=m$32{l_2hNzfu4q1hRVY%Aj0z#2|B_g$+O95?9cM!3$In?5vs;dDjj=- zKB(#P`YT^xU&>z;SvckXcSAsBp&b)+nuwbQ*X+x25NHZy4GqHD`&rq3BZ3I`)Z!ueV&+6WXiR#KXMd}@WmASUO6zrzF?37|~(fubjVP0~B7&*c6 z?wOMuxNv_-e_IH(zIH?y6g<^Ds@M0jyDrr|ms(;_{wqIMi^z7vhz2Jl!n8Ev)~7*8 zUOVGHFG7_WIly7vU2j^vJkGZNxp0D@2#d5?71d?AK%in`n{_RLF^tMc4=k*&!x+8j zl?<*jGwY<#j1wM|!8A|@L)F#SB@v-iAWz9g7{pw7q0X|ap>rn!zzKsdwjJdHmZYAA zB9HGSfb9NvR4}c^iis)9X43vRx#NG2$`uGHWbN6E_wQ^t5zvV{LQM7-5ArrDU~cJb zC4ws6xZpYa(@`dmLF{n(oy3g;zO&zKZ<||3N6Cs2vFt5fgk316mCRTxWo;^rq&be) z1j4JPNurRar*bY*ku>HP^HOR^FaQ<+#?^fQ&(*A+b$cq$j{_foIo2Sc-2(W6U+CIe z<=I()Gn^de#S1a#fwU?pPXkBtoH{_0p!6;9>6obBKB0|Xe;{?|Y4?*y&2o!jixU*4TjgW}EINg9M23tR+?s*WH%!?;S@-)PxetRFa^Fs#y=+jVG3|TG# zsx(Y=DCaF)h_Y(3rtn-#5m1;-ozW#wuQR<3rDVM8i38D_PJ%iGu<*Q5%xG}Q@4Xl6 zvqh{{9iCc+E4MRztba!Jd&FTbgy};am0FY?BtvKXFP0Bh|FRc1t9zC>`olvL?AXF= zOoMIKv&Q86+FxfIn}@eQ-^rs=+DWc9miX#m)HTo4%y$KaUqsgWE1eFN%{(et*ujmf$2~|kt<~#n;Rlfh1&04POqDQ z<_a}pz^_L#PEJJOgXM>Kob?n{TnF9a$b^lDlgsu>()U(9_M@*XwKIXwF_+!V=7MdO zS%i1|&(4CjAH%;#KeWol3<}hIIm_GBS=ouTkPt#$wXGRvEoG9ByGE@jOfw^f@-KH^+MY}^bPKj_r~FjZ3FL_nUk1rc*i5sj$nRrXLEEUNKQ-6x%tEGBdIgp zZ)y{Xx$x|&wRgu8s@C)~G^Pqz(8*6IMieLOre5vy6tCVh(Pp zsw{|<5|_9twSyLwSELW;=Z?Yh!dhmvPF>inHM$|-W@=!tt+kLlmsL_ifbyvOkhi>_atAL8K`TEZ;T@nToQWAxOmnaZ5=+lB60r35SrmB$mTB>$`Z)NqDt~O^4V`-{4+3;K!zFb zy*zk$Q_3Iby>z$7=iu6?1|!AZ7b5%pYH(j5YXW0cOXVuiF46~8e%{109(9aQLz&7Z zJMPilNakZOJb`aonwJ-o2wwT$kt)J4v1(mbd-nYO5K(o>5F41)L{%MopsJ;)rR{nK zW^{?6#&0r6Mp&ViY0IO)Ew3$Sc_sj1M zD1{;f87}l5>sH|}$VbI!KhQrTE@Kn8CBMJRZijO~BS98=V~39T3{8agq?nA)K={&h zv9qNmFCFY)SLwut+#JAjXQnkFQNDF`4SiYf7bvq z80U!Jl&zt;J}4Y-$m_H-C>eb&y@vUG-(i++i)Zr7YLTx5hLhL7ENHk{|z0~{@LGr|GX=lB->_47KXq!HGEVni!85uGd_UB!am_M zZO17F)K5u%54SUN@@VTk?G+pmcR652tUj1yolSi*rhdj}A_7w2W9pYzY2c=ZWX4T~ zxb<$0s=!_PlVWl3c~JU&$O-aBA&!~>ERM|I4A#`wS4gKYH@R{>I6wls(aatQmh=y3 zVf{bQf`Eu4(VAxGs>{pUYMNS_epFZ0SEDLwP~`vt%d4R>IB8fBs!200(x7l)Gk0&Q>3>YBqj?%rQH9$+8c9g zkD6$7{n`g73tj|oyvo^#7{u5Xn#M-FJE5bE(K`~PjNV5W>lqWKfcR~MI7`fG3=j)% zpNrrZ1Q~2VuW+#zI9y%sp-e*YIkZ*66kVr-MMD0z7m}V1jO$?i&k}~ZaiYittZA(Z z#g~0W2NF;JXO3w%Bh0joOB-Ap5`FuHUNRt6?Tj5uHm}J&xA6EP21-G2-ebO3qXS0< z&Ti-yk~vhcT@<_3q~`i9hdzOeTE~52`jtGie0)@Y&#Aqv9(X|=qtPmn5*fv*+v%TI zTkp<|R+)3xT1OQ?$RuV%MbOb1O13}^X8JjQ%99RPQ&5fDC|q0BB#+))3t*p$$Ncho zLe!7|K}Y9HfFSrg`fx&r=aiLY?>!=}-9NnWX1!yy*k%?}<%jc!nYgEPRQIbF-v987 z`Ie6#26N!+^pu4;u=HC3N4d8QJ12wa!#AIyqSX`;XUi~z!;SW?uCM$MNAQz7p1pyA z?O5ajY#xWI*+tpDZ7pHp5c`Va|Jgp)R@F5!z86Xx8=m2T(=AhmL}>|1A_{}AQnaB> zPh6J^4rY7O6ymeRd3oyApGZ@yldA8+aFG{f|4y5LB~wrrh>vsh+MZPb#iAq+xeB#^ z=9bM_WWBQU3Oyc#jrYvWy7k}Ri+3~|f#-~y7qGG<|6DI7Qg8E1s6Ld)iG25Lh z)JCOjxhg7OBc_JSy$AYNk|0?3QN9DU8&1Y(S2%}b6}9jUvola_QpDcb>Y-iBHmaIK zEdQztu2&c|gaqb9&MNRe2xAd#2O`wT79)=gHZ(4M3+#75UZJ;?&Z}aqsrxMJw!eJw zZ|LkAL(@%)*?$!TIDOOH!ZYDbltm-CAJtCx%&A;5ewNwRi~SbWfic`Yufz05PDbl}I^Z~iCt;uI zXUNs5lf+l|PWVZawf$CJkTktp!}EtHP-8GV`upGY5`KDiPzWa{tHfj@O4ZdK2b1tz zIF?!COL_`b*`n}o`8HePDSz>OJW3XnT+Den?c&fcQZ`hJV)D!DExv&`)=Rh3j_u2w zpo=H&Dl3T(4P{sDdMb%H=d~K3T3(X!#!?7Mbw|&^>v`lV-je`NJd&{%+yk+-qfW#a z1xWZlqdAbIeXbr3&A1p*P(Uu@U`m=G76b0@>0!J$Wda_ru^;YP;(4*%U8i96X~3_L z(No_a=S$PRIwu_61(4?p&(vsg0g>+CQ8-@r(Uo{~u{;EpF%X_u`+ju)A`xQ!2g_Jx z&YjDuECsX0hpUIMw-<>`7&lsY4-SvTlLc=qm54_kdUNP(kq^(CRQtr_)b=uhBqKDS(KVqvCX`GV)4v&f8W22spBF ze~90}9+GW_69JhF))8&szn`vov!7zeg_^T2GTy<$Mx^A`*uuq z1ka3aw6?eA+ zYQ%n!i;d-NVZUT;_4umqr|{f9(ZvyWh&n8D{<#F;rS&#^a*}UV+~^vwM0m*_kDUqP zPK@Wx%yg2XQ>GHl=Vf$1QPb_Vd_vtS?~*FkfHOMcpMJ)X-o<*GWF`Ia@F3!TU62yV zD!MkW{=9?wmnZeA*GFkyhhzGPgDR5&J9%FE)h-7e4I<5W_A$1YkCh>^;}@5Q5ThiJ zp{57VhzlPS3W|Hd!NE>q#-%8?EU-W=+z7pG&J;enQaa&6hUE}(hw)h5B@fPdu z?~}gjZcANTnXcu9%)XuCB2=@BnHB-mYf%HlT!gzgfo6a>qALj$Jl^~U^Z_-(j2)-& zdSdE4O`&`1Q?Dw7mD|D^-j0riTN#?eX8=>iDf0RCx$|cKss%(i&L{ym4r4EP5m;6y zi!qfCeUnCFdua8ST^&j^q-1?}za@Bfyk>#=HnytAqVD-pzD4~! z`Y0K-&AETdUiT&+%{P`Dej)xVTb22$(CSjUSg_i9Bh8byc~@6s9B8S{9e4~~dI>wI zWGo4C4z#og-MRh|Kf!BfEHfoO?Uu}e+=5=TSL7MXFRSZ0Di;hE>^cL0CN#z^v+7SzZ{oMBfRF*KXG*DOvk;0)$|WrK0>+)>Q$+|N>ahw6mLrAszrwOF?mF9#=iNnmjUa*IpMfx9hNc6Z8s}VO zi0m3&HZ)QN0#rb#n zGr@m^_a{BA_oRhTg`B>0;ZkS|>581735L<1t4_||Jl*t`BY*V91p-u#r05xU+wTj4 zrf{3C1ub9yop@nGfw%1a)i2O1x0Q1o(&3DW#m_mIIFds?+9j9Ci$315BKULKf`kzw@zdKt5ouVMXt-hi_f(Wyos-C>sqxd zja5&sS$7zTMccc%L6Bp!mXhHJBlljT*_hk&wmJgeqp=EnvH$DoWK>n1#o^{!+tFrAd%CCoV6WEAVoR>EIPz;^!Ntwi=BJpHBout< z4T`K@o$<0Ax~1ID0wuW8(+fli9kLHrO4*OQ>4G{B$bkd1bX;&%bh?$8!%4_a%N&pz zfB;ML064)Q9ML^0R4A3E95F>iTb0r_7v>7Bz^Op4<}XM$ZPPAc?1~XpCOP) z+|zbs6_@ZaVa4U%#EnIA$25&`Lxz~V2d$fwwhz?JqHNB}Jgxoga}Gb)*f};l(dH*N z_Bbk}lE+=c%hoiR5tJGpTCKLupVzQ7w?A~>AZ;>@R#fO3#^bL%_83e$YUP57iuuR8 z`3&s&_`UX0RxcE=@_oHQ5Gx~f3FO687Wc>a`fx6bf4BJ{`tl-o*@aI*e?g&e`U=lm z|4tT4ElVWs9c{aM=JkULN&_)=rJTj5ZqXSm5f*%8wv6_{u1-0~p8@rLocmhl@kuM9 z8OtTPhm*cejwWxodo|y2i)K}-AW^7L5=x_SSkB02(3TzeGP-s#7~VbihJ*F$4nnC+mVO}>$`;TW>{iXCTiaQn8Q@>`yrpV2kW z7ITqA`Rdd=#V&A7L;Vp&#jXltKNQcDFl@vpKB#~RSYcn`sXadmUhiX8U@fXG2`4cU zTfx<|#jC=LG$VS1U;($=oEl)ywHOJ`!3j~lnw!51k0BiPgFBa}=5WLGr}W_FC+FRx zWE7QZ`d>3RKnFL1D6g)51%Irg@vTMB(jT#MuGKxQ2Hv+=pnKg1_+GiJ4g zDyE=@_FO*+6nYtX-<$`SWsy*X9xupIiij^Dh5^+CV!a7qH^c1gnu!OC0f!GeDCqqM zo@o9bJVB6CJ=`zH8Cy}Py6@j|nwlC5%5qclvl=Q(%1eH>fV=)GFQ95Ph~#BRlv2)07Stb;S$76!|-{?h(z8RM)&_mHblthlT7Cl%HXB zmkCZO_z{)h>SPvv5EPm|h0~YpufBGE-0uxrQ=C})Sc15}6Ee>4U_qLgE}pv?S?=A= zQYfg-pNUmxuZ)Us|2#pe{ATSqP1ef1W^BF(=KVtydIO?6$fguHl**p*Hg~C007~_J z!3^MuHZYOY{A^;5H9*XPI=u)mE&%6kXc0SDc_{rlbzQwz)T}ATWv5PW@Yi>@fG=m- z?%M*>eAja9&40zK9kV1DIh_G`MTz9IGU%pX>eApZqYPI2XFtmZevJ$?+9I0Go`26?7X z%as!oIcR!mn3LwjuujX7^Lbr-$u&#wD>q0oXfu)Vph#GiozysY=dZIoUfLn`@6{*N z*Kv2p*T`PjV3u*#HpqETWJov4`90}9vP7%vuz36fxBBbqxJ^5WpHGhitj-HyUX`pQ zO>YZDzIn2m%d&KlM9vCDLWZm_ScN=8_U@ryqc;|m(QtEfRtRaaM3o|!0)I$1LJZf$FG?Cns zCaJQWm%1}={P-9+PpXVss%*#pJNyu$;A|}p3un#EU%oH$ZHP*Y$Om`7_`OR&JiX!b!=FB&d-;IQyS!^;qYyE*oWU7)zRo`Dix4K= zuafKi8`dsSug`iJ3Yn`lg6S`ZcBjWX0-rdxgvvc_A$K(45)Jv>qY?GdjZ6VDU#CR) zRQq@25)+Vi{Yk)0dl0;H?N}oBywz zmzs(9cZ~1%SBs=&xZJ<++=#=#_h=gLAgWzv)mN^6Y<7{QszS(DEg36zgh}ekP|`2T zJ21m!K2v`dkK5Kh*M6|#r)w0`juWEzX&t4GDK#m}&*cuuL00-tc^FIiQM`P%CuuTV zYz{F+M#T5UAOH?(7~f}fqMWA^kP3YFn=K?hB_H1oWh!V`!G38;h;!rCp7%Kk;BsH^ z(gFA3pYcrywk~Z#=Tbe;wWIFO`qgv?ednHPXCqA2dRVGIy!9^ptvF^S{rA+4-UaN% z-t=t}r_UGnrA$6|VA9eLMo7fEw%(1ON&NIdN+k>%IyEj&8gHB>m2(N=x29;=-e4@V ztyjdH-yJ!8=0*xVys3SA3|Py1>3_t;L0XA`6!l-o2XH@u-cgLeB#HnjCu0^PKa7Zd zC|~Tjg^if40~oF)P%5S{VRVI@$2=^X6u1t6CMr=<=R`Mxg^*wIW0ncs`km&l)!g=h z*wou1Ki8rlm`EATWl>=;cJwDrI^tr&`k<^|Ma}+byw%LbD@7YY3tHrn+#A@v9mK}Q z#;*+}QVMP#R)9a__jl3Zca_j23U?f(*^tWRc--`+3MmAV)Xj}!fkmNI?Nzhhwq*c; zdL#hGM(GhjS58C7iFfDE0r(vhjIdD{pC(B5b$P^XCC;6f7oHdNz6EjHnHP9%XN}uq z^!#*ja$w#F**h#@^t}H*3&{T2477k654!Nu_&VP~VtWfR&?&!*63%MWNIad!(FBHd`Jr!DowSDI$M0o)xv; zaCPnzN6hJrjtUoabrD4{LbYd)6Wu^3JFzjgO?A`cGBS=UOZ-q)D>xOvDy@wHPk|MO zo$itgBiIsin*4W*`***8J0vk-8M4!C1EhUnZu=tOt$179di|I z718ajm3TY;D`Ss2IOeo&B3V*d^3z0P2`vX(t}r5helHRIgbRW=8mH9l-2&&fOwKBR z)@2YhRlA`9z&B+iF_^A&a0pI_GP?1X_B{qml)awYwYr8b3c0@&!AC)6|F4`Bs-A^@ zSVbJE7pQl`hwC7c$RFZ{D(@zINxj3dcM?hjnl4ywaPshErNi zlu;hlv_)N|N_H~73nqMg(N0`44q?qiTZ~E+F6tZYx<0>7K|YfOYrM3QYu%_N$U{%< zDp4Vz4t+_yh%Vq?y|RV^sUoMa0N~Nr<2gb8>6S>} za9t$4BV0|#_bq(B+^zXhEKrjWVh;QabPowo76W`#`0}7D z&f(se_fyJO_UZv@Qd1{cpURAr$_D>aJy4%7w`mPEs-ROZ?dm6?_RtS%iH0uaw&@M> z+U+;zjbtsdKMj$qug%eKbEiZr%Hvi&vc~ZIKGK$ot>B|RKsCC zyDC?SjZJ+G&}eAWo)~(YosAkI1}xXbZG&o{&$<^8R9Z>^It(|A5NW{?vftddD|jfx zjDy<_Dug#=>EF1vmyEsh?_dBy#hI14*Z)3w$Rv!3u~)paa`gk$8)CIAWq01qv0WmR z#I~bUSC({nNp5MHXV-hE$x%&U?fQ!GLJbczHR9P}|4qH0xwA`Tj3=o?&CXJv@#8R!N6*#0PIf=3Uq_v?bd2!)dM~t1XB2(74?pzRN}e8DWh+Mob=V9x|goKEsl9vC^_icgHJ&ehjWwiWAF^ye{CzZfbX4ve?XwV# z@5o_onL5^7jO85{wHs1krdUXm_AEavcsyn^2WnIJ1+#KDN`BX=ivRF$(AZ zgj>ZXJ+usN0inT}7gy&0n>)^ezu>z`WN%CYa?*ROe1c;OmX%*MIKii9bKuV8#dXwt zjJYouo093br9O(;EBidW|J(0W-O@|i>OOJVz{5;m{>!fK- zGzqMxTLTy;GtJImVQ2d(k8Uw|1Rrp1)bC6DkA#0r+K>In$Mi^gB!sl~u-?VOgoe3A zbF(ad&(|}ft){T}&~XX3x#x=;D3{#LY)ki(y1iyGV(f=D`Cu2`<+s~+fK_ZTq_r$ey5^GLz1qtTNG*BRpONdS?-z4h1$WL5BQp^GU&%1b12 zW}TUUJR?=_paGNq#<@gp=?R-KG`nC^>0ciUO|-|%YShKV7wf`RJ)8PxU99a z&RnM+vqUN~nf;E-kMVDu!E&{yJ{#i|*`I5K*9I zgnqUa&2M3nRp7Dlyz*PUqej|#H6Err)d%d6)l|3IYoq+iS z8d6d8`51shiVS^%^H3eLz|Neb|7`HIMj$NwI;g*Ldt6nW5|l7oQE$imMfzmcM_B{8 z|8r&f7;2v%|Ef$AD~j^c!F>O~Mfzfw*+6>SoWI`I-XmL5A;rD*r-;*hq+c9cPT%Z@ z<;6Wg%(E@*Y-4e!UGSHM$^B!;I8KR~e4Y9E)`Xnww*ohhw;g6PyPTy$a=Df|S8X|9 z<*U-JKAiZjuH$Jd_FV@sYdHe(^~Abs%ZVt9a03AY5WHsr@)#i7OO*_SV~)&gz+2YU zKVQ0jlZeg|l{$>OXoFikHM~7|flmo04%JRloR^F0;vX`h_5|KHCHKE(^(h8}wI3<3C{{v0J`Y zmaJvVdvMW?#zq`=na*Krl#VHRH4wG-Ib}8f&}xkVa*UU=>q-i2OCA9_!wp8qdRmlL z#4vy05y3YAV+=>=dYtMAo*26)#}gV=x@aIkA&5S5eWSn^*ogoFFfc&O{VP{{^T?kw^kg2m)fIiX7 z7~^F9?R1-_RN*9>+EtDr@Eudb`Cv$LW8b^O7xZ zZQDvyYeD;!*Mp6E4Tr|KX`P5C*;;?(N{cz-3)MOZ!%*SoG^ zb&Igwkl_FfG#I{cnlNi%;Cy?jwBNPiS;pi7QViEU(So4@z8ZsbWfzl~Jm*e4=qkJF zn`ck{6bOn`&*Jc^nEi;y#%F|OYN)-xE$d!FjHMfR?0OGUK-Edr0=u$DPgCkLarNY* zk=4rW%($u`^{B8h`Kjc&>)~`m4rF3p8+{{U;W;4NPKiWw!~=BgF`s+twzBjBpXft_ z5dSU*0wI9eM}>7d=JQ$zIQ+YbeOpH zS^EjkU$XoV) ziAMEM=+!qdn|=r3u$JZXv`_@-cgZ+o%?-ZS01&bIT41@A{MN}AG#tGb?uIh0nI55T zU(&}W2g%cfobY2{p%R3cu&zioR(Aiz^u~+4PQ^!jf1a`+5+p@tFdRvWo4VqqbL;5 zof+`}9pQbtMEu*Q(N=61B}hFcUQm(NMxYcS1TQNv2%)%QC|7QbuvcgctlEuWYs!^a z`fwA$KmfuSxckTk_@|tHp4BvcX+i|ZOt_*G_kYsA+s4@0htKUYx@~*eEd&~rlYaQD zg-N3-f|jEnmQ`#jb$#G&B{k1b%2CxNdR!289if z{-U=;y=>dzqDE;9b~l}P3xiGT|4j~pE>#l`%9Y>V3Cq1Ry0Ue{GWdyd!rHq=h@;q~ z>kVJ|FU5#z3D#b}q{w3%hns_Y#x7ZkGbPC@?l*BuSHt~O*)@~Jqk@9Q{4g;y{lg^0 zkcmT!a&f^?W|!Inb6&$n;{gpFI3yW}KgEKwm=S?e(QJUvjDV;C5gd}Y&v+?-w)(Vh zoK2E{LfEPj^G^|MtfNk zSZ!~tyYn&>c|iFM8(rHC($XDt9MyJuA#sWbz)5@Gg$Ke}c)yfySZ8bvyv|m1@CJky zf3)qWPV#mECDE{vyWq*qVL}8AHWLD4e+T)R6Rnq}M$c%zCHxt#n{tcV1a{5yJB!`x z@sxmN)hnU+#~#0;oE>`cm6;5|B>C9YgCZGZ@Ud5$vP7Ml&e`n)<6b;1nZeBT?eVIH z^<1Nk5}4?f({l3T;*f_?yj)cjO3Mf!86fmu;6dEd(n7FRQ7`k53b#28)6&cMNzL2c z>tiwTb(Zmbb%jM6HgrXh2R~H1n&AFdtbuuUZ{VnVg@lTWDa1(&$B!qra}B2N-dS0L zhaKAv{}dg;Jlo$t?AU&pq|s!9veuSZD`dF>7aO-3j3)M3$=4DFrSY6 zbIwG^Np2JB3@uk+riZto!MTOU$>2*`Dhaxom_zI|AtHpf@U9(|^L@z}_9~gPDb%e} zW{rD_8z)5{$jtipl3y6B6ZvNo!HWxNZQIhF0{P2d*{VOc(o@a9U?`C8HLqpke_#z~ zxyp9xtbbSY@LXA2VoxAuqq=~^HRGrF7S%=7wvgc?L%Z7+=Qxw}4Hb<>RGpq#7BJ3v zv<_5xHCuXq+}*liuLUxpe$KKbSpf1wOMTO&e5!29V(29DlR9<+h!J*GdP4`nWzKoE zG<|?c1xy)Ly{g)v_1TYaYApH00V_OG_WKR}zlKN9b{q6kXnkz&rp{g6I%(vZ{(%iw zYzto+ap$y;Y;gQH%9v#goW4`a};6CS7sbQB}z=4Z);0I(66!13>9cUO6f`1NH< zzA9|xLUy91p87Nh!$|6TwQA-^@9ch4Z#rSFUQl&+H;de8UlXyNVzV8{fa#v=b1_lW zJ*Nr`v}6lZZJr!1z}4fA>}8PHyYI=y`R&Ju*%LpJzw~U?@j?P1g7weP^rR3rmeRi8 zwf!ivzxa0Nop|PG@f&8d#3P(Ztb?gmT@}AZ0!K&C$Bn1kJ4 z`W!>mJNp%u_w6^Q%4{%t?2=O+bg8_k9Dmc}%>**pUJj^lOu}*8;70W4LQ4@Jes;#UCRA># z2GJubcbJnq#R7j_bAGBkh4wyn+vje9TD;#ui0ro_;W3;1)Fncx~)a568oAU_${vNZzkI$^C9_oH)nBG%r^ZqD4(k{36WKHscz!G-$ zu&4eSQMApPvr+`bWCG&0=soWj44bn@n<>f>#5#uN56owiAQ#+gMmfJ-Y7>N`_iPrU zEgQhj13{4V>t(8Dy)i;rPek+dun0KR0Kr|?LEPr#^nM=Z>zkJ>GJU~r$5(SEsXCE7 z;qLFhDKtL$EEC#}rx(fl1?wX+@_Se8zR+wT;Ym zikxXLKR=>nIm8}J)~s~}9~Xnx8IxB{z&vplsMZirqr|IpNNe0z(B6(y|{oS6V7m<(lbZ# z!0W(zr)>Dqnd%_4$DA02xV{_(NRHKV(b_1EOXi%qjjv&qv%EnzZoF5qn2D778c+5D zmb9Dmf=$jnD*Z%BG^k-OQaLzG{W_|dXA(1>(ZO`onY(bEdV#w}_gr^i*f}47_6yU^h@bzK!48UjD%NsI^7nfyz~( z15TZ3l9XvZOX9s{1<3vAyBfrL#9Lg!8wVkN<3e>k zugJ+v38q1j7UDKJNlM1F3v*onlbuaf&F#-Aiasgiit)gV0E~?A(8>P)vWtLiAVpC) ze$%`3vQ)6+Y<6XWY@zL1a5`H$*Anad{!d?i%Sv2-9qOWMBHaSJXD5$6(qQwP>1FK7 zT<8tCqGcoD+UmVSP4^@CUIM&ZZ0lOHw54AWdoe9>N;9b9gsGg>oY66Vh6}d9Z*)cy zLyNFfP*aFNHHmD!lRHJwTtRt={j>;ONw$p@P1E-M2u!uXeY?%BVBwY?ceX-?2#~GJ zN|}0NZu{lmCk=3bI^JOx+Ph&n6dcC1mKoh}52ioA5_(uYzCC-Gl{`LN^|HoCQMX!E zaTUGg7E(W!!X@P+1-d*OY(BHPWB%JnKSrlNfp@EXXT&5H_xNR~m*g_=F#5$%y!J@q zxC-ynJ?1 zr@=K$@?^*UjF$9xy`RV`7LNbE$Kl_8@)Z{*TBn0GrEND0?IKbvo-iBGg!#$xjc@e=A$KnEoK$2Y`%IW& zgGUobsTx9QKdMj$3$L@WyPr1#jP1=<>W_Y_t5lhdcCy(gSMKzS@d|HQy|eD<%4QK+ z-d=ST`(BD(_5D$=0UZ}nv;Lep=+uT&uxbiwxvsU<6W!V?OR%<)(AO8R$bXsq#;#!a zC}WZRa4nnCp3%Rg6jFJ4b9}tU4=*d+IlU1VU?^xZ@F?r1oSa-HCGucq6JxM`P|~H5 zCA(mo#lP7apqd3&FWU24dqFgHFi;?0+m2dmhjhS!i?bjzV7e_C_5zumHf9401;hs& zVq*RW*uAxJ3^aU0Y+d#W6)0pI0KN*s$43T=j}NZ)B)tS79a)=i6z+|A(N3&mHaB}F zv#YY9Y*1g=R`;h^-$V$4uG}J}v^fKVs4pA{TaM5EzLc+Tc_Bx>jF*ZkxZNR9&W){* zk`y|>VppMWAg7*O9_}1G=~Tq;RGEE5Ci>!6Vl14F^q^9;;I`xCGZzjt^UR!V^jI#%kW0}_{>O1Mx{JiI3nk*F#I&7mMDskqL7%+7K2_KO&d#;nPOB*%^% zMW%$cjk%Q$KvqyetQWpEiX{%*%OIg?4s9p7VRg@f%2CU$ zvbC|ZJ)`6ypfW12Uunnx>XJj(gkK(-E;uSYY{tlF{NxOorO0pgS+%F>`rh!V!zJls z`a)MS9-GdLY;ip#1?3MzUxj~Ak-RI4BM$MmzsnarLeeXdRem6P-F*>ccOtK6{P<$hCcYMg~hai~aQ{j7EDsH)koPGEbZyl=b z+s=&xPci3ez3|JcqA&bM4m0dL*EaT#$%`~NW~!{q(w|r+AKamBU-rekc$!&N<6bqo zZQ(2CJCtFOpWyn&NYmRlxn?aP7KaL5dIppI`O8?b@ekS~8d1OVpg0ow^Vwc$$*Y-~ zg}}Uy=J@rG^A;Og(2=ku&%tfNc$!EB`2pa}f-F0}d9(ZM=gW$l zSz2fyZ;3@Bt6SkI%#bBz3)`C@qNw}67jnOYEWBWnly0>91|{1a->k)h0|k-#*v-l9WfSa5BQ=7a&T*E+*yrig z9G6zR&&(f5s|hCP2N}CG#FqB8>MVqKDaX5no@%9oFXDH#iiJ!4QWlFm^H1M?XQBT6 zJd?G5R`VI>Q1`ZuE~W!4Myg8=at7J3&bq%{wDl2>eo7jqDroB#!y(os;grlCRNvjT$02ymK(QLk)QI5D zlC@l7C^ZUI@EOpQ-wH}k3v>yP0)cEL){+&0-p^s{LdzO*SaTQi z0k!5I)8b#~=XY0j#$N3a0-qDtKq9Zz>G3!ip$UNrG34IcgxYMyph}bSJseWJ$2P|{ zzC}`jT;UANCV0oUHCg3*ZFi+Z4!aBfKDq6C#z z$k$uHY!YgngiDcJ8l=~gJ4GRzF&Em$X#JR^>om0_kP0mBatnOoE)@5+jzgW}S98Z7 zVz8x&n@c4L+!jL`gC>ZCH?l%Et@79M-#*oE(q}a z`#CzXu!e+G$wBLi5On|I`l1l6k*m^5XCX@wo zCEV?)AlD!_Z>U8)7zMa@V=16B1)Z2>=FbQ_Z29y@S<73y!%m{lfS0Z4SK|zatF70< zHpOxwqQ?;g$8B(St>X_42AM*&DP&M>a~DH0Td@md3bS&6LC#CuMEg#!iRPVJr0`_j z)U?zPkxYY&4p3sOvP3ef;ib}JY@KURce>5I3&@(BsAPEV=?3p(0SLXQ#?Pu@#OTa;8rt&LY7$;!)Yyk+0D!;#xCQMCtE)3 zQsbW#Ak#V8h#}DErq&_P&kiE=HUf^Sg!*AU3Dk`HWCwBd2!y-=$`y>23qR?iHJf(c zeGkXULbzI!gB{}Ka1^BJCYMYdQDO zRyjClKU@cuQlZz>2KqrWTj0sQB<&G~l%c29Rw|Gvtc9gp^;WetYZZjNOa)C0xi}a> zkl-h zB60sVyfXu2CppBilRNIN3>pPN_}xufG&!^$u)z%J-hc8n@^9h=-A5A@6nSh(elg^I z#C|wWdENvM*{^Q#o{6A{M|9rem>%d)BI`~-_W8;~Fb?Ytnda^9F#T~YCWhCAIyJTOC$lnA zr{#?~`A@74o{uS1(B3}n(&6Vg=c7*IaTucpUr?%%xUemLYsb$Tq(iL!Jp|I`QUyY+re zb(jT_$8VVR>MyPTn2049bzzuFoN1 zBuFEB@f`(3fXirN#q?1VCbWwfs`Y~S_hg^=M$qT64u>PjkoKGUx&;xxBIF-k&EZRq z6Cd_8#+9_Q7yCXD`tD@l*yh3fHqG?HN&=w!r|mBkp`%S?=%tZ}XG9hwiRNK`R(`!J zOs1x$kfrG-8u-U^O^65@-!oA2Ev_mucS!RyRq*jS#H+yYi=KC_x$huh8Fr*@x|Rpe z{)~UczaAO5XK()HGJpWJ~M`nI^+htNfFnyFu&Hh?<3@OD6iZTrCa)kmiwK6%v!KwwoCz;FLTlR`pB!J z|Fp(z84rYppmh=mxzY!ZYZMK6O1L@%%?#CcnHB9(JoLJP+&|-U777N;)59>1!`eb8 zmUw{(5)RA&JlGO$*SpOu?|%KMqfhXi>JDPtUpOn5>+YJ1bB=yuJ& zJTy_4A@>`{XHR8(!0a5I71p#N9kie^>w`#CwMBu#9t$>4L)zW8jy-F-jq!F2(t?=V80GB=|R(9jU#wy)fV=m_5j|GR4^{wiqa zS1~)Pb-(g1<$ zjEWfExIX16{h+5O>>ZMCsoUj~cjrZnh^vwt_v=^cy(;&On2L<`Zgf8@5`0^{u;lWg zG9AY3ezsoW(pFPPj0o&*&`Oi`4ak8JqN{z>{j;RA)P?~PASX>_>3-!8dzvNX*Q~5U631FGcE1!g~6xAcRqc5{b z)ay-#j!R`B!V16ep^b*kZ1A zMdzA+_86Pg+EReDn%sxB3)c|$>Puf>&13C~_p>KGh8~3sON2Y|lOW-R2)F7^N6FVp zp2*Fc7bAZnQlIaA!&Kjg5<}@hDMSd@m6chbGai2mQLh#p{|@o97<^iis`XA=O0Z!L>MvVw2K0H018Bd3&*f_+W z#^1!7;IHD=w~jWK&-K~CAZsz$L+eonNRlKV50k6ki5flrPe_R z?@oKN(GL-*E|R9NVznX6FXR8IH~X`9s4XU6U^`A6A-BipXH}PT!>>aZ?RB#XV?+t5 z^%K=rj6)om>{`U-6}L!45y1^srKIAQhxJ`OJ$C&D!*NgfyxdLDODyL-k@@j(>|!2> zu|UvSBe(Yt?r$NV$**M0H$~ZJg@9N#$9YioM3wQWsmlMJEF_b3Pv;yrgVIs3?}vcI zy~1+rghEd@1eL%{rwrfzf+L8)wMUHp81?|;26Mc_QKJ3Bjb&pk7*>18kZ{AIKO zh?Q78v9JLjtl0qKq}d7&zuJJhO|RAcE+bgXa;>xy(GiEY z@EesSQFs%i%+B7??(0*50xzk+n8)FAV-0ZR2S2J5d{#)uCM*L^qx2%w8d#nGH#I&T z!S=>|3Xf?poPGyF$9Yta`z)p*Z8F4YE-;1FLE~(-sW{bauEb2&gx7F)sNN*v!W3F1 zo7~O!{>8$;aDIiBPt2W)I9|_6&PVHA=I8IPX8CcIvbJxEzoRw$s=t!;?Iizqs(?c*~6aD zt8YA)?V{LjIB-y(z&lK2FgP^~z&$iPw2JYa(7FclZaEc$KJTgCI%IVa+5Ws(RhOBG zIzH=5Zi+$XjwI@2+OI!GtWjM+8Y{6v~zN;px;Yx&vz(g751 z|Cz$Z5oqo60x2J18YO*0&aF;-Lv-n)6=_Z;1Ay^!+P--!$6ii^ zxZ~%elSf3~4hZJ}EIf50cgiw zhB>4B?n73ZJ z*eydE91ea`=(anI+79@aOvmi)x?D_=8dta(c&>w)f68d%Q$JkzivV2RAC98>xBT_b zd8E|A4N@91|Cj$6J^)wtPO0cxmtP+{D#vep_V^JoE*?GSn?wxly@V(E9ZYmLn|UVk#e^OwMda903kgI zX<~UD7TOgI*WZpxB3(Y+)r3M>3c!N!Z7Tkeb(d z=;pf|4-*1ZKATGL8_wJ7Bp7oFE*0hDqY)NKmq}Kp8-ctikoS?&zH+^n(?@K@B0rfw ziGW48RXjBjsOtR+V8OvWSL9h0JA;i_WP7hctw(nuP64@lmZ;q7t%V|@X*H8Pq$7*$ zT!w-kwCD11|7l95HJ>2l0D|A~0_1iBp2e2_tsj=p=6@&^K8cOdDZQ`l*iO0Jr4zno zdHqSh+m!><#F>4iu;P!iqPUT&>f>mKIx66ZlXM*Skb?7ZJj!gIzjIg1K&um;zOcCX zjtrU4!dPOA5Lh-gDTr}+T}P?Kk$w5YT_uv;$b;0QNZPASTw`)NtA|Gkl#CI=Xw8JC zhG5^yiCo;*~_;1t>3)km>mY1J3EbG#Lse1^|~6-Wh(vlLWAKRfSXbm zPHfp{U8KWysc5$!&b8%uFpM(I1-Y*T634Zoii=kc1d-TG)La-z-p(W%xab>1UdK>i zl@g9UGT~z)_8U)+;w@Y1^;EkETU{_p4Hj0l7%Zwld>#eV79H7qznJ13NMQ&>fCU7Z*9cjX*?O9H`>O_qf3%hRc4yZK9J^;W_kItpax zGi2NA$UK%-INbw?CCD^{B&-UQ) ze8VUjyxtv7V1UXXYVP{Q+ zuMjIBSY6$dEAhqv*cf@Oo$30QEI?RJ4{Tl=$R1~A;82d5xov;nKu#W@++_){ho z!a232ISump9A<8}q)z!UzB*^GE$8TPK*5kEbY+V-W|Sg9I@L%-@6H6qo0FZ~5JZz-h@E@hS7My#>hARHg}XfVxc@bS(qV&? z++L;}3RXW#v462g=`rPdMg&*eHmL`IkeJXuv&?IS7!-o#7CMBNrUM2B`gj#ZjoZuR zKSq{^G3(0;ZTs8#{H#4T>7S`(B-4_z`kGH}H#PG!IBcgEe$|?Iv~5BJXjb_F-R~WJ zO5l$@^YftgyV+pH<{1o5Y>o)nqzusS*WBjQVH*aWz8*_EzmQ^zMZ4O!D3pa`$43bl z4&Q6gpMWz}30thUPQX0J6xwoVveDyW;?NS3sN)~3#Pag_uYKPpuD(#2x~{P+y4>vP z`1OV(9o-F0*f{8L^TjoIbm1T+n|yW+ja)O~up`b259Sy7A2kDa{f%(X!s{HLWQ7d} z$*HxvQ@90h#U$nxyI%@dZ=mOlmjS4>Hud%uxsKw~()L>tVtXY7NbH`I*2 zJtA`B_kNA+DkX0b@TXJ`k34R_6zxC`x%&_FqMY|gwV))x`aj$EWv=-TdPDE%@L4Jo zsCFJ;vPT0QqZTzW95D$Uf~CrZ0W4PP2Q!=tA4n_f?TW@CAB!zH{HBy;rA63PqK1Jt zY@K#>Cwm+xA}nr+0>?iLiAM3%y&Wp9XCME4)f`;fx^wJSdZRz}Z4nK?okUj0Fsls* zgx{d~>PYk_kM@4*R4g5sXkF|w5({Un�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

                      bz;KoCD4hrFp9kbHRbN8)xR!U=v9_=_Gb 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�LXx3lj4$X!^d`9 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

                      J1J_E!=MUjhBuR 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%0AM|x9&a(n- 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%0D$Uw82!jsZUK3lBY?M$R{+yP`(Cg@Q6E( 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

                      6$zt~nbLS*aH}JFFs%?fSGq!DT`6DgfpdII_WaU_UU1|Ua>9$+0z}I!G z<%A^o>m1;kqr`~z$wPWt4|+ew{z^_-O=CRyB3dXi@!unO|+T%^4UUy z+h4FT0KGGS=GnuJqqz9y(2`;9JjKwL?R6^mvc{uxqK6hDvg$O@`X@(Do(ia26N%#+ z-hKG}iiY(c`7M5zbg2}+r5Y|EWAfUPX169#+TeZu*ZkbduLEp6Z;z(50yg^j>7196 zJo3%l32AB66TJQP%drM2BC#LU737+XCMF83+LoKVKdktM={L)zrG1r|cbFsdfsROP z#I}bc%IoL|hC)F0L{-i%DPzu~@y3gs(p!T!tz!#c<+OUVj@4-fj1RjFZttvsH0rkP zvFV@2T!ifvub`l>-K~yC0g45G$ty2Ki*Fafr!G3d)C4N6+*)3=a(=sZq*4m{fV

                      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
                      huQQKY845O2&{@;$(hWDg^0w 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

                      IN!V)xTT)^J4Y`vsvpE|A zl7B|@=U$T!;3t5Dr_HdlFo&{Zh^+Gc@VN0V6reW*^EOYe1l0Z-Z_kOnSLFBM#)S@) zA3U@zwZpRnn25s@LRNAV1IIE zPpR!^|6haYbW9!GCjRXvxxdv=X4K?znOIVhz0lg#uiB++Qb35*1$753m z(?t6hqk;5BC=wkc#HIVZj>^38WVHgxfl42~-{~(~y#J33Ba+g=0nqMQF0AeM%c*Rt zK36RWzmg2>Y_gFivG1bk7o3|?8vdy2w7^do9~2UIeKdNc_3Y==o=Q_=+QX+9p5kuB zmintjZ$H^-N!}hNC|k;6K!KFtRta$CqLBoAD_C0YL-4(cQ_ z5jlwP)w$mj!Blso#>AzwvXfmuH}Ak`*T-)^Phv92Rio-k=wJ`bPB|g!4XN>lv4GoU zbpBxLv8!eRhYB~Z8SdHh-+U2NmmIHF9gj?%jrfDq2?Qnpvo zaoeMKF}2$c=Drci7r@!CXL0aj>>_VhoOx0Q@+<|uRytAfEgIFQxcR~$OW$Wdh)xb+ z9F7w4zehY%hKIwEXza-zaiU3uQ67g9kwykQ%Qlps~J}ojxkYP|DZ#%T{b3i)uB-w3+;DPiId-g3MPPfAXIR@^< z_4vDho!sk(5}~dnPzkGPv&2a75DtPq7R$Fbp$fO>Gy)S9M#k!wujXU8=|f&v5rcXZ z#Xzaw{{bck|36?N2txkinq*XQ zFuW#?;d=D2a(1pvFeT&u`lbb;4X4A}_F{Jb*yqgcRlNUV9&*#on^0m(>qNsrDem(s zNMHmdPuVY$cfY?V36oKHZB8A1OK!aVOPFwKS}VIC7*jGSia@h}%zJP@%{e#XX8&}9 zpAOm3olqtq>Y=WY8%WX8DRy~sIVE76y!r#7yNO2)_g+&EYtbm3 zPgI&g@jhW)OExfTS!Gxqe?GF8qWIz|C-$E&sl2QK?_tIYIgQ|h;07R3te|a{$&5qj=a?(@@U(7?sSHg7hy?9(~qbEWYycE^LlP8bQFef zNo~nuVjhSf!bMZUd*e#zy9RpB{@ZNR27YuCCJQXrnLD72U8d3hy?DHOmE(hOZA*BXdoIy> z8iLOG)6s=yT&P~MJ-hv%Bt>3u^YHy7P1jzE)Jr<3GyWq?F|b*oLmZD^?}zQ`Utxo7 zh3E^sGZDl<28GTop-gr8?Uw|yjc*XW9Y7~98@X4vigve}JPEla7$+s7`o5m}Wyfnp zy^X_1`_YU!VdZhVavO()@}@&=pV;3J%jX>d3QbRDkkCf^cjcDs{iUAh!aPMHOXer2 zafmg~C{X=i#MP+%Rr*EVXzS#oA;}~D^Q?<4o&1T`fTS&pV%9YisqzrgzLsfA1 z&N0Gp9l!L|&G~pFfS7x^u@uln(Wo2vL2rV?q5a1T_%~%f~pPRA`iB z#ESw^7!o=W)zIGuGuY2NqNPty{ZMg;Y%P)(v&Fi#4BNL=qB)r@3x$u}H`3%b2}a3_ ziit?LF@}YY$+;nP1es)`g$+4n7GIKNzF0p-FalC6oE`~V`ExQ$dz>M*0<-iZda{Bi zT^6E}R8E)qA0Cm9&VC$b(6Y#=H_+pxUO!}u68vphIQtLQ?B9Vfo;-$bbC(n|2j~w= zC@ZP&VG_VjZFYgJ5yAhNihcA8KW@D4FeXi4{~AJLdMN4F`!)*gz+z2qDMVZSA8vM( z=2bnlVi`e(phArwb_iX0Ymm8OK=fgMe!^tvg5PQ&3$-hLI!mgsW>Vt7-u|uck_d4_9%o z4)*Zs=TNVwcSsk_->JPCUJI)d;l^BcKD|hTfiStYLJj_Vi&i5A5=E~AN=8poC2i`8 zk=G;YxonPtA9`z_k?vLBTCH<+r~p`0#G~q|tyWvR(+Gq+Bi+d7{OexbTHo3A(IY6I z0@G{rKg)$8^&A0um5(7L8T0V-Rh-MJ)F^kK z#{$3&!?I%&dm-Q_iRj7wY7$+%?iVs_V=( z&WDffHR_(43FSzfixJlZXm%9%_&CcJf!ho!IY3jt=4Mq!mycN6&5LC?w3W!RzWm91 zfq&|tH;$Y8(%;m&e#Iq1%ac)SBLYxNz#VmwovLH#vpHk#|S4GBn?-BGm;+IJ; zDyuYG`L33Cf~Sv_-`qFoMT)t(tF(Xx3l@@LY<;VBC(bE4B7chf)y;mE%gXj0t2`+TcK{W${3cqEJFDb*svh74XpVmBgJ#zUgVO{%DX63SuLs(OioHbsOlv{4bsaB*nJw=}&aez7OS?#6QubhjWTZ7DAxU zF6${R@C)BgVB`&$3(+14OEEn}?RwNz$t|`s ziSM(ep%r&8@Ux9_+LilqfliOeo>wrZKzLjaGA%^j-mc4v%GJP^Na!9FcI}$siR0s% zc}xjNc?5$dOer6kEQ}OeI2dfsEB7Clc823_l8tL!!$Yv<9{L}m`UFa?T`!Z*Ib2oh+Lk7y23=1d3O6(@x(MDmf+!olDH=j7P?&kD~15&3_*E_AF;?B5#dD-tzlvO z=bN3eA{qG+5Z~u4tWtL|7Fxvh%7j#w53nJm6Uz&B4^~!PSwrHwf2fY{fKxiuCO*-1 z&+O4>7HSE&!@2x&-lwf;mHh8m@KlUM$9-a1CO29I(_{0 zs?(DvsQ9X+j^>dh1rhO{I^U4Dya6G&bxK#E`>)Hr0p`+{8pn zGlvHS?wffB;{LjZ9v?|xhlNd8QQIx1OS{L|q=g=H@r~og@{-kBJ;=(m)w|SzpOOMS z{zpPvTLOC-W^)Tl!tx6IQc&5MMVvL=6pA}LudxKnwIQe8(nJudVt491I=T-J&sJ;2 z@Ij;P&fcpcor(34Lqm<(=c6OS>u7zQ({B_&Z1T(a%$$HOy7dRT9(>#8LhWh zFA#*ulc&2oq6lM1*(xe}OL1sTZ ziDD(C0Av$&=#ILLS4~&K5K}kG(i^w_#&TPso{a1?#Uv)O_mwYq*ei!~ z!WZUOcs&T@$!uKnj&WB)Tuczg2i0;g>~z@zAyeEcnBReAiI4f8=pr$~0BN*Nou{Yv zFfHmEKM}@V3Sl{OH03Ku3TW7Y(OZ|<>Q&x!?`10u=lzr3MYro7l_$gn#e(uoAGOpDhsu~$LZP_kKC2z0& z&PKZRNv4k;-1uSS$*j!-bOERDdfdDGdg=fY%=J+hcp`-k4Vj$WADx8FU;KHD&v3D#op#2N|_rncDRkDIgznt^wl?FcZ4JPm( zS8s+Kgod2)NTVqB@RhH3{j&+)UqxURglL2$#I7rcLpmiaWSH|ju?YQmR{TYZl8pf% zqPfOVK)4m$g{8sl;!$M&uToSL?qVoU+6r^5ftV}-*oZ2(rrb+i@dusgr1UPXSCdJ! zCoViT!L8qqxx#*?FU42yIw%w;96m@$2{xb4LuJ3JFRdKh%5=tczmnzwtQg0C-?Bhe z!_u@W-oN~JlKAHy6+ZYp^RWU6@Y{b5g^Y;-&D~G@)NQ{G-0XG4sw9B~Hp-3IRQpnc za`|^?i8m(OF8tJa2tZ)TKCj#@-*;u8yp_hZSD>8+0DW4>08LrWSwuNRx1n}y&&OXR} zfvN%5J7FWl10@|Qp43EA5QfBL`%-077HuG586k@d)g@uddV?XP6uzZFmVucHbLy@x^uEuZME)y8SCK+0|zY7K27=j|r#|(?7W@Cie zQ3UV^pQh7h%^c=cI!lHJWKii(`sC_1=iuM~`Twd{5NLk+^RfOm!|1OK+eV&jIjaHcX5 zFciT!G}aI4cP8|rsYm67MbO+o>fsg!-En%+%OZJRLBUh^A0NHi3lI6|%~O9G#5EEvlO;>{pSiHtoFLDhd!rvSVx3!MjEdS0j>|IT3t64DXT z|9ty&ZyN{Ht#pCTXl1c?#F+CiL`HropzQODDK86x3JD>%d(Aq_v?6`uV*5Q&)1T=U zIO33KZHM~g`aPTOtSl3J_KO7I=O~}&=9a>&3L+Z@av_uO%o7PDwCo*-yAl}`L$ANY zTSlf52Dva=9?ies2uIr2K6n`!hT;C3GB&@FsBB)kJCzP4ny^r`q>4P73(!)6pUBQq zRznkjrGUxel&$IGSI<*;o%PS&RQ7mBi4K+WJ-nudI-2|RO@80CT_Nzo3fwIJ&uVXi zca?-^IBq^a5JOOrXsb+2Yi;d~!6-B-CZ;U*a{7N*16GnHBs22I!&kBoLIUCBY%>c4 z*)UQUH^w>)^@4*lre!`Vl7ofFTLiCSk!a$eped({lO4Nf2Qb&fpfl?S2|R`eO{{4(w!p}So?f}tMszdb)M1`L|S`z|>r9b;Y@0FrJXg3 z57{%2@6#uXV#J7J@QJ-z>8JV)J=E(2A)DI|U~(+lF9HS&03^VQfv~>4u;7jJ$Ow$> z-MDzAfMb;$>%PN)|0eZ(xP)^^fw`^IY28!znYmc5w1M`U<^0^i=?GxoQm8)wFV5BejKuSC2DX=j5E-CG)`DMY0%+t;rX zuLD#gyMKUBCU)9$aK`vGmqxy}OPTY{lE@Z>TXu+xPcBLAEcM+BB)af(cTT?VIKNhb z+T!$TKp0@z+51CzyL1uSbuiM#2Q7+Ks>GXwma+xd7dME=sBxi7y&`Z32O z-CIhRZ^0Fq-}x-nv3|mu9VG$`fJByh%sYD)Oc5*tVYL-V$s`pWJaSqOOnpzD%lEO_ z{rNBZ=P?|VHVp;G=Zo_Ht+$1E;aNn&ULi(2&rq7nZ#+u?01e3^qyG~m^+OSp9o)oG zup?Gszv*aFz)C`L^2dc2RG;8+6@Umw6$j3Qu<%@Tq;5+$MRtN(NZ>9t_}#OE!Xzl6=T(NI(I@L=R>rk19mnq&G2EM9RyirIpg(^j91ZVhCvp zgKUPUJ#izj*w6rv249N;-KwQJ%4aKf&SRnXI&OQNz|gP(zt=Treht5z@h_9{+mW5V8+RDhD_VK`L8|@=)PgC?VZnl z{uTiHwkOTsAC;|6RuGX*5<4l^bWE0J6UVl^fR=2ix zZgKNAJKTqW?&vgfeM%1B!s~-U<)flM0$&4|kx6fI(iJ*JJrRVU(p~7YSF?EDR&*f^ z)Z_)0fljWAaQi!$9J(Wo1-GQo!DSi)LM7z7S_SnrY=HM3J_Rt$91GWD?nkY1M8#ag z7azSUY-g*fjQ|22KkHjt0e1EUuq1upJcXDiL;tvUHy|~I3=@$QL1e3vh~)-g#6~m4 zy-tYk^Shdo?18D$a%%?ql4p_^n8KBn*j0@jrL!uUn&feBk9uqlcZQWt;NFXcV5pc< zCKZb*w(3LqG1ClLA5ZZy;%TCGx5mHal;3|mFaUmD?x6j^WRl^X#e+(% zAzVa2R@VT}Q1|%9a>$?csrUN+$8V9Xk6wr+=tu)#JpKRgA_m>BTSN*AN=ir#kf4xd zHq}tBN<;Ui$rZ8sKuPUuOM`Br44{2YK{uxKNjP z#S3XwfB%tbH(DWXa1TLtvP5tRJyp-L#W+E0Bu7&(_Ppio7~#h*9d=IF4P5bR-9!qh zDh<*y*K$9xs3V0;|6KG{x(z#bF7;Ml#o39{#nsa`^;*d?$}^6Uc)=Y>{;vflWr@a zlE9P-^^hCV`&C~dhR`Q-^e~$pG)8sWI?_^A(h<2_*_*WT^>c;Z z4gCakZ&sje#F%HzUrErjVG#5XSYdRjmu+`!$}y=KIS7Up2j%%?JBV{_YF?-cCEF z2UFo%BTsbxWtTH`=D$hv=l?c)eiURf+&A`5g@XBx+fDY zj0BLmrjF?++7(0_Mv&UdSmi&Ay8u6VZEj~%;%28xZJL~d=ILPSQk|(&-jI$tRZ-ms z128jc?3y80GDnOy&r~&=;`9u7VhZ=u&3$s4lY9z*CTfS^1f?!WP$}7eJPuhOS`%BQ zb}tA4=B?_$jC^HFn$%K^UbZ#xd9#1gE{#s#{krfbNfsYiAVsX{_eva~umC}JKx^YR z?)_0$^e783l!o~Q3J_m`wV_ywuM+daNKKSmcIh~NQ*1z9IS>F|B_i;?L8K?C{7l%= zHsn3-vznU0xD5=S(pn=h>|${r!@AfJ^uTL;%=49JeX-6|;4<0yW=b}kF3{O#nL}MV zU|Mo~uFD7Gv?CHfRO3i`+1zdJ>hS7k@gLudvOS=42{xInFZ-!|u+i>(e0u)MM#$iJ zkrP#AmH~Z{ALcAMutdi_GVcxQ%Nof_JCz6%px!5mHeBO+>dH&`I$<9DBHUzjF z0tFO!Wn&iiS?DfMb8&ZEyHN0K4K{%T)vx8d7VT7jB>RddMEFUpQribZJ-Pq;M{#&Z6!t@5zLWi~~{ zj?jgfm+5?lP5Qeqe;Bpl&wQpM{dTZRyGICaz^*o%Fk@HQWr2GGjC=uMUi#e4#X6&z zx$iJ4BU8{(X&8dpmGt(vhqx^#69{wNQ06I`|ET%am(ouvXnih|Ur7dIhrlvV8nj-0VhR>m9J~OqS)DvZwW(~LesTl0)X|G$^?xE_9di^kR=O;mLtqn(Fv;z z$N2Lx7bs=ErF>K5Jdy#r<%d;zT~w7?vtk{Tp0>jAH&2)v7Fc0B2kI*u=?$5^>|7{N zSR)`ut`97y2-x~y$biR3odsiqDiKG5t0>6QyQgO`|Fz$>5yK(I{w^%H07%FIEV9%i zema689@!6LVtBD1jtlAQ1(bv%3-uuw0EOyRVE}!8$q%ZGmlT(>18mnXXy4glzkYaz zL=T929M^yy!&9i48M`o2CW+>ob&8$-dG7*+1VAG;!>KW7pQZHzcPNDfZV)QzaC z?1-7w_U2!|%7#Z_!rwTu)?806=Epg^F0a~o;66~BH}0GJ?MlAGjRW&^x#51Z*d43S z?T3y~f%gPv292z0s5n%RqFqld518-XX#5RrWaowIKy;q&W;;p-_kNNjzCZ!*8QaLZ zFO?~;7FaKKL=CD#9;{phH`dlnA~P?Ef%%|{fk!HRcM(|g!iSB7zzCZqyc)=gMS;@% z4^!;+{V|IFrq49)AEz6vTc>rb{xjP-vRT<*MOV7{-$vLggGdV7vuglmZ6XA=&*`*h zsLy*|-LL_G=w&2cdxO(BIW&LX`nfbDcyrj~8N4*FiqN`KDgb|s^)*$T3Lb+gsBfbi zntD7(#p5_xRo5A=Cz9H**x1q9QCz&2{~F>viIAWZkw_Wsp}{}@4?uVC{(@hyA{ato z|FRwdB%2&vRYset&VLEc0fu#^|EHUA|NloGAj2O#AblFejMIXBQqOBYm~k9vH4PJo zhd3M(SA=_oi^7=`vOJ#CY%#i6_hc>l;PHs+q!M4O`YVl?O|#D-gMq9OpDC@^T%j{M zeHe#CrpTV(oi8agt<@&q%_10ixijm7%+wWBem!ygM9`;GB5;@s!bCvjfE z{At$wa?@~gY;{N1U)7V6M_{Lm8#vz!JDL+f1Z+x&96cpO-*=Jf)590%o(S~N9;PP8 zyQCi0%LwtLjoh>S856}5dMrhNX?ZhH?tFI?YE zz~NHdUpvtw6l8saV>oyhck;K(%pcF?f``bSKMUvQn7tSeum55_ugE#f0XI~fCIJbx zH3v)S2=?cUKF_XHTXN>c*&tf*p|LQPp?CIoZr>%TZKMI!!3Mrid7~$}^^zww96zPq zEF%)oBYZLw36+)rLUd8j?vgz4o0eErs>*OxX!IL1sjNJH`KTYMI#GBWXroLP*>9Sp zC@u_m34!4ikd45~N-xaICH0ruifc7hJ%g6XR)61Y0Q?8MP-4%mdpK&LXTq2s74kfq z5+FpwF5fDsT7Lr@Wu$docvW91fg3$3xJ>Rm6`Y~1$j1v_3TYy$=Q+O5#&}{|6nQ5Q zq@|L41QM|8x&U0rA|B`CpS|Q>^DAS(b8BK^!mSvvC)V-)6FZ+5ptckOT6+Q`vj46Y zw;T|zY1P$EZoA!|kPA9cq|DgCm}aF{sFa)xTE~7#-dlu@*R0t+drN)4b$OB+oa`1f z**vN$$wFXs6@NRpRKhHDo!f$A_40=C5E^`hzP0sM}T&dwf zVo4v^05wsFK7CVKK*FVo{>@!hV%^KOp~IG$G?Nn+wp7D62f!o&Qqb<((3`h-H>jnj zkl-(q!fI?zdL$^s$I!$UH99SdgWYvzzX9{@zy?E3M7TAAkd$1|f7LD$;sXPtz#0h~ zTJ83~jYQHX*+@wt{v{+Z#~r3(K_j%)i|dIMrJ-mKonNoJ6IC~{hmn+u$LT_bJtcod z_d@G$6}-9P7mfH8d5jKl>fkQUmRAjZGD?MSyqLVU*oJ%=UNzbQ3AkVeYIcYT2mnF>f34s)&(ZqRj7U6K`4T8k11fKi z=)#Y6L?w*TlR(ELmS4QMo{iXx$xSB$&u1E!|3WdV2b7>i+L2Jayse>|(>j;I8*OEI zXz><21om#gHZ?3gZCr>6Rt~~zdDny%M)mw5a2oH8thN1SBKqn`bR3$;_T`o@VaCCn zua-2Mk@WN?PL}DC1mOee<_^Q$xRYSG6|mA$kw_XPeX5q{ zxc=Xp4@exz`!yA$c~nA5C!lgY#nUD6n?7o+ow^^;u>Mi1o!k6|0EYHnxooKF4Lo_E ztGiz+^MbKun(XD`+*}{ql;Ut#rV)k4hqR}3S$@;}C02(4f(0MUi}F(^rxkt z;WdSQ)6Cjx+?M;(xo@6-Sex5U&(tk>JtnulxBfW33wqqIEs)9ZuSocjGMg{EDe5OG5S;JWv|mz~T7 zW_l`xuMy9`goK-xU&V7uT_#~F4zY6_-UvBjM%8nD{g`baI{NJk|D`;dOnIKweL~;b z_}{<(mf$k4a)~0#nuh*HSPVQPIsL6BP9;pd>lb&$M6*~UhmFhsx`$_mOOi!@WGI9D z3E?outb$bu=ZoLzfq6=t($pyfkZ7@2%qyIk>FWG|=qCGkiJjD;Ny0UqXHVYi^BnWL zE&S~~-N3x4CEB2V8t41~c%5`l;*0i+3omSI9gp9nnTb0iN7uMq!C$-Zm3dj!;KPQe z=h%B=D#KnGMuL7trO*IY-vE|4`zwE=2t;yOJxMOEM>dl5CT=0YfQV9{qo^z4?%ZDC z5ATr7r>jT1xLi}8BM(2-;O&)G^UiTvuug%!dk9_eo2XT;8l;;}trt7ZOieEpwKp8g@3S z|8>qA7o9UYv)*w{|JggK%T^(@x<1p|W()e#u3OWvsqK}+Bc9sI9{i=68sXDBrdG$y z#7Eiwfi*(wZFhHbGA+1rmEaV@29``7;cO_#dJWB7vOD5R_GB3Cd(LwwSW#t21lUb7 zY8nHn0>WD!6X6Hca4inE39H;f!cdw_yD3dOd9{D?%BT#sL{v@TY~kLIM6j5LsAIwY5IC*{HdRih~kzuHK18Pt}S0aOm2M!F@$iT8Hl7q z7dn5K6@1VT94c^I4YuyGv78aRnYt{|Z8aCeR$GA76$7P4BeVh?j}fzuC{-44Idm(n zj+S=$HmOK9lYmwl?R_hC5-v289^^ZSAwrVAlsiVA&Q|LCgpdvUcJwTKoZpBVC*G0a zO8nt97y66N&12y7c^sC2SBP668XVbHI{0~lNGc?VTLx{`Y3NuhI{?~ln)kI4Y+F^2Mc z)%K+M#9WU0R@|qZffJwgOJk&Q=pAq?4%fiubL>qL{m8xS!y~>i+18x}B^+gHq0vtZ zV}1s#?F0=k$gI4(=J?NZ(@XhdyeLMhFNIY2 zYqdpCgZg*%G$N*Ba!~52@HFYaHH$w9%SSO!VCHsy0D3+yZ_UEQ*W+^vHaGvgIS=}= zP|Q&#bg=m3*SIMQ{d9=)yS^)-HeeG8I$uF*6h(%2PUYoyr+*1StkPx?JZ$RjB?gP9 zjrbr{ICby%F(KXs;8DSNUvSWU-`RkdPrZ`n)8neNl6$TB+WD0YmMe;EjzJzGTXzd+ z`Z%?Y95_FyKL}w;>+jl<=OV|`9e5)D`L>XB_*GKrytO^^4&*JRX#4yR4X&2QQOAo5 zN4uY)G2qN;62~SK#S2bp6vY%lrAZ)$A;`T-Kr|EC-hFBOpxZoSVRlpOdl<8AG|9UaU~pHee%=#v(1U6#9o;J$Gu1@`M0^#??fP(Xt;H@9c$F>T=!z;um> zGaC?|KD}xrbwx|jDM~11VB1OpAZC9!Iljh>PSp{i@U}8;bl^g;7iJ_ z#2lb`5jpet<>Sf+wcgz&ha6I`tA>iVpLYl{@3y}ob)?jDAg# z-I4;+p_^372$EelNTE30a#uVUE^-3`h12f}ml&s-5tGJsq!_y)bwayBO{Vg5Jc7`5 zopPrVx4}|GCJh|{06yk5&NB+3LRtShLdy~s%6JcDJU3$N z+Utb(sEIOX_-U8m>*z#^C~SLGYgo&IXr^%fcnW@7!_h7T80RJ+F~L zW+(CdiVYM)U&E11HQd#l4N zU$Kh(b;Abk;G)m3uOYs@-wN`zj?Mw2dbGz`#ng=hNP|!YAmUIJV1^5oGN*MT!LoN1 zhx|t`O_;+2%MSt%-Us~&SsC`*Ry=I@ExT{FoobdvknUOsHdz6c1lqCr3>SJ^M)4&J zIQXi;1`bM5;As7CtotTM0`brAj^n=jJFj2#=Ej-i8_W_HRQZBDH3t@VT7X8O8y1!3 z--XT>Lb`H{dj=}#1a;}dKV_zdmA@Mgse6L<^@(n22FfM){`k=czH+LH^w^Ja(l zHIutSg+PhK?X525cO$Ua*8@Z31Lf042V=I^Ga_TD^!%?d=P6@N!f9VUcBt>49X`8G z>Wyr$93%xZ1R&OWi$!F$f}G(Z*_T^@eaN^P9Y*6ivO;H*WNt++eO>1||D_iZyy|Z6 zF~DJm7Mr$=&&d=GPXxctTRBu`{~LpVmT>W3 zgdEiu8O&MU!MO+SHta1OMxR*ST>WtPYSV2pbuUgbBuVI@N7e-0m00_Y>B3yWo542Rw*=d)yiEJ4h> zus;^WUicRd=Y!9Rh?BP$;bOrmKD7s(3bJhd)(-y?*PWIL*c_hFw&?+pn;7d#ag=q> zn?5mh4r9^V@$cQ~(LE+f$P`SxNB)^?&o-PxZm@C3bj zYPtpJ6F$TR@Wy(ZWstGjBk7?%4DGD^wg5VDo=(1PLT#%I#$9)Z%gqa)nS7RhLG`e^ zxkvm^Y0KxqkEJ)19--!E9b97`2Wxj?4e63k*QGK=?EZ&OQp`BcKsQT@0MT*MSHd9R z|2qO<_l0|qgU0^udu@1-1B05Xg0!30_SHviO?;j-%cbx?$q{U;`U5(lH1U^k%T%Gk znxO~q=@tK(F@eD&k*LRY9O7^AK_@BDbqjU8bMIyna;D*V-JsOg*>ad3Sh*_kr>4JH z(|TYmG~|!8k`87U(@xT)6Iy(yyjAVf{RI{plw|+{qt;Y#TE62=OA7`^zw?q_5V;vCK_)>e&wGWHdf!(wsSLRhAja*;?Vc)LQfe zYK+g)}dIBLx=zwZ8d6&t2Vd3I-j zV@>ty&2zXFQ~@XHe#zte!bt`G{(c6&FKJ_I5!GfWfOiL*>@0H&G!TQG#=iiqS@ykZ zFba}*0F}I2zl4CgXUTp{RE5SP2A!{aV{xB8uX>N75n8E zJ&BRZ^pA+G@)$8z%e<{B9m{rM%pir)-nu(YjSBC2m&?j`|HL~AbWpO-1&;<(LAwdE zFaGqF0{989(d`5|=qc4(dRMA0ad?fpduKeXGs2gSEvmf;7_0HMP`b{^3wi1)cM&8x zo||L|4p|B;NMtF&TUb*Qn`ZdsbsyiSJaQp`F*AhNjh^gJg%4a@&%V^?uix8X2e&XO zX%}|MKeLTSkwDCd6yl}5vZ9p}_-;tvH_6sFv)pdErxJB6ttHX2G&P=#mLdAT%I7ovrgefMwENgDyAT?&VZFEDO z2Vq8SMnb8>{-5D7t9!yrHJm{yDz1;!V|FI`o!cKM{bahNsz?ZYsX-^V{`JH<6*4}k z5&zp0b(Mj$L!BC|87#5#L#d)=;WN4UF%o%3xw27dlpCQ}5>=z(o-^HdGYNF%k9jLT zqFrfAd+>NpzN19wkv_iP+h68&%gdpDt)Ua8&U;2!W5W6+u*Zn$u6>0^53(_@ZOI1K z_-v*|^S@Cs)nyy)cA`oZxF5O{Fw_ZMm-0fekRt^LqQ%DmdZsG$TTsJWYp8S89#Gbe zK$CtMFk^BO{P#d7uZl<-fE6(Z&qA}qYy8|Aa-71wS8VJr+aTMB^T03rFn2`v(_9Gk zmbvr%BxDEdowgg!NT3*b_pf-G_tuZwK9WYwzCL7+omrGx<5_A=bWfUpgs8HXJWzsxLQ|C>`p8*^25UJ&M9;4d0 z^Ze1nSk0H$C2k`;2H(DMeua4XF-3<}W1nPi?elJA-P0az0&p|#b%ov)BCMW(SI$Tt z%ZEbU*YKK)BqkPll;}%mq$|s!~o%D!p~Oaq(@T*o9uxfN#_y#fVY_e32Wrt zZFSK;4cym1RMBSJN$leBR``=?0~!e;+bhncmw$;?v{zdkpD3MKWlYAo6#jj;aq#JE z=-J43tZRP}4M-}{39iOtcZUa2!3cmIV+Je764}Z*&!5Pw36#>L6syVo5N&~u?Lp31 zvggU4p{)=vt$ewuz6KJzMQ=*aQlpUDy~|T`4I7K0-@om?`l3l0@h<_D+%JC{hy)M< zy)Cxw?H81(cwzAci@8s|+~5A|ifp(6c#x4v)qA1X2A191}&$KMlH8spoJXC zzw&i={be^G_54o{K0f$@WC}>AHM%S2+WcYAR8gISNcAa|4EWQlC4f@8%iYO-WfIfA zB|U(C%9k*DT8td?$4pPl`qvs5*&N0RIO4GYzE5p;Bciv?d!h@j|9n?*Z;yZT@Y_>3 zZjn4uL85s8c?}N~A{28gBD`754un=dfQ*6^MA@ir-05LpeWScN8rr&#AZ^M-RG1Zf zE6|}oxq_baTx!^k18H%ytB#53EjpfegbB|jul`_qVi&(o&qHE@NBdGZr>C*9H{(gQ zSMlSd=m$p)C-g%5iyi+_L+e0m(}M+we7nLqLyIt0+3%22bf-?M#l2K^H*E6!ueuQQ zHg0mIbBi-jeq#TX)f#=+GB0`7dMh4O<$VTtxh&p4O4&;B2iRtB0bt%~3k6YRlba(V z3%0D)U=dwgmY;AmtdPiyxxiMf>rK|r!`XGmI;V*xJCl$XQd)?j7Mu(+?fdBr!MokO zM0Nl}t&O7-Tnr&M0&|N*Q+FEQPPtufI;W|JEOv#@Dxg;df9^86E0qcG1*-(|?mV-j zL9lJ?$kmu=qBtl8@DGo^PPpQYd~6Hy-fK&8#qfe3S3eGh4xq&b_2&2|Zy<>h!@dL5 zO?fhx?@g`-?HD5tx6JmiwTGLC zo_do!|Es3)k#6orC#~_~segx6QK_HXH(q=5&$xeS45(kY!*hrLUrZelm>Ce5Tz_y{ zQ~FFoUJic{)OW4+%L(#329Tl|E^;z zT4g+TzHHu)h(TH3=E%!Blf(y`zsMnnW*T7V>C=mhXR(VyXb>up;>q>Ei6AO_z+@*i zZ@;%S#c8$61c^qG5OSyV*;Z&AD}pGBh1Udi{`0>zJ=6eZ}R1_^-pQEwA&}I z=;7fWO6RSKH=gOBA67!F1)YKd55^y;zX%DuJcLY`58zeD-~mn%>bnXKK)hF}P78JY zidYD~b+}vn&{x#{K_K9WecRWfP-?_4rQGBI^Py;bwrff8Z4|=CSuF-;Kk+|i3PIfqtCu}qa1jN9o%yWjyI8o)B2?gU3qf=DjD7T z9>-anJ-dH4@5@?~SM&I^E!vWGIdEzl7GB3UNNiy8|GH%-*!L#vbh-#0r&uL&(;6;GX@fg8IGY zFT$w(t*>`sbw(xy0sdVAMbG@dmb}9!W(g1aUR>YpUB7a9@!I9xUrKO>9tb*PSdBi- ze2zzbX9a|_@3^2{?I^4b@N~_>L3xUCkiAdLs3rXAlgqyQaVyIq?FrGps()`0uX%O=Gb7?~m2YHwBF z*vt2jEUtPIVszR^z#IOn!G?qxH|TA|1#%tH>KRZT9`xQgYEGbI7CU{#jxV9tp39>W zVzYC+IrJ5l%*J^gmq_m#lqAPw2=LYBc=Pq~E@2TH5 zGq*pVInPG2^#yde7+YhFNn#kpMS)#6LwTL}Oxo;bUlz@r zBNm|Akm$`el2P3&&t_VfHqHOaNQ1?8uj!-v^o$giH=F+u1QU-)cJ?{`P_=Ekzq!?vFr1R@_i_Acftv1@XC!t3L1!Bu(M7$h zGSM{73+ZO5Rh=B(3(#RK=e0p)L=0uX;X1JyM3a!9?CQ$6?F~Y6O3|=)p*T$%wwmM} zni3*Z|C>6nk^0{4!3UFFT?3=`Nr#cjt`DwbwOc^&Z{^*QKenL`>$o^w&U=I7r3(@O zyNV0!-qqq)ePP24JM>6jO*RMDGUQ7Bw5)#M6@S;#yqx~gyM^rf;*-?a1%3lkaCnN6 z|BZ(ea*?kinVcftWPYZ=IG*OloNupZAfxKjzHEEs^$v$VzplCFkTVTOq}T{1C_pUhR#~v=Xu(W7+3iYN5H`~L;d=QWn-W@e(XdJL z&`2@?ZRNDT&q-XNd;c5blVauMfV$%}p+g(gDnI_PAWR;xk8xkf>yn?xt)FjbK+1)+=q?0J1Rx7*X&&GuC1>O4K;x-lw!o4|3q`e^ZMKH&Gc%KD@r9rj;qzx2bnUBD<23`|2qnQ z0t^AWn>jGX-hp(onWG3>E^sgGnwdYRy1C=q8(M>q_W(b_CoFLObVtnh=iHyK9`wUK zjj1y8k*krzY8T!~F6OyY$MN|5)*u-eAw~g_4UrjjYjVt$BY|IwYj{}u`O?~@L)8){xa{QtwY3lyBtQO4@~K8YR2%y-wK3Ga`D7ISBbx(*DGLSTDaPrSF_dN9@7c?$Ol|-}`!j*MhfL(aUI2dy7&QTsj zzO|_99ClQwT9O|{O)(!eJYV8wwb;ALY?&mE=9vn}za3c+c}ScGNh&eSw&gm}Dg6%a zI5EXTQj4`#HUt2nfLSeiu=_&pX-=fXoL>EQh(n<@RR58gQp6iCn^_Ht(Zula<__ym zdRvi2r}Ucq!;GOsG=pu*A0P;x{C#h8!diZ_}QFQG+uxqSAu_Q%XifOcc*-ZHiS z+WH9DE@VpKll9MF=cmeVrIJ{JZA3e@l0R=qMMUCyBI&=na>%u-lL2M+d2pY`{D!7= z_Gq@*u{FuZ`@JU`_dSVc8xu zy(zFCycx7RIfwxFu{^LkQKXkBh7Sr}Dwz^;gzU@3aqNVKUKnnM=sIiQo%4T<%({2t zx1yA89;elAdsp=$1EZZVZu534-ZM3U!{c@QfJFQDvP2UCLUj9Tg)_hu8JUmR z30bs!zF|LBiBV3DY#g8(G5?l#&EhMkzk5e7MQ!LPHZrE%`5pn+58(A zm_mubju45GsJYXEYxh&lT53cU1*cO5{Y#pYm&o^U_49EZuk+c@B+KsLIZRH>dfUal zu_go>IvH1KaC0m5;U}Wa5(9?^ajAE)NK?%8*(eDKH3|AuCzFm_NCF=X%wOUGzfan) z0Nbwy<9xsNVr~SMQ~SZsL>vnYL59PKwXzN{I&!9N(n^KSHBq!S8Np~Ufs(=Eh^W2@ zoc?F(66=M42+C%@ee{sV1a5PkiY=`kzZ_pC4I`#=KJ}gNk7reEPf5Vuqc1gW9=l9O zE>~ZC`Js5*{x+Gc3}XM$VgJeVdO_i+AOLjs7v)n*)uOGslop`m_T?#p%^%x8!M%m_ z0C(fi$Ji(}nG_}~JabB&0X&33xClYVU4q*`Z$efD8l&`mjx0XQcYapF@02f;-q#PP zC!aHHkk-*{_-(zt-L0?_{zzg^$YIj5C+9CIPBsp`otwdpSF0QCDO3aX`;xR=I7XfE zUHYH(F`7sCdPB?AJ8{?JwI;0Nx*87~CGoVxC&YR~xwZ>LzF$gRHC&drUo$3TNlQqf z6$rs2aBEExr5Z{HEW$3pAd_AAia7?sO)ElbkwfQN_WGpl~GezHu5cGQ7K3{5OW~sh(4>TgaFrW6M>9XIM`WwUKT5PyU zixXEAqGYLlWo=7x?0VYu@)_Q@z{l*5TFW#U9dmEqZFFiD^B|?dPlXqq?X%Vj1nE6` zH&1)9({^VD*M3S9ki)?tuO=@Qbi^Rt=x4$w7QUlZZiVLmaqOw_m+mi;z{4&n)e1B{ z_SZMg_)JH-`>nS;x3%H?jEHMj!6=9NhE%EPVWL+odOAr(cT! z6p8!Dx}(5*+O+9-?+*35H~_mln{F;p$iP#_jhGCltH5^Ij@sj;#vYcS&b zp)#HI{j^x2T?SEJ9k;`vH&}-W`B5p|Vr5FqbdevOe7$jiv-}WK1Npe!P(?1U@10@` zrsKJ}jbM)KLj3_Q<9~j0t^{~{!Tqm9{LlM{!{wxA*2YhEb(rO3g8vd_uiZ94^1J)G zB1Ci<+et6++?b9@Xkc4(aoc%hmNQ<`AFdR^46elD-;}ep<2LJd{e5YXaosre@6afuGHNzWs;f zc*2C~CL`hob2R6*m3PaYZiYEwx>%v>n#w;Ffjfq2WdV0;b^jZy+SxjF62p`PrtUO4 zy65w!mRQzvKZ{=A*Hq=O`fs3}Fk`t|Rk+*6Y(X+ZvSQoZ4WEDx2krT~W^y~B{rDz> zP1wB8pG<_um{Zgvl}Kc}r$6v@jl;(tGk70ro6hc3${Xtq2m}z6Rn?U2g=vr4QaO<) z&wVR>SY&cyQrCgye<;>G**14{S1~>3-2NA1$h^ZxmC@!;_T}74$IHVE?h9@LYpL7q zZ%xwdy9&6(WR@~MwA!3|y=~YzjV+}d@tM%AC(;m!eNgy7+$W`I{(0SZkM-v-Pxn1g ztc76_eT!Q7DfJUki5a;iF7FccVl#F&@}yO{-$~r@kb82q)_!3}jK@{)P8`AJ%tI5@ zwuJVk=~)nTXGElA7yxth^v8^QP6SE-k!QRQUW_8$0J|fwpP( z2{>5DB^AbWo#%oVk3boTHhOL}=jYMGW8V+;TlL8-AQ_0DSErg+4D(?E00=SJWjNnr zi&@V0=GE@)@6?zXay>;zsf=k)Q#dUN!G;BVhUjy}amRtK@=SR-Zt4vGJA5`#d3Q0y! z3s3ZKglF)HNak6-8C2wSf0!@v`GEi&3Af zcW1sdzm{2^F`|Ei+t-fap+5OhB>@wZ^rd9lk3MpWk=_Ua_^u3qnqsB6)-)IjTQu)9 zv+wmmE&@W9RNwHXD^o({jKpM0;6G5-{&Ty7Vy3$A^(&uzgnjzBR0m7D1;Dfk$;vUo zg(u}SIgz(zAqRK>g+_IjK{T%O)x60gN(xvj$H7o-tt8JS&Om0`^RE{m;Q!5D9s7S6 zgb+-mzT?Su)1CW3hJ+`aCt`R0;N0x|-uc6GD=3d?S~*+HGdz?<(nFcr^H|L_L!*;h zq_I@x-K%%T2lA5lYRPVV**APkTU(m6AvMmEcISU1*tSP@mq@3U`{n=EK`9x)Bnrbe z^YFoEYT!w8gOEz`*L5`hH0P}tsPfn)F!_$%bZ1@k%;bsEuvkf&^lEWSyj(<>csV%; z*e6CiHY`jbn!JjC{v9d-uox*og?YFgsRF+aW-Bv#u%G8pLGg_eH(lsI{@`=Eq}%$| zU1deOYx`M(fp+&^H}R}*4q=f92|C3OcjFE=-!Ol{BImVpV358F zST-zf*{3~k{K|EFmx-ts^Lf!0RNGH@0O7T-Zdc|#&kz2Rg_YVKXR-!h*YXHh$8*0S zDG0M?dGNvds@obIX8|xUp;9=8p9R1VM&R?~xo8Yvsl4A*Z`S>CiKXkX(~F(#U)adA zlJu1(`(|0AXY#W4KU*8x`pkugrpICopA`S+KrglvSg6H;Wi1E@U_Bcqk-d68qBO7G zp%m1s+2Gx^trlDFHhKl0N*pg_G?Z+N={Db=nNCyIa-Hvnqj+}cz-4f%S5qsu3)^0> zhwFF%Y+?33*_^xy{fqdV*OHRDviK5dZelrOtj07Dn|n)QBw<)chnDWAcx$oh8NGQ|KX&_Yff^njta{s>o9#$l{mz^r#0HmGJSp^)cKxoL}%(TJgGvs z1GwT;Gy6a21W7{=oVty$bZ}H}hVG-;uZI`2Rd6^6uELFkc^9!Qr57*W@ypRMb?4l0 z6Hf{=ToMn;jt1q>c)i&B3}GABEM2R7GNwwGm&f8p72%Q0pp6*F>HY}SPhUGeV_7x{ z$T7lAT&`$v>=TgLrd*1aP`ECCIuzbiIm+AEP41DB_|GCz-_Vhnz36rT&#qzg>iYx^ z95K0-1-G-!!;(22Zxz;Lb;evn3sJQbWxqi;qTNo;!#X}Hwk4UC`!5`_!pg87^;*MGV2UfzQ=&Ls{;ZTev z@h7De^E(}VQ$LT>=cim|kJ~T18lXRgwCa9FV3G9IB7n9GPm`~-d=&EK%iywkDz&s| z!52D$Cmloy&6@LRQio)pPj1n#gbk+r5IxlV%CbnYr2Vt=newCpqp~()H>oame$$6N zk5<(?&MpjuFPizTE$A-!B3beP?_$o4IVG5EP zeV-jyNza4gHHEpk9d)5s0~uz~ePNx#`yutWl{eF25sfBf`$JxIAL*Z9;xoc4XYl2> z!YQ+~b_*lCd{kq&-hYa}Buk=@+-9@!j}0GC-==Bn)_hv*J36UqKZXAI7YFaf-72)` zIK5S6Rz4P^iLw?YCMCzu-~;F{g*LU{g{_m^Z)9tK5dm1V2oQ@wmqxz%O7z2mQ+|K? zLBA}2+U31lT*?N5*+@J?a|9o>Mlb{fh&VL4IH4J0kQv{8m5agcioqdx{f6MlC<+E+ z&LUHRAuGJeH}@~+*G4a+_Yo;n?L5+}wl|+f*0K_8b(KQNR2k!6X0=5g&tNC71o9#5 zS&a#XrB(*dkFzy4UX_?jmxj~{;oAe}mzC)0r;n&UMIt)B%KiGRN{oY{P z_=;`nH{zXzBlFjdcDVVQNlL}aHOh~~$-p9_hYG{SfXtq@z%JMg^naZXV7Nxr!mFZT z@j2ODid=Hx=vNPMI31?{%bh3AN0DBipQ6m)Rqe@#Fy!Bt7uncs0R4!qFmQoixY`;h9-S0{a-sS5 z!*gav($`>cin)v&7#Q7>tfyW+nzj3Rv{05I?P&>=>orTk>?<5|bHS>3pC06hTPo;9 zO`(mYa6A6A?H74id5+$sQgMe4gBEc9O2srb!mST=#>z47Z79H!%jv;2zN1r(va)%& zd6rMseHN0EBPt!WX(nx{YFyVw)!;O#x^r~u^rQ3Ef66gKR{Jj{F&%292Qxn2JHwYY)1HaK(2 z7b8+={R8RBq8Pws#>fzvfs1)KhscV55tEy~7QCvJEtd>1+TRnHl6O|9-rxv6Ij2k= z5>r-uktOL!yh!v(zUjB@Laq`}n@R#kDxuBMjZZN&AcUZ^reixRuh-#gv6>BAP@SF> z4yQSWt6vj^7X7fY3`j5t`c7A_mzpKx=D_a#ON`;urUWmHphOhj5`Se>p{{RLjJCVw zD;&&dMP1hprts6NkZ|Q2F0adtm)bb>+7kyd|8l%Rd^f@an3i%v46bwq@}O(;J~Fm7W%|s4{nz^o2 z)X5fb4sEm;QeTbSoXin@RB7jp>i5?Ag4-i9GZu7(9lCKDu_$t2HR*XPih?E^FXq_# z1LP|bkQw96y)LGB>w0nHj{=c%P5)GlX^u;Gj^oZFqnX4H8*B1wlZvdA{aQ`p_x0Rk zt*7Y7u;ZVEtbe$iT(zGHHm+soHqX98>I0@y)0Bw*OndBW+N)-R3?84<4n&b|&GoMd zc!dnhBwmJyNFD8r_n|SDPVn30b-EWB?+uf9n>Vx3*ralN{2@zs8p$IHZY!kTmUZPZ z&02?u={gQ?$aTw0yz4oMNFsDS?BX0BC7c&=y{jQxy7kFYR}I}V$E5%$h^t?4d)W0e zc)ben$0Vlyl992D;wWuenl>Gf;I4%maqIqQ0un{cM~g;bi|!KHW3kr zH&0E_31OPcIq=D>Qt9%9w1n|(vdVv3{0=`_h%-csB@3P%jj`C|e)=T@;}n4z6%&4pjx=HV5N_|FzOIGBm5byaTdG@Hvov7s%(@V8 zVnqDXR^*SuAB*B@h3qpNa0rLMxRbFB=HCyh<*$u`EwgQ+g_8lT3Z zsiFYID0bxipZV?2fBiieio_{;c(TZ@)IG=jIcw-rjIygv$Hxa=4PnKZ?$m6ozgfty zynua8cy?0!hyN~d&&4o@+*LWG#RZ(jIJboMRX8pc7&3;cJ9_nMn96@N$KYcA_$Sbc?~^-V5m*?dSvqUv-7T zl6FrSS%~r0*J=9jtr`DW&5_T6r-!c%HlD`z$F7WKq_$MS|J>?!6^QH%7p90}KWXm> zp>PTi5)SgH+L0Y%*JXovW&Y=u3KxzXpp%cExVc~VXi4aCvL&-hOmdiv+FLK8dNSn6 zT;V~3ROF{<+^z*@5!9g0)kwEuNRtv=J80S%s7F34IUvz)s16pp-TQaPzx({wI?n?7?*FQi4!hSZt^ABE2{8oOm8 zHteneKMd8)FA0rOSEo#nP|Luc|K3l+pL6v9TZYGCsq8xfr1EFW=I{Z*r4}F(lX&n= zKEPFmNX-qyZ*P-nr&*lx=CS}|a*+K@dL1%ej9B?i5A(o zV`*A#QIn>J6_RvkWE-ZwSZM=E;-ESE6T|1mTh-oCX3>dzCCw$)DaSE7SA5FkPMs|= ze`!9mCT2YJ9wU}GK;~P$_*GgPrK^RD)W)R5C0F?o$eqLyXWTya{zy$U>b(&zz{C4& zelgXClld7^CTSsJ3IQ@Cjb{uUX5v#>j;A+L2ES8?%v$>2o<1;3NpE?0^n%{`D5B zR@@2kW|JEBC=goTd@%Cb|JI$b@?kT>eFxtXBcp#I_~I>k7`V=vh--0a4Y*TF1>$UP z?QOudq=35tXZ9W|bXtZ*zGObEfUex7E)ECLJVJPp4-0#=`f8s%oBAtjBcs8(lFbpE zGEdF!8@9H-V2dZZUV|IB^LM*q;~^4`$y1#*M#60DcuN9r$|0buhGbLP-)h?R$S%iqt9a zduJS1`|D}{Uh41VeN|_%IcowC z<5%uK&&&kjiBGN~*=97!#L!LBa$o+B56V`#iEK+FH);8yogX8k6}GbdqB8xL3XkznyWZ zYO*RB>g&7@f;bpi^)wVaj&bp7ccb2USA*!Ax-(%YpkQ5jpN97R#WyVbI4HVc@0Sv2 zWQDu=ONC&tVW(%S#Y5o>FBlT7o3=Lp)jHkH1e5DhLzhLKXb_7g2SMp zJHG^_)yk=m_rQyX>%^1b=HVq*d*mYm=^2&wJ)l~TWPdmH( z3c!dy0_a<@r?M5N+Oc)C~5nZMuV>p)B6-PYL2y7ZJx3e z#e`_lW8)T>e8{ZL4GuGVgdVRgE_Zclff1ZVEy(7nd_Ppj@A!>JdVuEgFT=X(e3Gb7 zsVbUxBut4#at`H*FTW1lw}Mr4rW{>(;O?uQI+%F~x^tP!XAOKh_!a(w%K22SP>C#r zvEK9l0z`fe6_r1eIuAYyyL=_$Z-l0)xc`i>+%1-UFk31>k^wA!`kN_Vlk_8JxVC!G zr!OKBh^M{tx(640DQEJJM+J>Z{*K_Zc)t}B@~~O{a-a5(E8$)}VqCog?5zDklpMjT zPW`t_$N%|fahyGKQ4zZnf@l7hcmCj5@P$7LnWVJvHauJpy|j7atNNDg3luDMma+RK zWw^19M~-jKi0ACvBl1Ir2ZSWzCGp@zS2R0|NkC>y5Q-#OOH>t!1NkU?oH6Lz%FfvO zx`Qmyr*>+V{HedbW2oMSWI*N=tKZC94SWLdaEq;K_?yYEmzQ&$A}Yvh$7qP4(>`%G zEqeKv?8@qzp>u9!_(sNg6?DSfpiZ8nd(6ku?v<7;lc(Iuxo;FC(C z9WvEWLP-F+vPrIO{;^>+ZHh>~teNpX*XtENXi$qHWn`QEU@0Czb32KBQtDsCY3_*? zafKuKgzwaIi^AH9;ngo&tc@|pl{#Hy%6PYyuUfXH`-|6|K!rw|YCbI;70&+E8FG2K z^lVZLTHw{Cl$N7HTnq^X>cog?Khz3}9pRbZ6B=AfF^V>FB$s~M9*S5Mnks6Rq6gvk zpS zRE|8T^;zQKXj+a|k86ZpvignUb)KSAraM$&>26{5fl^d&5W&>*u;FToVP(+50U}0I zulv8jx^IdZ)}0b_a0llTF^3)ulKIRXs`QbyO1!GS{(>)eLmNpXF(m-0LWpdEC_sVm+A&moEFI!2YvuIXAdZ&^ zy?j{^eY3-DPKqu>&j}iWz-0&kv>Q0(=ltINsSve*`%;7+KVy6fVeq)=>wDi`6bXo7 znjmeH>X^Bd*7|}MFvhNajIy)Q=py*9qJSxtJh$spsXaep zQBqu}y>acVzLYwecj=JuVWl$$c~W_gM+wbD#sWU`@894K6H|mq4qKts?ls(3FW&OJ zC$U~?bfxX7wl|W~QYLMG+x}KMJLHddkU%a&>}hGk&~5G#CBxW`pyOXw(m0j` zWPPKfVZ1ejOP|K=pG@|WPxcn?nn$mF%!V%>#?wv>q^mQ66hj7d=(=7r8PfbT@FK&) z_4=DFd3y<*!yc2bFh^_Ow;|heq4*Ut7`&J_7m~PY4O2 zxCqKT(XUYBXsjv+lf zQi=&arxttwlXX82z);se1-aBSb7pZnG+4@G=3As_(>n@k)|Fo3a7cX-yuW{!Zxb+VlZU zoye#*pnssO!2WG^u@w=g^qH5`Qy7C>I4mL>6sIHU_0%C{A3zG+tu7j+;v)du5Bh+5 zC~SK(S{`#M)K-kZbpQBtt(~94hXT88;4_7;X^(sib^} zm|~G2fxPUySYOhQ)1#l(jKZ*w@7eTMa$CaoyCWqlmU07%5ssEC+n=ELihNMh`4+)E ztgk@c0`O7oHl~V)e<%p)83%18zk&N_k2KtD^=!Q-{Oxra&VLROxZ>I% z8)~UzHdKywC?DW7mH(rLGPN;JEXrJIfN|HD>6Rc2^05=YAA8+ zfP;lOX7z6?Gw~N8l0uB#;G%#RPLCa5k9(k*>-FR<#QNo4;4DuF482WC|3~JkL@C~1{>(|UsljBP$8t;lg!oV3 z8(Z$Ek^j!E!qcaI8ZZaVhU8_E#hh{+T8XEGVxs+;JWUrkA-qbki)7(upI>Wj%vaaD z6C`=yrS;@f`3fB8t>-Gf4SMr` z$`P)5u>JnZ?X%N|#{u3)yRsT($I%)E!?jYK?JnGLEZRH_^mwgQf0$TuVvzNC-6aoY z`YW&R3GU<#3*%#dJ-(TRCPH9IYcPN2)D$ED3=0gtzMcyCiS8S*RKkx*MINezU~KhS zrVz{SWI|V>J=<)mYr=4An_FbP98wsDs0T82^4krf{!$w^^P9sEhnAI2!iQ?xy`TKY zKlC#b0a}~c!I`m6_0DgHWT)Deomkour-DKO!nJ-+QIVjgM$-g@;@(Bspv>;w+Ig}o z3!?iPw$GPJq6s5%K+)+ql=DIx!np8a0}PIdqlx|M)@d6xo)%oyhlG3?UcTLZRzGGS`b}G$IfPl!KsX}sMF_EMv!WgI>{u_dvE>q?zlyz z-g6mFu>foXPaL02dOuUA8@|C*9b*3cHuw>mfBz0i3_ax)M~m3&_hQ=J$46R_<{en` zeoE+g;GuB}qRlDHr?$xM?frYmg{&Jf>Ww~f1G04M%Lf_NK`T1`WUqjrHJ9v8x-n?kpj(h({!1T?QDqN%%K4o-&`!iEP;rnhG!@-rzAK7Z4 z{tvUPcn@Cu&g``xcX9a(!cG$oW#~dztWG=+-u>RQ_ELwwYPIY5YP~x2IOaye zZzwtm9M(o9m6YYQYBO1B(H-8O3 zoi+9O@-v}^dXee9%dG$p6(lb3I7oD^=}E8i)`Zv82zJXkWbK|@&p(by4ZhJX*r)jvge37H=f z@dV{nhL~)4hJUn>DWCoAX9~)mkacYZN(iQ!No3JV36^6pH8QyiGcFr8dvgn8*LDuJ z_7BTdnmg|+XfIY+v6-DrE@sdM9}EDyW`hzW_|33H?~{bLCeIwodpi1sO;EFECw_Uc zcP%|^Z&0qI{7_-@a@#?;Tn_)>2{CX!wUB=|^Sy0=ptpA8ht^HAv8wkIc@JpHLbph| zdSucUCx={~9zBrLZIV1&d;StD5Zr)=r9t`dfUkOA!cG#Mu3A*2D|ly`;(C4i#Q$@y zW6V^}!PYq{FI4aBVn;{RTl_dJzFvh2aM;eH>+M8CG5r8Mw$7`8i{36WjL9lQto~aY zYvZFNATuM-C@-h{JadKWS^3JFyS+?l0#kBdFjg?g;Yi-o`a|d+?7!T~4XJz&8LC$H zdC&Vu;>Tq*j(Ii_z)v9Xs*9THtm+3KM{yRBWwrOI_V~;w@_~#$OQ~F^C`$X}GqcLK zt^Hr$BugLlyNjO4iiVX$Skl!`sYOJ;xGc6TK-*!{{=NtaJd0Dbn7e{3c(<2C)I4lD z9g_Bf119UsN!n!G*c(qY4=45iSnl-^mNb+t-L+<2Il4So-cmqE-p-I0H2&tMZ%Mas zSiOAE_r~HuiQAhTlQ4ygBd)LMmTQ+m#qLM7O#X}JwzU|K32llY&7M4-Et-Hw?H%Tc z83)5CS`C-=4di zKmSih!t31W+y)K|H9R*R`u>zBvHpw0M((8Y^*4ikVKUb{@*eZ6itW_Madre0@#O1Nt>g9X{H%ui$qIK9mQ)Ub%Cz1A$@c)M z`qMvihz!>HY{@c$p2lTJ3h5mEZr#7LQv3kH^;A`XhI$`MGD`UQA;ORCQVb#^C)Ocp z0Q++1vCyqeR5cQ?3GZ*T2@+|G+A;;N^c#(~+=y)7mdVJ?%&-2b!jPmdPKwr%JMO*; zdB6D$=RAKy+pz56>T}WQN5PHM>({ISBMi;hLm(y|KM8xOsKLMAqkN+~(l^<^wXh?q zaRLYdY4%^uzMJL{%=vg3jgBPpg-M1M7FVwI+2zig_I-snlY$(rIfdrYj-725RsBK& zGlxAZbB5-O0l{!5VzPn^;S?8Qa8xUBqzJ$YM0^QWA|OrTvTKkzuEf(<6mK7$j0dtt zAhbl{|2uauVF>2T8&8j&G*P< zvA)%)gMumcm=MkBIh7B?nwx=7yG6-C1My5*ymPnAv$s3;zYb3sIlAbY-+lP}A-21C z^UE*X(s|E_s?@%-(wt*)QTgdeZ(llcw@Qq<1LO8!bJQ=fQk3m=nG_e7;um;B6R;)< zn5FYGsZN}Fd?DR1!+IcVX1=kX6vVti@H$Q)w4Xl~V5&IF7TMSdKEB|rAaA<}Xk(a| z8@6B4bqwMRP$D!@g0k`?`{C$2SEAwTfNFg!dW5iwNh2=Uf&eVot$s?0U~KAsTL=n# zsbQz8Mhwoa-3@=5DMvX4UW9GROQ`?EJ9LiLOqJz3B@FdO;9H_)(U?|6MDL+L=Bqgf zY8_CL*dCztBnz$}5V9j0Fq*i=SzR?atJ8>8_G_r&M5)Ncc(J&E5po6#S zvtUX&MMz=hH3i?vvt4+~`nA>EScd{1IupY%89y`y;j@C@KE$tU=a*u;+^Z%vwzK3n z8&F8YDy8jF_sXqF$LH6|g!}+22AiE*5gAea5N=y7iAi5PG~%G@_c}D3q!NS&wZ1K9I)(QPCn@6 z2VzD?q8rDVPi_Dr5Vyzz49>XF-)J5gBmX5i{nWy_93^&v8G?Vv;KN~YYM`-Q_2(ee z>}S-a>$Tp`n~O*JrpUCEW`W>ND*P?i%g|~Tm^@c}VljK7U+v$*zacOz3BDG1KA5l$ z4a_6NG7X9V;YtY5&BCO>cS$Ty-_0$>pZlFO0wll|7PK28AB_vrhO(79__c(yUS1~S z|ID~ERbdm~ZyGmey(IlK*y8!T@ZRFWbYU>Ge-UW$P{$GW3Qgf~!Jb`;i%x2WGPMct zEOe)V$U1- z!C(m}0qt&EzUm88S2;0MwK0mKSBwJd|KRoj35w8DWXlxRa<%*BO;0K){5-Iib&nkAQf6-HcSQv7?LJinG_X z63)0Vd_LC%*eIWHUFF45A91<#*g9w-^J#|iax^|mf4g4t3pv07229q$!PYc6rW&?m z3_iQOmmtER)Bev`;r7GG@$%e|NBt24@&aqWgEH}&*Mk4GNI(i%+9&_xX!lA8Kh=S$ z6G^!$$jzdxT$?iz8Q!pW>vpM; zMx!flIr(0#i)q%M(%wMy(ttNRKZTDs@GvAfvpXFZtw+&!$X&-LF;Dzj9c^Ij%D5N$ zr}Z1!B**#AnvvS5Mz-E`Y>^A+Xy$#c&uyM##PKV}6ubKQq3d_8WjnlbPN6ioPM5#D zs20u1dA%fblab5Om!sk@Jx5KMyA|!9uC2yhBAyswEA(@s}wVTKcnWijzfZhmv zX{u=z4E=;8fug&YrZ&G)T{rPqjd9!mPA?o6vI=jU`0YBvP3Gsc%K7z^DCn$UO0-`= z4}Szzey{P(`EryPsePgtL+d6wFXuoy+;2*JYWP}LaX(oI>G1m(@rG>(E>J7zhLZkt z;B|1I1v|h{Olo*|SC#9BZkQ4c66JqvM zPNN0&LH@Npbj(<;OQ#PE)~o?72AAkQDxf@Ml}~H7T(r`)Y=ca$`|O)(NE#l1r7F{} zG`yJaB!JYMLt#3EDHBV@CX)JK9ZdZ|2>?RUO^HV4vGzbCXm*kw-uD9qs!RfY0?;)#f6Vv~Ooj>@m zs|!wVFhc?Y`EN#UR#Ejaho92%;bbW>(o7tJH;hDZwaqu$<4srmXL7_6s=OnIHcsY7 z5h(PlFmb4VDD_(ohH*3*S86!;jKrRfU%B0OEHQ4}W;^;I^=)XuE$B}<#yggSR%zck z?0L?M>iaIpXwJ`H4XQu9bLO;n=}{*q-s7&vEEDHUiL{y2RX(ys@jvTKEm+I$ zjqy@p?!kK`-DNtST)w0&dyJo{m~nnkfCMq@8TQ2G>A&yUBj!Lv<2Tiwr`pIL%6mRE z9zS0%NY^Va&_zPi!gqz*0zb`2o$OrY8I{<&zTlYq;erffBAmen53qQw0`rxr(;!=9 zDBRif`gVe@d|}b(a&8h7DM>bNf)x0r{9`)Fx|V&j6Y&~_!FAobeubz0o%aQnf`Id7j~feoXXjTFBi}Z(?vLLM?oc+p3D0y8iCU;SnIg4gU4G5r6sjZhbg_ z@uN9h2#~QJsteaeuG0Fc z?y60V^dp?;CztGK<-e$$_A+@4c8-ZH%|(Vz-tG}lMaoFY=p!$NXFwHc^9#3f|9}Gk z3ucQ3r*90dtUM?RqV+OreF*u(OY<__biYJb!GTcFaM&?TIB874BRI;2d?ySAuD$Oq z;zD8|Sess5@c$9@7En=r-}~^H85laHyHr#JB&1;w6r>fUQ$i4>JBLYPIc=q1U=C^ds@f=AFP`O3%V?xOY+;}6R z(X@PxCKdsU0Em4``~%)dzu8!B7}@n4src>xS;*sAogW$B@y6#zQ!$Ta{WsaxC5I!p z@j{iE&Y9i8*Dc{l2b#ejC3Sz_nY?_|nl^f>$%ya$S$v)lU{PB9hq4nyAdAu&D@*o* zoG=L!!IoGTPf$2D=qgkgEiZER=-|7(7*Cz!2(r=a8t-G87^0*{p@Rs_KRqwnCH2|^Q^`JTt*TY+&i$etpK=xwSK-C zk^f*(M@#(R{*Q>;KRQXW%_$T~ir;Wj^au?+%B+a0(MUZP zOk=hRI7FC395qsx_8sBJ4tCblKMEYCkVHjWJ1L0aY0UlCKw;dc1G;8cj=>q;*594H zb+$G37rg=>xAwBtKU5xjA$s*%y)HWm^^HPX z)qUnhU=KZF1m(pW!P)@Bul^;2(9nsqe7W}ppY3BHOOK~{vLkYDxXV*#k-76{%nhoy z4-%#!mxn4A0ajLw7Jgbhr&l!)E_n=~@OF;?q5zMSbPkB**P=_g(HNdayBW4+?@_st)d8Gqxf zN`IXIGPXH8wd~BUK^@giNy%2fuuz;bSBjfB}+0D;`M0CJ;*a3X+qPaUS ztBeFE{k?-$u_=Fcwa5=q#o{3p-i(^8@$~lgbs{QlITV@eP36I2tXA}y&ncnw4zWW! z4cbm>)Ky^i;cRj7G2s`U=L>mar`o8T(Pr(#{U3FqWd&KOFIpS;uMoC2*}gCFPpBjpmB}6#nleWK7A!?E1soz2D`<4x8)_$jfxqo<;}o=X$T6 zrv_QThRruMwMjdYxl?Tf7xi^uSkGgybN|>p(WG2gxLZyXtYSnVGpZRS z*$dps{$ZEfZGziCzU5u0-&7t`ogbgV9L zP;C3J6u{kah1v(HWx#$6-){&yjV+}X>}D%i_ZHI|!<)QCq*HRP-$;o)NX|CzFURHZ z&%$y^*MF|ZV)v8(Vkb|uAJb^|Nq6j#E6?~40wewfGKH}>vOW)>7r^iAmV~XT?p9}KkSHN0Cwo7$Kz_`|ADm>S`H@yd=W&>=v=LDz^ck4xoS6gS#iXmr1Jw? zVZ?6&r%UCny1Qq_A4Z~6%6I7iE)`3=SOouRhd=(eKo+IDBjosJ%}4-&I62}4PodkV zSiLdd*O}jiSUQ|tZ07)COdpwe4ikKw-n)LZ(nN`&03jeJVRTHf?x^mavIJN(U?K-v z{y@0du)zmrw{bE^i??QZ@k;F?skaxTReYBsL%PsOaV;+kKVp@#Y4 zJ894`F@mYY_8S2FfJ;8(f}gOi5yyE>1q;RsoV(M+c4knq<&{P43ip%-cpfs(85hwg z1WDs(+UY(DSJ`ixq?cc#<3q)Y11tlF_Eta$ClUY?4qA-A0{J9$Vi1d|j8ld7(D3Fx z&?V^B{FSIKp-ZbS;1fHa%CCTNo|oDv*FG!JQ}N!+9_d9>Tt(2t3mcjEz~(sk#oq-D z`pTEB`IXEY4x?7y=J^kdScZ zHjXBo&20Bmt+H~D@p_k4uwl|mwam-UB6GZ3Np=4HMp`h!e_mS(SJA-} z?~GAoB30Vkp5m%HH7xC16#kKO~Z~M4l_Zm3^lQCTI561*|NUdInne_LMUbhG%(3$WR z!DneR!1w{YFD>Zrcl?U+kg$ZQcc9gx-vuz^dbh9k7ln#G96CqQne>+SEEd7mysx~1 zz<&HW^`KuYrM?V{#KKvKC|wQ2Np3G|=e40+4^7R3tBO%cEW&~;62sAN&da3CceOj5 zPfdtM@2rvoykcn>L2+u(&LAEI7E>v{A36bsj(?{|HYnTyJ-}r;JK~l2=jd&oJ^x>h z+1p;z?U~4U_gsPe+pL=7DiVV!iYS_mTg*G(|B?;zk~~n&HqY4VjT50p;!DLB^V2Q` z4eP33K~?9dWoEr^MPVmf&xc|pwt6a;wx1i_;04K9fkz&ej8pM`3?~0@pmRE6XVK>e z)4U4X2|QO8Du~Ef?F*py)8|`afS>AoXmBES|MQFRpwarS`gI-92vyTUHT)yii<4Nh zoH{GS-h#n6KCAJ;Ex?uVxFL{EYLeIhg`$l2x_#$GWE17w=q+j%fWsS7IU{40ZSM0H zS8mTUtzPG`Mq@uDQboEB8%0|2C&!gG4H77~!MqN}@R9-ej z%gIMHEn)d1-<2+_Byp0+n1*WT0m81(J%BlN0sGAZ;KR%E(#@(3?c=(&nX}mx^lc}NTi>4* zWBs6jYNhl&Tk@Ou;AJlffHPryZJE^GLx3G zpt2lBut!%ZoVn88o!34pPf_G?#9GX;G?SnJleAg34vJq3)7Cxn&;mP~7f;VSho0Np zcalX|MSgYK(v>7ufN z_N8%?MBPSC$SiXRK*%$Qozq^GdF{f7qBgrA4G%Fq7a94VH~syW=lYI!e%}Evi}Svc ziHPp)mdXnM2qTU4Bm^fyoD4cs8-)x28%uWoZ77wnTnI5NlzK_oyg8t*MOpP_Yd<)E z*esqLQAwH3yu8RaxVWo#zKDOxom)xL*(Gi)!p`iU>s2;yWz;?Y(u`9YEKQ?5_U#*C z^rI|Tf8+h&J8yYfOvm1c;e0gYmVys;Fsx4EeyGg|XkTqO-sB=Ag(>onIF9yjf2GT# zpebR{-2Jg{SzHnmje+8fD>5VRCVBeSpjRp}p^}({i5BDu09gi7EO}cS!R11NFjfoS zEZX-q3s`baQuTvLOW^yw=uMA|5SGTREL7 zxXd%O?2ce}GLx5>+kX_;KJj>d<31&*y#SDa?$>W8W6a;Cxm*w{DF}IM!wUIh1l0;un-PFkfuXFY0n3%wKU2POV zVJ2=ekjv4KLL>B@RqD}{dQ`ym-6YEM?5ub}BXp;LiB|ItyZwVkI2F!2&z2rWyJWpf4Ok7rHFT<5{#LswJ#!H z7lilvk(Wg`Ex%Ly4XXGp7QT`kzk723#l0I3?S7=VXZLx#Uao$W6J%!C3ro}|cG97{ zjbfuVXniCGnDxHJV(!|Jod14(8m`-cL(uYA#?wD(MJg!C`uf2_AGTlTrWe zUjXnxY)wuY7h3Bv2{STA_d9J5xvsq~K zNnXLJl(Bu>gdo99UM@2e)Z2uy7Ahs(jtc19VA4|m%+fa8Low9#p}8|-Iq2_Vw*KoB z1-K?SsMx9Snza{R;A@8)$bfW}_5d(RDN9AVI=K z%!i{ZIgmRkzJ*s>2Fd?GCL}wUj(P&Y?flF-b$EQiqs2__0|MBwFz7&q^mL8|_i9#d z_719hU-B<4I|09U56kEwnu$qu=Q+fsom`Kcrv`Z8%n)mtKSacls{bd5j`5dQ zr#oBaf)b>H1`zSP_ly7X1Xo54T(EJVLUKKhFe>@zb^`=_0{BiP zI45!8a@n1p2um)LXVQz8-@ZrDTBC)X&8WJhXGW{zkC~}37>k4C6}8p}RteN!J)P%K9O z)OhrKB26TSxi4jFy!e>Rhw9dC+yb=U0B^Sq=raK5oFlMLXT?LgEV1G)%>P92I+tJh zW5{LI8d~@%E@~Qu+$fs$I$lUIC!tMq9m<%T~b?b1A!k7roJ)IGt0ps$dR>J z6d=S<^Ys%$?o~4ce%V9m=h4;!PygNh)%5Ec1KrqkaW0SC!D~d)U5+ZzL(^-^9Nmps zN26Yu+ov)L{#+H~bC)aaV(P`siamz^o{U(Px@q0NFTU2fI!oix127yi$pkY(v|O76 z1lC^+(YM7orfSeX8@R#!Gea*WX+7E0#({HO&x9$}a z&?eu`eUUL_VLBb4@Hf3Q@HAlMLdq?*zSlsfcI==2+DuaiV@AQ&v!41OTZDx6VKSr8 zk8Lni?XjuAbE#ubPSefPx-u^^ebI^Dy9PbuLNJw%0o8fdKV2J2;v5bfv*nFRME&l* zVOG%7@V!O5{<~e_zXBnsv+;T-yAF7)D5lMJx~75%{3r!sdo_n1!_Dmj6cjj-FI|(h z7eS}9qWe4VM2qC7Y%-0TVzfrX?7SLK*#oXaSr*;sn4S6_q6dUi^N9EH<}DI3O=7pj z3aADfIzAF`?!Pwn6_tDcInF%8z&qUHu6A^W;XuKfcVpQhIe$Q+OM9>;b>5u-Qjq|Ro!qAO`2`sB8E6TN45SZ}$n&w? zY-=(GAeGcCuXp^FWgP#^+_EA6B&VCM+!DD`h~EW2&yS~@0g<M zZv8wqb~wGR28Cn3$3}!X+UQa6W*$2hL6p$>UX6_)^ZcG2tiea?{tBWXv zrFgnxHrbSOs<=5vJS8yjfhT;}LoZ^!;{zc^KF}pnAeol9{skGeTC42Usc%GUx2a_g z_Pc~l+=yf|zD2eV9_s6hVh|#rF>*9YXbds5U(MT)fVbrgiF~blkzS_iabUFaUBl`G zui1;+^fQh}tyP{>u4S%VYnQc0t7f++z1+8-O6EfRAB8u0VZT?jP&O*qR4=4B?VSrc z{y>9+B?4h?D_CTuNzjv;{nSa;ZK}N_w6lKjuR@cnOuzzC7DA80GNZf&cb^p-U83wd zwOm5#r zt-?sM!=2!@3Uxu4_3>74WWOS^$YSz(_wt)l_Qj_fEk$+BRHN^G3CI=;BaK3apPo97 zO(IdB^}h4p^16XUY|$jdq}{t1{*$r{$^D)gQ+^#&b~ZB_T9T3?7XG|{gD5*LVtcf2 zT|)Vwj1H`#1<|*TED{+0tIk;48<;lKE6$Ox3Y|m4Dg>oV7qN9rFB^9VG_eFkVdlBl z*bKiq#)O6w0@c?e2O4leak37gT|?H>>1Xc`mlyh{5E=@%R&prIrj{EE${;SSoWALB z;#%SJHffjrk>H=$R=27w(N2z&lU!Kj0QVojvPC?%YKK0jwjfATY=(%ORwwe}F#YRX z=dYK?L%500?!0((?!G?h7t;?@{#(34Sc0}g7@Yph=D2a5kOm|P z0{3xQEiM!`|Hhjz2#;{1FdsbprA=0_v56UjYfUwdzif_qt$u&kLP#x&6}2kao_nM@ z%@z6;+tz9S@dihE+B&HKKb-(SAR9R9SSj`>sE4t2Y>g%GH6&8S5?bSE+HNbgYNTHk z5LmGC6<1LlgubJ33n zjE!6&V%UOQGuV%@6A#ntNtsEvK`qi%eMOsmJ4|wF*@d})Uh#BlJOXg-299}wr=JR7 z7Wm)*lMx=)6qE3T<@ct$(b1Bf)#}@;UOVwp&r7ZT5`Cdvf6)b%{{M+DE9{y*bJ^{6 zT*(pm0d1$w%}p_j@wv5}l84{gEyD;z70;#`KtaE(x|zs<0WVyk7#E*|v(IHfSv321 z)YJ%C{jFQBcuVMkcZ#}Vl$nbj}*YoHz4E-1kW+&oelrWo$pcT%!h+xcuy+( zFCde&K*Vu*q&k!$u2H4F-E(z<4HE$;#eEpnV6a9`#@;aV$^O}4DK*{Ia8x%c$<`E? z`izL{91Ns&n}2>s0BfDsM&G@(h2RaEU^WZ88$b~l(K{}(5tX}Bzbe0!k^aHO<@ala zxWXK!PrF$=Jbg)-leEr%TQiMHVQJ3U;*CKko*3ds&glI0n*h5_Oc^gJU_ozIWE-M& zUYY4XEcx|I^`>7nTC9a;}=zF%=!^z78v<%#seG1=6S?cGHo@7KJlCJFv>Vy3M4Ye%xu{7P0Ff_m z-sUCSt@Coyb^Q~O6l zn~NGcpLDJieyx3C#eazl&O(ZBYM4LA^?14Y85cL&4rDyUKEr5Qs*pnohNUZ6JTU)` zkyK~rLCQi$T;~e>PXJfC%0qqV=GLlA=)aB2{9nHR%d+2Nvm(<>uBdNRuO%GWlwid9 z*Sn3vF!u=Vj@-}F6S_S#z&vzLi=6mE18d71{UJ?{4?%bl{)$nAy(InFeYxb8+1{Ph z`9GFkrpJ6@F9PL)H0TOSoC0){OXdbI}N?hbYdHn2SV5p?M9PmYJlA=o_&s_6o9lWbIPLy z%R^)8>?ZLb8ewO^A`O!f>w{y1&txRes!d8}C8LNwvU&Ka$>fzg+AQ1zA;_%?CEnL5 z*Mv3ti72B+?!nweTyC}B!_9kD6;^S#p~MM1{fd6-poe+1{QzOnYg%Bpg0hC+uXDv` zzZTjs{0F^B2m~PPP>_s1KG}!0%w~D%&gUc2k478UcLfHQZAe_N-HH-U6nTd}nH{=$ z{pouDuJnJ-SZvkevAL)}A)tP}8B;6-CGj=PY4r2H=i>a9Y?T)R4+#`R!7G6aRRhWN z*T>8_0YZ3D1-z$TU}}?EjYVL$SNMYr6A4(vAF2i4C6$jcSAw!h;f*^gI=}pjjx^3z zQeX*FF~d^6$tXTn-}Zw;KW#ko^G0IA5}^k5w@b-tYu_C(;&5ihcW8#XATXE8dui)h0Knp3{r#9au@_vSenZtMoq%?SP^_`)ppFVb9Asr z7u&-%)54`^>GFQ5yWciaUM!WGUvL`w#v8&Twf^-q@2Abzp6+?MFGhwApTY}G?#GzD zWcs}9c~z=Qw#%*0xrpe|K<=XmHpdm@814mKu9B8Mrbt@Ba!>5b|wK5dVl7!#} zPVM!ZL@#q69c}pEs)3QjUoT5?Q14i^H~%V|&5OL&>D>fvI_ua($w3>X1sV&XLZ0NM zjq0)F^_d=6k!7c8nsBb_XYzf30M`~-4{cC{u#}U#`D*F<;r3%ZmF^GbeOlak$RBhlocHb2p}0D7@TlUX~lmEnh)3 ziPiSx`+sdnmlmLC2?t3}W<9+}ek-i+ldmV-3u{(qmc-0W^=D7#88+O`^NMf0mc-3k z-lAaA-s6n=&OFcS-SEgQ;lV}^P=Kl3TdkR_{;h23 zna7O3Ph@el_w>Wj%sZ1`;_PJkHmsu3WrB&;wzD}-QLd`B^o?)YU3`y1KO4H|Nsa3y zSamlhIxly*KVh_T7*t2t1q{Vc{_~fReclrld1bfR%(#o)Pq`qbY13`JuKD`$+Kv~e zyYc#_(w~y~^W`fQ5}|FgJ3me~7z6idm7Spx0=*>TX%@v_?QJU#f|8Uqv5tF@vJOE5 ze$}3je15PwyhE+oW_oWvl6EOkaq}!A3GlV>+k091Vzza>eUi*jKB!M1vgQV-IoJMr zLmz%jJ#XJw$^XWSgQGV``4_B51AX|FIsC}~*D!)>_T9KXI*^3x1-wq1M3iVg!~uI(9|&x&E_9;y(Wy&W4mk z3ZJET8kSEMdhBQRwxlXPy%x>v3ai?DID7EdP_Ox}Mg3#Z$b6h8FnAI{Jf`{Ke{mCZJbT%Qyh$?M5bRQL zMi6=deKBMbh_)n_@=DdqkCh^v3Gy3B_SiFsfaSQ2Cn}mA^Oqs-5+HkemSoGyut_Zy zvf80Eodw5%s#tmZ>n$&C@0xS8+n!%AH2jv4qP3>qe%0G|((b|VL6oHgc|`>PuE8eC zHXBuc*XAV?hj;Q413K_ZLtijOOHG|l)@dUOvrBh>MurI29du7^k<7?&`h$>GBK{!< zN;Rg2pcNDHDO)a(Q50?#MOAcHpr4sJvY!Zv023;we#Z78APZlz92zddFv+oXFTi+s zv9Ag@e{Q(ftfFO8ZpFa&)LzEFzJbDjW{v%iY>=lQRqDlOA2TvCGM~y~o(L_tHGD?l z6Z~4*-MU)2D@G2UpP*Axd2QO%^dNai1su9Vd{eu)=4~Z{1sEZz0ykAMh%dtOcSw^_ z_|cS5cnjkpg_{?wtup`|Y;UELIXHtBI|A;U`2m1nZ+u|Y$L}oO2b5r_=#8)11C+z{ z4vR;mNoVcLbv1hj;nSXIk>`Zez?!;t4FKPxoQl`Nad6Bep#pfHL6}7&Wmc%EeV0{OR47n_(($dPa z0pNs;#sV{WD>V;i8B?1UIJ703^yReL%Y6GB^~H?j)hZ3%mHCC~FQY6e1uHhW5+5!4 zoLP6`lon5$)2j?j6!S>2C;3QCVQac6{;aGiaa*4ba++=-(_l3AXI|F18Ixmfn+j6} zMndo%I`l)a-JoRdT7m0yW0f1_Kov7=GXe~a1e9z00P0t@Q3(u?f0bzSG_K!i;HGjj&=Ma8-dFY@DQsilsi17Un5ux=oB+|Z$$$$ zg?;h2u|UB@FX_{p_oUbo@FP^S|fZ@BRxCCBSNZFlci#eH}i z=kRyVzDb@5w{9TKZ{W#hP(Q|d*yYA9SODfoOi zFTEO!qWtCF*+5q-=1coWt zpFGE&u4|3wj=U7$mtp1==GbSBLn41#gY$kr$##T9o?0Jw@;1oCRfuS#hc4DQz8`cY z#fF3moNHY+ zuptNE@*TS!ah&|MKif#9(cqTch4cBgXyA=n!hVpByH~68*ap?j%(~D|DW*wHZkgfe zz(xv6aIHFXZ0`+I1z;6GnQC+nz+MHv;1qB)8zNa>(FW^EaB(xFw>Phw`b27Jhp>{b2(SR9IGAn1A{=Q_TP_W z@&`QHxI4tM-dSGmF=MYuC~l*Pd7FX;U&$87pB&fbVNJ16092>VkM)GhX6eqES8QjrsdD}hy0b_f7 z3+xZSeTk9zZ(in$!_6u$+fAdGp=qP5UmoH2KPW8D1>mHF%TU%hhD_IvQ(pUWLXflo z6Q9A1&UDVPen}>eTyOU7sHehZ$4m#9oOl!rc{bSsAWI5LFF@QjFFd(=AR2ya9#P6~ z0rPhhl4^*5&w1f8%_T|y%IA1q3oYM25G($&-=um`;v$(BD*bx5j`}}7^T6|Op=l%W zegb5Fdy<`1wt+!(`OypbH~t#Hck7FyOG*~7Uqz;FC~Nn@rEe2BTaUI^6d8=B-=-zr zbw~Y)rU~j6mM8jD?z(UDZEx;7LzC04?726}XSYCPp%b4QC!j4pCwy zfb0RMsC(Eut7MWW4PiCO@w21MUFv-r@3`3|3YEx?TYuwanni)i@w7qcl``^y31|jOhmhw1ez`O$u!{ZPL-3a7YjKbS5e5YkIaanzAcO|6H$ehO=!$+9yUsAu?; zJk6$C@_J^gw~%E5S&-xFCz35&=B@U9?eI(h|5LSQ*rN^7^`kZDEEZ!ox4G8P*dGP-EKd!ww%;KGxH;$qaFFTn z10@fZ%94wKn5BEDS~mX~EI)`veu%2l{Dzxct6w%tP(hI>JIn93VhNO-e93~PtS9b` zWj`%z2XutYC@tDFCExgmreklHSg4(^2X}3=gYMO`cfptXnI=zMDWO0hv)uam&Vj#W zXsj%OH5=|^bp2*6ivK=g7F9M)k_-O7EKb|RJ?sM3U&<# z6vuY=bz%4OS%oV0BDVP7)`LoH^i6L4BR3@Mc(5(zoZ@XyNxB6OAdF`7y z(mI87eLF{tD;ELCL~uQ1(Da%i$fmu|&s-KTk|2@SdJojgVz^_{K4f(2mN{H#{n;mH z^mIIj_9T?7td8(XO7-QV?J_r(hnrl0ALB4QQr*=AzaUH00wC(FS1|);#4TNLiOT8ChTvc!#zE7aKuciVeR|o8#OHVB0w*p*GamGX?)lJ#vyKe^J z8HOgbg<`xd4h^1K69{5MLd26*qMk)NwG#bt-0Jv`@aPQA_C%Vk_egw&N z><7+vB+kP;;oi4^kuy0qBT8R7{-Il9Ykx|%opbHdwq{LT9c@cO)#_SYdhLH|Q~`br zM~2`1#N9wCv36C6YwLtT63;jFq~9c*{YwN`bTl&T2T^Bsm;RI zW(zJUbGaw(0_er6s^W!9G!BN74cT{xX8_37@%>D@Z2rY$Jbg_jAY` z``L43{ZO;EUBAJ@f_+hK3SZn1L+dx9sDwn@-Ry>)S}{+z-W5HGMqp(uWWg}MUz?3i z8XX;`Q=p9xp(A=TsJMDrXW@o8Mh1k^%itcHjfDPp>K+=gwu+zK{vBi7O~^1M(b`J~ zjs3T2wn*i>89_Al7`OhNcLiTY-B?W$jv3d7^3SQnteHZ61bwfzzvf5m-iRaanrqdJ zK>3(&Oa7cU3UdIZ%3PEE?*snu z_gPoJjd&P+;pXOn-R_6Xdu!fWS4lkB9S&=--9N4**~LANTXn;%af;r@ObRUKIv8 zeEqcq`$oF5mYx1Kq+GnYeR8(g^$^l_FayOcSsibT_Wjs_gtJH~T&O1$s~tT5ty5Mg z!9b>J@*@IF$mW#@Kux3XA2hh=C9FM_R-hbfFk3g>LE3JzJc+nM2$+>!JI`gB?}{2e zziU8{57UfU)&u8MeNR5F$SL)dW#{iIeB%8;uB}<;|0DTd7^luBnK${~CT_;1D+kwx z<~1d}mzdvde6cBGzClcLtyMjnMv-3m&Rrg!2Tg;I@A-*W0|Y<<{Z}qBaV7wb!cJih z^%GPjk>EE^w@6fxzLY8>7bOL~`X#ylHFe--{~wkCX$rx>kUa~FhVm`t+v*SPolZ{) zPFqgXPGe3JPoKd*gHb38EBX#Iae!lDLUZxFM>ZM7UWPtAfvVE9=BL9f*KRYntq!@0r-^Iq=>gff;)ictB><|8s!U_U-Kba3#~@%H`w zJzm@1r15Y=(`)X3P4BCtudKYPRbtcC#eMJ~1~0?|y7rY;V!VQ~_m0jBt~Vvkl(G8$ zSgDthJ-uJ5bmf*bu-LgcSU0;-qxu=;ad#&Xc`)bsdV@~Y;6vu}*R1-{G~WcdxG0DV z);U#8j5yCKUE3sm)>bZeP7Z15ZE99^>biPg&xn}Y`MX>bQyiQ1)T@pR?$cr&-;l;7 zWwLORInj=rucmUx>-&eO-EZPN#?bK;uf&5iias5PsZ|H4SgX}m(G!t{_v}WErIoW~ zFqouCZ{42I5Ko>R6#CLXy_(yQAzPhP#AY5C=#UY~UNEofYgq3i$!=?A;>Wp_A1Ws5 z;2-3}W65SU^{t`iWC-BKyCghakbKDINA3N~NXz?7^IJP%rkZh55>z{1DeqNZjlAI8 z^C&YnXxhTXy54{D*2RXS{jOB&6z$EHih|Q#KeyApYHPy>%a0fh030A_k-YL-WG^s|(L>ElJB?&NkXHA!=Zt4Jc?I)#ZE} zJ8XrZtA3;Vr}2P7cVzygj;5Z~Q+?woaL##X&?AiTL~d}IYh$_froh(fsgDfy$PW2h zYvqLn^5L%EsZCx$IM^>F_=vAc~Ke4w;V{ z_kXg|qT?~1`RR2JClqOX-9Y_bLlgHyCb`Lb5?Lx*vJ7WgUeDUYz0lLn(n%++%x9Pj zCvX)R0taQC3Afq*6rRk6&kim*%3POt)o@&Mn7-Q8nZz@=g8^*wp!rF&-YobOx=*O~5<07gtqhwFF8LtRktoYOhXx~cEW?kyLe@9@!3Ly+&ZOUxW%nEOy zhv>v~H}_>RwSnbEi+7O|E1AC9t|=cEi`#F-R;@sEV2TMHdpEGw6w8gk3c%d7K!E_i z;_E zy2ZFB?;Xfk0r118tu>VY8y;T23@`@!C7tWk(|;VIkvb3SyjQQxrnP0@n-;zfI7-WR z67ZoM9lu7I9L-D!S_l8$%{R4wq;|CVb-O?4-++{5y0o6$F-}n^In{+ z3Lavx)&vnY{en=c{V06Mte0M~k>J9c3|$`RSZ;U%FPC$QtWROM>Vu3AKWpCnytMeH z>)Ft4@yF&jf9n&mGYrR#Mpk4dZ{57Yx=96aHYU6KM)pIYoB%h{@O^>zZz`TVzoH%{ zcp+=YM$~^9+U~x=S5Da~xOr+)_oUq!rZX@E+(J?Zyq8J60KLLSFZ`|=R zSSa$Bo?-~;+8!!W_2*I`0&^!fc0(b>#}FJK;0U)&cH}D6i$Uv)xmWfu_8o48%Xr1L zK!V`WS_PZJ(@@wD?RZA-6P+wU8jChxIorqGm(+^|#%eQZ<_Q#OPOKV}S+o5qhCU@6MNX&l5 zk-h>l_;Cypc-;3Ct@F%vH8U2&`37<#?l%9-+*|g$1N)Uf@9$P8sUOc8y8f-tdd(a* z`8IU0Sa7E$#%t1_wYw7T$i{=C#kf{hAJ+dL1@sSBH79^`;UT{hY^}Nkz_(VO49)<+ zwiashZK3ZP&DkqQ0xqH-qeU{2!XB%No|Zw2z*z=?omOgWZ=HIgw^gyc3fsaRPk+&a zDR@Lj4k4?3vvuX`C7jk z7l48f4Mso&5^qmUXU7@vwEnkJ8X*@vTX?bkWuYDzZvN_~(%UaLU)%W|WzsnfW^wd^ zoB-=Z2rML5{|Hh|7v)#TWug9Vbxm+~V{RqrkiZDlX|>jGRjqmwCLTfBHfYOgeaUiV zb(gnG$mL2`$D^a6>qNR#ge80+wqQXSDaH)DE(pCj1_bZlLjuuaE(B=Y{wOGQ0Wz$R zmk(VX6FSl88~lhrLbJEkR?D4JSWz_piy4MNmy7qd_8o!h(Kr7^VT`yF+gr0R+#*B3 z&aD5=3bv?o7^nA}ZQ&lznddxA1++E_$cIx!89;36pjm&2{oTK9auxV`2j zfQt-jK!8a<2&E+h{sbY)&MB8C142e2^=WDdE=LR z*3)|B>t^wMBP8Tct}m3}5h*v?rei$v>)p@YjS`;r(RlQ6M8a8_fON>>rGSswS1|FM zMeU_3fN>dLqUoJG{p>r^Sghh9>05Q5la06-UdRLTi+t(FK(pT6enu@~sbV=Ix2|`y z_^#WAnO5>`+pNH%X4gR)4u9UO2zrJVz)QyV57^$?gMB~H4S6dB%PyWL2EEsa=LWx1 z7O6QhVs)RL;p1!0L|lZdx|vHd`NclN29vAv*0%zmQgr`Nr?~80PhW;1eh`&4A11xM zCJV5cL+~J;>=0m&#jj7k?|Md_7VyhXBRh5J=)C?aNQ0fuRI6 zutiVI{x!UNl^;u3_$4EjaE;iV=kk_t72UpI;%eb{kCqhc#ASRMG>x+x-MA?)44BfR zGR+HCv0z_E!aSCdJ@^%|+$eOecIyH7M^a2cfmCfhYVH}!iKs?JUtpa_|MS`S9vf5% z+FH&l?F^RL?uvHs;#Il1gDsfJV%_7-2S48uB~gsjjJu7%X=Y!uV8P`M{gs<5%wL}Q z@buedc3pwnX5S>=BaNRFAaibOxEm5W-03^dH3-vqLM1y-nJfDV^Lr3;fLEb99OSf@!iRT^t5dzpv*z{ks$O-s!_3pZ)JN;Rb z^$86uwS8jZ`7~nFeJHMiAp3>bj~C+FS)G&HUzMYY+(U(h+lC@Jxn$Yn5bUz|r> ziAQjK@SQmsTV=We5ggdUj1nH;$O}HuVA8mL_|vUhqVLVO96TIv**#0B6Y+5--ADYm zuOZ;ig`?}Y4JW>Ui&E&eQWxq--^XH$`VMcaA{mqWrNvEOqzlJ)rC-koD@cBOpDOu$7jZ=euH;?&gHvBu}nkox&vncK)t6!$`!+KtcG+y?!+>Z2+? z^)Nn>OoQsFzxj9d-b<+~`i-3Mr}5;Buyqs~b4*Ngj|jq<1z^}L|HaNx?_|VU{eMJ# z1yodB)b^Pf7?AEx0Rai=P-18h5tI-F1f;vWh6X_aK@e$BKtVdBQIIaByHvWn|I7P* z|N2;qHM7>h+q2}hrDMQBH zcmi;eaqJA@_HbSGo@__MKSD@xE@AY<$Bzy{(f10}I{WtD_2kD&l@$JH)i;eUnSZWs zaEIxPzEbcO2CF8=w}pu(ofu%d6}5cOaOL;gMO}}b%XXoGrZ8(cjNCX86Z3=NUD|1f zbHmJ{N8T4U1IjH>uRk!@0xXz0jR(}sDZ>3*uQp#BNA8}ijs@yTVrCmyLq&sRO%*LcT@@M_ zi23;mo)yD=zipt|*YZeU-HnMvCy6QK`8|wEB37p9bzKyUd&G`~6dJ#QBa#v?9f);3 zYg{@!@S-9d_P;GfTkxfzkN-y!LL4&r(kE$Zl-K^(Zy&3^FuU%!eht0%zD8fWT>D&0 zB~|Vz%@s#{);pl)tV`m=aykAp_uanjOY9tAUV)&v3Chg54&zN7YG@B#?=@k)=Wz<& zcizZ+5nziX>iYl23@UMBM~V@|pF5d<3?*0~(&_k5IUY5QC>7m(=ZoJw#vFc0p5IK` z!h7tMDSvGJRw9@TK3%W4^6%%IxLqjse6!&0uVY#e2^AE>fwFl(f1&wk+ILFK2Sc;r zJjieMw?!OswMWaCXXnlVZC=FJz{REB(gol`H=!eaorAd&w3U&Od)agFD4XNeH%=O! zCdvHs(`?&M!HsXAW^ur)^%wYT`IgSOq5evr>NDak1{P?cSC0^33UTB9csQM-{C%IX zuu;s2uPYZ|@dYKpfUbjrdX_x)d|I`uo-lW@SrF_eEJESb4FDcNgTlHyb)5!0b&zyv zE5Ol8jUzTH>MHHk%hJQ8gU}ZTXVXsFC?4J!-qWkfEU2CiiYB;6xy!oaRRGZ-o#A1% z1p@AoR5{|>Je&Eu@wG;7^ZBEoiTY|ft;~U{E z17fhabWMFbMoUP~+`kA&61dsVm9@^B+8u357U3UPmK!>_t{8^*#nmLgma?*9#u!(D z#F3zaVR3?7Qj#ys=zmmsXVtBTg&ZwPr1hij*SxkC;jwcM_Oq5SgnV4{=VE=cE7w@A zVU564%)dLP&q%HKdKxk7x?S$-hgFj13+_ox#*CoGFNjPc zFrByo8vJIRNEx*cZ=bHiqyQ4AT;75(o`6#_T3>k_wsmfCRYgjGm%|jE6XR3$%vi@p zG#$E@F%=?7!gG18nqiP)1)pYc`jOivPa;@`F~yLhjr2hgr{_k9%kr|iLwj@ew7-f$ zfz||&CZ`|aRHH7W zR!On=-c@a5V7e z3&*Y3dF3`hjPK%b>*}oGk7JKDhn-0E_vBq}KFP!riiU(L^~b&r`5!)e*RqntQ5>*UsM7xm-tZWWkWOcWpXoDI8JHnhEy zhGwTFm4jDGa<>gH2Dh}SoEM6|A+No0vUeP49^aBP{xe~s+#~ov8zWCce!epe%CAS2 zawOgU;bud02UB-?12Lm8F5?1L|?1|35i zHGS+l6cLn3pPd7dnxyC=FtNPd9J`zhSt)EnZqCmuFDwOa(mn@5OV2gKgWTx@zJV2czH>*M{VO9J&fW8_B(8di(lZ4C_M!WS5^DbZ?GC&&^0}G>u_H zy8H8Uv$u#^%7E|A$P8{t)b;ThoJb5GWI@M8W%|X*x=5hxVfl!*=aCqDoSJY z_FDbrmiLD1_;yNdeL;eMBvtJ_fAD|?|1DR*B`c%AEM}Ug!_W0wSGd58d`^l^+D@ba>(AMn6TN1}>(F2N_w2MwsNZn4H7K~AXRE`!08F4v z%b$2lt@b0`#idKCwFIc^tAKn3SlNFIii7~)=_{EC`i;ux_;hJ_KuvClUNGY^71!RC z$EpH3po4*x80jlda$p4q;ryTKmBlqq26=?LrldkhDIj7h-|Ez+8kbBV$eL%;U(J@X zp7r+ZiBmn|2Jd}35|?(z1^zg>D81c3Du=rfR$Bj%q^fG^Qi!FZ>-Tbo0WuWSNJ;hb z!-IKVMmj7IF8W;&%)-QYvw zE``(bRHNAZ(AgDzdx+_beaOqpk@?c_2&tB!fWA2+-JBwFe9DN&te>tX^?&O)Rv3bGOU!V5Q6j-5=SygqadB-2h z3ZFqcp>z8T4<9tp+YXddkmNykWuTg%M5MP##SNtLv|3f?dZYA7dVduAYPQc*+Y0WE zh7Q`t!7k_isNRxN}Z_$@-7id9c=zxtJNpby{j`BqbWieor*UE%`Wu%+<>d(SW1ls_{mtP=)g$ za>=53@1O+Qn$nWX=>ssZvjFkbD4zLVanp*cli|d@Y&iejFh>D8^|ni=I468xSH`&- zRM7w!Q)j?-a01rve;irHuzO(&#>^r0Q9boh$=6ohQRN$9Yfn^eQlweUPiV2-N)_Pt z=s`>!usk?qF@G_<%EL4+n}BL)tVLvnVW5lM8`IXc-#o`lQ?td(qL1q3)`QaoebMN- z=xM%_s)Rc}s!GuTSiR=y3we6w(tJ5j;;n6ACc6NxP^jG9{o&a!>S^<#*6vA18yMOF z&EK!LgMb_N83aL)%t|UDF!ra1@=aFJgw;&jn(>tiARq}(u!d(7OS8*xWnYu1&^9B{ zxn}d_otf~`WPSnkwWa^pDO!KV2;Ebcnpfv#KJ2G3aPimEH;8;5!V8U{Zc#`O=aR}B+rX8-x_Vn(U<+`ARlepWy@uUpai zO1wCN1I*8eG3tQ%U(|poaMYZ#X$Qr}sbI-x(inzCNV7Mp$0K)_a*2f7RaTBUgL3K} zri=5Wy_^^z6UdLPnF8jF<2k{1G%GOVI*|F4 zQ&@`Lw7ZHxjz|Cz!b!TKpJNv`VvQ;i%|>_;u`1A!_d?e@`1l=-=Ob= zV)(0jF5q*`CCY5H02v&JWeW;^H%xE=HCUWee7`p;@)J2!%Jj>Ul9})gSjQL+M&N zQpo5VdlxNsCEo^gy~tkSE&-FF-v8kR($PX~z8inauePQ`YC`+d7*ydqVJj1iPl(~D z_J+8O4dEs?(2^S%Eedg8uOOwIzZu5<{jx1f&aAsbp-3f1uM#Jv?=GIJ40<(`_eNd{ zf5~KHl57^{vVW6Y&ru{A2hnXo+;YV}YCFTid?Kjj=_2+}h;Z0%kgb{UV1VjV)eD8R ze>80Xyn<7`2*v~yAz?VMmS+@0w>K1_vz#$IHtK4(xcW{OLYawaBhx@n#v04|W2J&( zl#E7r0d#bI`g>_-cxs$iGel=ho)&`-;1bTCRA7~25mDj;uNK5Z>t`B8QHF3L{RZc^ z7(gfs=hbDYx``K*7|t>idQt-^EASIIftN%A&@%Loh*jD2fT)5=y=GgM0R$Nyf7&oZ zXnZLZE?n!U6E1QiP43M<75X>8$m>?b_Q>y5Rlwwas;}Zd0m$4Kc<*9&Vm4s_D1$z% z4$wHzxHG*WA81;E{g(rK86@ZvWXEYo^GOBT=*9)8(o;I>3fDL7;|B6<24y+}Ep)GM z4UYB7-f3QXLJU?iYG?CyURlU?lGRPp^<^9@bYeR4LdB*I!?NK3K&l?{Pw7Ii8Pqvn z{44zClV3$@5F6rwrd4x`b1eT{!(@>X-2j+KQ=&f3TzhZ6+JdebM?+I*JM;1UN7#y9 ztBto`R#Ll97sTWNomQ}KPh8{y3lW%3m?LajxnJKnJ7R|#V^YO?s02fElIiL$3XOck z1f7WferjFhB5g7rzJyD?1q?|79wSP3-ZM{Bbcg3PI^aS5z_O6M-UR71a$kkto_lt@ z{*{KLaX0m$Flvro-U)}CY4}K?8U$9)TR@kFf*cV5L2#@ORRdw*Dy-LXwrfk}xbpCE zP0KaGtHkAsiG;sjl@|tN+XDii=1Fg&&K{gKo&B9T@BG>`4|&;LbG*_ZQy5Y6C1JBI zq$vK;Lwv>`%eO^r)MU;p8OBt#bC5qI0P1kUme_05k|A!;ohpc1qefn2aPLPJf z3#jKtwS}3z?e)s_7YIo3g&+kmO^m{SZtp!^Od}!AC0#vB){O;q&}e90a0=&ZZkXWud~T%7&V_`5=2a(*n@rEOl%sT zn;qiKzV{b?r5~(zBYqM_0p535XF;)PlXQ&)TUolbl2aMOCB#bm zyO@}=Uv^JVFlLit_LDc+IW>#^Ku|8&VFNAC06GjRV$@xe=mN(40$X=u5ioAb0HV z%x*k2aS6txxZCwE-{5&%Y@uHRn~q!VGB0QM1CBkqsGglp7a=5{xD{I4Q+iKJ6yQM; zx%q*I9kRCX;F#F)hON2B^*CbiEM|hZnX=~KqNt^d{WD&lpLLOX&{1v1&-TF$7!PP>E{>IL^2rmju7aNkW3_!545DasYTXp`-1Q?-~?R} zn)oaC%JLei>Yp>jf7+NWbH0WMES4GB${dfrw57=W!7_={#J)u$S22CzM7Jg9nadyz zRnu-`j<-02ldIV4#mf@MfJXp^55amZVtds=A%@4arzQb5=q3ud0O+CO;PArnEI{wXP{|p)|3N;oy9-CUft52wI1*;)PHTWTSmH!p{ZkweSAfSP(qA8Yk}25_C~* zf>$LXK*^(qmDAa)2m;LaCV(mP*3}MeiUr?q49#cyx=g(|+9hFYZ9m|eg^83P4~9|A zzKlFV(?c>M&^bxa!mjZ71McxkLb!ziL`X0#^k=}1#0$rud(u*>5iSoj?!9Wxy{Qwy z#Z{}!jWbO3?5<)R{mYNXM@2;piz9ndg)5!$fPxAUNfwh_h+r%k|M}rv|07)$9Aj5k zQVJ2R;lKX&#FsqsCi*e5gBhl`-43z739ct$H~&n!G1J9|TZ<2x@1C!nIYdDlSr93P zVAp{nL%IRmKx-^36x}XNnTKpBF(n0sH&pQ9%R#6CCpOWRRtpj9pX5e0&yA~mlgAmJ zrl_{nub{d<3K6gM)cW@AS=FFLe-%3sQX5MSfVK`DD7O^?D8T)fT!qaUyt)yX5|8>dYK;z*EUAFpL^OB;!+vfys2ze)(Gs9Dw z6rx4I=j61xe!L&|HW(Gk^rf&q*#!%<;vx2}(LV-WI&O^WRQ+6Degq6TgA;BK|1B>B zB;T59d73b}nK;P1Sfe6iNKnda7ER}EuC|ahkr#a*=-J+G@C{Yh#0DdZ@XeqJ2gJ|7Em+s zZHJACw8kR`(z@~`Z_hq8@$|oS*cb8Fd35}0-+8Ziao^9`N8eJ);rD0nnIPP!PFAOu zQ){6YdqJ(LdTYrT=x4N0FE?DfoIRh}cP^3Ld5@9FcqQx%OBaWyUfwIVho@Pp;dk$M zqP>Uh7j@n1-y3OqaG3C4%=vw=Ilsg9*L6mTb$=}LYMRJ#TjWu@zVylKF?-T7m4CG& zOna8ztZt^Kd)@NfB97@;^E*gDQ^ShjSqKxgQYhGfFDvqNiEpEqiE1rzs#XOh*&w(9 zV)N>eMzmhusx3!A`JClk%=wM0!VTwX=~Fhu4IAJL@IH{bxMbu-=ECa8UZ{n&t+a~n zQz9&SUeDuoybKfdz++;?)?J8OI^^V17;Yz>%#^p zbvh<>JI8$gMHq?hJtg7rGAA|ZJd zD>I0lB)|flCQIRwID?WUpmZz%jxGzNM2WJ?A;-U`rWcDJWQNVdWGf<|avJdO9CiSV zwSr?FTSmAV;CF3)>#LDoT?`t@isQQ4JbRPxYu=}Rc+~HxaAMPKWOTgMe&^T8j*#F- zzgpqoXj$6VoX;d1tS1|Ub#hYXJReMObr{<9m_B?>OL#$Pt-k%*(^6+N;}9jy_s+7Q zpGAAIN-~QfjQIHCN_{}eMeB~v6TJFbZcRmh?~c1SWo)3k%cePf>o{qz0237#)F2Wk zgojsJXuaW=qkKu;W1gn7`4T!6l3AP$!Aj+N$>vk&!(N~m~(*01(m=OR(ULz(nojaF2vk>GmR?h_u1n`3A zaHKi!Of79U-%aoP_!gUQ5TH&#M=SHf>2U>Y>J|{{LP#C64m(dBDWwF2Yn1#ptyevl z_F#G5fQZT=XHUX5QnJo-WWJKXvkM)9ffy_q!vDl@=OLgC zB8e0%oo#gJz_SXi$YnUB5{V8%({N;<{VX!^+p<5ye0KWk&BB?l)*|_*`yK{L0DZc$ z40}lEvU6?tU8y4a6~??2U&a0PAUrRy+=_(AT~hGoqiq&tjs^=Clh9PFec$JmA7K-u z>Zi=pQCMVJq~_U9 zzfE_6JKq)@>qlGva`Is4nR-O>6Bsx3(ySf`7Vkia59z!mP&~Pmx;!nJ^=1e_ zruWSvCv`VpizM{Lu=sMuyD+rhgdZf~V1_^y=H&lZtmA_~0=$dU2-IUvsDe+v&DpRj zY9asD;e}EHO&l}lH{^j{m|Kd!qf-ZOw zKkVR*5f;?f-1qmAhlmuk3oRO;ujNRYpybcTy1KBZTOkXIaj-p}DzqrcwrzaEs=UkF zH`8-Gam$&xf#Nf^rUWI+_wd<9h8dY8!}Sj#DMpQQgkPh@3pG%BwMLmo+ltRR=&R7T z)zoO89Bgg}Mt3qmH;vJV+49H`k?gR=1^b4{VMA4$|%tNqIUVUYq4KzB^`kG2ARYc^5e+Dh5H3${CVNs+xOWp27 z1<@uucW{C6mnIGmLWCHA>OjBGQj$;T@*yQ!UXpUxQkp`%k2p|@`gHN$^ClrNJIcE8 z&9MKc({qftN^6#64ce`|;y9tG(uCwG-Z~ zcC10J(*t3&Lx8rdY*`c^Lny{AadLn@v1Y{ge#UBlBIy<2gzXSSaIsq?Y(+NSfH!kx z=mD1M##Z8(5r40Fx*OlGIN(U1-JqK~KwG@BN#n$Mop4`C`8oDO@Mhc_j9uys2 z*6RK{6QnDba))8`-@D&0r-X8Qd|2rsHxeT@PB&R9W4nAPx`M2LI}Bd#Ngf}(q-`CP z)*BU01l5`pzqZcOh{bHl&7u(1kS>so=OmISH(c(x zihj4Z|5*t00})4o$)GC27>U@E7>19wfJfYpU8V|vRRR}*mm%}vrmP4kJBi}~Wpu|%_ zlkcYUw$~a<)-TeeE2`7|2Yx_S4;V{&NFd`V=N^f4Q9=$4*7j{--K`^WpzM#yTnL%c_TuEG+nl8e(YzX;Iev-E9x>Hy40toq&tlT}kZb+}TUWQ&<3h9? z0%dTRAGO4ghWKBM#Pa_zk_XVJko_A{ql~`xy7qwjlsaD9K(Bs~=A|)&n5Y?>^JxEc zp&6z7S8@cy0KK*%e0*h_4!{-zYURRl_aQD57xlZ!Qj{JAUsle68Fl#`ZUrvENS-V} z(+PX^i64#k*up;oL%i3z@N@Y0GpcCeEZvt#IbT9Oj(1skfmfDZknt}O?dl5UxE*W$=8m)| zg8!fAoE1&`#nm&V`2N^I*uZUvd(Yh=k}P1KcWLlS2EWc+-Yz|Y>J}mT&U-LIA2IbldmV6 zX4sw+0lDAA2L)EvVIKk2Ughzl{c+fPMrbv3Wj(Ex%A``+;E6=Iy(kUz_Pr~gL|VaWt!NuFYm0K5UsCl(C!pX z2B&+58W}6nZZAy(i){vJQuBWkBS%}Wt15S5>Z55hhgqPR`wP|RT|mDSu<;TjCKX?* ztdy@f*;daYWjI2Zp!9iNo%q+z{g2x04z-&Vrl}p#4^qwcwfp=wPnZ&ey#v@$NZ`Ze zl>$P67s{hs@=V~gH`UOtJV6VFwjfS-;p1FwcnY74B&(h){QO;5Qt>YprW4xXiPv!# zV?oBt@uaT3e-Y;#W}vv8;JmIF3nk3W@}5zM+swcWVcvW$-$6eFsIdD)Gg>%V3J}iD zP=lC z?Po6C%kYIy<`WSSUu5`&nBS@PxJn-T9IM6l*(~e-V|9HOKZy^ZV50>NF4&)wEZ${9 z!3n?z0N(1RzchiC9&qDEfP>>Pov)UoBepeuIP{JKo`(A(r$~e7 z#Y)lz-!$aGd0RSx1p#AV|2WhovsEI(-HKYGXQYI(WCYqsX+cwEr+6Uw>zK}-0wfhU zD9rK|Yvs=KcL{d6H|Y8N`Y5$fv;W1zO$^t$f0GE2HQy0^xAJu&KUpI#b-t}Ya#T=n zBnkHGo}eZ%Ss1mMUtLx`(7-NG8cwZS&C;^RZL;`_TJo$|3LT>dRbFOHwh* zh@cGR)lRdj*q`5)-qW~r%3zeAK2Rso(1>jJaqg)%jIW^2;znq^S4J{TZN5m?!jIEn zgSEB^B5vFE!Es1(B;H}Glso+r^?*&#wU}n*&!jglH+3mp$@-MLE@a&#~O?`gOW_bXx)76+r6!BFrlFl zEsi|-&>K!aDnq}~y}M?neJFr`Fq;*^2Tl0Owa^q3V!ka(32dHcUPYD#&1{3cn7$ z|J)i%Ao%~u1atDz@~L_2Kb_uZ@FXYbIO1y402|(n!ToamQm@~M#ILl%w%Gh?uLG~PiIULBHq5v4HU~aR;1=es7=D)dH<=0m z1@Fru*7%U2Up6X?B4h|h(BIc@;#oa4$(|8#eoIA!jcrq5ghu@GO7D{2qTR=AUpZ6n zVqje5(6v^4k2GM47>A{>vg!_N>O;?n`(SNB2FH!}!TLr+qswWD@Y#OEu3Xx0lt)waL$EbsaRy}bW+mnZfiR)^WL#@nd_pRX1_+H20+ zJqE{y+3)YJbql_E{AJb+iUvka1^DNg@3!$0E7Mn zjpt_)duC|a?+KchFX-VwME%3fjY#7fu$Yy>hu+zWH`|(5Rl~iD zgGnZ*dF3*};Y+Kr0w>t*V`F6@g8bjD@?r{I$-35)TbN|%BfmNPLT0df+8a zzx~bWn1_tX4D@Z3@N;lDetp#bY+-ZZ(NdMcp?1`pTN6xP2=B`8T;UC-CpC?WBS@@c z>9q)kGOs9f;276f3E%wKi)E%`lyZZxLso+{j7|})=fIL~Fh17*$du4{{TH)1ibx3} zK0t`xZ3HY38ZnKLKfBj%?Kz$shC{O&wuIxjUYZ25o$D@used`k+bW81^&v$Hu^Xa^=-hVbB3F1}r>yP1fVMvTPZ4!HbIrmABIjJfE|LdNc!YsL)cu&EcLh@Y_ft z`IoS}IOZh{SQ&^V1hicXJbU1vvluewhhi{>WsGh=`!QC0Y3IK*HDGPK5Yvz0frbsi_f_Bv zvpQz8grUgW1o&(-e$=J<}} zIkg#Kbt-HhddSjnqn=B*scx@Ro$%H^* z;pCw6?KtO|%|c94{CSU3Cbrjv$(@bwH~>2R7U+DArXm8|^WOj#>-peN^V$M&a+ali z`R1b!*=RK=9tS@(tq}mq@4YzwIDIi!6lL5&dZqoNk1x76;kVOVL?l! z|0_Bx`^5$`L>AdHi!T?w@QfhmF7>OwHB*kGO_z`$;(NsFa)F@guDzYg`Th@Q=kh;| zG(ziwUzVL`%E01s*LMuKFywFB*laC*&I_)$0j&5a1V`oM(#H;MO8LjxSF;kv-=Su& zKqyLcX5H8eZG;sQMx1BtZIohj8Bmy9%ZP_~a*Gy$8Ybp`jupqRTX9|Pv|jo&{1dL4 zBpDh+_D}&Y(TL4oEeK<9jQdk&iPc{DN-EP*JeKOYMvH_qg0=MKp#iCaF%+G(-<)(l zPVX5MV?IbL?KO_}pnNy#V{e&I+j{G~V92kOA5!1ZwM}nmgp|Z%0<4y8p?|eDfbzts zfofBHtT?vJ6^p{prKZ6*-$@jF_Gwm$IKzN2BxEOE=WfUB-b{D?G&U@4`yvvCAz`8g zvY~7><*OQJuWzYbE#ulEksRRTv-1ueRPM72H@7awhzFBS{+@o558Qt*(pTIwtlD6Q zGxR-BK*7+9BwI^U*(@}Ugm6F+mAHnCc(JgDwnpud5K&@K=#0 z33qVeobpm4d_4gTYp+Y~ngMj=Y=MbFI5Cqng?~B?ERF_!ab(D}S2yuAq*ROOW_0fa zh9sq1_-Y$e8K>rb=ME1HUZQ)AR?HXIBb{3l?X`Fa87tEMlls1r*_@$k+HY7Y} zuoP>vdGyptwE(}!kx$KlVpXXy6cr?9s81SX&?~1Meg`~y{>?iqI@|^_1cOx8*W6U^damM z&9xTP!1M97#4{OW-69JillKGMGBHn?mTC^Jxc zrk%Yq@?UBmqAOxcN77xpx-!aPo%HAUtr-?8l9+RO&GS%YVPOB-o+fL<`bby;fZ>9d zw1;swnMNB+0nt^4s=XSSb}J@8$??*Ym+(<19g3#Z27bDO(b-&dY4N}@ZCjGlxM@76 z@|{oF7kVttyRi*Nc%L}_m_J8J{=M>h`FKeiCHORlLacMV^^cGW_A^m7qjI|saQGTx z7K&{mp3uquAj8Mtm5kr{oGm_S*ZRzX^mVB`t_1$PaxARnCXe z`;2~aO>WO_duKb5Ptbm_L|n#WroEP9*1rB>zvA2HrMbof(4xk>x7V!?8F@MB-HsGH-z%*EoIh^cMbcum=Zi^`2y{^0JdTM2K>tu2m zUxOH@FX*|BIx-VdfhziV=9^`P^#Z04o>|Vr!+5klwkJ=-LL00R&c$51{)dge58r;i zCiX~K!MEspMqPLy?$PE0J3%wC+Zt~McYWXOE`|wk1L{6ABYf5*|kmRYK z*U$aUDhse+d<&SP{2m3GA&@q)m{;SymOV_+O9TelRMQo*mx3f2R4Z-~_!atmvK-(x zAy+oekwt*GsRxI2Xnfk4sVY&u=Hq7fg5FPgrTdWf;K3wphydA{%6E$N>#vmg^Z7NJETwF<5?9j~_W= zed=cZniH=BBf)n5x1j$}(e?AJ&pR?ww(s@cOGG_ugErfS_>x`?Uy<5A0rMnA+myH;1g&UJo05DV9agU^RR~e0%H60Ie|NEHU`dMr}CJ& z%DGJ0ivRvLCA8zk+6$H)NU1~+2Wv7ki`XuIJ?ZA1-O28OVR|`DYr4W`^hx>Z(*ZT4 zeIwKkhv5nuzR0aMDul1(L>RJY2BTy5+Y-Ms!{2X8$%kE9SWmx6_LI z3@|*sBF+++`AN^OZ$>Ah>|X9H7xX5&B{>;%n8F6%aQ5rNluk$q<}1xK1@(nP7qMh+ zMiFWz$~mY;dw-5+JnymCVYjJ~E_Kmv5rV^yY*hmmHydD$B>O$VEPZ~8(hwlqh4a?> zcu!Jg&3EMaNZ<@gISL+!>X8$D_j#23=;zPl;ux0r=Uuf1N0P#{(!S>ovu)+~jP7M~ zvwO6=NT>JEH`&+^%e~3)Hm)-m3k3zT@VC_SYAO8HRdnB>-7EVAeOX;${}ip_k}dc|67-(TY|6EM?`rVxA{qS;f$?Vj#>uxcQy-u~gc6<(Z0huK(r&{-WrdCheet2UK)IiN3O9@3 zA9ZxKUac}1s5XqCpPunMo7Qhnb4MY>X5)J|I`9yct{QnmqYpdnyFG3F5mbN% zxDz+)feZy>Bo1(T3QLRF+w<|SNu9WF1;f)IOV=Dg4w|~eOH(=%FKwZCAUoj7`nRQE zTkO85kdI*w`yDp6@WC&XS`%=((VRhdO&qW!#&_2NU$B39I3~I{Gx4tpr>hG@0}dT+ zFzi)X(92j5wXn#cI2@Hfa(;8nsy4TSKO^bHuZdr`e1wU6)a2)vhzsrR%f|Ht2yTc| zypTS9J!c2{TVjgMWiy3yxzD# zB9!pr1E{p$R6m?W-y?wmNRrLA+kaE+ehXI?VVpI_2XrGCJQ8BWWnj6pDvr)cH zH4XFd2pzq>dUk)FwrN3n#3M|+is#nhUgI~)3$D3Rb$-bw#+Q(P0d$|BjG*$H*QVh1 z+Y0bz5E%`MK4TSB+{#iaHCENm*42~hgkCAJnxRQPKUeouZcKLmF@1#T$mErU7U<7p zqpr7R#bLJkwW;!3z~gK_I!W8E`G%q;e?uNr@k7LEePyc(bt8dez z4XrPgapG(3BXi>DI|{2kv;*`zo}TBXtF|hvG?MqN`UIRtT1JW4Rh%2O>G*~G3B#ug z^jX9N8@GOT?Tc)7MiXr3XP7+{qT)Q^xi2(wG284f;nAb!It;RwU(YOUPdzGhUdFMz zZ}iWo!8K)SraQfHM|UVS;<(uFU~J)Nw!>xku(P-LtZK!q>~uAS(L{OfLJKW^3p8Lh zid)r4_~8G7z1SbbwjTK4ul0EK(;dg%t`UplUMbSAL)_x=+d{xNb>YFahoD1u^><6x zb*v22=hv6zyv706N0P6tPYlT(*mj%VnVOg^4@$Zg!HtE`0x`Kqu=_f_|ITMDB8tzv zJFw4}Pv4b>=hWnv$GZ_wMkJ=I_*(w-YVw&n$a9&^3|wlhxO-dz2lHseWn2CwTO<_b z<}Af*ZA{*uD@&e_r8g?6M_QmY`0}+=D#k89G5?;%KbY5p%c!5=iv{31K{;w;r>pDh zM|1C{cKiDej{*dO+k9i=8w~Uu`>*@972j2wYzyie-8bY_CGY|(+YDY0Qon7ku3cnS z%v297jp+$`383t5AK5;HJv%Pe?N_LK9`e`qjtZt2l#FzCZ`dRUmu^cx4$?2erwx%P4QVkYxF5@ z1Yy%g)?6m{TWj`r&AF!Ii+|;sS?_gL-+PJxM5$Zv6Pnr8WgR)LJRiN}U5roiQVDV| z`SUmTnF-r^MvKUp>^) zGn1+C5NNqglbQe2JYZwf@fspaG_wL?7Zw*h~+Y$lPqPaiR`)wT~KO2xQ{((xpIl@XZ+l$g3YcNvdd<+A=DBUG|oS zd|A>~D+*30m63&)tO|(@U11%yLigk1=fdjr4E&2Wp=7oc`;M?8jUBiyc^##?D`V){ zv$%s383fCN?X)z8AZAEkK2G_=3QAwV;75zx`{FkZ zr{1f4gk(YU+Th#CR|6d>V^mOx^N+XO`hKa>bKVcA)?Loousk>Y2`o(4JH61^FGl5Cew zJywH?*cVMCAf@xl;At{LS>qxyXGk5eEeq(XfAh1I44Ybpm?IbzKK?D<-w;LH9dHz` zklY;vbtP?md#@qK@OI&k+DwLRu7r*Qx|50TUh+YO(F{(VQJFgRd0*HT<&IL}Bq8ke z9qUUtlHcx`m2Rt3XFpi=uz6jcPHr{^p`1oG~ zvQPGNXCR9NT^erjH=msh+$<9Scwt`474K_~R~MkkkO0qYGX?!G&a=MM*<1RiU#Vb zT|5Bggm|r-4j|yi&ImfC*=6lQZ-12?Utci*>_U5H9#Z^sCwkjltzAUm?x5gFN8*<@vJ z$3DN?`}4i7-{}w6b$XrGxL?ovIUmo*(*vuh-dczxs#B0FFm-f@Zq4sN2ySU4E?==W zH~IRuamvvOi=;NXTD^r_w9aB%)j~c|IY)5K?JhfMEE2rqaM^zQJ4|(;XL9TN5ggww zw|U`Wuwmo8H;J<6a=%1Yh(o3lk&l>@*+K3t?D@pt+&|2KlxmW}D?kT}fT&4Rj`6KM zQl@U_rbFFTYIXn zL@}o*5bzfUvxQ*t2OI@8C_S{VUE~(bek){+RqfWai{qlpQZ(z=#E9J#s{q8})RScw zM<92AuYqWouJXe%j$$In(xi_{Hsv~o=Q0lZ%PywSci@@#RdxFJq=_kELyODog?l^wN%uLSn-BZ1d~N4$cyhZ;e(Rz?V)$J2YkBX6 zVs=PLcKAwwNa(!si{6t@f!1dr$q6&S2(m$F3;K%xi8TtOr`@J_NM!es8R|#?tS*SZ z$RXv;EO3Z}tzi>~6m%*JZihYQ__+aRt$zIP4~{z;R5~2Eq%!z^#;-#$Oy!*g;s@Mm zWyT@sT1hyUBU-bwV3F&YZr-qW*nOW*`t$UUKGg0tyZO9Q8@YMYJ*`WD$I{^+WS8MY zf3J-r_hX`bX?WxbukAuI>|Jo9_b!C}VF=`+QgS$^8VYs*DMB6?xKlZp`HyGxMvmUF z7#3v=(smmw&FVRP8@^mcqRDt5rnJ{A$pJ9XX!1 z1p!N}Lws<9h!H^+00f*17Wbf@C%}0KP0zhgf@XSmhH;>q;w!FXybUgcaIj_wVuWwZDwgRl$UHeP0Dmj>*3CgI^#A61)G>`*yufGGby z2O4|!j_?O0-;A>ckX_)C51M)wN1hN)Y6*B=RT_t0`)P%o*JhROrg9?3`T%w%nrEeF`c=$iQ-^GK z&beO?CB$D_v5Wk%q=N(sT~dc-8a@2bq4YZgup9hPKLk@Z2Msi*USyq&az&Bl6nl|` ztlxoW1sLa#1!dOlJtgZ-u3J9yK7@l4P&rc@I&~#8jJw9!W|FE5A-k3e^_XLwD@1{G zN5~ahU*X^P`FuU&bADN@u3j1nM9CknON2e{G!#(e7}_q_e4@zeEIG1VpD4MhWIPn~ zF6yZkVLvw6pfIhchfi6fH;>}p!PC-TRmVn*&6#jV5%KGBI2F_ykmFkK1l|+v4JHEQ z=7jgtL~IOyU)0}<3v<7-zeJD=4A^{ueNKWsVe5Zw<;j)zT_8~X>Ak1-NbEebDY1y@ zSP~92(q`Y++oQ{@=H*nsg5^c#zB45b930`2!6Za)k(TrgmL5~aYznh}c{~h*&rClC zhtD>GA#TQm!YW}4>22`fm!wf5K&6y2?SGly&kmLwPglwipzox}P#h|}u6yR<`7kvs)c|)bNGI&c8 zp|v| z-xHQW8rBgTc0j}CscZO9qJ?<%pICiz8<$&|H<-1BCkw+&aJni+VPucRXGY| zbgZTJ-Xdio1VE!rR`}>S>+3RYl3XgImJ+J>OjNiQ?E*4~Q&ss2x#KhOr~KsE$IMel z$*$~#S(KaM2IBXn>8zZ^tjh|H92#2Vh+Q5_+0spE*f;0NPy6Av+2}1-^S_5t&V$*N z4U5_6MxHh#%j8r%YK`Ik!%@r~VoY&6h*m#Ow;+`OOwG-akQT&xs3gPJt;&0q>7XC| z!YNiMMQ)++ob%h|&(sURiv_DiLehgU)_B2No$_AK}cx_ zPAavWLoDVRWM;1Z7ZIjCh0knW$`stDX}@@5g=@7x?WSZg;@1aHJ6(>rjxD+6=ea+9 zzlW6hF@Q-q=Q4lxWZ0dKQy7NJdB6{_>(A^)`xC-};%|1esosn0Y*6_C%g!2G&V5aq z>=oT5f@;G-vR*Apw%%*xMQZ_m!1p`JcJ4khr62Brmuol=L#R&tq@xwrLdQq^_h^897?w$3 zyp*Y8OWN7(lgkgndfh1PpWz)=K2??`+uD1YexIx80XE}0 zl1>CsulVk3@Av3TWm@nGqff;{2~Y^V zS7f|LNZ$^*UOl(d@qJ^cYjH((@cDC}{|#*?0&F`Z_Yjj$pk{)M^zfSFrG2W+Umkq@ z;!$?-FJ2`yccWoAhF9r4o6z?juRb#G2dQ21F@0(|8O+eH_zIXXMdogWT-#<` zEWb%hgYjS7$78A}>gz4mkY{3Pr-Td*Z!(-N9A77)1SzE808a%{t?L#iT?fvt9w;EL zb6k`QNnTJmH?wh2*fYExcX{lXrmW%u>^mDDZv6_BkmCNAU;AHVj~m?CImj? zroTINuHXsr{fUz}ro-9D8x6RFtzU8XJ_M0j&>c?!W&LX#)&a|OfvQ~{qIJXQu_oe#IKFpVJR#hYl~#08*XS7y4i9?7C4edVsMs)26`%fm77i%TDzi}O&&Z{ zniqZB%{6&_&Mbkc7w`ULXSyhWHwJxXi4d^{25^?HwkT=zrL&Kquex>F9F~NdB^wq^ z?1VQ}Y3&1Z5K9@hdliNhBsNNlAKp6D&AVV2Z<;U3LBPVT^U%q0#K{0`!=*_htYJXX zqz=F?A*<03`X@lZlLBI}D-y*Psd8$F%9(Zohw6C$R;}*~kVe;;$mk1g$q@K&sDBRc zVvc{d<`&dr($U`?|NM8GKER2t`#Y*4T7cZ`5VM|U6d?bjm+G5(YI?A9vYT^`(rfeL zO)$imRD3L=plP9!GxJVWyXL6IB)On<|4~*zzNfLv4U12bT4xa6vPZwHyk5lOARrl` z=o+=guKZ)qnF}p3yA+%pyH_mNHXu_u?c)vI9RG6w!}hS+RE>rw!nAI`1B*=4(!3^k zev=z<{pHa4pH}JP_HGzWpWvgGFy z%=ZO1hke@-N}LVIs@p?mSwd%4bbng(c5C48le0%(O&uqlnchW-z`lw%_bh6?_NtUQ zHCH$x_w(fUm?I|=tQZpbl7qrjCt4B4yH>^j^8h^jn)3P`0usr`S9b!`Po5P_ss`|l z^_IG<;Y+<<7Azf7-1ehmGFpbiwxqc^ls5ZLp4tHPLx6|5&Up^&j`~X0iQ;C~H^a{j z`%b1JtjOo>y`~!uO@q6~R)Yzvrh}ulG7S46@u5U>d+Ku?tGQI*;>u+cV(?GY2?_MG z7JsN(>+^Nq`#v%x{O=V^P&H1C@NWKhZ-DUf{p-6l_PG|%f+k=5STf6`#?S`FtrsPY z`~YJlIKoTC>y}0q?{5Nw;HunLC*CBVUg@X_**b1SS zL?NgrG4G#oeaC9+TGRr;m`W)hl2W9h3QI~X)BcvWaZcD}!dd#fxVAGsth%a)+$OL1 z+5_n8F8fm!d1bumR#kvw<050!p-QSnh;d`2PP!j9Bbrj(*VSP%-bj3)xQp@g`kP>o zj((x`{6ED9CdS8a+Hz(-`_W!|kWBr`qQ#P-I9J--Kqu!VndrJ;E~lr%W%3)S>Iltz z8qCGLhEWseHw*s1V9>N)I*zd4$a8YYlH91cm+NXyjHLpIoAys9E(VBt4Mz=Ct5u5%cXvuCH$T%C4*NY5X?6s(v+v6pv~&tdfaOwLj+I zA`rua53CcW-bl}lCIBlN@fz#8^hk}ffnR@E!DKA}lgl$dD>x1Mj#oH)V~3=aM}?hg zk7;m<4^jQ8=hY1?dr^yU81Bh)^1xr71&$?T>>!-Ci)QUhi|PE5VfL-;Id^*v==Y|t zm`8GWQe73LDAx4(Rv0EP^El7uX+d79*Xr;1E8f>uJ)SqFHYr=A`7(hRdVk6v{2qT? z-jb&wDvif=;cZ-fk1ygAVC1$4ETzw^eZbBJFnHk|KKMUa()BtW5?}X8Zj!W1f9V&r zFpAk0CN7q_h(IbTTv8PRGqZZ>*L2$0Ub*_~)boLOYh3MDzf_fWhoz6q9EPC2QNm0g z2Pa6CX4st(x*!}FsL8~PeE)RNB=zSs$I88l}CKvK`-W(kpneXA#95E?48AKj$q)af93w`Md_s3h3Nm zDf(00&W<&etgudt+bPe0bnxS1+2i_#f@y)dAqlTi`Dz+Q)EQl?T$&kVY~Sz9ecHTK zm%DqS&iMXDV3YLG708QzSBM%$0WHo732H+Mz56u_1wy}Y==jeuGZz^ETOk6oO+@I{ zc3MB47YS!6wni(y0a;08`W#erv_aH%_s=JPla2V!7sD7xq*H>uMyd77^Eb<<)ftb$ zbP1C{eNvz>|7_NtFRSApIy@vo{t}NR5<7qY&yN+W7ml1q{kH<&&#nwf$5OtbV{a9v zRK9}iTH4gjd+$ugRhYqoY>{gfMB@G<2^>k2 z51=}Y<{};94I>GU{0?4Rehlq8R1f>lQH>rh$i{U}Tq@-LOT9&_cejpA_Jg2{oibfTE z;W2qD8*~)i9Kpi@=Q6-P&71nffEWz~qkjcyp&fAMqxv}13t~ZH2GF`l6@~DI03(Du z8Aj$q+m%oFhQ1URNtU(;ljMpCLSI-MN3{}!vq$Jr?u2{m8B?=+Bud zh<}9(x==;5%9>^d z#SajEOylWO&e+Y8nH$D6Uod>&88GBiI-)$YI;L&sr2YG=MytiOBOyk^LOxW(R9Ux% z_LoNT{o8fAA2Oa@gbb<}vW;s^>3{h6!yZqvCEFQcpw@In0V0@*LdP2Cqn52YA8_V_ zgmJP(6}B|%fqaAlRRls4e1?mg#`X7$o5Fh+MFo*|5FG4Rmf3{yD4dYVe|mKi0V*pY z?gQXnUAmHMT?~xd_0QeI$K_(z>DTm4qup3fY^;M_I^x?c=4u?NUTj%nhS!NSF!4_9Z>v!G>9Eu{HST}tr<5MypqOilk` zfKOY7eKgEnyUeO`_U+i(Mdr<1HO5degC}bntXW3C&*c#2_m=gJZdu(6)LbR=6mAG` zvyk)I5V8qG-D!E;>;Zbz$3jVvX_({2H}NcMce#sA!j7_~hcKYRn&Y(~V1f(zXK4rZ z(K5jt!4__|!(m)VUPT&YB=9hQLO*OXqZ&aeJNe0+CKs7>_RfH{BHAn4fyAcqIJqfcN!JjT zb$KoPkEJV@Ib-O4GZ@_Y%C-}ebo_XDjJu$@(+T%_Tlqr_{>r~KkGIrPhCS8N#lXQNNX!*CPGh;Q`)1g(tiE2&sAl3;^G%4Bhppb2*+aH z3e$x5MFd_M^>AZ3^WCXcg(~6DysRv7KLE4Uuk@RnCasAPJDwW{0{^9|=A4jy;DkWfYEF zDG18rCgV86j|9ynw$sUE&;mX7Ek5dHK5*A#bDR*sj+7^UW>h-PJ&3QoG#o=ovd*#V zgBCt(CpOm;Nk&M5oCpi~*LRE|TRk}$gWwnZ1H2`cNLHgdw@&ZAHPiP5 zza=?Jg%@_|*hg9%KCz2*gT;y>K&?W&hNfUky5jGT_rQ|8AG>kBmE+yNiaSHk2TM?F zbZDQR7yw~>SUbMMNI_TWTV%z6`q*{7Gn+|kS&cq?!0qn@;XdpRE}{u`QO68$0uuD1 zTh5&te@jbcezca+aMjfu$wecdBjny;l0eb!5CN zcN-r$QQL>EJ^c5ZP4xNk*ZI2)PII12dqe5foieV1T!XBh7LlI+0@IKXi)ZJ*mW<_pHbS7cOtWEdR z`SU~3eFms0uDSue%f{ra6`v8KTUxJUdg}q|`mB{vK%f^&QSCQQzoYD4%&*%7JQu9H zuK)TtZ+r0zQ{<9ER(i$4ZrQ0wD0ZQ+moUd1wu_DVU2dZAt4}F;qELN_uXXF891v>2 zfG*ZCfUv?}>jZ5Yk8K}kGEbse^qla~{7dk=m~T8px-d|%#z*grtit2&N#9XFuP< zFWc%aqzHBk-nyO~ zghxQVsej&|AB`a6v{KuMn2<3X(_{mhl|{f1pQi)QkrMkZ_>i<%u(Oq3=?jr+_pw3S zx)<$j%TduIy?bCrCv@rnO|362!Jl!q-v7q-umF65b{ zv+|Fxm~Q|GioO&(WTD4%K8OyjN^+zktiPzw4aOn#&fBdN!RaGXIIlnW<%WVTn3=nn~XUkTri)JZfdv$<(B0 zhidL|@^jK~pHSc7pI^diw?VhZwWf`zvbGNYb(l9cd2F<7+{{JFExyDI6p$CH=ePB^ z9>N+NghGMIHeTO=Y!Yk+fN@bcm%7P(_=_YYRWuy!>tS*ffO6V9j+mAL5-`gHx;I*h z97#|8*cngR+FIgv8Dcn^sE>11_%-qFVe{>?SAOhf_@z0v+)p1B*e+&nEg9$$aP6o6 zU+d%~arXg5q7TmN{e2W)1zl-EB4zWevZqf!HCfJj_L!d-Iu|Cri6S{}cT zdpB|zLH`zS9_NM?1C-Ea{Jo??lfo4u?Gzufk}1as$a-b=kOgBq30FzL7K{KtAPR<) zPb{*rG8QSs@Ra~<;g&*G$DU~vlRn+{ZI{g0{9BjE*S73?J??(<&3*i0p5%&x+h;1f zDeEPXRt?ptqz7{sZzq7AKV`x4=cKjIiK9gK6;)K*t*SB2^0WR2r`Et%B|8b& z?j{Q!G6U$0Kz()`X2t^Cm9Pr>Lr4a?)E|9ACJv0#4 zO8aUL%W3;UA8ckgSXPOXHyu;&1hd3=*2>GEgigG}iNM||V$sxzB2^S@50V^}BPJo? zQ~>~A5qAEG5mNrL6WA~OAMO5&MKsHv$ldV|vx|CsVv9>gjVe#UCLhmDB8&>sFtdJs z`6ooD;qn7~4HAr^ZznZ;Jap}~jB4{`wCQJkh=LVJZgFYHJE!lZ2DovlQ07kFND zpq`q$)U*FuqUBedvPL0CS~OzDMqkIAC(_^9*oeLRQ0(IwPI~e*Qo*HTr1)ZfU@4q- z1Yay*VtE%taZ#~eyj~OGK0!%}y#T+o1Zo!;rrWs!(OQqD2<|do{zU`IkZztax!=AT#hQK*XEcYOZ}u)y84fNY6uE142Ct0 zyGWhty*%Y%0C#OZPvsH8b(Ra5gO;toCZ%9eto9sdD$5hruxQ~qjcN|n zm7G6{*ly+!a(>-cZr5ra%3RO!Zg)5R&Ws&m8+MIBZf?*sycGZ*%2KmBUA%R;86knf zK}MI5!D}`4u9?zfND#t0rhCtEf#fv5qx1a6L&l*Ti5UaejoM)mDG4{s;5T7&;fM`cih03=c@23{ zEMoGf#gQ2*O`mUjvX%Ljc=Y?NpsVM?4A-Y%-0bIIxnnA zoQLpt#c0Ec7(nRMw=P%1XB}n$+%|=8@Ela>{H}GERZYL?cDL2nFo0slHf+0hA%ivJ-*vPW$TH&rnFnNR&8i?%H*RrXT8o!7Q zrfX!H^jLEkf7Th)blsYdEIoOLHoDuv4*Lwd+(Q!8wynta&zOjf^jvMpA8qP##92fd zg6-NUCN3=7rcD#L;J<-b;w(LEb`>Q3uR=>vroo5X{DrK|5DDJW_?59J_j2z=3{jR_ zmqhU~8@tHorQ9JNmhTDr+0tQyT@2id`x^UuX!jqusarnM`OdlQqRhvg&V@ z6*;w2gjbDBxaRA_Pl&HX;oe4c24G0VsQ}T|0WsPE^Ptb?2OJqtRej*vtXkqkM=eS!4AonBor$k9bPkvs5(M`;PycIR&>-?CfP=40|+WO&P z%!ZU)iCjj;e{{?6PswE&1Yo<(Qk#*hx;6GEH1bop1)H}1K!;pr;LZ;s&3So2D6g+7MoJ&-N@M^n~EY$mgA|%tJlGpVEDqomZJWG)_-t z*8d4dA%La@AmfppNNG?Vf)oZjI8T6`gvg(&Q@cKnXHD}np}}BQ9G=+Bod@m-kR3sa&rJQm~1fW$5G)P38mj% zdKH(N*pFUBtOcN`=wQJJ2f*{CP3DCe%+xWn4?}O@Bb77ZffoeJ^NFw@(3d*CHkK@w z8?bej1h2B=?;hU|d~9~zey0!cNstey&@bJ$@>6q_O@EG^woJ$k_MK}llC=DjO$wD7 z7ip$PtV~5t$GY<9OQIad4hfm$%a5bS394hlL0TT$LH3CMnN|Ok54^TL8og42?+Q#-sKTBJ6k4;clmt@z*b3NmMu<*0J>oW5ePZTPUiK!M&l{5 zLAx}&&R$s#r`FVV=PGtlDphjva4VtYo?T+ONv`mUbI!Y?CvlP!&F8iB@3vxZOJslF z?_5$oZvLGKR00S$#I0#taSPZjWH-%sB$k7n8S^hN(o`2Edur216_OYJ@;LRAK8d%x z8BK)5G`>|+)a{DCp3aQuXusoPs3<|-Uzq;Qwx*s*m-<}1K`#~P*3+hnVvi?5$6UJb z0nVfbmi5NRB&(hhIOq|^hHlpjOc|PHe2E4 zU+ud;HC9E-YhJsvwKfodI(5Wx%Sw(DgtO0rIDJka)^v}I;lo#%-Yn^65;BNuf^GJ@ z&dR-GO>Revjy$BVy2u+xh;X5FkK`RRKjVvIZ)w{nMl?nJ&NR>mPFfhUqP-!6IZCEr zE=6ie*yFlK#gy)rPhaOeb8(?}25)A5!e>3Zl6UXD)|C1)^pRFCbSyy)A>p z0O_lf?8%?rkd=COrQC)DdO*#d>x{Pg>#@r-?GA>qE^4Auu}oNq69T}-y2hjQ+4J!z zD^XFNmtVDk+CwrkTpuHkfB)5kd>4T??kyB7WU)wJ^~wJAvL|DQPNCNlR2ztxz6Ak2 zHPAN*KTdTT5r~X>Ac6E{)$PW! zI~sP*?yqkI?qD>T1Fo*Q*7#%(%nyESZUb5O8G9%nwt3u+XuZR8JG3*9U>r+Ok2&DK+aimWTSN%wiZwpUdmUmBjk2L)?zj=d>s82a2H@L$bzq~YwAcDg8y>)pe9;6}rxS2Wbw;EtEWKrr<@wZKyLnLZ zY%q|{Jo;~+S+o;8zuJe{<-}`vXDgBi9)I!`7{)jrWSU6KzaRCc_W4Ax|D^8F^bh|- zZ#STgH^4QuT(dvI@G7TH$=Kg~j}{7|b&cZfgOY}XU`D)GZzGx=cot+d)~{`1&WGV^ zU*s)|{@VviRuDLUnIcRNqwrupuE?Q2d zYi7y=cMUj3L5hWSrQU{03T#NdSiU6z{39BEra=7gdVQ;`4vJiy+)IkQ_7`-bZtow` z@>LbF$7eP&@nAf!Us8{vx~|tXTRScf$SVuvg&T-lejyiYV}#@f`rl9Boqi(Hvh3Y6 z+Qu4q9S4r5n`x63pgx|YYCJlJ~%?OGubID(Uo~@8Q;e)3QjMS1Vj( zTz~2om5f^5B9%G0of5UP^*BnoWv0MC-fE`F*z1;W08DK|7LpUqd*%MtFIBKrkw4_ zyI>;n)JZt2_Yl4>Hezh&J0xWC>6@BesWG}})k)^^tRk>hQ zObY2oSMvPx_J#vVHr)ru*S_jKKI7$Gd-hn3)gY;2C*84YVEr>m=)LZE?Y@sQk$JCJ zK!$Xi6DY-}fCoTwxWmfZpB5)a0dVd8(2L_oD!>X0@VL5y5B%*xi$C<|cA@JY19+Gx zb5Q^*dq@n>S3Xjc1z6wp$xR7W7-zws?PYS>hLU>7zjljYh`%*(p2^rjY2;7r!)qG1 zY05AVDF{E?hq=k8iBD{$;3-sC8y=inDo;xWRi395yKX{aq%xv5GX}si%I1 zyc?etLK$;Y} zJbl+^m(hF9jM5sQb7NCO$aO&4Oj1O)w7;Za{w*w~C*$Evm9uB?&%SX<^WnSq@)Fx> zOIJtUZyYGOdf;q@Cjwaw27YPV3&nY3utb}KSvALoa92hTWS*1nDoEu5*pK|b4Q?PO zpV0uEnFGANz^ky?p2#kl2b8B%Gue49h}HS>5MeKsTdWV8PSr?p&7VOm(=Pl)CGGLlGzG@~8Htt*`&ZQmaJcrP(cu zvV#-xiV=FD&T;dcomIF8M3&Y%(UAcXD*{xuIjE)#$CIIniAedI)Rq9oEIC+@E(LO*SMp;bSG`Bn@j z@BymtGqvt30qbse(l1VNiqM~G5(Q*($>cn;$_Z5qsX7x&*Vh5&vi3U(z8KfFEgi=X z_9fB7y}kkGe{}eD=DJuW@N%9nerePw{CyR$!BLG16E4PP2y`knz_!CtUKk7!)(&p@ zGBy5_TGFm7aLYIe@PWJpvgg_%fg5aTc$ws`uIj3c;fwDwe%nm)^WBVrs22S?w~wAX zF}CnQEW6v_1fcIt=Wjt+#47$>@OPLT!J%+>dzVIt!5{2fOL&kk3)B-zrPiF^r&hX^ zKR8pe*}g6IPG32mg_mvui#C{KUbg z6)G(xiNNL1HCZzqc4g*=787C(I{DsDi2gzNUjV6v-pC&F|?>i*Qec0@&Q zMAN^12IfvFV!Nq7MTr!^a$@WaBW!mq|N0B2%F)rqgJjv7RBtXZ%EC2eTHh>p$UTyJ z%58RIS&gQA`vNHcyL_qY^tsb$Mh8#x1m+p84NckOB4SP3m&7T2OVv=#*_RfS`xLjI zP0P*%-1ETRj6Bfj_*0<#wDf#}^0*w2KRolNZ-fKH!R;*;a>c-$2gGq(%(%A_-r!&m z?cYgF$3ruY*>Pqf>@>Q}$`0u;9J^9K(L=8CKn zk5RO&l(j;5VsDHTSah0)(W_4DyCft=@!aLJX9GP5cmFu7ib4yPh7fm9J8(?=)=?vt z^x=J&g6n70mp*UI+yxvJx(72G;GqPo3SSMO62)Yud;Pu&!D5&=`y4Gy>c##BK@9k# zOSMe;X#W%b{HpCL=pI1MnuTAK@@SFCv8yh`-Inu0yn~XL7)#e!V&-x#L(opQ=k7iv-=p%_qCQz6I{k z48ti>pBoOdWw%-JvlmhyH$~a#+_#jswHUDYd+}g2RKyDka27%DOd^_K)m*s&D;{3C zUiTcy*tk7s*HD<<)vpQV2%unpUz2W@lS=~UT+!Z%kxtY!>gM_{7EeP>#)OPU@>(oN z`D7OVDpZC!L~(EHPrFX*>Y?%PeVqee6@vitKhN)gkMf&iDd*BCz_ye>iYU@zF0*#%D9Q4Yq8wGmx7(NioT0XmGHDqFUP7|sa7Q@ev z*yaPA1a;a>$-=gg%P3qCJb1?7-hbZN4ls{(ZCIR>Xysiz3H9y}Q>SMm?tSO!#L+L% zmRYIVvVY;6c&(qW;@h+&!nLmTy^>hX-RXu;Pn33`LVA?)QbsDBcJfMHh+FQjvdfU_ zn6%BULIFvAU+wHWYOg7UYGeANbl*E?ik0yGTLKbrisz<`7FBZd=Gpa>e=T@SWEA!J z$exeT<{unnR^AA``?iZQa`p;J3iMJho7bs9?Qle4X@y!I4nz>GrhLgvgNl#>5R+%I z?{?vB#*m%}hf=i3a+5;s3JQoZ0hV*a#B9wRAA?j*Q$NUGwYRJ1CaPfXu)fLZ(gMCW zH?fzbTD5Iad~z|4*UDg((y}bj9BufU&6^kpPktL>`QioPY|*}k4AJ|)EjEuC7g18b zudmzaC@iz}Q1DioS?llI^*pTJyR4%+?IhnZcl@3{C@J99<(pe@B?CHoH_C{lxjj?; zBy2(Y6lrAQLD@2p&1VHUM*%;tRA3paoQM!Qcp_KBH%`|y=}zw|fA7a;!Au$3mKjIl z#cvn7s;Zt7dRkS%q$>4?IoC_eAPtpstQIN;Tb1(a%#>J}gpNOo`(6Z0xJ=~%QYZ!i zJKVmOe?JcD_Z%vGyNLk$SM8Pa6Ne4{{M~? z^YTDqA=Q+kw;h6Q&S(wp?q~-rWHn((6T%T8;b1ka`Efi++wH*NUx6bn;wEBfhU^}E(&eG;lsV$M(W_Zm+L*BQEywF9<8hb1SP4TQ`3|&QU>&Ze z@(o&KC+p;&xnGVhB-rV*i0Xj3HP;VoM66#rpacw&_bf1-W*}) zO~3Y*MR{IREoQZ2&>$l_J3s3Y+0^GNtl+BPoI0djn`^a}1Wt=-A6!l%io*0-6>lZF=m zcnZwM_xNw#O+s2es8#A8)T@xdFIZeXDVR&IHf`-GbeDS_#CTO=2r(gwC%<-_hD{Ws zV?5$lq186Xjnd~Oef`b+U{}Zd>zF@ugHnx_g4MOxVnh zu7K&7kMBEtyHnTh>X#+0q0WrwFYKY8-8(=2yOp;aKh?u#dyce%2AD zU#m&mc%-|GtfcIe(d{n_jGRa+mujcf(RAG|E;kLJ+Q(O}u%A>Hw3SUbHWP1c(#*Mu zA`K>DnknmKQj00TGJB0ED5AXIJM&t{;yOCp<_Fd5SMxt>k6!cWl*z$zL|Jv1i@B-) z!HtS)zY{SN#af>4Mkgbrlvb2)Hj|<>Ox<_Oc5FPxQ%Af?JseO=_izOPTm>=o9?Oq? zjF|r~seo}&hT`-;WP=KntREH}dd#+jV*-wl0_Sx`6FdkJgdl!sIVK5s~^X z5A7Qz=Jv^Q`JlVrqyn|oHKt(_SxE;LPi!k@Nw5T|D-D-ck@huWd$sQET=E4hhf)?a zEvfhd(!clF6hP5uCjPQ@w-tQx?bHJLr{7 ziz`zlJ^h)!bL?M4`1bhP$olRxncDj~7H`OT^O`yR7I(<$?h#MhAi+}^Ku7C=!j%iJ zMsSwpycX&7(7!8nS-$I0;(H?B4Q_d}UpCW&#hDt{wpt(9CFHL%P1ib)`aG=Le(%IG zvGbEPDe?<*t!El3Lw3N_!^Oq71?ug1ttW?P;@ajX7WSQb(&OyZ%OBsVjE^vYlgiPQ zJS5l!YQ+!Jymys*+x2KDyPK0j@8!%GDZ5En&0Dg?G~6<&Ioj7yFIXTo@3Pyb9rN{G zni0&n{p>yiXyFLWZLh?3S{$-yMR|@0d|Ehuwdlirh5a$BT=(0@4JNiCG3JS5h3}qUd|zFI#}}*&v;d2G&7N|tUytal8GdZ zgwlcyR3H@7)+yH!l(N}drGcpR4pWc9>}I0!0T1@xnP?6~_7aIWG1o13iSCh&#t|El zcO)THEg;Q^rIHbI?b@Y?ez%!Q`Vz|o*s=o0UAEIC#-!5U7TWHx_;|smQ@rfmkkZG5 z?Ak1TBxS$}p6YQS?erF7j)i|xs>M-r|6zPUb=xm`%2Fka>hf?{P=QFiM}7_`4!@qL0r=wC@sBC?MW1q@xf+rOR^BnkXFletOL z$<)^=vT1uFRK(ITrEy%l)xWT~Y}@#NNdI&*mZq{oo2%vg!0lXHN=&$r5iy`MWx-G{ z5K%o-o!wIXe?)zCSX6Jc^*b|kmq>$%fJjM5!_Y`csDx6|DoA$>N~uVfgrtNZDP04S zl8ST<-Q7~(;dk%%T>d)1GiT1(Z|%MI+G}4f?&km7b`6&wmQA)%P2obNrbvTHqw4*0 zY3*qt73?jakeHvlvEK&GF|#o4#9E$i1cW87WQX$zN>ml@X9?zvajff-uS?_Gs(278 zxYAh(xyGezZ2JkCnRWv7KIG|08W`16*oQrDbbrr73{|B9mTsM2EYMcvjcrPqqE3Z` zI7bdsdPM4g{Q+b|;By0FiuI5%DAw{NMR_%G5VxN8icuNIOoz-$MK@kNNZ-Z<4xXn$ zzS8X8g-z?Ps$`lPD(i_li?*k(gpX}X5Gnm|2;jP2yC)E9V-Sku$!k-Cgn|a$1BzNS zdhVND8-@=by*0RzXZ8BGRq$dS5&h84y`02;QC(&R+c$Uje6i;rEf1jdWW?{b9iN~0 zK=padmvg!90OR`^m`bMMBhwS={fZ)*e80YZu4?0Vo_bZShcDAh;u74kkXZNjSdQCU>>K2rFY0J)N4gir7R-i|mi z8-L0^iDWd({;S*&)PB!=SDZHkAx648BY)}aILN!PwOfa*^XKE};}^Bh29KkNTdSENmP@=x9M7(w&wz>KqvLa* z=PB5x+z{v)V}cNa$U}hpT80A(8=+h=Xz(v1vrWp5@-|s#=ck= z(d_E)esw>5hVI9O>D&!J7l6w9{Vskt*2LlJ00DL+8X=h+zpV)XrlxQK)%ZvMT=z4> z4^-(YjVn`Q#Ak_xc*q=;CrPO}OBfF3duj2ok_M4%w*HrCHQC;N-Dc5cmYpA_zcMg5 zm61Y`V8|6S<^4(;6ap+TdXUs-*tn&~iBy@g<%)!J2@H``3NAJ95Oyb|My)qM2Me?4=&nZYd1^l!00MHz z!r?z2ZU80UIa>}Cpd%#356MiwWzJXqE+)FH&UJJ7UkQD!hLfxScBIAe+8-F` z!U4ySyeS_};f|fWI;$IcX7O8aCkeDrmX1f4e}AB$_HBsgjC7uGX4$7(Vo>iVKiq5! zT)2eb8oeed?_FNp^{efW-T&!I?XoLQ#`wQ$V~!A_Qm?+aI#a}DG2GWDh{({?xPH?~ z1kx#@{d+C9G=Gn~6dNO$CIy%_zq}W&1YDB-P!!E{=?XDS`qaT+<{pok=;40FD6iM) zsuIK)-orQ6$7+8Fjju4aS5n`5yZvytd9F;#mWej^B7L==VJr;Tu~Os^{1>}@SRA#h zLnI|-2&c|>N6Xy(Ck?2vu*v87^|gP_Ob&fwAcr0f;Ve4<#jPKcT$Ix~45ICz#9JQ1 z0hMa2uX)<%*QE@Dlt`C|{I?N&em{l`(1wJ?@0u2NT6OOx7V+KuIPR+6cu!~B=!q#Icm*SzMAUl&Q<6!( z-ILZ_(J@a306K_Mi(x|!mAV3JPlB;@cua5VpwEUqq@Ejr zhcBhvXdvCAeHSZD)tQKf$aHmV3mi_St{Pi3LsBMGFK}{X9jQvcG-m5gK2ac4jC`4B z;F5oPRy&b8gp2LHgC-f)_eue9eNX@owkl3b7o%o~PAD*kex$iP0hN&T5KXvw^9H~8 ztrx$OdLMWHIQwj_Qg^7T=>gl$1=Q?>w3zqIjN{DDvKU$rkd>{kJ6l6~a4cv4b3iC? z5V3jT1nlh4{b%W|H?X%qiKZ9CvKfYxd5(=C=`)BRNL`>H`)#+rANk8y6JVZ+Z~%u1 zh>xEDSag%59j$!$XXRD9VjsU_@IA8_ctDU;;1St4xGt`b9c zWCd{zlFK`x%n_{(V0w#?8D;nDa{Oigj9ASX3Q(=|r?X1+t!lgnjf!riJ6!pU78QoK z+{}Vl>Z#Z?KktRnpu)K$a$yo?oHNNoiC8~s7UN7RPR{IVgqS{1r6Oq3<6a@@aahpM zVfmg#vR+c)r6ThuiSg2*k9Nx{KU;c;9_I(~;w> z9YMf65cS)G>mZ3A1aM${X;7lO5pvdGhg9)I1=4~g{l1KnyTC-9+OQ= z3Q!I4rYBG9bB9Rr()VuzR74m)@EzH^Kedtm&8rhN1|?QXZ`qmjR2O_`>Bh3XQ-4FX zPt)@(!CiN$!RP%yks5vqL%EC*sV?Kg$FC@0K|I_g;2!Bcnr_*^Al_=Yj1qIHZ0 z>^~^P$F_W0tT3YHD2p2T{6OMjR;|i|kvpXvpgX*sU3Xi-@*%HUwI(>m`;Wy)HbvS zV0JbNDqb#yL6ABkDD*w|QNb;OFRnzv#a$C^RCC`VcoVxk)y4Q7A}&aCsLE%Ob>&E8 z07~?%H|fxZtYEZ#0{U&{;#j5RwP-4~5B7iSAv|u7={sN%<`OZUc>$X%>?kOjscPheJ zh}+Gtr!2AmFR6Qs+N7Kww}0Dh=cJO$!3HSOo$h#5-eVS>Y=0OOv>%@t{m?e>=2qOZ zc?s<~Dpzbf7o|q*K0lE3C7+NlYD8Cckq5;PbYpEXQKcDM)-8faZR(UuTkCBWqd1n~l>mT%neL-k!09kUa|usT&fTF%7{ zb3-aKXecpCWA~J)R;h{;(y2myNPKi37wQFQ*<-h$F3tQ!Y4t!X;4apuySTVps&8*r zvHokYzLVQOb7?*Z#Q3@s7577?pW0;BM~oKx`&}3wbz=qYziH&AFF_67Men|gAu<{5b-rb{)SytC!aAXTb zAPLGXegzfoL&X|cR*-D}gOu;<_$pISDqS51#Lo8Y8fpK3@FDI0zy~>KQwr;Hl(>17 z2H_1pS9XvlrS*TD23@EtrsmbOE0M^k$P(g~D>cVRb)G;q=@N{`A{kE*a&b%}UfaL1 zc03xd*!4L&h7N3i+JyF#AOMcc`Ti~RlLJxj$tG1H=U_TVEH+$BT(7#<^`PJYSK{#f zB<3UcK?gUgO*?>*7KA(sFxgKG{A;bwsrjBDcUGI^F9h@7;cA<3O53n6OBOBUAbPXl zNNORP{j?{4p2EPbSZzJmesWE}nor`4wACkn*4?~WGq*;4>#XYBzdMnT!0PYX)n2@g zaHbm1;|wWz9G|Kob9a$sRu|L8%wY>qvd+#1`My-cE#jV6p2FW)PYA+^g;ICEiRJZm z$ecC|8#EpnAM}S%Y?fPMqYZIY+Go6^F~~O`(am+J^xSQ!r|HS&0Za|F2kVxeH&NK8 z0G9;77 zbdSq3^mg<4&@h-6}pLwK_LAm^;+$fz0ZsVGeGLH_yZ)oBs&%KDbU2voLqa{k8q z`%`%J$#Jn#89)5UT;`$?o8`*Y6aDF=N+zKjULtwv^yBgiG1~Fyf+Mx`K}ioSU8{iY z&->RN05~Oou|{tm;m_)VK3O@F&1N2^H|H(e&EU3vDsdy*@DH+1n-l~R%+J~^ly5Co zOFjYEt<$>4oKELNk7q^(Mvh*|SxUyK2#+6Xe3C@pnc9{{^6U*vZY`g! z{K^%!yv#D;_+C`4aC$dw_^mY0l0FrR`wfC(x-ZJET6BSzY-VV98Lfboxh zr@9ZQM%X%LJCh1i3i7haKFOcOU;aY4Sbs3N;Trb~Zfl6VUvJ>_Xmcs@p4LFOhwfM$ z@{Up6Uf)|)6pu5Go^?)gNDcsHWB~qm976+)Eg42fg*TrQ@f@t(`!}W0HR;?XQHrf$ z_iOFy+($W+`M3aDYdZ))b2V%C)E|ZRwLw3DbzJ&D#r-2^GmJ(qklW!`e|Y972(sD# z`qPfVDs#-p)wG{r<5NPWN7_tHRB^31^DV23BafYNUm1x34Bu{9yLu#Z&T&%!70;6= zk$vxeQoIFPEFJ$!bCF#b2I&Y&v75}_GA!xY$7nBz!3EdFFD^T{g@&7(@9(EOv@D%1 z?ia}s`4(7i+|^Zky^5=^`w?~gelsH2CMLcXmgn;UJC)+kM1^u1%hO0OpG1$#*C)Hi zB_Z+L^!>#NkZv3a`5LHIQvMQn^?Z*lh|hY}s5GsYE(9!ia1s0nq|t5XO2#utyz;wO zY4BTF&L|g#S>ysU@c=^WjJgEv2xyh)BIMV5$>`{8!rn;%Jv<@}H4Dj?jB)p-G95oR zv)#{PcmA5L9cVeMPfOn>2&jimA#=17oI_>UkVe-_NZ0bxk_gw{ca-DH+rr}Fk~@CFx6yx-y0JMi{vHr+L?zsiJaG}2})v=`2N+&M%jXYX#{O~8WJ=Frf*dbc=bJ zTQY4rcOe3xy0;Us(BFSTY?4QVlE(@l{cG;X4ki{Y&%xZ2tZFi7%r% zWJiA~9wM%O|CER7X+6GdIn~SnPY7~KK;>V97YsrBP%SHy#Pj3_l&HTgi6#;%NN!4_ zAbEUz3UwR%X$bCc0MsHOe z^SLR}Uvr(;_|B`DBH0EpxXmOD<@6;Rlp|uvy_85o;d)%&Io{Qe=IKO0r}s(n3Qn!x zZRp9gtbJM7>#{W{KR=P?le|O}-bjaZ9q?68hTXg*StRa&y(hXJ;$iH>afC>6l|w7b zCrfT>IIfRLp|mwd8z?+BvzmFJoV(!(C7?}FPEaW!ueL_vb`=^wkHvV(?#+sVNM7E1Dk-5!*Et2in1{nH9QB>SZAA@?>Ax;<3;Rc%c}?{GZz zEHljof)5*gAq|{0g5jgW{5%fDyDVjNLJ$!_t}0CeY^BFjhjyC`DkXPGU0f0XYx$-Q z@z=Vs&r#~onf<vq>-h3HZg(10vLJ zr79rPhG)HJJ>v;LIG8fS-)>O6;u{N&LbADty?j|k9uA95kG+`KyWF@>>RK^g^@Hm>F%~HC>9C`T!Q44Q7gkx z-F(lRolpbHXM2xKDoWlLZRQg-x|iP!pY6zhem^>*G13m&HEQ*on3s^F-)A)YW=MaqK4iY52HaQyI?!%efizypx z@?BfER>WM|vx@)zE7I&;T`o4IwoDW<*vaPVo`?CG!KJ0LPumHw|3;+5P^QDxrgB!| z8HCS9oJq7ENLm0iYV44=SNv`b3bnADE#l*~Plm!MO;|RuNFlXdq=!w-#|UrG7SmpO z%I=R(`Kr%5+4n4ruJ7PhpC4R~4{U7UccAa0;7BWV*n&9}LeVkYWm7GPpU>>w9IUHw=fR=AI(3=rKfMrh0tb*gd)l+Mp{lhU4aXb*gnwX+ybbLQT_dKV$|PT z(qfyjk%)n>f(IFD+Emw;MWx9}Ul>;6G%Z@*qu9GSE3FSBv*lTNwElWqs)s#oPwlOj zPjKmzw{R@787~-mB@YI+=IwUGEXYA^2}BEiB?j)?%*=BX*)Zq9f@*~m83k9j%(Nvd z+IT+gHq4q@Cuz1dBrRBw{i==)ta5&sbqeLQ=K|lK)4Br(ZSi*-VdH06nd8LXQw6!M zIsQKh5CWg(`Jr$kT0ZCrLfAmWRUStQm6je zvOtA(Zz@)J))V*AwTGzj!O{EQly?(0KVVsijwiKZ%)1(1Bd%J$L_{OmcYY^7PTPSP ztTi=_6H|!9!~J_#6hb^~)z83<9q3sh|Gdn+#?AQ|T!p7%TKWkaQZVWZlC|tVIL9arxWvc6-9+R{7QXfGU0&eKtgeB^Xp;5e6B+ddSt>>!Y3noup84;{kM9crii6)o z4=5@7cN8k64h z8_=%TJ5zX3Fvct?n)t3SB(-~-ZAMm5y*Kt@^g?RTR|0}`M@}r%BVj-!CvR9-3dk1{ zji*PxhnT@|c2V}R$hqQ1FAh$0BAzS32a#S%mRM1nf`9qu6lToQr0>l>hD6(RJ_Lb5 zXdDy?R)(n_b50v`v?V$(04qH{pvSg7iGYDP5ZW8v(Z?bu5xyri`H68NsM+YQSa_Y!CQv99F!lwb1h>Zs<2Rg9; z-q*3IEn@VB#|jJ;sPL>~U5!7Ih>7dmwaG**C$c$aS4b(-To3~zZ?dhQNz^D~&!0uE zl4wk&ZxJZEEGv}VCSh{ZKPXw3y5g?*AgN@;D7n$kfm&*-AV03{qAcabd{@0v1!3@@S!XHxLf>n3>6_7dJPUZEhw4nM=iCK}-keDZWSwz!< z88I4l%1lU{poW;_K@o@^omVM?e`y_%e+kA)Z)qk#4st3@7sz~X#me)al@lIE$CX!p zwxWBE?=bD2En(8+%$sD@@xY(w@-v_9%^$7eKE-m{HeD)TcJA3G2gu>jxcBo85LJBq z?hgm;@T1}PkpV?~eFW0s6yQg0(Q2}YyM^(PKwC2EP_<(+Tz`tYoj%d!0g!$Pbh}Wq9x58=QKH3H%`|dQ)!-SeIZbutZnpR9| zF`)||*EwHvc-Tx*POqM4H-DuKhV)GJad9HCya!j^44nz)C5Anxdw<}fu)HiTj4A$o ziy8kk%iwJYQ}vuglWi;(E!jboqG{L1BK2=->E55@@^K0#mYA!0ub9tkGVolk+*XCF z4=g8`C=0%u8il%g{@3vrvxW%ot%YH>en~;VhCOGHV16BRnQhnmP8i?Jx80ZbEdwVqgI47Ptq2V8;p4)d@i* z-h1xLc6nd^Ad~BV1R;=}|A$=2L$T>I$6u`s23Kkd50#bFG_+p4dUdsORekji5{Phu zN;1r^I1hB5G{2EyX@?gQXGTS-ze<5?eIK&L5*nSj=kUXfUwW(yX7W6|&B5^2V>e|E zxaxhv5(M1nKA`j_v7WQ#AHI|J(kW@e%d*;Rj$$a1_|f6sBa)=^mc4|zD+}D5Bx%ywOJY4+P%>lU+S5m^`z8qw8tBF~; zV?-&q4s2+?!^Ep+uYrZ~0io&r(ApbpNXwQaPvQS2H%`;IWA9=(4{?S&c@0jB$rfJP znYUxlY!J7#_$E82*>Z#SU-4efd2B3@cjxi9xR>}t&8Rn_sty>Ojv<iO;YT zwXopYm-+9oPhOj@+ekycY%R|pgmM|VeqyZ|aQY@^@X(9R`fi)v$M`xj5_j<8px5qI z`^_mG*w1^DA8A8iXcmFaHF1Gnhe^I+PE%7m6+j~pQmU?)WxYqluT84n(RcoX@~bm0 z@P$A@K*buwkzAdyY|`~As+lzPZ@INmN-oijO z?t*4o^CO-If4e7$e;3(u6#xcNjXx8#Hof9lNdaNM+GU&hm-dJ)Sn#kOw2}6&sy`2n z?Bphi;_wd3lfjEL7xX(`wxiK|4&O<2T&b*Lt?(nx(5O{>!{YMSUZTN?_}1rdTui|Q z21Gk}CL`FUMl4k9LGBUXSYL$M$O?Q?xc!f+Q>R$OX5^IAzmMT}XqXDjltDFHOzfvB z#X&yk`iUwl<`04o-Df2f5!=9k8jNHkoZbp+lCj}UbH!~wimoVe1p>Y=JPU#u@a;zL z-HD!1hOj(f$~iQ9JdYX5Fmt8q(Z91II?&vz(I$yEe#4H!9dSAFB$5xA#puA))j1=9^@`hDc-cfv)cM_*}(C3I^1v+bp?8@i2fj# z5$e8z67%8f4u9W0-`pn@y@{o-3mjdgI2@fVu`#z^n0=Tcmi+adH?ty-MGvqD zeh*UiMcm#J2vW8@V#N)Qq*UK)ehVAfjGf>Uun0 ze#%PGe z$7=azx|E_enS$8Ud*1|Cr;pS8uP!fW&k0)^nTJHCmPKy&%NUc^{!Q+OVRqeNe>Z*D zZYdKmcM|u{2VYW|GkS|*<|WLjnatF+>X&Zq80a3t0Qi-2ko(?^YeXo=7)Xy zVk$J7lT8(?K}SbvH+weRc{)2^~rnV$X=kL{Zn?kH=D+3L@U*Lx-U_c7%3w@1B8H&12Y=zG(s z1MxP|g|xos{Y@DkJ&*Q3`uaUsK_+$inzw@a?G>wlnl| z&!!OXi0+YaB|n?~jz*`&olE!9UGf>4n-Y@5Iiw9Wxf|Y}ckwUYe-V&ptz7Fj7*E?h z8OS|8+xy@@^Y1jSzqZ%j&K^P!+Y@e(j@EG;B13*iKEqi)Fy^&tcu?zKa$MO^A?kG; zk!I%h+lE=_`PJ@l+vdjLJb%|2-Qi@(^39Q>(>-1^2Z;8T7m@1zW~d)9iPWhpQguH> zBOj={(@nDz;+Zf7yecc~nC_MKXX>Y;c1bf=J^d*WF)fa%8|0H?ekM@vxL;SZ$5&m` z)mrB8m~+FWe@rILx9HnO090*?fr{|qhyOyQal4_UJ1FvMtnptyb&poek1k+Dps@xN z1SE>;ou`!Ip>8j*BT!P!FST)*E0dd0hwWyD&xM4sK-?O&i#+nU2>)NFsV6)*r~*it zztipSD(BW!|Ml?sAfS$@3uW`RYqzQTpZ+wqEd3;xN?p}L*T2DF<*H}4-6KsON9fak z53gizKIS*1xB`6&%zuQk=l>f_0q2zUxFW;=C42wRa8Y(G*<03$i*4P<0#y-kSs$OoG_w!<@J&dd603Eo7seS+Nz1J) zC4*k5)=nm#%J?zc9Uamx_003G)<2hZRB{?7>Ns-^vT^Us#5a2D>Hf~UjHAiVeWKWF z(ZzkTQE8(;K_gn~ucKk63irl^0;S+mF={5{0cb>IPv>Kn=-|c?)%hC1v z_31uR2aaZ06(&fc1>Yi%Bc_?4BtH_49GD{^O{t*nMqg!jAd`Nnidc>v_^`QC2#>u! z+t?)jiQ8)q1Fy^GA*Ku{v6ez2h>^22aee3Xb);SoI1C9}={Wj9t zSuTLoMczWsZXQnF-Z}b^m|X;gu#^zE#nk>|Pq)XXbwey`ovSRvC7tIbq1a57Hk%tS z`BkQ(t;AeN_44t-IMObr|H=X<#bhF8UHoW{-fK( zk9&%>*|&CQGh%ztHO8l7?zQ#`fq{ONjLZ=@jOqV#*qV--X%tz?%m4rj&R!7V|fP_vXpx<&wQ#f%9A=Z_ZP_zl>(qZ%kEQ1 zJ!IXC^bEyIL4)>rD$H{IWs+bA4kl~2>iPC3u_5_nfMN%J?QHvJN@-X}oc12fV|Z4C zeD{+FHtU{P3wej__?x{?WHI=&yl-h!(m%41>jrU;{FbDZm7y@$>wMM*=Ha&|+((aw zD1p>)kSJHoht!*W@`O_w#dYiY3+;ym`2KOsk4qc2U@hMq4)+eLYMHpNR(uff#vhx1 zSd~{Gay%lWO``!KK7svxC}LS*4*T*YO+QPk^(G45Y~AftHPI@czc$LvDF3lL)7}2G z|CRrn=|}E8Ya92r38zejlv2KyY$rX<&kb3%b$S{ch(pl~h>*%V(u#Fz!z}lD=*_<- zFJ)doObJS=7`hmMF1c(?1ufm6F$WGUp|j^#F={c;?n6|llYN^8P+;KSU^W9fdC&9& zzFho(r8#-UODuw6eHhvtY2ib@Rdm%*2IHi1RjKGNnoM-9uR+;`7CK27d18Ipf!P!61Wwoeoi zbh3i235Cn29X71c9j-|`qJ-C|rR@M0@iJk0fk|AX*1@eF=zpNT?`Y}$lwQ~)9O$_h_|Tt!>}lf74z{DR@z@f_*E}@S$S(Cvrv8ci8DSp8u2> zQ`jaFLJA6Y_|rivKZm)*oPLuLl#bk=NifsoP`mx{$?Xm?|G(m$zuJ+x#rl!ukBTo` zJGNmJ@{mVgB?=%wolnOF1^t_2!VQq}%ak(YoX7>4E_ z4e)0Qfc^teB7jEgmGEWTkKlha{VFPMT`z`kC{}R42dBs+5B6B)Qk%J(^{WrP4R4Hw zvh^N*^P2tYkr`f4jco=vG@6 z?!o>U7j2Z(nzhi`8NrX9a)0I*FAuox=;BJW$EzQ4>pfa_8MQ8qR&_io zoXB#EhK(9<=ACKxS~^ue|JwC;4Mv0f5G`j0gZkOJ#4xiOID&o zEIOJ}b(G$tt@7RaP5ncKs|8<*f*7knnVrJBBOc0pJ5!`!=e)|T5({ccmY$` z{jTH3-FJ27PmNLpdj+h!o`r4#C@!=4?VtA_LTd)7nAg->Gr!d++g&kn(&g@sn@rZ`i{Jxsn|^U|N2e2q3~#+P8g5r8Y|h#FTQ+_YOcfU#&JgDJ{7L< zD=Vk^Vii~%{8X?4`#Ko{B(FNs1e1xO1Zc$aAU4^2Fku%&E!RN|tc%d64fDZ!Uq2zE z{o+7zJ#$g7knp}U;wAp8!=Ly9gE0#H%cQV>(^81Y7{Q!RhYw&oaOBc`pXGV?kJi#w zE)43s;5Q;`%91wyM+^&P#=StPwx+Zyi(xhDyweUZmIk93M@xuzImT9AL@@dyvkCw_YL;F+cl*WI0f^?+3_DHCp#TJR)mA|>yNdUYO|xd zcX@1YI57C`E$Op}p*j|9BPdtMjGqLVlR>T`Fdd6?wPgw0(hzV!=higx^FhNp?T=$4 z-~XAY#GckzIF4iq+QV%~WEQZoh%DGV;877g-qYoAYu}r+yE0l30S(6^o~&MCdSCnx zyGT3h%C~6*k&FVF;6}-}PgOPiIx(zi4u|pMw&DE3f`8ZTCl(i#mgPp8A%=Au_KFgi~4P8$8##BCzI~13*zs-LBjX1=knC=TRy-A7*hA_UMC`nT-QN2XtL6l(mIE&>KsPs|@E z2p7HKs+pH4loOc1JM<-1oDYZlLZz!$l_L0T_<%qBQx?>rY`ZcWl5N_`H9{?j0?z|B zGRA*COlxU;N zW{zb6j^RN+ZasnVvZ*x>alQ+%=&dvdvbrCkqK6@ksfV0rTt63Cv@@_^0~mq?Ncf)2 z5Yzn^abfQ!_fSNXEETr7N; zDjdk5p$MUZD4C*Pl=p!})9Tm1K0ja%+(*kJPmyvepe*IB&4_HV5;^t_EXC`D6Y5BA z{td?@OW>Jxt{2$(Ga<^@Xn*9|=+da(Qj3MDG6C)JwMf~vA8v_WtsfsP$f?RDKGV>b zeO&Mng09|gol3mCwVY`+Uy_j<_Leur?&4byLbW_!CLwhRn~?ehk;ahwN344^=48Li#> zwtFL29GYVj_1Q?6H{FQ?2H;Gd?OCTDzQ|CPMX-RxjGqhXd3VG=ln-nYex_XS-zP6P zDlKf!K=Y`7%{aAy;hUmZ4Jj!+XgpBKc3b=V6sUmH^CRwd=;a-Pda$AR6Ki;Htnl3u z@BP08Lgl{|s2!fil4wZf{;q$t?5vcnCGACc=?wM9dHVegG}A?+VJ2M5Qm`GY<%%dE z2aoKh8en_SBy?92|E3$)wXgBXf9xVCvwJLI{g|FH5bZ;EbS9(8sOi&iFDSag0&|lI zHac`f0ClosV~Z`j>S?y3f`dqT>FDi2wDr3;fND0dqAK)_ZN1O@nM;2@%E&KbvqO_k z(AYcVPgTERkwZ~c2pl}RgI;7O7d#XW@%a0rmUC|6-#>}+jlKhdSFN=cC58AJ$CrCY zXNg@J3sZM+@7R~R(Ht;OO_wxsL-HlF1y+>}$E)$(g=B!lB6F)2ipl|DZ_Wc8iH3`| ziwpDq+--T%13Vx^6!S3F)ACoS^Gt=Z6HqwXnvOQZbpL$bse)LaQBy_`L9>&SV;tWB zq<3nY^gksh4&S|jYy4i#@cD~-Bq2PV^ArE`<0x`X-2bUEe&r5uNz;)Ez=(II-t*wd zNr;sdWy%jh^JTk6?JQt=xOME5ZlY~RU2MVSKIPfJZ@hZN+Emq#@GmM7Wfvi8Ky}-Q zw@||F2=4mU_1Y+5T4zJ~`QNwQJ>MH51l6lr@L%viEHnq-!{4s3@bo}o1G`msGuLmr z|1pkG84QN|r$I5su@h??Of~?Co9VvV@HM)df&GKC?c$@v}E&xV*R+eywvW=@eP1Kf>zy zf?vO{N;o@WN)RvM=KuUC>DF-YL|fBR3xow{U`QZ|f|=6SK1>XI)6>=OdWrl4IS>2@ zSB&A3^?6}MU3#`^klW0~8dHs;_+tXutjyTmi@O+6s0|{>S#`d0gbW2~uH*$y)NWB2 zSUjjXJ!Ezw#u+#8VpD@@bTnNtPeK9@0OE4zbx#Zq<7w-|0dDBQ-Mz% z-Y#|jY2Pvg5Sl>ijSisS;UZ9c#xPM5bS)Flxi3N;waE1t|Furg?VfxVsF(n1Q#jE6 zs>(UiOd=!o$&tMz3{0(8!7OxD(IL6BtdAU_?m_RK0p#b%(~dEs&(U(hJ2VOH7(oJn zdBn>sx46hKgMoW|_!r&b_4Cm0Eq4YG6Z$v!R!5aUONdU{ZsGAWBiCJj5o&_Jo;qjh z+szGA;s(JwVgy1XrehnH%(V=Hw5XteKX%KBc-6-Wp?Hb^EcJKQ0OH*;$*GM!Mrtrh z!Ab4=U~dbY!~uDHO+Z<{juV0Up(qBL<0~?_1tgE9*) zvTCzg2m73VxCJjuOlo`nA~G-%NSl@pY zqs#uO6w3kgZ6-tir>#@`r<+fqwu0Wr)t`4od__t-XPs{nrDv~W$H-7K0Nh95ed7~$ zx1-PPrtW6oyD5xho0>8H`Abx+YN2QULPeZ5VZd`WAMw)zp2MWG)xZ>TJJ4_txrr0e;r=IK;fy# z#nB$`>1i?Zr`-_fQ>MNj&8(3br~`d9-eYXln@9G40+E^d|3NS5o{ zgZ^d%v5m^57)tj7kxwBr+YcbcgHAz|)OQ3JJ}i4RbIQnEMu2ReKarODh;mcH<^ns9 z42=>u=KRkzobK9mX>}n>*H@i?ZEN!0M{ZC4iFu&+V)_s#k0mx8i4)C`bTnZeQ!Ff| z%86};m0mtCqLJ&PKV_so7li|D%Rui}!MNhg4mR<{lFVHY9h_GI#U0gAOq0}D!cVdE z2OihoFanXsI`vgfl$@JzmRqV%jY|bReiO61)S=;~{C`9~zC^Qc!4%Y`ixZ-9xJe$? z-Oeee13SW!)W9a4MFFtS!4T)D3)~R+U$>k?u|bs|#RpW}2&nHF=!C?f!R4?;vs2Sb z%)rLumhC%jVU?lB*0Eio!3hT!|3FdB=2HPVw*bBf1uf;#?W-$(tErK zZTl_|$aq04e0BqldK+0uvL0on6~KT6_R|vB7T>WNk*j0cF+O1E?vCwyC@n{7`J4E z%^U$^C}c~hXcj6`p8M~LX@u(NeELAKbXnqDSKFcjEoJ+7X}j{qTdA4ZG~XzP6)E|w zTjewQoAdy4ZB7R)UWRAw@SVe{Ce@}0tUfkTl(DK)M~lD{vySUKgXQJ|_mTvWW_mCz z!qQP(0-4bXoP2b-flEax3?Z|gWYhlSyQTIjB zqGx2CmaQnMJt~Q<^Dtr@ZtisS1VI5bj=><&`UKAapL>9u?n$Z&9+Kh3CyB69>6rv2 zIeIGakOBsfcihT5ZwpS4D?#fqvVh@P=j~43%EL9s54uv8!7TA#xRkijFgcucaeGvO z7dpIDG)(w%Op?ih#K2No{8(kI*9sTuIQ98@j#B+9Gx@G~zeVD_d^Bu1?dGSo-HATA z`@a}3cR!}QJ$j8Ot4&K~HA)U({and9|UnFYbQ z*d%DIdv~@c!1&zj0iNBnNMC zfCs@r-2Q>i4S7hakO)PVQG65Rr#&G4VJ3zVOXqspzSkT>fubR11DJJm*ocBKe3wQ= z(DaE(UPVm}f6xytbLAAXBYZ5-T7(dxb||5t0sI_81456OWF1#lrI~bfA&jk^YSzo{ zRaADgeS1?{xGQ1Jn@Y zXfNGLGMP*to*4@Ldb&kn}bM_$IMJHfU^t;3B;cCKidoZ z)7fHPPF^blXaDH=3!tot6Tif@|6|afp21tS`8Y?s&Al#8iKGkBNuwrW$!`xny8~J^s zxKR7gT<1UQK)VMpQNgg%omluEjZ4(D#% zdsbVUs~z57P0+PVdAXX)Fc2Z=8*F(Hv#rqH@Ey15yj|+-dRN$qMIF}Tgm2~oeq-aP zMvBol2$b7Tir&|G|1+0QI%fQw8h^jSj*=caV0gXp@uBP9l2Zia7+u^$-DU1%tvCsM zw50|F0^@q3(vqJ#;orHf^*Az$8jwZ`QlTi$%bg3?R4!?2>oIEIR5>g}qdEF)DV;tn zt!RquEM*$rxwo931f!$*wq2v<(fOLC?to0nSnN-e+tnJZl|g43>&3;4#AN<}*{o3? zXO=NNMLMwYLbWNpB%l8(n+jm4MqH8(1lfSVwiIivEz#SMfJL$NRB}~Q8kQ}c{ox_^ z^=cM%4sBvlVljgU&Keq}mN1g!ghS}fQ-TFXU5*KZ3f883m#J^I6GEPE?Cc)X%Vt`R zxr|t=QfJLx=HrjXcwgq}*SbE-A~s<@5BK?X_6m+k+bEJQkSCdW4|i zq&oC3$aqLZ+d=r@SL8nzVTzgC@~})}d0{$65qjXlMkk3E`$z0Msc=mBv#m+DFZ0ju zJtJ6WcNUcpsn`WGRhbqhPqs0&>*>7y>|#u$<%1% zOEBDezp&OYhYNz%pjiCGNNP86aQ6{0Bl;d@w(DAP5j!0RX_yo4EKmK5>G?-Jf%K-T zjb}PYKp>F6u4VKcsK>JsQa=_*S$Y~RU=%B#6bdeI?s zJk&tI#LxuoLue+&pxsGiQ|V*Ar)w9~2&?oMFhbC8W=D!DqKpw}(O6T?mL2ugtioX}j- zT#18~`g%Je@|jfx*$-Qjj~ox{zPUMTHqpyL*8EGd_YLm@0D)S1s=DW}o5iapH+BOl zb6lrZW`+AxFIvsFQ`5p-5B?ud?*UKs`~HvL=Nyhbl1&^W6qzCOL_;DZ8ChkoC_C#I zk<7BQDI_6#J0&YSviHc$$lm|k`}_I*&*Raf!t3Sry6*eF?(2SD&+B?Jb?mYg6%Fwy zT<26pu-JKT6x7_#8@O>jt^1La+scU9XNCSoQHQ=)kGx|@2nk1b_OpLygi)Af5~coR zoeC6!2y&D_os2j*t)J||Ginn$bw^%=^~=ciN$yB{=7-Eq=o*9H5X4xJso|%Z|{uK za@IxwhYRbQsUsTfyy{d0f!o`8U(_D$drc&)W@{+idoGpy28f9I9za#BxVX6RGQ0@t zo^dO;0UgQK+;R~M))qV9{PCi?;Q$>mY~`Y-QNpk0-#1WDK!)K2GkB^e$NBzYsml`b z=Rpm{tCY|C)U&sU!{%pj8Le}Xi+WulB|cvF<6<2@0DUo;G4UE17yod#g;WKdA6un@ zH)AKRtvL2=>>hYxB9_MP9Zb3I?07Eh{IfIgnPx1i<=h+ap%TC!&0A3qta*XFjiXB& zW$}?W7C3oA9x&(!h*$)W4pq+&^l*l7667R)ezG)kdDX>mXF#6kt4w`GxXj5DE}D^g z_Ik==$Ihj88OyD`aml>T-hUG$&-FIfd+jLfps0h`PaB9v75XU z`(nf4XVvw(^zu=U)6-U(bSk3lYFVeW?rkYVq!*|-;&hEfe_VE*)H~{RD!%AV*P_uX z$LYkYSJOFlr&5NNzR7cde!j7BLdUQ=E=Yc~tLpV;J@Fn5_UX$PUG$ve9w)~7I&2uA z&j4PUKct(#fFU2ft0Vrsoa#%!7j8rOApBL1KJ$dX-|69b>VJM#=9cqe1>{_uf9@~jK%0*XkM7!7BuV@^S^IM5{|zUqE6Ou4g?S&uHZc@ zhm*g0rQDFH12r%%9zm=d7BIcoC*@h;;1Le5lHf_8tw-XjZyI)8vu6|ZGMg0n%8@MR z%$`;7(WAAcTyFA^CVn&B?SJEHY{P^rs&dsF}HXW zxvg$~|DH$U%UUXxG%2}Nk#oKF^{;!Hc6tr0TABKr9$)+2H}fK8ag^eUgja_BeJu$( zAky`tcC8?4`ufWKJ#V2cty-p+%u4179EL94ifpRljX4?b7t@1SFB5e-OJ`Hf{(IIy zT%n`c|0w`zs&&}eU0?B#ebZa$YJQDuo9(gThIwmT&1&BdB_% zCOYcl-B$`DEdO|KK0jjYw|n+1<7#sJoSv*&TxzPp&>tZZU~0zg@cZaeM35=~{@jSP zpp=wmHPx)~ZT9c@248ZpfLY!??mQO)Wd$Px1Zm@Ezwh+e8@(*Jy4UI^e4n4p->jb0 z&oTy}$X~G&BJqPlP#vu4151<6^T8GRYv05b$hJcC&v$yoYkHXrkR7spBM_b)FTYT@ z>vnke?Szky;o`IZ;^sfkcR_!MPkpWt0l-KBoRqXYHqYfdMecX&fKKeI3tY1>U0)ri zgmJQH@#yWkv=n~**`IPd7g50jk6MbP6Ic!Un`HfiHX1XspB+?S3&R(?;NacUh4`5L zd^#%p$WhPQPu}D!FI=aeRlEhHZR3smjY6@f&ACgyB{p@%-(J%*4ZWa!5%GZ{!e`kd znW=0yH555CyhB61b`ok~t{2cXdO;ddzpJK#l8t%2I_DA8MZ--VOilXfgOaAZ4~@0& zqUOtLYaV}0K6mo(hRUlqVtYGuR{H3FBI(7MAA8IZmcK?0s-i^-j&Hu=X0`aBP3&k!y?8TT_+DmogC#LrUnD2V@%oB3P}q!4cWKnIl-M26(Y z!9@}%tj3*~IInx;L&WpezR$IMH|7fN6JH%aP#68o4;K-3j8B(N@F@V8)k-{r1KrIg zb!`$5_{I<(e*xS4hoMKCRVB066_sp9(0ifx`YzdAEl)XU2o>1M{1x4)AgzaUsVDj$ zaMVEJ;Q1I_eRiTfPXN0nLm69~gTD8^n*cdRTG5L`?-unND#Z3>_*l3CHWl;X4=H2U z#A;Z_<1XMR;^li#pnYO*4CpEF&0gK8C*u=3_C@A;wvIise#Fp$i)>ZLZ~ldN3u6}* z@7MHjp8C6Km&JM?>@R*xj6X6!;Phw3r?L5!ASNuw2@T&EmIt6;MqGN}x1u!zjU@P5HeV9K5 z+gv*XJzJ{pDMGXd7LFhTmF?v>{As>Icy$*@6X6jQpgmKI5YY|hy;z>&4<&HYM!sY~ zi3Jc}jy(en~O!kS3To?{L zgy(ZQ59zxQtXR)^QoyKoaus`(m_|8iF%d%uMn@eE=c?fa0kjcggmY0{pZQlFKzhmK z1rwV)f0Z0DW8|n*n_|m{zB_ME*8OzCVu#~SDhD)qZqr0|RWj0kEQ@!ubR^3@uMU6# zus_)wbXa1dECj6mUb|TDFc=t3Y91Ca`YELmO&;83%ENRab6%a;YVTm3?~U~X>>$s_l;oWjoUodd?9kI9*JifZ!~JLly)V(Jo`UdHu z5FrV`IWqj!`#O-7LueU2+m|xG>H6yz@HQYYmRi`ny>pc$&V+#)fsM9{+U*BQZ4`Kv z`n6}*ZKQuStA1b!zUB;9odZMLUL+jLx_P%rBn>d_u>)y&RGMiIW{j1vLr!8bEplp1 zTDN@!g+pRHpD(XdwT?Fnzgyrm=a{*69--Ac_1<=X<^~(TT${Fb`Kuy3(>o+yAEuY% zg7WLgF@|%cphmbWxhq0qBq!zS8ZkB$>#;Y-6^4+LnOOEHbn?esoV!H4A#H7AI-FSy zsVls%n9IA1Vtq?+!m2C_`mzXocReaHu|?=I4vp(8$BId052JtFa$5sF1#w=?$rqmwQ37dnhq%vJ*S4H$^d9LBz+U|3Y4Q?&`Z#I1HlbS zkb^eH>FB``0w9X~DdJ)f@&Ec<;5D#kUj%31!ENYs$?M4S7+`;k7pJC>UGex-|1|hC z`V@C+3wai71ARj;DE}@IWyUB8QBO=>8=m1=TOJN|y5pu=Z&zaxhR`{FDTn+&uw~Q% zrSAy`#D@gHoWSwoJ=43UW#|B|(6izA*L&|fzv0J=PHHE0B$Bx57i1vMTN^2KgMKu) zMF3$+gH*!AjXOc2S~t*!@ffV4Ndj-42plt}Yf1@Z+?d_fgsSYot*hv{_%fVYFe1dwJ zvs0Q=rzK}3$vdalLK+H>K;Q=i4q@!R)h(u4ABz7wJ}MKzj=qNH@_Ka~?X~KEmq>-r z(iaJ^rEf|B8mp0HW@SJV)M>KphI^@JjIG{L>{3946glrsB`4Mn6){BT7oHOv!-iO* z;Zg(o^G`4EV?h(5%uP*(-CEgd_yw9PiG-1Ah7J01W7($&PzcrQF$kG=P*2Wuzr^C$ zT})XyUBn+foc5cq&7%5eRrZrRjB#|F5PvDl zCB0RRiw}@SLtD?@XCl0~?^V6Db)|XlsFe%ReQx4Cpx)~QEw^}0eV7Ql;4UoGiOO?D zU@6&TbnmiWRU-&(`rRs+IGW4HCc{~$q|~`lTS;S7xfI55s|U=V z@wZ^2o+A9a#*p61zx%k&+x{d&33S~=MRpT*hrz{(T1m$vZdUo~`XfVS z!^MeZ|xL7{Q5s2(H0t8Dcqz_M*2LKSMs8nRTNgjH;Ull zs|ze*XLpN!D*fBVc|L)5;`jjA;uq`zRt6rkaUPNXECx`Pau%K(lW!Ni|CC-!tnIT; z-HtN-0(g5n_OD9cejP&FYGEcmQuSL^IHF^9!Sns4cO};Edg{z|c5WrhFUuSYaE>mfjYrD5P>exsgsWN7?Pb!MD6$ZM&i zPIBNSQr6_RMqR72ZUC{jLJ@9l931Y(njaqe1?Y@@%qRr0LWKBBNUnXxYE|)Sl6dD# zwR2Dn5cOSC>)|EBJC6wG^2{zHvgwg{#T*M_lzJhg(J$RtY~8$SXx7d?R;`tALoOGm zoCUdjrl|FgR~XL%6>`{XuL1>9%4q$qX8(%Be+*zN_f-$E_vth3>be!yV(|RHNUt69po=sX_9b8;uLqYs69WAZYg51XAV2>?=2K$;&hj)p zEGw{IT2tS?*wtx~#GVIxwSjyb{r^VB#R7Z9AAXXyu?jp@%p7g<=;x*$Pl5UP|0*Dj zLX25l&al=pHebjN6XGQH@A*#h+*Pe{`J&&~vyYLhr z*0`43-mb1|4v)&EVl+j6yWKtnYs!0tR=$=5;m?foPc18cu_&Cg%XQzHO;>=ysn{v! zh@FEbKY^nG4>*Tsl+ZU0j+n4#!twbE$Icn(0Ol7~#>2xrabIiqX0)Ye%5JofQ3oQ_ zlldt_ZQ}>y)&6jBEd@w-m0?JLOwbi%JGpgmlb4CPMZ{wxQww|{wS8V=*gSUJ=f??U?8c0RM+nh`Xgoc=`!tK=BWVcGg{hK z=UAh+0iW88C)1aF^8Fc}QG__g@Bm=GupbL!PtJq1eHUFuXaywk@MsPJ!r3BaG34%D zU#5F@6Q_|${B2u%wGa1JWL95Q8%otBK<9@wKmSUD@RiD{K>^j)b8$_vqfZa=;d~ zpE^zVa`>V-1DdryjibFeES7H42kI6xK2mfQmsRJ}QQmq*`;2MXPv$27MUfJ-}Bo4+awOT}=Po zB4pjAo9Wrt8J2$6niw~%*h7yaELD#|!wFhrAq+$?omF{|a*b3$z-U9rl?SSFAnu*9 zb@tuc4*J5Tr1f%K(eV_7EFKKMhwA2pnHrV&js~7&zApOOB@WDvzyAN$^*}IY$=b&@ z_f&nUM^gt7P=AR}&Ou_i#PGN7p(&d|y5>5lv`4UfP7T&QQnsO`zJ4%n@sJW*=W8U|CQ>>n`id=b;I&9 z2PdRaruj0^w6ybz#=vH1AR)D3xuAhVoKZTWd1k|H0`D9Mk-fK?VS9;iObqmc7w9bfcS-~8?$=Ciq; zM~f`lu>QV(O7A22?R8MFhS9`z6Gg`&f$j$wTG`0imZJuy6s zNNtthZ7~RmlUd^qIw>}Aj`$P*{(MCY1*wk0u;FYv(}Al-Rs=m zvnub{mCqupRc%2Tt)|q&7aNXxQc6$Ui%Q4xeEj+plZ9=bALD`0Mdpej54-WL{De3! znH0kFG~l?5n`Df$V;!g~R?TbeC^vJyY<+0%c=|2t+z(xu{dj&a5<2YFm;M3QYp0ZG z;z{+4+o`n-7C#p)TE#mIZS36{ONq$xl42Tw$=N+18AViWpP-e6j` za6NVX186UR(rY-ku58+(p)n$n=!@m`2c(sLeH{(X31G=T2xDtDBYmilE4Mcp_EWSd zr<(OkuA$7+zIR3kTPYcMKAw%v6oZuMpghx@D8=@UE8m_>)cf=cQS$y$2BKnAI@nfa z(ZOwtPZb0*{I$vNFL%qy$grjn_pJD&voJ?A%3RWXGZfe$lUayrkk6o+1y>m z1s)1Q?3~w_d)aXf!HO8JZ>#8YePP1=$7K={624Xx-B=Z*N{FwsRZfy?@#<*R-9l6sN-7j51@Fyl3 z1OCSJpkSmbU{t8Q3e5ygn))giSxvSD82_?7?-JuH{OZ*wRUz|;mizVGg_F!}(~-4G zt{ZO$IyYItWTnKL>H|32F!AWW8T{@aX}}t{hK3JaikA&!TtT~Ae1QOz1z0>AFmsRm6yiI!c6_R$yA6*K6y(e}_b;x$XKeuZros*)>A9A+WrN&~LZ8zi zVTA}GJ(W34q9o7Tg&3*j<`=q8FVzO@-R4IF*HyOl3a?A66cN~0365EA&o7xf-q09# zA3HNLoU9XPk&75=CTgJ1{(*7 z0RV>JZt44y9mqmrtj}MAU;5bss;}S~3Vv`OCwqHuJw8rt_o-uJ*nFP2bwzN3M4shnWb)@l+C@lny%Pv z^p^$X$!>hgGo)F5r1iJnMlhRMcwL>0EVm)_@$$Qda}N(Gc|2anv<2XP*XF|(hG&eV z)xCQ30{$6%nDGrfvT*iY;=?U8mes`%IP~&5c~DSVdLE{pl8OOrlp;!K3xz}HAJE>S z#KV|I>}7T1>YxF6<6{S$Ggzy{H3F_8=Htd<%cb`LT9VXYGT1d#Hcd6q|1G4AEdS09 zh)w=R{iQYNiV8lhkWpQX5W{IqE(5Uav8a1&<4qqbod@NH8eCI|?Q4_XHO}1~n>^XP z>?~$h&*hnAQa>-dEH-H1If{TDBxQNl3&xW8{j0tZvyws7yfhJWU>%3hh7JMVF$CKy zjtjJ8`aik^Ue4>cw!+=ifd>Qf71~gyiSyQG`2HA~SrPar%>e#LS%;wgVk0lZ1Zy`! zL?Cc7d1(c24NaK zd2hG1ODirb2pEWg0jh74*)=in%$EH!#W{1LnwM3USu-j#O0q%&uY=1y^UiuTj!bbaq1N;W7CZR!iWPHvzv_akrMYdNk{Tcjm!sf z-}pzsmnPGFBC5o8XZPF4=6wODn4ZUtsqa|2r0rsQ6O%;vn0pT#**@d;K;?{uPfznT z{dZ}k(bVyuP7R(mwLdVNp9DzN1MTt;Y|J<`W7X3z;vUKF9K`ov;mCW9sQ?Q*8p_0V zGU3f0r7a>K;;MB}Wg!g3N4=TtoCf4+(Zyg071X@0hSIvnGUjA8AxwZkHmjs1Rn-BXet6mFSV2BKBAMM|jKemjr2 zuYKV`j+Z$loP<{OcUX3H`jmBbB3R7yUO}c{?d1_(4U1M0rGe0q^VK zjA5-2c9-2yjbvV04PJtPsw(?PCs%nfjKP=lEh6v)9z#rBjMi-1FJ!>xS{a*vd$JMUEP9n#z3+~( zxrlO^31Xc%QeEeB(D&Pqb8bD_Qns53EPbh)Vv<}$#9H4{tPRZ_M|MA@384T9qTY^p-US7 zVNkL5ko%#GX}7>JFZQH(^Dcpm%`3mZRJe?G<}7P8{x!>smspd*EXULKTE%aPhysPH zn5p-FyG*4><&?6j+(iz?2cwyJ%jlzhljs$nyebK^du_|;Fq+QVjm9K%Bh+@H0Ipf-U8bPslG#O96%l@^ z%dm&cQflW~D9REyye4q|+|XqrsPiIP{IxKu!uQyAJ2;vr=F6InS@BaHtgM513L)CT zo}*4{{f)_Lxv-c8e`j4%at;)kkFMPQ`n$w3PI{$_GPsC4)bZfS;Yi8T$nO$ImkMrL zrm+#8D&G0O%nPoV2G*_PNje+OaZcU`ZvHJcU(zA`2S2EC9~J?reP!0VQ;Rvgw)ZZo z(~}8D2C&-l7ci--yljLU-!j1@C6|Z7-EE(9wAdfKtEE;Olb;?iJ(30LA0k7j(hwgO zYbt3;j@gBteqS7U&@y5FYw}*;+n*;5v+oTo_~wd|`R~x>k@A<+sy+6qFpnW$p478` z?{-`oc|&Pt8b+X#RSa5GI*a=O$EC?PDt(ccezbm)vCrbD_I}UiaNkSS5|<$cdR|c_ ziu)utDJY`i8~Z9QPa}eY(x;anm-x2_&*c78#wq{PZK=IZo3bs8x&Ep00_(0!LBcO= z3r5Npfuc5{F&?_sWZv*6=P>@UNj69^aYebln^866%%AxDdphln0n$6LZ~r;_Q|GX; z)%8SgzR!fU*Jsdemof)K|DFG3`k)W*#pWMio~I@&hJpptc^dm?nn~c7@}!O{8 zAz(;R+HM2BVs47$2F{aBcSN$XOF)WiHZL!1MGVD~$Y7vm^zxsudA_HJXqp_&?Y_$)F*8yN0 zhHdYg^2dBGZQ%;J&zt93Hx)Zo&@fp+nC#OI-Y*Z`YuFX*#$OwgAOG1J@T$+XfS+;1 zm+j2hWN&KT%YKqp?Y*f)8v3&ojJ)FcrPU|E}BqCax&HQG= zF2~^q;T>X@evO5K>mBQk#lJ(dLNgZqHXVDG>rRO2tPuu!^q2GAxtsy^c*m+!dehr#%$%zFApU!U398u_b!rmuOZ~}IMs-!`C2r;! zGM>gnI(&DMzu=|*x9Q>8AQ_c#)BGAfQs00U`Oa9uzpd?gicz9}*o~tOf@cV}G;HJT zf^Nm%!Oxn>0YaP{oyFmz*Bx1Dcty9zo$2Ba+EtT5_pfZ+4X}NztQ2GH%Mijm;XW2= za&uu|iT3$D)~|Z6I7b4Wm!UMrr_94z0S=rU@b#*jSo50DDzjt3qf(r2vLwF?2{I3j zQ_H0$wNa@g5f&%A`FAVjj?RInIItPdtsI1vUsd-Zq-1*sm;b(T~x7XZe!%BJR5P~15;zp~q_ zZw*;i=r@VTOJ(j{{Zb(3UbVPw&ot+(aY{h;4&URsh9Cu z2d}~Fhht_N{pEMy#F?~@g*ASY@Req-eHH9%S>LQTRJ*qN<{?4h_kW#IH2at zBzDHBYNrhPus-tJ)u4eKDlAkS0l2011Ko^^#jp{ip{9C_3FY&4PG$D#__ZV9daujy zo_HwDxK&wY_(@j=A|RLZ+ZLTY%k^7CsA)B*K}&fF0{7EhvSlMo5l4)FgoO0#P{o-9 z;hxY-eN=jP|E!aK^|Cy8N*`VQ>VWkYhFX?NNU~nXJ|8xCJApR`45Kje&@+neP=E;< zX5i^A0iir0wsG4)xiCQwA{>__Rct34LDu>&_WLMmJ{s5OJTR$?=g(c1{yAx$Kl{bj zI2rqc=Ptl?k>D)I+jgwCWrR9!J)#t~oV(_)bG*t5sB>$C)cv~B_6Vgr>S@(*`XDN5 zBu1|>XRMze1BlaGJquo>1(*X#FCDAWft5;X+`E%|@X?fhI{30n8g;5G8XlX?7c^HD zDBF7M)TA5zGwsY&5~Kg}ut-+!cH*x$`u<$`GID*A!th%`@Dp26WaFgwuh8At$^02%tmIq1}TB zM@@b{@G8t6(iQ~xb54FA)w6L{@5vQt7ti3q>AC8Blm$D>i-?Ucr4(}%x4Rt{aEv-VNNPB5M7EzND z=D{Qqog_N1a=bLrM0BxdK}Ivxle7Orn8elOhbOW5&+Q*1btfODV%DM$vfSj?Z|{v-juYrWt%V-sry<)?Q1{V&zHj0PBDK84&7jGXb3r z%?$rp8mFklq2p2GJmwCa57V2Dxj)0*?F`sntn^8rGwp($8xa=P?k;!}!6GXJ9=oCS z0AO)7tiLn}!8sBFru{o(XP6wm0Cyf9m+r&kcfS@~8ck07b0uH8SN7$PK3ld&D~c6L z1s#eiS={}(7kHW;<@axemE!x5e8D9Mi@?i)8aV#1KMAyW#UjedzYqM7XueQ=pQ=S< zDqZ(%T)_GrpJ~Ca!Ew99OwapihfY}U5||s41_*U|rc(vDKp)R~0Ngt^?{~;IP^*BQ z)w&AN@+t{|b2PR1=v}`I0Je9q6p{7bmO|BgFxfv(v~_5t)_J0SF;=|iEkaT!$1+r4 zXYTuZQ(hEa*Za6=5j{#`ONN5^zU@ff=K*NRRAUcxVDLl&nscpVsUzy_q4=pRafq}F zlaWN&I;wl(>KSp`vNha9L_kDjoC(d5P@V<%v4#p>ljA87QQSu1x+Hx_!`gM5f2>46 z=|c)zfdn_9t}^b5%4f@0u+kVkX9FdwflXfnv#A38Mm&G+X8?l)tXGg4Y->ntoVriS}9QXfpTPRdxBkcVbq*jUH6067U(0}U83Z8sBMouzufWSHz9FTY{_snbatc6odh&Kc{+go0JFv*RN z9TMRO`T2?0BlQ9PbA8!?63uwimj9-iiGUMBU{&0&=))YxozWLhobEa)_~c9(692Cd z>6<$Ywz1ZyJE?ILU`Nc2{MQmB_3uX%&=`9=GJRgHh8HJzB%Kc>c#>SBqbN5|%gWFr0cbs2sW%*smQS>0~@|6(%XJ@N-?0Scq;XR%h z!iPmJoQ;}t^LhK*sUEuApN?+189yV~Rn2bS54FZtH%#18U(*=0g)J!0F4K2lhOW4# z;@>UF{JmXS2zM!CwI|6h1$)K@TYva(_NLA6DC@agJ`8$3wleqOL>mP=Dn04l5q$0hv^bgOn9CI>H_%1cs~G!KwcvN3Rj%?9?7Q-jV$m{)B#YQXl3pFR zy+#H}j{IAmkMI1dHHqg`b(v=Ac#)|JSCbx|C1loBZsuPKrvM0Ys}1p=4ps;uoD>tY zbErt?K*Oy7Ep+H|UxD+%VgSzTsTP8~J8ah=TSR1*fJBVCahRJW4Pk7DV!EAWmVZs+ z6&xEek?9;6Li034WL$Ds|DrNV@zL!&TsSiXP6f`YW|Bz4TN8I+a&5-FiJEHa-^eg3)2-ntyB<@cu5v;VDllFl>Pyl@W*cQjzo@|yvi_e=a1 zL};!xLw5^58znmmw?`enNPR1cAaE$p$DR^FF3+<#WTb4$)6qUF42+f}9t}Ns!x=?} zQ5$sH=Ad2c`H8|s@0d7#cV+QgC+WTHtW()smpcA~EU|6Epr&nZNSWUhkEAEOSecZr zJ%lOnM;&OZTm$!dyJgaWsiaEf>NB+n68b!=1#?D$RdZ^h0iTz+TCp@(J?dwrWC=yA zIf0K!mZveoMu8q1#l&z-B~7Y#OAE0i*2dqM)^H(<1SsJKb02Dt&UYH)&$xU=n*vR< zUoMApQr{NTUduu`wD^E_AZY1fC$vE1sojN4@qrfd1_bFAWo7P;L zP)aAi4-M#qwdsQqmxbS;(&wq#Z{&2-D)x$Dku!$|jEtpk{Im|#hz;+xCojJDDQG8CU_rRHIT?62^04jXAoF6&1=e1Q_}VnVlPem z;fpJ|(S3QWRQxXVuqUd_Y0b%^($;i&ehORnZ>O1b&;Gl;p{iAclP8lHfB#|bPlq}BJz9~a0g+4kR|_$FQFeKd7Db6-WW;upK1>e81PgZ+^|#oY z5Mg89?O==Ey`+_mc7FHx+~ir9B*QTO#)`P`~Gb%&9AK*<(HC1u-*Uk2`U(zP1F=HCP5QUh|8(} zkd35dRPwKXz`lJg?DEuoZny!1JNeG?qGMC3>GlIrKC6f(s!NgbFdEKa!>u`X&Kmt) zqs>!ZGR0VY4PILOh(d8tBe56|De=sbd0Lc-w~^svQmtjyVWO>egO8fOn3{91oQ!6s z(Y9f>$R`hLLD8oVZru{)05PBBw7t4!-EU|q-^z558Gq4LD|$EU`K`w;A=`S!g{8w8 z*f*9J%I4SN?`g%n321^1X5OuK@{8raNy7=JRp9iqGYx@r6r+2Rpj`}_=A9oWCLv%& z+o*ofR9$@|+>$X=HToiWh`fu$`CeO#s%{n$LkT^ZHV%N)1Cjjq^5Lau2(~^*b(Au8MyP8+7f9v?p%f5VqC_wfYf;Y)PA{(;Eia*7 z<>ms~OEYgVe2Al}VoIk9a<7<| zqw$P8>m@r+U583KMWa3%`MB?RW$*L~?tU@&z(>=XBL?Ep8#a}P{sdkzM0oOLwL*8!8Vj6--yeUkCsST zoM+QS-|4Hit``vRpB&ziZ+z^2{ie}f?baMCHf|6nD{UxSEmrcXm+qsI>LhJi^5%~E z{Kl>`o#>sv5#jShwJndKZ)BhdPdM|u&$PYvSW^vm6f1&R!f319% zyGDJvF=t(BZp2>nYKD{RxjI#@C#2i#aOO?IsHAvrAFLC^A8!gx4x;hxafJ6#@F3Y) z*G@@Hg4>yY`&!Ti5?4su{kVXjJ2m+JF03 zA!b-i;e5SL$H20u>xR~`TAV%G7H2@+azD?Xn$yob`ESfTv^YDpWf`D^rE%0El?8oJ z`(SxW{m*XiJF3UODow7LGH4bdfx1>|GbIi78!Z+D+*OOatOs@9Zgcy+Ztg^y7$ZPz zXu4dtI^38@>dOUS3=GXh5W+KWKcP>?51;|@__~JEt!`)vJT1W5zqMJOR`OAJOa7s_ zXh8x825Nd%_EUXQud}^qgX{#SqE10sK|F&PVDfb^WIy=RZ}IpXpeCe_=^c|-_9;Ar zaxrV3(jDWcr@Iuu7^J-FW4T~r8Tn^RSVKIYTH0*s@serl_c}#GaaY#kGtc4;z(tKi z0o)8YbrQzIzz8-Yg(v`f9aQt^L4Xxl>%hf3McnmEpwGhaXw5r+l7$0Lw8w zWUpsuU%tgvTzOg9lsVZV4e?S&kz@NOj+}QtR<*5`q+OhXno_yhqS~p&Q^}y`P#lSe z8dJzRp&dyas*J(-0w6P+(zh+HrV0zloS;oYFaw-7xrEPy_H(2}`0L14_lU)_oO7(> zBA9eYdlJY1m`TCq}nwn!GL_ zd$)fVP7APy2HlcmMhFn@ONgnj+PL@MGMXtxosGlId32#ZsWTg<=r!gdG5l#*gEcXA z!iP^G+G`n*KL@M@cfx|gs`a83IZzHnkX}k!IKrMc!VbsS{`>L-99Tp2Ge)0i1$4_R z{dZojj@LeN0x5fD)%@PIkb-{kI(P3|pN&>x%1ifc zmuQr~N#Tc-JA?z(-f_%p2;R;7jiqb>PL46RGJ?k?a`qd7&z>r+jQut@Eg>xxh(zG8 zf1bX^&Rctrah^@c5iA7SpiCQ%jH7Sn5pazmOgmz$q; ziG_AnnmG?SvNM9`QL?Gjk*``lCt%KgUE1RA-TO^F-FfcQbltVcu@S+|hsa5ayCXSs z9-R;2`(3epk&gsa!S;_408?SpuyUI)4Km2$^n(M5ieau(w`4M8-PK|U)t52+^i)>L z`3Bp_{P?kYtD;2Gh!oLhockJEd>|7LsEj={O}Z4Z2~a>LpMpZwespKW7YCyV z-0ish4jf|z{O39>iKjAGT6vPF6lt4jh9rn=+>_{s|lslY^7vC>DV}q}z zuP~G{UZAvbYT4>q$HbkRb3DntX6bn|)~05nsAz(V#pA+cbaBdL$&fBv1H{6$MU=}ctx;r_D>K?!XN_=}BkrBWogge<<7{5<^b!wTdP2iZ~p~gCq-Qe-PvTQ==PE9|LLEOV&TvH zAGiP`Phj$TREG`X3gV~SrL{eGHoT9=iFYD>{jvXgG` z;S}N{dcbhv7V$*?hMmClg()943W^_|Dzkr~`C*}hS>IzqH{>48Iw53qAOLG2hE_+a zh?@SB$=frJ4n7<%aiFFeWuoWhjOP*49=|DZ{i~}*(%UPJ=vRi<`~Q(q5d!y!eYkn? zu8NEI1Q9`XO%?m6#Z!UG)}Aku478*Kw~MGMd&<)uvP=wC_v&|<-rzN*!fp$rajUCk z{Rk247a6O`!Y{JnK9WSTTj~y**w2={yWE*#NVHDKihQ4 z=9ubYGO_=wrjbE-62fFe-RX{fP%k|BGvg?+yl$E%3Bf8CSp3c`hI0w(+0ttgRa0x& z5g%{Ag1-{ED}Ts=z||07r|wx#efY$!K)(*sm$utt%3;v+XP=VTkCQVk%BPDQ!E1oV z{;S~OS)SK(F)UbpB0Y?UYRh|tu1fC{*~b)RY4(b4j!O{{;q0_?IQ6+S@H%*;ftQdX zDv-_OkWCWR{e7mVJF3Bj^!W?AN%$}+M3CAbUXu)P+2<;>fAf!NVsA*GvXK(;ET4Mj z6Mi6q2rCF9r@}bN=Gt8xvtuEB@o?2LbqV_t@(hIV3g&9Fb9@>AT8y8IISt+r!{^iU zw)G0A;Q(rpggW%FbNm*I3Yndy)M{`-?P7}&L{o|WT!=LZ_p=}acq%x64O^huSNBBx zKmWM6%l-!d1dJ!A`y)RFa|v*0YB7GyF19sdH^cG@sbkw? z0zZEVT^m47JgFM{9MZN?8nSd&xPWIo3O2U$fwvS9a7FC#a!1|Ur+k{zgwzqbBpAdo z6Se0lguNb_2%JsdA?M$rCbQ6RYbVhyrP~z);5sv|igdipcFMa;Mki$Y!pZq}9jyN@U4H$E#WowYHr}8bQihitea4kMucJVMy183|p{_C?B0A&b*VMA?bhA2~ zkq?wJ%+dra*r8M$Sa+k8C9Ih+Bw zh*cHE$`ocH01Y6tk*Khy(wtZM-tCV<(+Pd5;8;KuCY}wrP+jKy+20_v>hR_Sy-@u) z-M>0s`2V^x{{7>U_q?I?g^yO#qMW@Qo$3G8a0MJP;cYGc2E(vO9`5ST=Wd^cm__J4 zP8d3}8ri`h^C>A-hvjXK)T96I`;YH@(ST_eIg{!y( zqnA|Fz=8Xx4iCVhf$6v+hx(p3kDQ6*^RS$OgZ%xc5tlCYtIBF`t_nQUiHtyW>M318 zk#|de)6p41;uprxef}HL0&B^D&=x7?y!D!<_U8-@$scD4t+J=(OCiEt`fLv5>Qv}l zA&XC)D#qq$BnxizB4}kH8kPWf+_WH0u3wD0M)UCMlr_94`Fv@%7g@qhLRQx_Hhg3F z%l5TH&*e|hJ2+^&c*6c|;LmPVP1gvy3JUfKqysKxE2yaGFShypVv8RgA1$YZR2>PL za=thTIuKS`&)e0m-Ywo+)b?TT@;*IVgruN2dS)LvNl0EVy-dLh8Qh+!Bp;q%#qe7P zFeI4#XENMRpPX-krMVQTYxeg^_^{(Azgcjl^CMmT65|ZFd;^WELM!do8u_OYH!g~? zvZO|^vaNPjk9zzBEiGt(xl`MV! zep<&<5g>L`BW7MpI#o=|pd|Ho`W4o~EWNh~sTH!ohUcWXT;Bd-U9%G5B-U*-F>#TIgrZ0y0nYEQR(Q88`2UFd z?szKS@c;Wbj=fj*PGn|p2PqlZE4!>Dd(T5c6iSj!3E6v(gRIC%k?bvdZ_e-W`F_8z zpZ>ygoYVE(&wXFl^&Xe%iy5=>ywKRIl*DjJoIz-q3AAUeH{u^D=}|57cjK1;OrOlkY84kCb*QQNgeo;RNiRsx?Dz9~Gk$ z1i%*W__6OubLb;L^)^6rk)PZx$`X(F)4)gHjkvqfmX=R_5rAjyA!zKl&uD9y8xw&N3BDI;~pWKIsMQ^ z)3Vaw`_Fj2CQy14M8|#8qGaSR<9n~_Lg~Lk7-}`kZJ+|chFGuZr^#BWO60-gOR=}L ztb5HOozY%QftPPw`qMlCdMkJH$SugR978oka4_-F5$%BB6nZ~#D_=8Sj^-8?s$`fO z^h>>6F*9wElK!xOBfOislKbLxPW1k%V0(71I6o~G9&stl9uqoLb!CBm zso~eX)j(OW66u3s2qhDO<{>Q7_3Aw)*NuA-V#IlFrq zIr`4WMVD=|)CONzXmv4ltal46Jt{huD%ny%TH@-zz1!9#E_<;-J^VJt>0pELx9e~| zF=<0tyOngHz06?g41;FvI91)_K7sxH=%vptE$7R+!56+EA=?H?krFNnSKdv5LFPvu zUk=D7J{5E)#gz(5UHJ3ogl>I_yJnU6eOUcY75hAM`waK&H;*Wd^-g#eUQXDtMKaZ! z71~lApWLDCW|qv7q4k|2J2qD-C;6+tiZ8sc61HbM+{gDKTSGQ<1yiUeM6R4t(@y>_ z6<^3cH|>zA{@XiozIDsJ4sl?B^u8=zO0w4Qlxc3trbi7j8DLG`l#@y_rh`})M{|{| zH$SaP&XaD>vK&Toi?o*y2NbdX`25irm?aJ0I`zyx-?GmL^c1Jtk@;zDNjQ!o z?h`RNKWlJjZ=8|x7+Z`RLHHgKgfEfyE;Phzk?6{qU4=X+^0#9o7(4H@s6&{qwiFX+ zh5QP%t9KdvroBfIoM|A;9RfWpD4#I}zf0d|Wl;aHt_{qbExBsOpFo~SRFHTQqKD_d_`n*Vw zlk_s9ad|i-Q2cr0h^1!>PLnjX5$V5UFZ<|VuF@A{8Xhbx;PEs63GY|uzdHm|dBtqi zE1IrOPMnTdywKfBBzKBHZIZaa#K(7ukda$%-s-=9gM)&Vm8^D1Ibxe`ZuJYE;iq!A z^=H}k7@;qXGycVu&NVZov27id-Xl$KYE{{LJLIbp6Q5hZ9pA5%%T)#9q1|p47ROQi z*|+fih*s{t9QeC2oh1Lh^MlCV3a?_kjSxN>o#SSFb$NOo(`!J_2y&sD5b;lTB&a#4 z*21?%L`fCm;Six7<7>TeZ8n>+;Lr+M7ft6f3M11{)x!snM-pCHbMuGu($8-VP(>70 zuZQI6aMS=84X}|4Gntqv%3lAN$C$4ZUY znWH+^?CFXKUrx-R+2(&a$xiJl{cGZ~5C{N%$_V~I^HQ|((mq1AfE`JrXojF~Oe_BU@~BLQLHD;4smt_H0)r~P z>-9$>vVV0A&KvIE`&RYVz{BUP&9FY~&&4aYLM>I_?&@5XrV~94&jWI$MtbleWPIlU z-=LOFe5D$-CnMW8z?b^Ok-j&7<=i%Pus)H)*_>MF$`KbAN^ohx(9k~CMt{K?kBna= z$(wcxfby$szglLD3il@nQCJ&nw7>HL-z?ye$P@buK^eNF8puvF1?)CE>zakse>wH2 z$f#X)w(|1^q~NF}pFS%Kg%C16gJkA;G0TlZ2(Qp=?Af%F0?*N_tLU>I-FZ6z7Y!kl zkIeLhQ)Rk+@*vzE1)nFo88fc;bI;h6G zo~Mg zkDAVyZ9_JospFf1nK0D4UUP z@f5u9&CM$9L&7nn06ng7c)|YnXdGkN3-xTlEF#|W>2>D_DtF1wAm3}~EFUHxz{RZ? z!Clqmb~O~mmb>l}$O6{}`+iysV`(jJuJ{AVANF8`5RmQdDK}_xy&$Qgd1LKj6$H%3P2X?s@Kx>zNvw}Y8S!Poywis(4U-Dc3$Mx{7 zOYPD%hpL41>41+Ciqtm5&$s+914O^dIp2B{-O0ySO#ub}8?N4V+y$gtTbX=}K+h=v zg0Y`S#^9Ff_^FGhfDfV~+1u*@7!pqr`n>N?Dtzr%%gVHqyw{^~Q9hORZCh&7HttkAFd57V8}fFYBCxCGFj&+m*pjqf3vMm_7yhZIsmSK0 zZ3tR@DXgFl-W^u5#6*pKyZeb!eq&=wbr~mw{F_3tY5oFpNlL z>R&bks$h;OdBu!km@BE~+XLrE0|MC%_V#S~VX;}DM?he^2vNm5V2YF4XeqT#CCxj< zFNS8-odow`b4mx4&%!s)TYmlV^n6gqmm{Ygp{;AEk(FPv;Q4@dk8z5X7~3irMg*3} zO*1)vd)y@ejJ{O*DkBo7Y>+2$jlO%|hvUfXs)sDpcxHoXFW`ec9^6{c)>rvFy!R3g zqGl{&WAe0Y7cqqY0h|Jok%Cae0vlLaLY%9`z0O2`BQ^BH3;afsIVrK15cUCqsp+WM zcap(7!yi3^7CI_s{odXH@(}EU!=m=HwRVeJ`{m{4I1IHN>O$(HZR z*{hod9^_ej$kE=isK2yZ6VLbFMt&jcGZ}b6AM9X2^@|sGQNqMberh1>$Ys|t>Vsq! zIbOIkYm4of>SSsq37G9Gr;(J!*B&mBt!b2Zk{nE(Y*^OY+biR*(EnmiBd|#eMz!X3H9N8In%_y1g{yO;-+_tN;IQnW{u|@Xl&^ERH1oHjFV;c>&tl?!)c_AY*tQ z(Q1xm#RgHh6O2_%lzQ$!ry4W>0>Rn_XOqOI-M)nyD6kt2SSH~Oh^E4Ou%F%XOzCKU z1VU+ZZ8}_HdDixqi!uW?0s5P(;Kj%-8}9xjU==2qK|uFNg>KiIj+gjvZR%;L+;TFh z8{MiNubfzRwf3!xdCZec3O%Aj-@kRXP2s0Iro=34V>JUh#?P8z@4?{i!f#*W(#rdN zh;QwWpsbff6nNr+bdI))00;2HTx{&H_`OXjb5_nlgA9To4sKCy&ytlehb4i)V>R~k z^7_FL`pVX;fvP?y&D(w||OiPl{KlDY~&jmReT-yh3wf zLa&A_CZp?(l={H5SCzO~M+0mAC;{8BiHFd>+8IfUchQ-@7@OpO@&E6*zmXP~huN7b z#4jr+11KimtxOdzG*qFwDKVs#6Ed~4>E;n!@3g16|HAGJ6< z8NA=uBh0gSXUAWhOy! zJ^57KdB*PXTq=r=l>wyL5;!1#e*H|d5>g>PZ*c?f4xQ5tnR}{tY&6^drX>H&d;7dy z5z9&z5LzWSoG6zZd?5yCoopE5LBs)D7dM`KM3wu*;>zsP#ou4E$lmpRfX{JsgzS1h z{%!Oeg}(R?gS!rI+8jB=eMIX($xBoV#3D#3nlxr1jH0BR?UzKDzid`zqJ*vjWz$$z zolF#?#2-uHC{hYw!^4{4$Pt#cW`_&(o2qPW-gD^;yUz!-YydEZ4caMd{pku}VDiA} zPu$HE5hYgp4)4Ho-zklva_+!-*<_k=4qW4H$-bb z%_HUu?oTcCJe6+$9mgyH-5S{Z0^2o=pnLjc4+pOdnpc8iO3Itefm`VuT*Tdfp_*k+ zB&m#aePGi}098c*)CK|UXAv3?RVdn|14EOMn^xX zilGXj!P&ke_$j8^&2<18;?l$jnifIVC!Q?p&<|LW9;%P7s8ifoq=5^~lLgi8y|3&$H@AXkL{*QZlvT*q;9px4r{A`%zYN_r4*ju=9Lm`nDxE{%G z@3YZAbs$^MC{7mb#!DlB-Y_ur{9j0<)AGeD>a>Z8b66c0>JFq2uadGvAod!QN|$oR zUK`?RzrN^ zAekvnnK$lo*OxJa$AR@z{`6$S`Ll;Vx%1eYnYh^$UW=KPU{Ow6c;ohxO_RqAdiY20 zJ|#$tRH(r(SAkL(Sy^0w&oUELgN5=N>waSYp|sE$4$Tcl)j~GL|5YOUW1aPXqBrnd zfAvt$1&1`s#>?ZBH7v;AC%g(PROA9b-k|vGZGtI=hn>y+>`qLblJsmQ&peYB1kHNCA#q9 zK_!e?EXVp#G~K4@M=XooiAcB^)%0-#br7j0!24F#ZZ5MwwkwmSQ*TP=D4rownFQPJ zoigt7m#klbG_IkaC}WhxCtk|QJ<@uQt|oc6yoIarhPmonNXR3XIPp@ivx6^3zOLdv zC~pH)=>#eMeWPC0yT_A@SIcqBi=95k`*}ZcQ0T(Ypl5t-4~H~uoc97azN)1+czgYn zLx0QA?HKz~=srfusY281wk%PY%_CgVSSpq2kp`Cc$l<@ZDh?@xrBpFNjG z8=}Y`*nC#lyf}L(Mt#R?ayGB{Y*y=ueCNla)k1H05eu^oUB&c31dO1^MVJ)wr|$|q z&*0*rsCkWuKJ_J4t|a1zh#yUaID~-)<~Y&Vb#)NX3M?Xs_G$;Deg9^AyjFhaF_(x_ z8oA`_X!nP-4Ml!+orLf3jV&oO;VQB~V<)-^u8$BAtB~`eN~lQhh=GCG;5E#V+cYdb zMf+UX+hZJ<9&g~`?cI~)x~}8Pu(C*{(dT2NzJqkNyO%3xk@7BZC)8NPN>C3#3H}fP zw6&CY7aYO2iDaP~AGAd5K}-e!88hs5xA<7*24_P)OGk8tffI4i6ocrWzOAph4}zvU z>I=f0@!;Y+l{jMWO1%%ueRaeY^JZiA0CHe^?GuK1xbrL(Ko&9WeO7m zZ9S$@_#mtx%-Uy0RS}+1+4j+(k_rh&{WiH{QU&JR@Ja4xP*+swLjfW@73hh8Q57{}MG=fHnKnq{@I&qQ$)*KPTb1Q?%KU8>hB zx({D1^nHADKl24=kkK{IDFbE^lmLkXjN?Lr{rqmLvWo5Lb8N$clOyOG2<{`8I5eO) z1)*h+U&{?XncVOdA6g1=p50Gd+54@1$ENV;SZ+J@U(Ef}MQsMil3A^m1nD!=i#Yh0 zdgqMh{&5E}C^yP*Si-GmwP(;;lfO*c&0?mFH0f)-1!}s8$AvNk;dBN+QGSqL!N5MkLe(ycpatxWEAR99f2&8xlNC8h5p%Lo?r|h4@_N* zyT$`eQ!8uC9Ol#2OCp?-Y%T4__5wv#fh3P!9$xkQt3&Y2$B`wQ$Bp86LH9R7@b3)# zC#2Gwp}uZ@*`tnX4WX=TqI@vbArXdjwC*o`e;534C!R~mQvZ1U=AZ8GZsBy25{q(< z5RPqunakCH#f#jOjLP1b`#;xFH-OW<9{@!`>yoiTY&DQwplC#F-+Zww?vD=wPVLUJ zdzeAq?>o7t!9Z2EzP*MVvoYzs7D^g*i^O2s)_*y`&r@C=Ir+IMiz=4Q&Nr9?_E5OG zS9_(}m8AT!{krV}*ttn!68N=LY~`f~2@UFzMKHv#0LUtsB;4KIG9p-X z!-Oa&v}e9o*wLUn;O{DVmSBe$c&14R@5|j4b1b|HoeX zI^-(XAwM}{UcC;veL3@UkkfTJvVa8>RTphadGhYM52M|J8H(+W&9&?@rQCUI`4J@p zCJFmVkdiGBwh)mk2u@JTpPWRVb|>-rG!uhqqJU@zXS#eVf6}AZA8p`B&r#P~o(gh* zxvo_FPq8e0Uwu(N?Pel}AAUkIr0Ys`?0C4BPyDG&abnM9tRC@5L2gc3g;H{_ zF5QMu+)1)xp9jJPZ;F4OzeK#y!Jm9O#UcU`0jcm^luP);(L&2`Kn898KfXK#)3%I^ z{x5yz3%x=fKF1$94A6`BYhKDY(aF&^qPmO=29eN7P^T5XewN9yM1O1v&)LR~y}ar* z0fFO~S-Pmn(om@Pp>>9I)PJ@jM``tpo+9O@2@@qJB#Z@UgS4SrZ48HoaXk^>u}b6t6t?vBPt5Td+G&!#sEc{XkaN1prj1JbrEb4e7XP;5)9~wd= zdGgq6zv0y_y9jytq8biGA|;&*&KOXQkK>= zx#^}YTH7cAQQ5-0?XhN=sj^DsWJ}6zZjbrrY|=Pjp=Ymlo=LnS?QBFUetWBsbhwmA zgp9w+w;!O-&^9)Hm{LP+zaD^dgLnI#0@d+Evr5;2Z92^TJM7pH0h{Tv?c9jZ@x9IhxO zvICpU2xmBd)Fe6{H}>8RT>wcL+1HOnFxMy1{q5^O6e$Dqnp>pJr-`R5MACG$;VBLz z_7C)K(lJI1K1D&$0%R=Q0%i8scCP(IvI_wV|8f)zDDQC@Gf~;FH2!;8`r#^4exA+X zR4Q|@i)i>surL;w&0i0M3gi|T)U=Z%xCsGQPi&!4e(}<)E+I8Oos#Egg=$F;1mlkD?*(UDm3>P;}AF_>_^#KPM7CjvKm zFD%sHXbLTs6bG}?W6LXy5HpZ%Oc~s|qcJ4%pl&~MJ&^4g)&Z{LVO$+AqnDI+&txc- zWxwerUa#WAjR_)v+6X7n3JsML+PERP$nuH{jKXLfdIr;V!Ce@*xf)88BIe~Mgj80I zJg+Dw7#Kyv#P?E3$&Lv+{2dsOB716YI+0wQoLxYXi2O*$?MqU4a@H)%7R(j!;RiU9 z<~-Azb-kT+&WwVg;{J-G@|{Pq{a<3?5U?5$##eglO6kaX;Bxc$2GC#G673zcyHF}@ z?I@gx3L3Y0R*?{NtRy~~D@?>#$KB$j+wp52QrvL6_z98L;+G_D5H5NjFZYr2&S-+1 zZ2+|)T&YN)<8Y~*E}{D+c3ITudJGwo_h&yuJcYhgeb(*NPDT47R>;u)=jAedpZS)We*m86w44Un}mG*oJ|wFg?|y7=Dwx!7eK zSDyt0s8L#|(y(gtMJZ)bf=`c3kN+|`d~DF9oxP|NV%Sq1n@IQ~ql$`cNF;_o=(=}% zfJUpH?K6e>vLSxlQ%QPrDS?_KctvF#VsGmS@f#_rtOo?FliHlXSs4H6oB7u!M_nAr z0D%nUc>iV70@uc3^g(o}unpE#VwL-`wWFJKOd3C%6YH~w!k7(rnwAKK`x<{xgMt=n ztSsl85P^pj%x)@}JPx{~WetMI1|4P-&-RfD@?(P`J?!`t&&M|XVDzrY$aN|X;-{KI z{D}AePMDiIp&|LcCFEP(TN*iQp%0Ez7Vizua2b8t(16m~D1?Xmu@}sY$?N4Xb z7Nmab!SO)Dw#7nYT5;G-eyswSReF2aziZu z?$%U~wqpq+2JisLqL2V(PH!b~hsY}O!&;bC=+~|JH#$+8?Dy{(960k)ZoW(o{}%uH z3~j&$|9wxk@^Gex3GIfacgH6h6hV^pbQa#ib9ie?%5d|w{SWnGJ62Bo&??!QjOxQD zCapEmZ7EDF$?c}J5~qv4td+j7dzTfTTUw?e!LQI7F+goA84&<%=0lea0`n_w>r;=l z8Tf3b^O<-oX?$@M1!(z5yZP^RlkQ9NzmIFj~{(w9Zc)^WMa~BZjEj zBWWvTvP|{Rpf*T))EU{mm#-m_UxF2vkq6d9*q;CDCKVFlhM2nu-2s0+=?2QUBPDM0 zQ=3?=8jYi%r`pu!$YPOR^QxOqL&5kc8dc>l7AyF;sX-rpVaQEhWKF}kLEax zmPj(9Dks(kdA!`Gr(a%r-Lt|@3!I7KJi>g{OXt%v^p^5|WOr(hu--|c zQOd>zi^PW#ga1U$S`5G6zu6QJE6p8oF8hY%N=C$s{0<1uj5L-<3x!A*)|`gW=Fsu& zB5Fh!a_iRrosekq5vm-y{Dy2A`-s1a$BqkNF7Sd`XY5IKFY&uM#;^bpPUqGup#Yp# zUHtl6zf96c_M&fu)QcIKzM=yn;q*C6Ntb^fE!}d*oL$v+|D*M?H}O0DbMC_2hgeEa zIA|F=!(3Si1URJ?toTtW)=U+6q>*G^zTK6bj^#6Rmd6EDR}Sme&QE-7$}E#PJyAIU zdCYtIftXLnUSnRpL!MBT=kjQUSuMgF;~hGCK6A>b_2DS_O;?{p$g19HIp+NE!|MIs z8md-)J;57&_#vNxO55Jn8Vlj~GIj;mNUvVvlnDLJI`e1ux{2DwmF)hSJ1psMvsf_; z4{}}PcHe80-S!DMJojega^A=+_OXQOBMl>1)nd$GYe*jKk{yyj`?YdHlpa=^v5t$? zzP?xzPihOzp9^YY(rD? zkYc<7Z?@QYSAM2hZ)2*~J_r-vMRo|3D3fv|@M+P7<@6FEdr5}BpGdC{v=V0B+AiWG zEC@yUEtBHY*u*WPOSilc8M1RJvbCKl$JK{08MgVsn3dOR z_fqqtlCHM0azpOv8P|EDMC5dEipW*R$JXFxwk;aHF*--CMih(@^n9X7yCj5Lq4;{{ zb1IKcF;2OJYA+0$X5YUg>;bGttV_NYx1K|QD>um6SAw*SH*kN>Tch4k|yPDtt zEF?~N`KYYehvLYCvq%?PKi{@soU##sLYG_QJ$RiuC~v`a-PBw37@_|gwU}qq{iMaw znzC9qc|cR4YW411YhEYLC$^vios((-sOpkC?wufUzyel`=aMU+vXuGi&AvAlbn;)* z3*Igams&i3LxR*A3I^Wa)RBmn^AiNw;iWlGu*0DIs)cP|jK}QH%v!L|ePOPaG#N%2 zy#!3pRUn3PXG#z>nkvCu9}T^jI!LDp9E6hzO+yvMAJWwU7LD^~5dFWovp%)3@@x3< zpbewJji5-cSLRdW-4Ei4xszube;=LlBs$6tWNZGEnQrM+U>qFbPkiPsq1iMsKl=3* zaeI+Fq0i7g+puyt$;x?MDAQ>p#v_8Am(+v!e$$X*O=|z=xoKotSJr~W*C!bwa z$!fPggeKk?{pBc$LO~c%QN>jT-Mcwk# z6uBgk+L6NbI$^&(KS!jB$wbF}t&Zt{R9@Ehe$c5zGC3w=GYn;YxV~WLVFR`*K;dMR zYa?G8Ps=qQ-l9m9yp3&TLL&-WIp&CNa<*n8N@&OVzea}T|8HbK5*ZMto2qpK^Ah8T z@qtEpIQ%!zBNF06gkY>OEnSNu`-!7boA%%0Q=wsL6vV&26)nfPw4{tr)~j3)zOs(v z;;&kXd@ zKrhPji7c2{+w0tmXM_I?kU9CwCPg*+fiaH5@~79{yPzv_65rzJBYWNXNQ72uj);Cj zB%G>7y^p$^c+(f$D@@K=F{*I4saQi|bLEyQ#Ab_j= z6fO&z+6p42qewUl1)*QS<82lZsE*9i-nl^|cuP%H`?~70-2)NR9_4JJ$d}HMe|pSY zKjS|6;}MRDp^o{d+QrO|f?k;MYC?iJ0#c>824l70LB)#cb@z{%29RwkobGeEc~eAv zad;Z02l)vQAFgJWFGYI}bm=S344~U>r?)z+;ki4~Kn)MG3a#_)YixP|K z6FpBpI=8%!dWaVA(OBt)U(xf&#|?E3XF+L(&`=YctB-q7YmML?zSv_|oLQlw zYDJ_P&PCV32bT>!*=P9-ns@z%pL!=lK&&)@aE!VrY2XzV@o?^nBor0 zVn`ME0ciyOgYYi?M1ICWcgBo;5ij8f*FA7pVDZhT#91STH#w;&UHPD=5?Uo)4Pv7H zdP$=zE4VTVu;9xn88id1`Y}_7D^x5|AUr$amC(nfj03oRQ^9O@{M+xoqthGI&FkBg zu&Vb;tgI&lmV{lw#;Ua)E^NMCw}@l-hnHc3>jC&Sw+a;-Gc3M2q$f^PvCF*UO>hyv zI@k-7ewZuFO^n{G-P#IQ_>+jj68&R<&a+Gr#^E8gO_ha>T8p4rx(vLjO|m^Bb71ktc_@?_E_(cHn_uRRm5(i8{Pg@wNfTz{lY;Pi z)?aL5usHF83^f`qQT0QA`LjaNRcooNS#U6C63!$cm7bVTK_L!^g#FILMIoGET;h2K zk~G}OSQL^{LptuzP7gLF(~ze~NL0aD`FwCtm2Qi3G53yyrK6M8Z|)I6%LJW`U+tJ) z!v4Gbe}}Q^G9XY$g!yXcx&{n!Y9U3nw0O+&U9WmZbduVLGg5-7K#6VkBcu|8esozq z_V~w7YtP@>V}UnSi*|1iku<+N$JWoF?X}w2#v=0A00;#s`A6S0{edttq7h_)WTM{_ z<_Nt?fqgE-Bp~R5G8}p0saIQ*y(S$=z#WX za8Z7oz`#0?>80ZDk1nq>4>1uzsetkpXWXY)oGD(!O6_-^LYIMHRacXUw5nfP3RPk_ zvmGlpu%&7TNyEPP@Q#q4;rv*r92f<9 zuF}^P*u!>wEwMMIf+f+psk`4R1Lza|<(OZ$!AVe@XuR2V1IUq;)k+Z-kERHEZUHUj z%O=UVvN!ki>S32>`R^?Pj zHkA56{^aM?%$!es;FDzrh?kGmB|j(;Uf1aELapx7Chqk!nJ%wD)%(L7ddbd=IcelBXISbKhWW+*476bOpGa4KBcWt`O5kb4NwexG4Kp) z0I9SQIPnBDz6i+-`?E7$R$ zx7b&y=XXykJ0FAA&#WYT5E>~k(83fCf%i~g;|)PEFQ-)d4Ma_`BMVWPf%5< zV}*hnpY}TEeSC}?m3m-Pw1gq=jsmW?_;fCEi1#oLy)6w1#e#nQjUR&g4_S{ExVPaK z`rN2b&Z@6z{w~EYzY?n20Y$uwFyN)WTQo1lXG;%Ev;1~$GeD#bvEs0KXCg2O z*>?SWRy<^l&58%B2d{6C0@C-RxG^wE93&QWmSSn}{P{zs@cvw=jc>tXzraxhFbg3i zKsu`*w2o2V--gP+Wr7lh5Bil0;{B1!QlBVQ+YD0^=0oLcrax{`1{o+l`cJf`<&eO#Pa~~%Puy~MG zWz(;3yGn^_`BlgKz#drp(CAvAb(|&LGHIsG@AULjVX(eog(JY4bqAK8Rs8Y$fFjM+O zrpFqDolgS^@iPKy5oh})3Qz_IH6kHg_YLJuRAorvBSuWdHf%N*a)FHe1&ThOy>jqb z(=enw=4ua5Tce$WuDx9AI9D{OwtZ*~Uq2-ijDk}tfHoOA zX4$IHo?iLt%E6p<4%@(cP4dnx2||Uvr@eO?8@D9 zZ~^~jPko@0!Pef(hW(7~j;~)UI7ssOCHuCSu5xv8az4DF{TObo)9tilJq4@u@_%X0 zsBZMqXj>5rgrgrFg2_j+tYr87g1QFEcu+s*s6CH7S9$xBQVO8rU$W)uZziP!Xjr`I z&eNKC>~68#M28Jlt${L^m;77I5Y6U;#Mrw`|85l9&(yqUB1{vYA*!Dq_OiFG;dccn zI)}<{O&kqr?ieCUGoRv*{t%t%r<-PE*w7o< z6JZL|=Q1n5$TI941;1DoBm(Hba}rb}lB=1KgjA)zl;EAnkh!4zGFdQme%y2&slJlV zQbm9k2IuE=r;zX!W!W_xWc-y^8>Y&AGm%?Hh@I*MQs4_1?{FAsG_}=LDtZ36?5pyc zSz+1w?H79***|u_^S(|$cb@3rFhv-ziRN+E)_d6g)MP|IQlFLft#q^^Ba@4tsB{|P zdhKXF{J4M8WcDXW?P8zBd?O-O{#L(oi$v&{N>Lpu_5?wH(+cD<{3JVlIykcPHRo{x z!UhX4t6Grfi%G|h+6?lyB(pU*_f`K?Bh;t z4xr}%3ERY0)~}I% z4af39IL=Y*_SH{_y8B;>e)y-K0M$ooskS-Snu3kigbIu6A(KXeGM{7(hkxoD3*kX= z1hf*EnB&!3cha9?Y92cbRJqKHVsN=9IaN8m$89;m}R*mUC8vi7|n*f#ROUTU4 z4d{e=%N6hxicLLUWhBh`S^Ar*BSbW@FD)i!ZRNO&AXbt};R|Bl7X*3vm(6}_tb@q> z#?27Z_rA&p!uUgQ$@q?&&umnM%5s^%<33TbCdLO{!Xt+Sc7Qc5k_Oc2XHBY= zKDc*;Qig%*%r;`GdoaS-F6}h+`xWjH$``vh+_ZpEgpIFVV3}YcnfdEd+LFVhBb~(y zbp12_c-y9zb1*I#daBt97D7u-L^24kStfq@@Sfp0#>4tojJ~Fh3*;*RP%h$7z-Oge zYOqHe;yiSdts_|8?eR%&e^Q#7Nh&P=;Th@Qu4{-{!F!UMz*~CR1S!E;px0S3uImF5 z%WA$e9vWcAh(|_{t7}ikDlEfJkuUuOeMb?x21tG#vk-XC(471R7G;@?Hul5+}7q*+{;64nL>%GHn`YBebeEwA_e3s2cgc z`2?H5TL|xTR~_|vPD~(+0*??T*rz{_9Q!zqev6Nsmlz}iYR-@Eu31_Bk30kw|KG>{ zkLIBXEe=mEg9=7nj1e^d;~_>9ql!_)$U&}|HfmZAE$tjJ{kFtNYCnT8HX43zATLo4 z%j!!6k`%zoJN6~~G3VIvD|JKL?V))Nc;5>GtI3-wVld;qUa)f1J(qwWzE6Y$n4iE9 z_=v?s5T6M7zyi>Gy~~6x{hh?^h?Q}2Dy19vv`?aTdKg?!)1AJhU8v`)9uOf=W+sUH zzow8^5LO0}DGh*!Ws z=;zsD>S7Q!up!m1F809II#NVr*&rE<-`r-)oM4%~O@T6V+{kzyCt-N6@Myk}bjva4 z@NVMOQtjsR=au&(*eg29$PZorF*o%rX6s-6d1P)0!7FHDX;_8pY@HJx(5;$_1N zwI$!0W}$TP4h1^+i9+0+3051;VaN{@I#&VOKZm$s>C=g$IB?B14 z)hJ#GrdGW+bW~O*Q5NWp5JngvkH-WXUgt=^S^lfx>y_uHO;_m^U~;CM#!-bd)K2k> znS2&!xc`wV6CMgjsSRGGE^IR0d(SI6BsQy$-W69}Rq`=bz_JCJ%m;X^_w3Rc5g_Z1 zGkwJOo7vWWeveekzz{!?P)BtM7K%Fy_K_1&FTmlK#b5=??*fB+X48tY@5r)MA9RHe zpPF|3Nw zzQF$>O$}9)U1OA?OVUnXZx@9@e-UKGk&nmcT&0bIs65bID-W!KFPYJD#&yKs2-Q4&V5=e3m2P)B46t(6K!47S<3!grY?Tj?i6Q zM@?-9u*AI+RP?NC((${{&>wdEDisb#x&-1%a$i00?0oS(s&+M&Yf|H)y<|vpYrdi>n3c6&_S(XSm$*b$ZK#R9Je+n8aYHA+ z7F@Q#gs)$ryaFOHab0zN`+n89+9xb`jE|YtRqUN#%XnwGJ<;NDRL>#X$F3FwjTXk4 z+^XFg|3BaPw05Yy_j8+4QYj3cuf}fggUYupP|AjOE$9oAEof&FG*f%$HrMQP=h?s+ zVxXM?6UMd_KBRq)PY=-i@>^R^sP7J8DI(+Uy&A?k5C2bY(r415+%bp>w++xOC1x&`<+RS!|fmNKLyn6M?zxuGVNZ$0svAgne>VbqCL z8r=-m1_snNugSjf1N2YdZKj9O{>+gqBxGlNDUPC8G3glops&vr?!CtX?H$A{4>{Y{ zbD21wq78C@FC0=MK)Dwj#Z^e9lJd$?yV#sl2%zSGk9IbeUy~5AM^Q;a&u2oFIXueQ z?>eP@(XEe!P@V2EwxmLcXC@~EHv2(X(8651YIRUonA*Q}@u!5xF)GGG%{Hi}nl@vB zVJ%xd^u@NxU`w*tVsOs?I>QRoxjC7D9e0eOhsoa^L+wnEI|R5MTLLy zY%jobJsao!E{T~)H>9RGoqanbJ-r%uxh__svZBsVIhSxiBPM4uqspucR}mdmesbFsC@XKoW9-c*oMRZ^>~X=|)I=Ro#&`Ia}qnm836pXf#3_85&PYv+;=;r%Oxago8ch#PW0gp^5&hHloKh z#$~xyp~=FowwrEfEFxpn3J^#gxK(_Zn>0X-fW}MDT}@SSN!X|DJW>8mBT(}6UOB&;H=%5SD6R0*l9eJG_X|(O-_p>Y5i-uHvj^Hw&q5A z;?Ml*+y?DN(~xH0VdR;v2#|K32eqjltnq5TFZ0%=;y&`Q>*9AnVI9Ave&5Oapxzm0`8r%!&ZzGyJjk&hbMJ|L_I~!WpDk}_1jw72FjvhDz1GQrpuzczVu)LQF)mI{8nlL!dgsJW zA5HZA5h+Pk+hE^`?V~Bb8PmTN++8w9w=oVHgoJ7m zo6Xt= z*y%8R-PR>z7P3!uWq2gCx2`TXG``JZ4vy`~>gFdvi#ukL5d0lKe$56eRGe=Rb$1+V zpIu;s#Rx^$8d^^?MtG3m7Uvp2YkKOFpbvD4Dieeg1wm}X@G`6{x_XTq(dOB3 z$5vZ}J#a-k?U{NkZRx!NEqBmH_&p4Yw3#6?@gfOKemrHSe7*m8V1?NK0VKaQH5|Rz zdytww&pV^nn3(0e!S~>e(`aYV+#b2tzjjB4?JM0-`25@vog!xpU!w=^J@F$wDcoQ+ z0Ws3br_pd8QUOdz#fuGVvY6osM~i~t=ggR`FwBVs?Ejp=jwXB*KmUL+ndwPSE0SO{ zLHe-*8`Q{uyHht~~cC-Nm$%_LO<^YJUyNn;&0UN;>u* zNty-q*}?pjk{rN$pa9OgT$C5HUgZycxYCp`DD(`G^+yT${aZW(dKz=B{j=o>A!MH= zk3{+AG~Ntly3*SSh-b_KcZ19_FIoVT9EANekYpDcuWfA`c2WxS8U<&S$g?}#!#V^i z-2SY>G=qjhhQ7b&5bSmU3+zOpp%4CkCDZnO_qe7c|01gk5ktV-c5bY-s*3FKjq9)E zK4eMDMb8b0ZF;Gnew6H!VHjmwg%U0+Mx}$*$NhDO8nQTX{r`)V*7_)!I%%}14BkA1 z&5*9q$rAfTM#BN@Hu(|lD;l9G-L-1yShGhd*hU7h+=!VjtAKa!h##jlnQRNcP`uA| znHao%uhYNxY$0BFO{8}Jm4vgD>ezfYIj**Bp|$=8+id!MPc;|<(NdcFdhM}Cs{V~Pj zL>-PNPE5q4}zx`bDydbQYGV!?m{VRed6P3B3EKVB1Q@iJ(Z|9>;0}(3H+3AL22&f4Q z+RbVkpbEjO^Xn<;)2B}>em?z(tp_J;4Kk6uLR6bXVDV5$;W%lkFVlz8xOm{MguS{MbS3mkK z8@X-n?8}0;)&Zl&m4b9-c$gZz6GT+6khUddk9wFXcE*EW{?qz-w9K8) zKN@+LqOI=gc9h-PS^%LHyQ#CdU9X!P@xcM);`(MGRTci;JuHt_nR?g1$mM8XmiKy> zkkpOexqUFrc`g1XF4p|-sdw$Oh7g(vnYC;3IX0xHJ|q}fJ;cdj_mtbR<5Tr@?)eM8 zks&iWYeFw)Ru2=Ng|`nBi??D*A2GG0We=y8m6=EB<2JNP)RzzUjV1r&W~d6;4TreI zTNbhxa?ImDm`-6__c_}|q!XsL;7+-#FSAl^1rNOt08p>ugd*u-``Cw1wBzk@G~;Vh zsH}XG&iB!K`=^y zE$U3F+m z0C;%3l;z96)>qy_L&({{*SvB2p%BZi|FhqwE#R&nx~0sXB2e(kFI>^!L92Z)b*4aXLFN~Wc9Z^5)co%%B86eLpRP$bzY~P^i_Sf#i<+HYW6mV5RxxS zRWgK~(gDO#Gna$+XgKXxTe30*TY`EyOS=%EGcUI-w+~+^vShA3`SAO{L%pZrn9gH5*JQv2Ejs-+g8{SoXV|Ak=CgWMY8|4DKsrkd z{9D)yWI-#!F~zbTK4CS-EopL$Q+5_jTg@)ppH6#ie5fk#zEqeP_nav$-ZPEy*Fk)= z??)F=&xF0cvqgog#W7P^NbK#l+Fn`nuKpLrX7-#Wo|~M-g$=(f1KV~gHRI6Fn8Soz zSsvY=>)llyI`DJ;@t?R}?ET$|i`Bll z<|CSk*_7i}xv4ZabVE;SX1XhyyIT|H=48Z}8T56JJ^!JB;2CdHWA51NKF$Hd`fH8HQ#8nk-m~#Hd}ome6aK%)Sn<*Vpn{qd2M4wjCsWsz_2Uvd*Z6~ z5BC&pmByNGl{I|#O-Gz-)%-~lr~YmsRj=9ehm5{~Wq_OsL$lJ=ONIw!mhhJdFouY{ zF+A`WoDudnIz2wK2q}u;UAlCOlDI_=1C#58x@IN+Nid)U zW;VyneR;uB2?wMm3)bTU>N6;qcnOw?Qj@Mnyp7zPEM&Y~E`v&ZN3%?0;t$Cbwq#3l z(#+!?`*DY7lNjXY0K&HKa?eoIl@3O-3`SaxYahG}YE&UGIiUYN68nlka05D*UR?rd zSsMXFy>v5wG+K174hhcYnoCy>Sy}w0J@)FCe|5=Yznk)Tee=rb*k-ccL$Rg7*wq^! zQ&^5fOn(r<=T(EWjq z61J@fV8H~=nZW3S6odc>3L?^Rh7wOozaD;h(CL2t3j+M@6(p9LB3XE-;6~t3JT}4p z+B9dyS>sj|JHfG;)S=VOL3zHFAsoqPhPc` z5lj|@c$%Wo&41f`6tf{DBS;9^DGVASb`)2LfGr+~^m}CP3%xr`s-G2J9pTT$=fZ3{ zHtC-y{YNnUf9PL(@q|0tEiyyv{;20OQ^}*dvY|%5ti^!=nVzz z5fA>=kLkdK74aDVE(Z$6{6@RC;$uiE;YctxI89=EqSn3h;%*R=0eT{u)yT&z z^-!)jR0x(eiEar4L2o43_Mk;ieFHQIAhZAP&GN03?2EPE6b>Rpw0~sSy&a}&?$uKn z)Go`AEzHr8&-Ye=RhHK^$5f?sp1y^S7rG!uHnYG287-(K3s zVnQ`ur0h*G4Rxi$&vJ(0*%v=%v*IIj_V-8sE#_KS`CfAHZNMNX4}L>4JjvHkKD$`C z&p@CB{T@P)I7t`TV_lk745VL%`z{Li4$Ph#>()uH&!o(e%QX^%6aOY(Q>ry(QBF-w zyLM&B`~z6;a;6o1L&UxOHUuUxLOEjaE&R-8*L1^9O|44(!``VK_;cH(^(qz&WMg&9 zT|RPQK)Lr-VkKY;Hl#K7Ji`Y&jfazC1mi33T&Dr)19XkQTZ@%f;;22fE)Q2?^V-_0 zYpqXTgzoQ=1wF@xN**+3xrv3umXX`S)&xs4V z70TGp&KF+yE0gYDpH|BFCi7tHHghL;PZajm;)Hc0ZuI9%HD-TahH$x#T1Q9ujw@j0 z9f4ZH>xYbuzbl23UD9(tG)m<5h<&lA8V5)$VhZ{_4&Hcbi(@AamsU^iRnT;j$t2`l zGNjr2@Z!qBr5P~A_I+x}LV{N@{u0O&tDVhEdU?96jGR%mk=Xw-Db@PYW5;mfXkBeQ zn1zPa0El-Zg#kA1aTpHwpn~_FBIm^-MHr#!TGM>@aIe%9R0NQa52^FvXnSyxUKll%*chxz-2&`A0)Q$68)Y}Z1JOiwi zxU<(A^dl#6gM@y26_8Tws}D~X^v3Kk!lf2rYrw<2$)c13b7GP9hllg)k^|U(RoF_& z`t(47zG8=AHzqV0eTNgSqN`6vHn$Otz|w$wR%JD>3hZ^R=ZP?VH$U$02jJ#<*lEWc z|Ac-yn1adU@pf}PGVtPva**06P3plNx7$0fFgh(AA+ zu%5?0dZaTfAyDBa_EnHji%1Z_#>d@*PLb0CUIOui64La3yjf;Mm}haYTLrC5w@|8) zbg)P6saV{mSaumiE>_&26Gza1q> zuauk>*x;@eA>4?-lxed|O@9~?g4klDg8WJl< zI$ng2*=|3zR7y$tMv?m6qJqrf1Bx+YWSL_BAWL5ui)b3=Y58Lql~QB9-^0PtGd5=} z5+l8GNl|K}RvJ1D3|NQLaWb;&B$=O(d{|r0ZA!Fr{m+8eQ>F^)FPw*2hSY@GIqe5E z)|@bKH3CBSe9L#2^tvbq>y|oxvCB&Y6Yn5jG&p{s;{rycL3qSTJ@rK5E%cRbgq5e^ z)O5;}fQ*j=c{ergL3!pin(C7SpDu1~&#M77kuR?`^8*0P zlJVKr4i_T<>%*vCF^rn+OOpo&ly@GTTf*ec%#{bv6w3Hhk)Rc-8!HJD zt!O(X!+A@)CCE!F;(~-TLidTSNVJ%+gv~vyNkjQ3Xh;Mx_-Kr!+<^%|;z2Hz4ACy~ zRa?u)D4lIq`Of&Y?40(>h(VRcU$2YdTY%=;z+gyq;Z+sZzQw+1i8v$vr3k z@++PyvOjw|R7xoG1rMN?I?H!HmglDxqBBj1t`Pfs?^hxW4q8jB9uU`r|7bX}oFUi{ zc4Vv&aioOL4j+#A^rgl{?q(Y~fB!EApeo!0&1H&NcRl(G*u!>(-}&PCi}|+lBLGH^ zxm)Y!Cuwn^0M4AdNHZ+Z63E1ut5d%}v#{1^eJ7?$HTRbtd}3v03U)EX1UQyi&Mn7z zeIJ^-0om|xxw9UZwnBd%cr!k{Q@`Ezbo6}~&0k~p>pw1TM2wWIu@ofSmRw#{lXbqX zbu7D2IoDpe0Sl!zStSMj*0D-MAITP9+^dQjpzDbNdT44<%VPU?#ATOENo2ugHZBw$ zagrwO)Bm)URR4_KCEjYi=HfNpb-K21KolzX^~X;-6GNoK8b1e6{Drt1=_$Nwd*OH; zo(rv`1CjvTk=Vn=C{dm;`$&xb*`e@_W&px-QqN0B2p~fO-0P{dvI@U#b>s77@-np> zh4Rej0{5-S-}g&;67wy|BECB$F#PjxTyN%#w_LX!K>*ZnI)dh-&4G=R&=mxvz+9`J zq|P*?V7U)4S5l48+J6V{F&XzBk?`_E4`g94lr=mr>SnZ20Y3KiKy@N4%UuyQ7`p^E zQCSAMW|nR}bRwp^9fd?}?qOE*LBH2-Moc5Z=OYEDba|$w!#~qRk`M)IA&7tfCZqrl zH4ENQuQ~Np3-LpKJv$oO!QYIPyKv{Knbn&t0qRACsfJw#J$4V z!P*f`oH?Ac1{lfBH*j1mJb4u|qqlFj{8qzxQ8Q^TBvUH#c)&M7 zuY`-ft}%4aNvnG+IUL7M^z@n0)?ig~-eh(VSBFT3>s(5M&$Ko*JlcR-xah~K8&{XD z#WkhgznY~S0hk?szgeq1>(yB{G=hwP^j$%&5-Pl@VvJP{5QmnATfC{0IQ#Ob=2!v& zASumrzD?eo#X$&3OnB|Ztr#P1W+90eG}Lo$6y$_k|8^*}P`_Q+_h-|GDbPK3Sa&g- z$@=#c+dEa`noMt)Z$&+P_2S}nVUp$u(itkL*v*v1*%&nVPC)Ignc~t+4M4f`erPBR`X(s zkU`kM7ED!xa2gmW;Qf9H!--wk_-aneVk|>1?Un8Qr+3FTrr2e3zzT#=11`>D!#){VmgQYpJXNrT)I}q@v`LK zi+H4t3w%+$ee=T4$B#`4Y%2U_o|Na)K~+j#2JHQlAiIlicowDrI#!T1gAcTlM|Y~S zWafwcG16JdBH(P3Sv#dzKd8fpIY0O$P!tSM@7h*dZ>@UXb(Q^KtOU639$zCe9s3}V zdfVs@n4SKu3eRr`^=5u5ss}L7 zTD3#gMcpfX?V8M1Zj4_6{uS|ARtyicsZTARg;2vX8&|ipxF}$NejsIczJ=KtMTSjH z#K~C2>of+xlna?q%vD!l^rJH)qB@S0D$bd?UjB;Xue>KT{Mf@ zS!h!%5>U}V{?KOE;Ia=re^5a;I@I8OqL7@mF#S8dixXs-INxvkR@G;}toj>es}Atm zI}^G9TKZZ{Z@`wr>kMdtnZ;y+o~5n(8+*1Uxhy=AZp-7eKpZ^qnpynf_NOSlV%5<+ zY;YYd^022_Bv47#&o+#zL%d7=W;LN*bN!+a$&^dtJ{-nxV4U!@?pcM>U3#GPm*w)= zBqGyig$2V2I5SiGJ!l`WYtEXB5D3ZRpid5Q3}_<`bR6@VM}+~}0u>^=_2#3%MP9U% z1$db<(%MHysSR_k{L!x@XVY@|IqKabfKe|hxc8@n-uQymOQqjZ(_b6V zcu=&Zc3fr>vP7sGKD-wbLi46H!O?i7|Hd-2)fK^hf05=1r!W5cBU5$w&ruNgg+t$8 z#0#1-XC|N zV+(yIXTElo6X)G~O7VAnDNW<=J>`NH8OCqYSgmX$a@or(xu@CVhbwGF%2XuR1upIk z$>_ZSZwg;y6cF!UlsR}U7_6w*jEY}`&B0_>;Rj7E4vhnK#M7VxYCIUu#V{m6RnWUgZ1<&#@t)vGK6Z+#e%&7u=*U?pHp0ME?PQ zoSqXt_w>l7QIfneC619AF9hUza>Bl(h{&NQC>zyVA57H?E*wuVU-zhv31*P46@^2B z@zr~W2Z}$&4ORMHvJ_+@B6?e7`|bO(($&|uHRl}hNj6g<^~`MnPiEh7csZrq>Op_1 z%clr0mhBr)#``E_Z!_L8=*sy;=Ge@(W(Iq7L!&dIN)KHdtnN(IxxGJu-qMnImYti? zC3CHlCx9@bd0v~ezoJeldew!Fuf>x4pZo=w z?-+sBw&h{sYkqnc?`_7CkKTX_WYGE1O#PWeMV-(ug)l=S7Pm*7#8~Y+^W%oU{O}|{ zcy{?*7rGEznnoD$2_I3Ajf z3)&LF(r|ZcENf1?a#@oL5?XysARO?S?YKzQPd{l|kxXRnmjd>t6mJ_?moj3(y(!2+ z1$cr@DXd5yQv+v?7p zjmSZ<8;uJtLzk8n$#Lpp7l-)pp(DVKKuy?7pKT>X9e~IgQ@lDEBvhG1L#P#%$NO$f zEQsJ;xT7+b`5rf|(#0maXXgWtS)X1+S}S{~2(sMj@)o!eW3mx7oRdRKq~8-JNk=WE z7~NV_6N!|(sQ>p4$bfzh%IB7l`R9+5b`iU>MKW%ipImRb!cK*X{o_pDg!$0{op!bt zXxBpT^%9>b#P?pWt10KGr%mzkaAsvbeDtTItZi>Z^i|!m;dU~;yVThd#5%gD)ZB)h zm{Z=<#os1lRw88mf=Fz$B<}@NPD0a#_y$A2sJb&#;S7+^FtI z&MLY2FFTX7#lfZS(?KIsxxjL?PIfg!5K=OVF9fnwlXlV7E>(sS5hf zk-^}aj$Q7GWtWxs9|j>-kI-LUYpjH3bsQVo@fFZYMXjG&mlBtBIO-4>1>aLv=_Y~k`*@=FV2W>kY{F(|5Z7B!me zRgWwDNsgqO#U5!_+pLxl!H|XuJH1v)cy3&Z7FD0sUkXZfbAOrw-$jizkUmkd;njtT zqF#XlTIU#vxXfcyjP@r2tQy^v`J>PWx}wEb2AvfFmu`!S!DJ9Y>u>LpKR(>)11559 zuLDi*JDe<2qV!DIKDj)RE!F?SQ=F78gAOX+7{>5;NK70Vnd1RgZrIr2(&or@A*@|N z&A}iA_K5p`NDoS)n1nb`2q_Fjir{sSBXM#z_j}i*e%5$UCNkl3_ptmGH z7$Rp#LA|D`yC=P$Yi&K%93P4W2zEuRLoJuJimWIMFCE~z*S{E-obn4zz5nh)e~Z!s zwZCn=VkTx6#D+gE#pOx5hiL`}e$I;h&U(h>*&k_%MW65p}6& zGg)`!)!wy^t}7Q|sO&GRH6Ssw_ERzSd+ux@MLsk92Ef2hz!jaWm&K)J+9ylI&JMnn z)5=jtVj~s3d3A`X3L_a^_+X?jk*7um1moQ7VB`bp2KwYyOhv6;l?kc2P+y^siu;@M zdZ?=EhLVjxMNG(pWejJ-%YltGi~O&FI0@sb)qsYhQVN!f~xdWKl1-(ghR|oQ4C~67PGi z$ma!ReFyz}%$Bx)&fW#aZ=BX)7o;5$oYI0G_dh6ZzWwI!ud)v%Z~cAWf0Bi}tC9~e zy^j_FkHaq(huuOX`Tf4B%*12Rx2)Ul`dyHX3IxGmt<#I`-;I_AW`mjd38V!gGwhii z=vMQWM}k)G+C|U+3ooYhVA-j<mCI~kEX4btoJ{kB!f7 z;decP&)#(nG6j`k>jb;*c3zZyl5!SGlP3=%1?QvbJtzPER&YlFyHB6gFR7#QZw>tW z2V<3oCnpx!lVLkQ7rBZS4}wU*2CmHwIY$!_Q{M9EYVv&$T3sQh=qn&;mR3)}4oGOK zRzy`BEw6eFW1|hjpH+R@2wT)IiZ94wVu?76IB`;7bS)()16VfnZ5b`^{N=CEJ2de- zcByt-)Yc6_lL0(67SpV(5uIM=bFG5-oHHsC}x9e?)@K^guCO)8$^7OMMFD6c=^5SvQ@b z4vgvxAzDNxg1S$G7lo=a=JO`y9@bqaVu!U(u~kmec~D9-L);NEV0cWV z@t5-cNyug(VOg}*&+JS&SSvy`>}j7a&4`Y4Gxhna-=IDP3GK;yh5E?zbB$V@;Zo=1 zZQ4x*Le%Or`E#EcV4aNyC6}(()}FX~U&wA&kdflGJw>-}gbfC7SvYNvXl(>~Kfl;Z zi^gPPHh5lpwxVS~_xNr<(!vx0_}s`iKYYu5_1JBh^PB7_b*vgS!AmLrSDArp1Bv1u zI?eVG7bV6U{Pvh!-4Zb5L?^gUFz3ks%m0U@HE{TO4T1~wv&6pr_oO?vez2_{Tl&k^ zAi3}X5jB!z&ht+8@iTx_HMoRN4j$r(+dp)zAs}91GyoRVx9Z|Pf~(V0yQFA5zeWjQe!JH#jVj+z-5)w2#;h@vwN@#@fWY| z0PMjl>%~OSd10OZrQZ&eA^exV?6YLG6j!u8=3=+?(rD&)Q%uQcpD_i30I(_E=b!{i zT6Iq>3@(K3lA=UbZcve&4{Nvag}s(V1*H#5S}_g)l}cjj>-L}3ow~()wy?y(AzD{+ zh+}&<#xcFPV!gCyXd}Bd7?RM}@uybe_C&)-`Q1-X%aVoW)@t|frb!1Mmb;v4iy*OX zVeOYJZH8q^El4`p71&8>@IhWsLA7waYR62RjhW}}o47|!#3Qwi+K5*Q`pv96tWTc` z)=Km{NkQfEV&)d{9kjX{L&O7I3LJFWBqD6`~ifq0+@Sv3${pSLZ=777T1$wtC{#iLCl;XI=qR z$Y}#|5k*qD><=i3NJ$%G_E}bS#!dFT2(&)Xq8nIS>!#y-_qK*iA_>$;=-jLbKH(J? zUu$gB4ubk9uOHqJ)X)Y|dcjVKs#^KuK`Bbmz8&cin&NT~+kAE%ei9#8eb zyoNcAcG{COlPT8WKMrf@%)LI1Cp8IeOzL<=H`km}2!cl_;}>S2YrDBNERE)01|T>%ud0)w+}AKd-+V-6KU) zuoUc0t`4F*UorgKKB8kC%Ioo4qQ|Ef%}-TmduzZSzl&Y0iK1=1hnQpYa;avOIX<)mMG569z2^4-RTUrLTv6A z^7@3j^)$f~VJ||<8dKmzC#?6``u#`LH@^U3<+Y0>?MHf*u9kuu;$W4+>FfAo#{FNi z8;-ww<8xTe=dnfg$NjyF)qy2?>v(yc8o<+j3lu*?q+@>b)4$vp}nROPqn`1+I_ z<6clIT}QBd>3CP_!d)%=QT~5-hh#24=4|nLS~q{#Rgd5G6DK`-*pWNq#Fk^uiaTRD zbfWpSb8O$Zdjyy8zY9(d-Q*T0mXDWQKAViaQTd`gdUi_Gva(-Y=KkgjceZ-(NgD-P zyyq~l{zhBmewq`vKYq2)P#(zJpZ?=Pb*gJEe_ytvXFA^`SF|k=6~A8~-z*n*WX>fZ zD}#^@(BTFndre95+on3!8yzL|RmGYF$XVT`zFMX?y1p9!rFnedHiFu+q5I}xv&pB~ zi3mmLAe_sm(oTr7>K_Uuuwmi?D()U=&CYz4xs};)>w>BIQXH56)%81x5atI)eZ>9Xf9l}-hcjEk-2NLsw3aa+J)Io*EQ+wHy{-EXSZRIRcrINZmP_4se{mc&$na;CJqNM0tp5!e zo+{0e^iGbD)dUd4{j4ESE86&4tOzVn8+TiJG!A}crw3SqDF%QcHSgW|_p$%cFd<;b z`SAugK0R8Jy(hlDBSEA_5=Zc)z&D*z+T--6{zgKGM&sD}xvS0f`Q?$imKha%2KSxt zU4|$XE;LsX1J=;}itgVAE&=bOgUzF!3v_@lUW#?Lav{}RBM9QspeQeFf5YqD`-`x( zD|P7La`Q6+FoZv`K!;qsL@zEha@|nWd6R`GqJuJQhMjx0Gu+8ruiJmYbN)Ka zmi;&1laM$^oC+BvguHVkU`6+kT0pbTl?{Xw> zidDqbXqBK2xT&R3t?_i*_qK#bpd8_S0u&>x)Fmz{sp!BY?B&)U#l$zfyf-WCG5snl zz|G^Y|EJ0+$*$EJI$w=Wk>@tfvlhME`V^D4n>!{}2)MdBM|d2l#zhZvbxlkWZ{Jzr z_*asz>!gmcYCQXeN;df|5)J<0z<&oAn+s%ngkyJvs<`E3E4ToNw;dUYktd?U+b~G zB0$R#9&GNd%wG$DNCrj%E$-Sr*yf>{g_VKW6uDyaieD?_PLW-M?jQiMZ}EWlfN{x<`6k8w=(tHmYnK+h?YC;{N}+5l6xncPP5lmIR0zt~}DG z0IUtn^n1de6yr7SiDz*tRvN=QV<=w^);ADSC~juO zYP53Cnz{fr)U0w;u2952jIWigwB`}55N@5TK{`24Q@nT#uo+cirRhK1jeVTF7^Mi} zhhMsSBs8?D@O6+H?kVP0XC`PAZ~wkYCBG9+5pdDNgz`7k-=YMuH@+SSNGsE4BCyf+ z73^`Aj|li!$w9?k%$rwC zt=BBju}pRP6Q7Cv1c6-Y`Ea4Hxer`j9(HlTY1;_iCPje&f+@#V%fy`m50sHc=hbvP zMXgBejf=d)my=nMfPg^QW|xkf3;>OZjaOxebxD|J`46D9J&U+}enXk&e@J7|gs_*X zGh#a2eVb>Wj9*tTzTvbyzIX7P`rE{!{RPBU+e;|!bDo}_g8PcfR|9$<4VJ7#=#%+< zo7#-zEhm_1C9f3CLSKE}U+U*CdG2=Buo9bVnEf4pm9SOaiT@qHDccmFd2Qf-Z6HWx zB(>hZU~;oP#sl^QV7mP8ex@r|jMx0SqRT|$3z%R-|GL(YI~9TgXzKdKfX?oir^`pJ7l31HX&HCizKC&*Z|=N*K-~wDIPX`l5?4b3jZc zJSpQ(LLeqdM5aZA@_pKcz5~-o=U4E0nRNGU`I8{cQ(E&;*Ti2<%3;W=WlAOx$|o8Y zrR*sH^YN%2-n+W^~B#5z59D@%Kze9ZhAon0&2LxTvw~` znFv4OlNwM2h(HP$6!+pCV99Ton{YD4L-RlpIe1~*^v`$QM00GFSJ&e=i%WN9KQ>i- z^XiM2-HT;aXZ|5;b7>?oVi`qOd(WP*J9SaUH;-6)u>I*yaD|%Ks;wos!-;fFvfyYA z`K?n-MT(%i;73^K5dJLSbeKv{m=ru&mDo!4(fMI^J+6IHztGb_`t6|OzxA8y^Cnn& zaS0pUKgKR1;=bXv>O=<&03`ifZ+I>1+;~Bd9H4+ODm%rHAW;>tte%~1I5CfqQZxpK z4e)%=g0Z7*V;l+WWQ|2w(5T=Rb{JPN9?0weHaWPJ$iEK{XQibJ+7KF&7JVJobp;Ml9U`7 zRCqW%%dB!~INM)(Ln$##+Fg$D|3(}J*0~5EPKhZbf(N~=v+I=B(DrXABcgzpvT6U> zpS3L%dycVBHF4Spb;PW9q)KcSm2EGXQK1kz{}7n8I&WAbV!kPbh+Hw>Oxj!+1>mr+ zn_{6Q9pws8D3A5p^rLnky9K8nC1SkDkWar1IZ~n@$+h4eh z#5{e{=_WNyW$|w+?kxJ5>kS}|hebTMqW>^X+I^Og8;>U(7zaz|Z@s#%TfwYai2rsQ z5BObu2@`_Iyf`*3I`*EGpCRudJ_j#!n-2ER8r#>anO~RuHzLYPp2t$-W00V&vq@3{ z!v-?-LTE_61yE=I)4)lp1(C%2Bs3QUX#uy0HOYvnvFkfSI^^utuNlL<3Rj zFd$E>>q7ZuDt}mPumtteNy$}4|Ch3=5=E<$uNDYb^0CV<`A`DoP_CS%_7DKNFw#g6 zDSm98TzfKzrxsyPnTbfQu*9l0sjC%!^xpEOO|v=*#U}xgO-uS?f6reQg)YNuiq5DA zLtMo;<0tL76tsx=hymYUug=s(p~ehC7`1=X0~hch0wD@ks`kN(AgaHEMutnu-3C{Jqwc=vD*hdU7 zrU+N!LBh;0=ih(!5sHO3w-Ii*ERsm7G_OC@*t4G>=xM)kLiCu`sQKhX1`(A}CGh_$ z#;ybO%e~oTb`TB8tgGg9*V>=DCNWQckM)0WKCM{~B?!J9zxl<_;o$)k(cZZLaBf2t zTY)G1y~ojN!G3t?zF4_uxi}BoC6yZd`7YgDj#+M(rc{@7RVPD%=+;hlNtZRm&jE}4 zOTZ$X`n_qM^V<6JN;wK70-a@mFzBDYxSvAR?V0ufiE;1y18K&f7kgLC}8uGa5InX|Hx2)U6642vI{c%41QAYysRaLvW7KZ#rd^B7l?}JV98e`nU(&y>r#?%9LSV;e`m3ae4TyDUuZ=_?hsT zu(yZ7o>{XiMi)b(bGwUWhhF<1%l}~tB6s00{0~!5hXeE4W%7hcALsK(4Hj+m;nHz| zkO^T6nGjYu1Du5gh3Q8cBY;N?P`_%wL$nP+jV@Z)*uk}YUEjY;r*#`T6BznJN{Yz8 z-WbuSt)dg~_}1VRqy-QpG6>0k-j?f&z(8hQl5xRvfyb+(FqYuJ{Co+&e`p6L{B!;# z9ahv@A59z+@9L^O+qB$%&oky--V@J#d)eQeFrn}Ef9)o{q1|h5nXIia_ap%*uCG4! zl$cFgOxkHLugp-yRDkEZ)Z`=*er{jm@C)$P2AvX%W9dHba=2M(G*@OdB@iHfuv#?E z(bW#7n73Y6%2EBL=Qi=&OJ5$|(6J=E#Vwx8R_WwnCf@^kwDtB{igPzgONSrIjG&c{ z!fpwe{}Ahm(7nF#bD4qH+bM{Y|VOA)x%C}_ueWF zq5bv~7aQ$J%av1;*IkHrpAu(fW$YX`Lh7oY6XPxA+31<72m@b;a>cG!Q8Zm61&wH` zo^)Anv)fi3uKcmcpwZ<9s{}_Qs45d19N_DR0O)ST@!iu$`#rbWIsUTCvEUixvG9Bt zVT`g>fzIpn2a!q#V+sCj#LJ&Vm$-}ziV|(qiI;mgY zko&aw<|5&eA2WBUC1=$axe?_ROvr<6=)`lRY;IAt%Hhq4EDJT9i4L&SzJv{o_ZTc1 z@>FU~H%9*!bP3R@lVLi9PQ@mCc? zeBPcL_$ctv&gYl7^?yl8aW6v(S`5>6-t$MawAt1FGgpu3!xFV0 zWiNP!m5XDNblc`1XhdcY-#nO4nSV&-Gj!moF#O>%1I`Dr#5frA8HJnfD*Nt@7Ft_f z$7`D-q6F@YyUsYh5A!;2b2nu_bhqXo?zL@)T&Xqw#G%UB@Sjr-*8-onTcr4O>l(4G zC}dC^0POeE*3hJoNi!l=B5cBrbAqfiF8cxy_v@X)_vBf-iQ?m1A6C^W-()O8pKCl} zqLpt;wJhDob8JtEkU&u1O%ymj+kRPSS*E?^Tc04{u<La{Ud4)SFkACi*Ox;UU#_1m&iYwOXgjWS3}M;%0mgipL~ z9PS+{dKs!Ig$dlK&3$=KBg8!pRWv-F^ZIL&C5GAO_rC{yh3onLlt`)fA)c_MD3 zJnp9SneT69x<*_}5dsD#Xs=tT@c`)basSW`_c>uF2f`4LPdvUBjaMupqN2AHy4r>E zDa2=eLaq8IaDFt9MC+XBhavRo+V6*!uGQB|gOZ-Ke3ex&C&%Eu-)DE{_azx#ClfxN zr+aklQwU0Mb}(anwtRBmrkoE!EeM!g&j<9;f-h(fnrI5d8>I7PU#Fc6OK-m@Rk2Jt#f)l#{^P{xr9{RbPoiov(CYi z6J`Lwd)IhScQiwOP9oSlx>X0WEw=2e2uj<%8z?@S{h=`DP>8WZQ~rgjn&UkZ^T+)L zZ6*=N6Yo;hXma$XZ&fP(dO5uV4`9#JelF#?4BZzGOtJHe%T>fXi*^WhAjm%DIH+lX zo>zHxHQP+cX`fLV%Kh^a-*IlHxV+I}yvRat&x4%09Q@vmeMnC~t<$I8%p{F}rQ6u^Xv)k(pQ85n@kUs%K20H;y_ zOa3Ns)($+eU9ya^fPxdkfV_1|cH*2dnMsrBN1+kaa6>4OG-63{X}EVw!YlYR;tL^`v{=Nn6@)3Voe+JPbEv%@zP+uUA0#4XwDRU z)uT@v^Rvz4|IH0t8ekLeodC<}jsxVnzM}-2gy>YyU3?`-Fu)!OpP4!Wt%52+Lo;I< zH9z>v5GzG{OVJeF@hUZemUac|e4qz*D)*%ks14*Kgqp4b$IUfI-x-gu3R&>C#|$@B z6%cCnDINXcP%`;`O0rWtasBFax+d=3=Gf@u&UL9`tM-0Qv`Q~;s9_bVy0-4gHt23?Q*7b+nu%8h--p0lN%Yr$Zy)3{ufbNac zt#gzTUUvUTIzE@m)9=pv7}X=bClR_{1TMvM$3hgKsEH>iZnjtEBFsJ19O8p9PN{K^ za%!=McZAqvl1HV!TN3iO_qq6NXC+8dppjj^2Lxc=CWC}hm=-~dT^(^ELBs8&jV(nK zrC)g)fWTY~e(6kz-b%Z3e=|!U$v+f!)qbcC!K;EZc({8Ltu<_02cVzrz1zGh-^oz< zNjJZ3lxH@|(#3xxR-Nlg7cz8U_s+KDPRqx(52!Xpz=&CCGfWAuG z&LIIRr8?;gFXV+okR_*WbTTIY>kf^31??2(kYE2dbcpL9)<#}1zh`i!S9}eq^)kzC z+fTwh@2KhL>PNM41AfrupyZeo6N%`1p{Hvf8h2<_g!LYM)nqh;HzJW=*0tM7pBalp z#~JY%H3WI=9}&GO2T0p~Wn{PN&SMCdfDRQoxw_C7Vn*};#VZM8GZYfD_i8-p`RJ=L zsBH$XqFd@;IlK+IF@Nr4TuJuB^C7TW;QtD(MP%vw)TnIei%ww>Xx490bGKsvFwt0H zRJL0mxTe`a!c>o(nF8XhZ;hBiUf)Gg5QOUbKIr zU*PnAA_+pNP6a2V=Q8z}LfCuIR&zk)Gt8>F#C#1r(&EJ5{7pa*!@T z5D-a00Rd?Rqy}k0KuM8q>28?saPNJ--~2;7XHM+1_u6Z{>s{|EwFY@TGzPqK$a^co z-A8Cu%cgE<&qqi|Slez)PV!Y^g9mW!q(jd^s9X%#3fc?Cc}ny{r690qF14mbqh#D? zKZ_`!rxoI*0$p81NXY%IZlaq}-D-2!;xc;TOXy8q-No-fy%A^{uWA<`J)2rogFc`^ zw$E>l_{{$Q;r3_@rQiv{xS7+~NK0x<)OVO#A0PcwF{^M#lkcN9C}b7CI9|l_iSlWS1f|ijua<2&BdYCMS>er`-2t?N?GM1?(8@ebgevq zh72Gdta+*}!2Kzawvd5BX$+_cyEFfS$`R@ImvMnqKw%W8+u5gz;BY-2+| z5Au}}(ITx3?vfWZSYHRXLOm$vT5(z&bWM`49caBvzz!>i|alnRzk{4CJ2R;4Z^J zUL(V8zdgO~^f{Q?^qu~Laek?jw^Ekg6)EaYc9nHo84ge9>3`q>Dym(hBtex8$E)Zf z=*==Zy?aW|q8A+k2X;M(_`0dry;bnuVVt;;Hk&hJ)Sum(CMTxVU_}$r+NLx)?%@t*UExA1C0xg?;S?E;q zCUWbACHY7=-Z49;uY%)bs4C}Nna?Zu=^V6D2cwzv@G+qkhoJI)u)6IjLfphLDP#9$ zkuKobwahDqqZchMIl?C&DJU2>7$~dmVK4P_qyL5=CZVtVI7eW>fe{sUbSegdFZxUE zzH)%6;G37?*ZX%~zr?tW_+}7qM&OS176yu0j4A=AnwHl8KnF7==)V68I_N^PXcyK? zNn>(TaG|O3$kN^xeTr^E=b>Mr6VPwav!KB54<+?O_pV>S3UMia{B)YTAN1>2Y<@x> z$!!KqS%^|2q3KA50Sqb#^aQQ=SfEosx!MO*8YS^OPF6f52Mu6ZAygJjPZamIMZ{kffiFFo`M-ddarMe)&ds_ zb6U$pX7d7IwbW@21F=Nk8ax0N#E_!ermyT(`POe%FAxY{pMGwsQr)Clp^3trF=ydcnBWQK)Lz-g4^RwQdMLw&RR`~Ol@j(ZAp zDgWF{kR5;k@;t;dW#_0Y7Re+*eE#$z2}q#TJ*)Dm5abFby)aAD3=QP)_rjZ z)>Pol-7p8$l_IoSua58BIO0H@ns18hA2(LT^Q?t~xV`h@ocarxP1fLIu)OjW0o#Y> z5a^))=0Pa(GUT+pTkX~n;Oxt5$R)JL!a{}w zOz@18UM2{P-64XpKfDDvZF@d`uV6bloKyC9o+wC*(Y=sk&2~E}r=Y*K8Kw1I zuKnI8YWb_hSNG9X{)HBasCXf{;)z_1h(b+TOYPfUhcbPeTca z9OlO)iDx=|>>u&vBSSl@d&1%PEQ_T#TV$nooDhQDT~U$h@U$f^eE!$BuKZ5Mn;HBM zGAUD1a)})^`!7~?OP1&L10Py(Gz*Y5d87SXfAv#hu%KxqDwqx?f?ME|I3uw|!C$dU zOaSP5rHb1K3x9=A&F_R1-Y&lWM=zZLj5vI)3T zP4UTHn2kM5Y^~LZ(Oj2;X@-!Ch@EXn)o170XFmWlN0;myLT7xw`EwcpVGo@PBz+nj z?$!3!IS%)`Qd!AdnmV5AMM?)xH?mNyQ)2SJ7IAkcv>aSE)U``dz|zPgsPcPU(LG%| z3P(P^$ka-l)vA-G@0{p8pkwN@&xmOm!FNr#uI~?Nml1F|lfXG){_!g+{d36RsORx+ zXPc2c@ulCz)DnRub!6*p(8Sl7RR2KpC)capzlg$+N0<(}1NZX=W~4V-nQ-`QFi?y| z1&=@JUKY4#6((9Lv?~0lN;@y1EV5MGcBh$5{qfM7!NHYpw>c^D~d!UWs}K1UX` z7deu!zNxHmXk-eZ>ovaSMHdo0_8C+V;YNo9T|amAPJ>6e#4Hc!@q_gBNYnvGidW9E z+uYIN@w;&}8K4^{3|nk|8u#gg{0NRXmmuEsgQ(TxFAW5GvCVoE@c$@x2V#Kdy%ch} z{KyE1X||R|*UN0rqr>@N`Q6GUX+F~jqgve(t>$ihn%%TT1>e~S{%~UvBq8qpYS1w}!{;*N?rfH-v(D^g5y--uN>uwFXC!=keB` zw7*e4YmSzwBZqd*lX@L>OBc+?=u_eiBNFVe?!A3~LK`6bdy}S{;FXvy7l&$WwPj-V z$v<3~Mpj(%JU8l*TdHVR1%}|Yrq$ze>_T2>9fQr>5M~Qmw7dGJC>%iBW~4#+lT)Sb z`#2F%Ph1Ko;7;Bjn-|azr5b8=H-%% zN&KgC!;xT(%x?x)H9te`8zxk%QVAPUrSA1702kM|NajWJ7dT6xJY>^W+Ffak}`=-S^IHdQ;@!Twr&bNOStppzVhY_^Y-=#|ALO|h|D_t}T z_tHxO@qBXOENJ>x>m!&@V2A$s4uY}#Wbnl4(New`$pBn|qANd*(q#QLA_^CKbe9|jwd10Jak|%1n zwX?c=yw&Zn3kkvl9IG@T&0GKWvrj!ep;6hzn#-fy$z6Vbe4-0O2%7*`SRaIGOp{yb z%@e#e;{-V?`kv#?@i9em`NO1bEmBYA>+jBz%mg31jbRI}FayNlO4p@LdUmSe84LvO zHL#pjqTG>zIZaDE00ntZeFFb|iK=TOc;UK|OmMl-VbX!7kEA!DjTLaSc-bz}ZN5XC z;qYVe_#YQcg`z#?^EF>EBZd_ClgU+NPoas1__mg(hIJU=a25l&`)&iyS`151v>6jw zHNXlvtGm2Dj`~|`CmfpgJn}gW4Y@DKWL5KP6G)nBo1>o+qHt{e$>s-hjDW-d6aW z1GdUDJXa<&6G0k$qOW{CYCP+^>~Oc|{;OZZ$(}JJ zB+ts)QGQ#crEgCY^V99TS`pgz?qp3Ku{3i5ZF)l^q#+gbIPBvovnV^ zvuTjqAwSlSF5dpSroEdz&;N~i_IDPyNcHUh#|+&V@}tO-o8;E>2~P-NGrESTbfv6B#AD2NBZ z)-qKo@WzkA6@Ed%Ri6oZS{lFFFy``ClK__eYj<0J(LZIvZaRpm>gH0Osmj-j5tnyd z>qwHeFSMBbAG0YutGaAo;@ll1`tjgO4^N%ZuHl(5(TFu(w|3fMfiXO+8wi2ol{uO}~8~H6H1@H&f35-+=BQ3443A1SiH5(pQH(J^`s*>JgD< zYagGWh?+4t!eSnWA#aWm3kISB7;rELT)!49?`jwC`57adU{Jkq=8WcQcLNP+$P65e zgQ0x)&u>?@{Dt}4pu|vbug?juCcbhCUS`@q`I!+dnF4yGBg_g4^Jz1iJnes+$rB)6 zfV8gSm+$NaAyuKJ%?+`v&c6?&E-7@6M-^+@JU<34bbEeCQXj>3y9#_EK~p*4#LZ(M zi(cN6@A7!NgadX*TL&srNaiF_qY9W6r;vUb;;o|*ByRv~rmtVcMHCG{?KGhw z^8%9GpR9-6J0Sx@HfU?gtMlF*2CiExtx?xDbgamti(Pdn*@>jk&w#ovK|S9zzT|vw zsz6}0BN{3D=chA&_8j4K`dseKcV<;1pF`#=nDjAXk^+5q($whB1}-#Zxbvz{AnyHY z%P&K0Uz$#L-nsg!k7n>}rpxL1c28F9*zEnoO>X}^)8dpr3DYxNKm0Bmz55UDq?lt3 z5lZry^Wr1><)5t81P$j+%A^y|k2w)xiWgPGJdwGW*+&+%MrRD@!kJ8;8OQ`q#Yhb(h{9 z_d9O)j(1e4`n3EEzk*!*plyW~ZYBqn_@jrHP&yfX7uhJ~2b=$q9zPmH_TQJVdk(z~ zo$cA#(Z)#3dya%l(&0shMX}I;LJd*@>*r^MGGkNd>X}bILl;MHko+wH`L`MwO*vTt zM14ndzXrq}$N}8Ii@HZQ-`EcodI?=FX|k3MPWy5*KW6x29@8$3%4ha5qE`(& zkG3lARK%WNn^{Zgy5Zg(tMZ?@07LNUq1li&j`ZtSl7HaZ@AfE&snQ-IAAnmnG~eud z{sotEEviqNEh$=rNR)W%-y#6FN5U!^ zW+u3mHUsUYW3!QvWe2O6&gju4cuWc_*Ti zg%l9c{|71PK?nKqH44xrq65$|DjMpK)XmM&KhbfJ?xYji743x%A|CIAEkF>s-~*Ra zY+NF)#0~?kz`cr@=4LAkvy~12&q}e%^B$FJDyrmV+V;4w61mGmrjEq;(0aZ#3`X)E z2o$(f^}H#xh)uK8r^kmB+1M~(MS&hetq+N-5!2TFStTn^-qW$tRdRZN;9{Y@vK(h& zOu}<(gLTOz;p$W*w*llEq%@{DCfTM48N{o)cjirWWu-0@DW8zScJfXnGw68JwCN{J zHao^Qg|i(x@|m1m&EsRI`%E8un)y#*;PS$<4>M7we(oN_1#?9+Jc*VHYU`OO5}$_K^%|i5A`Z0tL07U$J?qMNEW{NGr#70irslv&wN5`cs9Ff`W^>W-d zBA&bi{;6Vy{`|+E;k#blva+2W;~!!;X;z?H9$nLNNMz6z*xdo-U+aJITn}} z989Jpva(hucG2N?9P#PlPei=T@4JlO`Dio);~tu%{galTnfQn2&0}|OMS9eCDd;vt z1Dl8?Nukc+1W0%?Cd)p6*S5UAMw=R_a(Y2>Xc(eX&C0>V>OIY&8DfmS0X{m=F`kD{Qs&2nOLz7!daEcJHydBX%?8T}aVy7kf+bnHE;^+IIq1T7NaDM8Dq9 zt5HbgV{&DF#CtRCTTf7v3 zfv2U38C0}IIKc4Aql}=5FL;giQ(WQ#yMxJf zFprklf$kr^FXB%_4j8PPU;U__QAmYhW27AHku1x%sg3;*PK70=={7b^c4^bR;TI|w zUS{hp5vd4V&PVlYYO)zUw8w|W9~=&2676zO*>M04C#J9f@>e5!l;Z1{1gE@%Oq3b{ zg-3EtzO8Tfu{z%OchsV3S!wKkD@Iax7F*|%Kt)R^cBn8D@%*9|VIl}{<=G(3*a3eun5yxUyFp|pgD z^=HJQ=JJkFy@dRd7na26@LtNGUZyX+nnHXG^S0E}%S(@Bbl`)10 z3rA&Lh(7ACaYrdadAmcdprWFjos8NmIfp;$FL}+*Z=08gUtLGJ*i*0IBU|Hs^&T#6 zioeuVMqZan@;wOa(jypp_Q$LiR8gpnd%e~8_8NI9gMB5j_K*P7ip8yT7+Q$niPhoo zeZxXg3h0SA>ddx}dKbEPMgTRLI)(V@)XFdPfzHR#?z{mg~Rs=euXiSiw!cRf+$g3g$zh zFG1gpdW@5^w%{2pQgce_w@GauRB!z3p1t?<(4gcsG3qCgKi|yN8jDo3FnhGsvPRC& zgI6x2c?n@Ty)l6GE{eq=t~VM1suI}zenMpl0JNwwOQ)_k(&%`yR~vKm&!qrK@TSLXM^-JUeSMY zt$PQp;>V zpN>PFJs}uf2*4BSbXwbLg!%U&r{2jn!Myn9wK4GcIlpZ(KTq>CWR{n5L;f~xYT3_A z=+51D8JxXXar_(NwYvzVHi-d)YHjAQBBKQp{{H(y7@)I4{&>l@cu#9MH?c8utETj9 zKZ~*3(tp<#3Q+RDh^4XzoWKRIh%vN{S?XP?S$ICD*u^&oQQN&f9eUbuvb8)8VFbxp zsV$cs7u(O51tI$nR?s58uJ{ySZY&MP>q0&cw@B0XP!+#g;Cr)<3)dSu&y)0wNr*A! zu~P}nW}Sh}25q9wqC%M=62@o7{5_U==#&CS$Cz%YrvNO*0WdJLjgX|q=i^ORYP0#N zfn>W0fep%F&eL=3W)`n51JRd4F$G(TbFOIHO)EDu%++7PqCm5hd96a%1@bz#CAk`v z@IYkV#S=JEC1f%Ul>XCyScb+o--hDcggMj`$JlLnc-I+gLLnhRMpW8 z3aJNkmHYOkgMnn!i)=E(7JTW9|AB!__zIs zT8LqO4AHAGWt`gk5~06}R27UeUb-=$#H*+P_tDr7%Lb2K4_U@JN|Yd=@9}?g$Hx#O zKEo^LL{W~L2D%l5vJwn|=m=)EBtv0TYQe24w*%U+A(aG-+i}`eNQjOqJii6MPOaTf zUvd}J_$9>CGdGZ8v+>on#4Yo4gxPl^uH7prhjFzVRh0f2^`i|!mQH5Xca!FfkTpwv z)Rw3Jr4Ve@$DvOlw{UBnqn|J44hw09gCgWTL)?V9L#xOpp1~Af`4fb-yqF6%k|*S) zk3ozBi?V^1XS>$Ixt}J~9%*m}sJVCrhM3?3_Ox!TbAiI&zcE2YC&AMU{{gN!iSo1p zar3G7Yu}>={&pP?tf~g@Hw8pag!+m8;3%bYo68dGL*{lB7q9?X3x)3z`->5zM5IZ0 zz5(?v@A|4dl{v2`?5n%E%bvab0^L@zOgty(e+J$?1(8Cx9uJD5sy{y~Hs1k|=#`s) zs-+CTgQ#ZPG9rJ?u~}$*iQ6}b!$dG&;{l}f3{PF+`HwR1ddD=$?#C%fkr|oe$4M&}e{Zsk6>FdX%JfKGOeyeqq={4gEH^-7Y!hkm7>YpeMay_LQMz;>YAGrXFM)#;E0!PGe{q0GC10Arl zs42(C2iF=Z0kvvAiWr2ob0)s0L})=iDNF(*zg!Z2Sz<}!w<;Mv?QfltLhmhsAt+O0 zP?3&(G-H_;ANqn4BOzkwcLbRtKGB0M3v)fuB!K+r)(1B=HT6@0h%U%PEymJB7|8MN zCvIeS!fD4XReuRC*7HVMp8qv|LjK-V30rXcmsplYL#zKur10TX1{7YhU*{`JA{T*N zg244v1Z4d%B#8iv%#|~X80~l>965L?OkqIu5kf-%GSh+4-15q)T+WzddnsVssO`M0 zb<4BRW=Z)NoWJ|};XL3ZR^9P43&_sseklV`{e(Sdjk^mv;EIxpNd;X4|t&jn@j_4XaSATJLZR)7U!rJDMD{72_4INKaa5Lq0l`+;gS4G_OQ({X>HjuoltOiIq=;uE%P0$+Z~hj(p<*rFGS}7?T~$}iMpY7^e99Y;uM9ai$dQp!l|?t!i@I+ zRr(o@V&g1Cp^#_On8*$Y7ZkQIR`~}5+v|i#98xIGA1~mAgO*f699P;&8>f6KR@PYt zO3Xo_tPh&X1k?ERL&=PCSmsPnS{1^{qHKsK=Adm9vL^aB7}-(JA^C?$|G%`rJo|lO z&ponv8f*NUQBROKHz@g@F$X6O`n)Wm&E+JgAb;i9Rp$DVQ)>r zeGoW6c^E(j<|MAq3{9cxusIGf|BXikq>#pUnykr_<>`De^m#?l=QbZwEBwvs;e>o7 z-Kxs!E1EM;1h(_vl)F%AfC~moOP^0;7wie(Jmih$p(c1mz`~l+^G6Qy#J9vu1HQS# z1X%8uY5bIf`lWM)0T!qQ<9B0it9K$+Z8<`6-iA5cUFr9HndUG$4t9{D4kKUa81LT) zuz$qlVy51})%PQpERv|-V-tYCNxjeQ>tS zO+td{mTFq4l)@2`XV5^WYU=3NK5;7kmqD^J)Tj7&OXPzN$6C{j`;`P1(nf@ zMfXAUM>p|%qZDeG|E)?9*rAqk&5E0CGIDOLo;mp2d*)7|o~0daF>?%f<;CfX*)DSd zIi{?Iae50~f35A8e$3s;5B(9CNQOu%TuA4s>!8s0!~I+c9~w${g@;d@AjZL1nQx-L zEH;A8@{Nv3TY~7wl?##}f)9OTu6ZObZ*awFlg-`Cq4L!AX7YfFOCsag&z>+#dE%%-n&4otA+Qy81l7AtMftOz`GU+CVY2enIdD-2bku~qI@Vw zPC9^u3A0-Djr!y9-x?}-sQ?k$SrkNsDb({UqkuR{BUO!iJ8~lB&Tl&y1@AhUBDp^|41Z<>v9U8_t+o zSwy7WNdqfk2)hmpL_sSXUsie>C#anHJOHKb4}&C*lWtWo`QKn{Ae-r}L4wopVJQ~aY7r*RzIKCbKarnUsK=rf9L51F^NWA2ZlVp>Nuu< z3}=c~I8Cr$g;d~CxJl3+bl$S850VFotBHzS&#} z<&rmS0wU4;GiWfh%#u*_bEAZAG7FTKrp@(Xb zk?X3>)fdYeuMLvjE@0?)_XG)5nRtLKmO-!~Q0%31k`kVL0)72pj z7~$fiFWZq_aP3TknZ?gIn=)TKHR5gYk zVhBqT)_p9%r`j;Fe8m33PM~w-?ad2aQ(vtk0^<+?3{^}PzWC7*H+5b9BNR?@SBy1K zOt&L3hn6lRg&$&6B=@%&f8>+pBxLxpJaoSyH-|dM$~W~1Cr$li2vTB42-GXLk+YGT z*=gAmi3vuOgmMT0JNR(8&Y1(8Ft9$v_T>mYu)x!RXo=#MMD_b1CxQ^$mG*DPboLa> z2fCgqijs;i84rBvgO!{+lQA*mnc%L+O;;ZB)C+T2moU)eQ%4?;)q)B9n#<78s6q)} zCLR?=7-BMn{7FQ*y2yX#Cu-gr``b~~gDhZ9Z~G12k$w7}4!O7P30 z2y#eT&j(+Z)lr&OV|YOvs^uc*;%P1cwf@a}s}^^5umQ>EA0xJ5dM@R=_nqnaC@`=9 z$pl-6W#bE|lNAkMG2FW3GgrdIjUfM&PLOt7{mwFQH?v}Ybxtth2PHt{7r9`P{8Cg zH9!CIIYAeSQ~#lKalA6{Y_uZi+v5q{4&S!Ph&G+l{lF`aiGfh6j{j4;_XrvN6iHBy zDej~HxqJ1QW;s_U#r3CRTnbN3tf1iX>7R?;d-0W>A5aI+GH7%bq;j(!XF~%R$63yh zlWS1;=BHG#6cx+ve%_f6ksNjg-$+7}>b$U4wk#4sA>|U4Ea#0)t(Z?mrc&9E@t}M!Lf@KoP zQF53)gy-dI#Zbl{wA9->-vx=bM5KHuRwsa3lBSI)v2_#Nwe-usSzl{n@nMDZdD^Pf z7R1MqHNb*pHK1&Mz`=IWbeH81QNAXi?0&R z@`YdOhOU3;u16889^Z;(RN+j= z=gpa&!XxKEJuK_!hYMb#DRy|L^K|7J`Mt-ZuTvH#L(Fpc;(0!@V3gmN7*F6M`5WAJ zYp?R33r^pjlCZSa>nY8#6It?ft00yG>w-e(2;li?iZdWR;9rBN1Q|F-k7ipqI1uV@#vOf)l(m}zSkAo#p#&UZ4 z!A&R0c(`pbid>+8X>N-Ml$|x10&33N?#xjmKO63OyT{min4>Q=r)x{>)xzc(nzqlM zI$FvciBdXkT%TGc~cdz6pQcDc7lT0dFHw7|cL_$vgwXe+H@?`ub+Z0$+ z6-P?uy?Alaf}jVrL_y-|h4h87+BlMLKYZ$_+~tl9qP(g$UCSJO+VQ?ok&cGGroH2? zw8X!^a;JkGz9>oanG4c_Qtnr0pRTfc{ElUE^S|zI6;Sm*-r=LQ-#oj*eu7Br=BTNI zSGV@H-Od~XZm@HEeUTXo!SD#OKW}?y+qeerlVMI}_CG3qRGE;se?yo%O`^DPX?l>3 zn@&5Jiyn?^Y4b1ZCeK6nVTCY29I{_GMlkQ+1uNE2N&z3jt3*T&Q?J`G!NJRN^=|(f zTdgh^e1VvBo5l(&E2{3>qxSRNX)8LbzNL}HqsoAH%u*jA)?-0Iueqc1cevRj`^Nq%T6*d=4`7B&g4$1AK1zhW}BC_j-4dG5)lye zKiD+nEBDyn&h#DIw*2<)$b-7s-y=ajDty*Jqwtch zh^;t!JUvu48?h`pm^ou?`0eV~$zNlCR{4~yQ!Ot3*K!?p$-|w2b$(?J3V(e|o{TCa z&9jSo@^M|pE~=blsGA0((RcamGHcchb`P8OQ0Vl4B&@wAQclClh}(uPqp)bzRs8Kc zo1c^)Kcw2v=AE_9dNM+7UZ4t{>S~tI&66xl6x`@-6{JQYd9j5id8Tn8(rHVF4K-nB z(_zxwP$aa1<-t~Nv+%wRusEB^oi(J&V#G1Hi$r2#3yH#YEu6=5f8-ACV>blAV31}? zrK~t=zRm{nv!KsH%T10wr%+#bSiV1M-gRlHC}S&Tw7#QkrD$i=#N@b)>r&vSPekMz z39wqae{oRibkbBm+T)nvIM|}l40)ZEfhJl&G`%&b^Tjt<_rh|DD(o4nD}8Sa{MzMN@~B9SaHe>oQ0y5T>uUF2@3UAebAA>{RH zVb(YOIvv@YCQ;QE=$S$JwrA7f_qPkitfGkQE#t-vh_x6$&gKpq7oCAvRJNDcT zVFXci7+j$8AqON#m{Yj){l#oKS-a;_(r~9wFZOSxvc>TW`&)bsws`2jqLz-V!3u)@j_F8Jr}#E+lQIrDduxIh>Q`0;ijTzCrnCr>l=09)=jKz z36Sdt`3UH@uHbNFZXcROQJA(TpTfGtRVJt2HInf3cJr6M*86UroJ+a^{W-E-L!bV< zlf+`M=}bNwth*97^n9D6?WjY5;(&aYv0U_%GY3XGt0x7>oeFFgVZ7qP@qcBa#H92F z{Y>Aq4e%lOLICP`jxazb25f5y>^RHuTA)S=XVd+1t+BxqsP@Fk*|8qe%I$YHNuK@r zN6z-l1qQ4VM`4YwSNK8$~a38k5x@s8(>F|AWZSdcg;anh3(28aTXl!MsI6Uis#97UOtKkJ`(F1HtAldS9u&cizkkx+muTfkb zaxpfhMZiL7;M<#k4_Qc%Nin+fWP(7LQg&{y!HV6r<&-(G?LdlyfBgLb4|M~H7H*GI zzO6s;likwB%_$utT0jo4ligBj1|e{>gaGX)^7=5)k`6i9i`%njO)G>+D&s#z!tMd) zY@|>b(Dlk3%9-$2(8>JOI7kqQT~dlCUAJ$EUpN0d3j;UF-SEiq%9=$H_sx`kiX0gr zdk+F8w>|74tg2{%%G6`36ZJ-pEgALvYU zzyu_uy9lac`7ewEC*K_wwoqpeiNlpxliX|c#hh-%f2vFxNak`)SljjQs>fz?e1AE^ z8RRVZYiv{9Cfta?V+|XbQARTWLq?ML-5ph6I%I)03>p%ZOS>qVH*u~!8ch2i!D9CR zz>LSx<%fSit)zL5ehSG#xT7u6_K@^s3?w>fgjPi>qftQwNSkl+G)gXi( zx3d&LEDb7@xex-`jl8UHWZy=RV?$KExgqhJ;=KgW_xWQI~8XXk*iN}zf^W92HOC1?w($p9R4K9`$1@HN+3 zDfJr=EDqFPlgp3)G`M?@QatbD1LzPd$~%YmTe=ln8mnoK8vahWX8GmLpHbt^YlV!O zhh8>f3(mG+AXJnMMt<@#wh$C_!GVu<4BhI`#GBjND7`s881khV6ydQ~l#`HdFh}%` znPQc0j6P>pyzLwn<0+iLO;C+}mwX9+xs3@X9!cT}ZSpG{|E1fx+z4X;6R}NQ(f?j? zA?}R)Fal3tg!kcdUl@soj>;cD2QcJwK&8heIkSI$9c6=&|4;{)fwYS->I34P{U-12 zVVCmzl==5rK);Ua6Oi_lc7*7|6zg%;9(@nhzbvvg%h|{ zRma)|4Qw6^{B9_NkSqu~MOw4O%IQL@;GXr*onFk!Xzr zA={Q#GCPF=PulSR*mklx@1{UzAT+b~`!DvZ&h{OP6~cRxNP%0qYrmnfwR;0G;sB@- zmy;hu5Tl80dQXSkc73jj#<~C2P9O7c^y~(n162JLqe0$nisH*)_LILMQ>J)QNuC2) zp?pEgubl2GW5ba-!tGyR^P2j8KseozTc^+>Y_(BeOj9`xC8eI)HOS8WOn}pIVq8ia z%ta}UO!@5BI0_SGN zc+Qvo;d(5=+Xw{$!Do`~)-0!QUd20YXIL3*uPeNmE983-hV}fsjL>x+b5JS6;H!)? z7oFzMS3R;E`?&BVNoi=X*lXX3YX+U!<$rRG?vC ziK{^ZrnIH%AhVyZ#j`0HS?Q~=&1OeDhcC{}D3$Th=DZI1R6C3I7#-)QYsR$Z!6ELx zYAYDmH)F^#$IXyCJ`4C~&0o)eSBsZh;|?e*GUU;uebR?7_z2aq5~ZrU44!ztH$k5E zUKFW@hMae+%N2*DLw&C6`HJ|6h6b$;pL0zC4i?*=k**?K!BK7sKYam zMDN>lzyR>yY7nxO#z0ve$sY@RukOlTne)4iHSv)Dkba*)2dFUg4TTSpXVLuP)xq{7 z#;X>t2E-3yUrTTi6I$hkK7|UrY-I_opmQRvUhp6?>gE_8nb@T{(3zZI02gf6Vc^`=okg8pTpkmWjGf~5IBZly!%pFd)?dBG95Oust* zeNLRpCO)tqUj6dHxJ?~tEglqm-SPI-tcg1B7(ccZ=NppUS*-SqR9mto1GC7fK!i!?Zs$9V)xah+P&XSKa_r;8w zfMXbiPw}8A1^t1J-+AT#YNC%O*7?C9y?~S!9797{Dk*n(2l-+`Z4CI`-lhljUG=f;> ziXNNahPDaVh<1k*%5Adn0UVx31pa-bE3&TR(?-$H4GJMrn+Cq|$crx92VtWA!hbps zboN}h>c^XYCTjR1FKhFvrx4kHB^jC%{SFf{447Cpe4rkZ8-*Acz~M2S_#;u|>dmm` zE#%hR{G20$VvS(PVmJxas%N#_jXKOHr=^|U&-3t$+f47$I~e}>xNU;R&39;j>hQ^| zmRue5n%v;qvIarGgk*eK_4Hj59iqHl$iFLwLuo3YqXEAx|IYY(m@Aj)4SS-=jL+Vt zs4bik^d!yH`C4CT)>1ZLWda(PeBTW1@#T63=H-M$9rFlw zs88*%2;LhdjwHZ4exl_=5Ar@uTrD(=3lq7S7>ntMYAF9E1oz?I2R7MDuNq~qhmWWm z>!zOjy7Y$H{DVbeSJuTL>w4I%ZU^YfC+@%n{T-wvbf^q%I6qkLzOZ-{W=7n-2Mxvj zwp#)rX@eEb92sB>X$}3SPl6NDW?PalN~!z!$QR$=Lnv?0S*s+f(2YH`MnmDnNWbJ_ zPB(Z{v+xFz!bEx64Qp&>ibG`qZm@J)WjvM^{*M*lRm7(YLelfwAaPqE?nNYd-%%N6 zTJJypP|>fz906SgurwN1SKM7~(%U9ObzIGFp5&&q4n7EY3bSkw37vb7sU)rRF1O{^ zWS=%@RG?U{*>HxOd(y9#KH8wgf)sEneMwUkUTSe^TDThp=Lt?|aoA(M0HR;D%pqzy z$Y5a431PruzrVa5!1OCOS=uAGo1myHv-!!)CEdHOsril7)i)l;{Wv}P*0-C|R?)c5 zMbUp3oCQzGIK~_a^QAHTcFi^?$zsz5Le^BViz>QPa>p(8~&rdXe^JEjAIk8&A;NcB*geVMw)+mEpTM7rBm6^<J*00if#7Iw2A~~Takaovit!3w5F4W7PX4O;HuzH! zXG3u}%gJ@n@EzOQ7{Shp+BUfqmpgO>5g2(TmHQp_IDsL!f(Tc(nzZ*~a?j*?7V(f_ zm(8CK(wHhH_w+m$ly&O@8xnM9}ns+*+h>K95{TV(}qk>8LgMfe&k<)UG0Lb0m;m6~-UTZyqT%o+U zOkGvIMKhdH8ZNCX5L%)4zMDJaTZaW!Jsgxc^bX2?rc=RO-U!PcE@$l%<5Ad0Hcr89ioO3P zk?*OpClDnyHE+MBSF8V>gAIC;dgd^Pl_ZS6%;17`-bGkAr`ovnVl&O&0F50D0O!-7 z1IkePw88P5CroP|i|{;$?EAhi^E+Pe&-d}0{^;?*ecxxU`<&}s*YkRw=QXGssLhx5?TG|7 z?V&vaAb}Cx2ONqLtch|vpZtuNSZ^MC;yiFRBy2w!J#x!=ro=w*PGDr7&-u4Bm9wqX zEXOBYGv}ab2j#}%q5K5qIsJq{EHjYt>F6Ztct_H0eKY+k(!wX7`@gLhzjn{3w94_Q zKQ)GEuaTl<=K<%y47ng@v2su!QPcQlo&yH;wl`B75f@N>X=mXbIcGEyu&a5;6KP*J zR>@AF%-yyKeiRw0RH=i->D*jj7TaAjQ=Gd*QqIjr`o5{ZAY-hrJjLSn+nWhlh@ONV zrJ7se6Ng$9RAjG(C(5WaABPjev5rr=G>g}8jbas0;s-0JuJh(_p91Jy#dsQ*_HVZv z&0S1!6l__fn5Y|H};2o6&L zOcmhq!a*6z86)z0;+A$376|f43e#6B-q+r+e7iex`C;7!nbDG>Qs00}yMM6F&^NDX zGpy&4(fNmT;%SR164WZqxVyX;&0dj@tDvm)ueTm`8xR3@h|KLRvq@+frEFiP1mgVL zGcVVl6yRsgh7l^>{%U47@FRX6ab87>@@MeCQTT_~gt_IEUVE9Yfdk8g9*CN9FhhobhMT7JuP;bv7kg)P?qQOpC~?rUA!!A70vKd-EWKkzH0*dPnE~eD3`} z6AGnD{nNWr88}n^V>_k`jThTwc-p`0+esdQ;~-VO*iLPSj~W%?%xW5|gKFv*rMEdU ze}s2RR57E$#vi>!qK@DWjuEzRS^VR3%X)ijk*Wb=ZTY(-)xK4GN;}W)36P??Oi6wi z6S)^4u~%+N#NBC3?j4#h{z##(OXm0Ik^P#Ng#k8@40Rjlbi9W}DC)i8fUDDR8(Xz< z<5iH>w*0(KDj6<^jso22+WkLdgGv>Cwg0J67(s8wU8hdNdX=C?&?2Z4GzmsJmQaym z0V+{M6T%74$*)z1dxX<500z3t`42S#j;+W+n0CajW>c(g>cW^nyX%jJ6ymSzc(mVW z^sGgiyfX<7s$}TMF*&RO%q!ticV1c~1n-Dr+E=dK9i1q@sdV$}dpUvjG-IFW^5E8? z<#QR`L7g8^ADa4~LmeZ>rP)=z|G;e0fPE6&1rl&{&Etf`L=-7L>V($i5$>UdD-Xt> zEa4p`6SSUXqRAk0P3mUDxCc7jo?XtGO)u<_SY!iMg6 zooYMgafCl(g|~vUN{PLl^g|&HuBibpQe2L;H0YwCdXwFcNg>KY;J*y_V3So-){S&E zg>FH?aWw`zgwvqXT+G)oBig03GIQiDOE$ilXs{D1M=9%rDL(0lhy? zh?YiEkA)urG=cSkC~-QA-%6NMB&ycb+)Nss@in5pf~MxlP?e%LGaLJRf`#Fqq@Lj? zQ>?4S0|o+e=4*o1Gv{tdn!(T#ekiphKWnl76R-T0hj3R~zo(|?Cf>0{u_$!ZqFBaZW4lmFbGZ-k2ek3#LXB_$2DFWw zOYZp@gt|xQ`}))?;?jR4l7CXakHWqlja}CV(u^3ZwjeU`Ti?w5tW$z+99zy;J~dR2 z4nuIdVQ8830U*;!j^$f`R2ym&pZh!FXABW>MG=!vza+kmyr>4zd!qWCmQI^JGT$bu zZ*6Ly8LOYRjPG0zvB3e~`|Fmz|S$$+9L-7L<2Bgmz&r&2bS}#sy}< zv)RyOxesC9XK;$Q@tF_8Z0}s7I*pUz$35{rJia;c>uC1yl22(t0EJScxkWl5GuiVs_(mkq8@ocT-v4etFpu`3yGZ)fBti>nu7DvmB}40!nao{S(lt~ z{j|Oa%2Bb{tElJXurzQ@1cPdA0kn9pVAogbP{_7D2UdM>)Z}y8US){k3ZeU7vex`^ zY=C?2SDM*H8=`aX$qT=*Nu%P?U1W)eRqq`E%ubM$_`km%3k<6+Z1=PlYRR5FBHFK^ zDJAhn3^9J=!)UlQK&qQP*0S-*++#aL;arrgg%&MRHNtN;wb(_w-9n zCr1~+FGbLFv?3k5Mm$UmGvuNd^EV{_XF#tNk-R^lY04Q|*KvABZOzWrksFHfxyktD zMA%zIS#K0f)u9#8m8pAtEGy%>Zh*EMdntvTC|aMNT$D2_@T2RBwnyszA*DFeIT58! zno?0hyubzKrWXbN>n*#BK8^e4SBR4}-@S`z{Nzn3`)-bn&51aFR#Um@fpVXJ<^V5c z59$7aR2EZ);!XfVb^QYv;u$t3mF8sqy|q|rN5;sDwg1tjukXAYiLj>i4rO?0N7-e9 zkG-^<{QcbLq}p`DB}scW)-m-rXtRs=n$LE4*xxTfgT3uO9_VN(f%|S6NjKy9!A(ZR z?v#|Aes9CVNnd|1iO}Wcj=eTtvu?QyQ(T?yG9%Mg2NZ|&oGkpIa8}`H6vi&w(*dKS z{c<^TWVRov(XTI`AO#r~yx#Nkuos=yeBtDa@!O9Sy1sfjY`>gqV>UBp@#|MVF~5xZ zw7tlg$RI<;peiTV$loQc+_Pb(~s^M20n+M9v%BdFohq+fv;DkSeY<@cqn&vWu`t@)C-G+Jmg}|z;h^m7an$U)(ScQ*$;#fnpc{IeBB5uW z#6Gnvif0_LVim-_w6M=i46$D;+r87}eU*BBmqYA!10 zs3Qtly${t?-wHRbh$uBL+-@zb7*zUN7qzojFnv;8(Z~xrHb&`hEJaQCb2pa8Pj9rp zY2}M19GV1t6uOalNR3QSnOomD^wns3X?$ab&`cD!_)FxUO}&+pq+%HWM8sN@F5Q*| zJene&x`F~r6|dfv_sHi_|GDmVz4EMY&C|4ZAZWHjz9?kgzv9?$jiU5$PtL_}LchUb zfAm#s$j5=aRS%=eo3171mQQ~^ZP#PIjgM10FvLBHSn41wT4A>#0ystWg`@gb;2Djm zeBI4BvWP~KO-rr(`OUu;Vx_Sot!ha+4;?gWNdP7Hd~FT6u0YIAZSKSPaGJj)hTbE3 zA+IJy^wz@%Zi{V7yqmDHQ7!H?SI4U|C86~5WVjr=1orNuz~8HsQU5ZmL_d3u4tv!` z_YUj6qUwI-#>Fikzr!dL^Pe}(R+Hv^x>Q$f{mvO1gofRbpHYapN`(49j@q|8`aHS2 zSw-xC)9+Fek#uw$wqpDKx+?4sTJacgt{j|j?_BAT!o}G_9LR;pv%D}ec<1=g&V`OJ zYd;8@^<$pqNGJOncdpsW{p!QzU+r{cKMScG1>kH-WSh0w#h~mp45qf0qWcV z-TOQ9=R!PIPNolR);*ekjV_ue1^W3@|4~{l9kYpX2SPw)t6AcaMsWfItJ#m3y(hdDZ>pJk^gG#`yfFez|>4WFAue3R2~N zLi`DJb$3<^q<-K1O`ehr>t_Jp7VEJhmn8SD^rd9*2f7snIYo>5rOv9i7d&PdNvO-~ z-J9ih-GvR44UCs0p^5I=0_XxPMXl(6WK!`6So1`%l(s=7PphOt%%=v!9G3pW`>9;Du9r zCwyU1$l?JrfW_>MKTN7&XQNMYMSK5vF*K{Cw01)1J>+jA0a-2QX^o476qLF$E6!Y+ zlpf`s^rh_9m|veW(}1LORr+{kj~kQQ=GFNcItFO}cYbJ;|I7JbZ<~|P?>NWZDQXv3 zpqm<6h#U?6C+Gx=urRwHt&79{-Xqqy+H|0QJMql}HCr1c8_v->p_hSy6b1!X>(g?N z`_F6C&JB`(n5vG4zRR8M2TJH2J%$88Oc?!k<9E;%DxT35h4^@aE248v(?U%;V>G%w1?E zJP3g#gezA>Vsi*b#lK%S`)xv%HIBCnY>)xDj);M;7Q1y7>iI+RzT~*Fhb9>*`j&ee zWci0baauUNao4*}byel(gHt<=Aep(ly}dx`?2g{`+^L=!0h|We8or#M4qHo~U4^Xr zU@BMT(^bwCaLg#n6%72eO}*5p;~uUrJv~SbK-LOm@j-Uu)MxqiEq3y9GXxQ(S^4n^ z`nV>nCeitp@DV8!PN*1<5D``J2G$>aJN#O1YyOdud|&v#qG7y|rr0 ze1E&vz}J&{uC?mmZR`aU(2=18dtvSJhYRsfaGX-v3EqwC3YxfPqVWz?3(ax7qsF^L zXO9bciVAmGl0#xyu}u+k%icBtgRY)}<1FwELOr4IM?hV+8lgkM+K7g!<-6R6wmLq^ z=@sADi7m-KorD@onnb$B*qi@7T%NYiF1V@`i!R*%u|918&saQy1sUMJzG5{I^#-m6 z>tpyH^t0BXKtazfIQPATT)Py}`=q7pjrC5w7*XzUgy*U`9grvlgz^@ObBSQ5I*J1-Ep>n4dDe-%XW<#njEAtmA2Kotq# zu4{m${(N;!Jeuk2w#48UIWSOo*y+P1<|}i5=z`YGRr>dtDTE;XkUZwPx=W!FP&n`IwGjhC~oz z+{r%*SrUyZ804i*bU{M)>5{+&c@z8ACG&+_Uavo02Y6gwNkxg0)wf)(qer_q%4+4* zvFeMJu@&kXDU!5{e#f$;5jv5yLDv)ipz)vjXZ3;AN+uU06gZ~bG(!QohZkf%DAPD0 zpeK(dT5$nHW2wyDKLU>*WQM2_yhHYhdhh;u=XYi0!12Du&s)@wkG8*b2bV1M*R}{2 z28di<7kPl0DMX9kVChC3JzPhYv{r>Htd03fR$H&M#!Cq-UNw%-UZ5= z9;|1)VSP@8qw3JaN|uKHS`-D=a8#}CI0Y`Q;|=A%EQ)77YtmeYlNeJqTdNJfqg|Z} zX-qKbc%mW)XA=UKe>=auh(zv?VDe}Awhp^%^U&CLxrR#&uK@m0?~uqqYX;91e<00) zqlVI(j%>L-Y0~k~hN`>0w?9eoFgebP3V<_RfInO)UX`q zz$ScFdzF&)mdyC4+q8{h67Yc3&Wpmr0Xc^^-4F78@x$yF7tfq<$$Z$o=dQrzEWq;4 zf2+jg3-zPT7Kkk?l@!%tu=qn+XNb8MqaBWlDskJEzI7`ru9&3xdU zV%smVubb$W_)oHiacztMy$rTqsdf>9#Q^zM8Tq$1D*Ju`o z+}P$$`=Q}tj0`$1$L{3L#vTu_SyG5C6JK3RH~poJ0I%jvD~nHb0^Db&Ww&jSOJ#&vOcDyT*yZxTn)FcFX6(&(5alx z`pG*%mU7sf3C_p1oK|QS*tag1J?2G&gna%Q1wvhuo!O~qaGD`0f5kFYzBh#4biAJ6 zgbHN`c!LjK_{s)ZDLy;)8 zvC)MsaWcoxeO5}V2-}jYD^_hB?QQZ^XXRE=H%H;ERw9`as*OuJ1@#Yv;Y(sD4?c#$ z#>>Nn+FLkEpkVHbysu&UL^<@%I((O`n5!>H0uiUS3ONr-$s5^ZX}5@Yo#v%>}{ZBTvH~@I`U~Z(72SI2~!L( z#6;rXaCH263cWoDRae8ijvU2KPUOIea~%4l$qluua|p|efb{&$$QQ}?PzWdE2~FN4 zV-$|Q9KZ#yu(EkZ0{Z4oNvb9~6p(-O;A2h}aZ3FI*o_?pvi4r`>h640VVfr%7tWGV zEJW)tbyc+5&F1mzF2bn`x9+YwCitJ_OfI_)w0}T8pYoa}s?#s5FGaa_Mo{<-+nb03 zr*6NWoJF5QDgRTS8-p}L5{*n~B6`=;ePYj~>tH&s72S4j1bp|F4#kq*L_@#{jQ=%W zvFAGYd*T)I#dUM+;6%)k#11^0fZL6`26}3JQgdD3`ff2f0Q~Nw$|$UgHvf}m*n|Z4 z&8jkQHCt_%T_FD2zrvmAmN!!gz%O@Y;%@oRKUbG?XW3tue4g08JXAwJy6VG~O!L1(_2OQEjaUXY(E@^Oq`akC{%(TC;35Dso4SuZw%H5qMRMNT~UjLBdr|3?g1vnKMX z0d?ajvI}H8iFJQ84nM;q z3D&u1iU+m?En&dn9hCUrF3nu@N&5Qt-_Vx}*TEg;*LUHMA)E-_JdN`h2A6Az?=^K# zgJ^IR=%O`ev;6!U)9kL!%uZb?N;DqTI=6N-5?0cl2$H6KvFb>fBsvl(oyIT*9IVTnw; zpXS=-lB1vU!12THA^Vs(sv($$^ru#7PMIVb#tql6eF9;7I#nHRvf@{(lv1u|aE|H? zbhwN94DIajC|O~z>83DOn*ka34!#6X#J&w7UlDz{x$f@zm?t|d^^yr}M~biTcUTC^ zn=tQ#bgR?Jcs>w@A*TlKZ3tYN_9*bUaBRdA*0InqDm5K*&61Zdr8FWWO?8|tQ0fjR z5pYkagkcp-&P_84{lw4 z&kZ~tWbi$TDN1B|{v{CMZ8nZakWqz)|GPGTl6;-VK7z`;{82V3LnI8HrZ*vB87vud zfg8S9P!1D;881{1+b<)%#O_`<5mURqKb6iLrh1+)(ws8h1a~s8b%v>JG+O*G39tlf zM^8VA5P{+&=vKTq*nGEjNX28kh-Dupw|Ou+BjJfUm=kEp`wng{b6J|q`kn-n@Y92R zByA8sf0LUfd!0M{i(_`0g75NozW6fVg3Ts3IdE7}1S!z;$+OKH__;fsY7r3Bb4b3J z*rhTxHpwVeWOFB!pVd=ThAZ<)jvP#NdRrvA*gfffi4T51%UHYBkciZ6+>U~bQ+*uD zZEUzx^g&5mxG6qdHI}Qc4viBW?aT-(A&Swza`c`1B;D`(ZtWOC3Uonz4S0;fyy^^@ z!7MM1{OT$bF@HMov-3tOLbl^_n7(=`&;TA)-!mcRg`7lPR4)@sK$UMT#b``=VeW!y zkEnhsSZh?7@JO{z{DGH?n70eNS#E!a0@x0~qfFrPU@Di}=h0t~&%tssY+ydpC!jpH^~g|7aSZ6;Va!*ojA?dWz))n6o$Hu0Ag z^hli?84!8;E}K0(o7?CNU*Hy5K@3Of)WJVD6rK`5V4#pDr)}g)>|h2?me{FbyxA+~ z+&{C}9wZya-CZiZZe28B8K?}Cw>NgM=tThzTJM~mtB30`XR4Cah@C z)X_QGukh(`6UTQ9yY$Yn$ZY=RAX{oK5j?rM*q3{I=z2H_%diE4A%!gAV<7bt$rbpw zZ+;N%l|JyXxffU`Kvq>(OB3{nq?4oQ2tuf@Uw$2VIHVqQciV22Oz*j0hV571G>OOe zNOp&)59>UVRmPGj(XR+=BV>HzkBp(AE0KoDT9t)Sl#2{NNG3u`?+-O8d7?BbmzB;$ zyC~`IL|=m6?`CD5oA9~)E_~1*Qp9EWEFt())E!3mCnw|eG77SB2!iT@&3(6h2~qixlmwpIpGv6b8`b;^F(c5wiNFICvg46&U_^p} zaXH>c*nLMT)pN=F`>ly466HV4>gXlKbP`%$GZt#9Q*smtDkzy33JIKM97}mab9N)d zFJN$GM5(s3Gqwyfh^q9fK}ztc#ph)UA?MteP*?DvlhnlA^U{`*TO@RV%>wynP?IqC1c#w7Yfx1KMsFq__a*MytQ|F7>2y>PITnRQ=hu_6T2(2r$;;@T3LMa@o`v`?MyKEp&Hex*LH@Q z0eYzE>McFH&ypv1%89Wmj965W7i6YkX)Q{B7imwD_5j+(~U039uw2#ntZ zOmjj^nxyJ55Nn^9zV#hRj6uY`{>I_QLai%|%0i0oBvQS0je&;+ytR{v5dgnl%($J% z3wyDKbCy(Qw5e8@wt$;7ni!CU$n5b|s`lRK%_ax)vF!ItBk~Vhn;EP!0Y13|8e_5Y z(g{qUZU@2g$rWcC>{Taj;~K6O}0K{%lsj!*&Tc5OU0 z320aWfZbq(Qa2Nvd&12x*I=j)Umbt%nxY1eSA*{)+I^QS=iLv#JDfcxZRXl>vbbs& ztN;Q-(Pw2Sgp4?`G>=2FUTqKyIyU){5+!HHw9;{pe1n1MXxm4A91vTg|8DiuhDb;)6c%FWqnRj=8B+=kJwORp(=s2GrOIyb~w$selV)YiR^?d7hqR%tQ8 z{-ol<7!-h8lZ__z-h#|+0UNJZ=OA1vD{K2MCmMieQp!L#dB@Z{jk(w&*gXtkElf#z z9-)~<{y2KFMU2&hRfG`mdhsp!APzo2%B}Yn2{!-KM6chm9nUR!K`nAw4=i2q; zqvyegRlt=w{+WmU;m-a~2^CL)Wop`gNFs)&t4*N|=2t%CC-wbf9uYoYrpT1i@o-B< zRFU)AfwKh5@HG3^$*8Ak9t@*!#c{law2pB^HO?&*9hcJYNB^G`9Q5qd^Y>Zk|8>Q#IHpPBlJ_lprFWa^S3|XT7U#_H_kgwAJQ?ug(;QEe+FnXp zn2A&LwZU0f6*pp(_OMclM8>ju$REIbU=;S5>IPE3^+>?ZSt_a=@bdU6;{v{J#g(p_HAn3KA9 zZ?Yo?&UBpo&bD3&w*-#JfakJjRP~3yX6f0gpSQ~F=~w2P->HLvuD&nT`gh5Ti{(7Y zLVotDwu)}@dEM8&>|Whu`xbwfwK}NvVLitxsl1dz$wuKtuZ_4UF1X9X8Cp#0Fm|Ab zz56d=7SSb!1bg%c?%&ZA@xZb8MXPh*X}AK`EdDlESSBZq$j7Q9f+{WoC@Asx@MSSV zLdx;m*QV_7_W)PEB$Mr@SLI*p(xcD%sJjnnlk4*GGNb8@%MG!-xJ#p z5rZn@ZxQNKA)T3pw zi1NvM+E24A?$}YqTatfnBm>VR5HJc+{WYU1d3SaVd)AM6g0f3PS9QSg3Fg+hYE@sd zMpeO1TVmm;yg?V(%<~Bx3Mby`;Y@od3Ct(0_Za~;7JazXgGi?6L6Sxd6rEZXlugbK zG!*|JyH8rV`2fddPL!X!Fa5bk;rcHvb$QI51h^Vb0t$Y!gZx*MG;tJLFeSlcvUvdc z>K3JU_>6|eCm*t>t~7ymH@(}@p{xq%!T5Wfet&sy3dkwO1<&nN4L=|)@?hFubcJO$ zoP$n0&Bkps-@Pn=ENJ|zj)>4bc8{@?_)W+2;l28FQpOw$P3&3(F)0qRRv3iG+Y)-q zh7s8AI3atu)&Z8M!eR8sN0=ACN>q6M#o%I++3%0+@le-ptuP$+VpX}l5%AAMo0_(? zVWpJCnkwkUr(I!50R(K`n)BsM+-tkpxLd;&?A;y~x4~;(Si0*~{iWW|dsgJ3e67%) z3nX-Mm7fIgipb8hhoo@|X18oo#u?rJ%!2?iH{L^Ek2u0guERC*k#N8UzQXyiWsG8nJ}CKj*Uz|;OQvoMF;;nTEJP}#_>vO!O3%M*20&~Vpm8rB z6=j?SO^!2E=($islC@ig2>cUd*;~>6y13j{_LU){$}8vf5kyB7#<5LOvTm-oBAFS| zF2}_TnBK?kSA6PL64}Kt9kA!Z##2u23LRyJp!h%(3nBO`)h%@2&;OW?mkfQAcIi#{ z=}Z0*qdUGL5SXwx?QVeF%y%H2VAH3T%Gyd+ECwbAW@pL~xrk{@V9})W$OsKjI2jnn zg^@)daA{Y>r5X^9)E~3LJQwN#F}_-Z+ZkZ8U*_Y~+y~r$6ypWyaMk?4@?CDju87wS z8$GR9X>A^9YpzSw7NZ~d`2J29wqOJijMOw#Eco-s3+B+1@a_T75*=n#Q* z1_^sxRaQixi_>D&`2!qIXr4Kwvm-*Xqp08CO1NQzpat*eh)}$x+PS)_(YcKVuhCEX zcstcPsta-ttll=C*I?U)d--F;94vWDVR770M-vleRF%Y;l!!?tTB2r?wm=dyIS#8a zQ3C3$<`kWoxTog*PRZH;5sTJX5}!f|wcPf7qKUwBpzZ-I5^H2iqlry8AGn(OhU*%X{TyGecOcbBFn^c`OgI^G(I^!iTY7!bWJQ zIpJ_irUmL5@xxW-2gH(}ABuTniu!P;i{4APIO8kbpQP`v2gU!hZkp(uXXiyXr!Jv3 zm8&f3LkLozo&J7(Z-3rrRGw-?kGR-PW$5eu#hTqwN3KUV4DU-ej^^!-_IT6mP?uF% zn3dhXwhq<~eDo{Qr#ylUZLcQ|$dFM-oxlRn9#g;LFLfzQ= zsruMcxCT2{Uf(C(kOG)ladEOp1g?!%XmNUFOZD382UZ+yz4S4YaN5yAf@>iY(niFV z@|J0r(q`_}SF|{!rKn}nGrcOgg7;>1Yk;*gpf|p90evg<%zflJh`z&DcUF-mRw{N?d1+er z2hn;-f#uS2XsS?@_Z>@|lJB_`1aMLG;=7p`8k0T!>o{Zd6~o9mPi31Ex3}vPDZw{h zRK5H1>lqY~s5U65!s~>IqPMse^`rx14!F(_Zc|;?-uKL^xuzm#F%r7^ul1W!&+5T& zxBj$3~zs1KL5F!@e(|7V#wW5sJ`Z>LM9ZdqFjp~?&X7KfPlHDES z{i)2aUaWUtaWacx#gZ=O5Lu`1OU#2_Q>%=jJ3F^sedVjaZL8`AS0jf*lCA$e!M=NC z^5TJ`uISO!Ga?g9k&qK*qzHL0y2e*edNbe#|Ev7&VC|8SoAQy{ba#6LGhIfNLhGLi z0iX5MMX{j!@2Rp2g-@c}E=nHXkDRG7j_c>M!S&4wtia>- z3PokDB}ei~qNC3a6da6^2Ya)t?hZzsUW{kS>`jA$(?4bg?>t4cSMp=&j<~gS+wAPO zm2Z(B-@5#kg6&;S%j%oVVS*~2HQ3T$gbX*b?D>@}@0;|GD0|Du`7XNdY%PC(_7kBT zi`(tHZ#y10I1+{igvGmz`I|SCKM@adTVe8hhM7UNSCP!85iau&-b! za#BZ=>ieKN6Dm}DDb4>CO+s@LhOtsi|;qwTS>PwYM=eJhm(+$aIHnWy`bw>b0`_6Xf&Qifep?rD?3^I z%^RPS7@%MBt$}B6{2I%QY2KBrrq7PI2Y6Q-+IrhwBN=3iE-;gA?r{X9-XlyL_D(J; zap?iQHI;|&UaP$^ilk&{dYVM7SD9^BdG6f6sB&V)S0TK1{JPz+{lK%1#JGp4DaFgY zK29mju1$nDey-0IIXQeV4~M+BD+Ty&#E75R-@B=D>64{iK5hPC;j#)@U)$48QGR~w zSi9B1;}ps@JeCG)lrdrQ^Y}!I`S{1ReLdxNbWwcoEo(sv>wx6g!_f=fdCFph2Pi1_ zmkB7c*zQ)9rXEl2Spe-1#-p2d!ESPc#xRy9$7Mu6gW!lYsLVMx_WonbJT$BLxS)k; zCscAdQ4UhySg8-KJ+Joi1?)Ts^TOysjp~6hE199zdRZ8B{*aG4+l|i2$w7j-_4a*7 zW3Ln_i13GqmxgJ7`8!epQ zn-7z7aMW3GEoUj+CBdwX6Mre}jNV5mbb`vtg*=)eHj-c@%;ZsDQ-hMj;&PpvPDCZgFO_xv?rJmYzQ{G*LAh^?%W~t5#C%qpFsHm zJ7EX=bCS~WSNcoNTqmgda{gO`d7deS79;sF^*Q(eFwQ}ko6J-|WI;qX4lgwzf63LMlS#i_gScoqLPEr=GXW)0>56D^xtRhNOY*=O>;lR zv~ac_q;8J}0(O-HHUdE+HO6)w%G9ooAnf>Y)jvZl5%K--Fkj~CVf$4w&Y%tzNl4=P zgO&h|_x89ukbpsR(0ayVM!Bf@*V1*0>z6&f7%VR+bc~G=_$P|IK*uArKGXe)+zh|@ZdaB?8#E)jvA&d+^ zUBRcqHc(e$>!Ih8{fofenq$Vtd|Mw<6YD+aXwBOW7sE;-6f!cc=8Dg|#SFqc6fWLV znP8mQM*!uQ@vLc07m;}7i~|A3JlwftxPVa}hGyr`|_vwhftH=9UL>BN9|0~{ACd@ze zpy1oN+MP!iRDvvn@pH?8ydGH3BAfH01>NWb505q#pNqoP8#O|euHh)_I|z`xDH|uM+V1rIs2EvFfjP7vZt;ewErtqVOiZ70d8^4 z<|M%1g3Ha(X^?2j?K4lKJQJUTS(2n=062S*y*EJ=HvB)RkSez@_gq+-B-Vy|dwY*Z z7`FB6tPPRimA@Rxj5c{z0o2`TQC^jtF6z|7ePm!cf14b*`;*na>#dm7NquKDyOkZo zdaqi+nRVEbM=oX1=8uxdi+gRI%*=M;sr&mkqhOs97I|SuUR>x&-5AlDKl`c7e#dwa z^hoZ*CmsO*8K>cU4qMB6V^~iVt1Eu<`>Bt#yMVv5691rZ^R+UKKC$)i2n)dXutW04 zozVj&yj|~Gh`Q6@;*1!Y(z#|zKEHvTUK;d%rQ;YlfydXc84qt5>aX8IYs#~Fvz8rK z2FA7o*j=-gQJ7y=r?1RN`*o;&ct2iCmzK{giNss~^(*BT9aSw(@`P1#fWlJ0$XpdU z2%tiKLO()7(gXtc5b8{ZMJX&*{a9u=9UUy01o9bNzvQ$=+T5$2R@wUO`04!uG_d~j z^%8UqAZBp*pD+~$=->ME&G*^C7p|k9rBQdIQR9V$myk{XS^s_Z6@8*Xj3d00)(bn@ zr5q$ARwz``EyL=D4hEPFM&*>l-~IW-36n27)x{QRiqX}DC*-##XL4QVSe&f?zMYG= zd6-V{4CVYIR~OsI3^Ofw0aQE%>3D%t19w5`WNY~eZ4Of^jBt<|dy@`2Nt;Cz{!x~L zK*$2EhJUu$%p25udhww#BCxha4oQ*#YaF?X0?2>Th&2ZUf9-`>AxL>jfmMgA%RGsZ zpm$_scz}YH#_vk0$K?xvq<~C zzjSHn380+t5P{1@0^aR7_?_?U)elsV6tlf&X|bQgh(q&pI1&4?H~|dg#(ZqtxZ{R} z^wIOK$6l^@#2Um_v6WZ4!EXrq_F-+qwY@hkxaf%i48O{Pg}~#3XOdL1xGXQ9IT{^$ zJYr(Y0`d>He{PGUIaR5U>57ZTDycnH+5M9Qun;Xh56{IO-Xy zGn*rRxYkd5nXsNlxpgkSY>m}MA6^Y77}$zJ^K^k7t>i5ze$;N)vZG-qBd zao1H^8rAt-5TL2Bc|pK)F~-WfRe4H(yp`cpLaDDm^%%|fqn$bMPDNngS#dKs2k>b3 zL(b?+t4Kj6!v0iODl|60*?_xJ)SB6EJL9=Ew<^sy4M^2ubt`H%al~|VAlgiBzYA^4 z2c%?ib30E;I4nPx4|n!mp+}qiL=hj!#@h+MD#}RrbFYUmRyE1~q;#!STht@eg}fiV z&@3-Pj77%2m@6S5;tD;n0t=9cpoHN6=%d_*q~trzgPkiu9E`8oHZ961U1U@-EPRp6 z^yc4t_ku!{FPjXVc*Xx;SL`uJGd}G>KzjnKI|0JQR$OOIqU=>tssCrsxvJkB8^xOi zO!SMkBysd}{{jU8z7`^y<4nLkYeo?*Wm^M>Q%;OGtG*~_kMw*t`>{4)rIp@!Qn`$nsyxvome9{xrxAN}JBW?tK zP#6f4X6fhFR|Owlkh+3eT%=lq0Yjo-JU$F{CF$%<@uq!yzXW@p-vF09;mU>+#UUla z_}CyVrT8b-uPOIvfAP=dfuLHA?w62y1DbN~r(gqF|5A&Chdkpt-x4k=&|1fl2t%27 z8pEQ=C&2m++;CYk=5cZ#2RDC-0{z=z&=}Vdxgx>4M2D@V2W%7}@3r3tkpByCZ~6RI zbG9>yc~$vRp`o1)DNs)IypR%_r#~5w=Uq%O8vnpg^C9Bjb{=H!Ej!Jut6Enou_i{LWL0P05PNAOFs~K^E%&^KE{~_J`fe zYbLj0-mkuXD=_4~^5BN_RZ|B`wO>^uJ$9O()u??kv?F`gpAq}a9qL-R-X>Dk_$P`N zJmQ{y;S|ajApc4KChMzM+-o(R1RVi;U&&CJy5U@1R+Rhw&YFXlR!MWiZ~nfOH2#id zLENSzV>qj4Nuq{&Q1J_cB*M%6^9f-sgC|#*V}*WyVyD=qPaS`W88KB-s;*O5VgJ%W zUZtkagK&2Y>}Ee|`ObB*YPfQ%T1WJv4ufggaGn)sVNB?UB8oEGl*d;xLn#_ibCZZh zkryJysY4=4pQc^X^?MW=UNOHG@%x+Rc6k3@hS3vlYA|A})NQ%OJh3(LyY*!KU+1OI z4;MG@b?iEleV`6H+R=|O=M32`&+;u#YBBRqBn?XbxN8+!18VDk5f0!IS`v7m=aLX9 zL@PIVK2??%KRA>fRXw^-m$;NyU?(btSlbD>Utv%;bT#q3jn3W`yL+OK_SYCg_eaig zDPJ(IQ*O2h6bndF2x@SWUnVhL|zahaDxDnOFMgYI_MVpsJd3% z+t}fkX9>0`S;IU*VmHY`AklJ6X>5k!>LN7=7laHLulngiMI!S!VC-=>q1K203VCL-;j@Z`sp(=)- zyKV9C&+_X}MQWjgD?n|PH${BDsMG@;BwBl9nZc0ax$A*XvgBqDtni<4=UVAU0fr{* zPP&_|r#R=Akw44wg!VIGAWo?D17`l&Nzk^4S1bcUFiQH~} z20KNe-Qn(!Ls*8^?XE0A^H@`n&=fB(7<9e}Ilq)l?s^jPUW+s>LvgwHpFB<%h2wDx zb^EK3a=o|z336NyAwmeX1f+Y}V`XND#-J9KNvZpWXpq6Y{CYlq_K{#Z?MZ4}gvlId z)lE^0?>dRX3Ypop?3oc9t6Tur8o$le;h^f1sqjY`ZU7(i>WIZ~+wv9-hNC?E9g<=a7m?ijyYeRqePz8g?hJ`dsA1x9o{$J0pwt+H%Y4^&da z!%;O&9H_x-VE|iCnLa_|_5H`?_cgqOw0c6h31eLUA5mW&73KGReP@R5PAR1%1PN&v zMO0Km8fi&skj|k*L@L!f;IEhz2~|2oPGA$ z2iK{Li6*P|8W~0 z!UY}wSlfjSR!7+3JaP6=ZPF2^h111ZE8kGPeP3P8%*GOz#+dq~3yOH=7Ci|UagOU~ zh^sN^vLqNwk+Ay5_u(=G_y=P%saNtb+b7t=|F{VnRTxF`j|fQ*ty)0e>58Xr8|=e6yI z(v!1TT@taGAGdz@I=f!D*A5oq!=#+YVxizySJ(YJM}IVe5;dsrf_BZ$AJ=#$8;(3) zL$twV6Oo}3vVUd`eFS}qP*AO2|S1*mD4~%RvicN+BbRBBv!_0XL{M2?XB-AwN3ca9((1 z0D6z@3s>^O^Zw(PSaK$PGF-3uZm;1@%En2_&+)jB5>WNI0Kgr*&;`q_y-Pduqr>dS1`IMEhd*AQlhM#RcfdU#r zR+x6n;ow!Z?=La<=u#WJ@KAR=aDg*-Ik9?Bm8TY0fq~P2ApmFPYd<_;_aaVv1o~xI z-uZKPTjM@EPKQPcQmP6L5u!k)@Nt|wTs-^b7ZD|0(xN6hkC0^js&#{cA9f1+1%z)} zgcj^J*gJS4&~g>c&(-S~DcAy!c`vw1Q)20ix~f?)5%Ojnyim_fc$zmGENvv0p5(BK zmc3MRfG5>p@z968P@_fO9@r6s&AZW^c6zi1Or&d-5lZNnPJGbUpa?0*4WVs&P z2fhqnEe_JGVE^J#Os_;Ij#-4->d#QA#u^ zmD)U?y4ZWyFLEpWd2!T;ih?2%T6UJo0X^4AA3>b>p4aIIZ-Du46~VWS|CMm=dIBF5 zHrlo!EIcsH0qZ_@vFVZ++$dly@crnRKhUKk^NA84r+$BMP#z&1XmW6Qg;%r z6wE2ioZkhy-}BSk39<)I`ZWI{G+g33*hzT8-r2mN^;0m$#fm+W*u!!J=zLQiIuvJcvf+FNZ9SI=@Lx zFdzl4CHR=U$9U)AF5a9^^8B-;j8AtjlT$%ym)NeM=h^eHTPE#$f$kpJ^3wB##toQv ze(uH9RjrZPU|N3}d_bUcJQx+N4g|i;Q*Z(@AP3&dD2Uufa6(Iaz147jK|p#ZBf~Q} zlz{3A=QLAsC20wbktYh6!*5`!c=-GmPvdLJ>ZRDiPKz)5+_WIwy<}DD7CEe{tRz{NrO2aj16FfXtv1FsY0E?Co#LeJK-E&V5`j zkV9^{6M*O2v5UPM%J`Sdt%TrHTjlG$Nd7jKqp7`X@ux@xNyU4?MZP=pXT~S67Ca`G zyyotvjj`08kNKPO`^Kc`@>D}T`LCIH#3C$=Ss6cmbF}yf((h5(&f#eOvp##czhj*7 z`h}wDMoC1;z`A%&p;I*=1Wbs3)hC0b|9n_JkB!R!d@$TNiC0d&-!$bzXQso5mDvK8EGap&WqZOk!5v(JsN z7CbLxsyjaKc!X@*-wAeb0=0!-1G``{laNW>4AGG6|k{^MYl`%?`Y628rSFc#H5{Cwg5dD(k|o{8E!}? z#J(7c)y}Kw(_^}UP9u`(p=X`NRahYC_kP|aakrAk4#H;bSNjZh(?ud#QSsCdSpX-w z#Guw@t>aaB-N4{ye}O*|B3>3ho^_RXZZSlFhJDvrLLz8%w~(OFPohgHkm&+2>vbB(k={{c7hjsHVL|V#2rukpO9n`q9?w?>Sta9TZ8$IprET8|R%jIbupxd*#h)P>!w6?^Cr*x6)=)MUoA zO)WI_mShm4QLeF!r2H(8ew^(Ko^R8iNHAlPg#S)))v$Y#XC4tOKH(re4ldJ_rMF5ByX-~MOte4h=p*XW4}MDP-F>qg)x!w=1Zq@YL{ea-%57yBdARL9p<&19B!HFxo=E zNeUG7SucZnKDJ*wZ&VjaenwFTWiW{p$qI};5pB&S@s1W9S@+*)1`glY1EFX3e}2Y3 z&iP;0J*h2WBV;BY2fi^ZD|Oty#99?4LBQ37e?Fr10sc?7m-9lxpCtp@rC?RsCkc~!*s9PA&C0DUy>4r7QFaY z_D~nC9r)`qJfZL%`>*JK%9p#eq#nByh-5T#`# zT?}#m_f~=jeEhgrz1{iCM0gYkbDBq}gDWMf0EP(M=oOLKp;X-`7*P)kO5dq z`(n2FKIry&oH>5}${M&R z*tz$@&DS^R-!g80r{xRW-u^RJKJ40>L!B8JW096aU_3E~(3Pa9fQOTVdiSDkD%`vw z(4KI&?nLr4+qU4SnIF;uxWSfjm;_?Le@*aTu!$iaKo=!9vy{v}b$avlD?lUgRdT;r zwjzPw1cz9xtoO=pVbVLdW{J4lg!E}iU3>Uj-}dt>4%H8gf3NQPeTn`WAi=`%MjIFG z-i>S~E8Tnd41RLv`$k9eC-|8}@1R0>wWX8+F|^vu;R6ANETdSeAOGsQJy3ufcwBj< z*NwKWl4teaGssE&Fthb=4G$ABk3d&Fe#B;i{EUf0B@+i(xKET}?cNmEUWInFl- zwdpg;jcbST0!v2PRb8a$ipBlLw=M4rtMhM2>75i`W4w98rs>DVRLm$G08!ZF2(&*V zMGdM(+`C~Az)?A$q3hF$ZM7T17MXNF8^j}q8_0PWM5cjwh1IK zIW)PI8Ks}uir4e~fUTMnuUpO2rD`&~7;gzk|Hk&@mF``$)WN^OJ9$a4>X$(0+? z;J=u$vS3=8{(_+Hso$){%S=o0Cvif=_o+rmR;3Z+DhlaQ{u6VDYK%uBU;Q;w?k^Im zowyu|*4weIk*LdZgR-&7%9)r~x4ztPZc6wSZvIr-ivK|sUHAT+kctO+9`RYcX%U7T ze@-F7D3-`8Xv`%{P-kUQ-u7pFCU{k+3hwAegCOhcPR9v3Nl6p>d?QSmJeQgnN7~;QMSOr73X+HFvq-W8~QM@ zRLe2sT|o4$KNhyU>qpW-!JXnwO&jueY zn8j0cHp`+ZRB)duMA$Fh5SaP6ufgm8Me8mSMS ziF_PuojOY(W@ldj{p;%9N)5`aBHK?PUly}@sIpm}x-3|4GIQ_A@`jg1(37ldCyhBh z6?LBCHqNhYKbMCjclG%-C{InOC6Cm1H8^r+aouyAjVWILPAwB0w%|qnB}qr8XVAgp z5k*vP@85iZ`j^a@9vuw^jT8Ib;IRMGpPW%XUpfCP=P-hs!p#S3U+DL7b+}AiBrX~k zgA0fFhaV(PL@VA$2)%qau`d)?F-*(prP~{KLwIP@pEFqRA(kD%u zS_WCItd1m4KdoEho)3Kaf+W1KKjN(TTXv*zu?|sW&Zs@8^LMMhc|hp+2Od%StUNj> zo0%72 zt!^=VIx#vq&iXX4gNOJIgGT7sADyfP9sj~j{CXWeDMWxpQb{Q@JuXR^3?k8BxBam& zreH_i-noen>dD^c6ISBRWOpu;y+m*ck>U+nhllGv_PJ$15KRbB$a_}ME>l zJhu?ONkwUj?|x^F2nA#x>z}P}bQE4>5LZM^%f_ZN ztQq;ZpGCRLehoHsI{BVJ0mk7LHlB*Wc(qhKSux)kRCu8l7a z^}GPik*U7qOEgF*^MTI<%!gDiGR7@LPO3Aiz^Ojr%I2{4@ARzd|0C$|SPC=z6%SlN zq4fyN@0ky1AsDaF0LA^eUt@uJEd!nH?h6eW2d|^5EisoaC-T7+Ir0(It-+Ji@l7zjSMO>dO2idkj&syl@VI zIX>2!hJd!g<%vzMgJP`G0~#PVLFdMX(+UsWr>m@LXd9iCymc%GM1%f_)WSNPO$5fx zdjp^u%Qae$T?m;G{F$dXzr$mN@wI$_W|zv1zw#|NnCKvm63;KD?!qUtS9I~#+W=Y=kXPl>khpM7PV4Ni}RX#>hRr4B{dH~Vi{In3J=JQPnc2S zDY*DWd+e#@{+KBT{khh(07D8$dMD+?j|#pvlPaP;)uzWRnHhY*bEJ7lBZ_4y1VLaB z)+>(U*-YD(6r}|vZ{l_6XZPi4l&`bEViA1o0&hx(`*Mc_3QK~aibazdo*tF;x6pve zJ)Nfg&aYd$Y$=-DteX@`eF3-AT9uS8RUVCDTI>5z#K%AWYFyeI&tCf9i-tUypf{e6 zhO=UUz;45c-;Rn6U|+eixZV;mH`I!g)q{@+e2=I;{5_GG{H#@3VW8-1^SHWP#j8k! za4kk&7$~w~5opf5qo5sS(!a2e=Hg!88Va;}LyKysQ!u!{MnA3qI1`+$ryjnG?j^)% zjjtbM`E;dq=aL{H~UY=oF6s@AD5q+9&4(n0lYFMG13vy%s`q2qt+Q=L|4 zdMa2HoQ{)O&dwjB4WSsERv#(yzoMN$Vo>zn)HukK8r*a!P#*lMO?&<$(k(&iR#9i= zJU&mYnn4Y-YqsM-r_SKLH|EN9UobUk)-iE~@|Xb}9L59?fQ8#2>B?inSJianKh@^>s5+e(T?D0_FYdThF$%j zXYy3ceVQzt3=`5_!HEC{zH7<1BW<~;b^En!N-D7{Z^7{p-c50g+kuAF;Cj0i<0v8& ze{Hc9$uuDL=B#GHbS;As9%oL<0Q#e_zLKuKX*QgRFQPBs>xpI3AqoFmz4Y@k)Alt@ zb^;nvSlepS8)<6L%lsym080Q2SV&a9by14Jyi@(}xstYP|Dy7_)j5ghP6&GD%_h2| zDr&42+Xx6Yp)Vr;s<3Mo-|f>JA=uh5V{lEL#&$_krxmyo|Cq30W^}jnsnoK>LzH>(AAOi|tLbRASR6VCe%mSL z>m3Mx2*EL?bnHz@vi{GR)$TvmudF1m@9nE)z7VUaqPk+6?+GJo8Wv960KUZaCp%#q z-A6vstGn?2%z*)!E?T+l<4!%-<2^rw0y<8@6qt*Xvl`j{@WKodeM!NfL^d%LA=<4ZqZYovcgiJ~EXLIZJc38A?PQZi{kBm}H-KTM9r3#AJK zglTKpld+GUu4JjSJRN5)eYL0ThjLNDXHfjy-$sYTOdk{-0bayelN8Fu?5FucoA_;*opk2yGi@8r+$ zOLN6TJur@RL_Z0UcT1J^=a~saf~m8bJYYVB0^j7N`S|rJ&C4~c_B&9O0I5kCco)LfF|<`35~+H zY(8K4nnNQo06S|cQ#9T#teThYWM%eV+BNA07GAAYl zoL7U`>tq0@7!^&Hq&z`=>zvqFpfRD*Gm|Clcv0zch0;GyUQE5lja-!t?jhQMSySp@ zyP3zs#f5KAASq~T$Ud|jON%|aWbD2c>=;PS>3?4D#vaY5f(No8eL880j^yLk%6m8q z0Mh4-JJ@jtt@)0&3sd5I$9U%C#nz9U%Gq_rFu$fB?gf7u@wk+c_+p24Be;MbxLLCf z+Hj!>_=zEl#OX)B@U37OeGx)IeLDU`a%M{g<{J6z{J-Iq9=3&QK=drLjv&dJWhwKd zt<5QK{+IHAbE0V3Yg1E8p#h(-c6b^5<}g3TZjgo~-}oqd%A$ ze}F6t$OuNi=l9=2|zm;6MolDH%Va zNN0PQjx&R`QpeLN#8}1x33VQwd;sPr*Jxd@WzyosTzAQUDS}zV0;Rd$Yx8_DFMTXK2DQN4OGi2 z-$-cM72rR&ck|KU>brL3S;NIrQb}Q6Po{WpO_tZWUDTa(0IpMT-$QH)j_iyM$`{h2 zR4Bs#(J;dz3!-V*MPapCL@DP2zi#^Cl%Jc zGEKJBmtNIGm%6^&DR2!JH6usgAPv1?y0=o`|7ScnQOSNIOW{E)^0zDi&QOggTMX|h za}JWl0R0mq=F3;l?5r{8$j>fM`l1587jkWm`S$X)xD0$To!doLkK=0EtuhcXgaq;c zjZuqSD^?o1RndN$OiOwj0iJ0R`*-n~K5Q74v%0C8$D>bunfA^bDoO4S{ja00|6}Jo zx4z4y(rgVaOArCpBQm%qbJXz?q4$j}zH9%HQr^Iw>l8MR8Y*ov64~88?;JhdOi~Y@;2Os@VUFa(#70E) zGanIlPd@H|WD4NFc-BkW_%s90{n2>&hTES~cAfaIcUNs5^S?ZBE;#{|iqsq#`!I&d0o)I+miIG^BJb`D9BC zx1QGD<$nKFhZtbV_~T~+VRq`o#3~C&12P8~dpi5_jr^~_KD9N69kCU~x|x<$+mnRe zy7!|@@RMr4P-^l!>ckl}m~C*C{NnM}`rV(m_pR=~#DktB+Qhmr!gt#5CB{OSOjLpI ztI*d@b1|>SG&F@w`$bxxS?@rttui^^h8Sc<|4ysV+$xF5seGNJ;OQSoN+F&J6_Pp;S?>*dO)6 zNtj~vbYW&NgE{dW&#qBX&A7<;2z&A%QSVQhUay{lDS@DVmC?s%grM(&sk&Kr-8=3H zM37>#r0fP7=NhSuIZc1#ysSHtI3#8fWh&kf!^SYP^fCRZpuJ#rguc*JcZO0t%mSBD zlV)SQ6ti<2iWAyD`UAn)4`z2wT@rQ#>z<>(Sp`Hu)M&70tS9fGd-Cy9W3z1)1HkGa@;B9FJW&Vk4sPH;=dADa|aP;RT)ZX9_SK7?_b&ul2apPk?E|@{sT~Esn zy`dZbE+L5H=jM{QZ)2fsq9q~EZNVowvGHVp9BWtMeqv5F@0o@-G+{`kGH*Z`pQ+?m&Zs86v1T+23l)?y+8G1w) zb^PG%-%7tv|Kz4z4MTx4&(64YZ(MCa0QEFGRD3YGU~2r@OuiNnL>qr9dXs z46synQF_&T`OwD;qF}&8=6tjc3P|FR@tL1))<>YlV>K%iVFwWEJ%%Z>^y8hbQUoVg zz4UQCwLwlU0x8#IrpKsmPZZ|*NOIeA4G*Xh`Efb6JMc? zwrl9qH*;8P$rq$uuP4qWk-G*G{3<#`d-pE{_{%oQG-PQ9|Aqj1Grf?hSv|T&4Ii?0}?tw!p!M&GK+g+ zF=w+{tg>Pf#`0ZgO)Mcy%Ab zI2ksF*}%(~A_Pl^x?voJxjDMuVOUC6*o6-)^0pt3?k2qc$ka$qGk#B)vc1D7^GgUX z<*|{6MsTb*>F|{Xf5FtZ8MPq1fe`&A&ZNm)p*a1g$~xQhpVO;FpA(lAdHAMk#TFUN zE$r;kWwdq}M0~j^ukHanw?nCMgD{eP3Ek?>~_XX^9onENQ*$C5AQveK} zSFDWbLrbSCUoS%~wOi8ve)hdkN_l94#Xe9qn-ypQ|T=6tRS-K_DiFQ3?DSEIZVZeZy-r?2#eD>9XCd1r`97diU zq0ZUw!ykHXRYe$-oMrtk(7Gcv^Nq}b6tCy!d?bX*G2GF>1{h$q6&0AwiLrO?0dA88 zo+y0wcVs0o9|PU)C6abEamg~aGzPvD%()#4Tht=P`*24zEJrJ5<^M++kVmXtOE;_C zp$F$sSP3=@SIektH^Tb6~ zSPP(ORYtY*R$($I0J3La5Q9{~^oKse0e^Z-9bOzA5hsSCACL=XMO^J&HQjj~O&ENX z$eLd`@*~DB%x~_Qv5-F!$5#Ebone^7S9ey^(w|Y_lZB&I1WMu?+`+nWvlV+2X#(g6 zXnH^TBA;|YfC(ioVTf31-5T{N8htr!$h+8|t3?XzFa+0dl@*sWp#PmifTi*Y#DIf? zwi=FmUjxnB@j~e^KK@-4cCv0Dql6}rp~8;3|CY9}tYu@~^$O978s@K3GiQ$VM*N|f z;4F<=fB3I;(fu@I8X5w-3`T&MjEMdBs9PW;v-G~!zbXmOIXn_35-TaupeL483Fn-S z3$R8LVEpfHz}h^Jul{pP6CXDDBrA=v-i&fuO8pj&KcP|_IMJp(nAO6t!t*p9b!rw=6$G#Yq&6UhAUI~o?bKUe9~rwBL~i%aiYt%h zwJ01JK(9 z8}q|=@PcoY*Px(b7#=!B`0=5>I7cpFmQbpn=O6^2nShoD;+AL?8rdI|Io`Q)oe}H9 zgn1!0mz{y2Lci$}&}U>uglh_{#^Liny#QTo14DJfO^$6R@9(n*X}oAaFo;Fuh>VCk zzvlkr$_jexQDk4K<{!;5cNNh}w;1gek*5fMdzEao@u$TZ5;mkejh}6(mKY;$AZ%iWSfdMUz0{Wix=e5k3QxT`F>CAk{sYZl1P-LqbdPGnZxss+7smdt8ujBBT zreius9jMu8r2(4T-#d_!;w?J5$=-0bDV~d$x3nh2Kw^ri)d26axh;H zkS9XhXJ)VR{lFMF|h6yXO4ha z&H+s5AitO-?p;LPigYuU540l&(T#s|ljwj^#0^d(mCvu@!r#Cl$5;>-Hf|mz1rOO! zrpp<>#2qkpk6Uy|8Z};cN!&l`OV8PlyvPo!=fX*pZmv3{Y!bV#10MhY3$=bbaOcf`v3Jq{;(cG${}j!F&Ss*4^Z_Uk#&| zQ}q+FsO)R2_{d$x`d@Fn3ol|Mr|U2e2vVmA>tS~bGKf@uArfq-_jD=nFU+Z(TDx!# zA=?n#>9{k0v;Wd*qOZpMN69gRmwN?b!tfql?tFJqH=Be8vY-I=zQy7C)GNW&pfS&* zBjwY?hD#HdTCz}7zxHqF)!e5b;zFqwj~yEk1~U=@>2*H9zx*#v_c9R34Q^9qK?FSW zOHjJ6?^hA|;sL3e`Xm8{A5_{7svY}GL!oop0p&j(X0H;YG%>N}AJhESe>x;QXPvN$ zQQvk&OC>^o0kmiH0dr@722A`u$xp+lQ`ebvhUD>3u@ZFOZLW`Bo@O8G&6&tVvn*%R z*(c%c09)$awanV*(vw|~gM(^$htd(br(GyNvLi4d45R@mS}oh+C`L|gedoddHXem%E-soUYbW%`lh^LaB3e9Z{Zq2m$)*HPH?Lg^Eq|X=DdXwm#{L8sic zsYpuyk9>iZ`2TQ+2|SQT+YEC-3ukas`NnNkHBCz^C)_eF2Zw=*6~Q=foGp&vxO;F} z;PKBZpUors`mm*w58jt3bxo$Ge%9H`?FT<1{0*il_ab;A1*Xy^KK)9y#V0-6DvmkhaL;F?X@`l5(Ymn<3Xq9cOja&m^7+8uc~*pE`3 z;;6s1bJ<`PqXjM5k0;h^13ca+rO4t)&RP8#6tAQae0rOZpNpr%xf^tvn}%e|YtsrG zq5%}2$%SZN-T(L>Cl6h6D@<;Yym{h?lw*%N1ND75AMA)w(9|91)pJKbyZznYtn=fa zYcZkGtkvmu1f13ntzCL0V#UMnZ}o*6Ufv1%@Vvll-tMIf51r0WS&0-imy2qaV2ve! z6*uIWuGG?>F0`FQ{Pf4cMO>oq_Q%4Ja7RnLqnaFN@JUu0{ra-~goDXvSlBVRE&dp! zBwTisYi#_0$*`5v_^GS6XS4<0Q%rUWz>x@l@JNygyx%LH>v_W#5CDF9%@hXhbqoaL zJZuc@RV88EY^0A4XYp3{y!`kYMG-bJ1fMAEafy6}!$+4*{o^=F^vZRk$%b70B6zY| zo>P(QbE(1fSRKb(z1Qo^qAsQHG0r?k{XO8@ui+4LZ-goLyFK%HZIR}l*FPyDz9bS{ zW)v-UPcls)Hz`#~9B_!syBuvw^E+Tki8OR3qH=#Q5HHSjMnkLk`kMFJHL*pQO^Zb> zj8FX)u_HF5_EBcqtj_f|IR5f75`JuGxAGE4JY8l zKeSxUF$?nPmxi4zmWPr*SXN9)iWziamR!+wOa}iXOT@<;#gru#$$iZ5-{N=GapxTh z>3y^)%KjJR!)X=R;zYY&Tp_aAr9Xz(Eed!S7u3xH43!`Czvzs8ND~+R{Gx5d8o?(- zq=W7Nx{mAQmh|c67rUJkG#>i?P(iSR{fGAsS+^v0`cI?BZHtVX-^48GFp_Tm=4uOB zj)W}_QF@>~`MwCXj&NpV(g9yZ8(rWrEj=q&Q{TZRUiWToG`VEyrAK42DiwG{S0!B^ z$xRj-MQWV&e@N8EN3RK2vjp8&>~TOBR)jJrPz(13#s|x*{aMZn-hI59Dq%YlZTQ^n z1T~$`dcaV&dv_>9JJtR>FK*#&y*PDi=SA0k8=rBd-La^&Qn4W@p)#VFRI&I~6DhDL zAU5N(oho2A-ThN^ zco@`YajJ4U{uc_%-cx$k)mL|hcfSMo;KwJs6C~6slZlI2?{UtiKG&eZO_nx?!Da7>5SK^DU87ew#Sa&AbR?T`Wb#ynpC5Xp4n?Fpe zxJ?jU(EXIcc3TNmNyOQ;zDYq2V(J#%9?W$`!p1c)t>r})@7}Nyvc}%@Tf_G_wll6* zDRyLTY2@axgp}DlL?OV|$Wcv9`k?7|N1pym4JRkZ-V95Boe&a1$Iq2sjq!1a6Pz>i z42&sv_!tf82YFbnSl_(c7ub*}>SaC6cDU^R z%XOn+7gN+_;o>W*Wa-pda?qcaMpV=Ppo3guoAIS$McTCc>E^*H*NL{c+!9VLDNP}w zSVkdR>Dbif-xJ(XV(Az4xzWnf_Z9r39*>WLlHX{X+$HhV7)-QDa%^XpPDc%R{4iu+6AzRBja=v=3NtLF)mv*R1O+zH zVj}oPg6&8^gRyF|7qK_EapbteH0V_k3B;BBrNg$f(7 z7c~g5I<|%YK^u&ip`J*j^m1F+U$`aRlArEw$URHyLQN;|1qOZa{yTDnvke*-%v}fy z<++bDWA%3YM`(uE@VoAV#@?^a51BsuC-nx5^d1(tv2XWYU-GY)W%?=9sh5W&Qqeu@ zTb?NNoqNCWN@ctTD!sFm8V3#DPKcY**{u)ULgcTrk##nekL zS0bgBt1}apA}b?=4@L}GCO#jmt@r}Bn-%uu)}Z(C636*I%A46p zN_kR-+W(xNg){R``h$2+fN3G-Bv@LW3H{|WHFA7XW8vc?56J>zYtpmOnV3F4UB8z? zXbu}mKD-tRPeI9xplYg+vVDuuyrj{g(v%3tuMrz+*u|qN0yT4VR-=hfvdjIQQ6~l>e!Jg^XW%fj#X+ z;{5bCT+#@!d|L{@dS3xhbi_Z)ZIoU^EyW>1fMl9nm8NFI2BwoiZzSYTI8Xi|pI98z z=S0OuzkO}*y(PYvaQz}!R%l&khj4_p*+Jy>W z1=~L)`isP56!I{V-=^x)Y+&&vctN;AZ@GFtDwuE|@%2}y%e24XKN7%7z*KvN#+=1f z%Fg%p?pxavZM{cLtf~Yvo*Bg77*Uq4^hsAlJ|t|)m%mv^BIA;x(58|W$?}M+!2sX3v=w@*8{HYp!{3=S;s;y6g4@7W`z%p zJ$i2$eiWoGZr!-(eCy{Wy~3&P@s{Z3mArMc-Ocgf)bsL9 zcIM0mm9k8xEkYn8^I<<^i68tUp2u4u02#EV~N`m~z#kg!3W_`B4dq?`N z&mSiEy^XQBK!Fwe#v5DZLbI@RRw>iP={X}qxBGfMr);kb5t!oO>x4Iv8If`lZS4*O zfT!66o_0F8+V4||(A4E9Dth}Sx^0WKq7%e9u>FkWB8E7Xc|Mh&c~;`UxQKV1SSWirH21{g1K<4~LvZum zyzF{-fm?upm>S^xIReZlkz8%DftF-wGy)*`>FHjA7G$4)SX7lh16w&s;&`>A9m2eo zAe;d0F}0GzdgqtyZ)1

                      7Mf-;3`$F&Qg-F+e$BzL>*8DX+WqM_rTL(Ajum3K`l;e8aK9K@K%*gJDyRh7S0xK$1 z2Ja0O#0%Zq4j2+3aD@zvzags4!2@K|2u`^zMv%I5Wgdpu3cb;3rL&|2ha0P6)PGE>GpA8P(_mEC*W2+%2 zargrp{>n9g6)%|F8tqtxBiJ=NPl34*Z0Dwjgy`}ea`bU0ev;RgR^P z5fv4yF%|cpaFL)`wB73`#EkDfdlhx_X^O>q&|(GRq~9HZ-LQ-(s#gxx#2}F(#268I z#7f&ivbjVMS&d6ae$osojY{6sF&!7sQoGA85=%FX4l4~;eavo%uiSv|)cwoFedU+P znpZ|!C!HQ5fATAJZA~CYT!O(^1lomapdi4`A@ja```wURtcCwjS<@*IFT>@pijvW3 zzSL6uk{Jh3bYx-2?AZSUHLU(Ws9_2Xv65T%HSK-o=i2xYj!ULmSDeHTV8 zxULWqq`kZ8bsF=eY+9s6Q@=Z*dH=Sg>zRpC^vp-Lvmtwe-C(?BpSzWNf7>Kwz2kgt zt=@I=CxIRr-}D|_?dPPA=1cLgh?9dd)r@32U9}Qb>2r52ps4oYh4q-Tim|L_Mq<_D z&E#pX^b|+4uGgbJ?l(S77VeoJ#Sms_w$H6y`p|DgP6Gn_?_RE_oZ}z?#5sM$QmGLs z&EXqnWpB75J5kraSQ%in=cX^DX255%m>NQGIW;XM#pRx&@@9rJErXK~hD! zQw8a+K}u8*0qO1r0YQ2Yq*F=+1*N;B>s@~D|JECqx|ZG<=6>hgbH1~`{q2pzMDMb5 zFOCEU^Heu?8Z#s?H7Y#nKkCTwxiom{ov5SCxv}d>Aj=g!>XQdAtasGZt8}vAUpZpIIupKdy8q8lbw5g@znbnP+O#6o5lM%pD%Tx=5MLyPBXgqpMpfCbnR;d`tAJs_s58?uih76P8@vDB>NML<))XcpYBM?JpM%}gZ7-WhvxChc*S)9FuSw> zqEd9Y8GlpSPgRf+5Pfam@2#!Qb9OM!8Fh1Q*;=u`Q)ay#zCQVa5i)6Uc2OUbg5IZr zS?nPLf7gru86uQdsH16th|cTpl0?JLQbAZ8KZSRuCo;f}-EQIoC4aE7VHP*2Jn9JXxL4;<|kB7 z`(UkN;uz`}*{1>Fjv}1|MLOXCfo^uHcfuhp%6g;6N@`l`JnL{sIVJm@yuY}Oln|}P z7KO|#%7X)Jv`rIz50tY(nacje}$ zo@1?lHtA?-l#-hMk6@pQb~hLhM4o!B)g(6~sqA_wl4=g+0cjfqo9UyoUEa z-=?+EY_+3*Sq*t7bNBGJo<8E0HVmVG%m=V|O%8)qo{fH(Aj($&_}-A_Yx+;$WC|t{ ztzm`cfzv?gxkf=_B<{ky(ghh(NmcF?ZBrV}(Fom>mj_oDGnx})Ae}z0th=WuGU@IW zW`)9}Yy*Aft4jl5vDsV2F9DlSiEWRMMNa=K6T>YdL&NasBqrdcXDhG7i6aLY8qSYt z!18Ieu&uuZ_az4pZM(iM-V(>agj!q$1{IRC{*};&9X?BLW``!c09gD|3}Y&#`p_=$ zq#tL)T;PV(QIFkhYvtA_YhT3QgM$MI^>A{h2kz5W>^p0)!h)@BmBRLoETUdd*V)Mi zAu)o|gqHdZ7BYsLcq}n$*DyDrEO?kvLZtGA+R2MI zfDz-c-Hyzqg%ZPmUBI!{NLH6=BWW+&PV3q93j1!>xc10EUv25}Up#MD9(c%{;kJgd zay6UpmBncd^#bACH`_A--6`%oJITGT-v(5QG*h2Q&(`W$OOlP6-&K&E7oRB~c#nMT zP8qS5o?ZbTI+*Xc^IIHD>6E3~3R5g{ZRz2fy|HhZTfOn*gHXVkb7xwymYpUMV}90~ zrmGGz+V7}-*xPSkLF^o&)7e$A^&p%LysWKb3Vy7jjbe9iKM=W?lR($klw~|LA@I0^ zPg>D6$P#~&J2)&fA5y}6Q|`d*ZoZ!`rM?ngrQX|8O(w?}I3TRt$n0)-fC5`~1|Abl z+zz@b7tZUfYZ_qf6E-DgiRtZ~;2;8fC|2E2t+uvf!td5nE`{fhER(#qG|%sL$ymQ^ z>8$O@3fUYfzB9mb2@N`smMZm25K}`!DYjf~Dh^tgBjX4ukd70j_^X8ybJoWU*?{%X z+m7*p6%t;Zv@Cfx*nhAQ?iS2!fq!l8?w3#Zxn-2k;Q`Kwj$s1e=Q4A8ufXfKgb*k$ zrMMy_7vWxPC|wVx5`=ZLL=%MEOW&UA@~GZy*hgKBnNIZabg~#b&)W}dIa{) zFg86%n$eF2<0#5WV>}2`0Dy`T-Tb-?yo3Ml?C5oAm5kMzSq=HwM=A8f%Thz!UVqw7 z;j!wjq~7D&yK=V?4IBx?P!plh)AesT1}gCX>(YqD@z-8z!U^b-O02_bSBtrLprs2s zITrXZ|8-x}rsKulVRmHZ@_eRXGD->Iikn2bwVOd_~UCoT@?y_=uj-hJ6&du_1&I2Y+gSJvEq<#;Fw0WlDc<#ZWCd-ei{~2nE0%4_de5 zdi{+5shH<7JSVfkrrR#NBiJWY!^YwIPRsYLDXV$EvOEq46t47}f%Sfe(2*4Fz3~CL zbKZJR&W~QM4z?VbtN}c50h7;g?ed3)#rUBikN-;=%Wr!4)6pJZ{z?nHx)O`HWV>gM1BkdcvT*OA2yx4Jezr6xFuk#69pBs^hs=t)ziRH1k)mQdEBM2Er( z`fo1x1mm(_69(l!$+rCEmM2$CnT%@^8otM;9rN!(Lbr^l?C7Hn@vGcu_*KE#1WX_{TQ}Ce} z@j4UB4C?zgYwOUrvEJT_GMW2-Qe6uL>f+-wPL$I(^{8Mg?qs4OqiQ1mJ;<3VA{xHW zW|Q6a0ybL(x`Oyx2m~O1)aA<_a8#yF{N!d+TKlHop$@Z`#yt_mJEEo!gIKh*v;YNb z+%1v_nv_1eeT4(ofk2ykK1W7>;$nMDd2b&zhMCWOGGQ|JXLfrk-L`r0kn6d%IAJDF z+zvYq*Y8o5JOD2phU25#^k?=eQmP*!JPezHNI#Hej=oT1*M@o=X_(TYS7@H73f!=u zMd6mE$GuCi2siojz--ijClP`e?=6n~55b63`tOkn(uXKL&>UI`Xfy{m*-b=SBY02p?(xNEA}-0{lg#zkk;?}Beo&eSbw>fE3QhTlp)C?A2mMC z|HCB!U)sxT>J9{qX5wUeqneV4{Jz)zq+!0%lAqhV+nid)|LvDeNb{C*7WR|a?qcijOl8!9@B?eS@W=4TKXabwZw}Dg05L>SN6P}U0 z8#?Cyefh({&oB6I{TiEg-UWWAUylGm>O-Uq|WIXKL%S{Tba|oc^pXCFQ7` zU!dSa8X=eT^9Pb8?Pngyz(#o6yfNirH@$(%Sd2@E4fVO>}_ve#YO-X6l>79VxCyi>VA*EZ~L0b{n%gRj4+yT1yRB{9;X+_22!Vz)$~QA0+A z61deasFU@7SJXKPbE35fpRGfW98b*ZED@?<@cCz9h>q8Niysi)O@yPZ#k$0oEa~y% z-VJ4&DB>Lr>A9dWN;g1U%y{kT7zJmZTPU6H^Vo-nSrW1+e;fnz$it+48TMNB`|{bF z-8w>767^wx7FwuLvl1LDqLQlnmx*==;rrAI%tS^Xy?0Ws{5T7e@8Us)mI2YP`O%OW zg!F2anbI>6p=&Etz$qksP}*`X?l3BhAtWTndh&_ZOb_FR=lC{vY>tjo9y-IyJM5r2 zsnGf8LPgy!_XUltcJ3C#<1EH5A;|1cG~nA5K zb&CR`mruw;p?8Q96?kA3cE&8Bg3!q;;_;7W*b}=vVqR7oW@BDv&EVZ|XFVev{Bltq z%scQ5zmJBmslMFUyGxK&&Yjx=8UsfU+S0!~- zU@&w6VP{vlkRDzz0vq(B29YH_$@|YEnV|!XHr3>C1y? z!p|j^GB|fezAAEtTt3L6QwN^W=MBuTtC%X(2y)s83DB?@p&O8{G$gLyc3E#n)+5a^ z=6DlkSSY~SUwZVy;X~TVVOJ40;rWoRi6fmgBT-k^rsmKg)aJset_$U2w@%>Y4<63p zIz-c=CpZ!cwFp+e3sR8(x9ebPKX15i(_ds3(4GjmSu$+%dwv-pI|zQ!Dw6B2 z0E%=nWcYb;-{<^x0yb#1nUMEH7ErjIm>C;`Ox3R2p!@gP&`DpIgD?=4(}e`m=_y`&&pq?#zyqRksyR#M{hlwM*K-Ps=bp2>^b5k|O1 zu+EBG^{#b~6aLki_{W(tw<=z41e%i&I2~Y6*3aWZIx0)PG!IBzunQ2Ov8FS}eSB-{ z-iPPNB*K1MvVlz+7E1gLHsxySJiD+Mjn;NDX({4T5&Pc>_6A_0vJxVVpQIjm9ebSR z+`;c)@K4B~+1mZEHoY*(;C_Zw2y90%N|zrVXKaww{plnD??(J*DF-?n1=Y;e4yyf$KBXWD{Xd3Kj>fTPJQngvhg&P&1Y=x#64gz21KmWL0$z_9 z;i4=0R`#i4H8!!!2?I1G_EZEStdLBi*{#J?gu_ca^FD&eolS0-DIA(TRK8O>t8Q35 zZW}ib_|qS&PndftuU{PPS)~7jo_8a@`v#i0Th+`R$IrAv#~??2l-Z> zw*L(F0Q5wT&$`86{R{^~>H0bsIg~tnzDmDbF*bc?RH{S>=z7d~IcbKgn79$w~fS^Iz?IW|f8ID9FTzztAl<{tRn)@$JL(PJuD zIFYuE*2##$kwulvVIyCDXt+9xVLLb#lH0^xErc83yu=CLyy|C&SkoZVTtbMyDPnPD zM>6uDTfgA4#CW%%bpg-VK?tQ)K{q2x%j(LHeD}w2#i^Eh0e5&Sq4RVVHO+U05jqC$ zhyCgQHfvJ^2DE1rd9$SDq8vZo?z0SAbUW@LJiI$uWjb5n+MvOgVk_rQF!)}6&aTWS zB&DQ@*Rn`%5avb$*04eDg|IM{=4d6CfuMHa$%Bw5nRxj_e$*3Yj*L5%6VDbd8i~G# zWL(l|u3cfvaSk6Et9{$Ou{_j}Z@9&0@-5kC`RKhV|Lv;d9h-E^cHfL~Et&H9<8$qo z?X7$$Z)_4z&mqN9(HW5F2xo%KuZPkiZXw@t-=IMIlMpJ7V1S0bDbf_F*eAHSgcBI5?yFOix0}{V@oJjJwnW1KQcCVVX9bUe zFiKNs(`ef!vygtJr~q|$(;ZDI zsK+u5oDjN!Prc8@-u)n*dZG#nLSdG_-)k=X@{EE~mI-`tS!)$6BFHC1cN@P7Rvb#- z(d$$`FTEFGL;jp!g6_eMsiS1rQ#G|;TK$9De)kvOb&gC!d-Yr^w9`Qj+DwuFEm`ip zdH)8GX-f@Dqc?`BhFUxyBQuz~3nzuF(~i?f#}!Jpj+<9K+F$DNs*6>O{n~QZo)V)= zuaB{l7LETI%Dy8N2mz8yedv=@Xa}2b58159+cq^~25ohDF700^{fE34zV$67hIN%6 z?qsEXuXsfqAa$@?Rr)Y}<&B|AOOn@_V}>l|n_Vp>sO4(k9y*bSSs(KHbVnx4wni}I zC^A6eN*=y+tKZJOF`PS&{$9-m(#haKH($5vWA8vK;lY1@XbRYF65!}-yGY(PF-5S% zVpT#lah%Zcqf`l6a!Xi0_5_?5zX}U6BBV|Uq7N==V~~(ygLSeeNG>gtSIyMw9be3SSz3SN873)Se_o&V@N zL!HmB>H}+_<0ytE%FBQbz2DI4UVMH2NQDElqOv~Sa1>5_iUW&#r(zK2H>T?(3#sd7 z8j)~AI@qyY_Grs@IhT|?KhPBBhmy&O@(HB;An(ct_EZ$hj2qvT*PCZ)xnwZ~q(Osy zh=9L%(7d*>nw3fJlJ4mwZkSW-XQQNP_iXS(s4@Ma)ytlCi@urTuAyXOSA2Q~-@hAw z3{pJVRsvVy>bq3BWc>1c^FKy!>=*mbhoYhOffI!`e1LitquIa_a8RP++#Ov82O+x| z$`azk(h#TXI!5(QN6oFGcjTcWY*zh|zS)~q7_BlGJ#sNd(gUW;QD6QxVY7%^jI;2Q z$jHVNPX_wvz4wX=2n=~RP2ulf&D5JeW#r`aKIlevdEBpZFPW--SUeqYj)jNXx&C+- zHq#+ONMHQ=^pjac@RUt0){5=MPJVzN6j9;V%Yx7&!gL4qK`HyI9T0}e9=Ro14>j?` z3fXoi-bjk{uHdSk6#YCb7c3Fg*v0<{O4pXtFlq~9(A)kSAF(Dt1r5fv({~7xB>Y*+ zYGE}oRwaG5+MTSGae+72>_hN{Vry<$^sW8ciS`RDNruYbkbKLzAu&_*okyYjn$uAr zbkLU5i$=C4*#WA~?C(JGB5>i4zNsXg+!3x9SkRFNv{B4ta=SW?u^!k}EFq8fGEP{g{xoF56_zi+2p&&)q#PVf^x-S`co25{48CGfSE6!+( znFDdHh*ZR(8v;T#t3f_)mjj7lHCYI@cW`Ey9HV$>=TxHWSM-9 zH92%Dqsuh+C#hsSx@CWmcBAdIuy!&M-j66LB9NGoQ*vEcG|(b6UFu@+nXHV9Ni_mx zGQb{~xT-{QqGEGiXFUUnOx-J3w6>HV`es@ahR=q8FfbCt)TvnX*td6)-Pybo2S3-}H*o*zpHWbUkq2YV z8KbhGl||+I*XJfU?n$Q${s&TY%ptVXT7pyA)9E_l`vL{Vo^G8x^WR^;<6X0Z35!Aa z!}>*_pLYT@*TvB(^W3n1;c`B!IA=yh2rk z?`{J%KThk+vDnemVHw3|PJ=QvNk7;B!uB_pVZ)`5kYA?+nxiGWGQEcT)X$Qv7d|LB z%gg_H=mFjk0(au8JKxyIKOG#pdrv=nzOs9%zBd%#e`o#V?Dl(BZ;)~OVWMv$=h5S& z0Wuoc7uCRh0c|p447gEwWc#J0O$8wl#WPmZcqQj8uBBk5Z}2Tz45jfM6-xxl*9nJ* z$K--aVfP3H06B$Q%4WLb_GMA8@sm4tga8gMXjfmVJF<4V6``&@)TmtuD{+fq{c1iF zX()Ez_1Zq!0g?FUwDOv-8xa!)Sco_GcISZ?S`j5|4k30BRn{$ zc32bXV8HGgzoW`Avgf(d5+@j2!t2l;nHB%|% zk*Tb$twpB`>hr%-Mw4f0dsZ#e*j2CkT-OKrAMf}dC^HViAFV}|o-2qwAxsH^Bspu( z=bPUPN8T9z;<(l5B}q=6YnxjBWFj^R zlTsQMIO6Q*-9!jf^2|+$bLih4#=@8pfRR+r>&iNmR4&>Y!Wfr@>pgBb7&t26nJXrA z*V+Y+(Q0VQ_W8VtS3Z7!79C^IlrwjX;rO2gCg6&yXn`4BdVM<#*`1iBMKQ60b@tnK z1_YTCd^%csmH&0~qGm0ZNJsX3cWX`=c{Q@lViFaaY zsx@F$1uvqoG@DVQ|7KFcUbzEoA8-@7(o)U>dll+QQW%-PT6V@PGDt$35g{lKi9e#+ zhXFYc`GDR+Z(_UD3kTCKL?dG{>6i`T@w+yNCJ5If$iyh_dURfd=3^ZN7SJHAwoJ*+3_hA@;wxVmckuO^5f-^=CGRjv_J~j|k0z zQyuo-PCog}m4`8H0GwJb=(&DvWo+O-_Yc+$c{9g2HnqGPSSs)3xIb2`sl$Y9w95W_ z@}&+hG_ZLmS9N`kV#iNL&&tfImgT7g)(zaFK=Oa$KbK@I81j6lZPb+v@;zz2Aqak@ztbQ2Dm?7drQ2VG}$zkP>>9-nqV_EPLB@wf7Sr{5; zbQn?u3k8GXObm)dyIiXoiIqdPocx_np`xw8`4SYQ%(N&Th;cGDRlB^eN1K!Ons_%R zg!iw^vziG9`)BpBQ};vUXlzOC{iFj$;avOXQ6ux;LnM~1tJjVvW?&qKJQ!bC^3VRLkvCg^K;#+q2_-q+y#Aj|2 zrn29~9Bm$6$yONzy?`ln&uqLH3Y4mT*g+3;han=l-fhI6xHkBfdl_~NC2lNVJ{O#^ z(-)v19;N0h8looH*h9L^PF0*Pc)a*y@wuRIzX=ig_~`hmzu!U$Kt9Y7YDqzkJYi{H z8GG|!#Ac-ikh6fD&E`Mm_q-LCPEm?ejp}!yEFD$W1dSBr z`vt8ANiEC%24WnMJ1J^C+3~-Zas@p*YAkT7MJ6{=B0c}*nrT?TAZ8~Nt5G2_3TJb{nCwBsN{{`-cuWi-A;*_0`!%L|J9es_-8vFqMEL zrW+Ln{$G)g@++JV!s^yBQ+mCG+ZwgBNtKff-f@GEs~!=C=DB=qJW%q%yiehO4Dmp- zN&MF>hsEedzOsQBIp$}hFL~ZW`-jfdD&3ei#yLLzwW@b&HJrolU9=3|us4;!v24gU z1(~;tK`<-AT0GcI5#x|}+RyPG!x01+0A@S93@AyflG$k+Bo$%duW zqlU^{-`=8+X+!4dE?8l2inTcqM+jpRPD}^T@gS}bAX#&1ehu`*4z1Ad{v^>qxQZc<1HCz%Xdrie%S1mvP$Fg zg*DmPQJu2%=-gzIQ$yN(Th_SuPzs;L3GCP}C#;u1>jk8J<|O?Tp6GYdS;`>^$xHlL z=Y515F^@#s7}K(mkD#5{>%@bT6IM2Yz%$F`8{1Uj9hF$7AKR z6^PVAt3@Xj<5-Hh`D@`<`dv!(d3DoHYv9K8h1lG}m9VNp-j<|myY-nX3m+5wv_Vc- z^6raj0ygQo+eLwxRlz)JH;q3{1~IPgF1occBhM%oT+Pg$MH22rl0JaMfXw1W?uEI~ zXTgnvz>|-|tX8SGhz=AVpf2nk2CNH{688S~b7sT%q1DucC>i>>Pn4O1)$Dwq9Jr1; zTi~Vgz=}{npeEbO<_@wx=^nSJ?GJ~1;c$p#4f`s%1MuyrZPJ8+We}EA4`VYHg!+YP zL&ypj^eFsZ8asKG^Ldfy5nkux%Ejuk2vPcyN$XgJf>l?#Z3#fnzWyFcXaDOG@J6mU zIs3m-{*1@u+3C*mJsTG9&eP>q{N{Q#s=@JU?$IsX?V6rF#J>&CBnB&o+m||M)77d3 zLhrGbG}BT%gXS87CxgkWBUTP4Qhu{yIa*B;FX!?T9{LfrV98m>H&-k)%El)1{|@-s zo(_4Uj-37;swuyXt3Z>4WyBNzZ)v`dj=%Lw(4)JBJ;D+R?@co{_UKy!1Fyt!Nwhu4 zEK33iWL*v6$HxPWa&BIHM=fWr=Eux*F-*6q#qN6UM#4adR4 zy%AJ92I&?(+eY~tHhT7^p*y6Xy*j+5({E$P|JKzx^)e~WFo<@)6~iT9{B0T}o?d9` zoi&PltJ)qIgVAPwkt|mAItq^ur$h&f5kQJEO9yd_9vH2U`jEtRxnk4#pu|#8niFMs zJ)r5+m7-Z*uh4|M-}xHF2#EvTz`n9o0nvyE&=dg}m;X(5?UrNu>g7=oV{Ss@Kg5+9D!OWZ^T`{l9MdGI1DE+_S`{ADK=BnKfD!0U%A_4CyGWX^YF z@>9goAR$}c-aN4^B5BU{K?@t2xSn_VUN>MCe(3mzjFViUE@*msuC{sFjUW z_`0+hJwb5#lg=fvoLo8uH#bsJO{Y)aPd?oqOIT#f2y{p($(&AqohS|Nx!5vRXF$8g z1G|MiVb=OwrN1AM2&^YIHw2uZWXk1fSlKIes`h_ADRwGPD7S^%tzaMZZDTzrtf&BS ziWG7*K;}LiMomp{m~%{NgkimFx~SuBxY%3kdA9pc3l%S73Bv~V%$b+;=H`Hje*wlg zsg`si$IUQmlFAPVOS zvaACut!EdG^KT*d!*>;dvi1OTc9}y2Dd}f9N#?SV=qKD9)Z@Hx2bJ7ImkC*#Go`i-w!>7BP-Q;h)rC>M5CHd z&P5#JeHO>rqyU(Zu$_g8m;eS&^gI78V>@C^=BU_kH6pJz#8kKq|7$4+uRE`!&KpPe zTSmD&3-)PuUzJJ^by{D2`N?K_xfyx;G5N=c7#tXJnPEW1uidZOV9xu0z{S@82QJK^ z;MX1B)uVNTpbFh9N$3!#d?j-we&nd0Xl0c6adO4H@ex}LqYjMtiHxpoM!Jm68gV#b9C$|?i$FL3ide71hZZ|Fj z2k7vu0E&J=MLW2DR(YDbP_za1CkIN%ugirQ7iGOYJ!fE^@agaVB{h4aUCW1xtr!0F zSg$%dWZs*)N0np_i*r-WJs7&uaCY~zU4U5aCBF+tcJ;wbz0%=hbm1!qR9(iZISGCS zeCFvf`)$ymDrUOLm}+dg7aRhu(Hou;MF?p~9g>(gB7t5Z>oArEkTb=?@PF(_ zCZ^^LmQBU6+{Di+6)Wiu*ByFXe&;I2^;NrRZmyYcGyb!jTJ!% zqWj5$LtP_QK6$jnf8|o0go9zlJ`~j_*dPH4wnOe_T7Ch)OMpxG;EgZu&V2+J#k9BW zj|!W(g~n_N*FsJrB=2CNTPGpRPY$l)vegd!=R3>u%S5o}sn8-nh?gOEQXjzN;ZZGd zfX;19V&39?lftW6zR>IKIsyxbkDK!DvoN47l2LT%w|VGA6{*;@$eR@69DcgO9^^^h zp9GOAzSBS&eC4F#Eo7+HW8#D;gx@loQwO#ll4({DMmC{Vt#w_Q1DGuy7iANnl!@67 zhGMI_>jX{#<#@(XC2aPC4gSgNtniKZm#n}tyv~H;0aXimjSLd_tXMu_BlDY5g)!Nk zNGx^VRo#6Kb!l^vj(#kBkV5AvE?qR$^K!2=i0*d@b0vk!eO|`^aWl0NRAy6Fbii5L zpU^{hsCyG-q8P@aYz)Uiemy0APm2XoJw9VTeQ2|YceAEIxBD%b@GSD+1u1FAF=Bkn z#4Dx4XyvBfZrvw0bOjpl0Q0Gjcomgo)|$VvpKjUJ1;hFZG%;k9(LjyH5=0-7KD{u& z1mzi0vs_LmvnzOzOh5O0-a*)tLUp+=BpW8v5yqJ2BtwZ7oLPdaMaQK1%xCl&I3 zFSiA-%f^%^bIBNOtQ5IA(1 z?U<$B&70Hr$YTB>B=ap5j`Tid%B2A5?jdyjDlPWCKax$K&X3E?SMFEv9*8YTeO0DH zZjErLLG3F^@Ax;F2cU(~i2}_JanE7ov-XvI@JvzxTLQa${laS)7m^Ko{}fX2ebctx zBoa{1cb4XhbrQgI)?1!c^=AhTHIU1IjH`Q`XsNPjnAt4DBRCtyzAPh38fn(WIsM|h z=g_GQUGD9dS@MmGJp2^}J^VHyC!hOj*Q{z8YE|@kf6j~& zOYvpoNyQx!9gLvSj94v@D24(6;RM&+_fQhHj_exge~uq5jt&pSUwL;{un%WRjf2qaMuh?%H+xeQ=(W4KfGnI)+f}kH+mu|@s7YGjC{&nXry7FXe7QP|L2$GRmX& z-!6hW=?+UUDU6Ep7k4`T*Q+eMiS%hC_Gn1`-D1-oh!wO4!=y>06)-P$6uhO#q|tIG z-Q_!|_t;ld(q5s0#)QKn2+-zh+KI;y#+xevPwn8~rDfL{ zsW|+L=(oY09f$Tv)}y&UT9Z#?QSI4TLMlvn(EOGR46}z+7-URfa*UvAr6f3xl|zfhDOKz>1EmpF@8ygg1wS8LlZ6L_ zrD$-*zk(K5(Yn%AJ!xo>)p53*$WMB86Hl#_cbt|5n1schd>%Duz4M3ePrlMHiP(`^ z`$V%rM1kEZ-Q|0n8YK^{jL1s5jn4B`$OAs-5b8yCYLEPHA|Bw%c|nEkfp#IL}(4+XiWm1!{F+`uWrF+5fCCdh{1)kXVrPOCTP0FDGqrD8f zIXaG*sIL5T`4e%oFH3%c{Jo;03L#W*qd0?%~Up>O;J^ zn4W1EoCMs$oeR?9-1~f*TiG^&%@xwjRPXuXWwXh1g^#xR7Ott5Ue5L(5=byN!I#~N zEu-Dzf_#6Zb`_0h7b30B%@aq=0Y;87d^MZ^D!*At6{}H#xz7)ySPmTzzF3cD0w;OO z!6cU|`p$8IC)p$2C;HC|pYg*4^-niiNYb?LiUZz=9n_6LA;A(^gi~&apY;g;eK~89v?)W5y{1XC zkA(Mu-`)rnxlRD5Vc&n@yle1~U4-{lx- zYPT-x{%)J(w(-)-M?*{>FJ8EHe9#EFOHTWV$$s= zC5+p<>9Gj~UVj!pl{HDsyGaftct?FMr7~=6*jVOpFR>eJEKG5*vH970J4x!?*LEP~ z4a;}@%pWi7d408cIKS*4T-iO*s+NAHh?r_7#6s|8;)#S}0T%_kZF9R}QKkHnP2}sN z{5Gl~b4YY55mHQ7gM%6Be2Z@D{Msj0#y_z~dzL1$83{Am>!tRU|FBqou=*aeZqUqg zvlr3sl+SzoN39#rCx#U|4}BjpTjQq(-c%pKJux8EOoWG-5Xea{D>LT-_Au~|gxro^ zm#1IO2X><4`RNPx~;P6lu? z;q27_@odvtSUfyLez|qCAv_b=`9BTR*E+(oR zSzcZG(*fDR_bh;%ah#H;%KTebC8QF@Ivlg7YsJG@BPZi}v))meZ1MvUh^n9b$G>FT zS8{pG+fqhhQrRjeUYx*L>hBgHmQZ&!dA1X)D|spEg`?58?0tSIz?AWpujM3-8{}SH zF#hZ$pIW53$CUW^*z`7DKeI>g_^ha5^vj#ARw}sv0hV%*mW%KCW?hNc+*kjOo0;vD zaG;0$bmcw)6yTC37eAu<-%FEYZpJA?D$(*(s2}nAr^09f-YpFZCMd9IeZgM(mWBnJ zOy4j?Qy7!-Y~;T>pP`Sz+i#BA>JDC*Y6qou1(46!ynOz}-`RZwMf>X)HhNCzPe*GY zS03;yPxmbv@c2>k>uTWv!Lb$-cm1+%GEwN_>_e#YzAcz|xFu{@gt#`ra63Mo7%9Cv z(s!>1z<@%EDy0Vrx5?j)&sWrEE5AgF>g&R&Oh&JuF)3_7%)t(qJ70MpSY~YS8)_%qZ{A8H2Ualf=dSC*v1nh}L(mmm(^+xl zVG0|a^Mdqi%n~17o!~=Q0~(7dh*fynTT=9A)Sbrqdby8uA4n2c7B6Ta!V`Y@t;Q`s zFWKs;7Q_k+QjGd3w>mr9s-jH+C@3&YC&_^=jD#54iB*%My=U~;PH@IadqiKX74rij zWec@7xw}%<>s`-BMFt~|+kbote3@za`Ls^+=l^g&GQW58&Y;r3(Z~h=zuZRy21xvG z0yA^1HoRjZ?JF2cZ$WQ?ooR~|T0~ni!vn3v|oI*>Da$ zo$hD+NASuD%{>3@vKFed*Fop=>pwD^o!urxq=*43S~U7JD1}2+^0>&dIFB433@oq9 zxrATvZ{_{1mOGMo=%T)_UdpiWMs8nC0Xq&$+CJSocZnqDmjff^+_G3$*d4PKBqKoE z&}K5WlQ(Rj0@~l-hb9=L%Hs_OH84OY^gpPB0Rq;c*LCZM1$2R==bd5tuq!J_uHqg9 zbSOX|2R{UQ$SA2j)VDCb8o2uS=dFog5Kqo;XoN|5%wUD=jzJ7H_Z47{G>{r@pT9b_ z(XT2U?^OFgbKphz(KBFU=40~=`U#omyTs5A^Indv0Xo$|hZGX$hTG7;b24#jDhWpO zq{A_8)6EQT>%>zdIjFdyaR+_SZ@(7mR9)zA^jJl}5V1_H5|nrTKwM7z3+{T>G$QE{ z*2?k>^L3q+Z(B{=Kc*{cr@cXOyFOTc;rLt%D)Qcf-a3ajS8{}*0@wDWmAJ`06_VGw z`5xt}Ono5@phDlP2f7G68Wg(hl;q1N);!UMpHU7QPB4PZ7C`Q&Fz3B@8v&`JXvRYN zksoLORdEFabW{8DfY*;eH+=_yr4 z<)n&T%0S7PSW~zEqcA}M+v`k|35JCbRkr2?y$7$4zsj?;xiY@Uhn+SuVj9n9a5VEl zCUncRe{bC<*8=HG*WV9lVWj>h4I6Wme$5IB3rnS_>M$}W7lHC0nr|&z;Z~N{ZT%Xy zt_gB(G&0|C(1>kWn|_|R2}tOJn6LDR3F!qO{Nn85`erLBsRhXK)?*350Fh%9(oK3#D`29mZ~^GmE-?C z8U(VPpFsDrX7krO02BpH5Ch2LpuD9?(QN^Swo!R$00FI#K&W({o#VHJe`@m%^A&!Z zoj5;+(Cd*2aKK{^n9!4d;H8$xVxWXzxnY;_So-BTv*)VrA812x0z_ z%awpaSZHAOgD=%QwE`u0rC^P33Ics!!HnPCf0$j}lC!74OFbh46rl=alxPDyW)=bb zj1kV4t7e*V91_+koQd8 zczs15oXJ}NITy_QIUGcvuQZ~O}OHi^~^V>>H*JTo&c7c_FBYN9v>h5{wBW$;h_4yq$-c@na@%L9&tiwavziPd6pDOv>++V*aetaKM8;h2hg{O zTEr@-{1sWSTy`IPC$Ho@TOB!jhQ77q^0(6H=UW{6Z(#37YuJJwn?=#mMKRT52_*GI zrv~6!tgloGn1pNyU?OSf&->W-9{eJk#JBDOlZJv@Eckv&b#-bA)c2Trz7AwkHV0sG zEL?;iDIo-Qqq@on+z6ce@+%D*=V^M+?g^nu{`9o6<7}Q0&a-)QU`!xV}v{TkaJEl80SR8HNDy8HEd)zAPjGRjkID>_q2d}bU|~qH!7k11;)ni`rI+JJy%mF`6@kUFy|vL^76}4MK85zhe7{g%S-NMx`rVafA3ax5{{`Otykh}dC0%xYAC{3$>v9~t;7F5|ofS*SVXU0+y z8du+}p@4_H;5oPP$ZJwyJd-QjFlRUb|FZxEer{UsE>%xw1YkvNAD8qk$Br#6{(9&X z&aQkdh>qdb;p;J{c*nX~SqB~V?_ZRv9etf><=U|UoKpjBl$<%cB!I>?~-fR-P; zY@J4Q4Zc%5`e2h!qySehj+=gbX)EJaG)c|X1zfvF3KAK&`hd3GpiLZd-KCtg&)y6$ zFecXYDA_wWBIDdW+VM<;alR9#xYId1I1P}{wuD-2a}Jk0RjW!(Jp5o$-#{#LXGtNr zD)v$AH1Yqx05>Y6aHX{9hD@tlLMOhxFnOMer%1Rj7+rEx>%W_r{A2Kro;iI{{RQ=+ z;ov7h&kDw2>H&-pPyn;x?s4}jSNS6(nY){e$BUjGK&WS#ZBP8Kz!DjE89Yx5`Q1I< zZ4e=Q?wt-HkIeT5H}o|7-xlvZp}?4dfNMeSHm{QrgqVF@F-p-vV3q(EP!4lM zF)Fd%+wFb%xf>(Q`2?hZK^6+cjr&OrUYm+_%Vowq{`t{_GA<7N`&Fw#>etO&AyC_pqQWL?J(Cf5z!%u<)^!gGWF?qLb_*L{?EB%h_MOjX1zh1%JIemS;_q74VBQACP!xsd%*4-N*a9mDMN`f@ zgelpVU(A_)0;3z(F96qj%m4*S*Z+Gly)4q1$CWsnJG_K`Mz7)^*W`YaXXUG!29jy3 z54zYC#s^KaZkOVI_Ue&0-Nq80DZ`^n8bXNI2-egZ|LZ&xGdu^Z&&_Y2=c3aJ=l>j7 zL3Q=)mvOeOc9^QP2(^x=x{te;aG|m|yT(vOFeB3Ok${XjAwTj|sc}{UHsn0b^t>3C z4G1^>8RTQv{DIf(Oj)!B>5$VB_oNA<`HW@Y99FDPc5?E#RKB2CK=!ayzyYp#5D9|ac{F1IcV z!eAK>$JN%r)eEF9-E_~dA}!WS(#*n5$3KKa?1sP$t9EF?ps;L@dKB`Tzn#U=i`pX) z=#fIKY^*==e`99saPF0G(qaaCYBT|8zZiZ9xz{`2w0?(jx^SpfpQ`QIc=k0axjH7M zyOb7v-`^ZA*VwHaJ`fe*eKyQ$H90k6o(g3Khya?DPnMFL_@I>Ou!0b{q-)7WG`;!A z^XM`5(brrpLO2nx6UiP6zRSH{vR2u90N_GRt%kuG@Vp zjLpx_m6u*InYD*O5V-pJIJdj%1I!wUztk=(dPA8u>+WTJwZVP}5fwxo;JrK+sA6n# z|B$%%u9v^2@GxD>Z26I&cuUt6YN~ls5NB^VFRf80wG(}72*`-Mg2;_fzHxD^&XNOp383a?m-Prwhhh{X4 zTJCZeH?Vd%l-^uO|HY=#R-oPf{ro~yP8ab7lSk7fH-d^L%zUFSeUl>SPYF(W;= zts5KcJ&SZzDU8W0oW%=)Be4#HN4kC0NKKcfY|ozrx`_M~<2dz;e`l^Vnn!P@C#Et0 z(NdismAjP-!^Iw)%y)RUmj6(7bZBTt+Qy{0-^3lt>?|pI@$mx+@d@Uo#E(|D$_TBN z4Vu+1vet2~>{IPzDX*^n6_s}V4GBv2PWwCDBqNonUKJY3w_itW&>G%}jws&>9e3L} z^2>6an==k&8ySDT(=xEx8>4ni)h<8?2!z*DxkN6^t-fmicUNCs?~v0M`^oR+?&_Ga z^x|hKV%(%#ZDZy@umtBxf<@jml!-lFmHLZSzG=}TrgFIU+vm+Ej>F>%b0IV0r?sOpNy z97vW6X|#4X7~5>|8Taej-pludBc=V;X_*=9lX=ssiDjV%TBS}EQy&V^<|tVHK+cT8Mt*) z3v=TAHTNy*Va-3geKUD6ASWPihG!9UUd&;=sCeB<8I{YUP4P<~^QJ<_{?<59h$-IN zD;xA%*qsj|xz2NcG%#RVtmWM+HSw8irgFack-M7VczWkF7Gj-QBz5mVVZ|{aXYkt9 zLD7l4ic4A6^=3%S>UZbh1KY#3a~3iEEjJ42Du73CMbz?gny^`bcHO+;APVT!hxyco z8J})`U#Ly%SZYr0eIN7O?*3_ea(JGiG5uCTd&iNQana`V`Dyu{X;HA>x9}8lWW4r*s z`DPHaeTtphCBj_t(UNWEW+S&vvdSb@mkVDkr&@km@{Aw@24C>m`#6NpTi;0P768HO z6io`jI?f7N6Ax>1J0IU5K^y5G(1WbOdCwc^AaUCIRwJ3n@sPzwe>b^t| zf|(P&9&D7==kC%1l5lUy%(CDpEgGvp?THXJ*^;`d;X&<}WBz`3m7bt`3!?j3d?ytb zr5_%*dHws`PuV8$i?x{j9&T~Wy#C$x*oTcOf`9K}&>9WpUH*q;U~c~(k^vjE0^w?F zLe|LBd$8KX1=gCVoob%mJk>tE1*scm8XCIJCTQJz62IGO5o`JY9Q29Ez&3D{=qaze zD1W*842=##g5I*N=0a=Hvxr+muRTaYk(5=BIymqwV+e6O}R zDRs(x2p)^H7ILrtxnsB0sQ4vhEAy6EutsS=<0X_JQSOpBfOK-Mh=P;gHl%fUSptj@ zIOYaXbF+DUqTY+qE{IJ_*!D&bZ>gjolQQ6!ve>$q!^I(yAE@Rq4Ng68__2c!@R{Y!KDr#v%wG}r?d zj#nId!6HM*p{$#5O`mX;-sSwgQ^v5Z$6d~L>LhjhlU(cC>Z`D*W23Ecey$?nTZMc{ z@HQGr`kT`#)&CQ5It3{5$3{V2k;LuQ^0SdM`F;;Y3FwSIXIMF8=^dy>-+4|5@$*hu zF85&P{o2dvZ+}Djs5p$+<0$(A_KtO6De0=Gln*OBVna>m{Xnam&RB%?NSlmOWr^!y zv^gx0^uTSc*EtjjItC_2WNlr0GhnTp)Z~?k!c+vvxJn{0GQjf7*NEf+UCo-@n{(u- zr{15(AH=2#W)1JC3=;S2zgL03jf1!w+3|0Anli}Ue|h|GIvIQ$`sR7MHH0Mh7eATl zLgF9NBlHxidr@k7E$2wS-g)(b23jqZW3U4!z{Ddyr|L#egSm* z3PGQFzOli~7sQof3caBBW(J5pTCah-MMyY12!d;4@>AN3*A#rVQm2}(PI1w^g=we!lIOvCdIMi_jYF1--0`T} zjR2$`znsK+uvXLPap)5sdy}pTA|SftH%+}J<#~FR-NA(ZoDc;bc`>$8QTFRNL2|Y( z;G%3v;R-9)I*nXfqXnZpdn#J5Ya-*~=m;rrimoV9`)e(wJ+>zG!4se3pr#(Vi8{@v zMLT(QRY#;JuXzBE?_WAnBcpyc2w^CHdDn8VaO~wf)@`azXs2_xxhdeuVTpN?+%@5Y z;R5{J4VJ5RwWm3*^&Kv!d|z*dn#*xCKn+OJ26%XfGWyV163JT4o#OR}tetZOjGF%r zw1jin$PN8>vdGm?P*&`&Qms1aDRS+J^UWtURz8m7lm?~-f%R#YhH?f~KFVx3h&@=_ zjw68Wb9h#z*$M6X>zb?A&R@Tlx^Dw*C)ain=gL?`8;!sp+WnS`9Mx^N?r2w<_SY1fHG^|fty}0`$NQv0m|5l^y9a0lI9O4NAt6UG` zDR`!xWmEWz?O2%AK0P->0ML`QV69+?eB9HwbCUvBP1ALf8)osvz=A5=3)9)#%Jf$f z6sTL1v}g=m??zc!mZdv0`yshO$#Wqh*%y+fdCv%}U${E96M$=OJ3Ff~a1-K%J@3rw zo!twJVa;;Yl$CwpOLZJwV>eGMNA!YIS%lGgb@=XB;mQnW zMIiSI^{@WTDQF6aid6z_n?gBcf0RDzsEi4d0VR}iQ{M@!e~5SfA=v6`Zobtn)^>KE zqf1TEsir;Riv@f-J1_6<*G`YbXR;jbfAmAa4rWbF-UjGB`$gtHxjt+#RkZp zuwf#?4{sHi2BoB|HDfjjW+jb$kA*|2+vBA}F9yDV4+D zMJrmOifrdAMG!RN7#-u7vm7zn6}m>qS&9e|rOp>^%=Xs1&oh!FS|+kC7^`cMn$2n6 zZ~8h*WChep6|r|iL>dLK=M^nPPzA=g(&g^z$m&aMz=%8Y!>`n+Gdn!$7OUc9Y<$bAh8l|QZv zDznGic&-f6lYtZVZ;q?KPDYiFZYwQ2@K7IGeu1zPjj{^pXUn>W5DvdIm)sYdEUMSIr}heEGEcJyG--QJ(h3HV)0^j`SaBhP#z z2JvlwQ%eBeAUtq`-~J51n_-<|S{^Q5;ZFeI^R5iFGnqRCMx%6-XiF9A*R*w@wG>bC z7O4+;7S?+0u5)$_f>Tg2$}}@`FRf4pc3UyyU8L=q=K@cLqY0(3 z1oQnxengQ!Br0HCx}e>8CfmxTqtS@%j07S6}e-0a?&{|X? z#s83)knSW+3$=?02sn>$yOy>@NTb)uqM)jkRuZp=yJ=jDu+>-rcic17k;C?C`&?ND7{ z$bOV^Q~uMV)YlHXE3U1xGMf9I4L-aZywKp>wR`nELZFjn7S*xDHN->meBMBWvn`;I~%rWJ;?qR^px zi`CK@6r@nYUlfxgqDA$t2~~0BSDz@Qx@mg8sw6C86Tp^G3+~*Yo^|d_pP|RH$;`@a zQ@{?g_AN=}W*na+PZhFwBAz~caJj5)a`^K}(U(&jZ$0VpSPr65c_cW3Zf5D^5^lh_ z0z_~MH0W_<5XO6`OSCm|bC5Q}>V5VsPe z*w^SOVA?DzWd-oUxdPTnx^ZL2Vg*lQ_;y=i(>4h77|K{&7 ziJXVg2-6pp(z_2agg;Hw+9Ljo0nx%AX`G?xTULvwm`O`M*6_?!QWZVDS3T48=iIJn z25C|S~Wr*vbd@eX3(P#05MB=~EBK_4*Z?YOF~mHk~o)sGk?<1VQ` z+{jn06FXPx6h>^)G89N!0gjz?g%pln&|dj&G1vmTYcFdUjIrthV?z` zd2Ow4*Hvn}?UzM9-Xke4rDt~Ne$At@G=&NIl83!Y3VxUUntGFSME|Yx^@;RAvdr5a zHQ$CB&qd`aSsR~Tf{{J^$|nt1x*O_Wk00mOiY(?|t0e;j`GT^g6U=r7Fdv%8XZ5C1 zLK2PazxeDS^IY6t+S!0ta0Fhnl^7q`d|>n5nkfW0R-{|BJG*qS6p5Ri&-8B$^oEWPh|zJ^T9 zLz^fWwqBP{jrKQhUmUS{G%!RBeoCU1VCpeC3kAMB17Q4e6HAF_{fQCw{xinrYy7nY z55FlDqwP)N{`O3UjB4>vWgvhKWv`<5a8$<|rAdouy?1Yy-*|H++#)DoeWT^XQ>DU* zbR`E{?E8OQ2Br^2+6~#_iRIT{VM(2iJ;q;rXIB64$^9QE~Ck$OUj#NtO#eek71HXw&;5;ip!&n$X|Xsv0JC&KL$uSkoWy*cA=?8VlzuCE8rQ^(RGE!7NbVV`>M^uFb6mNFpe!Ze$ z{SS`-IG_K+BOtp43_YN&V{mpjJtc)Kiub3Hr#Ytyr>Un=Q2RoVW#J!ls~DHij!yFa zpgGMCSAjX)>V$z4k1@inw4DXx{xW((!JIX^_8?L+IWM&MZE{sL)j;LLFb=&P?}C%# z4M`Es885w`2eU_}fkA%ESjGoGr#I^qJ71kDUk|oFpqIt8xIaX0(I3k(8PW|@aJ&jk z>U*vnpMfvS8rbsd?eDr2Sj<;#7Dx5hd{u*eB=p2+O_QRRiMyVyvgwE%d-($?jpu)Y9*LPPL&o=V1Q$_pY{ zN*IByAljr}R2=$m+aZ-ye``H{q!S{+H~z6%teGbpSl{5bE9#{EQd_0_Eo#9@MfgOy zeoueY!dxozhU%$zZ}<0A+9Q>e5EIFkm2xbtRESf35FzF$Bg5c$!0b4YoWqfri*ZU} z;?7)%!@ezfK*i~(`&Jw4-D;9>j+n`*y-|me$9UiV_c0bJQ+4I8(wxa@8Qn0MdhVl^ z+d{Ijx$^wm)rKy!K*r?8Se}FTayb)}Y5kI?d|N@G%7=5txg zC$m0B<{fQLWy_+llY)f>N+Oruth=k(U#~`?NW_`2eh+fsV^-7!H6l~!S<&ooXW*J zME5g;*rJd3cfB2HX%2C8OXl4)^bVKhg*7=Q6X$n0)zrN%1-=HzE>HE+qr){dDIq#O zI3Iz5AA0wL_qUszRJeIAwW3>0oS(WS9PFqyN}prF^=Ibd`MG;^MyBHJsRgx@~pfQR$vM+7Aod!APolFl;LU(ZX2J`R*wp;QSes}c^ z57LAA!aJ`gg34*025U`o#p>;6V{GI7oMwHTW(R7`zVC+yv{qjAEBIUjM_LvK11veC zG_+8#^}~PZ@2S2pQ^_)(P$)Pzhx4dlTYuoTeC3Wo6ehICSx=d8AatpfJmo*pcc}E&D z(+iFdjla5cG(@RMM53sHAljf-TBCSK%zh%|uLGUy z#ezM-rgPWMb&D*o0^DBY)Cm$O9(e$ar{4;|v`%zSA6B|t5Q-yR9++5IbyxP^Wk%X( z6yJH|tGGv}n8v|*G<#cQs6S@+M$sgbNvnCUY=>G}&xp@pLHv~T5a^>(Det;-$%NR6 zUa`m2Ln>E!?L{~vS4enhkl%#Q%H`DmXmmtq)EWi)0Z;DJ+z{_Z-cMu&6wDvO%f!g~ zySjKy<9Ho)`(5a4t*zP|JNvu|i5-Iuu6 zdKbU0%y(Y64G2@*kvLMzsIFPgm_xj5A^CAo871@4Xc!3sdRAp&kZgv)dwaGos!mnkK{z4T!5_(n9W^)rnO z7Lfy-Dp>QH-+j0gv;6v!YOtN>deg=!RQE>q6bq4YMPEHXy1A7(J7O_KtcSucx%BY z2p0TZKm-*GBeDz+Iczc4iK-kfG(zG05jEMfeZn?&Q<+g$XeTr%i7Rf=Lei-|S?Ro0 zUSuD&bMXVvybZTXG-rtCB*TtScmIE3>fVt&%^8*t`Q=!+Q`9popBESTNTSPmYn~mI zC!B@FxMeb2`red4^c^SmxqelZS%Q*>etrNwul&mUeO!pczu#Wu;OIzA83m|0%aD2p z%`BOuKZ1>Bg_JmB?!6wy#Qcz{%IEvxw5TJN`M7;aBm{7uXN@bABLo#zv%Ow<0M*@LE}kd%Imcp0Uv zbK!X9FnVBiF+e z`c-GWC8VJNq>#CfM3}CDYdtoG;zH zbclkZeRQ_Gdh)>k%+{G4Xi59taZI4`E%b&vnwnH4t`<`L+aCawVPSt>k7t%G|Y- zl0Ld@rP9`3Ut?%c@vweL^{-6IP`r=*T=&)U($=GL-#I=b#Vd4Bx7hl45d&a-PPudY zxbeFyA}0L-%3o{a@lIWbOk~a9{;6+N7Cn0%FEX}GphiqAF%_=VH8iyGQ}UtUo64SP zK|G6f=Djg4v#Vkm%TmmnS5&V}@#AckD5~GRlNo3iN=@@Fb3uzy>=2ebwvZJ2#pys0 zhkxDlT|Vd`B+DyC;tkX`lfn^wpTByIrVTsulFAK=cEi(vZPQ!5f0G@l#PvUYPS6Ra z@9pd(&li6CR^H5|{NdVb^-S06aSl?g+2>?v&MI_uY{)cApKrGVoUEy^DAJYcQ!AMC zW&64IyiQF^qd3;+=f`e2CPj&0Vs}2r5bti{eON40XB4k=(T2uVbi7T6>Rc!BHjUUS| z*Tw(#UES%HUB7VWi#gVxOJZSuwGnSHs+QPmI(iP%X3fG<6gz)pdy|-ke6CKr$1+@A z*}7DfIg@gtMf8YQ=|MBQbYc4rvIqJBY8+?P(z(3P-IQ)8HOZT@!)9Pb3G;U3#`!-j z4>O0~9P;1U8@*cbl9Pq!v3x8FvrfhZnBE0M5FzAw-<(v9TJ)=W+~j7Bh@QN(fdkGR z(MNjxm0GEsxsm1tT6ejCN6*S#aNoCmr2b%kapiW99G|0sj^?M?<)XdXj0&F1Rqt5_ z&|Yqb5=MH2e#CHApi-7mZts&EH4LHzTuf;0H|e{ALY_oYNPqsC9&=$nL^9bjGA`pGo`|AFMA z;#UAx8r#S~(2mehAWt{`s&NqjQWBB{3Za2ELS$|Jq}o;cMsXG^hcAbVCw%!>omv-- zTG;GgSN6371u!ur80IOsX%xv3t!OWs9C6F~wUH?PQ8NF+ro#QEy1Jy~`Z48-K@xI3 z6L>U2QQ#J%1aG9OtIh|2;Y-+KAa*$^Oycu!kN}&5j zH$qY^4L}$4EM-Pg*{lwUT|Bc|UzI?zYW^#R*%|hXdu=<^=YTwoQy_{Jqm+ZOmmL_T1aC8O`^U8XpRl z;-2Dnv3&lIA;NcsEY3 z?gq{?y+mRNp@V-Mr`_O;E2;NW7xzebMQ?9ipzV(}L*H5yn+W>#@W=Q4{>J>@73l$S z^nz$ha>$i6hc%vov0^*X?pZCh=uapzL#2ruEt)}TL~($ll*(@wkknA^{g{8#exCWq z3nG9g0d)NA)&G269y&;qOY&-%mKoktL-Hbihzq>Yh?o)3Jx@eSi-X~*`uzv<63?K* znI4XAG^BUz0ZeH)u#LB;9x<=y%x75GL`yje`>ih2`d<+{sL%PlCE0I_D~=kypLuL0@FtcIMDQofe?|^KIw++u`A5 z_IkEmZD}9rUs7K_5C1Ej@B_GEn^g&xS?-%_O;1KM(FTP1j~s(x8ru}$X1*MF9-Aql zkk`*sH}J+M8(k?mm0Hi_;I1pOzT7i)%64wGWNt|)Glk8#WKi`%Jc81ii9xE^ayV%4 zLEm)Yn|8PPhA^sacfTq%DWU>jAj`=X2Xhfa}Q4m!6ct_w)&D2J-qe3n54oRQl&NBxd3p*@Z%kfJGuK@gCG8>w%TE;$`ar7aD` znLaXlWplokh)et0bv~aLNsmkB`*kjI$3eIes`E)mKTG^Bc>@6~ft%^@vA!4xbzqY| zQV+ZtOh3BHe<51NiMNjTP`Ke?k&eQ}ped0?!uDSw{Kkz`oQX0zCujSh#|hEanHB>` z{@+%K+o__qC5glo^`I~1RyUs+D-iZKd4smmU%(J0!&%rJ_FzZ)SK0`h3{hY_0j^~d z;B$=SMVX@&$t>mzQ@wkDcjkV~>P=$cCII533w&ZjgWNKP^kJ)vYEv1GZ#Q{_fc-UI zUDk>;yPKmM^%H-mOa;}_<2Aw?9=`eggQGlsY3S8eJ2`>7tLs%xGF>2|ArKf)3KIF? ze(2|}Jg>=c+%`xXZ;>T7ktJJ8swbWnTV9&FQ$9lO);!kCG}I|>kF~KADn@f@GPLI9 z4`vO8cQIlSvaXuzt^yh_|J~|XK;Udfc|Rg$YmQ$M?~V^A5dstt^?x~gM1T2Dpc*Ed z-fdoO>_9-B)kvQsdb`t^~Qsr-*VuB5}1)UC65u%zW$0=Nma z^HF8#FNs$xXI|$oytzs3ryg?uq|5k%z4DhDN>~Sx5E~YE*}u{*XFm>j=u7RE3-_+h zSGJubAM8WDkiPW~J_Z819mta6PY#7k=*@xR>KC;!;F(2T%X(l2eg$UNjD@GrgIHR6XK!WH)`6Vq6)lj~UhYkbE9J%KF28l%IRP+h$i${(TrnwxznG5XPkaQw@mV*dwyzn^u13rQ8%T6->eNnD(Sg`tl6Wg{_oroBZ7un3|q$}uDX0u}*L zm|yB`5w)8OPrY@0hR*p$b!SeQC#&O!Hm#1Ib0WyH8x{RrRR88uVpsK^0jv6^^gURg+#$oi7VO5iT*^^8SEQ2aT=TRnJFt@A}gVRMeR#E6hREA5n&? ztt&wS0**HI;xxbBX-d|vJQ`l^Cla&nkkTs)N)|@A)evS*CgnY?R zV41H?*EEld*3zDkx4!r9Ac$*NpQ9pRmS1$R??!btxv8JXSl7$UNN0x|Q{6Aywx8J^F*3Vfad zE{~NuZy7EHg?i#hysGOiApUm_Ss4H_P!I1k4}t%am6^pJxrqQJ>}hjq?s7yp+aE=K z=6{vAZo+_0my0IyBbUwDq%c_x)yOwxIF=YA)^?T!Zmtnwhyjk0%4wDS;v@Zy&y*r{ zbO6&)YVP_l8-!V`J0~+3&Z?#5I{o<(4LiNeE8TxsF@E`(({fvN@qjmxA|ccMl-U9e z@KB>qEM-&U!7I6^xQ|rYlD^K`^WGgaXy~!r3XJS|-nmY`WV{% z5nd;20o$JgtwfJeQ~kQ|!D7o!)$k|rjTLLK6}lUSbq((GoW66Aq6R~&cgr0F78w`% zw5o2Y>z%oBYnz&EzeNVq#VO~MfKw!1n0O^ix0oZ&5Gm-l_%NU@c4_{`{D<$GB9bIV z!-Gy*2dt(781CFn3F%&4u~`DZL@#sa?Y=D? z&tc=Q>W@)=g3oZDl|SnWjc#r9NEl*F$YR=6{Zz2X9{Ros8k2&kiP_AUg({k2r|Ne}AYWU$S0#t-- z%s|Wpt&sp_mn{XFcbSQnA438#=AUQ^1IF~|My#yC(I2H~nmrnEt`~)=Q}m7=e+op| z)+b9b1hnA%%Z{HubFKW)$fvmnL$*E>;n!=PX09mE;K0Tf8nY*otFI99>lRBgACJVU zX7JOT8QKHG`^vbg94lNn?f)x)t3>!A&Uj$AKR`mkrCHXqlU}!1p+`L#EiZg0Oq6@s z=$^6Rq2>MkrLZot`4GRiv7|VYRV<3e;!j7u@^l0vHk$vgwG3~zwJ#;IxrxMmb3zQ=+C4aOi>uM|%bSe?2ai6R3K^YO-tY-;>2bA-f0HW}j zQA&q=Be@bw6C^a^ad*sIR~Wzi9-5SQ{qx%bh(Vs7C2j7m&C&jsT|3Mq?Q657JH5Rt*(X?k}vM(>*f+q#f;qpt|XDTmt zzHIG^{hymG$ei*YJ%)1&tb+$7?1>bPj~|2dSgjw~zCC%wu8~X*UK>uw!mw|KL*jrk zDfjtr3&0;J&fl!5T~54a`aKe0F17tL(k}NR^5}-$k>{7+*Gm(!#H$RlgyyG=1TA3C zTZFO@jZ5c0w>CCiv>lamaA4lfo4f?GLG?n5=_+csX~<$S2YT4X*qQw2%0wpa_8){_ z&t(7zmU(i3^(-OI<7Z~U+4Fm_v@5I3{JSLGj`RN&9MT+fFTs8@GR^_im?98;8FVGI zQj7Mtb?jA=BAr(C8Oe;%c{PKAt%}Q%?QqN z1Q-R(^y%St8`WC=X%n1+etQS9KdQZvDkXm2^Y#A%7~d92|d_^ zq^{MJZ-lJ+N>z0V^AyR2ONo`e^p$`hp@}8Ik7=J=h&ZxsO+$H3*83!x}36mXpC6R`JUg9~OTOB1_#^1_IY0feF^M7L& zrRJxnDF03O3cym-*u-a(^L5bk#OlDNe9Ra%$vXJb6hQC{?VVDnoOM>rfT=` zb(2}(;_3S+h+|)=GBy5&kSSl#m)lc&u1)C}Y8zkO^XbYHR0ReFBB4#eSj1UVrWgZs z|X&y<}n#_VX{m)9>t!AMSJ|%;#=1D5^HyV(g21*Ys!S!imm-%s}Y!)(_-O zv~>R4hP~&93#rOqHT_1ILjupvz)b!;R_80vpUP!j8@vAHub~&Gz*J{R#Zg|b-bFi9 zK*Q-v9aLd-^d>pLa01+_nZOe&4^9I9aOg52uuTJvjEUBtG$~b3sGi(>0eLpM)>_IV z0S`vlTDA+D5Oy|y$iVz`om^miYczIsi{m}_1th`7eo2!6&xW4 zD%Oyi43oy_S-d2i)2m}}z%;x#?{@s){qdFez6Ms0=VVNQa zp*?*cqUR4&#J6RM6cXB}nvEYn0t8U}3qD9@u2K#1e6}>tQ++2yq+(@{eh?XYk84Rd zxJ%g@g|FIPZzj5D-A1mf2Q)ouT*xq89-*G*jmDHd?Vd}Q`p8n7LozRl785+N>u$aJ8Psfrzh z0-n95bdR)soU~o>^rbRU`lpMR=(Ox{b5o}-y5}A%{e1=dB#1mSH)gSRAON_~rA^(t z;E$CI%#MC7{r!Qr8@%Jq$<4Tc*zQ>q^SP{l24llo_b;cM4fo#sMqJF9uy07vX*LokHV$%(!i>8~)bk~5x$lt>6!yJ` zlBDf6W_BiSf7ZD$A7aLz-)Rz+X>niYs8b@xOWSBw^0uDaO8Hw_^KEo1&s(9mVTQBq z%kMu8&o~+!%86GyhTlF7-J&Pa@^|Xw+AUogk$vz^gxiHH436a4k}hvdvlGM|{~RtS z#sBH&Im=7GI(oxZ;jtWON{KPa5F=;Lg{L++?Aa(hY-x4EQH4h0jr~JkYDoIUzW$|~ z+9zMF|Kz<4EpV(0@$!%}E%$%4tNdiaeK}s$l;0~#-@?qbSCfV`p!w8DAnbGG=gUrp zOG)3<4iW^;c^tC6@Kk6VT$GSnd3bOG;Udo>YGd)zg#6^qm%4c8L2UjgS;N9?*cDDDmDM$|gkTjKTyP?;$L_yiRtA~@5B|~$d-EEW}sxU^{iV*v1K*93NIk0r?D;d{osSEiT zgZkuFK0JD}$AAqy@ZcI2`-3lxeeHeeW2xw#Tb3W0xBp{VVp)s<0Vu(YNumf?$h-{9 z3f~bkS47*CfD~OHA?%$AK8xl!aPFxWZ+27}i7FB$N|pVEF^%!QlEl@^eTiulOw?Q$ zy(U-NTqO&kmSGfE;d@#X=tJ1BF!yX=)GR38M+;FgtLpL?Tz-AoVM`0pknT8ijb#bk z)!vodkeS(HxG()m(;&a8Ed=r+^h2*Hy|`s~|Kjm~i7Oa)C`nxO1&6Pc_smn}Er+tY z2+&XL9FBAD5FljJLNSg#eG!gtp;v*I7BHcfNER z(YQX)#7<9MyHwKjcDt&#{Fi;@YSgTOm6PqeKGr;*M&`FhCW4&IvE1Bl8a920VHN#F zv)5HswX6ijoX;1c$_9f@LDDr6x%>kecp(0xUwuJ@r4FX;dNG-kN zjvTd6s#|zFukP>W&NnS7c@al}GN(8Xm^x*(N=bE4IqmYJ-fU&1glpl=qH)~iKAu#! znllMrJMw=IDEK{7U))ANLL4C*oJ3Tj4Ct=3%GgO;?Te`EKBIhg_5IHON7PpUMb-U( zpWUUqq$Cw2M7nbYRFG6cI;0!vW(ffm2|)pARHVCe0Rd?Q=~^YFOFG``^ZU=dJHsr@ z!gBZA6W{p6QV7#VW;_%1{h-vN;MyI(_4j4BAb-m#Phaf&4YjPOwD^)>7peWtUOX>>ljZz? z@1orhfauoC=DEZQ4dth$h`@%%uPW>28PGS+g>x$k!lW~9rp3c9D2MncB7{OF_G1bW~bd0$3ifaQ-LuL@JJeQ?Jd}_+nD&21s9da9{)Bc&sZ^ z{7pbb{a37`A@A9&?4Y#yuYt;#PnhuKjOFVkDW?=AHv3Re99`~SjPrIDc6NdvSALh4 z*T3Xy>asU4;N=ol^`BPYPBo2w?QoQtTEY-rd@3=>D5OFpj6wSo@ z;rBk=^2hW0IA!zlOKzERV|CpR*F#HNg_^9X(hF{nA7a`A(2#&s|3wlrO(SWf29rp2 zm(AdW*xk~YM8D{@?4`x+3FPL4P2IjelpaB#gFON(ezCVqh21BmY;Z|b**b;j$Nr&} zy-bx9HJTJQ7UCcifw{356Fz;WmK!vMcjXT2_6zfG%SbyOmzpxO8w#I&JbaozdrVE< z-*(wun&~o$QZW-~S#ey%e|n9cnc2IS0F_qAkM zr*YHyj9B_4V(qDiz27gQWXYHxons5eQ9o{$KfT-bF!?tL8Du8~@7Kyy6BuudB{&Eu z>{v6?FXrnCG~FuEzw7Jrh3RiAjrS+6c~UmZwQvq>b8y0j4nNr|=` zrMC)8N~BHx>|l^KZS-@nHE`M(44X2-mmNO)u^*FW-8$>-^lr9v>+bpT{QO^ySGZjx zzc90;VwHu@HSEp}Y4?fj+@iu@p(vnMJyIHpP_Dn_TKuP0wzdnfXG#psy2u@T2C5XP@Y zJuIRhbV7yu0j3LhQ1C2{^DW=`zzQ!7_1LtuLbb4|3sfjh-m4n%4I?-jz-hrPOA?m8 zZD0SHU}-ttNbhK82^AKFibUmu(1?ra>&xY`DOm>J>-IS_Wr$VtrW5=ah&=u zGU0D^Hiw?(yR-!_D>f)jRpc{!`-i^1*eE`ms_DtICeCg#v8}l+tSEQD``oP5ct|0s zIhJqcxN)`dSWaa8;GAK;SriG8W4dLVn!%CPDPJ1)f3-0v@gtLPj$XCKMQS8Rrgwh0 z!%3xeTM;sndgs%#b%wJRW104Q*DoyD|qjoWDU=uWPslK$|0@B5`k*Qxo_RBWDbw1(-msqr5Um&;CJ#CKZB z;rfN1XHtZr;?;|g?3=YF3}k8VJJ2wEt#347@(D#>&>*4ogbmPXB86#*V|B)><1}SruomQmhc~T z3+jwUF-%OvcH$tDa&%a!R^g!!F`-b2Qb|<0^5XK=464`#%2r_WWT!bo32DB05r3DLo)FUwso%&LwUH>HGn zW?RH!4Zbn|Ft_F2%J#hTvwfxdgCxsU*7WspldW2B>pBrJuzfngy$rQV4qFcV%pm}} zVtgR6^J9_vOmltM&q!t;8|e~uU(>c8 z80hdajT2@57amF@|H4{lJF|f;04%p9lgf`I5_G88s9cTjt?k*fDnsD0vIO%^XJ#G* zCWKS7@vg)Cv76oAmyZkLC_ga6O-%L6XH1_t!=_bQdbw&YY+{(v2wOi6@H6p%=<+=; z2zL|>OU2DKhPpakpwBwV1fT=XoFKYt7u%+v^VuVHb;_R`UDgHj3Pp$m@8n3`O^Nnk z5xZnA+^p3~Hp->z8h7X_uYVX*p9;0gO}w*<}bJ)DH%HVEa*ASfHtROELV9 zHuQQ{waiSNHTCF`2eB6J_Pp-WL4<>D_4sq?zOcPdvGC1grYvpIySc9!*7Tvj2PeWX zB;dsCyV`vFQSeO1)TVOR&PibXqf@P@$wBekE=T)63IqKDt$DN?#IC_oEokU1z+D_l|RNpFVSlf^7%mKFA`Z=*8ops-~9wl)W0}MPa zB(SYuspIU?Bg*M;ZhoAs_LH=~7g8?c_3G<&iFF-5$7T5)ZNOG@ab;^ju{gdAKI=M5y|Ofl^cb~<_1<_l=!n)8g+6u@)cQcsmN}Ob6j~L0 z3W1}ZquTaurg!JW{-YVz;qES`LRFaM*syRg|ADRjD0<`5E{}*KOUDz}sFx7CjiRzT ze5r~&=r~IjA#${qjXb~tK37Y#QP8IM-=wY-b>%U+x|)E1bHitTf=VMpLIlXj^e)oG zI8D{|a;kO@ZsP)$7E?ZFRz=S`l%$;8^i$^Q@c& z;61qe(8doN@AZ%+YF{Y*M8PRwQtnd6nq-~~$h?~xvq>TOc()oWTo%1!fQZ$d1&&BSum)?*fVQ7(Cwp0^V64Jz^;suaLq{VIdv9KNxy?YkTa$N=FyAfyl?ffwWDGv(&{li?4Ori$}3#!4Rnq zx@=Hku{wr8C3Q}WaAWk+E{B4dt-%}cyty3F=V_`^=}3Y7w!B#^Y@sIJfCWb z*YQHtrru^YVq za732fmMbdu_G&p!qX)ODulkb!;c8xPM630H;b6bt!H;5JADGV{iQjhQ=m{?=j3qup zoc=wOTXz`V$Wt-IaA*3t(-VLs_T37J*+5e4Xlmadt%^etEjLJY-(!-x?(GQE&Jd%T zj1H+DiVj4hVqO-RBv(Y(J@Io)?g)#F0h)sK!#uBg?^YmJ_Xf7R)H}m2i35i!wXo(9 zm|p>UB)hb(fC%#)W^pVlVl0;7Rjj+h53vKGTWfddEaxxuP6a03hg-bzFX{n7HEe>O z3q|B;~`CTR(r}H(!gIYDf*f1F?F4>=6BHpZ+7%LR}HC z^>ma3;Zd!l!#PbhuLQl9*AAfRZi#SeF&$_$xZSGE zH9{=@J64&o^EWaPtxPPic}8)@iLoX}QR>-C(2VA0}4usXV%e+jSQ8GX+|}wi#2`W{D|j3l2I4g#rjGg-zyghp9RQ71MGgWG^+UUIly*D{ zeUL9{Azd4f)WxwPvDxN<xtxlWYHGB#I)eK81< z2h|X$;u%KEW|~zQ42)Fi^oJekE}yj^3yl4k;p!FJQiVH4wLw@rl!8B?LG(v+;V1iw zK|G;lqg-hilwvHHh}gesH)5)&E_nvKY+xafFJ(xMpwBvE5?l_ONRk@<@&-Sc1)MVPykB&yUcYcFl!1m$In9kKHF&T=CRcNV#a z+wrbB_;M_pRvF&T#>t)+&O-_WGG8sBN!?vZ4@#t)dVFtU^nB{f5g|ghA`cC2y7E-& zV5je8EB59>BMd%DGhU|Qw?4PmaKuudDtdE5uAxR*DmfElh(1vWM6Et9Afj_Kec!jT z`)AM}g8xY0&(XGG{*0Xo@jGlM>tiH#TZ*si%hQDkKC=32b1s$zpPo)>=TGz0GxO$W zeDZvCQg-o*Ii=8i^9?0M0-?#dcSOWP?b;$q=*TmVskMCHWhe>gRE*$(L(9LvT(YzTBJ)hJ^dMs6E^`3 ziVBvXU|t;?CE(J-BPLYXU9rV8;)EdkK-Z}m(GD>SyJ9|-pMxz3CPS#o<#Hr6hO#o*0_EP`l1ikvD0%DLeq!As<@@V^df z-LtlU*Y}iazv}p0?Y$>XHf3}@teeu8OUyBd>*w2njSGtc^i-?wL2h@p9~IDKQDtM2 zV$_QL{6v=&ur}3}dBcHdZ5nbu~_~itLx31->xPKnc+(kpN@+@a^(;4#z!$_(o_5g{Jw_5?L$*U zcl(2Ma!67=?k|sz4aM3Wg9578`A=@o3Xnmo1n=3D4(k+o*#!c{SJoqGp+mUd>X5f?e{nsYFi= zj4*~l97m$QLmrMaBQkswe|krM);r$USa}Xg6F#4t-`I>b^4!}! zupeCfcfyu2*@bEJ{(P~wi~zHaV4ENYQ6_ici`&Y_hk0L=v#go~;$Jmd{DTRgI)>`y znSb(ljf;y5GlzLQ1aC#3L!j8B1!6R9*Vj0iFKL4^ORg<}LX2dn(6ldCHj`iJnf`vE zl;=I&d~i0|kNq7RrGD^sG}OtGwzgdHHjnr#E7O<%QsrIV^S;(I4&HIAS5}6L6=6jl z#3e2M3{tOr%?WRc1D93_yO zl~3=?f!@_zR|hfOLBEgRa*~NuaXL=w1wBwe3TF+v?G3u{k}|`(;UpcOYDrvZeEunR z4XX+6+i-cwou+AcXezP(E|uJzi;uaFHgEX3cR82I>#E0s#}D|eW4Q;-K59Ch$sG7r3DGgrxu`VCgQ9=%jfNS%4a{iz>7`HCgwaDorQdLBLR&{$nS0lrA>v{Lox$T(;clW6;}k z?wW+V4MT-SD^1tZOJbtVjO9zW|}^VJWBZX~kXxZ5{b1*qha(39PofXV z5MI6~kwIGD%xO?e`EB>KjDU<2O4u8bQ|lfh!ZBH`}c+!RA**0488o>FV!% zM3|SZbC4wRP~x8L&(XZNnGk1s0BV$!dzzj?0ld%oudO(9XchFjY2ATxpsTKL7Z;AJ zpJOx3BNk>JSPQ;!3DzDO+7NtQBEC#_wRiW_epASiHhaJO6EWER$6(Qm9eRVcyS{tY zzqhhcI|RezV!L+S0xNvhQ6tkxo&+7`UpT*@-vhsgWYc@EV!Gc`;9`D*%SbrbC42_N zVwdr;6CIW=f*iTvNF2e0zX{_nU~ao`%{&PYa_~Sg3lFQt*v5Y^_SN14Ap*@PDkfns zn^N_slyhP(%_BPn)1AcP?$mwG4#p%E@ZYNPK~?<+gQKe!R8+b+kEeEB0$A*t%-eWq)w3IclMg9!}v<8ZBg^|YpzPlR#Hty%Ng5~WO;rAi6 zjr!-Kw?{25hS|x#7>@}1HCtE1aTKAH_5X&s6`Ij?H`ZqYrAbESGE2+X$ce;f3L( z;Uf*1@FfI{-~^WM`3~_5M{Xs*di2X|h6)GOC)5FLm@toGI1+ahkgD{LPyHH0K;p+3cf4j1w0nUq;#`{qr9#q$ucAz^SP-Adm-Hvs7Y6tKC1q~=iSP9wu<;O^dl1{ zND$r=m&{KI>ZB*xnO|QuaYD!NJ@;!?f|mWqkW7+wiWnD0L}k8`U%sdRx9U>u(-|G^ zwBUjCX&r9|qrj17QhM8LYQ-l6DdP-JP!C(*2Q7TxhWxtT5s@X%Eo*RT+j%cdhAQ%Z zgqbaFdybAYHyBkBL~YBx0gQu1#!x7NL3m$u66Xcb-2haAU#);!AjkPij_@4p<^3KD5GwnZb4ao8i%(lNYql089 zwIKgcRp?9RS`M<;kiE`$Zg)L>&9q9@b}?V2%%kof>6aS(p#tZuCciIw<~=9dQP<1P zK%-k`n`foZA2Em=gmc7_{wL8|^a$1XqGbl10`g(DrmZN~TeLZ~FWEG2<3NLhoLCtBh&L?Mf z5=w$?8)sRnuRl*@`0jFuKA{Tl)y(_tZeKOk@H>Q}BTtn|=e9)gmxCj@YN7kb9qg?6 z&ucJemcftmxlFGCQ z^=|vqJbQ=k$6ac?vV3&oBh+S&4StDrz{Xi0tvC4@^;GiipXxrtjpoSXDq9X^7&;ja zg&%Euj=GB+?!6Xb~L#w>8K?G0 zEdrLTaFjegmx%p9k9z3~ElVt_;LUPJQ$7Tx)8RIjmM9k@sS8}mQAhi3}0n@z~0hcIH#bHix@cD$bZ zkE8&&593EPKd;y9j1zd!q0k0=7-)SRlK3KwI`lv7vX-hnV;V#iI&j zR>$v*UjhdVMP5bW!z64e5>Gl3H``6hG3Knr&~zu_L1FjhBN_syqa*AD#0lnWEXS|r z4dMkRm!FRcDAI1q39^I|iZ8dVq6?<)tZLDX@t zh)~|U7ykU;YK9(lD6Gx9n5%SVNNKYf*Njv1DZT2#-9+hzJJ>+pHIlJlW@BNn(hr1k zg1CVvT8r=43*2^}wsR!3u|LMCH7I%7@iy-%gA=4cWLg?}@z$?~Njf_2$Euyjrf#3? zj-cs&J1dUlcXbtHoW|=%F}rf7E+!lrH&9}N3CR0zG+~_F$*(!gWytRryHmXnzVOf_ z!FiK6Dvzx4Dsv}d#UdHuRyg^+tyVZ!BzYKv)q==D*_XCwO%vHE`Ox_ar6yg!lM)7hD_B@Qb0C?AW8if`7Z3<^C=gXZ zMbPp>@R7-FLb+I8B+kg{m9x4IFD_uY3$nkjYBT-pMf8`&@} zk0c!FXiw{V(56C+3R%s~{_|C$>^lphg`~F9X6QR*%0-3Hf$m zdwOE+7ZZ&w4go)^du7?WJ62xm?v2L@6#BGqeNu)E==4=0Ah2Ti22cp#8lTbtIFHT@ zsyW|Sf{YL0>n)~5ox5ss%y;+_d%oDlXyIXgBuCtz?WXa62Q^$ZAMkBa2(j2byn$B8 zjcueDDl)lhDVEwKNugjjbO`iKs`kb{t=H4Jua1M7jDVR9OJOuAd-+QqG@Eszuu^#d zDvH`zG9A)&v*6_JX>o$-k;btMCYfOe+Ki{wI2iqu4_aY6xuN!_FVb9O1I z^o}GD^j;D6 z=JGRTUfh$p<%sJThC=ZjC_f83oW#oJ{Eq4L`#TX6l1K!?+pn|J$tbOypqBNmMFcX} zlF^C%nf2|HwOpH<>Re_i$lGQ|&~{jgEuWJyBSpU?9TTZWEndN(lb zy+5o^5tx^tT{~Ig5&0CVVXTiHbl-P^gg@G1t!7L*RojAosKAk|KP3^Mw;iCyADe+L z81nX;S_TYdUK1>B5lcJL+Q4*UjENRTi)RJ{6aY9^K#o2*kSh(ib?ZY9W50Px8wsSj zz_#x{H2BTqoY4PUe;MAwOGSj1=s{LpM`n7837WB(2P(Gz7tW+*wU@`hTrFIU0`9^v zInFG^2E>pPw2=IN`!x3?GTN z>59Fsud4vZ%bAV5^(<0C(4MiH5(|&E@E*0z#q{(?IIZGbi~X%sOS$%!)MYVY@|a7e zFcKd^xKO$e6JZ>Vg`vwUSz5?3y^69`1n(rZaiw(3+7u8?fdTlE=Ml*F<>T7 zec@{p&pwylcFl$5!@^CgaXvU$tFSLY%8&mZG4t17_V-)$lU(*XQ+6f~-RdM1ldrxO^O14Vg$yb*YcU6X&3R4qSi$9W!fA02!azcD?DD*ujs#b0b)fKr3Ys&fz3h{nYY>( zR1w)~b|-&>?-5KHE1oE8(f|Kg1)rPY4_q{@lwN!kZnt}jVq7&b|6{?-_s|pUBnx26z#~)2 z{d>7&BO3PREPhfZh$;u2@zkAJ?nQA-(u{809VUY! zr~Y0w#N4eYMBT^dcyC+!?@%WHnu{jd@#?Z%%HlbiUPjx}BTuL(bkW8lI)KJIJy6>1%XJXrK5W#S3<~0KmnpThLP2Zdf z5}zzn7MDO)?uHqy8FAKCV37Q^Dl3)d=MQXXaC~$9N5btF9;45;+gl&u%%(7M?wCw5jPI zT74$V^G00Mv2As4hBeYag2ANzK#mkF-4IZBT#In%RJx@lXTCu8#l2JM4!7s#P+PvC zse)iyvJg<&@K~&NITsnbda$AL?D6hxi-CE=VA~H;5PsiLXgT8Hb%0?_n(_6bZrr6^ zZM9oeoE*K`0{w^B%PpShD!;3PD9%zc@X>2&bAL`)p$cEbVl1LrYC^m6tjXxXTKX+V zO6RVU|0WtUK-KA;cU~_`Ar4RG!O3NkKn$hBy2TVOY7KyL@$Hq)H+?ZA9$Zb@o<^VO zY+B}%gg<46B^}!Th5)d`Emb-d@bML^=?A&-Q!JpeqOS z2;PeT!$9^YKw3k%c{7^+&@+3*z^Ph-_wvq5>kMiSu_zi#ADPA-(j6DCXp=tNS!u_{ z_`RXQNn3+Cfje~@G54w}KF!7OiLy%gy^N6Id~{Dnc_+WLCFrc_+{SOm9*W6E^$&4E zXiaFXI83$PNt1OqOKNCTr>4yt$9X&Zta;`;#Mn7p&3L02s!RL>(k1WYK1@HiPQ%7m zg)PL|nN6Y|Fd+QOi@ceV7!hUyW;~8n-#6ZtoN0A*FIIY6{t+UdfjzsD#k1(GAWgR& z;bt0f43_jbA2>PAT!}tzy5KwJZTn5rxC8sJ2m_|7mwF%-=#}sQBJ9ScqM_E*iIdJ* zqk9Obs4-0U`DAYGHW><#`C25?U|rmDo4V8>?YQ_TZ^?Zt1dD|btiQJ6N}W?#J>I`m zC`){L5c(L}4&8w}q5{3XyKERK2K{J~t9Vm2-ZSOLT+VB{vE<`Co*93y5(n?+%Ra9Y z-v_i{TQ=^lP1QntqW|vk)`^odYHIAbwKfp@pMM{UfbP<-Q6v;*sUr0oKaZfZHtV6S zGKMyU1;WCFq*4AJ6@RqK#8)o`h>nsFU{?wU?ZpV!{5jQONb7PF(zFXg)&{9aRo}%y zRkn28R}nMjU3o+1u$~t#+Hc5E^VZMgI6#)eU2EjhVuMZM{*KP^u-=vopJ6cH%%5-X zlk{Ae+?pyPLxSe5Cj$5-H?@ls?y>p(VHLY775Js7vEyj@?P^f53}!ZI`_A-}8lM6_ zGGwsZ2Ckee&CrqmWV7!7Xc@Zyzj^`Th=AQ!tNXO?ue~9i2Z#S$HB2FwP({ckR1qp< zY#57{W9Pjq4&BXv?ziyDHK!+tPKiPZinL!>Ct6AmjM3i_Z!s&i_>A@!ggnPAk@0w+`d;0iR$6jOyHn6Pst}l!l3M^?5ac>K$#WVe0Jh* z3k$%~1M}^Dw&hT|2{88|aYBicU8$YlT53?l3WMa!OZ0ZBp)vpjsQVn&JmbX~O)iWh zBs#pHwujDeR8xO(*YD4>r_zL5r=49nna8cIDe86f>`b_a@l1qs4?sJJYQztfB#^JAMSDo*^H}rBnI$U`|c}K-ZxJ~B&77n5MwFE0gEA$1962v^&Jn?e(B4{H#_yjUp+pz^w{E<@OR?K ziMOKTC0Mp1xS|bAC|cp@13YFp;Ii!(rQV?#<(SL0MuLCoXTRV(W3j(h`7xDt8(qqb^8!_%LJ zt>2t*`{I;MzJx00&`1KYG*Z_+OKjA{%EEhHgee^0VQ)RAoO9HXmlp`pY{&kW&t>jX zUXp;xWr#_dl!?p9j+mNZsL7^!7;Z#`UIg+#9}&WKo8-C}K6ZPC4nZ{wFI*JvclnG> z=3#Db7)^nJQBsP*ddWoNRqE|X(l3GI*_lNC2anX`bl?1PW3r8tUZUt^EN-cK_%Y_r zy!RA|qRRUORt}?rgs!s{rt6O+>NwCfBnKE84##!ClX31ax~^x;adTxk_WK&*?B~rP z@Or$f86bmgj7Av!n;R^4NGgDtlE^l$c(zfR`}i~(DFLCbw664dZrh4N0_bI4t+BOx@({W&5vy)o{@i7H@r)Wsll8Q z2S{f^YSqw6OI*AGJ>H@%!LxT zb}_@h)5X2WXzDcy;3NTlXk*CL7Zfa1x_{y@_H_M7@BCtn#}dtsTw2TG-xjNO4K80F zKzQ!+NN+weuzLDr@gyOFaka!w&@y&>5zkH4TqI?*j1Q8o9rOj9R60J#JrV3qA%Qe+R9Mzz|Gnqv1sLR}>A3>HIgWp;qVNRG6^08SNvoSQwA{ z8=1;#*2XUnHurKQ?{xge5g_7GCGHCqFoT()zW9a+_1-`LEzknZyU%~yprL^tw%E{? zZHXAoIIgZTtNJ}ymH2jHJ?D;))0E@fioW%U%$CX&wJ%lLKNZpc4qifT27l(8=;gw@ zB^0|40I+c-e`Q_sl0a&O0t%i0Cg^s*3Nd49p{dwon$zA=R|=q&afJgs7A~og?3`;k zOi4(mB^O*boX~9Ig99Z^AzPe)57A?UfSU=0QJ-=Yj$jCCue71_v5fD||ILcXDtoj= zOg>_m)PbohX+Y_oh^wx%k>vF3LDL+_Fi^dT8PnF0r7a?<`C zhX~re=pcY7mwEkh(P@8yQ{6XsS|9S?@<#t-XoID62od+K{tv@od9Hb6UP4Hs{ay#- zPux)%(=B=;u6C3Cr)DZH5SaWw%pnQp_elmHs_A0l?gg|}%ftCgu!OhNvpRHjvL`8G zl%Z1=5=?B*sl^BV6HMUq*iI8-cb;Ydv{-5=xj=1wnOy{=brtHj+v4Vx>NL>!W^Xq3 zp)*e9J^;mR>-WcOrJgeLtj6g*+^oOM+zil3JMDYd%Ck{A6)3^SQlU*=cr@f~RqQn6>mo%R2A zi=zhsbtzt+DF;&;!I+zi-$V_QF_NPS$}H|fSP%df&c(K2urMD-Y;Xd3vj8T|hRr&r ztQPJ>BTZz^dF)NkZzIp?tUpD^KcPbPb4oh(S{DD2!5n<7C-G_|duN)qx6zs*ay~~& zz2nH5^y;%{jf;!=sC3YPzRTT3spnR2j6~zJ$7t+$>vy-?^pdoCpN7JB_x%^%QA_d5 zZ$(@MN&^qR3@G|qo06XYR0XZkyw;+j5P}eDl0dD}18jM5jOIXM4un#9AwnF7CemTR z1BR*y?POx0k9pk>-d|$9nZvX_ey9ET3&FaVz%ra15*0aQ0gTITa`Dk2lAk!E%RMJk z`|!a9Ts*%UUkBR9dII`Gf>qrtQC z!QY8=SF9QD?q$BvNSS*kYFL|UBVoSK$*Jtr56xid1(Jo+w=NudkYjvIbL$)!v~T@2 z#6w1K6(+oe>tUPAO=Wmr6AryIYNhox2@q-85Wj(>%ff3gB}K9F0+vYIf<-HTyXIqk zndB$0aRK+ll@rc-)8DC?=kgUGE51tDw`IfrR{F#-6KRV7a;^=D(beC^fnPITlJ&lS zfZR*3{^_@&UKSUNGs-qel6*a>UzqTup46<^@l5&V|5{{a%>H=5 zptX6BxqI{N4H!NvEb5iPT8UO<0sp_711?qXN`xn<)?RwH_6(gepkcbC5GwBE;t7f- z6Bl^BA5xXrCjW{Z>W2+jHvUE?{I2rnNUbALe<-V1pORe)og9M zZoLd+j|m0YrSW!hJ(Q(%__IL7!-#1#CUcG`4+g1e} z{kdj1Q&?!cqAm0B_5(EFRb%B6nRa|L_x1F3wG^WBAxl{pwr`nZ$d+^VShHA562eZ* zg%&UC1=BmxqGv>@64@EYp1KoFs-AC^h&thTca-DOPXVcPqTojW1--OoJa1S%T&%?J zc39-@_z{7UM2ER_kC;+%M^Iw%-GR#Ha=^2@}xYO?B)(9)NTFWVYLS# z*Dl13ins7#IS8Pbqfn)N@K?7D-;f@d+fL>0`%}+;EdIgyo$5n_ z05$!G3m4wn9tR&QabQJD9l!A7wy6lGqRg7VTh_U47leZ=pboZYj`Mkq)_jKd=H3VM z#uj%ZOcQ92lmkwyv}z25K|(r?|49muM#GaMRJF-)IaLit!MCt|%Z+up6oI+hoCHv# z=HiC5D}R=3;inSaQC3@GB7R`DJ3V>lHd5hZ)%{NSSO>O++r;^-r0;aTwK!HNfsSn^ zAdUen5l)UktEDD-s>a2_Gi+QvkNAC}Q@o9e0RM!?o!iNKe=a2l^a!P=@jcpLXl7`X z%$PP9P+n>eg1&h%xH2F&HHZ~URDO(T|JRsBAzWGt5YfzbBVrjdZJRnlSwHoY(R=4dF=9Kt5^JudOi&A#U?Tw+m1Et?~t1PsU}Z z#zWT_@y2dyhNR%GJ~?ReeSCu=bhhuk*PIU42!+x}q2y zoLEt+H+QjOBcV}yYMo;rj&;xw5496@;tX%sDjm(QYjVa^V<-7S z@(q&_J7v!IfZyiRB|)oubr-%&$o6$B z1yeq)GXm^$|7%+0MU{;zms8(QwTa{Jg^xr&hFriWy&BqKE zmELk!sqPHv^g;_MpEX|h%n^D7C(HU@j(OX?ni!cR$Nyu*QM&Oo{hZcs7}w0};U!~P zk>>I7Oumw8*R-JfkSd~s>YL_vNkPF=Dl!Wk3NsoU@3=oP6B7xW{(`i#V7Pxx5YGSZ z=X=fnt5QTf{I`Ps!&ului^$GOc6H@v{)U8UaVG6Xk}5o^k3G|N<|uwVDrM)#+D%OYd)EVJ}+$Zaq7g4?B6xjEN+z$9rHBvn6M< z>(KQhl1N|I@i`AR&mZaOr@q+eNb8}bfTN^8)CrG?n+Gvl`twRS0dtQoyfWrYUgvzs zQ}`SpLT7XDQhiIRHQ~~Qk|FEUPyOA?pH!)3xjen!i-`T8sF?sJqm>JLvk)4rXyKIqzV4C>T|AMr}(aQmvREgZEP`(4PSOTddam^eut$l`RQGaqlfjw~hPn{qI{WnzRt5j-3_dA+B|H8)b1Jpgv<#Yxg+HmhUL^dhA3yWzE33Sc=av72T{g_aKU2t#N_x%sp zB#j${>+%fgiyU^FL+oZMm13cpvS7(vq*+jBnEz0Uc(BM&@H%)Z0*f9iE8h3{@2;S$ z0;Rr3Sg2Z(CR{B*i?LR=({nwRqDEP5Apo1a>d<%b!VOFJg7D#OLxlC~YQkz#+@I%X zei7JuXahr9lxiOQbtA!(c8i~9t!}q%X@WldtpAfS@l(XW7ebANFJxuD`C$J4i24q2 zD&PPA`g03MmQ5N1k-S3nLx_u=%7*~3 ze!bxhYyU3($oGp61$AIF2(^Qeo!9-m)Y`fgN9U`@r`1xZ3TB_ygB0KM2OM_Y-_SdS zU`MtA!Zy4CHk1tQggbQ^tO}Q$$hfSNL~I->Qf?F5+0eT# zk$9_%I_7~6(c$Nxn%@&57@$>9T~9gM=`co0NfFT~bGj_<4}_ukdnNGcuh~)jo|Z@? zze)Q!{O)r83oo_}d~5{Dyl2Z85Tb<%)g01isy6%i;UsY9EU?iw&ZL?_Msh?=`NC62 zl-=1`Feql%{HHvtd{}6PzViJC=G;U0#bd7KMEu-EdmxzK?8zU3%d&smQlma74(3 ztYVUeVa2y_4E$IR+^^-th?==OC(oa4Uqf(1zTOvy?c8@?{^uz3XO-*m4Mf~FNIqyU z6l*-%5WzV910Z=Hm*x8D1Dp+UmXtpRh!|Ok+*r9gTeh#`?&ictCT&nYt#?3_F<$p+ z!#CR}4cK(Zu14B5yt;a>FZ$gpSL*nbZf`Iqfuzvv!Lk&}CU1T6VBCzGi~^GsbXit8 z0Ziaw5O}m-%LJ*EDC{YyVMpj(4U&aOUfj*X_}e}*w5%LKPMU<+$X^P}=ejXIh=&|f z1=zT|SFz^cVX0`JVJ$zi|Ll(B^4il8$+D<`d;Gr zW_z5`_~K5-w^|ovePZIdJoh|HGqVQ?e}C$OVASW-Nzt_!vsgozETDIid1fL?+%wZy zBW0d|$EJp&yNmE4>+v2SQzNK!0C$KPJ2xECTCoO9!6p;072*Nm-9KL9>bU-2yMoz$ z6S`$5h8SJgf?Np8mc!nAwspipCP~z)D7FPoxlV zCIr{9MAyMtWIJ0rvn?6_%EW@RPi$O8zMW~vpj;Q5zem`}T2XXBm>u!qP-JtI$(}j& zZD}??lQ%a*e*a|1g4hR`=>_`Kg#cSDftk+>JRBoVJK~vAWnjc4wYT+g|6inmebi}| zk?1MwC*$W--kW`RfN;FR;k+aW%+EGB(B&GIIDOYal@G`f)tCK(d0tum)D@v0Dn9fc zASii=UW)YXb^fptKHFv9eca`I$mAwt+3<{d)WLXoIlwvB`abn-Iwk%7k|kU6;x`>k z`U}PY`)L1l#uBbEvfZ!dpXN(BHd@RhX3U^F&0iLDADp|L-P<_*%YXVIzPXY-il4EC zA+$F`fbc27)Q9WfmnONTfj)-v;it%ZUacrRTCl|5^Bdd8w;{#-x_>e5)q~iBv57wx z4-`2mdLCLKi*Nxo9|a*RNjijeXFqTTo#HDZAf_0uuo`y)+RkoSo(zn!HC5(`@uc1aj_AB zlu4CE8FP4nhUrOl%Tne#Ew(ux;SC3Hdiel?JTiGmo%j%qNUK@a=A|w)+qy>?E8eU@ z)0d)yLs6)Cd4^#&WoJ7xvu^Nj`FPf9(T@Q}=09ZynWWKW-y^t!p1fhu<3C=pJmE4+ zyrmiQ(=n!NYl2yBMoGCJ&^TlJhCkP+G`ZO)EXbUl%Omeo5RkT_K&Htgw>qwv5}P^- zCWrauFk=smh|%Oq1T0~h4>b4d|8<0XiX0iszzyebeSp*Vvfjd;(RH2Fdxh6V>N1)- zgchVl>WpMekzhH{BDj=>01u$B%g>d~i%Be{4YdSOuVt>GT;tljI@}E)DJ!*{Z~R2H zcBJRs2FC&--J%FW(dySL9bESgpPeG^KUQL{Yy2M|N=)NFN#cYyg{e=Gfdfi*-PdU_ z8wal{8jnkOQ!=ktR-%{6&UHb2bRl-F4gq%75ltU13&gy@;Dc7TP$c5rQK2w7HLg#| z-e=r!n&=mC9Ta|>7#vm{z#JoWJ{C$nuVFW`Hp&*QKlc>nJ zfE(_?zx`54y3;BZ)O26;qkNx!!ZCEFu8BB&_MQLJrQnEaDgc=X1pj`f`U{JxD{^$M z1qFL5Z{rgigT*sS86FEax~dLi94z7>`|P%1`a8;2B$rf7B34-13SlmE?P4ke4#UXI zw@-iH7EUa^vwH1qp(5f(o=vM3W`@r@hqt?k)&F0Hb^2xy9}*;|w>|^1^K1jEKmOB( zeWGm{w;v*Bf->zbT_<;apH6wof|)#+>MFLyY^|Fw5F>~XyyXq*s@j`-_M2h11W$3=hc)o4kQ!E>@ zSN0Bh*5^+dsQN{8EVTUEWgaQ%xg#DNuu&_1Jl+MZE{p#=Y_T|gQR?}5;Sb&e+O{|Q zZIoab*uBve%%-CH&n{2-TOtp6_&I<4E{N$EAI3RYWWcOsv0d3nOFgZ0C$1iwzg|0fR|;ERxOsm3ty zz@7}7`=;jS^>8w$*7==t$#V(#Tj-qQ{AN%VMrg7HV@}IVBUZM%Szp>EC2vH9xzU8# zeFM)VwK^oL;GEy)@+-fNvT)^|3cPBLeRMD<#G|BfL;7?O#o8409Or+X z2bJO2;wnUC;C8-vL*Gz99YkSmoYQF!#VvDn$dd<0>_$Oy>x(POR zRs4uLcvkymw?{@+JE-yl7%_Z5OM*igTsShb32_wSl~ryMwWbVtR6;L%T3S!s`lg0j zMtch<%==B^rIJc@1-BRi^&3p{h94@M@an1Br#(td&COln#fWez?I)hMGMap&%FbmK zyhAU5pNJgnVlW3RE>lwvl^%^gT9Irq?B*eQ zsgw_U6^OtO{P;IQbl8TPc?I=Df~;wFvs{BB5NSM$Ix63<@oU_?v1p8l6?C|uV<=zY z-;jw$0lW< zBx)KnHoQZ_+)nQoaF}97B4PThD@f8oy0+phF>y0vwLXY+h~6bTB_-+Dij3zk2Sk93 zpi{5NdHH!PF1n6`>oP`Y(*ZJ`CrTP^AFmr9mkXHj`<=Nf0 zFWsw8nyFZozV}l;@9mdpWAPp@uhRhEyjsTnU&XVp8LCeMRR+vj;;+c@W^- zj*z-Jx+LCdN`{*k**-5%#gXS{Q2yFM^26S=NxZF^dp2rgrAm&`Bw_R{kD2CdvH6DA z%$BaBEYA7sz2$JKnfQhX?~~1dqlN5|L^-}j(FRe*sF-IWw*!x*0cv&>36jbO<(A`$ z+glg!o^n^>e`Oz)=}^U4rJ2^k`D^=E^KFZT+VOPuy7~_op+K+3YUK+#jdPR7cgm?o zW5{;kLMm`(jbg-iA0pT5shDj)#Js$N%Q@wXZvrfg$QA}bQ(0w%Mvgi z0$c8Du+Yqw(dg%cWVtAuWJJ%>(zi5pw-)EckB!K6te3oZv!#cjHA+gNHXUoub@B)oPTR2jHyZsT_Hrrh|)^IhFyG*W+v<>RGkEl=&#D`Ss8M`X<#|nHKFpLe$pl?*jLgrBK_`SOwmpZ(;KiCJ0V2gz%^z9t1{VIqEeiTDq{hTkK! zvMOyRF|O=+ldbM4u;mmWei_`oWJ=V$eUA*MU9^Mgux6=`)#g3E6?-!h@E`3L097G? zSrlvw$WPM5wO-y2!U0M+&g6I@=DBDq#!!ooS#)s7EHx}gYkQI}mF%QR05LRZ+?J6+ z0G6nAMr8!%Vo^XWQQ(&%__k>F@S1;8VRSUjv^X7<&m%1vduC+I#8lyrV38nr&h{yQ zniWe50P=@mc%jk7{}o$brlF}X&u@+-~kg-q&vIrRZ!E&2i2@tXa8L@-_C(4K%IFHLcJnc_U>m z04-@5;%4YjIh>-CKD$`V%BW~rmCEAwwe||$_g%}MuESb2Hj0c>toM?AAT6Y{1(k=;;rSQU> zmuv7mG|h2iH}e(4CNd<5_7Ou{fQ&)frEH5FtKPYb4|29%NUZC@<^3wNdvz%tu&inF zB&Az%q0_Ns=>uhB^T8rf@g7nt-Qt>*aoImaJOzVrxu-OZTjcMV{td5n2HxKGDhPhG zC9EFdE&d`Y`r}hvoObe;Q5yWcDKlnE)xyvH;i-8X8bV zss6Cby7sIO2=O(mdLeOzcUxbo>})XMO>NN2zTB#&sUXCBs?IX)G$dNPmKFMHpGlk! zEh?pR9h_9AJcEkGNsNPXdjT<(KsZ|kts9h|-13zNY26K)sn;y9vP&6Esben`V+I6I z$QS0S7Wk2m{7NCb7A_ya5cf0}Be4kw(QQzCMcIwo-HHTxHrMW6JUe(@_(!%Y`+V51 zYhj+~z#ThhgA2rPA$uHo^Ij-PqU&Xr7l9Q&=R`Q5MV&3W=^-jA_?5ZRD(V5D$@ORB zCod{KSU+l3k=jcaD0utE3rFBV=VRBe{j*y3m|+9Z%z&a#qmPy#D}YRH88aP#swypp zV~Rx*>d4CR$)9BCyldFZ$+PqQRlFp=tV9d=F{2oMQKTJJ$mhbT>wqL?oRNtT_E|h` z@F9&MWyIkv)@=Fn&qAhV`|VUY7F31TR_))y-+i_8{JEvHmJ=aA650m@hAY9P#ow9yC9{=Bd!{fPf%yU=F8lf6g*c8f($7Cd{XaG~|uaI_Y$x#dG zADE;sPE1*I@m5n+-ZlKRYawqeLU>d$VLxq2&@&iG(z{z#DdhK+Iq@ z%%?LAbB~;+Uska^A!k4`$y@x6i$Y z0gLd4GcJ~H>_DH)Dfj;ltN-JVq!0H!6|+0|Fr|7^t&@AS04oeip4%!X^JPLX+t$mS z#|JQ0&Pa3L7SQzWK;IDGKiT7H^=|##sgvK-<#vc+_@1(HCrXjL+p6{eZY#!^7jhFW zp*EgnSJXpL^D43^GzY&>Oc08Z@in6aV&ZQzLQDiuYot@YERK%nB%B?THnjt-s3O2m zXrdW|WBONqpv&{?Q8bRGv3T&mUc5mS$D{|y$c4!Tc5vV*JYjjRK!f(@(92<6dp$p+=4ERucG| zW&Gxs7E2B8=HbtWWx!PDac;T}8I7&GnB(I8x~6a$1G#}Hmr?SPtRBCY;h*$|7ta>& zVNf2_p7jBgq%44|2Nem>RUEW*-^GKV`FiqB-)x+b*qe+ht?0`gmoo-RB-L}4@LPiF zX$Y32*lv;g6afDPf*k$xj(RI$N9|jMUl**f{BhQNK8%%xjqkEvRpy#(opzeg=d2y- zQNo5l*oSJK{|Qt&0*oc2H}NwTwo-vF`T5Uh@tB4g-MT*B#Gb#}*Iduw8JoC)KQE|V z8U6f_2uwk}Ha<-_)!E=MrH?Qlnv~#PJK+IJnK-s-Rt7dr*Ixg3PW$Q#A9z^0*4NfB zi?oA}jCv9= zu~1-)Id-SEb5{S+yU0XbSB?E@bn-Fa-IIX4`T9FgN3!Yc-jaxkok^0Q(4;#FV>gKb z^|RSu42zVnj=v2H&~p57fX@j+C&sx!EH`azrN*gxSP%_w)KY2FULKyxU}#!H{JuPl+Rl1bz)NN<}r9^NB}nxI&P8W1)SByL=W6G3CXx(`PK8pI_8 z1yS%3!J9;L_+W5lCQ6p(W4DI`$C~^`+5f6lI4oDl zx9miPjATu{5V&9$Y%6?l<3Lek@_$T81q>(|Ni9Q5gtb9f@M`ZkQ| zWr7FI+fHW;?vG#Rx@AZ(``MQQyhU^KLlLL&Bkziyo=T3Vv%bQl<4^IxHk5QOjP`y+ z5UO6f^9DbLtE2l9OKupO^+OoNfVAXIx|@$nC1))7^|9l#X1m+}14Yb2Hwa!q z1^_&Py6aunSM96U&u^Z~DJtAkQN3?uYH{9o9s(&aEzWHqHbU!swP=7ND7dQ%MSERy zWW`nh5qhEWFtrsIw@GspKvm6Gq^`h7#)ziOtoLN5Ds*YOXHbbFay znv_F5D&YtD>G{!eN}(O9n7arv;GFI^2u}ZjDfR!}3sZX^m_KzyqD`Rd{XUDk@vJ_r zGAZ^f^qhmkAkWB%#>2;{*4wJTfk3t(apHJvruHBsp-@;>Vl#iQ7IOQ*f^nQPW8Z;c zC>y#r<4}|V^e+ZgPzp!j{darW9A>&1nazk9Eus1k*w3<<(>Fxu&6_@}%Ly$eHQN)u z>(ZK&zc=c<*TbKCQ#2lp#C-WOj}XFP!NIDm)!f!CqvoQlxcpXHZe?)IlEmLPXe1+7 zMy3~|5zpC0-=q*A`yqSK{;)SCh;Ht>uGyq61(=Ow63$3_XLaVu^OJ?3l!GOW1x_=} zH#zyE$Nt+*1hC|>GjuMOMuh+*knbBH)xLuE`1a@lDMRbCR>QNOvv*6Abv@K6vpHCU zaPYdVrake$t-JniR$X7SU*cBm+rq$$Iv}w!LKKOfgz3}62ReVtP$n>Ldt?Io5 zA1c*^L>$&gc_EdrBvs-a$-b*yzAI;QdtL!#$S&l{jbBE0^-b<5Qzl5TdtWD;HyC{W zq`&m|FxL4@FHCwV& z*B@Movw|s~VfXP`$bib}Nu-)ENM`?%{e5xP&(hAdT#DU;SYW(O!oTrdhs)_|cI6SP zjfD=R@cuJ4BkMuf^v>4S`YTn=T`si0L~4q=!eO7hV7m$P0s5AuwtJb$6u zsvA=%&gMbrI32EPdUg9(&DH|(lU8;x+P!XPc=%NQRbeXcdu<6S!H}}4-%{%dnGBO~{aT{A@Z7^cvgYIVt#eWIZ4{X>+mxI`^d?x%uISR-2XP3qjp0Mm8?ug0X;R**)lGVH{`o8vlg>k8{(&iT}uUV0AtZ3;!<<+A|s-mX>IYwr+SU6Zy0 zR+R0KbwFePX>&-r%)t~Y*?)9Fsr?<|Q$=p(7t1}G9ls54ma>J{%~`{|)j1=t{j+Wv zR7CLBCjO9dRp6{+in9V%lcfQM64muvNxugCU~maOzy5dIrbE4{)$5?pC;Hv+$aqD( zUPIE0Z&iAADp2~1m#HQ#J@niYp?RKN_*8D4fgST_AwSbx$ zp*fyfOVAW=OO@K$F^9m=vdpYfXz^#QB=j3S$HP3YMc9AB1ww+i3Ry0!v*jr@4Rc89V92GPQ9Kyw*Vm6@?XUj zGif29C{{kLZ(e)w2Cw8&rEHWirN|}sn>ZIn7^p?AFNltR?=7g{h#zlJK~5$9`_drP zA#_@F7GdRrqLza9ASITXY|KN>?cE8<616k<{7ISlKR zIParJ#iW4dM4J<@XrF}UbG~YK-^hulG;za29D0=RwBETsOv;@+tL$Ue@M#a6`<|rk zJa{7`2JCAQP_dLx#)vy*7aOumvKUrYCYjsgMVpzyyaonf2vZSC&HP1G0Oh<4n7RR7 z@#*GW6v&S0Jio7@`=9q|(r_dp4bUIH$5q`WbNB3g(ek^lUI_-24q73*OTOKx^W(@a zqxDf@)nNTuAsDcNtqB-F0d%ZFo9q&deYksQA;F33P3Q{myjYghePr#&*1dS?@J}*J zpxR2u?iY==^+!2H&t(Coo|7hXyJ&u<Z|W$G-M|KVT4J%iZN3J43O(5J-aB~4TMcU-?jeAZh&0w(I!5e1S0EfT4}PEjet~C)G8kU3n_N8*Ag7if(BuW& z_LwhucmUtod*KTm29F-f>($BmovG`W@IK*tI6V9C@m)nOd@C{VL}lGBb5&Bx$Jx$q zvu8`ov|Jyrxf1%-o!8cv)uHPSWU{PK@jST(@kv`OMk0LzoZ>6*OGTq62RF^kc*1)F z?Fdn&b!Sz=5XA#6IeFu9$fW($Ba|83^F(0dZ*&SiCW0uxi!DK(TW$7549pV2Oo2%9 z;HP;P_Ay3Epck1mAB_h-&n9&`hr&FuQqN@bG92B>5AOh}Y<^P}96}tyrL zJ|!UTEN;Bkm2{&e;6Ne3F7C$r@+^jCNm-A9`>5<%k2N}{-Voi!mawtWQ3SyMdsug* zb_?JG{xfZkzgOCtrBkHQYPeHU&`}%TgPr7<5Ip63rW4Om6bL5t*Yh;;?=Q0V#w%b6 z31DvFv-rlx*8~JC^Ac#PUgbtNahTiZ+%IcxL#16XUS>hn1lG9!0cbP26udsRing?Kxl>F7<3NpR_ z#IRR)bSHb|=I~%-FCV+CpW1lbuG~kpRGx1ca1;AkPKaERl8~TH^}_|;&$`HMoSCr2 z3zISqfHBkwV6JTRr>+xXN)ba(=xozkB#bkX`L-g~dZ!bB`S6 zF9#l(F=U8m&Zmn2w46OH=oQpDaFmAM0gTDgX2(+3VQ9lbpmh56Hq};kPdO!$APtzI zFY^;#VvCmGu%WGNa~}KWaOsXY+lf~;_kX{-=<(zC@p(8R!9Qr*c6 zDL5V>HCvd1BBi@YS{FU5I-tEd*4g#+u_AqF+&2l`f=1rTv-MQ= zK?^_c6K5x4f(`A*iO)eki~#0EKv7TNnF|u6(f7{F-R?adyf-^po0EV_!&j4ZMk0yduw(k)T(JWB{(gNf+{j^>n}#^0qmvth_Q|l+f;8 zdck$kCmNHS%b||y3x%w=wziqa|FJ}j3>w2sAq)dI+)yNDI6!PDH47zOsmeuc81s&@*oRb+~v7@W)Iz*##Aj;Dhd;pSW@9 zm_KsZAH`uvfU<#y_anY50D~Sme)8uyD+>*3``NPadRQ5@%NyDWb9w*$V0&t)!fnSS zvOvf1uga-?H=F#1Q5mbubK=vN+U0}NBYeuhe25Z|jP$#ar&Uy(CwoDlQnE`|AWgWj=G2r#OuNWG^fB#0j^D}I~q;d(Q#VqomaZdPh)|XSrbmP}^(2V#W1cOTP zzsJ5vRa}r~hCVKP&!7o8B@`hHLjs~NM9ve{)Qv4|&(CooA|oxOd}{QEl&4{#agR5P z%^myX9zV78G=x5OF5{0vqrgoec1oi(DFISa!_P``u=O>!e|6= zl{z_EfUXGiCHk{B+-Gj{OE^C{xefB_>KN;9A)JRO_2au#hr5ZbQU7^5n16DcQ{0zM zHG5x>6}_SRD}unj=6t)?%ywDaW``@COLa#^uH1+7C9;>PX3f2hlncClySd_>tK5Oc zqsWR9&wX_B4m#I^_fS#qgT@fqNK5@afj^2-E?a<+AP#5KwEujsvb@x4EbSk$mP8N0e^cGD}&OVUu=_q z(xI&n!F|uFqEKP8s>=NW#pL-`Zh*q!XT&OBPCfmoVb$i^s++)Ro_0EuS|L zww^#SCVw`nSRunmIU?*nOc5IXD~naVBRF|bw(SgSuLL*k&CJ|>Yi`_ablCemJjng0 zbc|mh!mFu9R+y0P#_W05jUBD=HXHh1|DF!ty8rPZy;H1C!TX7=+(Pagn-fnaNFFgY z;^95zv5W^5t&*BIwR2uu4} zm_<7^g?La`c*(K{9lzdE(yXFw0)D|>t+{-M-HZ2tm6mTExM|?q{R~-heFM`WWlosx zz@_-jLn}NaPbQWd)PgmvBB`cLBcTQ<9>EOiVd6gtXEc5ZiM+X`6+RX#(X|{eeCqXu z<7%Q^YQr-gMCdyO*l7lxtDUx9CH*Vd;+cw4JeGy&xdXFI1a^d#u$=pSbrRu)YK7c* z0u$=UdygfDrS|u?a|qT5m!`ZkjINZj)wANizI|#b%hPz~wD< z38#G)%hz~hQR@XHwK-2&JF=5dl01oz1a@(H8pVeeJ2=V4;=3@;?<@`d0q$)AtS>*~`@ z9QKQ}p6ta3T8EUXl?rwt&?ciC;=OYyYQg3~hfRZU{BJ7!r$_#8SW(n5Duxen_sqJI zW*oEmwB~O~e(r2zWM}${&o235IKAQW8_|f-2YCZP=`J5qu@Z6wJ!yA72-S0afbX1k z_3`QUD1^O)Ek!0i`9go@&Ieg7W7 zrEso)RVfHxi^ewC$O=Cp1oxFyOF4XatYif(W>5s3*}kvhO!2}t)<|vLO^Q~t$HsBTG3f+W?Pv?e!Vj=bbH1XGDqJ z1++;%K1*F0!$&z0<74pr4oBTA5=>5-#x?-YK+!GQgMkGZDiI@QWJk1-{} zY9rA&U)=>D;YfwCx+ETCoCAQU$*8e z+6-(=7idNXSbuMxKad#A%Q8M<5iqvD|IvUrRjW#d;e&DReKwSTeI+fLv5k)o@;xDd zW-}BU8xOx}{j)_-w93}yp3_bO?+q~Y1qlve6BT<;qu0g}$Bg$nUY+5jRqj1lYGaQf z?%sDqL14hS-911wKNdz6npOpHF&-1%rTtob7761LB@^-E)tA>-?(9n+cfZ#^uo|JH zcQXpL_s4O*N>(Od9yEbR2Hvi4<6*;3P7NVB^`C=PkMUpdP0_xAH=kl|tR2|Bt-GZF zS(B0cD}pR+d4^#KJYcRTrHMurm_pZp!3MR$j;*I#;$SQ>l;lU5x8?2FN8h}_SfX1`;Y$-Mmb_L0?C*>@~~ycS``hW|E?brk#~@Q0*jA{{-(Kt_}1eITs*kze~H`2X2L$Y`N*C3 z*14Cvx8CF^SDZW!SoTY9KKGOB%n=yZ8*hgr?KIZLofj27+&#pYLcCo?9`Q=o`N{Mr zurbx+Xm>wNCpHAf6EJ6RYZjn56|VgWl>q6izOY7AOu z|4s~0YXXFfT7;lM<*|+r+nqaJUUe2oZ+x}WNf)nsj<e}+Lr;=2UO?gIxVAua&vP7 z_0S$h#t7}mBQz`gq(BHYqKN~xKBTUmo;R$+6vxV@^A<_+N=eTk-J4{)MHxE&@og{i zVLj2#NIFa}$#K?1d`D9^)o6V~|FPKucaurNRwYDS7dg3N;=HCQ<6TSCA z97s^M+n0bPx_tG;aCY-ZsSBmSBZ8M_qhFN{CO}aHZ~#9(b0{{P59; zRnSm6j@)1GbqbeGnch6RZlZZ2l=i3@w?4UV6O3*4(c^4UyO+Cgk&u_j=&HZ{F*+(6 zUrj`X(tLMd8F#6v&O2r7^vJU9U$ZDVCGUr><_{HmQOt?!>j7e9lL1R%GQMLUJD2mW zskNV?4xeqh2-{~Cv6Z;=A)dj0Q>5B2?Dy6)t}l?2(O;(uJJ@F~|^_7J;v z86Pv=I`ICf-0dfsG=a~aX8rT!lzZnGxY&F%NAK&Re!&u>x4;YjUwa2Q{w>Q~jk4t3 z!(Pl=)^1~hQBH-gq-byf3C%akmG)TLFZU%=df2Z@ZU4PHkTB@|VJxor{_5Zfu1$wf z87^?Eb(e~>_#1JhKe$N2>=jeg+F!*Rtol;j78@T5S3Kt{aB2u@HEj9DRvOf=yb5rY z5%Ri@|%++JAH7hrr z-~dync;N4}qbkNlkKWAhNH#%#@uU08-9KH%lb;?_(;<^9f*tgt%+jlN%C1UEzxx)Q z`9^M^yjM7R@aaePXhR+U@At3Nm1NLWi|H%`civ$NuuSs9QZY#ROy$J|=DJNb_)I8r zM4gDaap9e>xN9*-PU7>txk7(BvtVocq((BI%iLpx-B(TL-Gfm^w-PgRge(2c*Y}q~ ztzVyyY&X3b(~nNB_)MqnaHYjjsiZ_+#o}KaCtJt52^Nw?vFvg#=t|K#9Bmi2ofytm3RX9*`9Pk%m8`L$tu zoRM^!SI=1S@mr(T6pENeY)l+S^VWLrq}f;v4K$WgAnl*UGl>d6>0jF#vu?elu!IIc zI6_VPQMKRkgj}m@dWJ*xHpSKgNKlTrjU?c$J+HQYM*`B6y8wI3Q+@%M-8ExZD(j52 zh67Y@VxA@enUHRh0%>2Ss4v^TnL!eB;-$?)8&SXS=guncqo=5B)~v;%ML*xMl)*vi+r@4 z=Xdg6!lpL~S}*@mT!*={<+}LWJ`?>`XZcmW{88iQxkHSiA#Q&l!d>!58)onKNrhx; zMU0-CdE)8ewdf9$AiMer6r{%ITPFl5vJ(i{qh$t*3tKY0{CeBcAyK_${WR284B{!n;`SNYo>8<3IpZleX zZwn1PWwbABD)a%&>C5$EnF6ua=Q?eFhpK70H;5|gM$A6U;~J&)h$& z<}*i}&*3+Tvt&H!v06c+VdJ#*oKI3J>f`D^yqk6&gSKDZ`W`MR;Ahkag)`dDT`6;- zGuy7Q8aGnTM$qFMo4;~EoYrth$Han$|M~_Ff@xw322Aa7q0e8Eb$V@$FJ#?Eh{ceq zx|Phn)HB{KVmUHs&oF|ywKQcE$XyoEe2?Ze*C&JCSU0I-s6SbG#(qsG!pE1aYs_*o zbhPwmMFofX%r-vgtNmzu%hRcUhLu@*_*lD#m{!_S7PdW-Uv!>cuwk9T_0obcJNXJW zF)gvvw)QA&>7~1k#^o_^`9rjl1^VWL zoZC;=>gF8Mt#Mdi^S(FQjU)fIT-PlY5xHnvCq<-oW%1EycigS0%Tf)twE_$&wQ3YE zM-y)Vq1jYs-;qzd+#W^2RNj_8Vkv6Ta+9i@-v@V$dhdUD;`@L7if}cz6J*a%jw9WY zKCZlZmybat-~%bXU!}a#10@rLslP|-zx_&)7i0u11|$Z+c}Ns+JBBcUBv!hmR5ZI# zALx^!!%Tx4Iddo`;w=2~=1)2uT-lRJx0HxKUB?oj9p)akC=I8s)AFOQi$NhRy_n_B;u$Cz(`@0saqloyl?zcX=uNA2u=}l~**pR9O9)N6?YSc)+{Y4;wxP7ZC;{ z)AVT(0=~HMKMUvaz4?VlBbhChJJb`; z0hS!*@=Rh?Tu&^R3!k0uT#$*@*W!bKwNaQtA4dU#)t1oDH`r3|20ipUs%LB?-4?w= zxRK$;HT^8*e%edklv?-PiPk)$QKxIayB^A0zwX%?!}+1RV5L%vA)!$G!4A`78)ug| zRJo%X5k*BKMNI2K3j?=Uh-y&>A)b4&>Kqr_3#8zlTdjWzoqVS;3*BgEDQ|v$LH|iX zv5?(oY3kMLsO}Q-v$+fb5J+lY&Tkh8OdI7k$fk!V?3yNS@n#F15wkA?*X) z$<2pP^w$bQj{M+ZF6!$Se6u$4Ey*=1fRr|i8acd)jz?rrwFi8)7!=z za6>Zu)xjLR1#p%jhUK{nok!r00Oq&r5>BU;6;bYLB|2CQx5pO>dP)XSiE1X+t7}jE zG10XrLTJ7V9dz%rc=VS}>=!<|-t7uzFg0xkLC+r(LFJLhph)Sbchpr8`!_%6YzyK3 z5uL!N$uOAAp`y{3RnQ zVA$wGE+s3%6pyFWb8u=IN+0vEJ+0fhAm4r{690W3IUzrywT8K;wz+)!@<0UUHV(M; z+^YyfZ938;awKhxiOF4i8{hqlkv3;gzRC=Ovs$(`tbSkpyllxXY& z4>Km-Q56YCvr1)4+=EXDtGi?vOlqs2$Le5Ky=P6bN(jX#Lrx{<`Kv%v))pfsD0*vv zLFVgLGelAaL{}j(PRj`NgqGQkpjdrpv%IHAae^E>o#hCEsKH>_vF_!lNeBrYJ@K*v zn^Fkg#=8IK`YHCWMR00woip0ay`y&6dp1_UpzXcc-ziDa4x_?v;$p;N_)H-Ac*Yy@KlVuOcd|E4mDk`gRO7CsE$^Rgfbbt|q_ko6nsK}WoMP|8l zn?zW*hTcj`VY>e^JE`sCvG0#mulcN@4gK1_V6uY11VmjP{r*apD+ zx=)@X>#e&Ti`pjG$Y`>4Eu0txugE;!Gp<$BnbduXgFPh$&NeRh^m^dg06^Uq@qhXV z-2jgu1;FrL8V~-U8AS;H4bWCVkl-)xU#mK|+=K?&K7FgvUu8yO)*RtH*MLt;w-Wno z?&NIwtAi;cQBL4I3iJ5!a12*f?Dv>gzF{3#Is3jiTiWyuj{k^$)%*{%h^?5+v7Zkw zxR{cw+-D-p#@w#-#Ti~@K7BAU$L*4~;qz8dYN3ig-S-u%XGHAZqhg6BM=fCKCZwk3C?B5eaD9QqG z#Z1gB_Q~`SGnDj{1n$8#NDcs-AimQP(!c>FmtezDhV`Qtw0DE}FL~rbJTPom0oT4C zm!I2``5cU&PkY7yZ#XboRs4zfuj@QHG1e0}z|U3{y!xuqO)30a%cnyVtw#mgYyBsR zz7bkmQG@ER1xMfCxPUd%LQyN-vv>R z8_niRvDH=6e~1$<0-tGuuVU67?>Go*Yz^U~U1?lf~4Db>-V{H(lgiDb^9rN;B5RGu|F!MZTogNQ@)&A%^7#@vktdY?`*8 z!MeKZ8}Qp>TvmaSnA*Gy(!j z3P=b7A|M@7s~{mQN{BQ_w}9k+H_!VX-@E?sha9)uvvbWgbIv*Egl4mti7lCK%(&np z1m2<#sw2Gac^Uq`8+&|a6ntG7kd-|cRE%lzQP0B<_~fKNk`#9Q*WBLefDy*52{R&M z!UMiI99aqPBZfFc!h{EclT^*7(HYbbJk5EVI)9YzIB#E}nR;j#tRpyiM7V%x2lCrT z?rJZ$<-1|FXgDs<@M@meYzvm`x$!Mx1`l1E8?null&=a+9bf;CA*h4Fx^G9BAa;{#*tQHx- zDv|z7k?B|F31PGT$xL9w4Y@U;kT=Fp`vToymy(A&g9e1J}6 z?xEz6kr5G|D>#3lun>5_i#tv;Rv66-G+hHd#RLy7!{Qg2)rB_Rw;}F8g*2A}|P~#kU zuKHRTWm&X&P{O#xTe}!cbZ|InDVY$gMipo(=i9@86G((8PB(q%f-HdEfP;QYhmVj> zrfoklllpOt>Gv};t(ZXjKEV*PBT3(1s~cj%{~$neyQss{TTVBCYh{OwQRy!f`en(W zyA~Y@ReX?_J0{-B`=GZfpRSad9>xxt7Ca$Ccbd2#pZ@96;q@um`&lkIm-7kFD@7r| zbp;yt`B%#udIzq#5+(rk7#!xg)VYDjXU*b%Phx?gn8zro zrL)u)L0o|MbbOxaaUJO{Tt|{zGn_n6kp<1d*X)~5{^>BX(Cc5nZ5Iy;X zF=+ZjNwu#B1&295Xiv3awo<@tmbcG0ViNReQ3}^(an&Y9?5_Q4Oh`&afbVySeVMW~ zi4;K3ph3UgI9 zHv)9)S(vzo4S%ZOM@O(g`B-~DKh?`w2d&HhZq#DXEqB)OXB0 z`>$sj2l%@H%l<5E+qf}4Fc_%)bv~}5H}^M{L%rZZz4k3#XH1^TG#|a;8_$8YY0*J{ zv6lox={{ZoEivJ~q$v``tfR(p`3{y9xS7u>L`8mR(b;>cZxJ4zeOdq8&WFrJ0t`%+ zd6xl=8|6Hp9XL~(hYH)N7mOOJdO` zWVeI?B^(2*Bmmhp0Ti^ui{oU-f-hQ$b)82{tcQTF9mne-^?KzXZ zqswCg%(NL+BJ+orVRWEq|4MIR;A^!ihV(_`NKV{b0-Ar zKnFAItt~@vCjn>8e8v^b59EAX?zBfgUHGRMTq)<^8*+49>QdbISlXIX+MaxCXm)=J zQ;DA+?W*&AXX=HU#!dRYHu6t%w{X}NMY<*0nuBU#c?xyv9V;qF<_b?AKRUi#>oN{7 z?1>;3W)*xCTb$Ip*gKY9;>;NLiGOw~apg9kTRjjo9bZ7%TT+p^{mN&`Vw^K;ZY~UWXUETQ znjJ(t=bhQlK61W)+z^??hT9|EcAYKYlUUo%x?|#)#a)LPEzna~8X7_4Jg=D z!Cu}{N&@CyOcSeOj%F=e25&6YXW1UwBs9b*C=ea$ea^@|i~1UTnSasc3{ggcFgtx( z3(Rk}oYBRU5=YT2L$DT!mRfRX2tyS;O29&ENpa#hISYF#(P1C+F42zns?JI>jAO_? zudp*2hFW()e=ktKFJ|1|&GNA;E0hJz+q)}b??lh+Wu?BJ+hbsD7#M4>Nag#Ez))%Y zz%%D*>0bG}Uw?@Yd}oO}f|te+Y;)~@GCUSZOFnI0la0s@c+ukZ!47l3g}cL8*JE$E z`RI3h_cfBWCzoq`#{@_F_CusKd{R8rv#;0XI78ZOr!vWMpVjyz+f4FGfTVCO2Xv6c zxolMYqttO?fQl4SC!0!NJv`7G+zii}G<STaiIFs8K1Y8asV~*)nQG(e_GJT z!sZ6Tm0M~`uq^!a#(AXwoYm=HN*Hp2i0=M<_1U`TAK7bQH`eH5CMzBolGGJsT*SxH zfEwlFpy_)%^dA`Bj*78VTkaPv+~)72ouuL{EXR|blOFS+MOo?Pao*+xN6RA_{~xJv z{y(I`1qv!YZu*S$5Jq8#wZ%SyW$_lK)pZ7CER+dB3|M{*h|{yp;0lA#CRb`mBM0-9C?VuBaQO!bL7^j8Oqxg> zCtu;!F+!7|#J5p+fBsEtzo!buR`9;tPf1=LKJCB-73}w3hOwxVRzxYkPlS4S-sZqH zF-k^F%D*aEm;tX}7E%SCtZm%^Al_p}$70EE_p?Zir0co+!QPh<3EVLRs_??@$4_4J zo4@@w#J@g z&HF){A6Y$~K} ze|=0MK<=Lo+He#+K!@wR=z3zjo~>zCI>RR%(9=4qxHuCV7`)f3Po}N-E2R!S;@Cin zY~i=~J$pXjFE5kPxQ2SUS)@BpoPS2VPN7n6D@!WV3Kz3EvjNJeT$C-q0c>C z2s@6sjyrFkM9EyFq$K7ba^cYW&m`B2qje^W+fZS3?JDUXLVf!v4+oD@<_zi)g(}aU zDX*il$yupK6^ZBnlO;z_y|x=Sb?UAEyzh44qXB0Qb|at1--xs0rF)g^-oT+%v+u=A z&CX7BKbG4-4OeB$TSh7KGr~dYt_Q*u?-Vw9-<;FFAQwW~Iyh}WkHjwHABl!B{lH$- z?rGH>jnf-Yqvpj8XNc^Q1K864pviS#eMDRzZPXj zn8!%z&&93%@?BfB^q~#fAE*;Rj=W+ab3vtBe#Y|sS{C{1ge~pRi@kcE1+^1_A2nLv z(L-({;=NCcE}ftRgAB|i7N~Iyf^FG3I7IcGgNZ*rbtI()Q&s#c#Vn96pznDZ)eD@} zbz%ZDWvGP>eO^u3Ckph;oIIOShyU5R-UtWYXAhn+x+A%IS48NgOUQW^JZAV|tmG}T zUm1b5PM+TS=+wb+cCzeQNyq>3RNnEqrLzoW@{OHlXGWnhvpuZi4oF(S0#ca7O>&GeHu@=|%ko^WElb_+v%W_&)qnYZoq^0AYwPl6J{$qHWc%~16I;38+nWYR+J zOBSGd{8i{&qOSXfzn31}@8eo=(lv{TMRm%XGIG+n7{cO5BmgAx(^&{uOZ@risPHzdFyY6kYbih6Ax-th)c`o;8Oe*!+pqOir0ORV{Obv3 zb=ipKT4$cdKdE7Sq9@Js`cdF^h&T<{#rd;AhD;l?U2&i$ahSS!RXZ-l~U`hR8E!51)gB|CNjDVy=zR zjZwSu+k(W-x@5$fUv)yaUy|EH1!+Ht%&R}02IrC%NIEUwXS(di6a9{x3f;(vQGt_iQLK6l_(QN??yZtS6g(s2kWyAaS_Dr!F^YYA zWlhjnE^Ply==NcNH^J&@I~Bhg_+m1!6CX#eG%S47`j#Ew=wC0A%LC-Q(}%b4HE063 zUgv)&PC5Hp+S{mK1I_Skyf7w(=Q%}rJ8Zc*c)(%BS^2iGLFPrTv>3E;XqBOE5XiT7H&m+#eDZtKC258hcDPZ}Cs^ zQ3N}capryce@1QBir$1gs(Gh|L`Yi%a(#Bs*wKPWeh0k zD5-C&`kFx}4TyWZMVMyFvxtT8EW>emx9{D&3DnTNgxlsFEd|$5t%v`LgytN8cEtld zFB-oh_BPwvXy(4MuW9>o+oLp_$&@v!0?(|$N;g0aes4}(wdPZTPo7aqd;^46j)`g0lRacv^rdH0+dLZzdISTl z2n41#o?6%>mYcd|QZSv25Naggu@JdOVRN!JvjA(kSieR&N>5 zEAjUe6!peM1;25LBGE3sw`bosxS4k`)%k7XpgU|`>26l~b+yc&Vl`jt9{P;$r*fr) zE$o4KV$wC6d^Ea(dh90oWtV``YUW?3C}sJ{Hwt^Q2>K2l4{a48Q((pZe;Pi zMG3c74^Y+o=gt7oLl<}>FaIUU;Wbh+%- zyUCFM@-C=7eOQ`Q7*gWX*;^r9%v9tXYa8R`O6q#&^8h4_fdfz|uc}6?MSwDo`DJT* z{XWKZUE&SjM?Iy&i>uc&N$P?3*!kj|GIv=~4(&nluu-$NdevcLxPfT;V5S?{l zVkKT&d_pcKwg_VtffL@^U>zYtBl)t+D>9wNT6NQYlzKxf$r)Q>_Z_a4$3EQ#VvNMy z^vOf*cl;NQh~*Oe2nu?FWaYY<`@8t%eo{ed4q*2uNwlc5064Pls{@ZNb^Go?1qFF` z?6=eu;Qm6XDJ<~5+-fLg*qsb)UTiZlIec|Id`>w{y* z4|blqj4?C0?lN0aA%Xi)X?&Glax}wT29(k;>JtuyS;i!uT@r7oV`AKWd_L!Rp}eq7 z!Y2?sgdq)=Bh=#@ARl~Oh2j!K=xstB`0fh(rUk8HS5H=wP^wFfNexm~NBNlZ+{ zhV=Ibf{5FRh6Y)StEoSu63z4Qz}!hOA{|u;ZBa3U8(^vi-V@9nt%pNCxZvxcTL%aB z9^?*bo!_sN3!xh)MkFxrn{BmYd9zm*$ZnUA`gUTzKP0PG>fx3v2m*6dLfK{Yajw%? zcu5igd;{%bByxDIzA&8%{K5KjnMS~OE37M;TjMo2>p+BAvusPXwmnA{dkB&BjJR{~ zq$zf?(k=U?4h0e)xZ@rCk-t_r>gwk*ltV_8Qv4pKC>I)r1Sl^iD9Vsonvw%(_7Eb= z8&D&t{b(hID&Ur4Q@@gU0_e1jLNn?znM-iNuh+%j+;hL4{KzL1{DHvz?!GKIC#s12 zju#PeL=FBpV}2~$gw7V7Ns$Q&({@VgJVLF{Xt!_;hJJnG3q73KuGZsY{s+NmYBIht_!$m}b1We_NSLLD0AuRwl|Et1_eh}Y6UT=c zo@n)apM?Z?YI5epkv$q0+=G$t7t+(Wyvo_%gaj6)4L; zLH*uEJKHZ%|5nSJ{cES2DS3r|%W6a>tONZaQo-euVezD;H5Kkgygc~-a897Khxa}K zun%Eyz<&}`d*yXuPaSnfVi!{v!2`0f=w4%!~D{vv#)#o*NWv ztA1O6yZ)M_2a*es`%9!B(a{vuqPEofM?4;(kCW?I^XmzO{DR>!A?P>3IGoA4^AHiL z7?FGZ&g){x%aH(r*Z;UVf*fH*VSkpY!v9suc>RA^i7Vu>#F`6_>7o7uw&>mi8~Z2N zKiCp%2*m7ghO{yqvG_{qLa*FJB*^*Bt&IU*uIGBD@9HhJp2tM4VmV?ub~Rua)RvLY zIS=|~+(f5tvpuoPHnipHI#_GSFTFB&^+)aP7tgw|Y(a%#{kVZo7Wxk;MBKEX>%2=@ zn7(I((GwT!HXWG@;Hg;$Y~N}84kPtJGBwNPBIrU0-k+IPSQryv_9tSJn~~_+5B0;l zRkc?=K!}aPK;0emrqb!}BFD$ zRv!fd9%U3gCe-ND9pl&G(t8F4@M%0Z9>7ZODk!t6!30oIyyc|<_skGLmbwZTyftz2 z?htI%x*(pWy{}vpN{oEzW*hLn4+mqdM#KIM2Lr*@KJKPob@xB*NuvGfx`m5C9$pMJ zEl5K0^=d&AL=D-PFdxIv+tfx`fcBw*@K7#KamX**D4Ea5RKI}lyC*Npr~5?p@v)-R zLI;5->}MU5XNfG>Be^}fo!Jmb-P~7=;zyLsMl?)+Mqtheq53KO@$0)!`U+w|(z=nK zXcHCs(XH=-4;~Q3I(9=6EV|>xmozSG;r&+e&PL6LQYVh&+P8-U`faa$s%WSiYf3ou z|LZuc6LNAmS&JW$gdq1{yI=NNgq}6Is`-e$$Q%)|8~p4cR%qs^rnMU(ndOO_+)PqR zzq*v?rI2`h`Oc6J`&5!q_F!@^5|+3il?Ehr4jT*mY+IdCw@abI4fMRQ0L}nrrh0F* z?#7opI}LXvhZ~+Fz@rzR)%Ya`lRSMMct3(i1*;>5l|61MOmTop||(1i^pcuLMOqba=Jv66VU zAuA5Hob8GJWk$Aj*rR@q%jA*N=es|uItqCIYRR|2cZ-yVxdvq(pD)-#J13OE2lIsC zoOVun8;TKiB2DKLRjuzlG`y!eOf-Bg!WsD<-P{D1Q>86=Z0?=S5zz4G)h>5~7{?dd z3R=Tf&g>r&R{FU&>^dX@rqi>W?}JO2FEh?{qDo(AQXV!kStH0#Hj)so@>qswX)WgC zi))q-7z^QpX3?v6^J&`|HJUC8Sp|3atc z8dik)Q?0FA5^Vly@x!E(OFO@Fz9Qwzb8JGLXzBT7h*`tg{E#Luzks2c`L2^!BNMk; zX^Sk^5H>er1uWdc?j7t!EO<(&_v{7h0$&nl3SVSer%8}OXEK&(|~i6y5Ez~b~yiFHosz)R*!L=j}6oQehoVx z*PON&6@IwBEXmPekaHY3D4NB8#q$J% zMfxteI1@M+0Ewxsh0X^_u9Z}0mTlfVhsLecdqR6AW@V@hpdZW!cdelYq)H;$(Co^z z=*x%kG#W)?3{5I~&e9xHc<@0)Yv|w%(BFmwJA+j9wjbj`k`efsb z3j+ek$banA2^P<|yI9MxP8ke0jC7ArVg(@G-rC2#+>`kCc(H&kzuKGdgK8lOPsx*q zjLWZ77DoyhL-)d201jC6`_crF7X{5($eryOj;5AjJi$#dU28|HQ6|;b0{PM&daKHw zG_W;qk~U@%1ZPQD$+kNwRntp{h4n0d{if*5e)q(uXzQ}SA@wv;;G;}u&p+4knkOeq z31b8P0b9M*hBtg48QMzt$$$7TBVelh;MHw!zmOC!bTwwIVSKZqYPZPlx=T9kwWG!F z&xHgI3zF5)J?M46LoO^`X9+Ppl~u2asI)hW+Kwwp{)%wy>Ma$_xTcb9DZWRJ?uG)Q zJmve$b3k$$qmSIS~ccS=kexcR!o?i`e=^z+Ss zygLj?o+E#sIT=}Ud>mNJF+Z;2%y)pa_l8bqTf|yQO%Q+<6>eqJg}$mVsFw^9pSm=v z)Exr4#ug7DV2EeFN#j9=hu!9Lt&~wFjuQX+8S%9?{cVa5WeE1oeU(8v_tA+MNo26U z3&{i%DX^rMwbq21-E&cg(YNRz4@5KN211GC)n}Iud?jP?KgW~v#E1T6ZubbdIf(D=6_EkEqy)5Hph8Bp?HC2&jG z|6tYS$Il=-jVsICI7F`ed*fS>@6ksplRZLKg&L8L{mg9@4c56|D#^*)w`zQjh@&kI zt2c&k@4S1l5uYCV-bgc>c2zHBqsdslB~^a9(4auK1jv< z7!?(g*-sbIfWYFp2>HZsP99n?G&EnVS~ipXpDBPz!DpS*ziLLn5?BE8)+cZX3}f=x ze$AIRAI1;BIPZ?|@x~q>LH2$|MQ{ZUC74LzS1q__e{X-r|66gvlbd6KA(p){Y|#)& zE~W;0CR$8(ff@S$(2JpUV?W0Q=pe~Ux(*W}=)sV*1q5h8hIR_tzfe{8CSQM$Hc47Y z8e}-2jcpNUlk`|Of0s+&GqDn<{k?p7DU$X-n%v@qgbo;Dxm4OmLQ#>O}jfA#BHW)jvKhr1jP>cP5`2uE;!}4kd58 zDYU_}iioKa5U%u9z5FqyWbGiu_KKAS1n(!p~c-Nmw34)WgWi%i<9MN#&VIy54 zjel1;($xeIk1P`?^@P{w6v-6geFNyQz_UoXyRuvF32U>y7|M|TvL=D5)#%IC#gw7% zvV@r*s09J*q$a$Ra}t=TF5~l2+_XGg?!FxQAlkr`&!!_x{8hfxIN-6neAvPaLdLLJq@gvg)MphpO?| zr`mRI-|-Lq{p>20rA{Ab2f=|fHoD4C;94OLunfGq?bH4(^v>dfZrJM26`@hm2Oun~ zLPL$`R~*k(QafiIp7xnM6WhE!(R>a=NC$ecK00&H>R@kwWc7LPqc}A2R$wGGfs0-U zf+@>?6nA*_v;7o1TNs+5(G{+VTDYEPuKJ``OL*tiFYXjKozVI*>o@^(F_Rj*4{^~_ z8wZgElqb@BtVNj9*90kwy4~G^Z~~0s1O!tM{wR|TL8watQLw_@Y?t}kbJH>QTKfXE z0UE{1xa^n|#35pblgEk&q6Q5ecHJLniLeesJp6ZW=TP}U1SVYe-cIdKi5kf?_oQtQ zf+AAnZwq%G<$Bugw00ca6OIx1#;&Yo`GSWMXvT-Zq*5ODI{`dFRBYKMI|G6fFhkuz zRK80iG*JlMj+Gz)X7MGsi?iBm=vZ}5&Ht87^CH8a))BL+vkYSi>WC&5sjX4Jf{%upnixg$uU zGXMJBPm!GIw5RXgE5LZVp3f@cYKlZzu20hr9RrhV?)=*G?so%8#kPJQVy7 z$2{&zY{V=n=6U+P%yR@hwSxf?tOK_|5h(~!&GB+-81y3T73H+-_0yHm48HWqw!AfhtlZD6A~a$bfn`C z6fPEhZ-Uyk>=c%6-H=m$bf+5#XtA0f)j+8dKbUv@uZwO};LNCT_{^_^5H;8LrPEFB z&&H7%}vL?;M|@#79cQ24e^lv=y${|APLN z)D0xE#q}>b$UNxDD4E;tS{}QIHGh6aDm%of*=xCJ0V#nrs$Oh47clP**$dAFltkE2 z`8#X6|LYTexW*f*SMpt}v9DK+p+|4>j5#qR+W>jtB6Z}g*us^YB|*|~GyhWL&L*X1 zS;5jvMUHeM>1-UYMDu=*_y9(BG5*_fwd%lo0g)Y;| zPB`nu4~;I?R}@c#rG{FHziTAXmWGjIKvd&hX#W{E4hDfDBS|81ct#OH$%|_VqE@v^ z)(Hh6YrM1h%Z`KuyObuY>$hGuP7Qljv1NX>pB1I-!&ZxN(Y=p6jYDbo`VIxqv5w_f zKoA*3Cts~vi~x;gOgk=3edBGLe_Y$$Um13 z2dxnpKZ^`7yI@0|T_EUV(yf&uTqBRFS%Vx|0a!bC6n#3_*5a4-g#I2Vi4YQR;l9+; zt25qL-XYF4E~ENhofFL9gBT#N2(hl3d{Q38Nw<}-arm|QMbMbXM(0tVsRBS2RWYIo z`}L>Mp(?m&dZsdDJqJFW$BAMc8a&p2yk6BZM7qHR`Nx7=yL61n^KN{QXDHjBSp~_Iv-s!Y2@tT~I z!4#s@v#UQvt(0{-ouS6#9Y^l+b=dg5i4xa1b@*_W=)$ z=g0W*&ehvb$U#K>Zkuzyd5Ls`7EPk|07ZK#VbfLbYhIS0T+Uv-owO_2@yJ9OIjFiM zLGKcyC0>$z(RRJ8dw z_*qH%;{`4}jidin*Xi_YG`BUQNExAr1GcsnZv+yiaJtpfg1~?>dDvG13?NXRM(F+M zgcHW&y}SnkOP^)H^K77=*m{21yVIp=VdVa>4WI;-aTSb|)wU%?RqCAdH9>S)Gx;vn zPSvk&GmQ?r{P-`4rh)h;mhX+F9y~*UwJRH-Y1kn*#4v)(F`M;&Gueu~gT7HAXUM4p zqs8q!9s1lBZ4aB`_?VDY+l)QF<$`NJu4qq}fiH=cAYxpXn+Gr{Hvg8W{P9O3&KGuY z@kjlis0=wbUrd^c8c%(c^?z;T6>OZIN|yDndH?#OYsuizqkF1~5*xP%>{z6C%K`pR zB2aDi2~P7-LYk~(g+HGaFKnc(S9WuG55s-mx2K6Z_POr%uX&`$FvIT5{qxT82fsgi zP7b9Q$j|?^J?q*oPrmMM^x9+~UQGRVAaBMyidZ-EN%=vVJNE|qd-toGI0A4v7!6@S zlsrAjSZk&U?$|Hqw^PIe*8_8VvDp{wfDmPh%Zogwi!h!MfFT4~!(kJiDUqlz84(dp zO*MFV?&fF)fT_9T3UACPwb$bKyD&_*@#Z6g{;}Y_?HnH???``QC|;vgKH`;CHSt+? z|GDkw<7EeV;12=(K`39CssAA#;_@Vn-o8Y8@zwl`A<3ee(>BL+>N;x0c3sCP+OK;K z1kmu)Ri7zwnijqA^I)IKf=VAz87D6CS}zD?D8-J*AdJ=|xJnOo(@(U&QBHSl$pz;~ z!&r0SbA~!#^2-qNfk$_M#=}kVXQd!VBNot;3Hhon+-hn| zyr(?o|8%qqe#zGD*E`%qH6XWdaS*6#TAtlr_qfv4ZYXdJ+a1*{YL=10N(zX|ZQK}y zU+JO^Zj?vVy9)Lx>xyiNX>H-FMv0K}q4f0L=0$t}dJ!Al(1{uOCKv*ikgRHGp83dY zWvEKQu23R!r6^gCW`C(4$yv*Rs)FhY@JJs$d_ilCzw3M%;y&Lj(MVdWTr=&`(thdO9kkHA9ai=c+HwyFK$#$v&|0-ZS;|Zo_2WR6LULf&wWW6cf~DpUp*@Ny98D zFnrmY5jDuiF%Mz#^NuOjkaaQGPp1}&H?95^OD3iQ9P?VNA1zJjxD2v*pz zwJo&$4#i_5jB@*)CyP+#qbP}AIWN>5nX&q?t0<_%r_7d!UWXxkl%H z_ShTY(%&nKoc_LSrkK8X34!S3Ug<$;210oh{3f@)>U#uF(K6gR(`W)`*YRjDSEu|H@} z?I%0I%P$J*knChlT;%lK7H3mwSMdSE%(_bQEXOK0&qIUb_DcE{igMXy^KHM)A-TUf zJ0@WJF)pJ=_I;cUx+gDxKZ^=ZFClmq$c%J@YHSwhXDwyA9JtYa&u?Y#P&WDzyUH_U zt8G>hx@Zu5Re*>A(6HL4lx{ScfaiRQUA#@l@)mHGhIWPo;<6gKqr+Bb`vxbfJ`92q zsBoP6J(XEX?ZiRgi}u(OBUsWPL;(x$y525I=>?JxqjVBI1r%XBaf0=4=b1S+3*#>y zDlPuRdx?>hZ7GzeD(kyJt=4Fw{ot@Dmq~DP5ykfm7E^zg^kwr%+H5#am;_F~`j^i| zZwH9;*}Fl~qqwZM*65-po`iDj$$SEZo;u%qjw`D6XR_a#=7&Z!L4u%2z>2u|X6m$? zuM%cu2E9wdd}aKLb)PTFyF7%Sy~cJ{(s}QT9@5=3#rNZ&L@&aC3!P;24I{dz;q(GM zp`7YH8fq11rBM6@c{5KH`eI2@j_5d>Nh#si8wN?PS2mu+ zzBVuYWSwT^!dlgin*p7h-4Sv0?h6}WbZ7g|27Lh`eYO7ZhFpX2a4R7+4)~=wT8n~Y z(rxMKXr97)%1pPw~EzdcstFz;#e>%s|V)K>3GFzE3gh!iaMqHRbs-sEkllIJp z6%Dx*|B|&h>kOxuzr78ca3o@K2CgLcRhL6#q*c}guP;QvfyRsit>1*m;fu##h&i(O zj4rCR)|+Ar`{&4e>TpOguy+X%{|8uN=m()Y$C3*2TrKF$E2JQs+MHibSEw9h58?0J zmdCB^5$2+=@T$2HwG(((mJzo;uV6*~MCgB)(L%|>T;o{k9gzM0Gc21h_{xy6S2hH6 z_2S!8^Y@FG(+Ha75jZW&xC?ejuv84q;JbELPxTY)OD2aqVD9>U5Y@fU*PpEz6jmSXpdTo8yNssrpXbGF1+hR&CyJFf! zv}#Cieb^OMHN9|Vj>cTc07(pOGN-F`lbH~%Y_%k_c?WEv@(AftPf4Ahdic`!! zidko-z1E_Ar?pho&BH{8nM^f`rKQD?WYAT@?T8XBgl-y$VvBN&8+752A%9<9A9|JL zbD~0*ZpxU4``h@{WS{rQjj;PF6CbU<*z^xca8zccM;ra`9-BR7fc}e=NRT+=198Bn z4)>*ZStzMlspZur22cx+*tiw6f_kvHmLckvwYkv6b_nAH9oN?de%{whoC}Q=OEA{t zT0z}RB9iDn(d5}$>Q^7_>~2wzUr~GG@S=S@`8CCLtm{g`(^;=^G3Eeoe5+-iY&n6x z86yD${*1$m)MRSP0z!TRxHoU{slp%^hySWVDm8PJosb65Lr45*4Si;b#@STOV<8{4 zy4wZUy;Nei!mr$hvKB~QAv$V$nHZ(?7$#UzawtNVXG|)ArXO+RYgPOH*`O18fqM+^ z@%jl>bSCu%YWKq)oE0WN`l3e{|3N68G0PV`p&jgi)1iG~6Nn2S*4g}eIwNvS0lKj| z*Z1gGD5HIv6}JxAx#Ea5zqrz;dkFou{)b=0VeH9VJ|_d|p8VG(ql0u&)pUL4@C96% z(37>H{${`QAN&XApr8I*&bLy^*O;iBD?hjmqP=rr4H z^1l_M<^oJbrhZRX)WcRSt7*tsG4g%*`ViYMbM0H;oTZgoNp*0obi|t7vePD3;$oR;q?E&26yOAiF$#^ zWRb^8LlT~H*jv!wH?g;|8Y;>vDvIiwkF6cCtJsVL`%LODh>IjgK!v{vsU`Zbt>QF@ za}PPV7%df6(3IJlX0I3%p`CF_&-UCP*<>q8@aQwUPF#mr&5Nxck9T2hMJem2ttOgJ zb^KH(GzU=}m)9txM?bB{Es(m7^Pdz;ouR}sw>j+dskzWt$ug{R9?+scLK&Wv$ zaBO##U`~u&4`+BwVI%A>NvI4w7RR-+GQ_K#Pd&9n4=I^3Mnb@vO$Jj$XvZIKA}I-= zL1i$EPiXmucsy1jH-3gD><0m%HO?y$WQGuHS}pcI+qT`2;!w5duo(L1G2X}DrGLy` z^eK`#-KmJ>;e7+FjWZsQ0o-;zNRu)O${+6EoE$f`iKj!Sw?Z| z!DC#?h4GYMnIE^Z@$H&A>W?pkati0D-XB~w-v=zKJFScwfw%F znS4f_OI4F2ZcOq%L^|BopPAfse1vFiDNM1b)h#=mn&+Mnz0SjXa;@Js+Y*0Be(oKU ztQFNe{rg>SEyuwt9IzHZqBc=&xTW-FQFIhh|1Rkbkstz{^A^&g)%&QtLqbxU_w_ObzMdVoS5msdstT41Oj0DLmq(*B1 z@)&_UEcTw(-SKAnL3eVP36BF{wSMHnM=QC3F7V*es+I0g=2pi=gRde zrlp3HrMjn2nYptrbPTNt2vCZ`)sNP#5hsPJ~m|)0~bF$eDm*w+NIrN z<@?WarQ_Kw;fAx^y1|2ArGZ6`_`^T%Akyi`Efj%GM#=Bngv?$?$JBW@mzfEJO9Qf; zLk*h4qP6nQXW5=V98B=I+noIq4>puUAU7q|AN8{%>dnq)fw*P=K)<=&<}~5ShoANB zY0Av++lY$wTfMhU(|c^yo1`L00pTJrt*ANIktkLl|GvSxS{RP(q(G{2f+6u|Ku)dx zir~`+eDd2|_~h{ii)J)<=5UNFF&$8p`oQwx4W(P<-W5`Ukeh--v1Hzt*)`) z&DDTM2xJKKVb3_a!b3KHyhVx_>c(VXYxAF1d@|7f&q%Iwwo)GnwSrnEocrVD70z*4 zotXier9q;jVG{I{ z`i;+GR*C~cbq+sIl;*2bgznkHu-*V$3^IkNcq>GqP}5i;u_vD*4-g}h$seS5_^z$V zg>q(U4ZaF}K??3F)5M25qZeSAI(SvMREqa{sRiRimuW5THVoJ}eR_wFX13GvP$xa6 zVs0D{ovIZ@J%~e+*n(I}bB2spsb9&f$NDP?H>E^z7{be{+Gn6QTZgub_mvd4F@qA` z{ZADUmTP^Zx9@oJF0~?M?F#1uhsHZA4|F>joAqur+v1!wB|aI^8s!%2;F~M3{Qnh= zw;2+Xn%qUfj2jU~D#kZ5tc8rc3Vfh(({!iwMIp7gC{tjL1ANzCk}iG&I?&G(;SmAQ z5@GD=&&Y{RuW^P4Y??^84f1!~x;0Od*)X4ddN!BU6q%m?tZec1+|k}#DxXqaJ$n8r zig$Dm_eUJNTe!r{Hr&vNLbK#kD!7UiDODdUZvge&rSW~l%kuD)6f3MrMidNlrW=x# zeBDR%J}2Gr_t1M!c_Ac>92mE%^asq6HP;P)2bQ>l@_PKGv)vL| zr7sM3s3ZQnMKR%$-j8~xUa5WvzxxN44D5?jI4e% z4>k31r>D}amUa$0XB@AAib2aawyWeba=J9|LD^@pY{3N>=${XKJ<}4m5Hl$4LDkZ zC>ZBV);*@$T)I2VhI)^pEes+4`^l|=9(*98wY|}mdE3108rfLiEzHU9n#H#`_ytb_657gK6d$ru zv&LaoTbY$TYCaR8uYDeITh3Er8%U2XZm$WokA6VcY*BwR{30>2yP$*p{}J^SU{O8a z`?I@rOLs`B2q>sXE}q{4Njj zxX-Oc~7X6htHz6QU8f2IFq>kckKse^OH{ zc+?vFsFZ{A$};^bLd(n6yZe{*I<+KAhdK@~9KI~9Mn&o?(P z>Khhc62*o8Fo5g_IsTuknAg`HqV6DGJRD`q;;*`ww9)-}s=GYZMb&gk^i=I3QQ5w@ z;h?WtK6|7JqInL=g*(n1}`42y4vcdp3=ZkD)d!;0@)Z^R3(0VVbXq~rSKmVY?A*tov ztjl88m$?ksmY-IRMR9LDS+6C#ePvTvj5eK~!2c?1g{tdgMF2NRkjnPzvdFJ&oc+b| z%4=zJH+xI-PJFsL^FkPwHfHpb;?vH_15C~9Sj(mO5>aIS{@XCdfd`DM{4~9XSk23g}UXDh}s+WisVob3EhYHHb~j?5LNffmM5Uhu<4cWIo5qdtbX>;H-f9Wq zph>0dn#E_;S(Nlek2PkHK5uc$(dgaBMu`;ZoUOz#g{eD)?~e#Ic&sm&ysb9c3PNd~ zJm6rs>U%#iqsdzR4OYtYHbRRivvvsp3Cn3h^_ue1`ENH|Rq~QAy|`}?%`wu+EqHtC zqLxZEtceC!rXLKfy}IG4FLLA{Tj>{&3^}(_HOTj=WYD+^b2OAcQPP6Mh*~G z_I?+CADq{DjViV*&GX#IO##}m@jKWuuwLM~WHaVrZmrwP>bM~{Ta|v(=CFEuU!j%i zTHwR=n!%M@OM-b@O>^h<2smAvgt=pd;Xt>$UVyd4Et1)fSCykqQJ`WTuDv!snO84++cA$@6 z%WIQFOsW<8R?Sw`9U0+cfgmY{*|hSWyRWORJbaf4ptL$(=5DuA{E|jy4$q~_rsQrA zyvdCpKU`fRWTXJM{*3rfuvTj;AwU|Q#%-?4aO*0Q+Tl^ymD$?7d^{ktXC5;&J-cA_ zO>;{og-BP`{R)ey%LfYJJv<7LyCJM9`)K;@Sye_-O?*6ga1yay3q-Q&~QLq}8 zFaSIz5cy`Mq3-lGepXWT94&I!Y7SutH=W?|zE_g8xM}si5iUj})F$-n^l`5RQ&8QM zaE7NbFgl#9?qsVeR2XRu`ia^Mg5D$R1nvXY1`^QM0B|^oadKYCFN@qOt7%OWyA80N z%;JhAZ+^ZDtTF$2vfnhIJ3XzR?|EXuE@d1}Mj|!I=ykn`_F<7z(B*O^Kx8_!oK3hg zVCHxW`Ag1)#k)Ag!#deJu5F?1xB3r~0Ru=mi_O>bVs#wKZWn_KBY?6m;DnI?6uKF{ zv0_f_m^L?P!>2RO^^X7Inf$J;tCAgTzDW=HVdI2u$QO+GDoLwz73h;-{~n#!fR|H# zZ)jMOJ(9H>s+cumBL81f-zn|@*YL@<DaaFvDnA7sF|)2ay0N=8e_?58g20#@9tCLYQtKo=Nll1 zat(31b0Nsa1EQDZ^0@aXscIAk#b^=3dfHOl7T(21(#5|%N+^XC=K&jpa?fh79lr^4 z{sShlXTw4?DItNy_%gA2y}=iOLi?p3W3C)nGS!GiaFpj9TY1qxzOVJ+p-|QhT6KAEc=v zd}HC^w*T-X$;2U6d*TWC>bzxN1R3{_MCObWfX6YCjF%GdvfGmjh4vbO$+Q@y%amwe zGAzt26Zo_8Jp3vD*Jo{DkKE!8?Lm3Wl`^(3M=Ea>4Cd}qa#Yy1%a5<f=|ZpP9ui zcz5(^Ui;6l8^te8$V>41%V8C=*{!zG5c-eXu)xdtf;v2V5;%mgHnuPlh@*B}6+p^l z&sdzA{;L^U*mihuZkn`M&HNr-cjfN$@;z8+cp6(5rJ+h2Tyyi}%6=X*X1W%`O1kbk z1k7)H!SgLo8kJ3@04)(<$LqIZWww5ziY0`2Gp5(ey4+`oG{T*&eF@E{N1i+WfcyGI zjk`e4K7!``o+p%M;zyx1ac;NiYG#NDyWr?XQq!L5pK z2yD|igm}wInR9?R3geVij;Gpivt~t-udZxnQB;uQadz3FWdH#d1?K26F-;<)$D0O| z_cHYg9)oz~H%5u^pDq`7ex#n#jW5ElItw`ecrAMb18OdaDSuSRZQW{E{uV8Na@XOV zzS&leged<*TBm*urW1JsUbjyt2siEcE-0)xlLsd{XY;6CeiYeYlaa z+{%E_>bdX=k{7GCVfxqE;e4*n>5nT%x4R9Z^hZ~`?=pwsT69XqFh8bx1(9mb=<&2e z{t?-nE3}DNGgoiysWP&(R)a|X>{>;p@}f!`<@X;HzNA!cb5(FOlbn3NM~F4qE92Ou zldHP_9wc7pi!PiU`xTc1(6NlC1qv6wulf-JOmkFJXn6k*3;fnD#OueT(zDV!H~P}K z0hWs7CO^ZExjotAKM$;pPW1-uAK{t8h0TqC(|%n3NKqxGB=+&ZC6?Cgy{RU$X0m(n z4Ln3xLj!hw@Jt3l=;JbLdKqatf0F|gkYTmed(t@>6uy!m8bA>20hbSvcJXM{sP_4< zM4u^FIURvQUtVoivu#1ssrgb06vGGB7=6P;PGp!V_2~d@MdC*e!;DwU(p~-&18$+r zPEKa|3^P|(>9-Z^;*ts{0QPI;_X*cu^x`^jf=^2QZ@N>7=RL|@>NXL>%nwb;hB5&n zeBKzXQ@4~i%>TAVK&8a#(t*(_`-xFi0kI=x<^dYyC}7+;m!1%08m zch@IHU1hx}A=Ty1_3^%GT!lxRiqUUEtNE<_Nea59165+Qr zj8G&PvljK6I~Cz8pIqEk%{BHMtcEl6RW1{vlSPu;2YGu|DU)IBkZt^M&3{Bs9DPAt z+|^5=&-|`2Gs*AdU#QqnxdZNB<9n#V?fhz+Od(hp1@7tz6FmJ;7JQ|Ts;VOM)0H-@ zST!q-2|_97#SK8a5zGC${EjKMVPgm#UYORG)ijAf+4Yc#0qxh+b@(HFfLmz9XS;F3;Jj)f-akPh-G6io8fQ$bs}s4ZGxe$V2L+m8RgI2tq6 zVRv*Kp8smf#O`1=kx90jy|0f!rgZN{N15{#oXk2Eg%swH-Q3Se!>*|E7VYH07wAEO z(8S6Ms;jQe&#wC9{>n2pS}i)1Cj{u$S1va_23um9d+!+DOvE%WCjEVF9?_4|&kwv; zQ8JPhcPVqE^PIR=%IROv3lbM6E^$J~Yx@|RZl;!BfO&<&{t+0BKdg@Vxq*)V(s)-> zY3NTDM`@iAV&uCP^8(jkbIr~}QyJn+nwsNv!_vjez&JDT5v>!XW9 zw8&u;rbnwuxA~JZ@9@Yi-MZK}3Z?cdUtI(b_FoMD;31J~6Zo+2H5j&eodi71Jmr?e zQ^fl^)8=bHC-Io+kvHhCF0e(#Zp=TRlSIiNhB* zbKNc=&WH(aQee}=Np~``2+!R{6_RDKVVA)DUOQPtGD5yr=6G{y&$sD8rOZU8DKiR- znPD=O2iJi1l}5KQa+IkxhH|{$6MKb0;EH4E(_i+0`710%IE?@z(#7b|qNvWPO6v=d zw+)6HZ~2wi!*?}tS8O=(_{oLr>mN)+=Jf^4YF{?ne~ruTH%p}5P+G9_I)#tqamV2M zJm1aCcVBqeXrZ}=Ov21^n6V=gs&E^(r&;uf&(+#W+U)#)T^aW!i6Vh zam6L)gt>yOapPl|z4iC`6gKUqCe~@dM(+)5E;Jz63S1k@kDFA!Vv@3ltFZW!8|Q1g z{39QqfzD*OQeYzz2J&agBZO?}+X}RWKzwb(tGEg2xt*W!&AO2|#T)L?CE)z;C|H{2 zxfQDCP*d;I1!t-xPX#d`fHkgr`mi4_?M2r;LZux1q7e6RtX2`(E%SDl^|fnNxUw+{ zi1EC(B}&Okp#&B^nT(2ba&+L*I|}iAHiaNLDE4|4Q2E}>tF5XzExc{Aqf?RjRNNgP z350x1Eu598BK;l%{VxFJTD(qKK+Avitlv>r-a+COVBd4z)uv#`{xt3#l)PtypSSTl z*~4C=(psg|byH}-Kco2sV8ZiTS%0kbRxxN2b~l!dC zOo_%^^2s~$Rm6J~E7;!O8<4n=7P^NgfiNYb5MMA7o)Dg+EyP4RctJkq)KJega#Q`` zd-@qYn}&UaH%|VJAfUOxRQM-u7@}v0k}odgkn{+szBHX@p=$WiUW~c-TM_E0ytiCg zB{~O8!?>OzJi8beAP_k0GACo0sN*9bNKhjOoBj^{+UuO00?a}ILwEvsefNQ&aTXy1 zoUhmvCfUpujh#yUw~D=8T4(Q0AGH z*v8F(NtW{bb3ds+=Eg%~8JM=J$R-tySb(DBpyR{Iln ziMGS!k<(lZ2R<(+7{!)D-HfM7Wn>hM&1}8a(xqcVY)+EKy{@6E09Lbv_B21bRLim3 ze=G5~Q|%3s{F3yyo_Z{dr1{e6%1SB-b#|vm2BNpb#`8B{&ZFA0!!rnbu$h-SAbY4=-8)+zRs27jjgBjn8hY4Bw*z6 z85UK{VcD^cL}B+O>4NGs3*4TX&hzNHgU4aX8@6)~PiZ#RltDBCs<)-w0hl43w}(Qy z%^zFt#d9*7xs7*Qv7+m}!*_klU=4hHaF!)x2KD5C)}_ct~z$ zu-CdB^1>RJvxc4e1p1`c5tzD$Q3>4_XPIopu+rTwZM^|m+|Q_S)?Uv5>~-Tfnx`U4 zeOx(@V{}O<-^))xj#n^E;`F?-XAU#~Fk|_(FjR+}CFbSHAmFT?ao54)|2LpHSL?Pm zQb@A7;E=Pvs-nZLBMHr}gj2O51V1n21E}H$nm4I$2JQC7`^1r5xOT_R zSTcEEjRCBk=;<|_%Xs>uY)6)Bdp6w3FYtwZkXp_4tq0!}EH3hYQ*5-VsH?7K+eXZ?uXT2G++9d%(?mc4-DkMkuk+)5h`m=7`yCg}Xd;c$i1P3o< zN&z(c57)t@1U5ycTTf6T*pAxI0{`P?=>8v;;S5{&ci!_SqZcj#=MG_vXAr>9g+E5H ze2Fnm9rxCenIO3m^Rq{fM7uw1@P)GNR*P0l)w~vUptezUvl3fmdXT}sI zmR^W{y37I3oOHh?*Api^!T9u_WHo)~IBstblzSmzG8%gSeV2EK6ZkN@&`IP%Ch3pfVRwF0#P(+?kv`vR8G*D{Y&0F{-C0t#~#|f#5I0U*U zR&6dEipci*E+W~H>>Am|eBFEQ9GD&>(KZRv-yhdJ9~y9w@yq0Uyy?0qRPa~*?URll zp{%o=He2jgxurwj4qC1n^aNNhGnC@o>Kjv&e<3T*2c@@!9t?af2}2|^69JPByTW7} z|2-L-zi0usN5q>wBg~thiNfo?Y9awA79uGaW4?vxjWqlHslqGVSRg_lwzI~1!7~M6 z3T*P|#AoZJmO^<%o&#!u*GU&Z^5iFBDudsb2G^Y7+7GmMx4nE%d@P}Aecy}32epoN zn2B+cXUdrMrM1B$d(@quF=Ssaxh^EGPo@UjD4W8#{E5#JWzhGP3TBsnr*j7gV1|Ij z4y~XX)&nER|1xe4cxh{M{l4sBDc?hXV>!FDstattbq8I7->pv|jHxbl3nO~VnQ@1^ z@SRFz_|o)rMfNmf5cVUnWyu@12>oRBbk_<5PAvwXaVZr`7c z{v=|pT|w_=LGu0DV(DJ+m=^Dd6y`wFc&lAPU8Rizi>5?t`yi>%Gi+?go-jmf$P+U0 zlJCI_z6Z8+oLB@A<`{y91SqMgKCd|+?VDB!2I`x`^hnkI7?(OWD! z4> zqJAZ>e$ze~!?T|Jg5ysbGM_5%hX2fF&%A za`ge3NO4%IYgD^G0q`$BDRY|{3TBMF2NlynA3z&qVBiu_%D04DEGxd3pa=OqK&$l& z9oBew#?!^uC)U|W>Ai~o(~3vnhT`3qaY&41vLol`B1?tOtYOl3-Kg9W(|8a7dT;_l z5PC5`C~ki`{Lt$D5KFp2y)J6{&I_L^yfoFCU#CGHkw*1j|FNPH_XK&*EiFaC={|X| zGbRUzUU^B|pP`8q?4K>pFQt>*Bv4#l)8tqtbBhZf5f@>P;NcA3kL*yeua2V_ce7dd zue04#X2L%3XL^X7<_IGLWi05E*%C8;&N-x(xOe{hv&Y*fg9-c5(^2>+JMbV*b&>um z6x*SqqTB1U_0-3&wi}A z6$z{O&#x}uB!+Ppcs&u#hIlq|<>kwKoOAz}v>XQX6lL6F=BK$)v^mf(jC)&QzVW?6 zwwrL*S+b}0Hkv5%ND(r17ftE~+}=vWye{TB=Qx@t zQ@+hv&U|DEjLVku~?+<=;}q;Mjmo$0#V!eo#6VV7|i6sRS9#|YB_0{xj+%??|&AC3-FVNR4K`g4Tx>i}|? z7Ytero?ac+`TOQERBpqa6ULgPjIPo{{;(P(f5PeS~h$o#r20e={*JHI1;4d%gV z^(v`WY3Hgc6Ws*O3L~2KEYuiQ=0FR-8vLqLj~fO$NqYFu=TT1pv>+oU7kbp5CM9Lm2h7mZ*S?(P5qCjoDH_bYl z4;vb+C;)-A)(islfRh4gq?fqbz}w5_j(h+QBR?SaFgyKP{xyPOQZ2rl+uVb*T{@11 zLBq>Y92F8Xv!lP9Z4Bswb?@K1t+6YX+qn>=p22QM{V}J1<#e_n*vlCFBmn3rpq1Q< zAB{}G)4F?mCMt2OmBra3J@6%<0N4$H52!L2{qgx}0XlIZ>j^QI3awhS`RMnrWNA~z zUDh!?Q)aA)kY8xal$^uoW3f;pM}j6ro&F&;U`#Wo9-3K>o>C*ePcsqKKNTf&;;iGi2jjsEZvgr zz_9_ahmUm+GZgEtBnMqWla~O7oit`<%|(TZEsh4lL9AVZR3-n7?BvI&eUkSZ4*^Tb zRH)?j8)N54C;M2}JvNdnf@6(vGjRGq+b%TZ%3`i>Au}IGA&QfyP~Ohb;l9A%3t)N^|BHt^5o>}8({<~@jhRx?u#C9A#Qxyo)`A0~FrI|x z&YO%8A8ol%-%4}+d6`2kB&_p44*j*()Gp2AK!dQREJ90c^*r*s+?yyqfx<`+M~mtE z46dJ(MxyR3N?Ic*$t)2G_ZxwOKVZhn-TUyE4?%>7eiP&*!7fREcTN(Z?`ge4hqYJe zmyAZ@&xBFIEeZFapMJ@R%=Tuc$ehBGATe_1i?TMx%bNEG{cnkCfxehF^jM5h%8lkz zAkOj5{S9#|9)#3n0=HlGbxcQ8=x!z72+~cx!=))fo)gD4^lP2Lr90-IDcBnR?em*u zLanwLZXXyz-xY4>musI{1L<=~d;wA4xxV86H(OtCRWFnGo;*k4EvgaQYVJ%uE1}0w zvXBiX{`I_fC_!S5_)Lkp0a~X5b_CBn3#0Ln^C=0r<1HH-i`S_C#Dlc73mDd1@9Q&|VA4V&C*^dpRY(Cbkef+sQ>pprp$9V+0QVOu%1e?PSR5=WmoMl> z$j1_Jwndi=WWDwBOa_cQUuwsn()IM-c^i}R;j0SCWLH25F&td6mriEIHa2<>HhVZM zh%?&Ve@YZQd?GKMpj-P$IGr@*pI7$JKD;wcQWr&ucU4WC<{~C@@M@u}KupI4XFt({855UE8h&S+V;nwzJwzK=u#b1=klk05__hF?G}HeJ%Gf zJ4Rfx?)03Voe34{mun2c8s`)Fs%kzY8BqOvdo)_S1c)T71eWnR_t@;>ld6su`N|u~ zA@~8LGl8dj+ynLmbYxm#0ga8GAnXYs^LUXfoPdA@grkS6Ua7(--kLcmD-A*s>|MdBzKAV|J&dN>qXm4H|LaKDpkJcz?1Vn)Ug3V zy?Gv8l9BG-yPT+s7{pbg0Ga132z(djxn1)BBgFJGR|f2l&pHgD)RRKP>~mKCTHG`6ktN* z%pfX)fub1FxLdG1${pNo_@jvPgK8N1qgtHtgwPEZVXo_sP5ZG1nW0#57@35GzM|Uk zAPKFlN5&6x&sPlca!E#^aRBQ5u><{otQ@+r|w+$d&gi43%Mye0<3MmIP3 zU+m}JIVYfG4)$4+4HyY9scmh2#303x_dfodmk^3983V_lprjThVpGcxnGjtoo zM~1qePF-s?XC#OZiy1qZ*4cAebI}%pdJ6eFH)HPdv;zyc)~J{-)Ch*UyPZt!z?wkx zgwY{+wsQce^@&kh_rWd#a@ntU#lXI^*HW&+)ov&FNxZ7@Mj+cG>7*ojj4Ht7pZIz+ zgvDF{7#%!z%SM)w`z}SoBN;618h9*DiQk@9clW9uh&ej-Eu0toege^C%d)9ukA>Bz z1Bb^E3Q}0|N#^+$~IZtonbN1om zoiz#QOKz=|ER^7$bsCPn{$jxAs8hwtD3-lx7=F;Gl^{rGg5RXB%Z18GL~vTz zk^(oVh9cyN$?U^jSp!VF{AImUgwM(%h$t)E4IW16X?iE?wX!C3e0u;be<^hlZ_&V| zgJ0|mOTiD9wN}C&*3!|4%X1g_;RNIv=)A%%m5@3Ebi75Om(0 zja9uHh5?p1C*}ByMwZnyO52!s?x)U5t(UB69b5;>3wiJ3E&SXJ7jgtiBXSHtR8@UV>+)rtPX8)24g!6wgC%SboQ!^|-my;`j>GdP9n;N$Suc%G=b z?$+ZvU_IC-2QvHp4xh0|LHZAh?Kc_3#;BRx)8C}WWaP`Fs~ja$i{_kKMZIcKVvymN z9fK7;bC1-28eBHZteuhmWM}JRt5HhA!?5<(%9F`ZmB4!s=WodgyrR)?rYe4ZP^%e@ zqIOsU;-)d55DEz9WkOJ)0II-cWmtgq`1-Pk>zfMUvlWWT<9u7|-~|&Xu;_6r#pRwb$_bG)Nj*qk zgNLbahTGpZyd-}3*(YZf!J22f3AQ6$1$A1?`27T|)un$%tQa1tM-}>hZ(g`?{-0~- zW~^^IN`(hmI_t-ZgyLNXChWkz90BtY^`n-~xkpV##f6;R8y@k4rmV!< zReb=ukOFVb^zQeP-HK){vkDa$Cw$zn57K^7!7z4iVKT8B&-KBM7ZFfod(AxXAfoc% z7rBs!-yihv(&gdv{!P&lK|1q3*9Iwy^}$E-Y4g(OCSO&}H$OIBBbuRT=;3i@ z!%dkJ&EQ8PFezVJu-N*Zu^#{=0N@>I=w04WzSF=)7Mz8c1Y|#s=~e9sfpu#dvoyf^ zc)l#OZ)y5o>L~H47mdX00k^(4ia_KQ3PK?v4*k9%R4DMV5L?in31>0)j)ZH^w~N%{ zU6_t8$>3d#{?C=W+XGk0cc!>OR|c%Z>V!8EGYw5rVZ7?y^zi@ra8ySPh#ESnCt;U1 znxnsx-;j1vZxO=up}@F!Bt5!WuU#e+$s2>jyt_30IP42CPe}D{@v|6-8W5Wq_6V0P z&E7AW8iTogi^#9!mtN`wr&K?p;P7&I;HM{VKM%qHUyHR4zFZc^ncyou=+`&!(--Hg zdTBR+Xg9g|;oqaA@?}T0B0&%J)y#r0oX>*SX3L+;DM9+t%$SGqz2YhAKevfMz>9<> zkDM0dCko)xQt7n5e#$b0|5_RC_)Ku8(=GTb4}1#PCdP0*sgX{=Y_qZdD-^nc% zGG-mWocQhnWg-qwquVHbNQ=Nnt5dM4e7D>N$s_@w4_66Sui1yFL=~8TO@+A^Q`pcl zT1P%{)(UI_u{i>i;yt(B+i51Ri`g+ z!38=qDnXO*wAmRoci*t`=L_1v&O{ZhYm@9H6jjSVUVeMB!uE!RU5oFZe``4gLmDY$j<@}gOFk)o7j8vV?z)5OGvQC$l8eK zUGN$(3ePJi=uvqbVr$`RcrA)eOWs2C*tS!FQ%S;p>S+-MPfFxu`Qrit5FrW`#pp{a zMmMdF?c16L=SQ`b+>TJyo z=uIx#^u>kB-*^@9);F9KM$+BBd_7IWAlad({c2=x;POzN(Q+V*Af>n)6}J>=Eek0Jd@mk6!HL7odX4uVUN^uTh+q<-u^skeHV9Z15u}ZG$Q(ZLWWD zHwIpL1OA>(!zk6Ep6;d?-;{BCA+Bf1o_&?|D~msw5-RG#=PA$vVRSfnA_Qc>QB^n$ zHLR7OH7LeEj)E2bzBdpo{Zx9b`@eS?Z2ZBTlGGlVm-^UgXNq;OpWsg(;Im5KfRncs zdxV$Vk?4DeE0tCr>iVEazRYImo%%9=TYCBS64EM)@q^{E@*x4owSvnL*?S(5zKVhu zra3rP`(afp-c(31eir*&s|%62nOj}lejXoK6A)mG{`zfS5{1QFfVwpSm?Q!`ug726 z+0S%4QNp}v5fE1JON0QN+rh@-TVqnl(fdEj5_p4^5N{raeQawL^?mp0;}|9zn3CHA zVGpLW5mA2V;2a%t92^LN(DzY0A=hrw60bk{m{uKZcgCFs&hf1sY7+KmBLaj3OuG}b z5s;Yd{PM_gimB7f77wrm~ftdzg1E<=rQ5<8^0e2p(eL3m)F&&ofX`WVTR?= zyhbk7KmsX9Gx2-i%qlC4*!bELy|VDd-7WSLBQC%*;2t4CYng_m02$lc3(dOQqk~+L zpY7LOObRN3lrEVM`$=3K8`+r+x>5iz(D+%$;}w(PV?i%r^gStJAn*}o`iHpu57#|^ zhorM^9!dfdpf!n{{}8SxIi-^rEZ}6qe`6Fu!XpY^qaB2noawd5-I|9#*JnxDqO{>o zvDTn`D#e86Ll;dRsK_8E#0R4pH4e|26_2y~MUwe#>cl|slaZeCi}i%Ya)BUR;l?9B zvgB>#*r@ioY;d93Swf_2*nDav>h(J|X`V!hwCkY$FZhQ{6!ET=CQ1+uU7G^#`F`;~ zK{*EfSt0Oy&W|KOUU^`kDG*(V43RO5#u=-w(%bM*$ zsn}?|b2{&ddaZQMwXr!i@HzSE{tZ;kO7YB_x?g0d(rFZYfs7YZe>&r zzq-cy1*q24<~|ual;+7;mzjux(h47)(D}`C9;y7^@3=3g>`Bzkkrdye-J}VHpvQo{ zb$S2OjUBV1xDGN#`pFmgm*6Z3(^d)$z#}6yB?sfi2a0D<9mWd&bKS+fV(Xsd8;-<` zSH5hKuW80^?Gy|ODSq}?bA{4&nT;Iqq)7ocIFH|j9cgmxfB*?^;zM45X05-VFI4qS zC^Af&4%!Rg%oRBQ_eSFJ(|6@+`ktD7rYrp#3g)_Zk0(vv60Wqb0+ z+jnxkTfLXIlLpYWS^~4*Tqthua7CmUyu2}0_QS+=#d1wWdg9O(J8lhaCw-2><1IuwQW-uu1$gAHMFSZ!g!I+5pzxN1cGy#Z0GC*xQ|ptr`}kM5SWv{GimgW(%ix}L1D;xaF0 z?Z%@&Bna+KGLJ8OYDf`J(0CQ_GzrI}7~sQ>Z88HyQ&7#9-Hh`2_X67RgR~D!p{dgu zMFZ8YuI?*7`Zc_9Z+X9@-a&~>#Z*lEJ}xuc7W$zgKZu@{Y>!%Ne>dM^Hq)JxPWZ{B z`^Qt&g_WhOw=upnG%WVD%R!N4lsAoBwk|7g)&xiFjl;lVl zqq05c*k0ex0bX4f0*5Thj}vW?^Ih@E{e+a?FqF5HeC9L*mz>N-pTP;0|M|1ck@L0j z;?3Q(t*2h=q$KN)dShEH=3Ji8nIO%R_gnLG4TEfJvj_nPmPYD}0U>?L-rjHpZN_lq z*{y#tmY74%XjV!$}~vo>JlEcSHpGPYwp_822OwoSGLm!n}{qSw1Z5l^xFN zYOCvCG{#9T3I47a|9xoEI3X}7IQQ1dcIr(~?w(YQ`%(fWHE0``b#g(4@w@&WseR~k zB6EDY^Ppxmo}8y-?2JQeIT9fIlJZu!Q_KS?bo5?i)3S$&RF-!Nr~=#23k>knyInL4v`zX{6pUJRPi{aW4RnAMnK;M{sPK5%7i>XS+YZLTZN0;ku*G`h+gR8Iv1H1;^%ps~sGXA^D4nYa4 z9KR*JOHSj6urYkCM(An+chP%hJ{wE!-M?SiEZO3~$N*Z!n%JW8!scp4e_Tmg{C3>r z>Mgmo8eXOu8To@J-EZ~+oIWhd|Aa30C?11_`&&%o!*nJakP&f66`y~W7T1OtS z;UiN3r^1t)&TBGf{R1b_UyuQFzHIQ!s{wSkTz&FxZu3>+XaWChC;4!>BTGk_5Wm`lEpoV$GBB-*zAw?j+TLU~uS zqbp`^Fm1i}okl=6fh@qV{XLkHz4KG_+5eyWrn|UPqDdBjC55zSIIzQ0xDt$TK2n?l zy*2XA>621Bv%aMbLd}L;?yM02BRWy#SspZ^vVGepMsvD*8IF=2@iAociaVbp0oV~< zZxjR_P}8g{7I0hijIC>q0qz-vNMyuwL$D5qyw*2KxUD3J>#Ce9EeX@WtjtBTw=JIj z0jrAXAK#?r@jbBL_=<3j^py0PNU3Uhl<{M!owEQSM4#jcnKbYq>?vR~YFLyh5|St2 z6q%g6fTF9iq67btm$r~v>N2CX@3epvC$0u>@|C2p`s8d6J{lzj=CiD@do%`>fqMII`X9(WdA4li=O?V|7eA>Ku)Tp z^{Pm{DnajiY2%c3;@ZiPCIu>(H#vIOIM5%7xmc|~r&wEzfO3Qt2bIs_D*Ssi*meiu zw+4KxDBL%;loi8^F@g}{MWgfdL4-GT9G=ksnH1!CPU!Jn#QD8I@Lu@g?-{mL_qCNj zs20}VW2F+}dnG49n)m=8EetNtyNF-jkGI-GO~Rg(XITBdiV}RX*_({g}H+`cfFJ526vgAK};NYs}7oV@9DVDXr%fz zL5*Joi(3s0B_WE&nezAXoJJ8fc>GRmk5nFH zq3=QdDKzRCCAvw^t0)N@2W{^@SolIr9l!Bl4^|(_H?7)X65C_DP8x=|IF!!9i30AL zd;F=NTY;7qdi7g$pb|a0JBW>i1a0xY@zR6Kk5iv5q<%2qFDc=s5ZyT+zKCR69I|AK zAF&SuM6W&kA6V(wQ8=tapT%nyQnc6>UD+ z%b$IN3ul<=S1j5ff zu7Ac0g66yYy{< z-znRD`A0d~GCZrC_f-(>m#;V9zMjELf~9*y5N*Kc*Ni|YXNBiD?H81S_Y+AikmT5t zfL_K8N}>h^$=NW3>nK1GfO%KS)@FS)Z>=7PNN0TeCO0;qkmtbJ3cOTjy!z0qg&lzh zL^x;RBr-(+x)(8OPcZV=SuWBDre(W*UpwnA5IM8aPk7Uu z7oBL#p1O|%p&&G@8<$lW-o@j!Aj?XN$GQIMVve!0(>Qap_Wxt*J;14c|Nrs(oMUD0y+f3}%Q{5J zEXm$vhLUWKm7>tHXA~l{P}U(cva`3cXZHTxdVl`c_kUa$uFK2o+~>6k{a%{4@IAtucIm}$}3FZL*EOC-;kFg8N5P`S`1pUaR ztpm9pmZKt4n6fyAPC=GmKV$fbp^$en>h>?NcFX%<<*``Okn#EKCUdyicJb=6#Y^6= zBp0^3F={539ZCwib-02M}c={(@*)tb8VQ@m&vJYzNK%I7G20E>Bc%-9wtNbb*%mIS%q8~MfQkm%J zr6*z|fPwh1Q|9+5+j`z*zD%)%HoL0wd`(8bdP#xb=F8jVZ;&{;P05d0eH2YDu*ViL z4#OM#Bn7?baXd840vPfdSq!IL%f_6{Z_(m2Vh|WjqrAI#UJ}GOV9@D_K_Dd5fQ+@5 z9rey#w!{}O#FhxlTWxP^&iGV_dr5C2NHNzkUZgap!s&zI2be^YTL^Fm39b~pU%Q3M z8EHUb84IF{*6$WXoUeXqbgPM5_4M>PD*KxFM92BN$A3toJ1Q^E?Vg^m5C7rUl$ zcDyO#N{riu#91i>n1t{f#y!q%TI+XzB)kf~VrN}(_Yk5S79%@UFbb9prDIE^xm*pI zl06f0NCNg)6d}hwzciQHVQU;;cxUe{9Cl`p``2lJl)evdfyTmO(2jQH(vKf)X$)E) z5i`mh@lL!sywSo`4At99Z4Ry{R=Lfvz7UK0Sz1*>6hfE5b@Tzqz{(LfUx6wuQH}|B zy2Y$Y#11V1#>y&vn&P2;Y@IU5;5t{I4T1bQXvO zJRLy3qvvGrRsgV&7}=qKG`>W|PVMs4Wti($%Og0tq1NrKBdS&APkNWI4%u_C8r0Mx z3BWQ-H~!R1Pk4~%%6XjybVXsiqBzvTH*Mj6;1YxlHuG&>^w#ot2OE9kWA3S*s*Px} z=0zz=8Q~w5w!Su>I&=d|qKae}lP+_+bzc+VMHm8ePo+6?$}&*PW&l8v0dYvj{(>fvRM4;z~9T3NX#fn7;)IV`Kclll(Pr{TxbfFy|?hU_9vng2@s`# z{&WcLA^WKp>tWM)Id&$NGT!Im|0Mrqi)y_R)P`4^xW7kn8qP%WwJGcJTd5Y=t>QUk zW#{10=9@?S%sG5b*T`Y|X;fWG{{5E=wB0exNZ_Drm!j*+{2bQ^O>}=*e6S7f&aZ-> zXK{;ZWCcISf{y4|zL&17yA@aJuvx|Ak%4Ocdn zBUDM9r+<&htyB=Ix@-aVdJHr!4xdqIUy}3oM*w1mcpGzxoSxjQb?w8VoKWqa+Yv1z zR1ceF?4`Cx+<6QxX`ST~FQcbk`YGd^Ox#93Z)Hq^`(lUaho6^sgT)L;qY=QUIM?jrj}9Mdsf38IJ)6VO847yFx4HZ>d?2nVEsdv(5)wq{n0-+6v*(+ zSROGyUb~Iwn;M6>iLjEjUR^?Sqiq0k<0ukFU%gqt>Q{==O(klhUCe{KChPTv&?=7(9XDVY|Q~g z#8J`V2;mHr$0eKATa5(pGr8DbJW6YUvM~%U9tP3sFat{r(Z6a#mMSGF-mvl4a(IWZ z9e5M^KnO=unoZI1d$J+C^A_znA)H*1XG0YUb_bp(+UQL4zv1jp4c!(remJ@w&ZO}= ziC}VW=|6o6e4DVH3KDbV_6a^p8yz#t%5n{uVl~u&ElFwX6W%)lcjC-`h`?KB$aa}f z*sRDKN+nn@0ktj8o+SMsJ9PA1iU*lj4U`y8WvVfBc@EdKbeNZ}$9i<)fJim{50{|D z`)<8PET)O(uE1o(*CEPuo1OdK320)Mv5RW98D z?&9DeIbfGjyqVlr5V{)#nS#We9vWe~v)vJ2C_l2+GfVJr>YbS$F*)zDBbGORsq)Wl z?N%#042Z>BnD^H)@0%`Gg!s;WVVIMuNi`Qz+F3bqW);osdiXAAkn-Rai{AQ`I=hK- zAC<5E00nW~_dj;bdajHxKBcVDxTw0)F+GUO&EdD#NEZIEoB**@^nr3kzLwvBw$Hw3 z{q^8{*XmXYGiOQKWL=#_9fL|&SDM7*FWQXnrIo{u9{8RPw=5gy2DuCdn4~L6u2owe zScxejhzYae_MgPb7>g5pdHh!WJva7t>dZE^eMg-`U6h0`14(K4mlnFV%2Gwf=c8~= zjP}Qbz7^4GtG`q!+VIdfeL{XE(2#Z4sj5!qfbZVHVrIh4K)I2y!V0_eYZrqEFfa0- zR?o{(5-guGzWwmn-5eo4AH@U&L0T!ibO= z%R@FXRaGmZV*y=Q!!9tN4}jSoF?p*z`{#*mkP(tzaDQymgRH|`yKB45tqA9 zlic_@KKEk6g4J7l*6J^#jnwZd>&SuYvjfWyuI8`P*lr9y^sp$!Q2l)DuF6?HX0cx1 zlor7qh%y@8xG%M!0jqUzUm%=Gd0qziU<);(O2}@%d!)YOMO7p|Y zorI4gg}U+Gk4OD8{>cibtLugOCDK)e>+;Ek2zb_mImeUJSQtVAyt$I<dh=iNoqRl{{Roz7VN1C0B76)^dLb0gP+b)j9}qHO4D5`>PT07js;j* z*XtQJ4@VnDENJ()sBv##9a6Dw4uHoggk{|oID$Sy>R4?}#7U2t+n^vB+Ch-+%FogL z&`AWo#-c=h#N)#=qX-L)VP_c{Ghb@Dw8Sz6_!5AT>?d_UaxjHkpY`$zPTyVe97Cox6Fx;~CB zLh|=31;(P12r;3=IhHxZWV|LcTe8Am$goB{v(;DV$kiX3iKJ5Sku#7I;mI8j5A2ZZ zJ(QpGu#KH|3wf?-lx%4z%?k)iRRd z0(fMg2A5o@di=&e(*a9UX0o6k%kste45;NWcus^ez(-bNg1;|rrHJ&azLvbaBHuyl z8d&HT%wW8)An3&1E;hjiFZ&l2xYzqYkp%nk|M$3-|E#wI_GmQvGqoabr`iHL7r}WO zuR(CTsW;U&$)iqIt*Uur_*qp~VB&{GuZtX}5)8q`^#`9h@HL(R;@2qPuo1h6sGD1faM4U_X7<_YN656suX1IU%<{AZp9`6H5#2USo&(RdEQfyM+ZNv%2u%#8j!99GUQ55d+>h{`4S>mi|K0*2Guw_7CH~n%&|v z(Vb~gUm26G(du`7I2RoGzEh`{JkRUJ4?|`0&oyD0A@W1O!@?y)^ z3Y=3>_*7_$LQTsVdTq~F@b((MRg{F)33eeEZC@)b^-M`N~(i*5-&Leo8CbioG%xkxGj*yq&2Lgn%yx2%U!N%{kW ze_2-?mB+HnF?fbgJz4Z44)M z_UFmluBR(9sK8i&8~Z)7>psP^5Y<^f&u99hNl)xiTlm#~8y?cxUX(wZHhN1%J9-j$ zRv^Tw&7D_`N*TP!wzI=jm1?H9i>;3vV86_eEcsSxdh0T&0ZK%x#C{GXSmH(XJ2V#7bvIsBtLIG)+T zpXShuBKs^Dx>4xnl>R-Cb2B?rc4fb(;kjG}@QJZkSt^g*y|V>bE^{sDz2(8n$Rt-1 zL&YnQpvDd-MsnYTL>ptFZ<1G(;;Qcu3z6%@CHtH0R5aTxj_GU9FNn z7x#mda=jOuF^soJZaet4*YSt(=Tl!nrNv=dS^L&T#U4K>dr#_sAs#QzK+dh50n4z2 zLPX_F{B`p+=U}}~nV;9kU)W~KkN}8BfH*sPpd9e3xB5>kPG4^< z<^C_5f`AdPvwBxmzg7g69c!xzCBHR;%*!f0++BnoHrraLr8cGF{>i9(BQvLa5~(G* z99}f5yZlHDq9YuBTp>CDQOS#63ioK?mI~CuD4g=l|1D-yH*gzeA3|^^?hVS-v=Q}Q zS%xVVRU4C35NPfkW!p@#x&NTc72#K8Uwgbk^FIrN5F)5C+B(~K$6$d31Q#p^ z4j*&&8e>RJJ`$>6Y#`o3@%18CY+R7tn?Z*Z5y zrNphxL=oE3{8G*%t`ymB(lIF-d-Bum8V$EQvbsM>!b^ydv35wD0J&Cgn&_g6TFjh5 zB!sm+d3R(rGqyW`Oc)#^;vcqMAOU(E+zHK%{T(A)V@$Eu5ODFtfD`3$XlPh0oo2(3 z7qy)9FrMv_fD#u+*3@ zz_J)qkFgPWS}6Vts*Zp#g3bE8GYl~Zc6s(0Kit!|+23#92%1WMH!m{&YgFo!;*sgE zkbxWfMFQ%H0^|R`Nae*W*f?ITTco=2XE@Q4gIbnHLk6dt@7e{lK5wbAW&`edL=0@_ zQ5&(Ac!r~H0KGSEfyxfPO`n6(Q~7cWLyXkr?sUHC@nloZ@(V2yS~0hoim!K6|KO5D zOH!yW!TxG-dwC>(4ZC?{SH1qm(F=Vcsk^K}PBQO4-9-P%T|IoR7gTC`ldbgbM;DQq zJ4|oSGHh%w4Q-g7pbQfmA7zo!K5`j6o9yM3yK>`Je3@=YoWCX+6CL}a7cR*9t7*4m zdCuyON_=BUAoMLc$&{($n~Ytirza4G5e!w|1s{@-s_~E;&b%mLo~V&jXyBxyi2{1i?!& z3h*2D6z-itArVZHL$sX8SXCYJh+M=^7k$qgcicPlxXy10;(hSEwS_4=y5!*hoWb>J zisNaRfe!%=S2i!qvy<^(47?k&shKz&g=E!wn?hErU{bQ?m5IG{>wfhoV*A-kk~_I6 z!Fs>82IOP>7fY^+rWKWnP9GDQkG;n(@n$~5{fY6IxHtJWtMh96mI><{N@C9Orq;x> zkLK<~jr=Ro1ESRq%s?8r>xqrJ#@=kJCGAG_RWabjJYDSWnDL6t)WRgB5Wm(J!1HYe z3|O#-*D1OI9$i6jrkQkEUVDNg$N=ckoPqfgpS&$yt^H9Y7&?t>_&g=OkzCC`MJrhG z*F}b|F!8YiwPewi0$Amdn$DFAuFU&57=+r!t6wyFcf|fdPO}b;>dpKuiV5Ouc;~+3#0nV1kb|Yu)mH?yRCqjtelv z+0}=QMxPVlZ2aI@lvuiOFYd0xga|;9u>RP_(WSrk0S+GMK>Qoe=>ouOEkN)YmGSq| zf*3ojpRmuMNA2$d>*}eUn+!PU5RKC0Pfk+LdmN>noM<>Nr?o6O@wr{L#0s!exa8X} z!vaZ#JtMeS8&jx&hmd>d!=*9UT`3ieFuFs#HQ-N_i{Gu0l=uAPVf<{PM@7A-naoaC zWT@GWKji9@L9O<%25+`5uV;o^wWs$_^`DeQC>)x_)$EZ-MUz_G?Ou0$m=PQW+PS2u_}QY%LzdDNOz> z>8Oi5MxSo-pnYV)##O(Db1wt(Qk}Qq;V1pWJNM#xzlY)zno}ugr%=4jHF$U{MitM0 zU9c)wgctLefO1xK9N*yrSJQ*{?Yt!9ulr*0cri<+O20zloPJ(Y2RL}@PI8atAJ`M1 zc)gGBXSkECV&1zeqb_vFVGzY41dromD@8vsmVucx6a=%`zGZ(b4ESt&Wc&<=7?{3$ z%B4kdTOx!Y!9cBS}yrlH^GY}$Q}tPP~uDpN%kr_UuC)|dhL*M+TTAL?{qkg9Qi+g zF!B6SNt!{Q(5d`f6qJ6@w;-Ym+T#W41t_OS8MOJei^TfK~ zVc}WgRu6US!RHS%9D2(Ma&CzSwKMiV5WKN`8M1;K+f_P#qkapktk%y6*|j$3{Uj=- z5*XuR3yZ~m)msTJpMr{zKl8P9G?R7DKK?ygKj~Y4p%GjbK3tAx_B_2oA*Pta1GFyh zJmSqp7;0&~2$*~@KDoXJEr~Htk_uhJ)=p=3sOv1=Nynb&NU>-dpM&Fl9gn~iCq4Nd z>STj4-_zYx#&--3t&L5`hhM~|`3Cz zKNhi@^hNlrH75?|#36b-fZ%#}dblyhkI-$fdLmjUc<}fG7NCteFbXk2r#{L`!mvns z<9B1WWsXXX`Taz`@MMD*-$xlsRfI{|K69!c;6YZ#>_Yq2`2yqqgs}zL?OjuG&Yn_4 zVdB@%$)N+&I(O&SnWpfgr$PiK!!GI&yr%Vfa7p?6xmRjG?u+PohVm4wn_X>BuEp=U zasez%OrUK2F|MAXg=EHUg!M(WzrCJ$5i|<`_V}d)sw)W5qsSaxhILcqRhTuXPb~cA zXd^E~L}*LM`b|{a3?O953AV1(2fIHo2R!$2pBm&D3+2hC(qfkU5V zo@Ck46N;`O7y2XcEMHKvp@QblMP`{UVj^QK3?RKYS)TZ>B0fp z>#86Z=dbqb(N2;~14wgo^#tg9w_QH8pz{vJK%m5EKk5Z1N@Zi;O(OoIJO_)qA~kQv z@}}K#-T337iHl-4%P|5^TRfked8e?Bu%zr5XD7I5Ez;V!KmBpH4d+%tS#e&#J9~2* z2lh6euw0?slpk8rI};3d5s=@s&*zt3`gHx=w2`U8v8rHVn zwyLsd3Q5#%jJeU#-@KgFnYcKTfMd0yo6eYcTniZiV{!ho|K>ft^KK--azz4aE zkC2&DpUYNiq0w3S1-B1MB9`Y}4hO|S<4XE|z=T&4m~QP-5YUJO9h9%J(2Vw&p*g=c08MRH{4Qbr}iqu!XYJd9Osz|0eTY|rRht80Mzds!o2DFY@f2}X5m|F8SP_@#zh{WL0h`h9xl+4-8j z;WvInVX9Lp@eY3?_`%c6*R8iRSS-Pi>AI8qrifv)tE;HzrSqp#EICXKvBu|C3Pppj zc&${A9U9#YbLAFozbxM*%HAbCLzUdReWn1f{4a?XLiE2euEmtWL{5Qq-??TzXr*dP zawpsx76$wGdLlDLnt-5Cz|w$N3ncn2XgaKEx{e3N+y6z~+uipWZSkxR6~&Lk zh;!L_f$WXCr1|d2k~#>>9;8#QQ#ZP^@uM zf_6Z{57Y>SBBGvMF}$jg$Bvj9$MTGJKg4Anz~kt8FN7zx(GBob}jiYqFR( zEIMm%uLsBR)&D~seBhxbK$=CG`OFX!8RX%Y1f(-uS69>0(l9kWt2~Q1^FM=6Vb{Bk zl4MttLcR&dw&!}<=h1*V>KB=*R7*UfZSkArIQK=gh z;x}c3gr-Iu0$kp%#ccfxw|^Izp~_p0)nJ7m$)#jZ(lS0O#K!acbWG# zOa#LT6ql~3G$1x`=d7bBX!%#4aTZRmA=ENi=hPm50`Jw_a}lW z1XiX>he|ACaT$%Pi(HRj@w(s;P$xHXf*+&#t`D7o_O*F7d6QUB(&h6-YOwJ)!Pksn zl9H%J0>#Dk!bo?cvI>t34Z1@2m>-3Vg2oP^2rgpr-~#*EoHMuAsSSiTdC8{+Du~e- z%6>g{I#GgfYSabLR8A-Sq%ub5UNJ>Rv}}oACt~-jVCzMEJiU92`OL(^mJ(S+kgsa; z!%t-O-uU9C#31Lz0Uj)MG9JWlZ=R##!`});>W37pl4YC7z35WK0w$B*#jH@BMoe=~ zDRcsvPS&&grw@5{g1&xxug?_(dj>*Fq{LO*+har4Mp+pcGI(ETj5?E79rt=hS5?3Ibazn+LH(^MP2uFt&?l9kc_RTYF=c3H!p)E*CgLix;?z=HumF3#{9D5 zXik1Y@X_NJB_nIhAwwS)zO{*#q*3il#1yp{N5X@IL(e6=Yxi%?E}@s0g;5-XQL5Ka zloP?o3@L@qt+#&Z)FB7?eFf9q%(Q5t4B0sXsvf#ewDBmfs|1+LI&OZJy00m695!xNu+5#SS5oiNA|(7_po) ziS(p2QNJvg3~aOd9unZ!ekg!dLAUU1>Mr_AQbm$m?4^jEeCt(;YqrQvbHtFJcCR+h zjsMxqFG(^FoTsT*{(F8bm##n9=LDEp5tz|3-A0CmXkBAzS5{Qh{nw4yB%jWxj#p>Z z3m#_y6i?+w7X%gr2Jyk~BLhSRx-->C?47JSAvoNgb%GROG4QW&pnUx^A^6#;_4VjR*PpW@E?C}X*NMvj`QBX=AoC|P?G)}S)sX<< zzQ(>Awq(B}a79CB6`GdH(mzb^%pJtxWV+246G4S|pF7eb$Gq{xNC$yJ>)TdO-egw_ zuvp=Ax{wyf@8pH*z9BltG94jSD!%*4NNmtgcD-F2*x6%b~ z?=->nZfc}Ty-h^{&0G0u?wX5Z(!T)*z}JaUN9sY>9lOaGk*xAMNGB|W^sWBgOKP2H zv|`2`=<@YRtdAj6a}7iMjyioUD6U}7Venah!|fTPO0kosKM`rqLze1VL&N1r%V`Uc zYOX77J1<6<`$|V_5THB+s4(4$B?BY{tc1C?sY+ZY7tapp5QG>sqH!p_Pn#wq9iK@4 zZhd3f7OU?Eu^LS!{98qD7R>wW!BVf!5=PcOPbEq=vLGa;eX1Uj6! zIL!gx&71tbTVvC88X2}6lL-P2ltqiyzjiJ5bwol@JO8jB6kz|e|A&NPikK!Eg)Ovq zuVtFz#KeNn3ZB94v=<(I(N$vo*MF9FScnT6M-7=u2 z^HOfu0IA)2-6{;#g5E!n-OE0nN4mJ^O(M8A82|lcj@>rhW42{4!wT9%4u1Ca4=;Pi4 zZ#V*u8tp9Rf=+wl>1{bHre;)6+SLOD56K1}I4^%7z#L{W%_r5R+FTsFpVyF`riV-i zKeA-nDwpTWPCgebW=Dl|Sgf#G;#9MERy4}$u9I=mX`OI4#b>~6-rN>pd!I;Po^{rE;10}LM&#z+X=}4^Xv6uI@ubBxWOei*q7hccoGEvH86>Jp zu5%Q(ElcVAcEDfx-elFdTyeou9AF(G*_pT#?4^x)F%kA=G8{L~8Mlf~ugUk|=5IPg zb>~V@^$crMm8K$Sag&q&8373L<*S7pFkobGqw4TRZ>fdO0CLfAghJ zb^c3aEWq(t;cI_r%U3ET7KxPWg4#WIyzzJ|g3czl$>8k#+l5MD+3^re-ZIvcHme_S zjJ&=St=yKn!Tu$KDM0^m_s6FIvk@fz68~QGkYcxzfOBmq-q>44%_7lJz4f+w2P*at z5tpeaAtA!;;NA+$=Bo_LwkxaO{S}2-W4!+sxA^vxP#T?h;LGrCt9w`i?ZBdw6E>E9 zfrJ8iF@KZer%xp`aM-R?@vo}J&G)WJyTnw+AN$MasRY!TrgO)uMRC1!oANeIsYk8Q z1Z%V|w8Y%t^l1D21Lb@_!o;1o=4f;NgD3ZG(A&;*7`Pf(BoMKh+GBTpk8EMkJ0RHp_!&id zzKUUuhi+hTe`eg5O3sK+V*kPjH|Q0;&-vxae!wkQJ7HoC3jr{tkQ-i`L3@^$Sbcn3 zS@0hX&E`L}Vns+J>@S4Jpv7LRR$k5+{&(J1gXW`xlVf%1^oGF_9Ij;I231>ob-O!R zOP-&<8NXC2XPoO~wLaO@&fIBNfhf+DE9otv!%p|+xn5nj53AG5C)I9${1SI*!G1Rt z&AiFut#`xon~6xk&?@j=#we|Wb#!by)7JMzfSA|7Zgrk^(d=90{7@o9GnLI@;5>t` zmHp0-v%oBe-B0QC->OUY?D|B;I8vYVQ$=n$^N!^xLBDzBKd|oX+u!Qv;8zPJ&*3oyeE8qlH!G(K5hPfBUkC(e2zQjsaV0@EW0&7=?GM2_M|1bOfE+f)c$RfnmZNIFmue2l5zAEtm7`jBOJOob z>rwnl^^g2Ls}aVDHtJaqMApa8p!08|8h=u^6EW3f&Ev3ZMeyLvOqKzp@dw?0mOBoa zcJn_)EEEKBU)5dyDss0P8t06mSgZVfpi&o4kIWDgJX;*rvPs!;=54?u07U`cR}fPI zAU8^eh!L$u#Q*ls%+8VrX^m|#7=G1$X?IkZ4nD|N zyN;Vm2)jH3l`#=*`NT=JQ)Znw`ryJ>RA<*Xh*m%OC`V|Eff6C~E!&cUyymNf<^j8a z9P?oBC4(nR2(>80Ar%llm!@3>@vXORwGGcZ1^Nw~<-Q?~&DG=J|9o{1&6W;Rk!A7fLh%AuPNyPL2bUQsx%FxOkirU_(Y zOhBql*{)2CTyEc7*vy$exQz`)0iy7IvLd>pzAwR^_^iypty1UVGh;DocJPfi!_jB& z>e%-Q8rFBbotru}En;`Hb^A$mn@fIvAIxG;;$;9CKFH0U zeQb07l+f<{l8P465UUmikL1dLsQmbZV+_8T+et#wOuAFG5L#7);I_&McshgdO~T=PX3c+|=%D z@+|huSIi&sq#-U+N7DVZ40?6@mADrHu1|l)E8Nbq_KwECCi4rU*IL%G{IOQni3%s) z{N?xY$Y0A^BHEQMZEqZ|wia6=XaTA`q1@SDp~oy1J#e>)82r{}KBpGd|0Y$NU3gU- zaZ62dPW~f@U>YW^vB)!SLd}`;SMi^tVs)KO zC2k)2K>cBPMjDPX#DIi1TuLXR-|B$Rzl$tjKbU`@zCK${Lv>xSXNCFDPY+Q@%1*Oy z99cXm;&j$Et`VB}lvzmdbTx3j%E|fc!Nta*^Un4U`bGln7u|7Ubq+kCW41r^?k4oj zwAV&Giv?K!Bp1HkjwyP0drYjiZ}hrk#g$)Yr@2uF&7H1h=n34hfKhPOJ3!=>IEulW z7oZW{#G9!S0cNRpe@}*MLR3)!gZwSLN%f1(?Ok}r;)HcBt$5TeoQIkpFBdmdQ$3q+ zzEW%Ys;@A>Lz^vaMVCb2Ud;(L1`oWtxwc%U#zKhC-h6-}KCH*~0`cOE@*ns`I}-WD zN?B<))2>h6g?vGb*IjO;I0tN=M4_S>x7+~YepxG^_4t%qM>ztl{; zXHo-GB_vaq*$aJP6t_<71>>*1{th4M6jbMWtPJW2YcoV9P^<3hxjL;Y^<=MZoc2%7-+&jC-^x z3kZyl(e!Q>)o)m1^5hg}1AB7LnNbPZOglf>jPY=Q?0Ysd!qGQ6UwJhdW|s{M)RVl= z^3Jvu2sYPQdqLO6iiRl`w4#QK_sxy&v!Z^_UfEM`lB+!*e-@{{XnS_-XG7W>vfz8Y zuGae_>O-$MTe>l16F42p8U#5?LiO6Ye0XpF{d|XZxJo`Qa4tgn#(z0O^WCAGRq5P~ zeJ^jWx)*VC`4db>$>RGP;AgXe_CdM(TG7Ez0V5_3sLiYkbmcuW69ADwSRKk*u;PNr zf&-0RI_d(ty5|NIeHME=9W(QcW&GF!hgwn)yzO+jR^<$YEpZOG1L2I8zZZ6JHQuv$ zr^I8w>t23))a{)>^G{e48qVWLBBRjVz-VPlqdxyl|Lth|Hyh`Of*}EzBIw>#fo2E@ z5Y`~*J0s4%LR=ZM*#@nRUVg04gV%r&qTsT-6T>O2OCOH5vYdN9kFshxG$6?@SyiV4 z!3)5D4~_?nD$irYKutxJnkj(cI+9|$oS&gC? zxNunCj=98Ogh%S|<@JR|iPHzt^)s~Tea&j426C7FE9ZWLJ(hoD{+CUG#OWeDk0{5@x8GB7Kiz;vZ#h< z+D*<4G(g(^`}hfPhqiGQ5R5>7!0ELR7=x)K_n40ttvu8WG|J2A?FKpsAZtX3&P>YF zfALBxOO*iEoYC)+h7VnxO7~rRadQR=5JXq}H0~C9Us!TPVcUM^Vzy)M0BNk2(c!1O zfKf>7_~rJOwSaZ}o{uwB|G|=!OkRz(IJD+JZ8_UDcaP`l1$zt%Rq)ai@hmrht`+ru zdF|RT7|0-C9OMSNJ)ZV+93#s#-^Q63g#Rp;@UFun4krOKa?@9PGpf_p_44%w2Y zu#>_0dVw%+85~qNB?YwvaLePlosx^@^v}lQSGjh61u#TyX$mQ>+h@xJ^7A~YsPKI3 z`CBYuk_G(01GQB!SJ;X!E|H;=-9vGEW00UiT^GEV^IkjZagOa?{4$=oYRj=*#VEJ+ zk;8ripv!lEPcvyqboQZC@5#A*Lb|YaXtwksjdFlD z*63Jc`i53tcdV6wmFz|y;U_*DiM_@rmlCWn*SMIqKU+~^1Vs@eF^Rg72%yQWE6ioN zJNT~5+hbxII8Y?{dF;qiFFaQhxSM8bc&b2(6=n}vM*r&6i1PP}z{kSr*V>!2mG`=L z2W~j@z|y*^js#Y;Bk#Q1MM8V8gD+-&Nrpe@M&Cf1X4u`0s$3vdwrF&)yIXMMAI}*H8XK(ZAlCAk$o?6Jz zN>fs~T>t5$YUCfT zbs-OdT4Y5jf-()?QkRc->)_zvYb5Z_<}J$B3B`e>n%{$L0V3CD$%0$RXDJqnR>LO%YX8@VycRTlX}^n>Wy%dYKO zHx%<5j;P%Wqp~5@A&8>^^Nr0m ziB#Dy)h@o~-LkFmOIoayIZ}3}U0 zypp8*cC5~adjBX;p4yYrZ_S%$=GX$~t8_AO#(ef_U(FaO&v^J+l>|yHd&b zs5I=RxIOmP!UZ;?kbaTFO7D{|yHRh&!!}-07E`B$ob&ZD^cBN~ohcKIiS+boBUDp? zDpzLhB&;f0xtG)jGJTlqoRshg-oJau(x4;nyfPh8bPpyiz%X>u!@{Xm0 zu8F1IGk{@3=it49V|B zRf?Z$p3k(mZf1)?dP^VdduglZWj^THPbtZw|tBTo{Y}_WVo+ zz~~RX^Mou(%@I~}FQX-j`669?)W>GP%>jV3UUPrsFO*~PHFXTGjSI}3QSx3UGj92e z3$W0A1BfFg=D0*hBkUI=MPhPL*t1o~`7{v=j!14FuM;&V|3DO|mf2`C_#bCCk00At zviWn64Kd|C8>9OFi24esD8J|Zy8%nLbgY1a3Q~d~wE`*%2ns4F-H3#Av$Uun3eplP zp>#JaqI8OYG>C+Bcl za&@iyaEXb5&~^7fFXgD)i%m>FW&^qqB-d0O@0L9R{1KN-4!kQjU+xgeTyb1wvMFM9 zm7{O`w7FVo?Raiq!y#sG3J|5=51*-0+vo199OvkpN-oCKZ5sbM>s_YRJ>f*|vLP#S z7@AVE+WR&8wV^iQZ1U+sA#*ynvIYau6x#O`AW+(qmyqeFj{wXmvUJvCRTKn!{=BM& z^9a0Y%VEb?dVr)OUSD00M*uW4FqpLs4}A6Q`@Y=haMocddGNfcUoN%UVIqbxGr_#xWA$k)B4=viqNhkxxj^xoiX|r4J z(EsLNC0_%Cs{lM+-CKf?OLN&VHE7zG0kIo!0rh%wKP$1YxZ9sEjdHO%fAQ?~(@meS z>L9FcDbl(oqJYNlS4SZlV?w|2vrYeD<;ES*@+y(QYB~7+XZvjUxMq65KPuu#4h{`` z1$(4Af5mP;Pv*b4SC~Cw^R={G2T>eIhxHUpy{YGEq+?$Q3mP9h@87P; zm8=4Q;crUE*V&N%sfe1sH1kuKk zHIl#NU6K6(&$y*vHIK(m`uoFQfoovoXWT_um)H#DmCmf^&4J6c0WTP~2AFo?w3H(NtEHo~gsP%pRT9K?8*wrU?B!wB}n zwG)DL$LX`gS8GB(>E|^;mcaw^EkIdLW=PjlXc&mi z!w}vza&cLc#b4&l$pyBqe5uVnaFXtOu;M_Zi0Bqm$w-2}7(#jT=9-89mkTmb0c1Nn zsO(u=3Yu;ppXTmIDxakRAOJBI#J1Hb0L9Uq0_zDs5&=Hxyu<@xp8i@-S0hsm4{1u< zsdY_iLrs_Gh6V35Qp*E;d&9+B4GK}>;}8>mJ+(2ZehSO6S0I{lw`0IWITrNf(jPde z$|8A%1hNCs9B>bZ<4ELv@|oF7viiSr_R?BOXGQ@#&Pi}Kid)||rx}q-iU*6FI1|xm z6+a5Y^Wti~p97;2xHt22XB0L@D_DqnE-IP@=ZlK;%IJn@FI;(_lzAMO;AqrOwf@T{ zD4|PXLn&#e>LED>XO>|>b?!Mi5dBU;e(P^vn3&i{L-Z&y$SgW8T7*+cxn|ku;iP|G zLAQ&`unNXA#BINqWM76a((u!c+vZs-lNvm zsQ82EkrBEVA?V1~bj9YhLHVYl)M^M?+~rEy8@YdnnE!QdPEg@HlYZ6a2*mM7!;M>( zE?>r+9`Y=*zIw?A@E0FZ`w&F5+$i4@tCic)u{F8@vdh(Vba@ zFl_1Cnf$%!(L_*%V18=u@x1(%cgo85dd6!h@J5e1Y_TLXma*ZLUh1I_iIbl6hr9z< zT4q?M;Nl0rMS@?tM1+%=3?AEUQ03lqfNL5od0mF}IVV0wciu^4=njAIw2add5U7B} zux#nj(sWjpB5pKtgGxLs72zh%whVm+e3&u(UXod{gf7qatIuISZc%VgH5HkjuZ|fk z<2ScHTUT?V{vCC)w;Y~*Lvy&Ui_@CHfcL&b?@q_K)TT9RZQ9q3V;6Kis^fuw$8ZlC zVS3@w?PpSvVj5R_1Bpo4|69AW5EWR@TWxA>GxPo#fM zq$!$|BjE0VG}lXAPC&iL31mTvR7?M_kNT=S6{FcC^;53cf&@+jS@2V9=Mi<-&Bq}B z(l{pt4i#B))!s$kFPhvVX@uPV*EPT(=7RoKork~yP~SUq03)Q7kN?68eQqvaVLa;P z7NP{apMS7VT`SZcljzsCF&pejd`?V8aMJyvs&90SYd|~#M3BU?nVbU8G<@ziO3n$} zvclJZxg#_J4cjYl)1%wm)MH_34ggd-cfkm9lAN_L1E0OQ zS*Mzwn=sr_364v6*P|rbHf-QYuk$>)hqjrg?xm2B$;i?h>ZK^mA|JE`{FCnU&hWd2 z?p|9~#L5#S!X34`wjTwm?ctly^nDoW3##;ayz*n^T0m6?MQw*0uTUu3otok5mbpBxmEi-IGx%PxbO0&$ z3kY6Vk@_yq^(@_G_$~mSP&B!&I8ff6McE#LaL6T!^SSg%^>RPZGw*iZ%rEKGmnSWta5`$WZG_ z4Cg8}w_~!8jSlTCtrHk)O0-;oM(O<%WH{8U-K~RzD;wai`LrVA?;qJ^)Sd72Z*}+6e!?=nBDe|JWMj=p+Q9w+QBc#;=ZA{^ zT6G>|ctgNet_gJtcgd}uM72l}RKee>)}G7tT8IJ=-n5vMFa8+YZm z`@**T7|eNT$olPJP(U>fPYm30_X18eB3u`5vN0ON0g{A~Dajtc3!jk@Et;P{ebNAA zS15X1h;(Ghc=+bH`sDQzk9*weRz2~Q(Z`B^C}{V~mr!%r9w~tu%3XBaQ`_Z10&x_p zJDeQ1{a?m-3c;fVvKF?a%Qb@AUvAxtVMw$!?W$h#xL299>}!-ku*WoyKBXw&*n}ZQ zvi95(2CvD*VHipbCO_0q>ts3#y)SM9?vsL9SgagPMx0%;NMtP7G6duTVA_edOP|6o%RuS zgF#fgL{1wDa$|dfl<9J!LVvu)2&f{U$qc^y_Q3!Cv5cTF$D>lM^&O+6k6p%lvuzZb ze`}~Y5cfF8ynX7e{Dh!pyG`!>8n=c5GIW2Idy)cAey)2On8&S>GM^R5{!ene233`X z`(?Q|Gg$KuM~23=GR5~TWqcNFM2$w&HDV1d*!Y6pg;uJ0fm#%>A3(X;70WC3Qh|<3 z+2X%uU*EKI^hh;LMlL2xu@80!vx*;DU!{8>do$0nnN<{|T$m2$8V4?5h-J^(o*F%*^6b-m;O=f0Lce2L5e#=<45#qL zIC1ZUy8OJy!7E zUK{Fl9K)&~+X+hIfp-$chSZu3uE4(7O)ln6JdVLAMi_fUiw2k03|xJS?Q za@ul9^UIEzf~WI%u}mZug`-XyI-7xkr#k&xxkf|T1Y>K}xX0XN|!-QMSF)KIH=fnn~cKBt6Yl$f;qw(pqh(Mke{ zRp1gkp4Z5o%T&C;lJ2FX4d9_GLjq`|as&98nOQKY(h_AEX~qgT0KN+Re$0vwMov(K z)~S7_eX~0`WbN3w+DPHq-!eTi^kSneK0A>}%eh6+OFso-_q^2pmbjuOABJuXNyOa3 zeWo}}{qgCnnTJ;<>v8577sAo?TS!26m{aT3+%TA1o{2A|D7XUpN#_GpIaRicQWQ@ zK8;?U;d>tP1&LS9<-TNO{Y!}a*!+83(N8KTRcc-aibv!0fhy%fu{IN?Yd!$vjo+l- z>+ViHI<^Vhd)4$J@8s|ZxmDC$wIwrGgPIfGypLiMKIxaGlswVp_Y+7s!=QQ(-T(ld z%unllZ|qE$k41-DZ8#{jkHp2UzdPXf4`$~aDl21D9`EiVt6ktjuaHL3-OZDA{0fwL z2j1ACxD`nJXag@R2CG(7v8rBWQM@d;8@cA~nJ<^LvNe>>2gbM-O?A$H?XW6xy<*#} zR!76){2{)E-s9xzgB`t$D#S!kLW6~w@>)2Eu=AD6Q@a4lt0FIz)7Q>FQ+I!sFyc2C ze=E?bHy?pt_h!-n_(Bxz*DvRNw}pJ&s@~k4pmLMl|I{RfM(vnfbBt3I#-V7|E0&$= zj`kFs=xZuR?mcr~eC_;~rm2hvwpW4Ob5Oipc?jA?gOTeqBB9W*Ve_()6$T4IxnCRg zCMC;$dt@5{Ucy=!3F0mSZ+0C%QJ=D?`5f%fjbUu+GwiEAOS^=pw;z{yBWYL;D1nCC z!`KBF(03I4l?z(If3deeL{iS`NDA<|)g5VcSRAndER79*lQ;VT+zRTAhp0|V>o?J+uZZ10s77>G-GKG#r^9?i5*0FdA5v>?A95mU>-TnK-!KtZua#_3z+D;gRvy z=3j1kadfd){@LE0Pyb_VwEcfP#0xIrP}3YLR%h5|R1tz8*I-VH_=(hsz{&ZOOD7U1 zwkPq#DaPUTul(^nCI@YGJT$^T|7fro_8Wm2IRo(f+Xa4pz;JZoa$qLlNGO2~V`yHz zUlF;?F08QlsK)auGUeYqd>0tT_Z+wQ2dcJQt12s#G>5Pmy|RbZ0N|c&sGov;VxHZF z=nVGKN*1gDA5R8+T$BQ0VoQ}9cQ1zW7)+L!=6-tYRvs&lQ2c{|tqid|aW+R!JE5D4 zYnc+@L~0*pfX~5PorrR8YDsEsU6?gcWR~?NP0Q#%%M1*!N$DSdi+`ML9hPQMx;VQU z;SgZ!vU=}dq0ieVAps$#EBh@G-d6f2kA`patDo4nj+ z5E3ZMq(R3AgA-`s+J4;K{zGM@e5K1yYkbpFk?Eo6Gp7Onx?+*yZI`ueVx>Zgj{F|~ zpEnB)_LiSavK65TU)&u@kd{Dy8n zYH_uJ+ZiC}Dzs*S9H_sW#fwkH4j`<3iG$SL5rSU2o!{3n=Cqf0D@K z1RLMs2OF46OazNb-~41Y9IUZI;YE&}d4mlsSJDN7j}!(!P&b6XvHKBaZ%3|yc$Eh^Uhbx}S<2e~SBn!w^dFo| ztXCz8Z*}&lQeDW>59uT`QBSGZ?P;>}kt*}}+ES{LQfhqxR(a!f1pM0WTN4QIW3n>d z|1T1xT74p80CzT=s5OYdqyeL$;ENSc_g(`kqaxDxVm-3z!&A!03X7_V$dGR>LTZ15 zR_O7855;uC%7^}+IuZ=+zDZJelvNY@@EE7enu^^MWn>dz?_R9?iSH34{OA3De z^kB^L>kT>~VuFAODRclpdsrF+Vp{3AuS?%Zt3ICMim=VH|HNLk1Re)?69Q^<&d79f zQo&756`}E^Z791DOp`q^>0=YamynXn1)~+qg8RC!Fvk<@sf#OD#fO#|Yl@)+&qeJb zzyi5-2ap;}hFQD#OS>{w0qNx^oL2@j{zkk0GtkLK`16PZG{?}&A_c_Xo=ygit#ym! zdq1Q+Rl4LF-4(!9849LXZ}KI!pitwD|nl8c)L#H4D2C z%>kT74u1tVx^FJBxS11U{pn(!mFpIPLry>3$ycQ1PJ#QaKQT$Z4h(bIS8F@!p2Hl? zPrh+1;6+E8I6W1uX!Y(bPMLmh60mp$mtwf=c{501}gfGKGrG)(Gr#U$Y?&^zB z$=e^}TCzS`N;i|F_&lSefOjev4AF}v#<#eMG`Kj$ z)F~390ZG_{yTSMG$}bK3-mIzAn18uQd`${OaWWqJ>wv_)_%(D-@6Wi|nvbCbft#JFff-rSl}cBN!GiTM z3$CyESuYEc0v0n%c)BX56TG7;MU&HA_ex?^&$aRH{P<>3`J{xUuVZPDn~0OO-qZ1M zJz}meSsgyrs7u3h_Gh`*#i%{rlV0C3>xo1iqA9X5iG0Ep`W6bE^_m#in}CoIZ8+b5pN>nU&X8-*xQ_M>^S?tsjo`Un=T>0WiRw?ltt0+}L2SP7xz0o=y&%ieJ{z8iBA zn=e&D-#wAod+sel?w(F-eeYk2LTLG)ug_5^jksW1JJwsZT2<1vc-V#fMb$eNAlNUG z4yeo7pON6`f`Pnc#@NB%(ovD@`tVoW%;y1l`mgLgLthbJ(;KYJHQ@~ zB%0frQp1cAmY0Gnn5tgYVEZ-B!W!?W6mkmT@sCM@3#d>}AS34F|z z_B`pcQjN@0_O8U0$dsEDcY(UJOpbk%=B!rTahNZ@kHCf;$fT@R`fmPBeq1f;NkJ%_@VWH5khj(*QTftxA| zqVm(vi>~S_JHN!F7pr{roJ7K-ZN;#Yq@WviKpBV*z>EMjL?&QODv9F2D{nYEHFM~S zt}>CWa)z5NdJwdZ_T@Tl@n6v(J=#b+bUE(jI~bN?$y01iSTwXg>NURS`@K-d zd@{F|x^pP+t2r}BQxI9B&xu!U7%W6GFa+A%)46ai(g?;EJG-3n@;4v0uh@xhwgVfF z?E5m4XZL;y*U|!cYZjbuYYD8v`hGeNiO|6DEqr6A$`$F~2#6^HXn9-toX#dgq%FBG~;Z(9q?Dw?+8VdMBqVPXd_0fWpVzbWp4~s8MY} z(tiAg$;`tS%X6_S-C0I6&|T{&*Ealkbql(^t8p)HeMH+&r6OKiqkd!{U1tfI*sZ<}KYl8Lj3xcj+xS+b{b{6bx?k&^UuDexHEC4&~cp;+h+B!}I= zTC`g1b7waWWvz9&kGwZooRpq%+>{cpK$x&?yWkX~#+fiL7;dHZRKumC^PZFhMBVuv z=&7j4@qH+>fDvAoq1ibQOW5~H0``qh$;vcNOg(xznMp0IEOP#kiZku*sB~o4iHz2s1_5I+;vguyE3F?0Fn#XV#7t8nitszdu()Ds0Rh za<9cfJS>)#X670-?su54KRnU5ZefHgQ|!@Ypa8B!GAMs@zeSnjxbZgG*XjH7J9EE8 zqdB95?d0s0!-7049b6wYQ|gEvpc>1b*1*=Z+O zzuLbpyPE^eK6ESCl78qe{G5soJTvU*pPDu@`{P^)X$jn`Zd``9wLO85R zc%U}orsXGegUBU^ww0pnbP8og@B&N>QKzdGU|C#kyBuEIHmO~_?(T_nI-(*WsgZuQ zf*h02R^Tk@fQ5b`I9MEU7Oigg$hUN{?bEToT`fyBH3IqGZ1BQkob)*V!KBd3)lb=X zTJOO6m0G@>>y4|N4}G@Uu4a%Nrad(eKTc1%a31pjt+Fv|s@X{aG`gOJ7$kQRQ-!9~ zUvYnbQAh6iuv(`K29LsRk9oek=+;N;6qTRf_qcMIYz#pmROGURhVfeCSAr}FI;_+Rdw#MIIwJYed?bj{8@n2-ypu#?m5R!5-$EsToX4vszV zt0B-p0ICVS*qgno<0euX%-A~aChr8E=}um>?FyifL`*n(A3ceNE-ygBtZ_1M5`#Py zwqjX(i8h0;q5tx|$>4$GB!_<&)I+@aR=D5?C$2)g4(~RXaI_!x9NcxA$x> zpNvRDUMuY3rIaiH7!k}XxebFnen<1f+GUHxiL1rPh#dTXfepC+eGmDesuLaCFh`Xd z(rpYIW5~gi1WIrpD~R(nIB|(N@!T0$zxcQUoVVK8-aA`{#;=2UM9u@3?TG~erh9mN z*C6I1Y)odYnvm}}!2!4N10mMoGzN|9YzzBmXW&NW|uVm8^Sj2A%B#V-UgO?8vH!7cCDeu{s(?tV$YPg!N3<{7C1fRv% zg}cvSIU4AO-xBG1O#98(nqo)#BIkCtr>n~2_wK`gyi5HWI0uGKws)aDhN{xd{~t+Q zk`Z*wzS)C!`p1e~k_sf&txXUChwUm_l9eYjIR*bYO5LxUEOT9C+i0rhvd4)c%upj? zPfXWiTl!lNz_3TaM+mDd5VfaD5@HGOw z@qgzv8$r^x@D_1sNO1+M<^y5P-t;_}lomw+J9@9#a+FW{Q3E_QxKMobLO(o9!Wto5 zf4iNf`3||Zc0GL-)8y%8fb*y+0-A5Oks&d*k~C8dzsR3lebeJz@wR=hmcmyF)VRab z&z*V$nI`{H5hW4HFxUp2GkGX=*hBIvmo5>A=xFP~vQ|;qobEqx;Pz1%PcJv{q7AWn zuX}Oh{Bf&%wWnlV6_n-%C;s*w<|Q zM2MXke;g)k?8iOEJhvKk$Vz{_Ih^;VEGFvxU{`tfuj|74g=alZ=q~8+nFEnsdg7X(HV>%h#0K)L$ zX!JR@^7YGph}*#-BEV8FuW7K+Q!?iFx;Ky!4*T?iNUuRFM6w#DUUa+!CplgVE)!Z3_<$>!{KtZUQ;P)0 zTB_$&ClfF5!VHs=K~0i2GJcKFkQO3QwG$yKg-HYWWdyd5OjSL&XY8gh*M=z(>}%(x zY>+pFz$fwnY}qJprl;Irzi96Bx6ycGAG^Glg_`;myo0HR;ZF)rR(8g0i9YWw#YI>8 z30<)LQ1Hy7_a^LZ)f9Hoj9m3|CX)&Re=|Xy`rbWCK;YW}ho1K-8M*-}?5Svz~V`2k5TC2T1-DAaJEa;C)*}A5m_n55V3w z{}5Xa@WsC$N1FjWVDx!*w8vC7{?w&I0Ot2VGyn3^+3-v7OyD^xE)G7#@57gWQr0@7 z*<5GZ8*l81*-O0LQZqSzzD*x(Pntx_$#Q%uCKwvIy>at#S46|z@ia|jX6rYAF*!)_ z>9Ub7LFkxzo}L}S_NMrIZ(v)~!y56gaiI!frNy)p2>S*tC0H60%&o?t1=FC;1@{_8a11w$o5m^>5}fi`8<%r}k{FE%kX z5TjnuHMcm)Q(iL5q~P%J5&D3U&bnTjFXoW65qDiUnMB-k^jham1%9@!hySut$1H z2MuTB?3O^lx`tpd|-;D5KU65|*DNb16O>diU8LvuIpN5+_Zyl|925K^hQpS?g z%>1y@^5j%lb&L5q!>aMpW14wq`MLg5o!;t3q|PGyo!xm)Z}&?UTJ5@aA2g@-Uh$!x zbzQk-D@xD)ETwi`VsF{Zj@i9WTA4_o{vsoIA-{Q7Q&^3>k5fQAQx|5r zOQVEl->l6cYjjc;J2-|Ksb6@cJJB;=|e@jwbS!v*hOL0{dgbomjXb77nEPeE&YEmt%wNL zV16=tzpsD=x)P^jduwkgOL&6^B*{4$e*f+xglJcD7bVi_Nao?hWddrffyPi>U)y=BCi3(L^_ z6_hn;IM=2Q>(lx|S>W>kNEUiSMScbR&bff+!A<|fbmDz%9Rtlnul-M6oqh5L-5o0x z7)c9MdxD?UBJzF>QsEP}%Lx;S;J=W9o|~?;3FUSz+`4lQVE;~>p=PPftoTqC%zcM; zkZoge;YL8`_>w2ZiKji%Wc#nx_1>EW@AS{FZ;3%%9iM4Y=66K;878b=d~-$Op^)5U`MftDfubAjbX7NZ z)esO{rqtW%$V9zGSR$3B&!!O3YF>d1B4gn8s5jOa5sN&QvwQro7Xb9L_zMk>VJsSF z^uc>3G5Co6-d8|4Fm&wAw=yJ)wY+v0$|Wg1s^ZpU*^_%46gHwRcC3yAf=MY6z0$w> z(BHY>?c&cM?fCe{ykixi7AdqqG0=pDSkK zLbl;HhCis??)#IXsGsz(6*X3z`cOCJT3pcuz)zz9>Kvx(&05&Hx~x0^36AP9hCU^R^ z&3QOBbD#chGO#P6!EIZtt!ZGV?}>)`rO$oVCH)nox3%0_v=N-lCJ&GfUN1_VgJVC^ z@hew~>gHU6ErndgFgtVTtRfL*XNk$DGe?xd*1F+saU-{+w9L-qkYUm3VzzY%97l$YMXq=e0%SU=0wFF0^3`4{6R(1fjkc!Nop{a_R7x6y`^8>cOzc*0 z?k?e_3Y!u<`RskQ=QJ0pUiT>m(PzJJkEonoM8-L zM$=$8rgdKBHY@fc051&r^R$u^iF7L(76ZY@s~a2s$HWMeDxc&ndXX35WTVli4oB_891a2c2!eLb>MRIx^;SC5ZL5j3o#f>iMc$L~6 z9>@>_VnTOTmsqX$q&dX<0PwHogtu9KWfY)1*&$9WOjuZ39hSW!3*AM6$f@mYMy`8$ zRZ$<0RfU{lw+R)Xo>f16lTEKxQ_bxRH5uNI!90V~ZdgJ2(oK7InaQ2giMZ+SFly9D zAOQYG^V(q-hyCjLat`!e6gy(GX+5yFfi{XJqlV31iHJ9g?0*(oV@%FFpvP~YMoR9U zytmc%zeOZ&8$q;o2lnLFNEy)tNZcUXat4x2gCuAw0aRT56h~odh-SINLTPb&CI&yHx(eO6?Km4}$Rgq-<%}G=$q59u46fIJfq0?FY`@&t8P#4ePXNm8uO9iSo znJui04b|h#a^+uRBngbgDm#CCr2kEh#FdRQ;8Wf3nGB%&XyNXP2RtkjrK~COkrmPW zzswExw9 zSbAKZcPl@Y5g-`XBk(s?A0neB5T6lv;yE@60U2p67{^t7Y*;1>oZ7wMvpSF*b4l`) z9SXXyhwWQ$!>la482~y1YVdP%v)K)Ac3fNO@?4k;2Js<-R==&~Njyd-Gcf<{i}I&e z>4Cc=un@AhMvdlcFAvB6pdH0$x54*L2kor0zh_F132GI_w-|e~D*nIzNDY~8X<$mX zIE(}uv78+6DR#Mbm6DxP3IX`B-N!5tlg1jE(OLVSQ8krY)}S|%%&B;CCn>72$9y#B zHg$Wm`|pIy9!TfT2euKfx)Zd6WU{TT{?U7id0tB-!Ye25HtJ%4J#&hYTMY5nEY_4P zQRZ3EdU#TAPL3U~y^4hFoa5HfbeO+&c!5%K9ZnO^SRCx}{>eRdL->P!$x8HwmO?s0 zfck)Rb8|?xyMq(p!t@v~ZR0)S=KvOA*lQ?yiTs`azXblK8;qpy#XU+H)?U280?bIqhyv4K1cmG*fPHKba%~ z*NjJvRi@Lq<1-kQUkY8+6F83otaIl0xU$rFgW4fBklATBZB_~OY<|Ba<)=rI*g@Ju zQgx4K;XNBjdrRU$x;%i{3>Nj5)1e)3>+hTA6lFn@z|9b^xzj$e?8q2^Acy^GUn@3w z>?maHG8NqZvN{xEdoad+X^JCM(!>8hnQ=jxOw3V3Yvgj(P#&3CsT;oaLIS&7y2^CA zjN!mn<#9!z1Zpr~2N-$*wghRs0#O8F*$%-Qv!7+23P2nM3tso;)$Cg{_H}t|wQ)pX zy!zkgPiR2hov48>P`YCATP{#8OULCmXYq7`)Y-a$^)?N_3VW{ht}V!BFZ;V!~d1&QILG7gq={ek-xW z!7fkbeh6(%HGn&JQaFqaF}G(VMjL;*aic1{$A_@M)k2 z0&5XgYA;YzO&NW|dgK^DFx1)ZclrC#5bJlw(oI8mLKtCa18e!p&8jwZZY4$aDz3}_ zVL|;XN~cVQ-IpK!$We)yghGS8Nd|BMyEBK@5Lm2%X2r@CwQW`_LzNxrjnZ+UBm9hJ z`A>+z-?6sndL61wF0lTfn=>$3o*eWKVl6Qe01A<6?zCHZcdPQnwbLybFkNL)kxKfkOGAzLLczAm+l&pBu zC0_&A`n4d;+M_ie#1iAp|5W|^U@&s07tkDbcU;CT7LntTDOM?Za&!k{0T^K!L+xXM zcNeV?z&Obh@@l#FLTb?8Yf)4<1O;f9HaCg66-#W`DzS@l-G2-7>2X6>(Bgz#m(rRb}UwHWxK(klfZf-NMPxzvakYDlQ^45ZfCQhbZ6zV-eZOn z9y!CP{jXL52c;`_=g+tX4xsA)TYjg4wBLje<+ByR2d!bz#^ZK2-mJw60XKrvVJstl zolAQ^2^PZzoo~1Z`WF=t(9Dg=g4LeijCedOrvsYr9)KWG8Kl>9fI=Psr z+j5gu`C9+d-;prY>E~l{=*vvE#u%RnUY91{T^=WU67X$$djBtr2mG*GS%;+cMX7W1 z4vZjUo0Jms5VC4e-4PMjEWTVg@p=Nl8H>&m#AVMM7sM}^`SyZhw6D#xnStCMg{DdT z%cY7re<-&K2=~ZMqv%!7f(9KR%+Wzc1nrInk=7N5-Ji#d*A0om@xWf`_wqO(>0`*?9n0i zZK35q{MgN>{2aZ0&9>L6`2MqZ4tku|$qS!V6hmm>zmdn4OXKKo##QcZcc#AWVlu2W zPul-86u@?U3@JX4`X*u~`MXXkI1%yv;dV3q*WoKUy;*W2Ee7IP$`7E*;eVX)I|8jYMW(TPS; zU7;$LP8jfA5wr)EY51DiS{pVEq+zf!4&c|V%PtB_qnHiBt0lAji(94>hA%ib*S5uP zcI?2-6;JIlw3A`%LZXaE5#IkghK~XUtFzBo^99K0nvwM$Jx9%|kmQ3X)_KXx4$HvD zK89uB8Bj4B)oHCZGQVE+8sp`jvLBDkK3B-wyE%VzM*MOZ?)xaWT7f!4gYzz>-!1`W^0ye0v}0)#uzF>tnH6qiUuBu3%=hn zd_no4iR%crWiwgnw+9vc*?RF$p1%3Sr_{AN^Kpe@Z2BnPxR)tgo4_4L{t0My-sxDRI?~}&sYkGwXqd=KFt)ezsxauAqENcZ3_Rr1 ze@>uJeU>kCyrj4@vDScO^t>|>Hxm3t+jr?fPeu^-1~P51b3#nSK*3=Xg~As3#5!o?R{8uYIJ6IuVpE4Iyt z_D3luyi0nf3)8h;#H(`kGZy-OAAu=;0Rz_lYPiPB$vuQZkDkyf3@FCi`ecO`4hFQKWy8(QzwjR4M_#bsRJY7a<%_$r#<)mnxGvcp6aPH zMUiw(mtuP*|6o3npCIl&xPBe}CFq*OwAmegZ@4*D{rm5uF|m;y@`QtN^P+-1hh|1m z{4nb4*Q8&oLy3+aD{XUe?8-qDLHX;8oe+uZw(jRK&s%A=$W5&HwP>C<;FiV`zC2!Y z$MnZc*|wmENy7s>aq7$$+~21{s}E-0e>T66mcb-$V<8GgI({91TFlSIqAw`Gtu-#F z;tB9_^09t79#nXK3{A@S1+lt3U`>)Kh<@&|NOkT;BMoSG#@olox@>LG-DW3wQKOyh zsNbAgfCBVpI=V6xT}!$J%oL8TQX0A-pWh=NNbp4=Ss`Xkp*d~>JJutynP>3d^chf1 zC807n2>B#)MhA7N?;Z*q{~bR)U)JFwIpi1|+s^i}Ci|nl{b}HErX{KQaMEp7aiLB~ zk-qdJz{^Hf{&aLarWB(seAgo%cXmAc9BaCUd80~3LhDyjSRZHt%D`H z6D?wHmmyLK1S~2btL7RQL5eH?5OMe4Agsnro)*XTVhR4~eNyKgb_BXu5Y)SG(vglce%O zJR}x-6y(7CnXio5{T3j&!jjJCt=CPdrt^t}Uf;enCC}!O6i{ZEATu0EJsxM}VrK16 zWEj#JY9naku{XK;sltQn@jZr6iN`BPKGoBVTn0g!A$4p?1{t~qHP^x`a((WU$@|Kl zP1cZys(wiOe6CyBUUGc!&ZpqPw3tTf53Z#Pvi8v8)4Xqg@DE2PQKAxHN`aqQ)vN0Y|L0WM9JZWk%dE-E#Y1trf>8J#;E{MPngLtN( z$uD(NN_`G5@`dhW3)Z$X|E_w3T9{URKF^Dx{68=i0U`*)h^b>vypVmR^@MVU9ZZo& zG=kxT|9V`yCK|2ytB z9Ji3FyZ!ejb)>Sv(Z5~<$Pv`p{7~on>)O?ht#6dIG{B+dT+GOrzHI=;E3exAF`s5s zF->(ylR=2QbJr7@h_gx!1{|N$HgV+YF@gsv9RNenfLm~27S_U z*LI|Vqv~0?3du+Y($|w!38Omu`LlWxbtb=m6kz#QUj2Jo8CxC4&aA1uT>mZK#QP_V zezcGuGGN$=uRpm%tlB`*ZEf79j1Bm0Vd3!CLhIELc5{Iddd<{lmZP=E z*Pvp`!<~!(@(PgI#o|hT2Kx`=5zqm`xkh&p5j3fMs=HoySuD!(V#q8q)~EcZ-HU8W6P6yPO$Aqq#61$X`$8-1F*Ihk}}I5*vKd_79sBI$D@dT zlSYI+$X`H&q@o#$eJqh+LWfC|dbjZ1(z@NaZy&1H`tHMdUN{GsL~2L>RR(hO@~f_S zKX-4ORFpnBN^W?>4&1_z_I5OHxXP6a1!Vk`c!tdGFoJW#|5cWco;bV+zxrplse&KA zh0V}H={$_?gzP4d~ zHwm>UVubP5Fvhh+>uV7B-w~jwD`T zoT^tYb#w=(nv-xn^tXNGR2Lqe1m zkdTG}L=hxJ2|;0$5JaV0U=R>dQo2DAkPeZC5fo8cy1PWWbMEH*yZ3#^Kl~`1Ip?gs z_ljpdYpslb&kko2lxf@{7)O>0U4z?qh=JnQds6NTC$x3UKF1{j%Cr5-zbGgEa!~wL z-KE$G_c;Hkv*KMqu`vGlZ~*`)5A4ar-9-pmr^}ooCr9fD>Ir~!|6I(36!;pIN5K2U zZ|>YP&e*4lBr-fC@DVW5EW1c0ZSk4&qH+<88(}C6Qr&Nn=EC;{p9Tc>L3(Go5cp!_ zLBt0v7+t7A%TD_qpfTR(3OBnc;!Q+PsN?QbnX*dQeG8az3RqsXV^AgRdMe=MW6;e0 zkB{7V+5YPY`@o83;{BBbNW7%H7R z;FqGcFT$~Dv)AH}PR**HuKq+v-{Z)6zw;$gZBf6C#@zxI`*BNEY|3W_oT)75TOoSmPf`*gE*4Ll)p@87gJ%G zmZ|-SIdgj^z&TnpQS8@bN|Avi4tYWX`Krn1Uh5#=CB;z1hG@vX@vJGvF_UGP#{Kk`7Z6+Wd;p8##K!r4ei4EF+L|&7PS{|P8h9ezc*I9 zcQ22no%eqFyKcKH?BG3>Oj6x=-LxR(#mp2~&I;f@`;)oXL9V&1344`xWZH11sd$D~YhrgrT~{)y&kKW%R4 z(%Ey8*3eP-A)Q7BP-reg>(=&!x}FF-ohhh&>X)t(gTD@890`2U)88`J=UaJUgW`}1 zUX&Dq?{iRo$-8$^3YQ@^^|m|qebjZTrK!am;p1bWCIo28URWjl6PdOE^hSNT+wbL~AljY;=bYJ-A^*3pqMvv?UJ!Sdw9jXIC$KBld zaPty@@{Pr<(I^G%ZiNXYsEYi6Jar~`C|p8HmeOJJ?sC}@HTunc&iVVUlR#Wi*@0G9y4Y1#}Z(XLMlwuz0PLulSYieI!XLj zK$M03bbD%St7o*r;a;V&74A!Lv^+agCmF=OPrbef+|hAEQNWuYTsMXi3n<^sC>;ab zUXsrLU;-8c9u$7;yn4T{D67YU=dsKqBJS6RSd6eI!FnHoM4IgYbfh+ZUBVp*`|;XEvx2Z3 zKkn+wM#AA}s-bg}3w8E6=C9xd(6m+7$W7Lxm>=IKrV)=UK~o8wkZ&~jJdPBHrf-qo z;|^#XST$2n??@C>txFJuIe5|4)MY{}nyBfSWR-8z7kZ7);EOw@n6OP5+bzG4z4X?9 z+%?sMy^AFSQE1u@k6}^I+Wk*Snor9nHzoJpNH?12Jv7Mj6z_MNh_H;XGD`5?ttg5r zts|XU;sKkzHCX#lRxIMLpWl5dwo5O(C)_IT#i6J&3GMjJcKqe!a<&FD0Je&t#w9RN z(D)*i-6Jss6NteJ7$*{)9qkx`F%QwM61Fb#{j+ptiIO+ClF;OwNhciEO@#>4>I?!Hm%na{>{;usDg956iw0nR*F|e=f$bGC*G7Sv_j)tC*SS_#|wd-f!#h;rB0&>ziR7W zk=a&Sbi$JQ47#O+pVcLke!cjPl5tZ4y7ZK$=rS{4%|y0K#bVALoIR3#I?X_Xga-T})sgPs)y? ztE*8ccFcsrz2A0TW4!!nQ;Na+#y+Pkn;04^1O_~Vhb{g)L~Syg79K0S3*4mr`#Fj3 zqW6Vps?oxeE7O{WH@-L2F@Jgd{~5L-+1Z6HStJ}8YetD%LdqX}e8K{xFJienmi=j! zq+bPCCS!X(t4E&`KJyx2iTvoecKi(ctUU{4O08E#)n%TFlt+};O_E!8lU1R$j;s8LIT}x9e_~^P zt*HHk%k}j*(r5sQeSPwsXx$2&2kyo4ofPRUatKi61<1Rn+L>-$8Tr~JT*B1)JtCU` z3TV)>np^5j#ln68HFjiJg4@6Ij!vIaJRa{Sg9J4!BEp4@LsqBn>2-A`qCfVm?ldO< zoAD$CRc~x;X4Sz|g1hLc+O*!at7_HNyccRs4=<0+HOc997QS=-PqKC}0qdYdf~H(P zc#567#mi|@Se>LUP4YjMwb-|kpG6(z;!iG2mcA`w1Ejgbfi%_Y2|r?zWoJ@rKj-Ee zf5ATGbdFSABa2Yg)-m(hsiu)2NT&&$9j(7_NM_uUaB`B-kSvqGF-c`4SpUdJK~AqQ#%2W7|NC9X7brq<_W10#Uaf}X{eQw>y7b4n*L8UN znmj@2ML#yIRprI!b_g)vbW{J6R#=vS+e%vF(8~w%G~XakO_A~X3rI8=jJ!`o(BJx1 zk%9FIJq%jji`Eg85p}#T$9i=B{<366)Lcmwp z>SD`lO1~=&W-fcMuGH7jz)3D1b0|?P@!AYyLgtqK)oF{U8fV_4e^J&1hWHhnc;LLz zW?aaVcJeoivK{R0`!y`&7&6h_q)w@*53V|>bp~<@KmhJ~zg+w+=SRTF94jfrjcqia zoS(`6xrSemx(bYWKC}LGxfzrRjD)nYui0$tA&35Sw#OWQZPSYmSVLGxwQ=MQ6Hxts zoizRae`o{??fV0VoZs~LG&r}^91i!u!U?9HcyD|l{GWQM9p<{E_MT5cuG;$zIHYm$ zh4pt2Q-W=4JwwL#hsJB~SpVMoyJ&P`vURd}84jtD_-JA@w5>%92H(Jq00}iThZo`K zD+nV6yxJ6WVEl`(^d7b$;YoCj!--KqxT^B-c$m6p$=6irQQZpaTA7>EyT#9LYpHA? zlyY#w6?%~F`FxwMN-;ZofN^E!Uz885LzL>eaZ-*X*XRB67U)9%!T+etO?+!j>=( zTE9P5sumGk?qVOy{w^W*K?Z-gG<@q1D(ZKM;av`$UsU#2-`{=l)hw*)G;)}>{mg(R z2UFa<<}SRu$(6qlT=gP#F;Q)~;|1rtjnQj0JkG!-QI=itOVyR>1+TQKn*5xYDM+;v zWhcYLvMJKO1<+Hj?ka_*(BiVi!o$n&hBhnat==<}tpi&|418lri!MD>Gdw2%=R~mH zEN{jzWv|T(-uSU2TAJ3HuAHqIyUZhS%41m-9c|Y5ICY9q&-R*I+!w@b*1PLzv zggx)am;s604QH5A?f)Ko_O8F5JXe@p5qFbqDywUCa=zg7O5y(4cFPibet@?R%3d6- znJK|H$_Z~+!@9LngZaFjU(*V}UJ6+MZW=o7QhfAttv9Iv%+wY1+|Jks4|qO?>}`h= zSuDE1Z`U26^suVyv|uhR!-lN;=Avfk?a5)98(}~ zxo?ujcT~;8$v<+rb86( zXaDHi*oCwEfUfqF{zvrQqQcdlJ6qyQzA_Feteg{4xS3FQIJ(5%r{W3R7v`-yi29Qk zV2c6pxrPp0_)SCA+gnA?wXCP6@~rOYMqSNmsQHZHwc?X>TS?C<7xE{hr&4;bx=-UR6tWlXPr5JCR3 z;$E-+&efTWD;nxk`1B|vJ$&=?()ps=XTNjh-2xhLhm!86ohM=c#3i20ocQiTJnJl6 zk)Ak99`_dkaMo?M1FNt}gXUXw=M;b9M5H^l{^#sawUBbG@NfD$6{oqhj}vTlL0|$? zKStoF%C!(;rx|-L@L(Bce=*-hypWYiUW9OOtLL=shMfL6zX%T=mc`NP$f0LISvJf| zHqEyC*=nd`DwCnYYj2l*cJcO)$EH`$%YU<}@mcSaC1bZEd~0~=vPa!BE#}@(roPqP z&Q|(mRZ9vIk1k2n*n`UFsxXZ@I3TEFvXth4d*zPlP8xv_4jFjEf}Q&HT2JiR3`186 zx7D07`H5gTnKi&_QUi>b(D{mM9P*K^ayG)>TU3-~*%40F6ocrf$i))S^y3@`eXv_* zA3hnt@aN&!6k?GGgNYs2bGuJXh5I(LL-s7Z#jOKB&Dbf~cHH6_wy1wR#F2*weG+PPz-n%R#lW2zUDN#*B;;Dbp* z{9P}PoO&MZaTIrmCI=2+AGlIidTqlki3_!*w)af|x7uk5&h&nO^SPtC+GjaRF`tF5 zHaG6(cHhu{xw~hg{iIbmInl}EZ|>Iy+oy_ISyrekmrO(?<4jK_(POK!OjPJwg}vB7 zCreaD(9UzXe9CLzHHaq~SSK-DC?h3jDL{EB_LQ*L6fN^dyQ5s@L#*>%kt!;M9#JjS zB=o(%=`E8c9({?Wuh1H-9f*`osqt)tee@sG`S}5iMTRE=*9F==x3HQ_f1h1RHx8u! z4%x8qHVeO%S0v2)ODcSR?dim^-5!gQ3~5AS1po+KQ)ceB?KHSS6i_(7SW?W&C$XaU zGSrGqZQ#Az4Ue>h^Jp05W6(@~q3Z%iY(Z@F2pXWs*f&)AshuldkI!e_DG!tSN$z`A z+wtN~R&BJ`jeT+zG52Qg{vkkhaMgFOeY|<2r>KZ?pn^K=zm=$gil^BS;`GoKFAn}{ z2!lGFFo=g%gNraSkFo7+v8=sxote$#I$g4xH}QRRAHoCGbvgz%7-`|58Q&|y z4x!u&hjRZyCQ-UZU;XiMcIS`t(-&oosb===rQ{xZTz0=KS$9X|@&>j#_cd<=Uq6}q zb0>U;pmD#F+Uv2hSTq;TX>$u?zC-Q0PdTsYtikidY1ZDAyd-W!CT-M`>b6LQfWf2@ z@p&u1P3d>ZDi<+bMBKOCX}o_Jq{GQgDC&KJ$>drWcGm`}(9V02+3ZSvK@n4;pi8$x z|9a$*GnPNJXDnt9v8F=_+ut2_Og&T;kf6NX$IUkRI^t@tOzz8}s5L>b_imb1Db*X#=yK|OEGx8uQ= zx8D7^k+W8DzS76*u8hPBm*=;r%~y-Z5Ig$Pn@8J-w%y^CjV7dIs@|tFt7^r|f9#_N zOF{n1;)*HVmu|}ovoB|zztPBFD|vY@pN`>hI*_pAC>$TI=986gb~t7ubxJ3wtuvJ)8q zD%er{!^vN;PrH~LNGx}liOsv=hh4~Q66XZqR6tyU+!xRK?7fN5is9nuEn?!gepcz! zllw;C&N-s0@JA6`7)N)mi1BYFXy=}9uG);-2C4o{4{0IiuaO7xj7gX}j(E`L;0vbm z?x0qBS2F7|`y26u+TpKsylr%gAHAz}wXVAw#UT+*k1^Rjpe_PS_U>U56G)iVfb#r$ zW(q_QU>ll((-vNYwEtad+D3tB)&Nqd)Zw0fLD83mcVJE2iSSPEtg3?7aGbaIIjw^0 zrRe*fmb2qIa+j^JkH8WV?0}kACn_ytEB^DjSp~ZcV_|jW-?o{I$0n9q&14DpxI^hZ1 zp-Ce@SphQIC-MrU%(znnF4Bju8KjXaiL)&|O)E94;e~J4=v&~g;~@ML=WbJ|w>_L6 z*8O!jdr|j3n&39lnv)^~JXJ%Xg(%xH=XJm)V)+I%gvUgT+r?PoiajTqVo)q3XnwM* zUs~uE>6{wQYGYJ}1@BOl#N*9lm_izm?nw=-gAc|NzWglDIpjSLNJmk)&F%6^y4xt= zBeiqj;7}DE)cfA2wM*zv{9dwyYD)FtIfLiCB2oeo-f8bBTXuilRaoHc956I5kQ`RH z`5$RuFqjGyLq0b;JaDY~a9xpMw*I!i_mym6)!BQAXBOaJM-GvKZClJ?{FZas@>7-p z`*Z!U#0$&_(u(@JL$mzvl*4#k(D0bQpiIx_ItY-TGeLiICBqe$QfCWRRRQ z6+u=U((!6wL4Y}~K*+>frIG-Rc=!Cg{;f?1ij>;)n3b>;>#=#H zS0z5nI!9*6=F9MGs^aFxkLeOOcDZT>;QWch_|wq(KS8x0gjxrHNt(*lN*c%5R1y`? zCSM=32l;id-yJytchbu1zEFQ=6VVaOtm`yK z4A1PJTBjiXxAp(<;Zz{b#)tr=GZ+P#@T=5=VQlFnHtDY4AEE!uoaDXhMnoJ0I^>+M zgbM)f@< z$nkMcq-TcVUgchRq@R$*Lh$crctyUa*&iM3?LT+i+8G@_;Vv-QLZYb*?C*+vgpa0v z@7SdDiIgTi3EP8z-h`jh0gape|ViQC`-tT%kQFp3$wz#vYc@B5F2`TIF60Zx=qLHG9ETR-#odQvrr0sO@l#@4-H zgrZcRs-~2=xa?=i2An8zpi=SKQ2Naxddt3!4WC$*qGrXLKZPW{z7&P-!BY4$H&vZ- zv`!IRhhcI90kjC5ItEV()WfzBD$2|B!9|nK|C!`T^mvk?xfv1QR1$`fG%%VG=To6u zd!U!-P54a&dWq z0(LPW?A!$hH6)l_jiM*%LrCaqT;Wr#3taJcbB|n_C^E-D1PD9&KfVRFOatEge?=UA zP&E9dEjCOZ5L2+mKgHWX-o*>NE#3e&j4;4k-k1WFuJ^l~QNCDB9l8W#fNcR`$VVtygPYxY`+tJW6|L*1-(7zU&t=lFP6j}iFB|m4O_AB@Kbgs4KacDn4euwXW)QoYd(1bbe&BojS zxoJax-GELkZytLE$3Av0MEjFmqB;m8Y1rmwyvg;9cHl4M^&04?`m1B?I%9TxA1 zujGlL9W!5m4BYkk+vFCew93%Eg`dq+3JjQ|4LPx*TKrT}9(6)swC0N>QC4|1`-7XH zc>#K{*h4X0i*{`$%Q?dJ~%=^s6l<_Axw$E z76}~{-#DU@qI+84c!7Duv;-w^*iW$^ltp*ze$R<>cj2C~PPIJB+DM1kmsWB8?`It!yq)#^r)jnBQp!jqUj-y3)wHE8bN$ATjv z`b46|d02lRc8=4pjDR!basGPYKypJ(1$;UNq|ETWY1B`4Uj@)&ao0D5J~J!So0IxH^+T;macHtc=#7RVTsk zzRxMj^{!s3$Jvc;5i-SEG5+9y^KZ767?I9#=V5i3X#HUrl{94X9$kcJ5O4a<(h}md zPAm^_ zA@lTK3!XfC_pJ4#bu&}Y8aBx%V@XHYGiZ|W@u4ZeHa7W%s@5UIeG z%To)?$?r+C`rKL{!dlRg0y@vvGOP!Esks5#^xn6*XIarNff_Ap18Lm4MMfJ{BX=k19Js#ayWb}!M(Io_CmEcAnu#xW&khXh(npdmA@AJ4B zM{#BX94TN($B{@;ylT-@4#nEE6QH@d0R{G+g@>>?f=w;9#9t1}hpQxh_*fLy`fY5B z;V2Y#R#6R`G>Bf;qdstDUI%nZ;jYHP@gH(V`~x41qfV z4%US;a{faZ6qRR>hoa0mFWuw;Ptt2{8wDk%pB+!5&?x$)sw>EIw`;u5+&^j2|px^nJeDHpolcaP?gzXPg8X?l*ybq-^Vo*4kx);zGz30_|%0B6)?v zRLhs`3B^NiBGLHP)jH(|}o&aP(r=;@K zFMh6~+k5QP)~EZo$78}B=tI(=VIifZ{r#iDkPB~XnGgoY%g4N~c0&2C!~J`@IvO)x z)O%}r7$HSAgnB_)oUGv-A8ZU`$08FcjmY`1`p++j-&TZm`J+QY>m3|<_T1Ri8#GFn zZsZOtWd}EkKttPx(f;_R;JBUu0*U|!Z~~TY{o+jFmG-`BxmO9lcY~9fzRAl6rJ(99G$h>(Z7ZGq)>;c` zZa!Y^Pc6^Bd1>h-H1Yzp023uh4aSLL4qSd|nXf!6)YSTn83G=6;}oRg)C$LLJ+hOI zdvn*vClV=&-{}i4f{4M{+T4WD*CZXl{(}%guLF{LXT<-~NhAZrl(nob?)<07uoO>X ztXq84E{sqD5so-QECL9pQ6hMoMkg)s>BEJ1i*(# z?#9(>T`367{Wf&k)|h?k9{OR8`NDJYlM>p_#@v46@egjcH;l(csV)BYS#{1R@vq&q zpka=0KE9TH>534Y=$Y@sDNf7lDH?m-@-Z{bble&jC!+Yaauu`_|4l+@xa%Ln#{}{X-U7Hc&qe;L?t;dz_?Qf&|5P?TKFo0A zlr04r=vF-=?=zW0f3fGs6=}53{+migZ_<@7g3JjBPBS~i`Xf{X#KQoePBzw0+dgsHn{2_B_6kCwV&`|49y&Q{7~H!LJPv&& zmmC3lw_Cx^N#jl^gZ)*8q1Mnb8@Do@E8(1kNWg%#ygx~AswNQenSf7J6uLS{blb2q zQ;+?cj0w2#u~VxC`&FRwN294dL7NFz&e$w>ysbd)tHWSr5!lxT^CJSjbNc6Oe-^R# z8Mi-qO*RLWf6YgjHd{2!3rlGlw{1)usgs>nZ++lzNKSoQX?+^xn^HI_(peyW-nQu7 z$2|_=|BJc9q0lrJ;PfmwKt5b8i{srMf`lW1h=wZT%XtZC4&kRi#`n_O(;qC;M5s#N z;E3VL^mooi*--R7W+E z!l*yiN`V&9Bo1CKmXMg^e^M)eZ0IIIjnM0m=}>7*%Ox8240S1?7+Mhc z5k&|)R4A#tQpF!CkJ{!;TvN)Yj+pH#KL$o>>fp0Z9>!4>H(J{5 zc&i`!DCL)2AjIC&Z~Fv|bb8VyBAFdymUgeY4w=6nD&LD|B3fFA-mHT@cZ={K_xwJR zefD_+=crP{hJPu4z&S$FS%5Al;e2}iD?qECWH``Bpr3MP2=3~J=m%JxB_GkcSK|`O zp1bTBFpn?4`*NuZ?MN|+Gcu{XdQf|6y+oNYFRxM}lZcH-+=Mamz~o{#0dsyTR`$Ud(Xp|IxCMx=Vr{YQB|>kAM9Y zvbu)z?T6QoH2gWr_M^Z(ee~FulITy)eEO<;wWLzq|KSP%H>7bU=KscizJg|N&b^(R zMMFzROY5GcIerSC4+#rS@Q*D78Xn;v9A73+RoL?QyP(+|cKnmqv24#xHP*4RX{XFk zEl!sWVQ;B47B|?QoBi^etuQj=ILL4VxjTYr9Co6#AbhKev3Ylay!ZGexjSO}0=XH5 z>XX0tPSRW7b2a%qm?}jY&wshrG4yb5*@@ZPhx7&=5<~rGr>;BjLz5hXfEi~6CD6GS ze|=BqR|dareyT}OAcpYeF%c*h-sU1-O^v^ezs2*uXE>y~sj%LJ|JJ?EHSZ0BLbXBf z)5mu&!7*pmD{}OS0b;U4T{CTIy{$@M<#nX2V45z;3eu>XQr6MBCT|jZsg}QTb zHrdfWZIqi<{@JLWbIvmHP3DQZ^7K_Faa$E;gAU3_j_x;yv)EdMxphU{@) zd<#BzwUE`ieYO5cy%4VRC#BsQwW7~=n3+5u$m>=8KJwF$ovdZ)!or53&GWt8ItQ^- z@3-aZZHc}JT+_R}CVbznq1BNCktkRi= zyRh#)7B++TAUf6@5JA;9ufu8Gy;VyoBUYE$&-vK1S&z!v#)^KL`{om*oA!1Q_VGBG zyZOX-b1c=NB21*SA5Icx)tDrIfJ@Ov0e2MVFutMb5$7dP*152<+L$Jta(j|wfRZ;o z(iPA!n1-p6((ICNd0;Eaqu^;lkFExumI#lGG)jLXlG9Q?l0{^GUTdx&D3CDmQ}Gk3 zAT@dJ8gMN=@chf&Me8Z)jn%4$i1fS6j@jF+Hb&l6N!jI()P*QYUQ?W2jpm87?PH;QE@7mkQ01O5-U@%UTUNdSQ*Q{z`~woeuqLbhSi! zTUB?+nC$gNDH0p__ANnkc&bHuHtCx|j{_87&^ElD=zSVK?e2&}{ycL2(SMYSy1c08@3qZ=6BR^NdZ&ob70mQ68hLbYs)F2z=O;Q1qJ^(e7=uOD9s8GuzfwaW zzxl#nQ<3Y>t(9-|{1VtZWVieQoh`aj-j;ponh?`x*Q`4rkQzqtT1uPq(X-DpX)N>+ z?I)f`=Ds->YO=UXgJkC%^*?qX1O&ZYYFqaeET9CjvPfpmXk*9ex1QtrjO6ff`S^y) zYo3?qlT1+HjfiJu-Wy8VQcIXGK1FaMF;a$La#kI+?eE@@&3w4Tp3a59qO|ICqZ3`| z{rpg8i^eh^z6QIFK-m<^qg5>%q+YYE`xvo>-OatMT9O<)krsD?gFiJ9hhT(a@(<2D zF(iOcOJ~;d+q1|PbjVQ_kCT}aUpd&3PQd17 zf>0pyzp|o+!>6nX3uWx@?{+R6oFVt_xL^=gFM(2osqxalnh`kP8-@pVkP=1&;e4ai z-()muPpj`(8il_F(0ziFVU?3F8xJzE40H|Lk;4`O_r? zf%OwA7eE3bPOJ90sdzOAqM!w3W-0N!l3$v}<8Tht!=BTm~<5$y;k~!YMc~kZU=cxoouXeAbN$$ioME`dQb;5 zYJuE7lNh#zzd?E?eQcRz?U&ypJ_9=^RK5?jYv_jrlfwcl!cidI8_9QgRZb)qr~&Xk zg{6f^+z;t!IRo#3eW_Ux`p1g+1q|EZ$lLQhjjB@)3tjr2m-L*EH|PH;WOTk$!QPLR zJO-&~#Oj6qL$%p(#!YjyS$7j2J2~6EJJ5x+MS|1K=iFVZ27+5RRQo|Bp6ssX2-@716gJuZQG%?YQ_`s zi@8g|8Q#ci2?j2srz5Rr$=>PHx`~}T#2+#|hi4yOMdsWYCdrH4F6G3qCk6!EOZz)V zV46n&M|=Vyz{hAgWpfm~MIjZ%bG)KzLqLE-qU-u5H@X|V%li7`&l^hsp@PHHhl?+n zU!fxmxGRU{*7?nu--^fr5-i(2I(da3vM61@kMDoQ(CZpd-g`XviL!L@RU<;02w7lL z46JbQ>Ak4K_NoitO!d^fwrbo>|W5$8t&M^=C9Z^Y31eVsIGtB`2 z47DKw_9j5JCOo{<`r-NbgY%`$>{i+9FR#xF#W@=XgillaI^8?h(4$ggqSgwx2W+1s zh5gwH1wA?a`||1u0k*fEUj$5QLZTq4NC>wS&MVSVHrf?plA!WsOS>Zdh0aF@98B|- zJ=ORo;*mq09GCYZv2|D3V_|nKtR{ywA^rZ{AX4-%bX?{gHLO4jET(k$p`z27@LOP3 zV6C<=LL8|J?CS_N{LZ^gu7@OCj(WY=!{UA+T>$hxXW88QvlcdM^wgH-W-uYJZ0m~m z_?Sy4O=yO00nQbKgg|2s{n7b`U28N^nsX=yIRlT|Ci2J1PcT!wiD&L@K zKs3<3Ko5jCqh8=VIk_{hW7RJF5cG;bybdvFTRJKKUWwoYn1?iexf|Qx;KUpTAzeV& zbs%p6-xEU(IGY1#Z4sjV;4y(ydiltsRRvM_10wK-loc*NXe6$M|Ag$2=Ls`yUzIDE zD&8nnL|mJ1Tuzp0;Fl8m^Wt1RsSPIR^d~c>bH=(M=0UT3QF0LT&PX!{RIga#2Y|f} zxeo_bp4K;Y!pgDE!c$ENun+faajXw)zHNDxH2drh>fA9zmojVmt}Q*-7&HIP`=*

                      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

                      + + +
                      + + + + +
                      + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/automation/nw-in-mem/package/jquery-2.0.0.min.js b/tests/automation/nw-in-mem/package/jquery-2.0.0.min.js new file mode 100644 index 0000000000..fbb594e8f3 --- /dev/null +++ b/tests/automation/nw-in-mem/package/jquery-2.0.0.min.js @@ -0,0 +1,6 @@ +/*! jQuery v2.0.0 | (c) 2005, 2013 jQuery Foundation, Inc. | jquery.org/license +//@ sourceMappingURL=jquery.min.map +*/ +(function(e,undefined){var t,n,r=typeof undefined,i=e.location,o=e.document,s=o.documentElement,a=e.jQuery,u=e.$,l={},c=[],f="2.0.0",p=c.concat,h=c.push,d=c.slice,g=c.indexOf,m=l.toString,y=l.hasOwnProperty,v=f.trim,x=function(e,n){return new x.fn.init(e,n,t)},b=/[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/.source,w=/\S+/g,T=/^(?:(<[\w\W]+>)[^>]*|#([\w-]*))$/,C=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,k=/^-ms-/,N=/-([\da-z])/gi,E=function(e,t){return t.toUpperCase()},S=function(){o.removeEventListener("DOMContentLoaded",S,!1),e.removeEventListener("load",S,!1),x.ready()};x.fn=x.prototype={jquery:f,constructor:x,init:function(e,t,n){var r,i;if(!e)return this;if("string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:T.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof x?t[0]:t,x.merge(this,x.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:o,!0)),C.test(r[1])&&x.isPlainObject(t))for(r in t)x.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return i=o.getElementById(r[2]),i&&i.parentNode&&(this.length=1,this[0]=i),this.context=o,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):x.isFunction(e)?n.ready(e):(e.selector!==undefined&&(this.selector=e.selector,this.context=e.context),x.makeArray(e,this))},selector:"",length:0,toArray:function(){return d.call(this)},get:function(e){return null==e?this.toArray():0>e?this[this.length+e]:this[e]},pushStack:function(e){var t=x.merge(this.constructor(),e);return t.prevObject=this,t.context=this.context,t},each:function(e,t){return x.each(this,e,t)},ready:function(e){return x.ready.promise().done(e),this},slice:function(){return this.pushStack(d.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},eq:function(e){var t=this.length,n=+e+(0>e?t:0);return this.pushStack(n>=0&&t>n?[this[n]]:[])},map:function(e){return this.pushStack(x.map(this,function(t,n){return e.call(t,n,t)}))},end:function(){return this.prevObject||this.constructor(null)},push:h,sort:[].sort,splice:[].splice},x.fn.init.prototype=x.fn,x.extend=x.fn.extend=function(){var e,t,n,r,i,o,s=arguments[0]||{},a=1,u=arguments.length,l=!1;for("boolean"==typeof s&&(l=s,s=arguments[1]||{},a=2),"object"==typeof s||x.isFunction(s)||(s={}),u===a&&(s=this,--a);u>a;a++)if(null!=(e=arguments[a]))for(t in e)n=s[t],r=e[t],s!==r&&(l&&r&&(x.isPlainObject(r)||(i=x.isArray(r)))?(i?(i=!1,o=n&&x.isArray(n)?n:[]):o=n&&x.isPlainObject(n)?n:{},s[t]=x.extend(l,o,r)):r!==undefined&&(s[t]=r));return s},x.extend({expando:"jQuery"+(f+Math.random()).replace(/\D/g,""),noConflict:function(t){return e.$===x&&(e.$=u),t&&e.jQuery===x&&(e.jQuery=a),x},isReady:!1,readyWait:1,holdReady:function(e){e?x.readyWait++:x.ready(!0)},ready:function(e){(e===!0?--x.readyWait:x.isReady)||(x.isReady=!0,e!==!0&&--x.readyWait>0||(n.resolveWith(o,[x]),x.fn.trigger&&x(o).trigger("ready").off("ready")))},isFunction:function(e){return"function"===x.type(e)},isArray:Array.isArray,isWindow:function(e){return null!=e&&e===e.window},isNumeric:function(e){return!isNaN(parseFloat(e))&&isFinite(e)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?l[m.call(e)]||"object":typeof e},isPlainObject:function(e){if("object"!==x.type(e)||e.nodeType||x.isWindow(e))return!1;try{if(e.constructor&&!y.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(t){return!1}return!0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},error:function(e){throw Error(e)},parseHTML:function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||o;var r=C.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=x.buildFragment([e],t,i),i&&x(i).remove(),x.merge([],r.childNodes))},parseJSON:JSON.parse,parseXML:function(e){var t,n;if(!e||"string"!=typeof e)return null;try{n=new DOMParser,t=n.parseFromString(e,"text/xml")}catch(r){t=undefined}return(!t||t.getElementsByTagName("parsererror").length)&&x.error("Invalid XML: "+e),t},noop:function(){},globalEval:function(e){var t,n=eval;e=x.trim(e),e&&(1===e.indexOf("use strict")?(t=o.createElement("script"),t.text=e,o.head.appendChild(t).parentNode.removeChild(t)):n(e))},camelCase:function(e){return e.replace(k,"ms-").replace(N,E)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t,n){var r,i=0,o=e.length,s=j(e);if(n){if(s){for(;o>i;i++)if(r=t.apply(e[i],n),r===!1)break}else for(i in e)if(r=t.apply(e[i],n),r===!1)break}else if(s){for(;o>i;i++)if(r=t.call(e[i],i,e[i]),r===!1)break}else for(i in e)if(r=t.call(e[i],i,e[i]),r===!1)break;return e},trim:function(e){return null==e?"":v.call(e)},makeArray:function(e,t){var n=t||[];return null!=e&&(j(Object(e))?x.merge(n,"string"==typeof e?[e]:e):h.call(n,e)),n},inArray:function(e,t,n){return null==t?-1:g.call(t,e,n)},merge:function(e,t){var n=t.length,r=e.length,i=0;if("number"==typeof n)for(;n>i;i++)e[r++]=t[i];else while(t[i]!==undefined)e[r++]=t[i++];return e.length=r,e},grep:function(e,t,n){var r,i=[],o=0,s=e.length;for(n=!!n;s>o;o++)r=!!t(e[o],o),n!==r&&i.push(e[o]);return i},map:function(e,t,n){var r,i=0,o=e.length,s=j(e),a=[];if(s)for(;o>i;i++)r=t(e[i],i,n),null!=r&&(a[a.length]=r);else for(i in e)r=t(e[i],i,n),null!=r&&(a[a.length]=r);return p.apply([],a)},guid:1,proxy:function(e,t){var n,r,i;return"string"==typeof t&&(n=e[t],t=e,e=n),x.isFunction(e)?(r=d.call(arguments,2),i=function(){return e.apply(t||this,r.concat(d.call(arguments)))},i.guid=e.guid=e.guid||x.guid++,i):undefined},access:function(e,t,n,r,i,o,s){var a=0,u=e.length,l=null==n;if("object"===x.type(n)){i=!0;for(a in n)x.access(e,t,a,n[a],!0,o,s)}else if(r!==undefined&&(i=!0,x.isFunction(r)||(s=!0),l&&(s?(t.call(e,r),t=null):(l=t,t=function(e,t,n){return l.call(x(e),n)})),t))for(;u>a;a++)t(e[a],n,s?r:r.call(e[a],a,t(e[a],n)));return i?e:l?t.call(e):u?t(e[0],n):o},now:Date.now,swap:function(e,t,n,r){var i,o,s={};for(o in t)s[o]=e.style[o],e.style[o]=t[o];i=n.apply(e,r||[]);for(o in t)e.style[o]=s[o];return i}}),x.ready.promise=function(t){return n||(n=x.Deferred(),"complete"===o.readyState?setTimeout(x.ready):(o.addEventListener("DOMContentLoaded",S,!1),e.addEventListener("load",S,!1))),n.promise(t)},x.each("Boolean Number String Function Array Date RegExp Object Error".split(" "),function(e,t){l["[object "+t+"]"]=t.toLowerCase()});function j(e){var t=e.length,n=x.type(e);return x.isWindow(e)?!1:1===e.nodeType&&t?!0:"array"===n||"function"!==n&&(0===t||"number"==typeof t&&t>0&&t-1 in e)}t=x(o),function(e,undefined){var t,n,r,i,o,s,a,u,l,c,f,p,h,d,g,m,y="sizzle"+-new Date,v=e.document,b={},w=0,T=0,C=ot(),k=ot(),N=ot(),E=!1,S=function(){return 0},j=typeof undefined,D=1<<31,A=[],L=A.pop,q=A.push,H=A.push,O=A.slice,F=A.indexOf||function(e){var t=0,n=this.length;for(;n>t;t++)if(this[t]===e)return t;return-1},P="checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped",R="[\\x20\\t\\r\\n\\f]",M="(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+",W=M.replace("w","w#"),$="\\["+R+"*("+M+")"+R+"*(?:([*^$|!~]?=)"+R+"*(?:(['\"])((?:\\\\.|[^\\\\])*?)\\3|("+W+")|)|)"+R+"*\\]",B=":("+M+")(?:\\(((['\"])((?:\\\\.|[^\\\\])*?)\\3|((?:\\\\.|[^\\\\()[\\]]|"+$.replace(3,8)+")*)|.*)\\)|)",I=RegExp("^"+R+"+|((?:^|[^\\\\])(?:\\\\.)*)"+R+"+$","g"),z=RegExp("^"+R+"*,"+R+"*"),_=RegExp("^"+R+"*([>+~]|"+R+")"+R+"*"),X=RegExp(R+"*[+~]"),U=RegExp("="+R+"*([^\\]'\"]*)"+R+"*\\]","g"),Y=RegExp(B),V=RegExp("^"+W+"$"),G={ID:RegExp("^#("+M+")"),CLASS:RegExp("^\\.("+M+")"),TAG:RegExp("^("+M.replace("w","w*")+")"),ATTR:RegExp("^"+$),PSEUDO:RegExp("^"+B),CHILD:RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+R+"*(even|odd|(([+-]|)(\\d*)n|)"+R+"*(?:([+-]|)"+R+"*(\\d+)|))"+R+"*\\)|)","i"),"boolean":RegExp("^(?:"+P+")$","i"),needsContext:RegExp("^"+R+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+R+"*((?:-\\d)?\\d*)"+R+"*\\)|)(?=[^-]|$)","i")},J=/^[^{]+\{\s*\[native \w/,Q=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,K=/^(?:input|select|textarea|button)$/i,Z=/^h\d$/i,et=/'|\\/g,tt=/\\([\da-fA-F]{1,6}[\x20\t\r\n\f]?|.)/g,nt=function(e,t){var n="0x"+t-65536;return n!==n?t:0>n?String.fromCharCode(n+65536):String.fromCharCode(55296|n>>10,56320|1023&n)};try{H.apply(A=O.call(v.childNodes),v.childNodes),A[v.childNodes.length].nodeType}catch(rt){H={apply:A.length?function(e,t){q.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function it(e){return J.test(e+"")}function ot(){var e,t=[];return e=function(n,i){return t.push(n+=" ")>r.cacheLength&&delete e[t.shift()],e[n]=i}}function st(e){return e[y]=!0,e}function at(e){var t=c.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ut(e,t,n,r){var i,o,s,a,u,f,d,g,x,w;if((t?t.ownerDocument||t:v)!==c&&l(t),t=t||c,n=n||[],!e||"string"!=typeof e)return n;if(1!==(a=t.nodeType)&&9!==a)return[];if(p&&!r){if(i=Q.exec(e))if(s=i[1]){if(9===a){if(o=t.getElementById(s),!o||!o.parentNode)return n;if(o.id===s)return n.push(o),n}else if(t.ownerDocument&&(o=t.ownerDocument.getElementById(s))&&m(t,o)&&o.id===s)return n.push(o),n}else{if(i[2])return H.apply(n,t.getElementsByTagName(e)),n;if((s=i[3])&&b.getElementsByClassName&&t.getElementsByClassName)return H.apply(n,t.getElementsByClassName(s)),n}if(b.qsa&&(!h||!h.test(e))){if(g=d=y,x=t,w=9===a&&e,1===a&&"object"!==t.nodeName.toLowerCase()){f=gt(e),(d=t.getAttribute("id"))?g=d.replace(et,"\\$&"):t.setAttribute("id",g),g="[id='"+g+"'] ",u=f.length;while(u--)f[u]=g+mt(f[u]);x=X.test(e)&&t.parentNode||t,w=f.join(",")}if(w)try{return H.apply(n,x.querySelectorAll(w)),n}catch(T){}finally{d||t.removeAttribute("id")}}}return kt(e.replace(I,"$1"),t,n,r)}o=ut.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return t?"HTML"!==t.nodeName:!1},l=ut.setDocument=function(e){var t=e?e.ownerDocument||e:v;return t!==c&&9===t.nodeType&&t.documentElement?(c=t,f=t.documentElement,p=!o(t),b.getElementsByTagName=at(function(e){return e.appendChild(t.createComment("")),!e.getElementsByTagName("*").length}),b.attributes=at(function(e){return e.className="i",!e.getAttribute("className")}),b.getElementsByClassName=at(function(e){return e.innerHTML="
                      ",e.firstChild.className="i",2===e.getElementsByClassName("i").length}),b.sortDetached=at(function(e){return 1&e.compareDocumentPosition(c.createElement("div"))}),b.getById=at(function(e){return f.appendChild(e).id=y,!t.getElementsByName||!t.getElementsByName(y).length}),b.getById?(r.find.ID=function(e,t){if(typeof t.getElementById!==j&&p){var n=t.getElementById(e);return n&&n.parentNode?[n]:[]}},r.filter.ID=function(e){var t=e.replace(tt,nt);return function(e){return e.getAttribute("id")===t}}):(r.find.ID=function(e,t){if(typeof t.getElementById!==j&&p){var n=t.getElementById(e);return n?n.id===e||typeof n.getAttributeNode!==j&&n.getAttributeNode("id").value===e?[n]:undefined:[]}},r.filter.ID=function(e){var t=e.replace(tt,nt);return function(e){var n=typeof e.getAttributeNode!==j&&e.getAttributeNode("id");return n&&n.value===t}}),r.find.TAG=b.getElementsByTagName?function(e,t){return typeof t.getElementsByTagName!==j?t.getElementsByTagName(e):undefined}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},r.find.CLASS=b.getElementsByClassName&&function(e,t){return typeof t.getElementsByClassName!==j&&p?t.getElementsByClassName(e):undefined},d=[],h=[],(b.qsa=it(t.querySelectorAll))&&(at(function(e){e.innerHTML="",e.querySelectorAll("[selected]").length||h.push("\\["+R+"*(?:value|"+P+")"),e.querySelectorAll(":checked").length||h.push(":checked")}),at(function(e){var t=c.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("t",""),e.querySelectorAll("[t^='']").length&&h.push("[*^$]="+R+"*(?:''|\"\")"),e.querySelectorAll(":enabled").length||h.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),h.push(",.*:")})),(b.matchesSelector=it(g=f.webkitMatchesSelector||f.mozMatchesSelector||f.oMatchesSelector||f.msMatchesSelector))&&at(function(e){b.disconnectedMatch=g.call(e,"div"),g.call(e,"[s!='']:x"),d.push("!=",B)}),h=h.length&&RegExp(h.join("|")),d=d.length&&RegExp(d.join("|")),m=it(f.contains)||f.compareDocumentPosition?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},S=f.compareDocumentPosition?function(e,n){if(e===n)return E=!0,0;var r=n.compareDocumentPosition&&e.compareDocumentPosition&&e.compareDocumentPosition(n);return r?1&r||!b.sortDetached&&n.compareDocumentPosition(e)===r?e===t||m(v,e)?-1:n===t||m(v,n)?1:u?F.call(u,e)-F.call(u,n):0:4&r?-1:1:e.compareDocumentPosition?-1:1}:function(e,n){var r,i=0,o=e.parentNode,s=n.parentNode,a=[e],l=[n];if(e===n)return E=!0,0;if(!o||!s)return e===t?-1:n===t?1:o?-1:s?1:u?F.call(u,e)-F.call(u,n):0;if(o===s)return lt(e,n);r=e;while(r=r.parentNode)a.unshift(r);r=n;while(r=r.parentNode)l.unshift(r);while(a[i]===l[i])i++;return i?lt(a[i],l[i]):a[i]===v?-1:l[i]===v?1:0},c):c},ut.matches=function(e,t){return ut(e,null,null,t)},ut.matchesSelector=function(e,t){if((e.ownerDocument||e)!==c&&l(e),t=t.replace(U,"='$1']"),!(!b.matchesSelector||!p||d&&d.test(t)||h&&h.test(t)))try{var n=g.call(e,t);if(n||b.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(r){}return ut(t,c,null,[e]).length>0},ut.contains=function(e,t){return(e.ownerDocument||e)!==c&&l(e),m(e,t)},ut.attr=function(e,t){(e.ownerDocument||e)!==c&&l(e);var n=r.attrHandle[t.toLowerCase()],i=n&&n(e,t,!p);return i===undefined?b.attributes||!p?e.getAttribute(t):(i=e.getAttributeNode(t))&&i.specified?i.value:null:i},ut.error=function(e){throw Error("Syntax error, unrecognized expression: "+e)},ut.uniqueSort=function(e){var t,n=[],r=0,i=0;if(E=!b.detectDuplicates,u=!b.sortStable&&e.slice(0),e.sort(S),E){while(t=e[i++])t===e[i]&&(r=n.push(i));while(r--)e.splice(n[r],1)}return e};function lt(e,t){var n=t&&e,r=n&&(~t.sourceIndex||D)-(~e.sourceIndex||D);if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function ct(e,t,n){var r;return n?undefined:(r=e.getAttributeNode(t))&&r.specified?r.value:e[t]===!0?t.toLowerCase():null}function ft(e,t,n){var r;return n?undefined:r=e.getAttribute(t,"type"===t.toLowerCase()?1:2)}function pt(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function ht(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function dt(e){return st(function(t){return t=+t,st(function(n,r){var i,o=e([],n.length,t),s=o.length;while(s--)n[i=o[s]]&&(n[i]=!(r[i]=n[i]))})})}i=ut.getText=function(e){var t,n="",r=0,o=e.nodeType;if(o){if(1===o||9===o||11===o){if("string"==typeof e.textContent)return e.textContent;for(e=e.firstChild;e;e=e.nextSibling)n+=i(e)}else if(3===o||4===o)return e.nodeValue}else for(;t=e[r];r++)n+=i(t);return n},r=ut.selectors={cacheLength:50,createPseudo:st,match:G,attrHandle:{},find:{},relative:{">":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(tt,nt),e[3]=(e[4]||e[5]||"").replace(tt,nt),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||ut.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&ut.error(e[0]),e},PSEUDO:function(e){var t,n=!e[5]&&e[2];return G.CHILD.test(e[0])?null:(e[4]?e[2]=e[4]:n&&Y.test(n)&&(t=gt(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(tt,nt).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=C[e+" "];return t||(t=RegExp("(^|"+R+")"+e+"("+R+"|$)"))&&C(e,function(e){return t.test("string"==typeof e.className&&e.className||typeof e.getAttribute!==j&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(r){var i=ut.attr(r,e);return null==i?"!="===t:t?(i+="","="===t?i===n:"!="===t?i!==n:"^="===t?n&&0===i.indexOf(n):"*="===t?n&&i.indexOf(n)>-1:"$="===t?n&&i.slice(-n.length)===n:"~="===t?(" "+i+" ").indexOf(n)>-1:"|="===t?i===n||i.slice(0,n.length+1)===n+"-":!1):!0}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),s="last"!==e.slice(-4),a="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,p,h,d,g=o!==s?"nextSibling":"previousSibling",m=t.parentNode,v=a&&t.nodeName.toLowerCase(),x=!u&&!a;if(m){if(o){while(g){f=t;while(f=f[g])if(a?f.nodeName.toLowerCase()===v:1===f.nodeType)return!1;d=g="only"===e&&!d&&"nextSibling"}return!0}if(d=[s?m.firstChild:m.lastChild],s&&x){c=m[y]||(m[y]={}),l=c[e]||[],h=l[0]===w&&l[1],p=l[0]===w&&l[2],f=h&&m.childNodes[h];while(f=++h&&f&&f[g]||(p=h=0)||d.pop())if(1===f.nodeType&&++p&&f===t){c[e]=[w,h,p];break}}else if(x&&(l=(t[y]||(t[y]={}))[e])&&l[0]===w)p=l[1];else while(f=++h&&f&&f[g]||(p=h=0)||d.pop())if((a?f.nodeName.toLowerCase()===v:1===f.nodeType)&&++p&&(x&&((f[y]||(f[y]={}))[e]=[w,p]),f===t))break;return p-=i,p===r||0===p%r&&p/r>=0}}},PSEUDO:function(e,t){var n,i=r.pseudos[e]||r.setFilters[e.toLowerCase()]||ut.error("unsupported pseudo: "+e);return i[y]?i(t):i.length>1?(n=[e,e,"",t],r.setFilters.hasOwnProperty(e.toLowerCase())?st(function(e,n){var r,o=i(e,t),s=o.length;while(s--)r=F.call(e,o[s]),e[r]=!(n[r]=o[s])}):function(e){return i(e,0,n)}):i}},pseudos:{not:st(function(e){var t=[],n=[],r=s(e.replace(I,"$1"));return r[y]?st(function(e,t,n,i){var o,s=r(e,null,i,[]),a=e.length;while(a--)(o=s[a])&&(e[a]=!(t[a]=o))}):function(e,i,o){return t[0]=e,r(t,null,o,n),!n.pop()}}),has:st(function(e){return function(t){return ut(e,t).length>0}}),contains:st(function(e){return function(t){return(t.textContent||t.innerText||i(t)).indexOf(e)>-1}}),lang:st(function(e){return V.test(e||"")||ut.error("unsupported lang: "+e),e=e.replace(tt,nt).toLowerCase(),function(t){var n;do if(n=p?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===f},focus:function(e){return e===c.activeElement&&(!c.hasFocus||c.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!0},checked:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&!!e.checked||"option"===t&&!!e.selected},selected:function(e){return e.parentNode&&e.parentNode.selectedIndex,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeName>"@"||3===e.nodeType||4===e.nodeType)return!1;return!0},parent:function(e){return!r.pseudos.empty(e)},header:function(e){return Z.test(e.nodeName)},input:function(e){return K.test(e.nodeName)},button:function(e){var t=e.nodeName.toLowerCase();return"input"===t&&"button"===e.type||"button"===t},text:function(e){var t;return"input"===e.nodeName.toLowerCase()&&"text"===e.type&&(null==(t=e.getAttribute("type"))||t.toLowerCase()===e.type)},first:dt(function(){return[0]}),last:dt(function(e,t){return[t-1]}),eq:dt(function(e,t,n){return[0>n?n+t:n]}),even:dt(function(e,t){var n=0;for(;t>n;n+=2)e.push(n);return e}),odd:dt(function(e,t){var n=1;for(;t>n;n+=2)e.push(n);return e}),lt:dt(function(e,t,n){var r=0>n?n+t:n;for(;--r>=0;)e.push(r);return e}),gt:dt(function(e,t,n){var r=0>n?n+t:n;for(;t>++r;)e.push(r);return e})}};for(t in{radio:!0,checkbox:!0,file:!0,password:!0,image:!0})r.pseudos[t]=pt(t);for(t in{submit:!0,reset:!0})r.pseudos[t]=ht(t);function gt(e,t){var n,i,o,s,a,u,l,c=k[e+" "];if(c)return t?0:c.slice(0);a=e,u=[],l=r.preFilter;while(a){(!n||(i=z.exec(a)))&&(i&&(a=a.slice(i[0].length)||a),u.push(o=[])),n=!1,(i=_.exec(a))&&(n=i.shift(),o.push({value:n,type:i[0].replace(I," ")}),a=a.slice(n.length));for(s in r.filter)!(i=G[s].exec(a))||l[s]&&!(i=l[s](i))||(n=i.shift(),o.push({value:n,type:s,matches:i}),a=a.slice(n.length));if(!n)break}return t?a.length:a?ut.error(e):k(e,u).slice(0)}function mt(e){var t=0,n=e.length,r="";for(;n>t;t++)r+=e[t].value;return r}function yt(e,t,r){var i=t.dir,o=r&&"parentNode"===i,s=T++;return t.first?function(t,n,r){while(t=t[i])if(1===t.nodeType||o)return e(t,n,r)}:function(t,r,a){var u,l,c,f=w+" "+s;if(a){while(t=t[i])if((1===t.nodeType||o)&&e(t,r,a))return!0}else while(t=t[i])if(1===t.nodeType||o)if(c=t[y]||(t[y]={}),(l=c[i])&&l[0]===f){if((u=l[1])===!0||u===n)return u===!0}else if(l=c[i]=[f],l[1]=e(t,r,a)||n,l[1]===!0)return!0}}function vt(e){return e.length>1?function(t,n,r){var i=e.length;while(i--)if(!e[i](t,n,r))return!1;return!0}:e[0]}function xt(e,t,n,r,i){var o,s=[],a=0,u=e.length,l=null!=t;for(;u>a;a++)(o=e[a])&&(!n||n(o,r,i))&&(s.push(o),l&&t.push(a));return s}function bt(e,t,n,r,i,o){return r&&!r[y]&&(r=bt(r)),i&&!i[y]&&(i=bt(i,o)),st(function(o,s,a,u){var l,c,f,p=[],h=[],d=s.length,g=o||Ct(t||"*",a.nodeType?[a]:a,[]),m=!e||!o&&t?g:xt(g,p,e,a,u),y=n?i||(o?e:d||r)?[]:s:m;if(n&&n(m,y,a,u),r){l=xt(y,h),r(l,[],a,u),c=l.length;while(c--)(f=l[c])&&(y[h[c]]=!(m[h[c]]=f))}if(o){if(i||e){if(i){l=[],c=y.length;while(c--)(f=y[c])&&l.push(m[c]=f);i(null,y=[],l,u)}c=y.length;while(c--)(f=y[c])&&(l=i?F.call(o,f):p[c])>-1&&(o[l]=!(s[l]=f))}}else y=xt(y===s?y.splice(d,y.length):y),i?i(null,s,y,u):H.apply(s,y)})}function wt(e){var t,n,i,o=e.length,s=r.relative[e[0].type],u=s||r.relative[" "],l=s?1:0,c=yt(function(e){return e===t},u,!0),f=yt(function(e){return F.call(t,e)>-1},u,!0),p=[function(e,n,r){return!s&&(r||n!==a)||((t=n).nodeType?c(e,n,r):f(e,n,r))}];for(;o>l;l++)if(n=r.relative[e[l].type])p=[yt(vt(p),n)];else{if(n=r.filter[e[l].type].apply(null,e[l].matches),n[y]){for(i=++l;o>i;i++)if(r.relative[e[i].type])break;return bt(l>1&&vt(p),l>1&&mt(e.slice(0,l-1)).replace(I,"$1"),n,i>l&&wt(e.slice(l,i)),o>i&&wt(e=e.slice(i)),o>i&&mt(e))}p.push(n)}return vt(p)}function Tt(e,t){var i=0,o=t.length>0,s=e.length>0,u=function(u,l,f,p,h){var d,g,m,y=[],v=0,x="0",b=u&&[],T=null!=h,C=a,k=u||s&&r.find.TAG("*",h&&l.parentNode||l),N=w+=null==C?1:Math.random()||.1;for(T&&(a=l!==c&&l,n=i);null!=(d=k[x]);x++){if(s&&d){g=0;while(m=e[g++])if(m(d,l,f)){p.push(d);break}T&&(w=N,n=++i)}o&&((d=!m&&d)&&v--,u&&b.push(d))}if(v+=x,o&&x!==v){g=0;while(m=t[g++])m(b,y,l,f);if(u){if(v>0)while(x--)b[x]||y[x]||(y[x]=L.call(p));y=xt(y)}H.apply(p,y),T&&!u&&y.length>0&&v+t.length>1&&ut.uniqueSort(p)}return T&&(w=N,a=C),b};return o?st(u):u}s=ut.compile=function(e,t){var n,r=[],i=[],o=N[e+" "];if(!o){t||(t=gt(e)),n=t.length;while(n--)o=wt(t[n]),o[y]?r.push(o):i.push(o);o=N(e,Tt(i,r))}return o};function Ct(e,t,n){var r=0,i=t.length;for(;i>r;r++)ut(e,t[r],n);return n}function kt(e,t,n,i){var o,a,u,l,c,f=gt(e);if(!i&&1===f.length){if(a=f[0]=f[0].slice(0),a.length>2&&"ID"===(u=a[0]).type&&9===t.nodeType&&p&&r.relative[a[1].type]){if(t=(r.find.ID(u.matches[0].replace(tt,nt),t)||[])[0],!t)return n;e=e.slice(a.shift().value.length)}o=G.needsContext.test(e)?0:a.length;while(o--){if(u=a[o],r.relative[l=u.type])break;if((c=r.find[l])&&(i=c(u.matches[0].replace(tt,nt),X.test(a[0].type)&&t.parentNode||t))){if(a.splice(o,1),e=i.length&&mt(a),!e)return H.apply(n,i),n;break}}}return s(e,f)(i,t,!p,n,X.test(e)),n}r.pseudos.nth=r.pseudos.eq;function Nt(){}Nt.prototype=r.filters=r.pseudos,r.setFilters=new Nt,b.sortStable=y.split("").sort(S).join("")===y,l(),[0,0].sort(S),b.detectDuplicates=E,at(function(e){if(e.innerHTML="
                      ","#"!==e.firstChild.getAttribute("href")){var t="type|href|height|width".split("|"),n=t.length;while(n--)r.attrHandle[t[n]]=ft}}),at(function(e){if(null!=e.getAttribute("disabled")){var t=P.split("|"),n=t.length;while(n--)r.attrHandle[t[n]]=ct}}),x.find=ut,x.expr=ut.selectors,x.expr[":"]=x.expr.pseudos,x.unique=ut.uniqueSort,x.text=ut.getText,x.isXMLDoc=ut.isXML,x.contains=ut.contains}(e);var D={};function A(e){var t=D[e]={};return x.each(e.match(w)||[],function(e,n){t[n]=!0}),t}x.Callbacks=function(e){e="string"==typeof e?D[e]||A(e):x.extend({},e);var t,n,r,i,o,s,a=[],u=!e.once&&[],l=function(f){for(t=e.memory&&f,n=!0,s=i||0,i=0,o=a.length,r=!0;a&&o>s;s++)if(a[s].apply(f[0],f[1])===!1&&e.stopOnFalse){t=!1;break}r=!1,a&&(u?u.length&&l(u.shift()):t?a=[]:c.disable())},c={add:function(){if(a){var n=a.length;(function s(t){x.each(t,function(t,n){var r=x.type(n);"function"===r?e.unique&&c.has(n)||a.push(n):n&&n.length&&"string"!==r&&s(n)})})(arguments),r?o=a.length:t&&(i=n,l(t))}return this},remove:function(){return a&&x.each(arguments,function(e,t){var n;while((n=x.inArray(t,a,n))>-1)a.splice(n,1),r&&(o>=n&&o--,s>=n&&s--)}),this},has:function(e){return e?x.inArray(e,a)>-1:!(!a||!a.length)},empty:function(){return a=[],o=0,this},disable:function(){return a=u=t=undefined,this},disabled:function(){return!a},lock:function(){return u=undefined,t||c.disable(),this},locked:function(){return!u},fireWith:function(e,t){return t=t||[],t=[e,t.slice?t.slice():t],!a||n&&!u||(r?u.push(t):l(t)),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!n}};return c},x.extend({Deferred:function(e){var t=[["resolve","done",x.Callbacks("once memory"),"resolved"],["reject","fail",x.Callbacks("once memory"),"rejected"],["notify","progress",x.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return x.Deferred(function(n){x.each(t,function(t,o){var s=o[0],a=x.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&x.isFunction(e.promise)?e.promise().done(n.resolve).fail(n.reject).progress(n.notify):n[s+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?x.extend(e,r):r}},i={};return r.pipe=r.then,x.each(t,function(e,o){var s=o[2],a=o[3];r[o[1]]=s.add,a&&s.add(function(){n=a},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=s.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t=0,n=d.call(arguments),r=n.length,i=1!==r||e&&x.isFunction(e.promise)?r:0,o=1===i?e:x.Deferred(),s=function(e,t,n){return function(r){t[e]=this,n[e]=arguments.length>1?d.call(arguments):r,n===a?o.notifyWith(t,n):--i||o.resolveWith(t,n)}},a,u,l;if(r>1)for(a=Array(r),u=Array(r),l=Array(r);r>t;t++)n[t]&&x.isFunction(n[t].promise)?n[t].promise().done(s(t,l,n)).fail(o.reject).progress(s(t,u,a)):--i;return i||o.resolveWith(l,n),o.promise()}}),x.support=function(t){var n=o.createElement("input"),r=o.createDocumentFragment(),i=o.createElement("div"),s=o.createElement("select"),a=s.appendChild(o.createElement("option"));return n.type?(n.type="checkbox",t.checkOn=""!==n.value,t.optSelected=a.selected,t.reliableMarginRight=!0,t.boxSizingReliable=!0,t.pixelPosition=!1,n.checked=!0,t.noCloneChecked=n.cloneNode(!0).checked,s.disabled=!0,t.optDisabled=!a.disabled,n=o.createElement("input"),n.value="t",n.type="radio",t.radioValue="t"===n.value,n.setAttribute("checked","t"),n.setAttribute("name","t"),r.appendChild(n),t.checkClone=r.cloneNode(!0).cloneNode(!0).lastChild.checked,t.focusinBubbles="onfocusin"in e,i.style.backgroundClip="content-box",i.cloneNode(!0).style.backgroundClip="",t.clearCloneStyle="content-box"===i.style.backgroundClip,x(function(){var n,r,s="padding:0;margin:0;border:0;display:block;-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box",a=o.getElementsByTagName("body")[0];a&&(n=o.createElement("div"),n.style.cssText="border:0;width:0;height:0;position:absolute;top:0;left:-9999px;margin-top:1px",a.appendChild(n).appendChild(i),i.innerHTML="",i.style.cssText="-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;padding:1px;border:1px;display:block;width:4px;margin-top:1%;position:absolute;top:1%",x.swap(a,null!=a.style.zoom?{zoom:1}:{},function(){t.boxSizing=4===i.offsetWidth}),e.getComputedStyle&&(t.pixelPosition="1%"!==(e.getComputedStyle(i,null)||{}).top,t.boxSizingReliable="4px"===(e.getComputedStyle(i,null)||{width:"4px"}).width,r=i.appendChild(o.createElement("div")),r.style.cssText=i.style.cssText=s,r.style.marginRight=r.style.width="0",i.style.width="1px",t.reliableMarginRight=!parseFloat((e.getComputedStyle(r,null)||{}).marginRight)),a.removeChild(n))}),t):t}({});var L,q,H=/(?:\{[\s\S]*\}|\[[\s\S]*\])$/,O=/([A-Z])/g;function F(){Object.defineProperty(this.cache={},0,{get:function(){return{}}}),this.expando=x.expando+Math.random()}F.uid=1,F.accepts=function(e){return e.nodeType?1===e.nodeType||9===e.nodeType:!0},F.prototype={key:function(e){if(!F.accepts(e))return 0;var t={},n=e[this.expando];if(!n){n=F.uid++;try{t[this.expando]={value:n},Object.defineProperties(e,t)}catch(r){t[this.expando]=n,x.extend(e,t)}}return this.cache[n]||(this.cache[n]={}),n},set:function(e,t,n){var r,i=this.key(e),o=this.cache[i];if("string"==typeof t)o[t]=n;else if(x.isEmptyObject(o))this.cache[i]=t;else for(r in t)o[r]=t[r]},get:function(e,t){var n=this.cache[this.key(e)];return t===undefined?n:n[t]},access:function(e,t,n){return t===undefined||t&&"string"==typeof t&&n===undefined?this.get(e,t):(this.set(e,t,n),n!==undefined?n:t)},remove:function(e,t){var n,r,i=this.key(e),o=this.cache[i];if(t===undefined)this.cache[i]={};else{x.isArray(t)?r=t.concat(t.map(x.camelCase)):t in o?r=[t]:(r=x.camelCase(t),r=r in o?[r]:r.match(w)||[]),n=r.length;while(n--)delete o[r[n]]}},hasData:function(e){return!x.isEmptyObject(this.cache[e[this.expando]]||{})},discard:function(e){delete this.cache[this.key(e)]}},L=new F,q=new F,x.extend({acceptData:F.accepts,hasData:function(e){return L.hasData(e)||q.hasData(e)},data:function(e,t,n){return L.access(e,t,n)},removeData:function(e,t){L.remove(e,t)},_data:function(e,t,n){return q.access(e,t,n)},_removeData:function(e,t){q.remove(e,t)}}),x.fn.extend({data:function(e,t){var n,r,i=this[0],o=0,s=null;if(e===undefined){if(this.length&&(s=L.get(i),1===i.nodeType&&!q.get(i,"hasDataAttrs"))){for(n=i.attributes;n.length>o;o++)r=n[o].name,0===r.indexOf("data-")&&(r=x.camelCase(r.substring(5)),P(i,r,s[r]));q.set(i,"hasDataAttrs",!0)}return s}return"object"==typeof e?this.each(function(){L.set(this,e)}):x.access(this,function(t){var n,r=x.camelCase(e);if(i&&t===undefined){if(n=L.get(i,e),n!==undefined)return n;if(n=L.get(i,r),n!==undefined)return n;if(n=P(i,r,undefined),n!==undefined)return n}else this.each(function(){var n=L.get(this,r);L.set(this,r,t),-1!==e.indexOf("-")&&n!==undefined&&L.set(this,e,t)})},null,t,arguments.length>1,null,!0)},removeData:function(e){return this.each(function(){L.remove(this,e)})}});function P(e,t,n){var r;if(n===undefined&&1===e.nodeType)if(r="data-"+t.replace(O,"-$1").toLowerCase(),n=e.getAttribute(r),"string"==typeof n){try{n="true"===n?!0:"false"===n?!1:"null"===n?null:+n+""===n?+n:H.test(n)?JSON.parse(n):n}catch(i){}L.set(e,t,n)}else n=undefined;return n}x.extend({queue:function(e,t,n){var r;return e?(t=(t||"fx")+"queue",r=q.get(e,t),n&&(!r||x.isArray(n)?r=q.access(e,t,x.makeArray(n)):r.push(n)),r||[]):undefined},dequeue:function(e,t){t=t||"fx";var n=x.queue(e,t),r=n.length,i=n.shift(),o=x._queueHooks(e,t),s=function(){x.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),o.cur=i,i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,s,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return q.get(e,n)||q.access(e,n,{empty:x.Callbacks("once memory").add(function(){q.remove(e,[t+"queue",n])})})}}),x.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),n>arguments.length?x.queue(this[0],e):t===undefined?this:this.each(function(){var n=x.queue(this,e,t); +x._queueHooks(this,e),"fx"===e&&"inprogress"!==n[0]&&x.dequeue(this,e)})},dequeue:function(e){return this.each(function(){x.dequeue(this,e)})},delay:function(e,t){return e=x.fx?x.fx.speeds[e]||e:e,t=t||"fx",this.queue(t,function(t,n){var r=setTimeout(t,e);n.stop=function(){clearTimeout(r)}})},clearQueue:function(e){return this.queue(e||"fx",[])},promise:function(e,t){var n,r=1,i=x.Deferred(),o=this,s=this.length,a=function(){--r||i.resolveWith(o,[o])};"string"!=typeof e&&(t=e,e=undefined),e=e||"fx";while(s--)n=q.get(o[s],e+"queueHooks"),n&&n.empty&&(r++,n.empty.add(a));return a(),i.promise(t)}});var R,M,W=/[\t\r\n]/g,$=/\r/g,B=/^(?:input|select|textarea|button)$/i;x.fn.extend({attr:function(e,t){return x.access(this,x.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){x.removeAttr(this,e)})},prop:function(e,t){return x.access(this,x.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[x.propFix[e]||e]})},addClass:function(e){var t,n,r,i,o,s=0,a=this.length,u="string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).addClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):" ")){o=0;while(i=t[o++])0>r.indexOf(" "+i+" ")&&(r+=i+" ");n.className=x.trim(r)}return this},removeClass:function(e){var t,n,r,i,o,s=0,a=this.length,u=0===arguments.length||"string"==typeof e&&e;if(x.isFunction(e))return this.each(function(t){x(this).removeClass(e.call(this,t,this.className))});if(u)for(t=(e||"").match(w)||[];a>s;s++)if(n=this[s],r=1===n.nodeType&&(n.className?(" "+n.className+" ").replace(W," "):"")){o=0;while(i=t[o++])while(r.indexOf(" "+i+" ")>=0)r=r.replace(" "+i+" "," ");n.className=e?x.trim(r):""}return this},toggleClass:function(e,t){var n=typeof e,i="boolean"==typeof t;return x.isFunction(e)?this.each(function(n){x(this).toggleClass(e.call(this,n,this.className,t),t)}):this.each(function(){if("string"===n){var o,s=0,a=x(this),u=t,l=e.match(w)||[];while(o=l[s++])u=i?u:!a.hasClass(o),a[u?"addClass":"removeClass"](o)}else(n===r||"boolean"===n)&&(this.className&&q.set(this,"__className__",this.className),this.className=this.className||e===!1?"":q.get(this,"__className__")||"")})},hasClass:function(e){var t=" "+e+" ",n=0,r=this.length;for(;r>n;n++)if(1===this[n].nodeType&&(" "+this[n].className+" ").replace(W," ").indexOf(t)>=0)return!0;return!1},val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=x.isFunction(e),this.each(function(n){var i,o=x(this);1===this.nodeType&&(i=r?e.call(this,n,o.val()):e,null==i?i="":"number"==typeof i?i+="":x.isArray(i)&&(i=x.map(i,function(e){return null==e?"":e+""})),t=x.valHooks[this.type]||x.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&t.set(this,i,"value")!==undefined||(this.value=i))});if(i)return t=x.valHooks[i.type]||x.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&(n=t.get(i,"value"))!==undefined?n:(n=i.value,"string"==typeof n?n.replace($,""):null==n?"":n)}}}),x.extend({valHooks:{option:{get:function(e){var t=e.attributes.value;return!t||t.specified?e.value:e.text}},select:{get:function(e){var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||0>i,s=o?null:[],a=o?i+1:r.length,u=0>i?a:o?i:0;for(;a>u;u++)if(n=r[u],!(!n.selected&&u!==i||(x.support.optDisabled?n.disabled:null!==n.getAttribute("disabled"))||n.parentNode.disabled&&x.nodeName(n.parentNode,"optgroup"))){if(t=x(n).val(),o)return t;s.push(t)}return s},set:function(e,t){var n,r,i=e.options,o=x.makeArray(t),s=i.length;while(s--)r=i[s],(r.selected=x.inArray(x(r).val(),o)>=0)&&(n=!0);return n||(e.selectedIndex=-1),o}}},attr:function(e,t,n){var i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return typeof e.getAttribute===r?x.prop(e,t,n):(1===s&&x.isXMLDoc(e)||(t=t.toLowerCase(),i=x.attrHooks[t]||(x.expr.match.boolean.test(t)?M:R)),n===undefined?i&&"get"in i&&null!==(o=i.get(e,t))?o:(o=x.find.attr(e,t),null==o?undefined:o):null!==n?i&&"set"in i&&(o=i.set(e,n,t))!==undefined?o:(e.setAttribute(t,n+""),n):(x.removeAttr(e,t),undefined))},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(w);if(o&&1===e.nodeType)while(n=o[i++])r=x.propFix[n]||n,x.expr.match.boolean.test(n)&&(e[r]=!1),e.removeAttribute(n)},attrHooks:{type:{set:function(e,t){if(!x.support.radioValue&&"radio"===t&&x.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},propFix:{"for":"htmlFor","class":"className"},prop:function(e,t,n){var r,i,o,s=e.nodeType;if(e&&3!==s&&8!==s&&2!==s)return o=1!==s||!x.isXMLDoc(e),o&&(t=x.propFix[t]||t,i=x.propHooks[t]),n!==undefined?i&&"set"in i&&(r=i.set(e,n,t))!==undefined?r:e[t]=n:i&&"get"in i&&null!==(r=i.get(e,t))?r:e[t]},propHooks:{tabIndex:{get:function(e){return e.hasAttribute("tabindex")||B.test(e.nodeName)||e.href?e.tabIndex:-1}}}}),M={set:function(e,t,n){return t===!1?x.removeAttr(e,n):e.setAttribute(n,n),n}},x.each(x.expr.match.boolean.source.match(/\w+/g),function(e,t){var n=x.expr.attrHandle[t]||x.find.attr;x.expr.attrHandle[t]=function(e,t,r){var i=x.expr.attrHandle[t],o=r?undefined:(x.expr.attrHandle[t]=undefined)!=n(e,t,r)?t.toLowerCase():null;return x.expr.attrHandle[t]=i,o}}),x.support.optSelected||(x.propHooks.selected={get:function(e){var t=e.parentNode;return t&&t.parentNode&&t.parentNode.selectedIndex,null}}),x.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){x.propFix[this.toLowerCase()]=this}),x.each(["radio","checkbox"],function(){x.valHooks[this]={set:function(e,t){return x.isArray(t)?e.checked=x.inArray(x(e).val(),t)>=0:undefined}},x.support.checkOn||(x.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var I=/^key/,z=/^(?:mouse|contextmenu)|click/,_=/^(?:focusinfocus|focusoutblur)$/,X=/^([^.]*)(?:\.(.+)|)$/;function U(){return!0}function Y(){return!1}function V(){try{return o.activeElement}catch(e){}}x.event={global:{},add:function(e,t,n,i,o){var s,a,u,l,c,f,p,h,d,g,m,y=q.get(e);if(y){n.handler&&(s=n,n=s.handler,o=s.selector),n.guid||(n.guid=x.guid++),(l=y.events)||(l=y.events={}),(a=y.handle)||(a=y.handle=function(e){return typeof x===r||e&&x.event.triggered===e.type?undefined:x.event.dispatch.apply(a.elem,arguments)},a.elem=e),t=(t||"").match(w)||[""],c=t.length;while(c--)u=X.exec(t[c])||[],d=m=u[1],g=(u[2]||"").split(".").sort(),d&&(p=x.event.special[d]||{},d=(o?p.delegateType:p.bindType)||d,p=x.event.special[d]||{},f=x.extend({type:d,origType:m,data:i,handler:n,guid:n.guid,selector:o,needsContext:o&&x.expr.match.needsContext.test(o),namespace:g.join(".")},s),(h=l[d])||(h=l[d]=[],h.delegateCount=0,p.setup&&p.setup.call(e,i,g,a)!==!1||e.addEventListener&&e.addEventListener(d,a,!1)),p.add&&(p.add.call(e,f),f.handler.guid||(f.handler.guid=n.guid)),o?h.splice(h.delegateCount++,0,f):h.push(f),x.event.global[d]=!0);e=null}},remove:function(e,t,n,r,i){var o,s,a,u,l,c,f,p,h,d,g,m=q.hasData(e)&&q.get(e);if(m&&(u=m.events)){t=(t||"").match(w)||[""],l=t.length;while(l--)if(a=X.exec(t[l])||[],h=g=a[1],d=(a[2]||"").split(".").sort(),h){f=x.event.special[h]||{},h=(r?f.delegateType:f.bindType)||h,p=u[h]||[],a=a[2]&&RegExp("(^|\\.)"+d.join("\\.(?:.*\\.|)")+"(\\.|$)"),s=o=p.length;while(o--)c=p[o],!i&&g!==c.origType||n&&n.guid!==c.guid||a&&!a.test(c.namespace)||r&&r!==c.selector&&("**"!==r||!c.selector)||(p.splice(o,1),c.selector&&p.delegateCount--,f.remove&&f.remove.call(e,c));s&&!p.length&&(f.teardown&&f.teardown.call(e,d,m.handle)!==!1||x.removeEvent(e,h,m.handle),delete u[h])}else for(h in u)x.event.remove(e,h+t[l],n,r,!0);x.isEmptyObject(u)&&(delete m.handle,q.remove(e,"events"))}},trigger:function(t,n,r,i){var s,a,u,l,c,f,p,h=[r||o],d=y.call(t,"type")?t.type:t,g=y.call(t,"namespace")?t.namespace.split("."):[];if(a=u=r=r||o,3!==r.nodeType&&8!==r.nodeType&&!_.test(d+x.event.triggered)&&(d.indexOf(".")>=0&&(g=d.split("."),d=g.shift(),g.sort()),c=0>d.indexOf(":")&&"on"+d,t=t[x.expando]?t:new x.Event(d,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=g.join("."),t.namespace_re=t.namespace?RegExp("(^|\\.)"+g.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=undefined,t.target||(t.target=r),n=null==n?[t]:x.makeArray(n,[t]),p=x.event.special[d]||{},i||!p.trigger||p.trigger.apply(r,n)!==!1)){if(!i&&!p.noBubble&&!x.isWindow(r)){for(l=p.delegateType||d,_.test(l+d)||(a=a.parentNode);a;a=a.parentNode)h.push(a),u=a;u===(r.ownerDocument||o)&&h.push(u.defaultView||u.parentWindow||e)}s=0;while((a=h[s++])&&!t.isPropagationStopped())t.type=s>1?l:p.bindType||d,f=(q.get(a,"events")||{})[t.type]&&q.get(a,"handle"),f&&f.apply(a,n),f=c&&a[c],f&&x.acceptData(a)&&f.apply&&f.apply(a,n)===!1&&t.preventDefault();return t.type=d,i||t.isDefaultPrevented()||p._default&&p._default.apply(h.pop(),n)!==!1||!x.acceptData(r)||c&&x.isFunction(r[d])&&!x.isWindow(r)&&(u=r[c],u&&(r[c]=null),x.event.triggered=d,r[d](),x.event.triggered=undefined,u&&(r[c]=u)),t.result}},dispatch:function(e){e=x.event.fix(e);var t,n,r,i,o,s=[],a=d.call(arguments),u=(q.get(this,"events")||{})[e.type]||[],l=x.event.special[e.type]||{};if(a[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){s=x.event.handlers.call(this,e,u),t=0;while((i=s[t++])&&!e.isPropagationStopped()){e.currentTarget=i.elem,n=0;while((o=i.handlers[n++])&&!e.isImmediatePropagationStopped())(!e.namespace_re||e.namespace_re.test(o.namespace))&&(e.handleObj=o,e.data=o.data,r=((x.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,a),r!==undefined&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()))}return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,s=[],a=t.delegateCount,u=e.target;if(a&&u.nodeType&&(!e.button||"click"!==e.type))for(;u!==this;u=u.parentNode||this)if(u.disabled!==!0||"click"!==e.type){for(r=[],n=0;a>n;n++)o=t[n],i=o.selector+" ",r[i]===undefined&&(r[i]=o.needsContext?x(i,this).index(u)>=0:x.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&s.push({elem:u,handlers:r})}return t.length>a&&s.push({elem:this,handlers:t.slice(a)}),s},props:"altKey bubbles cancelable ctrlKey currentTarget eventPhase metaKey relatedTarget shiftKey target timeStamp view which".split(" "),fixHooks:{},keyHooks:{props:"char charCode key keyCode".split(" "),filter:function(e,t){return null==e.which&&(e.which=null!=t.charCode?t.charCode:t.keyCode),e}},mouseHooks:{props:"button buttons clientX clientY offsetX offsetY pageX pageY screenX screenY toElement".split(" "),filter:function(e,t){var n,r,i,s=t.button;return null==e.pageX&&null!=t.clientX&&(n=e.target.ownerDocument||o,r=n.documentElement,i=n.body,e.pageX=t.clientX+(r&&r.scrollLeft||i&&i.scrollLeft||0)-(r&&r.clientLeft||i&&i.clientLeft||0),e.pageY=t.clientY+(r&&r.scrollTop||i&&i.scrollTop||0)-(r&&r.clientTop||i&&i.clientTop||0)),e.which||s===undefined||(e.which=1&s?1:2&s?3:4&s?2:0),e}},fix:function(e){if(e[x.expando])return e;var t,n,r,i=e.type,o=e,s=this.fixHooks[i];s||(this.fixHooks[i]=s=z.test(i)?this.mouseHooks:I.test(i)?this.keyHooks:{}),r=s.props?this.props.concat(s.props):this.props,e=new x.Event(o),t=r.length;while(t--)n=r[t],e[n]=o[n];return 3===e.target.nodeType&&(e.target=e.target.parentNode),s.filter?s.filter(e,o):e},special:{load:{noBubble:!0},focus:{trigger:function(){return this!==V()&&this.focus?(this.focus(),!1):undefined},delegateType:"focusin"},blur:{trigger:function(){return this===V()&&this.blur?(this.blur(),!1):undefined},delegateType:"focusout"},click:{trigger:function(){return"checkbox"===this.type&&this.click&&x.nodeName(this,"input")?(this.click(),!1):undefined},_default:function(e){return x.nodeName(e.target,"a")}},beforeunload:{postDispatch:function(e){e.result!==undefined&&(e.originalEvent.returnValue=e.result)}}},simulate:function(e,t,n,r){var i=x.extend(new x.Event,n,{type:e,isSimulated:!0,originalEvent:{}});r?x.event.trigger(i,null,t):x.event.dispatch.call(t,i),i.isDefaultPrevented()&&n.preventDefault()}},x.removeEvent=function(e,t,n){e.removeEventListener&&e.removeEventListener(t,n,!1)},x.Event=function(e,t){return this instanceof x.Event?(e&&e.type?(this.originalEvent=e,this.type=e.type,this.isDefaultPrevented=e.defaultPrevented||e.getPreventDefault&&e.getPreventDefault()?U:Y):this.type=e,t&&x.extend(this,t),this.timeStamp=e&&e.timeStamp||x.now(),this[x.expando]=!0,undefined):new x.Event(e,t)},x.Event.prototype={isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y,preventDefault:function(){var e=this.originalEvent;this.isDefaultPrevented=U,e&&e.preventDefault&&e.preventDefault()},stopPropagation:function(){var e=this.originalEvent;this.isPropagationStopped=U,e&&e.stopPropagation&&e.stopPropagation()},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=U,this.stopPropagation()}},x.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(e,t){x.event.special[e]={delegateType:t,bindType:t,handle:function(e){var n,r=this,i=e.relatedTarget,o=e.handleObj;return(!i||i!==r&&!x.contains(r,i))&&(e.type=o.origType,n=o.handler.apply(this,arguments),e.type=t),n}}}),x.support.focusinBubbles||x.each({focus:"focusin",blur:"focusout"},function(e,t){var n=0,r=function(e){x.event.simulate(t,e.target,x.event.fix(e),!0)};x.event.special[t]={setup:function(){0===n++&&o.addEventListener(e,r,!0)},teardown:function(){0===--n&&o.removeEventListener(e,r,!0)}}}),x.fn.extend({on:function(e,t,n,r,i){var o,s;if("object"==typeof e){"string"!=typeof t&&(n=n||t,t=undefined);for(s in e)this.on(s,t,n,e[s],i);return this}if(null==n&&null==r?(r=t,n=t=undefined):null==r&&("string"==typeof t?(r=n,n=undefined):(r=n,n=t,t=undefined)),r===!1)r=Y;else if(!r)return this;return 1===i&&(o=r,r=function(e){return x().off(e),o.apply(this,arguments)},r.guid=o.guid||(o.guid=x.guid++)),this.each(function(){x.event.add(this,e,r,n,t)})},one:function(e,t,n,r){return this.on(e,t,n,r,1)},off:function(e,t,n){var r,i;if(e&&e.preventDefault&&e.handleObj)return r=e.handleObj,x(e.delegateTarget).off(r.namespace?r.origType+"."+r.namespace:r.origType,r.selector,r.handler),this;if("object"==typeof e){for(i in e)this.off(i,t,e[i]);return this}return(t===!1||"function"==typeof t)&&(n=t,t=undefined),n===!1&&(n=Y),this.each(function(){x.event.remove(this,e,n,t)})},trigger:function(e,t){return this.each(function(){x.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];return n?x.event.trigger(e,t,n,!0):undefined}});var G=/^.[^:#\[\.,]*$/,J=x.expr.match.needsContext,Q={children:!0,contents:!0,next:!0,prev:!0};x.fn.extend({find:function(e){var t,n,r,i=this.length;if("string"!=typeof e)return t=this,this.pushStack(x(e).filter(function(){for(r=0;i>r;r++)if(x.contains(t[r],this))return!0}));for(n=[],r=0;i>r;r++)x.find(e,this[r],n);return n=this.pushStack(i>1?x.unique(n):n),n.selector=(this.selector?this.selector+" ":"")+e,n},has:function(e){var t=x(e,this),n=t.length;return this.filter(function(){var e=0;for(;n>e;e++)if(x.contains(this,t[e]))return!0})},not:function(e){return this.pushStack(Z(this,e||[],!0))},filter:function(e){return this.pushStack(Z(this,e||[],!1))},is:function(e){return!!e&&("string"==typeof e?J.test(e)?x(e,this.context).index(this[0])>=0:x.filter(e,this).length>0:this.filter(e).length>0)},closest:function(e,t){var n,r=0,i=this.length,o=[],s=J.test(e)||"string"!=typeof e?x(e,t||this.context):0;for(;i>r;r++)for(n=this[r];n&&n!==t;n=n.parentNode)if(11>n.nodeType&&(s?s.index(n)>-1:1===n.nodeType&&x.find.matchesSelector(n,e))){n=o.push(n);break}return this.pushStack(o.length>1?x.unique(o):o)},index:function(e){return e?"string"==typeof e?g.call(x(e),this[0]):g.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){var n="string"==typeof e?x(e,t):x.makeArray(e&&e.nodeType?[e]:e),r=x.merge(this.get(),n);return this.pushStack(x.unique(r))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}});function K(e,t){while((e=e[t])&&1!==e.nodeType);return e}x.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return x.dir(e,"parentNode")},parentsUntil:function(e,t,n){return x.dir(e,"parentNode",n)},next:function(e){return K(e,"nextSibling")},prev:function(e){return K(e,"previousSibling")},nextAll:function(e){return x.dir(e,"nextSibling")},prevAll:function(e){return x.dir(e,"previousSibling")},nextUntil:function(e,t,n){return x.dir(e,"nextSibling",n)},prevUntil:function(e,t,n){return x.dir(e,"previousSibling",n)},siblings:function(e){return x.sibling((e.parentNode||{}).firstChild,e)},children:function(e){return x.sibling(e.firstChild)},contents:function(e){return x.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:x.merge([],e.childNodes)}},function(e,t){x.fn[e]=function(n,r){var i=x.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=x.filter(r,i)),this.length>1&&(Q[e]||x.unique(i),"p"===e[0]&&i.reverse()),this.pushStack(i)}}),x.extend({filter:function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?x.find.matchesSelector(r,e)?[r]:[]:x.find.matches(e,x.grep(t,function(e){return 1===e.nodeType}))},dir:function(e,t,n){var r=[],i=n!==undefined;while((e=e[t])&&9!==e.nodeType)if(1===e.nodeType){if(i&&x(e).is(n))break;r.push(e)}return r},sibling:function(e,t){var n=[];for(;e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n}});function Z(e,t,n){if(x.isFunction(t))return x.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return x.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(G.test(t))return x.filter(t,e,n);t=x.filter(t,e)}return x.grep(e,function(e){return g.call(t,e)>=0!==n})}var et=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,tt=/<([\w:]+)/,nt=/<|&#?\w+;/,rt=/<(?:script|style|link)/i,it=/^(?:checkbox|radio)$/i,ot=/checked\s*(?:[^=]|=\s*.checked.)/i,st=/^$|\/(?:java|ecma)script/i,at=/^true\/(.*)/,ut=/^\s*\s*$/g,lt={option:[1,""],thead:[1,"","
                      "],tr:[2,"","
                      "],td:[3,"","
                      "],_default:[0,"",""]};lt.optgroup=lt.option,lt.tbody=lt.tfoot=lt.colgroup=lt.caption=lt.col=lt.thead,lt.th=lt.td,x.fn.extend({text:function(e){return x.access(this,function(e){return e===undefined?x.text(this):this.empty().append((this[0]&&this[0].ownerDocument||o).createTextNode(e))},null,e,arguments.length)},append:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=ct(this,e);t.appendChild(e)}})},prepend:function(){return this.domManip(arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=ct(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return this.domManip(arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},remove:function(e,t){var n,r=e?x.filter(e,this):this,i=0;for(;null!=(n=r[i]);i++)t||1!==n.nodeType||x.cleanData(gt(n)),n.parentNode&&(t&&x.contains(n.ownerDocument,n)&&ht(gt(n,"script")),n.parentNode.removeChild(n));return this},empty:function(){var e,t=0;for(;null!=(e=this[t]);t++)1===e.nodeType&&(x.cleanData(gt(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null==e?!1:e,t=null==t?e:t,this.map(function(){return x.clone(this,e,t)})},html:function(e){return x.access(this,function(e){var t=this[0]||{},n=0,r=this.length;if(e===undefined&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!rt.test(e)&&!lt[(tt.exec(e)||["",""])[1].toLowerCase()]){e=e.replace(et,"<$1>");try{for(;r>n;n++)t=this[n]||{},1===t.nodeType&&(x.cleanData(gt(t,!1)),t.innerHTML=e);t=0}catch(i){}}t&&this.empty().append(e)},null,e,arguments.length)},replaceWith:function(){var e=x.map(this,function(e){return[e.nextSibling,e.parentNode]}),t=0;return this.domManip(arguments,function(n){var r=e[t++],i=e[t++];i&&(x(this).remove(),i.insertBefore(n,r))},!0),t?this:this.remove()},detach:function(e){return this.remove(e,!0)},domManip:function(e,t,n){e=p.apply([],e);var r,i,o,s,a,u,l=0,c=this.length,f=this,h=c-1,d=e[0],g=x.isFunction(d);if(g||!(1>=c||"string"!=typeof d||x.support.checkClone)&&ot.test(d))return this.each(function(r){var i=f.eq(r);g&&(e[0]=d.call(this,r,i.html())),i.domManip(e,t,n)});if(c&&(r=x.buildFragment(e,this[0].ownerDocument,!1,!n&&this),i=r.firstChild,1===r.childNodes.length&&(r=i),i)){for(o=x.map(gt(r,"script"),ft),s=o.length;c>l;l++)a=r,l!==h&&(a=x.clone(a,!0,!0),s&&x.merge(o,gt(a,"script"))),t.call(this[l],a,l);if(s)for(u=o[o.length-1].ownerDocument,x.map(o,pt),l=0;s>l;l++)a=o[l],st.test(a.type||"")&&!q.access(a,"globalEval")&&x.contains(u,a)&&(a.src?x._evalUrl(a.src):x.globalEval(a.textContent.replace(ut,"")))}return this}}),x.each({appendTo:"append",prependTo:"prepend",insertBefore:"before",insertAfter:"after",replaceAll:"replaceWith"},function(e,t){x.fn[e]=function(e){var n,r=[],i=x(e),o=i.length-1,s=0;for(;o>=s;s++)n=s===o?this:this.clone(!0),x(i[s])[t](n),h.apply(r,n.get());return this.pushStack(r)}}),x.extend({clone:function(e,t,n){var r,i,o,s,a=e.cloneNode(!0),u=x.contains(e.ownerDocument,e);if(!(x.support.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||x.isXMLDoc(e)))for(s=gt(a),o=gt(e),r=0,i=o.length;i>r;r++)mt(o[r],s[r]);if(t)if(n)for(o=o||gt(e),s=s||gt(a),r=0,i=o.length;i>r;r++)dt(o[r],s[r]);else dt(e,a);return s=gt(a,"script"),s.length>0&&ht(s,!u&>(e,"script")),a},buildFragment:function(e,t,n,r){var i,o,s,a,u,l,c=0,f=e.length,p=t.createDocumentFragment(),h=[];for(;f>c;c++)if(i=e[c],i||0===i)if("object"===x.type(i))x.merge(h,i.nodeType?[i]:i);else if(nt.test(i)){o=o||p.appendChild(t.createElement("div")),s=(tt.exec(i)||["",""])[1].toLowerCase(),a=lt[s]||lt._default,o.innerHTML=a[1]+i.replace(et,"<$1>")+a[2],l=a[0];while(l--)o=o.firstChild;x.merge(h,o.childNodes),o=p.firstChild,o.textContent=""}else h.push(t.createTextNode(i));p.textContent="",c=0;while(i=h[c++])if((!r||-1===x.inArray(i,r))&&(u=x.contains(i.ownerDocument,i),o=gt(p.appendChild(i),"script"),u&&ht(o),n)){l=0;while(i=o[l++])st.test(i.type||"")&&n.push(i)}return p},cleanData:function(e){var t,n,r,i=e.length,o=0,s=x.event.special;for(;i>o;o++){if(n=e[o],x.acceptData(n)&&(t=q.access(n)))for(r in t.events)s[r]?x.event.remove(n,r):x.removeEvent(n,r,t.handle);L.discard(n),q.discard(n)}},_evalUrl:function(e){return x.ajax({url:e,type:"GET",dataType:"text",async:!1,global:!1,success:x.globalEval})}});function ct(e,t){return x.nodeName(e,"table")&&x.nodeName(1===t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function ft(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function pt(e){var t=at.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function ht(e,t){var n=e.length,r=0;for(;n>r;r++)q.set(e[r],"globalEval",!t||q.get(t[r],"globalEval"))}function dt(e,t){var n,r,i,o,s,a,u,l;if(1===t.nodeType){if(q.hasData(e)&&(o=q.access(e),s=x.extend({},o),l=o.events,q.set(t,s),l)){delete s.handle,s.events={};for(i in l)for(n=0,r=l[i].length;r>n;n++)x.event.add(t,i,l[i][n])}L.hasData(e)&&(a=L.access(e),u=x.extend({},a),L.set(t,u))}}function gt(e,t){var n=e.getElementsByTagName?e.getElementsByTagName(t||"*"):e.querySelectorAll?e.querySelectorAll(t||"*"):[];return t===undefined||t&&x.nodeName(e,t)?x.merge([e],n):n}function mt(e,t){var n=t.nodeName.toLowerCase();"input"===n&&it.test(e.type)?t.checked=e.checked:("input"===n||"textarea"===n)&&(t.defaultValue=e.defaultValue)}x.fn.extend({wrapAll:function(e){var t;return x.isFunction(e)?this.each(function(t){x(this).wrapAll(e.call(this,t))}):(this[0]&&(t=x(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){var e=this;while(e.firstElementChild)e=e.firstElementChild;return e}).append(this)),this)},wrapInner:function(e){return x.isFunction(e)?this.each(function(t){x(this).wrapInner(e.call(this,t))}):this.each(function(){var t=x(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=x.isFunction(e);return this.each(function(n){x(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){x.nodeName(this,"body")||x(this).replaceWith(this.childNodes)}).end()}});var yt,vt,xt=/^(none|table(?!-c[ea]).+)/,bt=/^margin/,wt=RegExp("^("+b+")(.*)$","i"),Tt=RegExp("^("+b+")(?!px)[a-z%]+$","i"),Ct=RegExp("^([+-])=("+b+")","i"),kt={BODY:"block"},Nt={position:"absolute",visibility:"hidden",display:"block"},Et={letterSpacing:0,fontWeight:400},St=["Top","Right","Bottom","Left"],jt=["Webkit","O","Moz","ms"];function Dt(e,t){if(t in e)return t;var n=t.charAt(0).toUpperCase()+t.slice(1),r=t,i=jt.length;while(i--)if(t=jt[i]+n,t in e)return t;return r}function At(e,t){return e=t||e,"none"===x.css(e,"display")||!x.contains(e.ownerDocument,e)}function Lt(t){return e.getComputedStyle(t,null)}function qt(e,t){var n,r,i,o=[],s=0,a=e.length;for(;a>s;s++)r=e[s],r.style&&(o[s]=q.get(r,"olddisplay"),n=r.style.display,t?(o[s]||"none"!==n||(r.style.display=""),""===r.style.display&&At(r)&&(o[s]=q.access(r,"olddisplay",Pt(r.nodeName)))):o[s]||(i=At(r),(n&&"none"!==n||!i)&&q.set(r,"olddisplay",i?n:x.css(r,"display"))));for(s=0;a>s;s++)r=e[s],r.style&&(t&&"none"!==r.style.display&&""!==r.style.display||(r.style.display=t?o[s]||"":"none"));return e}x.fn.extend({css:function(e,t){return x.access(this,function(e,t,n){var r,i,o={},s=0;if(x.isArray(t)){for(r=Lt(e),i=t.length;i>s;s++)o[t[s]]=x.css(e,t[s],!1,r);return o}return n!==undefined?x.style(e,t,n):x.css(e,t)},e,t,arguments.length>1)},show:function(){return qt(this,!0)},hide:function(){return qt(this)},toggle:function(e){var t="boolean"==typeof e;return this.each(function(){(t?e:At(this))?x(this).show():x(this).hide()})}}),x.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=yt(e,"opacity");return""===n?"1":n}}}},cssNumber:{columnCount:!0,fillOpacity:!0,fontWeight:!0,lineHeight:!0,opacity:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":"cssFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,s,a=x.camelCase(t),u=e.style;return t=x.cssProps[a]||(x.cssProps[a]=Dt(u,a)),s=x.cssHooks[t]||x.cssHooks[a],n===undefined?s&&"get"in s&&(i=s.get(e,!1,r))!==undefined?i:u[t]:(o=typeof n,"string"===o&&(i=Ct.exec(n))&&(n=(i[1]+1)*i[2]+parseFloat(x.css(e,t)),o="number"),null==n||"number"===o&&isNaN(n)||("number"!==o||x.cssNumber[a]||(n+="px"),x.support.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),s&&"set"in s&&(n=s.set(e,n,r))===undefined||(u[t]=n)),undefined)}},css:function(e,t,n,r){var i,o,s,a=x.camelCase(t);return t=x.cssProps[a]||(x.cssProps[a]=Dt(e.style,a)),s=x.cssHooks[t]||x.cssHooks[a],s&&"get"in s&&(i=s.get(e,!0,n)),i===undefined&&(i=yt(e,t,r)),"normal"===i&&t in Et&&(i=Et[t]),""===n||n?(o=parseFloat(i),n===!0||x.isNumeric(o)?o||0:i):i}}),yt=function(e,t,n){var r,i,o,s=n||Lt(e),a=s?s.getPropertyValue(t)||s[t]:undefined,u=e.style;return s&&(""!==a||x.contains(e.ownerDocument,e)||(a=x.style(e,t)),Tt.test(a)&&bt.test(t)&&(r=u.width,i=u.minWidth,o=u.maxWidth,u.minWidth=u.maxWidth=u.width=a,a=s.width,u.width=r,u.minWidth=i,u.maxWidth=o)),a};function Ht(e,t,n){var r=wt.exec(t);return r?Math.max(0,r[1]-(n||0))+(r[2]||"px"):t}function Ot(e,t,n,r,i){var o=n===(r?"border":"content")?4:"width"===t?1:0,s=0;for(;4>o;o+=2)"margin"===n&&(s+=x.css(e,n+St[o],!0,i)),r?("content"===n&&(s-=x.css(e,"padding"+St[o],!0,i)),"margin"!==n&&(s-=x.css(e,"border"+St[o]+"Width",!0,i))):(s+=x.css(e,"padding"+St[o],!0,i),"padding"!==n&&(s+=x.css(e,"border"+St[o]+"Width",!0,i)));return s}function Ft(e,t,n){var r=!0,i="width"===t?e.offsetWidth:e.offsetHeight,o=Lt(e),s=x.support.boxSizing&&"border-box"===x.css(e,"boxSizing",!1,o);if(0>=i||null==i){if(i=yt(e,t,o),(0>i||null==i)&&(i=e.style[t]),Tt.test(i))return i;r=s&&(x.support.boxSizingReliable||i===e.style[t]),i=parseFloat(i)||0}return i+Ot(e,t,n||(s?"border":"content"),r,o)+"px"}function Pt(e){var t=o,n=kt[e];return n||(n=Rt(e,t),"none"!==n&&n||(vt=(vt||x(" + + + + diff --git a/tests/automation/window-eval/internal/package.json b/tests/automation/window-eval/internal/package.json new file mode 100644 index 0000000000..a33ab28774 --- /dev/null +++ b/tests/automation/window-eval/internal/package.json @@ -0,0 +1,5 @@ +{ + "name":"nw_1403254112", + "main":"index.html", + "dependencies":{} +} \ No newline at end of file diff --git a/tests/automation/window-eval/mocha_test.js b/tests/automation/window-eval/mocha_test.js new file mode 100644 index 0000000000..de11d3e1e9 --- /dev/null +++ b/tests/automation/window-eval/mocha_test.js @@ -0,0 +1,35 @@ +var path = require('path'); +var assert = require('assert'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); + + +describe('Window.eval',function(){ + var server, child, result; + + before(function(done) { + this.timeout(0); + server = createTCPServer(13013); + child = spawnChildProcess(path.join(curDir, 'internal')); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + result = (data.toString() == "success"); + child.kill(); + done(); + }); + }); + + }); + + after(function () { + server.close(); + }); + + it("Window.eval should works",function(done){ + assert.equal(result,true); + done(); + }); +}); + + diff --git a/tests/automation/window-eval/package.json b/tests/automation/window-eval/package.json new file mode 100644 index 0000000000..3b31df6584 --- /dev/null +++ b/tests/automation/window-eval/package.json @@ -0,0 +1,5 @@ +{ + "name":"window_eval_wrapper", + "main":"index.html" +} + From 870813bddc89865210927906f35f67d17c8dd383 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Tue, 2 Dec 2014 09:34:03 +0800 Subject: [PATCH 340/492] remove useless comment --- tests/automation/start_app/zip.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/automation/start_app/zip.py b/tests/automation/start_app/zip.py index 1db9d99c1f..66f228f716 100644 --- a/tests/automation/start_app/zip.py +++ b/tests/automation/start_app/zip.py @@ -1,6 +1,5 @@ import zipfile import os -print 'Python----by Jingfu' curDir = os.path.dirname(os.path.abspath(__file__)) zip = zipfile.ZipFile(os.path.join(curDir, 'tmp-nw', 'app.nw'), 'w', compression=zipfile.ZIP_DEFLATED) From f1e8b3868826b2733e9c8aabc9d3a7f52575f9b5 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Tue, 2 Dec 2014 09:34:37 +0800 Subject: [PATCH 341/492] exclude bad test case from batch testing --- tests/automation/config.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/automation/config.json b/tests/automation/config.json index c114585038..1c100020f2 100644 --- a/tests/automation/config.json +++ b/tests/automation/config.json @@ -1,7 +1,7 @@ { "format": "xunit-file", "exclude": ["node_modules", "output", "internal", "res", "app", "node-remote", "save_devtools_settings", "single_instance", - "source-maps", + "source-maps", "temp_dir", "call_require_with_node-main_set", "show_devtool_after_http_server_created_in_node_main", "reference-node-main"], "single": "", "timeout": "5000", From f0d71dc210da9e4184dc5ef12baf0d26a2aeebcd Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 2 Dec 2014 10:13:17 +0800 Subject: [PATCH 342/492] support policy.setNewWindowManifest in 'new-win-policy' Fix #2543 --- src/api/dispatcher.cc | 12 +++++++++++- src/api/dispatcher.h | 3 ++- src/api/window_bindings.js | 1 + src/nw_shell.cc | 10 +++++++++- src/nw_shell.h | 3 ++- src/renderer/shell_content_renderer_client.cc | 5 +++-- src/renderer/shell_content_renderer_client.h | 3 ++- 7 files changed, 30 insertions(+), 7 deletions(-) diff --git a/src/api/dispatcher.cc b/src/api/dispatcher.cc index a8583d5214..4238ea03d8 100644 --- a/src/api/dispatcher.cc +++ b/src/api/dispatcher.cc @@ -205,7 +205,8 @@ void Dispatcher::willHandleNavigationPolicy( content::RenderView* rv, blink::WebFrame* frame, const blink::WebURLRequest& request, - blink::WebNavigationPolicy* policy) { + blink::WebNavigationPolicy* policy, + blink::WebString* manifest) { blink::WebView* web_view = rv->GetWebView(); @@ -246,6 +247,15 @@ void Dispatcher::willHandleNavigationPolicy( v8::Handle argv[] = {id_val, v8_str("new-win-policy"), args }; node::MakeCallback(isolate, objects_registry, "handleEvent", 3, argv); + v8::Local manifest_val = policy_obj->Get(v8_str("manifest")); + + //TODO: change this to object + if (manifest_val->IsString()) { + v8::String::Utf8Value manifest_str(manifest_val); + if (manifest) + *manifest = blink::WebString::fromUTF8(*manifest_str); + } + v8::Local val = policy_obj->Get(v8_str("val")); if (!val->IsString()) return; diff --git a/src/api/dispatcher.h b/src/api/dispatcher.h index 90298000fc..8e24c41707 100644 --- a/src/api/dispatcher.h +++ b/src/api/dispatcher.h @@ -54,7 +54,8 @@ class Dispatcher : public content::RenderViewObserver { content::RenderView* rv, blink::WebFrame* frame, const blink::WebURLRequest& request, - blink::WebNavigationPolicy* policy); + blink::WebNavigationPolicy* policy, + blink::WebString* manifest); private: // RenderViewObserver implementation. diff --git a/src/api/window_bindings.js b/src/api/window_bindings.js index 49ec508675..04fda014ef 100644 --- a/src/api/window_bindings.js +++ b/src/api/window_bindings.js @@ -146,6 +146,7 @@ Window.prototype.handleEvent = function(ev) { policy.forceDownload = function () { this.val = 'download'; }; policy.forceNewWindow = function () { this.val = 'new-window'; }; policy.forceNewPopup = function () { this.val = 'new-popup'; }; + policy.setNewWindowManifest = function (m) { this.manifest = JSON.stringify(m); }; } // Route events to EventEmitter. this.emit.apply(this, arguments); diff --git a/src/nw_shell.cc b/src/nw_shell.cc index dd7a398b93..5e23d0e4a4 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -21,6 +21,7 @@ #include "content/nw/src/nw_shell.h" #include "base/command_line.h" +#include "base/json/json_reader.h" #include "base/message_loop/message_loop.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" @@ -568,11 +569,18 @@ void Shell::WebContentsCreated(WebContents* source_contents, int source_frame_id, const base::string16& frame_name, const GURL& target_url, - WebContents* new_contents) { + WebContents* new_contents, + const base::string16& nw_window_manifest) { // Create with package's manifest scoped_ptr manifest( GetPackage()->window()->DeepCopy()); + scoped_ptr val; + std::string manifest_str = base::UTF16ToUTF8(nw_window_manifest); + val.reset(base::JSONReader().ReadToValue(manifest_str)); + if (val.get() && val->IsType(base::Value::TYPE_DICTIONARY)) + manifest.reset(static_cast(val.release())); + // Get window features blink::WebWindowFeatures features = new_contents->GetWindowFeatures(); manifest->SetBoolean(switches::kmResizable, features.resizable); diff --git a/src/nw_shell.h b/src/nw_shell.h index d206e06704..2b75f2c35d 100644 --- a/src/nw_shell.h +++ b/src/nw_shell.h @@ -165,7 +165,8 @@ class Shell : public WebContentsDelegate, int source_frame_id, const base::string16& frame_name, const GURL& target_url, - WebContents* new_contents) OVERRIDE; + WebContents* new_contents, + const base::string16& nw_window_manifest) OVERRIDE; virtual void ToggleFullscreenModeForTab(WebContents* web_contents, bool enter_fullscreen) OVERRIDE; virtual bool IsFullscreenForTabOrPending( diff --git a/src/renderer/shell_content_renderer_client.cc b/src/renderer/shell_content_renderer_client.cc index 9107d67329..981b948564 100644 --- a/src/renderer/shell_content_renderer_client.cc +++ b/src/renderer/shell_content_renderer_client.cc @@ -502,9 +502,10 @@ void ShellContentRendererClient::willHandleNavigationPolicy( RenderView* rv, blink::WebFrame* frame, const blink::WebURLRequest& request, - blink::WebNavigationPolicy* policy) { + blink::WebNavigationPolicy* policy, + blink::WebString* manifest) { - nwapi::Dispatcher::willHandleNavigationPolicy(rv, frame, request, policy); + nwapi::Dispatcher::willHandleNavigationPolicy(rv, frame, request, policy, manifest); } void ShellContentRendererClient::windowOpenBegin(const blink::WebURL& url) { diff --git a/src/renderer/shell_content_renderer_client.h b/src/renderer/shell_content_renderer_client.h index cd7a85e938..8fa9f5f9e4 100644 --- a/src/renderer/shell_content_renderer_client.h +++ b/src/renderer/shell_content_renderer_client.h @@ -54,7 +54,8 @@ class ShellContentRendererClient : public ContentRendererClient { virtual void willHandleNavigationPolicy(RenderView* rv, blink::WebFrame* frame, const blink::WebURLRequest& request, - blink::WebNavigationPolicy* policy) OVERRIDE; + blink::WebNavigationPolicy* policy, + blink::WebString* manifest = NULL) OVERRIDE; virtual void windowOpenBegin(const blink::WebURL& url) OVERRIDE; virtual void windowOpenEnd() OVERRIDE; From 831a6af8543cd3a9e3cd4e9710664f30feba7e14 Mon Sep 17 00:00:00 2001 From: Roger Date: Tue, 2 Dec 2014 13:24:52 +0800 Subject: [PATCH 343/492] Fix #2707: support Window.disableCache(bool) --- src/api/window_bindings.cc | 21 +++++++++++++++++++++ src/api/window_bindings.js | 11 ++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/src/api/window_bindings.cc b/src/api/window_bindings.cc index 0c249471e2..9d0b2c3589 100644 --- a/src/api/window_bindings.cc +++ b/src/api/window_bindings.cc @@ -38,17 +38,27 @@ using namespace blink; #include "third_party/WebKit/Source/config.h" #include "third_party/WebKit/Source/core/html/HTMLIFrameElement.h" +#include "third_party/WebKit/Source/core/dom/Document.h" #include "third_party/WebKit/Source/core/frame/LocalFrame.h" #include "third_party/WebKit/public/web/WebFrame.h" #include "third_party/WebKit/public/web/WebView.h" #include "third_party/WebKit/Source/web/WebLocalFrameImpl.h" #include "third_party/WebKit/public/web/WebScriptSource.h" +#undef BLINK_IMPLEMENTATION +#define BLINK_IMPLEMENTATION 1 +#include "third_party/WebKit/public/web/WebDocument.h" +#include "third_party/WebKit/Source/platform/heap/Handle.h" +#include "third_party/WebKit/Source/core/inspector/InspectorInstrumentation.h" +#include "third_party/WebKit/Source/core/inspector/InspectorResourceAgent.h" + #undef CHECK #include "V8HTMLIFrameElement.h" using blink::WebScriptSource; using blink::WebFrame; +using blink::InstrumentingAgents; +using blink::InspectorResourceAgent; namespace nwapi { @@ -153,6 +163,17 @@ WindowBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args } args.GetReturnValue().Set(v8::Undefined(isolate)); return; + } else if (method == "setCacheDisabled") { + RefPtrWillBePersistent document = static_cast >(main_frame->document()); + InstrumentingAgents* instrumentingAgents = instrumentationForPage(document->page()); + if (instrumentingAgents) { + bool disable = args[2]->ToBoolean()->Value(); + InspectorResourceAgent* resAgent = instrumentingAgents->inspectorResourceAgent(); + resAgent->setCacheDisabled(NULL, disable); + args.GetReturnValue().Set(true); + } else + args.GetReturnValue().Set(false); + return; } args.GetReturnValue().Set(remote::CallObjectMethod(render_view->GetRoutingID(), diff --git a/src/api/window_bindings.js b/src/api/window_bindings.js index 04fda014ef..c60e32337a 100644 --- a/src/api/window_bindings.js +++ b/src/api/window_bindings.js @@ -505,8 +505,13 @@ Window.prototype.capturePage = function(callback, image_format_options) { CallObjectMethod(this, 'CapturePage', [options.format]); }; - Window.prototype.eval = function(frame, script) { - return CallObjectMethod(this, 'EvaluateScript', frame, script); - }; +Window.prototype.eval = function(frame, script) { + return CallObjectMethod(this, 'EvaluateScript', frame, script); +}; + +Window.prototype.disableCache = function(flag) { + return CallObjectMethod(this, 'setCacheDisabled', flag); +}; + } // function Window.init From c1426db63f39c537413bffe1d727ba533ef41c3a Mon Sep 17 00:00:00 2001 From: yejingfu Date: Tue, 2 Dec 2014 13:37:49 +0800 Subject: [PATCH 344/492] should run batch test in sequence --- tests/automation/mocha_test.js | 100 ++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 45 deletions(-) diff --git a/tests/automation/mocha_test.js b/tests/automation/mocha_test.js index 990f4b970a..7424ebd24a 100644 --- a/tests/automation/mocha_test.js +++ b/tests/automation/mocha_test.js @@ -103,39 +103,8 @@ function performTests(config) { if (Number.isNaN(timeout) || timeout <= 0) timeout = 5000; - var resetTimeout = function() { - if (timerId) - clearTimeout(timerId); - timerId = setTimeout(function() { - timerId = undefined; - for (var i = 0, len = children.length; i < len; i++) { - print(colors.red('[Timeout]: ') + colors.underline(children[i].testcase)); - children[i].kill('SIGTERM'); - } - }, timeout); - }; - env['out_dir'] = g_outputDir; - var bindChildExit = function(child, code, signal) { - child.on('exit', function(code, signal) { - var prefix = code === 0 ? '[Success]' : '[Failure]'; - print((code === 0 ? colors.green(prefix) : colors.red(prefix)) - + ': ' + colors.underline(child.testcase) + ' with exit code ' + code); - //console.log('Done: ' + child.testcase + ' with exit code ' + code); - var idx = children.indexOf(child); - if (idx >= 0) { - children.splice(idx, 1); - resetTimeout(); - } - if (children.length === 0) { - if (timerId) - clearTimeout(timerId); - postTest(); - } - }); - }; - var spawTestProcessByNW = function(testcase) { cmd = 'nw'; argv = [testcase]; @@ -156,20 +125,61 @@ function performTests(config) { return child; }; - for (var i = 0, len = testSuites.length; i < len; i++) { - child = spawTestProcessByNW(testSuites[i]); - if (child) { - child.testcase = testSuites[i]; - bindChildExit(child); - //(function(theChild) { - // theChild.on('exit', function(code, signal) { - // onChildExit(theChild, code, signal); - // }); - //})(child); - children.push(child); - } - } - resetTimeout(); + var curIdx = -1; + var curChildProcess = undefined; + var prefix; + +// for (var i =0, len = testSuites.length; i < len; i++ ) { +// console.log('Test suite ' + i + ':' + testSuites[i]); +// } + + var runNextTestByNW = function() { + curIdx += 1; + if (curIdx < testSuites.length) { + resetTimeout(curIdx); + curChildProcess = spawTestProcessByNW(testSuites[curIdx]); + children.push(curChildProcess); + curChildProcess.on('exit', function(code, signal) { + (function(p) { + prefix = (code === 0 ? colors.green('[Success]') : colors.red('[Failure]')); + print(prefix + ' : ' + colors.underline(p.testcase) + ' with exit code ' + code); + clearTimeout(timerId); + p.removeAllListeners('exit'); + runNextTestByNW(); + })(curChildProcess); + }); + } else { + if (timerId) { + clearTimeout(timerId); + timerId = undefined; + } + postTest(); + } + }; + + var resetTimeout = function(idx) { + if (timerId) + clearTimeout(timerId); + (function(idx){ + + timerId = setTimeout(function() { + + timerId = undefined; + if (idx || idx >= 0) { + var p = children[idx]; + print(colors.yellow('[Timeout]') + ' : ' + colors.underline(p.testcase)); + p.kill('SIGKILL'); // 'SIGKILL', 'SIGTERM' + p = undefined; + runNextTestByNW(); + } + }, timeout); + + })(idx); + + }; + + runNextTestByNW(); + } // end of performTests() var content = fs.readFileSync('./config.json'); From 8366f30f1fa531fb56934b74335ce8fc9cb30ac3 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Tue, 2 Dec 2014 15:29:53 +0800 Subject: [PATCH 345/492] Fix automation test script. The test cases should be run in sequence. Set default timeout time to 8 seconds. Exclude some un-verified test cases, they would be added again. Add a file to list all known failed test cases. --- tests/automation/config.json | 7 +++++-- tests/automation/failures.md | 16 ++++++++++++++++ tests/automation/mocha_test.js | 8 +++++--- 3 files changed, 26 insertions(+), 5 deletions(-) create mode 100644 tests/automation/failures.md diff --git a/tests/automation/config.json b/tests/automation/config.json index 1c100020f2..55129e7dae 100644 --- a/tests/automation/config.json +++ b/tests/automation/config.json @@ -2,9 +2,12 @@ "format": "xunit-file", "exclude": ["node_modules", "output", "internal", "res", "app", "node-remote", "save_devtools_settings", "single_instance", "source-maps", "temp_dir", - "call_require_with_node-main_set", "show_devtool_after_http_server_created_in_node_main", "reference-node-main"], + "call_require_with_node-main_set", "show_devtool_after_http_server_created_in_node_main", "reference-node-main", + "start_app", "chromedriver2_server", "console", "crash_dump", "datapath", "fast_open_and_close_devtools", + "loaded_event", "node", "nw-in-mem", "process", "quit_with_secondary_window_on_top", "reload_application" +], "single": "", - "timeout": "5000", + "timeout": "8000", "slow": "200", "quiet": false } diff --git a/tests/automation/failures.md b/tests/automation/failures.md new file mode 100644 index 0000000000..e3622911ff --- /dev/null +++ b/tests/automation/failures.md @@ -0,0 +1,16 @@ +Failed test cases +======================= + +* cookies_api + +* document_cookies + +* website + +* user-agent + +* user-agent-app + +* chromium-args + + diff --git a/tests/automation/mocha_test.js b/tests/automation/mocha_test.js index 7424ebd24a..db7f86f779 100644 --- a/tests/automation/mocha_test.js +++ b/tests/automation/mocha_test.js @@ -140,13 +140,14 @@ function performTests(config) { curChildProcess = spawTestProcessByNW(testSuites[curIdx]); children.push(curChildProcess); curChildProcess.on('exit', function(code, signal) { - (function(p) { + (function(p, c) { prefix = (code === 0 ? colors.green('[Success]') : colors.red('[Failure]')); - print(prefix + ' : ' + colors.underline(p.testcase) + ' with exit code ' + code); + print(prefix + ' : ' + colors.underline(p.testcase) + ' with exit code ' + c); clearTimeout(timerId); p.removeAllListeners('exit'); + p.kill('SIGKILL'); runNextTestByNW(); - })(curChildProcess); + })(curChildProcess, code); }); } else { if (timerId) { @@ -168,6 +169,7 @@ function performTests(config) { if (idx || idx >= 0) { var p = children[idx]; print(colors.yellow('[Timeout]') + ' : ' + colors.underline(p.testcase)); + p.removeAllListeners('exit'); p.kill('SIGKILL'); // 'SIGKILL', 'SIGTERM' p = undefined; runNextTestByNW(); From fff87749317364eed9c873ad3053b870b0466247 Mon Sep 17 00:00:00 2001 From: yejingfu Date: Tue, 2 Dec 2014 15:35:44 +0800 Subject: [PATCH 346/492] minor fix about some test cause so that they can run smoothly --- .../mocha_test.js | 2 +- tests/automation/chromium-args/mocha_test.js | 10 +- tests/automation/cookies_api/mocha_test.js | 4 +- tests/automation/crashonreload/mocha_test.js | 13 +- .../automation/document_cookies/mocha_test.js | 12 +- tests/automation/remote-img/mocha_test.js | 66 +- .../isolate-0x1f73bd0-v8.log | 1480 ----------------- tests/automation/user-agent-app/mocha_test.js | 4 +- 8 files changed, 74 insertions(+), 1517 deletions(-) delete mode 100644 tests/automation/snapshot/internal/1266-snapshot-crash-start/isolate-0x1f73bd0-v8.log diff --git a/tests/automation/after_close_previous_window_then_open_new/mocha_test.js b/tests/automation/after_close_previous_window_then_open_new/mocha_test.js index f14fcfbfb1..77540361cf 100644 --- a/tests/automation/after_close_previous_window_then_open_new/mocha_test.js +++ b/tests/automation/after_close_previous_window_then_open_new/mocha_test.js @@ -19,7 +19,7 @@ describe('after close previous window then open new', function() { before(function(done) { this.timeout(0); - if (!fs.exists(dumpDir)) + if (!fs.existsSync(dumpDir)) fs.mkdirSync(dumpDir); var appPath = path.join(global.tests_dir, 'internal'); diff --git a/tests/automation/chromium-args/mocha_test.js b/tests/automation/chromium-args/mocha_test.js index 2ece78f593..e0ae047d3e 100644 --- a/tests/automation/chromium-args/mocha_test.js +++ b/tests/automation/chromium-args/mocha_test.js @@ -41,7 +41,7 @@ describe('chromium-args', function() { describe('--app=url', function() { - var result2 = false; + var result = false, result2 = false; var child, server; @@ -57,12 +57,20 @@ describe('chromium-args', function() { socket.setEncoding('utf8'); socket.on('data', function(data) { result2 = data; + result = true; done(); }); }); child = spawnChildProcess(path.join(curDir, 'internal')); + setTimeout(function() { + if (!result) { + child.kill(); + done('timeout'); + } + }, 4500); + }); }); diff --git a/tests/automation/cookies_api/mocha_test.js b/tests/automation/cookies_api/mocha_test.js index eeb279fc6b..220ab5fab7 100644 --- a/tests/automation/cookies_api/mocha_test.js +++ b/tests/automation/cookies_api/mocha_test.js @@ -111,12 +111,12 @@ describe('Window.cookies', function() { describe('remove', function() { before(function(done) { this.timeout(0); - child = spawnChild(3); + child = spawnChild(4); server.on('connection', function(socket) { socket.setEncoding('utf8'); socket.on('data', function(data) { results = JSON.parse(data); - changed = results[1]; + //changed = results[1]; child.kill(); done(); }); diff --git a/tests/automation/crashonreload/mocha_test.js b/tests/automation/crashonreload/mocha_test.js index 925297a6f4..a0c4e29b55 100644 --- a/tests/automation/crashonreload/mocha_test.js +++ b/tests/automation/crashonreload/mocha_test.js @@ -10,10 +10,14 @@ describe('crash on reload',function(){ var child = spawnChildProcess(path.join(curDir, 'internal')); child.on('exit', function (code){ - if (code != 0) - return done('nw crashes'); result = true; - done(); + if (code != 0) { + done('nw crashes'); + child.kill(); + } else { + done(); + } + }); setTimeout(function(){ @@ -21,6 +25,7 @@ describe('crash on reload',function(){ child.kill(); done(); } - }, 7500); + + }, 4500); }); }); diff --git a/tests/automation/document_cookies/mocha_test.js b/tests/automation/document_cookies/mocha_test.js index 0984aa7900..7764443c0d 100644 --- a/tests/automation/document_cookies/mocha_test.js +++ b/tests/automation/document_cookies/mocha_test.js @@ -48,11 +48,11 @@ var server; setTimeout(function() { results.push(data); child.kill(); - //done(); - }, 2000); + done(); + }, 1000); }); }); - setTimeout(done, 3000); + setTimeout(done, 10000); }); after(function() { @@ -75,12 +75,12 @@ var server; setTimeout(function() { results.push(data); child.kill(); - //done(); - }, 2000); + done(); + }, 1000); }); }); - setTimeout(done, 3000); + setTimeout(done, 10000); }); after(function() { diff --git a/tests/automation/remote-img/mocha_test.js b/tests/automation/remote-img/mocha_test.js index 1a4f44964a..aa5582afba 100644 --- a/tests/automation/remote-img/mocha_test.js +++ b/tests/automation/remote-img/mocha_test.js @@ -1,69 +1,93 @@ var path = require('path'); var spawn = require('child_process').spawn; var fs = require('fs-extra'); +var os = require('os'); +var platform = os.platform(); var curDir = fs.realpathSync('.'); +var result, app, exec_argv, timerId; + +process.on('exit', function() { + if (app) { + app.kill('SIGKILL'); + } +}); + describe('remote-file-access', function(){ - var os = require('os'); - var platform = os.platform(); before(function(done){ this.timeout(0); if(platform == "win32"){ - fs.copy(path.join(curDir, 'star.jpg'),'/star.jpg'); + fs.copySync(path.join(curDir, 'star.jpg'),'/star.jpg'); } else { - fs.copy(path.join(curDir, 'star.jpg'),'/tmp/star.jpg'); + fs.copySync(path.join(curDir, 'star.jpg'),'/tmp/star.jpg'); } done(); }); - after(function() { + after(function(done) { this.timeout(0); if (platform == "win32"){ - fs.remove('/star.jpg'); + fs.unlinkSync('/star.jpg'); } else { - fs.remove('/tmp/star.jpg'); + fs.unlinkSync('/tmp/star.jpg'); } + done(); }); + it ('remote img should work', function(done){ this.timeout(0); - var exec_argv = [path.join(curDir, 'imgnotshown')] - var result =false; - var app = spawn(process.execPath, exec_argv); + exec_argv = [path.join(curDir, 'imgnotshown')]; + result =false; + app = spawn(process.execPath, exec_argv); app.on('exit', function(code){ + + clearTimeout(timerId); result = true; + app.kill('SIGKILL'); + app = undefined; done(); - }) - setTimeout(function(){ + }); + + timerId = setTimeout(function(){ if(!result){ - app.kill(); + app.removeAllListeners('exit'); + app.kill('SIGKILL'); + app = undefined; done(); } - }, 3000) + }, 2000); }); + it ('local img should work', function(done){ this.timeout(0); - var exec_argv = [path.join(curDir, 'imgshown')] - var result = false; - var app = spawn(process.execPath, exec_argv); + exec_argv = [path.join(curDir, 'imgshown')]; + result = false; + app = spawn(process.execPath, exec_argv); app.on('exit', function(code){ + clearTimeout(timerId); result = true; + app.kill('SIGKILL'); + app = undefined; done(); }); - setTimeout(function(){ + timerId=setTimeout(function(){ if(!result){ - app.kill(); + app.removeAllListeners('exit'); + app.kill('SIGKILL'); + app = undefined; done(); - } - }, 3000); + } + }, 2000); }); + }); diff --git a/tests/automation/snapshot/internal/1266-snapshot-crash-start/isolate-0x1f73bd0-v8.log b/tests/automation/snapshot/internal/1266-snapshot-crash-start/isolate-0x1f73bd0-v8.log deleted file mode 100644 index d785b7b73d..0000000000 --- a/tests/automation/snapshot/internal/1266-snapshot-crash-start/isolate-0x1f73bd0-v8.log +++ /dev/null @@ -1,1480 +0,0 @@ -code-creation,Stub,2,0x2a6a4f906000,755,"CEntryStub" -code-creation,Stub,2,0x2a6a4f906300,1103,"CEntryStub" -code-creation,Stub,2,0x2a6a4f906760,168,"StoreBufferOverflowStub" -code-creation,Stub,2,0x2a6a4f906820,388,"StoreBufferOverflowStub" -code-creation,Stub,2,0x2a6a4f9069c0,116,"StubFailureTrampolineStub" -code-creation,Stub,2,0x2a6a4f906a40,117,"StubFailureTrampolineStub" -code-creation,Stub,2,0x2a6a4f906ac0,450,"ArrayNoArgumentConstructorStub_FAST_SMI_ELEMENTS" -code-creation,Stub,2,0x2a6a4f906ca0,410,"ArrayNoArgumentConstructorStub_FAST_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -code-creation,Stub,2,0x2a6a4f906e40,466,"ArrayNoArgumentConstructorStub_FAST_HOLEY_SMI_ELEMENTS" -code-creation,Stub,2,0x2a6a4f907020,430,"ArrayNoArgumentConstructorStub_FAST_HOLEY_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -code-creation,Stub,2,0x2a6a4f9071e0,410,"ArrayNoArgumentConstructorStub_FAST_DOUBLE_ELEMENTS" -code-creation,Stub,2,0x2a6a4f907380,410,"ArrayNoArgumentConstructorStub_FAST_HOLEY_DOUBLE_ELEMENTS" -code-creation,Stub,2,0x2a6a4f907520,430,"ArrayNoArgumentConstructorStub_FAST_ELEMENTS" -code-creation,Stub,2,0x2a6a4f9076e0,430,"ArrayNoArgumentConstructorStub_FAST_HOLEY_ELEMENTS" -code-creation,Stub,2,0x2a6a4f9078a0,570,"ArraySingleArgumentConstructorStub_FAST_SMI_ELEMENTS" -code-creation,Stub,2,0x2a6a4f907ae0,530,"ArraySingleArgumentConstructorStub_FAST_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -code-creation,Stub,2,0x2a6a4f907d00,590,"ArraySingleArgumentConstructorStub_FAST_HOLEY_SMI_ELEMENTS" -code-creation,Stub,2,0x2a6a4f907f60,550,"ArraySingleArgumentConstructorStub_FAST_HOLEY_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -code-creation,Stub,2,0x2a6a4f9081a0,554,"ArraySingleArgumentConstructorStub_FAST_DOUBLE_ELEMENTS" -code-creation,Stub,2,0x2a6a4f9083e0,554,"ArraySingleArgumentConstructorStub_FAST_HOLEY_DOUBLE_ELEMENTS" -code-creation,Stub,2,0x2a6a4f908620,550,"ArraySingleArgumentConstructorStub_FAST_ELEMENTS" -code-creation,Stub,2,0x2a6a4f908860,550,"ArraySingleArgumentConstructorStub_FAST_HOLEY_ELEMENTS" -code-creation,Stub,2,0x2a6a4f908aa0,546,"ArrayNArgumentsConstructorStub_FAST_SMI_ELEMENTS" -code-creation,Stub,2,0x2a6a4f908ce0,506,"ArrayNArgumentsConstructorStub_FAST_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -code-creation,Stub,2,0x2a6a4f908ee0,562,"ArrayNArgumentsConstructorStub_FAST_HOLEY_SMI_ELEMENTS" -code-creation,Stub,2,0x2a6a4f909120,526,"ArrayNArgumentsConstructorStub_FAST_HOLEY_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -code-creation,Stub,2,0x2a6a4f909340,542,"ArrayNArgumentsConstructorStub_FAST_DOUBLE_ELEMENTS" -code-creation,Stub,2,0x2a6a4f909560,542,"ArrayNArgumentsConstructorStub_FAST_HOLEY_DOUBLE_ELEMENTS" -code-creation,Stub,2,0x2a6a4f909780,470,"ArrayNArgumentsConstructorStub_FAST_ELEMENTS" -code-creation,Stub,2,0x2a6a4f909960,470,"ArrayNArgumentsConstructorStub_FAST_HOLEY_ELEMENTS" -code-creation,Stub,2,0x2a6a4f909b40,2723,"RecordWriteStub" -code-creation,Stub,2,0x2a6a4f90a600,2680,"RecordWriteStub" -code-creation,Stub,2,0x2a6a4f90b080,558,"CreateAllocationSiteStub" -code-creation,Stub,10,0x2a6a4f90b2c0,149,"BinaryOpICStub(BIT_OR:None*None->None)" -code-creation,Stub,10,0x2a6a4f90b360,149,"BinaryOpICStub(BIT_OR_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90b400,149,"BinaryOpICStub(BIT_OR_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90b4a0,149,"BinaryOpICStub(BIT_XOR:None*None->None)" -code-creation,Stub,10,0x2a6a4f90b540,149,"BinaryOpICStub(BIT_XOR_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90b5e0,149,"BinaryOpICStub(BIT_XOR_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90b680,149,"BinaryOpICStub(BIT_AND:None*None->None)" -code-creation,Stub,10,0x2a6a4f90b720,149,"BinaryOpICStub(BIT_AND_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90b7c0,149,"BinaryOpICStub(BIT_AND_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90b860,149,"BinaryOpICStub(SHL:None*None->None)" -code-creation,Stub,10,0x2a6a4f90b900,149,"BinaryOpICStub(SHL_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90b9a0,149,"BinaryOpICStub(SHL_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90ba40,149,"BinaryOpICStub(SAR:None*None->None)" -code-creation,Stub,10,0x2a6a4f90bae0,149,"BinaryOpICStub(SAR_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90bb80,149,"BinaryOpICStub(SAR_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90bc20,149,"BinaryOpICStub(SHR:None*None->None)" -code-creation,Stub,10,0x2a6a4f90bcc0,149,"BinaryOpICStub(SHR_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90bd60,149,"BinaryOpICStub(SHR_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90be00,149,"BinaryOpICStub(ROR:None*None->None)" -code-creation,Stub,10,0x2a6a4f90bea0,149,"BinaryOpICStub(ROR_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90bf40,149,"BinaryOpICStub(ROR_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90bfe0,149,"BinaryOpICStub(ADD:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c080,149,"BinaryOpICStub(ADD_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c120,149,"BinaryOpICStub(ADD_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c1c0,149,"BinaryOpICStub(SUB:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c260,149,"BinaryOpICStub(SUB_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c300,149,"BinaryOpICStub(SUB_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c3a0,149,"BinaryOpICStub(MUL:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c440,149,"BinaryOpICStub(MUL_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c4e0,149,"BinaryOpICStub(MUL_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c580,149,"BinaryOpICStub(DIV:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c620,149,"BinaryOpICStub(DIV_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c6c0,149,"BinaryOpICStub(DIV_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c760,149,"BinaryOpICStub(MOD:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c800,149,"BinaryOpICStub(MOD_ReuseLeft:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c8a0,149,"BinaryOpICStub(MOD_ReuseRight:None*None->None)" -code-creation,Stub,10,0x2a6a4f90c940,348,"BinaryOpICStub(ADD:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f90caa0,380,"BinaryOpICStub(ADD_ReuseLeft:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f90cc20,514,"BinaryOpICStub(ADD:Int32*Int32->Number)" -code-creation,Stub,10,0x2a6a4f90ce40,538,"BinaryOpICStub(ADD_ReuseLeft:Int32*Int32->Number)" -code-creation,Stub,10,0x2a6a4f90d060,498,"BinaryOpICStub(ADD:Int32*Number->Number)" -code-creation,Stub,10,0x2a6a4f90d260,522,"BinaryOpICStub(ADD_ReuseLeft:Int32*Number->Number)" -code-creation,Stub,10,0x2a6a4f90d480,518,"BinaryOpICStub(ADD_ReuseRight:Int32*Number->Number)" -code-creation,Stub,10,0x2a6a4f90d6a0,288,"BinaryOpICStub(ADD:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f90d7c0,320,"BinaryOpICStub(ADD_ReuseLeft:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f90d900,288,"BinaryOpICStub(ADD_ReuseRight:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f90da20,498,"BinaryOpICStub(ADD:Number*Int32->Number)" -code-creation,Stub,10,0x2a6a4f90dc20,522,"BinaryOpICStub(ADD_ReuseLeft:Number*Int32->Number)" -code-creation,Stub,10,0x2a6a4f90de40,522,"BinaryOpICStub(ADD_ReuseRight:Number*Int32->Number)" -code-creation,Stub,10,0x2a6a4f90e060,454,"BinaryOpICStub(ADD:Number*Number->Number)" -code-creation,Stub,10,0x2a6a4f90e240,474,"BinaryOpICStub(ADD_ReuseLeft:Number*Number->Number)" -code-creation,Stub,10,0x2a6a4f90e420,474,"BinaryOpICStub(ADD_ReuseRight:Number*Number->Number)" -code-creation,Stub,10,0x2a6a4f90e600,426,"BinaryOpICStub(ADD:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f90e7c0,446,"BinaryOpICStub(ADD_ReuseLeft:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f90e980,426,"BinaryOpICStub(ADD_ReuseRight:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f90eb40,272,"BinaryOpICStub(ADD:Smi*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f90ec60,272,"BinaryOpICStub(ADD_ReuseLeft:Smi*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f90ed80,470,"BinaryOpICStub(ADD:Smi*Int32->Number)" -code-creation,Stub,10,0x2a6a4f90ef60,426,"BinaryOpICStub(ADD:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f90f120,426,"BinaryOpICStub(ADD_ReuseLeft:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f90f2e0,446,"BinaryOpICStub(ADD_ReuseRight:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f90f4a0,216,"BinaryOpICStub(ADD_ReuseLeft:Smi*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f90f580,204,"BinaryOpICStub(ADD_ReuseRight:Smi*Smi->Smi)" -code-creation,Stub,2,0x2a6a4f90f660,182,"DoubleToIStub" -code-creation,Stub,2,0x2a6a4f90f720,184,"DoubleToIStub" -code-creation,Stub,10,0x2a6a4f90f7e0,408,"BinaryOpICStub(BIT_AND:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f90f980,436,"BinaryOpICStub(BIT_AND_ReuseLeft:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f90fb40,432,"BinaryOpICStub(BIT_AND_ReuseRight:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f90fd00,408,"BinaryOpICStub(BIT_AND:Int32*Int32->Smi)" -code-creation,Stub,10,0x2a6a4f90fea0,408,"BinaryOpICStub(BIT_AND_ReuseRight:Int32*Int32->Smi)" -code-creation,Stub,10,0x2a6a4f910040,316,"BinaryOpICStub(BIT_AND:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f910180,316,"BinaryOpICStub(BIT_AND_ReuseRight:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f9102c0,316,"BinaryOpICStub(BIT_AND:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f910400,316,"BinaryOpICStub(BIT_AND_ReuseLeft:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f910540,316,"BinaryOpICStub(BIT_AND_ReuseRight:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f910680,432,"BinaryOpICStub(BIT_AND_ReuseRight:Number*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f910840,316,"BinaryOpICStub(BIT_AND:Number*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f910980,316,"BinaryOpICStub(BIT_AND_ReuseRight:Number*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f910ac0,316,"BinaryOpICStub(BIT_AND:Smi*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f910c00,316,"BinaryOpICStub(BIT_AND_ReuseRight:Smi*Int32->Smi)" -code-creation,Stub,10,0x2a6a4f910d40,316,"BinaryOpICStub(BIT_AND_ReuseRight:Smi*Number->Smi)" -code-creation,Stub,10,0x2a6a4f910e80,188,"BinaryOpICStub(BIT_AND:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f910f40,188,"BinaryOpICStub(BIT_AND_ReuseLeft:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f911000,188,"BinaryOpICStub(BIT_AND_ReuseRight:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f9110c0,436,"BinaryOpICStub(BIT_OR_ReuseLeft:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f911280,432,"BinaryOpICStub(BIT_OR_ReuseRight:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f911440,408,"BinaryOpICStub(BIT_OR_ReuseLeft:Int32*Int32->Smi)" -code-creation,Stub,10,0x2a6a4f9115e0,316,"BinaryOpICStub(BIT_OR:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f911720,344,"BinaryOpICStub(BIT_OR_ReuseLeft:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f911880,316,"BinaryOpICStub(BIT_OR_ReuseRight:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f9119c0,316,"BinaryOpICStub(BIT_OR:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f911b00,316,"BinaryOpICStub(BIT_OR_ReuseRight:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f911c40,316,"BinaryOpICStub(BIT_OR:Number*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f911d80,344,"BinaryOpICStub(BIT_OR_ReuseLeft:Number*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f911ee0,316,"BinaryOpICStub(BIT_OR_ReuseRight:Number*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f912020,316,"BinaryOpICStub(BIT_OR:Number*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f912160,316,"BinaryOpICStub(BIT_OR_ReuseLeft:Number*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f9122a0,316,"BinaryOpICStub(BIT_OR_ReuseLeft:Smi*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f9123e0,340,"BinaryOpICStub(BIT_OR_ReuseRight:Smi*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f912540,316,"BinaryOpICStub(BIT_OR_ReuseRight:Smi*Int32->Smi)" -code-creation,Stub,10,0x2a6a4f912680,188,"BinaryOpICStub(BIT_OR_ReuseLeft:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f912740,188,"BinaryOpICStub(BIT_OR_ReuseRight:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f912800,408,"BinaryOpICStub(BIT_XOR:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f9129a0,436,"BinaryOpICStub(BIT_XOR_ReuseLeft:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f912b60,432,"BinaryOpICStub(BIT_XOR_ReuseRight:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f912d20,408,"BinaryOpICStub(BIT_XOR:Int32*Int32->Smi)" -code-creation,Stub,10,0x2a6a4f912ec0,408,"BinaryOpICStub(BIT_XOR_ReuseLeft:Int32*Int32->Smi)" -code-creation,Stub,10,0x2a6a4f913060,408,"BinaryOpICStub(BIT_XOR:Int32*Number->Smi)" -code-creation,Stub,10,0x2a6a4f913200,316,"BinaryOpICStub(BIT_XOR:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f913340,344,"BinaryOpICStub(BIT_XOR_ReuseLeft:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f9134a0,316,"BinaryOpICStub(BIT_XOR_ReuseRight:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f9135e0,408,"BinaryOpICStub(BIT_XOR:Number*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f913780,316,"BinaryOpICStub(BIT_XOR:Number*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f9138c0,316,"BinaryOpICStub(BIT_XOR:Number*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f913a00,316,"BinaryOpICStub(BIT_XOR:Smi*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f913b40,316,"BinaryOpICStub(BIT_XOR_ReuseLeft:Smi*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f913c80,316,"BinaryOpICStub(BIT_XOR_ReuseLeft:Smi*Int32->Smi)" -code-creation,Stub,10,0x2a6a4f913dc0,188,"BinaryOpICStub(BIT_XOR:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f913e80,188,"BinaryOpICStub(BIT_XOR_ReuseLeft:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f913f40,188,"BinaryOpICStub(BIT_XOR_ReuseRight:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f914000,412,"BinaryOpICStub(DIV:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f9141a0,518,"BinaryOpICStub(DIV:Int32*Int32->Number)" -code-creation,Stub,10,0x2a6a4f9143c0,502,"BinaryOpICStub(DIV:Int32*Number->Number)" -code-creation,Stub,10,0x2a6a4f9145c0,522,"BinaryOpICStub(DIV_ReuseLeft:Int32*Number->Number)" -code-creation,Stub,10,0x2a6a4f9147e0,340,"BinaryOpICStub(DIV:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f914940,474,"BinaryOpICStub(DIV:Int32*Smi->Number)" -code-creation,Stub,10,0x2a6a4f914b20,502,"BinaryOpICStub(DIV:Number*Int32->Number)" -code-creation,Stub,10,0x2a6a4f914d20,526,"BinaryOpICStub(DIV_ReuseLeft:Number*Int32->Number)" -code-creation,Stub,10,0x2a6a4f914f40,458,"BinaryOpICStub(DIV:Number*Number->Number)" -code-creation,Stub,10,0x2a6a4f915120,478,"BinaryOpICStub(DIV_ReuseLeft:Number*Number->Number)" -code-creation,Stub,10,0x2a6a4f915300,478,"BinaryOpICStub(DIV_ReuseRight:Number*Number->Number)" -code-creation,Stub,10,0x2a6a4f9154e0,430,"BinaryOpICStub(DIV:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f9156a0,450,"BinaryOpICStub(DIV_ReuseLeft:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f915880,336,"BinaryOpICStub(DIV:Smi*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f9159e0,474,"BinaryOpICStub(DIV:Smi*Int32->Number)" -code-creation,Stub,10,0x2a6a4f915bc0,474,"BinaryOpICStub(DIV_ReuseLeft:Smi*Int32->Number)" -code-creation,Stub,10,0x2a6a4f915da0,426,"BinaryOpICStub(DIV:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f915f60,426,"BinaryOpICStub(DIV_ReuseLeft:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f916120,450,"BinaryOpICStub(DIV_ReuseRight:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f916300,398,"BinaryOpICStub(DIV:Smi*Smi->Number)" -code-creation,Stub,10,0x2a6a4f9164a0,398,"BinaryOpICStub(DIV_ReuseLeft:Smi*Smi->Number)" -code-creation,Stub,10,0x2a6a4f916640,398,"BinaryOpICStub(DIV_ReuseRight:Smi*Smi->Number)" -code-creation,Stub,10,0x2a6a4f9167e0,264,"BinaryOpICStub(DIV:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f916900,264,"BinaryOpICStub(DIV_ReuseLeft:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f916a20,264,"BinaryOpICStub(DIV_ReuseRight:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f916b40,491,"BinaryOpICStub(MOD_ReuseLeft:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f916d40,256,"BinaryOpICStub(MOD:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f916e40,256,"BinaryOpICStub(MOD_ReuseLeft:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f916f40,380,"BinaryOpICStub(MUL:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f9170c0,514,"BinaryOpICStub(MUL:Int32*Int32->Number)" -code-creation,Stub,10,0x2a6a4f9172e0,498,"BinaryOpICStub(MUL:Int32*Number->Number)" -code-creation,Stub,10,0x2a6a4f9174e0,522,"BinaryOpICStub(MUL_ReuseLeft:Int32*Number->Number)" -code-creation,Stub,10,0x2a6a4f917700,308,"BinaryOpICStub(MUL:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f917840,336,"BinaryOpICStub(MUL_ReuseLeft:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f9179a0,470,"BinaryOpICStub(MUL:Int32*Smi->Number)" -code-creation,Stub,10,0x2a6a4f917b80,498,"BinaryOpICStub(MUL:Number*Int32->Number)" -code-creation,Stub,10,0x2a6a4f917d80,522,"BinaryOpICStub(MUL_ReuseLeft:Number*Int32->Number)" -code-creation,Stub,10,0x2a6a4f917fa0,522,"BinaryOpICStub(MUL_ReuseRight:Number*Int32->Number)" -code-creation,Stub,10,0x2a6a4f9181c0,454,"BinaryOpICStub(MUL:Number*Number->Number)" -code-creation,Stub,10,0x2a6a4f9183a0,474,"BinaryOpICStub(MUL_ReuseLeft:Number*Number->Number)" -code-creation,Stub,10,0x2a6a4f918580,426,"BinaryOpICStub(MUL:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f918740,446,"BinaryOpICStub(MUL_ReuseLeft:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f918900,426,"BinaryOpICStub(MUL_ReuseRight:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f918ac0,304,"BinaryOpICStub(MUL:Smi*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f918c00,304,"BinaryOpICStub(MUL_ReuseLeft:Smi*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f918d40,470,"BinaryOpICStub(MUL:Smi*Int32->Number)" -code-creation,Stub,10,0x2a6a4f918f20,426,"BinaryOpICStub(MUL:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f9190e0,426,"BinaryOpICStub(MUL_ReuseLeft:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f9192a0,446,"BinaryOpICStub(MUL_ReuseRight:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f919460,232,"BinaryOpICStub(MUL:Smi*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f919560,398,"BinaryOpICStub(MUL:Smi*Smi->Number)" -code-creation,Stub,10,0x2a6a4f919700,398,"BinaryOpICStub(MUL_ReuseLeft:Smi*Smi->Number)" -code-creation,Stub,10,0x2a6a4f9198a0,228,"BinaryOpICStub(MUL:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f9199a0,228,"BinaryOpICStub(MUL_ReuseLeft:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f919aa0,228,"BinaryOpICStub(MUL_ReuseRight:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f919ba0,316,"BinaryOpICStub(SAR_ReuseRight:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f919ce0,316,"BinaryOpICStub(SAR:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f919e20,316,"BinaryOpICStub(SAR_ReuseRight:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f919f60,324,"BinaryOpICStub(SAR:Number*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91a0c0,324,"BinaryOpICStub(SAR_ReuseRight:Number*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91a220,196,"BinaryOpICStub(SAR_ReuseLeft:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91a300,196,"BinaryOpICStub(SAR_ReuseRight:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91a3e0,316,"BinaryOpICStub(SHL:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f91a520,316,"BinaryOpICStub(SHL_ReuseRight:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f91a660,316,"BinaryOpICStub(SHL:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91a7a0,316,"BinaryOpICStub(SHL_ReuseRight:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91a8e0,324,"BinaryOpICStub(SHL_ReuseRight:Number*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91aa40,196,"BinaryOpICStub(SHL:Smi*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f91ab20,196,"BinaryOpICStub(SHL_ReuseLeft:Smi*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f91ac00,196,"BinaryOpICStub(SHL_ReuseRight:Smi*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f91ace0,196,"BinaryOpICStub(SHL:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91adc0,196,"BinaryOpICStub(SHL_ReuseLeft:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91aea0,196,"BinaryOpICStub(SHL_ReuseRight:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91af80,364,"BinaryOpICStub(SHR:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91b100,364,"BinaryOpICStub(SHR_ReuseLeft:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91b280,364,"BinaryOpICStub(SHR_ReuseRight:Int32*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91b400,368,"BinaryOpICStub(SHR:Number*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91b580,368,"BinaryOpICStub(SHR_ReuseLeft:Number*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91b700,518,"BinaryOpICStub(SHR_ReuseRight:Number*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f91b920,244,"BinaryOpICStub(SHR:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91ba20,244,"BinaryOpICStub(SHR_ReuseLeft:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91bb20,244,"BinaryOpICStub(SHR_ReuseRight:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91bc20,348,"BinaryOpICStub(SUB:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f91bd80,380,"BinaryOpICStub(SUB_ReuseLeft:Int32*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f91bf00,498,"BinaryOpICStub(SUB:Int32*Number->Number)" -code-creation,Stub,10,0x2a6a4f91c100,518,"BinaryOpICStub(SUB_ReuseRight:Int32*Number->Number)" -code-creation,Stub,10,0x2a6a4f91c320,320,"BinaryOpICStub(SUB_ReuseLeft:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f91c460,288,"BinaryOpICStub(SUB_ReuseRight:Int32*Smi->Int32)" -code-creation,Stub,10,0x2a6a4f91c580,498,"BinaryOpICStub(SUB:Number*Int32->Number)" -code-creation,Stub,10,0x2a6a4f91c780,522,"BinaryOpICStub(SUB_ReuseLeft:Number*Int32->Number)" -code-creation,Stub,10,0x2a6a4f91c9a0,454,"BinaryOpICStub(SUB:Number*Number->Number)" -code-creation,Stub,10,0x2a6a4f91cb80,474,"BinaryOpICStub(SUB_ReuseLeft:Number*Number->Number)" -code-creation,Stub,10,0x2a6a4f91cd60,474,"BinaryOpICStub(SUB_ReuseRight:Number*Number->Number)" -code-creation,Stub,10,0x2a6a4f91cf40,426,"BinaryOpICStub(SUB:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f91d100,446,"BinaryOpICStub(SUB_ReuseLeft:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f91d2c0,426,"BinaryOpICStub(SUB_ReuseRight:Number*Smi->Number)" -code-creation,Stub,10,0x2a6a4f91d480,272,"BinaryOpICStub(SUB:Smi*Int32->Int32)" -code-creation,Stub,10,0x2a6a4f91d5a0,426,"BinaryOpICStub(SUB:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f91d760,426,"BinaryOpICStub(SUB_ReuseLeft:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f91d920,446,"BinaryOpICStub(SUB_ReuseRight:Smi*Number->Number)" -code-creation,Stub,10,0x2a6a4f91dae0,204,"BinaryOpICStub(SUB:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91dbc0,204,"BinaryOpICStub(SUB_ReuseLeft:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91dca0,204,"BinaryOpICStub(SUB_ReuseRight:Smi*Smi->Smi)" -code-creation,Stub,10,0x2a6a4f91dd80,256,"BinaryOpICStub(MOD:Smi*2->Smi)" -code-creation,Stub,10,0x2a6a4f91de80,256,"BinaryOpICStub(MOD:Smi*4->Smi)" -code-creation,Stub,10,0x2a6a4f91df80,256,"BinaryOpICStub(MOD_ReuseLeft:Smi*4->Smi)" -code-creation,Stub,10,0x2a6a4f91e080,256,"BinaryOpICStub(MOD:Smi*8->Smi)" -code-creation,Stub,10,0x2a6a4f91e180,256,"BinaryOpICStub(MOD_ReuseLeft:Smi*16->Smi)" -code-creation,Stub,10,0x2a6a4f91e280,256,"BinaryOpICStub(MOD:Smi*32->Smi)" -code-creation,Stub,10,0x2a6a4f91e380,264,"BinaryOpICStub(MOD:Smi*2048->Smi)" -code-creation,Stub,2,0x2a6a4f91e4a0,383,"JSEntryStub" -code-creation,Stub,2,0x2a6a4f91e620,383,"JSConstructEntryStub" -code-creation,Builtin,4,0x2a6a4f91e7a0,115,"Illegal" -code-creation,Builtin,4,0x2a6a4f91e820,115,"EmptyFunction" -code-creation,Builtin,4,0x2a6a4f91e8a0,115,"ArrayPush" -code-creation,Builtin,4,0x2a6a4f91e920,115,"ArrayPop" -code-creation,Builtin,4,0x2a6a4f91e9a0,115,"ArrayShift" -code-creation,Builtin,4,0x2a6a4f91ea20,115,"ArrayUnshift" -code-creation,Builtin,4,0x2a6a4f91eaa0,115,"ArraySlice" -code-creation,Builtin,4,0x2a6a4f91eb20,115,"ArraySplice" -code-creation,Builtin,4,0x2a6a4f91eba0,115,"ArrayConcat" -code-creation,Builtin,4,0x2a6a4f91ec20,120,"HandleApiCall" -code-creation,Builtin,4,0x2a6a4f91eca0,120,"HandleApiCallConstruct" -code-creation,Builtin,4,0x2a6a4f91ed20,115,"HandleApiCallAsFunction" -code-creation,Builtin,4,0x2a6a4f91eda0,115,"HandleApiCallAsConstructor" -code-creation,Builtin,4,0x2a6a4f91ee20,115,"StrictModePoisonPill" -code-creation,Builtin,4,0x2a6a4f91eea0,270,"ArgumentsAdaptorTrampoline" -code-creation,Builtin,4,0x2a6a4f91efc0,183,"InOptimizationQueue" -code-creation,Builtin,4,0x2a6a4f91f080,638,"JSConstructStubCountdown" -code-creation,Builtin,4,0x2a6a4f91f300,567,"JSConstructStubGeneric" -code-creation,Builtin,4,0x2a6a4f91f540,546,"JSConstructStubApi" -code-creation,Builtin,4,0x2a6a4f91f780,199,"JSEntryTrampoline" -code-creation,Stub,2,0x2a6a4f91f860,194,"CallConstructStub" -code-creation,Builtin,4,0x2a6a4f91f940,178,"JSConstructEntryTrampoline" -code-creation,Builtin,4,0x2a6a4f91fa00,155,"CompileUnoptimized" -code-creation,Builtin,4,0x2a6a4f91faa0,167,"CompileOptimized" -code-creation,Builtin,4,0x2a6a4f91fb60,167,"CompileOptimizedConcurrent" -code-creation,Builtin,4,0x2a6a4f91fc20,210,"NotifyDeoptimized" -code-creation,Builtin,4,0x2a6a4f91fd00,214,"NotifySoftDeoptimized" -code-creation,Builtin,4,0x2a6a4f91fde0,210,"NotifyLazyDeoptimized" -code-creation,Builtin,4,0x2a6a4f91fec0,189,"NotifyStubFailure" -code-creation,Builtin,4,0x2a6a4f91ff80,189,"NotifyStubFailureSaveDoubles" -code-creation,Builtin,4,0x2a6a4f920040,120,"LoadIC_Miss" -code-creation,Builtin,4,0x2a6a4f9200c0,120,"KeyedLoadIC_Miss" -code-creation,Builtin,4,0x2a6a4f920140,121,"StoreIC_Miss" -code-creation,Builtin,4,0x2a6a4f9201c0,121,"KeyedStoreIC_Miss" -code-creation,Builtin,6,0x2a6a4f920240,131,"LoadIC_Getter_ForDeopt" -code-creation,Builtin,7,0x2a6a4f9202e0,120,"KeyedLoadIC_Initialize" -code-creation,Builtin,7,0x2a6a4f920360,120,"KeyedLoadIC_PreMonomorphic" -code-creation,Stub,2,0x2a6a4f9203e0,972,"NameDictionaryLookupStub" -code-creation,Builtin,7,0x2a6a4f9207c0,1024,"KeyedLoadIC_Generic" -code-creation,Builtin,7,0x2a6a4f920bc0,691,"KeyedLoadIC_String" -code-creation,Builtin,7,0x2a6a4f920e80,188,"KeyedLoadIC_IndexedInterceptor" -code-creation,Builtin,7,0x2a6a4f920f40,307,"KeyedLoadIC_SloppyArguments" -code-creation,Builtin,8,0x2a6a4f921080,133,"StoreIC_Setter_ForDeopt" -code-creation,Builtin,9,0x2a6a4f921120,121,"KeyedStoreIC_Initialize" -code-creation,Builtin,9,0x2a6a4f9211a0,121,"KeyedStoreIC_PreMonomorphic" -code-creation,Stub,2,0x2a6a4f921220,1822,"RecordWriteStub" -code-creation,Stub,2,0x2a6a4f921940,1804,"RecordWriteStub" -code-creation,Stub,2,0x2a6a4f922060,1786,"RecordWriteStub" -code-creation,Stub,2,0x2a6a4f922760,796,"RecordWriteStub" -code-creation,Stub,2,0x2a6a4f922a80,1805,"RecordWriteStub" -code-creation,Builtin,9,0x2a6a4f9231a0,2897,"KeyedStoreIC_Generic" -code-creation,Builtin,9,0x2a6a4f923d00,121,"KeyedStoreIC_Initialize_Strict" -code-creation,Builtin,9,0x2a6a4f923d80,121,"KeyedStoreIC_PreMonomorphic_Strict" -code-creation,Builtin,9,0x2a6a4f923e00,2897,"KeyedStoreIC_Generic_Strict" -code-creation,Stub,2,0x2a6a4f924960,1786,"RecordWriteStub" -code-creation,Builtin,9,0x2a6a4f925060,401,"KeyedStoreIC_SloppyArguments" -code-creation,Builtin,4,0x2a6a4f925200,464,"FunctionCall" -code-creation,Builtin,4,0x2a6a4f9253e0,469,"FunctionApply" -code-creation,Stub,2,0x2a6a4f9255c0,410,"InternalArrayNoArgumentConstructorStub" -code-creation,Stub,2,0x2a6a4f925760,530,"InternalArraySingleArgumentConstructorStub" -code-creation,Stub,2,0x2a6a4f925980,450,"InternalArrayNArgumentsConstructorStub" -code-creation,Stub,2,0x2a6a4f925b60,410,"InternalArrayNoArgumentConstructorStub" -code-creation,Stub,2,0x2a6a4f925d00,530,"InternalArraySingleArgumentConstructorStub" -code-creation,Stub,2,0x2a6a4f925f20,450,"InternalArrayNArgumentsConstructorStub" -code-creation,Stub,2,0x2a6a4f926100,209,"InternalArrayConstructorStub" -code-creation,Builtin,4,0x2a6a4f9261e0,116,"InternalArrayCode" -code-creation,Stub,2,0x2a6a4f926260,574,"ArrayConstructorStub_Any" -code-creation,Builtin,4,0x2a6a4f9264a0,120,"ArrayCode" -code-creation,Builtin,4,0x2a6a4f926520,491,"StringConstructCode" -code-creation,Builtin,4,0x2a6a4f926720,175,"OnStackReplacement" -code-creation,Builtin,4,0x2a6a4f9267e0,113,"InterruptCheck" -code-creation,Builtin,4,0x2a6a4f926860,162,"OsrAfterStackCheck" -code-creation,Builtin,4,0x2a6a4f926920,113,"StackCheck" -code-creation,Builtin,4,0x2a6a4f9269a0,202,"MarkCodeAsExecutedOnce" -code-creation,Builtin,4,0x2a6a4f926a80,193,"MarkCodeAsExecutedTwice" -code-creation,Builtin,4,0x2a6a4f926b60,193,"MakeQuadragenarianCodeYoungAgainOddMarking" -code-creation,Builtin,4,0x2a6a4f926c40,193,"MakeQuadragenarianCodeYoungAgainEvenMarking" -code-creation,Builtin,4,0x2a6a4f926d20,193,"MakeQuinquagenarianCodeYoungAgainOddMarking" -code-creation,Builtin,4,0x2a6a4f926e00,193,"MakeQuinquagenarianCodeYoungAgainEvenMarking" -code-creation,Builtin,4,0x2a6a4f926ee0,193,"MakeSexagenarianCodeYoungAgainOddMarking" -code-creation,Builtin,4,0x2a6a4f926fc0,193,"MakeSexagenarianCodeYoungAgainEvenMarking" -code-creation,Builtin,4,0x2a6a4f9270a0,193,"MakeSeptuagenarianCodeYoungAgainOddMarking" -code-creation,Builtin,4,0x2a6a4f927180,193,"MakeSeptuagenarianCodeYoungAgainEvenMarking" -code-creation,Builtin,4,0x2a6a4f927260,193,"MakeOctogenarianCodeYoungAgainOddMarking" -code-creation,Builtin,4,0x2a6a4f927340,193,"MakeOctogenarianCodeYoungAgainEvenMarking" -code-creation,Builtin,3,0x2a6a4f927420,120,"LoadIC_Slow" -code-creation,Builtin,3,0x2a6a4f9274a0,120,"KeyedLoadIC_Slow" -code-creation,Builtin,3,0x2a6a4f927520,121,"StoreIC_Slow" -code-creation,Builtin,3,0x2a6a4f9275a0,121,"KeyedStoreIC_Slow" -code-creation,Stub,2,0x2a6a4f927620,972,"NameDictionaryLookupStub" -code-creation,Builtin,3,0x2a6a4f927a00,353,"LoadIC_Normal" -code-creation,Stub,2,0x2a6a4f927b80,991,"NameDictionaryLookupStub" -code-creation,Builtin,3,0x2a6a4f927f60,424,"StoreIC_Normal" -code-creation,Builtin,4,0x2a6a4f928120,180,"Return_DebugBreak" -code-creation,Builtin,4,0x2a6a4f9281e0,176,"CallFunctionStub_DebugBreak" -code-creation,Builtin,4,0x2a6a4f9282a0,180,"CallFunctionStub_Recording_DebugBreak" -code-creation,Builtin,4,0x2a6a4f928360,212,"CallConstructStub_DebugBreak" -code-creation,Builtin,4,0x2a6a4f928440,216,"CallConstructStub_Recording_DebugBreak" -code-creation,Builtin,6,0x2a6a4f928520,178,"LoadIC_DebugBreak" -code-creation,Builtin,7,0x2a6a4f9285e0,178,"KeyedLoadIC_DebugBreak" -code-creation,Builtin,8,0x2a6a4f9286a0,180,"StoreIC_DebugBreak" -code-creation,Builtin,9,0x2a6a4f928760,180,"KeyedStoreIC_DebugBreak" -code-creation,Builtin,12,0x2a6a4f928820,176,"CompareNilIC_DebugBreak" -code-creation,Builtin,4,0x2a6a4f9288e0,178,"Slot_DebugBreak" -code-creation,Builtin,4,0x2a6a4f9289a0,97,"PlainReturn_LiveEdit" -code-creation,Builtin,4,0x2a6a4f928a20,137,"FrameDropper_LiveEdit" -code-creation,LoadInitialize,6,0x2a6a4f928ac0,120,"args_count: 0" -code-creation,LoadInitialize,6,0x2a6a4f928b40,120,"args_count: 0" -code-creation,Stub,2,0x2a6a4f928bc0,1792,"RecordWriteStub" -code-creation,Stub,2,0x2a6a4f9292c0,487,"CallConstructStub_Recording" -code-creation,Script,0,0x2a6a4f9294c0,796,"native runtime.js",0x117bdce135c8,~ -code-creation,LoadPreMonomorphic,6,0x2a6a4f9297e0,120,"args_count: 0" -code-creation,LoadPreMonomorphic,6,0x2a6a4f929860,120,"args_count: 0" -code-creation,Stub,12,0x2a6a4f9298e0,148,"CompareNilICStub(NullValue)(None)" -code-creation,Stub,2,0x2a6a4f929980,234,"CallFunctionStub_Args1" -code-creation,Stub,2,0x2a6a4f929a80,234,"CallFunctionStub_Args2" -code-creation,LazyCompile,0,0x2a6a4f929b80,2788,"EQUALS native runtime.js:9:16",0x117bdce118d0,~ -code-creation,LazyCompile,0,0x2a6a4f92a680,504,"STRICT_EQUALS native runtime.js:55:23",0x117bdce11960,~ -code-creation,Stub,2,0x2a6a4f92a880,280,"StringCompareStub" -code-creation,Stub,11,0x2a6a4f92a9a0,170,"CompareICStub" -code-creation,LazyCompile,0,0x2a6a4f92aa60,1444,"COMPARE native runtime.js:66:17",0x117bdce119f0,~ -code-creation,Stub,2,0x2a6a4f92b020,1061,"StringAddStub_CheckBoth" -code-creation,LazyCompile,0,0x2a6a4f92b460,944,"ADD native runtime.js:98:13",0x117bdce11a80,~ -code-creation,LazyCompile,0,0x2a6a4f92b820,432,"SUB native runtime.js:136:13",0x117bdce11c30,~ -code-creation,LazyCompile,0,0x2a6a4f92b9e0,432,"MUL native runtime.js:141:13",0x117bdce11cc0,~ -code-creation,LazyCompile,0,0x2a6a4f92bba0,432,"DIV native runtime.js:146:13",0x117bdce11d50,~ -code-creation,LazyCompile,0,0x2a6a4f92bd60,432,"MOD native runtime.js:151:13",0x117bdce11de0,~ -code-creation,LazyCompile,0,0x2a6a4f92bf20,432,"BIT_OR native runtime.js:156:16",0x117bdce11e70,~ -code-creation,LazyCompile,0,0x2a6a4f92c0e0,620,"BIT_AND native runtime.js:161:17",0x117bdce11f00,~ -code-creation,LazyCompile,0,0x2a6a4f92c360,432,"BIT_XOR native runtime.js:173:17",0x117bdce11f90,~ -code-creation,LazyCompile,0,0x2a6a4f92c520,432,"SHL native runtime.js:178:13",0x117bdce12020,~ -code-creation,LazyCompile,0,0x2a6a4f92c6e0,620,"SAR native runtime.js:183:13",0x117bdce120b0,~ -code-creation,LazyCompile,0,0x2a6a4f92c960,432,"SHR native runtime.js:195:13",0x117bdce12140,~ -code-creation,LazyCompile,0,0x2a6a4f92cb20,324,"DELETE native runtime.js:200:16",0x117bdce121d0,~ -code-creation,Stub,2,0x2a6a4f92cc80,1819,"RecordWriteStub" -code-creation,Stub,2,0x2a6a4f92d3a0,350,"StoreArrayLiteralElementStub" -code-creation,LazyCompile,0,0x2a6a4f92d500,536,"IN native runtime.js:203:12",0x117bdce12260,~ -code-creation,Stub,11,0x2a6a4f92d720,170,"CompareICStub" -code-creation,Stub,13,0x2a6a4f92d7e0,148,"ToBooleanStub(None)" -code-creation,LazyCompile,0,0x2a6a4f92d880,880,"INSTANCE_OF native runtime.js:210:21",0x117bdce122f0,~ -code-creation,LazyCompile,0,0x2a6a4f92dc00,304,"FILTER_KEY native runtime.js:228:20",0x117bdce12380,~ -code-creation,Stub,2,0x2a6a4f92dd40,514,"ArgumentsAccessStub_NewSloppyFast" -code-creation,LazyCompile,0,0x2a6a4f92df60,504,"CALL_NON_FUNCTION native runtime.js:233:27",0x117bdce12410,~ -code-creation,LazyCompile,0,0x2a6a4f92e160,504,"CALL_NON_FUNCTION_AS_CONSTRUCTOR native runtime.js:240:42",0x117bdce124a0,~ -code-creation,Stub,2,0x2a6a4f92e360,200,"ArgumentsAccessStub_ReadElement" -code-creation,LazyCompile,0,0x2a6a4f92e440,336,"CALL_FUNCTION_PROXY native runtime.js:247:29",0x117bdce12530,~ -code-creation,LazyCompile,0,0x2a6a4f92e5a0,308,"CALL_FUNCTION_PROXY_AS_CONSTRUCTOR native runtime.js:253:44",0x117bdce125c0,~ -code-creation,LazyCompile,0,0x2a6a4f92e6e0,244,"TO_OBJECT native runtime.js:283:19",0x117bdce12770,~ -code-creation,LazyCompile,0,0x2a6a4f92e7e0,244,"TO_NUMBER native runtime.js:286:19",0x117bdce12800,~ -code-creation,LazyCompile,0,0x2a6a4f92e8e0,244,"TO_STRING native runtime.js:289:19",0x117bdce12890,~ -code-creation,Stub,2,0x2a6a4f92e9e0,182,"DoubleToIStub" -code-creation,Stub,2,0x2a6a4f92eaa0,491,"NumberToStringStub" -code-creation,LazyCompile,0,0x2a6a4f92eca0,808,"STRING_ADD_LEFT native runtime.js:111:25",0x117bdce11b10,~ -code-creation,LazyCompile,0,0x2a6a4f92efe0,820,"STRING_ADD_RIGHT native runtime.js:123:26",0x117bdce11ba0,~ -code-creation,Stub,11,0x2a6a4f92f320,170,"CompareICStub" -code-creation,Stub,11,0x2a6a4f92f3e0,170,"CompareICStub" -code-creation,Stub,11,0x2a6a4f92f4a0,170,"CompareICStub" -code-creation,LazyCompile,0,0x2a6a4f92f560,1456,"APPLY_PREPARE native runtime.js:258:23",0x117bdce12650,~ -code-creation,LazyCompile,0,0x2a6a4f92fb20,312,"APPLY_OVERFLOW native runtime.js:280:24",0x117bdce126e0,~ -code-creation,Stub,2,0x2a6a4f92fc60,228,"CallFunctionStub_Args0" -code-creation,Stub,2,0x2a6a4f92fd60,234,"CallFunctionStub_Args12" -code-creation,Stub,2,0x2a6a4f92fe60,237,"CallFunctionStub_Args38" -code-creation,Stub,2,0x2a6a4f92ff60,234,"CallFunctionStub_Args3" -code-creation,Script,0,0x2a6a4f930060,2020,"native v8natives.js",0x117bdce19de0,~ -code-creation,Stub,2,0x2a6a4f930860,234,"CallFunctionStub_Args10" -code-creation,LazyCompile,0,0x2a6a4f930960,708,"SetUpGlobal native v8natives.js:113:21",0x117bdce160a8,~ -code-creation,LazyCompile,0,0x2a6a4f930c40,700,"InstallFunctions native v8natives.js:4:26",0x117bdce15b08,~ -code-creation,Stub,11,0x2a6a4f930f00,192,"CompareICStub" -code-creation,Stub,10,0x2a6a4f930fc0,196,"BinaryOpICStub(SAR:Smi*Smi->Smi)" -code-creation,Stub,11,0x2a6a4f9310a0,192,"CompareICStub" -code-creation,Stub,2,0x2a6a4f931160,236,"KeyedLoadElementStub" -code-creation,KeyedLoadIC,7,0x2a6a4f931260,130,"" -code-creation,Stub,10,0x2a6a4f931300,204,"BinaryOpICStub(ADD:Smi*Smi->Smi)" -code-creation,Stub,3,0x2a6a4f9313e0,112,"LoadFieldStub" -code-creation,LoadIC,6,0x2a6a4f931460,132,"length" -code-creation,Stub,2,0x2a6a4f931500,258,"ToNumberStub" -code-creation,LazyCompile,0,0x2a6a4f931620,1040,"SetUpLockedPrototype native v8natives.js:45:30",0x117bdce15d48,~ -code-creation,Stub,13,0x2a6a4f931a40,188,"ToBooleanStub(SpecObject)" -code-creation,Stub,10,0x2a6a4f931b00,204,"BinaryOpICStub(ADD_ReuseLeft:Smi*Smi->Smi)" -code-creation,LoadIC,6,0x2a6a4f931be0,132,"length" -code-creation,LoadIC,6,0x2a6a4f931c80,132,"length" -code-creation,Stub,2,0x2a6a4f931d20,237,"CallFunctionStub_Args20" -code-creation,Stub,2,0x2a6a4f931e20,234,"CallFunctionStub_Args4" -code-creation,Stub,2,0x2a6a4f931f20,237,"CallFunctionStub_Args30" -code-creation,LazyCompile,0,0x2a6a4f932020,1656,"SetUpObject native v8natives.js:1019:21",0x117bdce17e78,~ -code-creation,LazyCompile,0,0x2a6a4f9326a0,492,"ObjectConstructor native v8natives.js:1010:27",0x117bdce17de8,~ -code-creation,LazyCompile,0,0x2a6a4f9326a0,492,"ObjectConstructor native v8natives.js:1010:27",0x117bdce17de8,~ -code-creation,LoadIC,6,0x2a6a4f9328a0,132,"length" -code-creation,LoadIC,6,0x2a6a4f932940,132,"length" -code-creation,LazyCompile,0,0x2a6a4f9329e0,368,"InstallGetterSetter native v8natives.js:24:29",0x117bdce15c28,~ -code-creation,LazyCompile,0,0x2a6a4f932b60,660,"SetUpBoolean native v8natives.js:1081:22",0x117bdce180b8,~ -code-creation,LazyCompile,0,0x2a6a4f932e00,440,"BooleanConstructor native v8natives.js:1058:28",0x117bdce17f08,~ -code-creation,LazyCompile,0,0x2a6a4f932e00,440,"BooleanConstructor native v8natives.js:1058:28",0x117bdce17f08,~ -code-creation,LazyCompile,0,0x2a6a4f932fc0,592,"ToBoolean native runtime.js:299:19",0x117bdce129b0,~ -code-creation,Stub,2,0x2a6a4f933220,608,"MathPowStub" -code-creation,Stub,2,0x2a6a4f933480,237,"CallFunctionStub_Args16" -code-creation,LazyCompile,0,0x2a6a4f933580,1556,"SetUpNumber native v8natives.js:1200:21",0x117bdce18778,~ -code-creation,LazyCompile,0,0x2a6a4f933ba0,472,"NumberConstructor native v8natives.js:1092:27",0x117bdce18148,~ -code-creation,LazyCompile,0,0x2a6a4f933ba0,472,"NumberConstructor native v8natives.js:1092:27",0x117bdce18148,~ -code-creation,Stub,11,0x2a6a4f933d80,184,"CompareICStub" -code-creation,LazyCompile,0,0x2a6a4f933e40,748,"ToNumber native runtime.js:306:18",0x117bdce12a40,~ -code-creation,LazyCompile,0,0x2a6a4f934140,644,"InstallConstants native v8natives.js:33:26",0x117bdce15cb8,~ -code-creation,LoadIC,6,0x2a6a4f9343e0,132,"length" -code-creation,LazyCompile,0,0x2a6a4f934480,560,"SetUpFunction native v8natives.js:1325:23",0x117bdce18ad8,~ -code-creation,Stub,2,0x2a6a4f9346c0,350,"FastNewContextStub" -code-creation,Stub,2,0x2a6a4f934820,1789,"RecordWriteStub" -code-creation,LazyCompile,0,0x2a6a4f934f20,552,"FunctionConstructor native v8natives.js:1318:29",0x117bdce18a48,~ -code-creation,LazyCompile,0,0x2a6a4f934f20,552,"FunctionConstructor native v8natives.js:1318:29",0x117bdce18a48,~ -code-creation,Script,0,0x2a6a4f935160,368,"native array.js",0x117bdce1ee00,~ -code-creation,Stub,2,0x2a6a4f9352e0,1834,"RecordWriteStub" -code-creation,Stub,2,0x2a6a4f935a20,2680,"RecordWriteStub" -code-creation,Stub,2,0x2a6a4f9364a0,2710,"RecordWriteStub" -code-creation,Stub,2,0x2a6a4f936f40,758,"FastNewClosureStub" -code-creation,Stub,2,0x2a6a4f937240,524,"CallFunctionStub_Args2_Recording" -code-creation,Stub,2,0x2a6a4f937460,524,"CallFunctionStub_Args3_Recording" -code-creation,Stub,2,0x2a6a4f937680,237,"CallFunctionStub_Args42" -code-creation,Stub,2,0x2a6a4f937780,234,"CallFunctionStub_Args6" -code-creation,LazyCompile,0,0x2a6a4f937880,3808,"SetUpArray native array.js:1166:20",0x117bdce1ea58,~ -code-creation,Stub,2,0x2a6a4f938760,355,"CallFunctionStub_Args1" -code-creation,LazyCompile,0,0x2a6a4f9388e0,372,"SetUpArray.b native array.js:1173:15",0x117bdce204c8,~ -code-creation,LazyCompile,0,0x2a6a4f938a60,636,"hasOwnProperty native v8natives.js:140:30",0x117bdce162e8,~ -code-creation,Stub,13,0x2a6a4f938ce0,176,"ToBooleanStub(Bool)" -code-creation,LazyCompile,0,0x2a6a4f938da0,296,"ToName native runtime.js:342:16",0x117bdce12c80,~ -code-creation,LazyCompile,0,0x2a6a4f938ee0,792,"ToString native runtime.js:327:18",0x117bdce12b60,~ -code-creation,Stub,3,0x2a6a4f939200,147,"hasOwnProperty" -code-creation,LoadIC,6,0x2a6a4f9392a0,132,"hasOwnProperty" -code-creation,Stub,3,0x2a6a4f939340,114,"ToName" -code-creation,LoadIC,6,0x2a6a4f9393c0,132,"ToName" -code-creation,Stub,3,0x2a6a4f939460,114,"ToString" -code-creation,LoadIC,6,0x2a6a4f9394e0,132,"ToString" -code-creation,Stub,3,0x2a6a4f939580,107,"push" -code-creation,KeyedLoadIC,7,0x2a6a4f939600,152,"push" -code-creation,Stub,3,0x2a6a4f9396a0,107,"concat" -code-creation,Stub,6,0x2a6a4f939720,170,"FunctionPrototypeStub" -code-creation,LoadIC,6,0x2a6a4f9397e0,132,"length" -code-creation,LoadIC,6,0x2a6a4f939880,132,"length" -code-creation,LoadPolymorphicIC,6,0x2a6a4f939920,151,"length" -code-creation,Stub,2,0x2a6a4f9399c0,526,"FastCloneShallowArrayStub" -code-creation,Script,0,0x2a6a4f939be0,636,"native string.js",0x117bdce22cc8,~ -code-creation,Stub,2,0x2a6a4f939e60,237,"CallFunctionStub_Args72" -code-creation,LazyCompile,0,0x2a6a4f939f60,1892,"SetUpString native string.js:617:21",0x117bdce227f8,~ -code-creation,LazyCompile,0,0x2a6a4f93a6e0,544,"StringConstructor native string.js:2:27",0x117bdce20f38,~ -code-creation,LazyCompile,0,0x2a6a4f93a6e0,544,"StringConstructor native string.js:2:27",0x117bdce20f38,~ -code-creation,Script,0,0x2a6a4f93a900,364,"native uri.js",0x117bdce25258,~ -code-creation,LazyCompile,0,0x2a6a4f93aa80,520,"SetUpUri native uri.js:312:18",0x117bdce25010,~ -code-creation,Script,0,0x2a6a4f93aca0,996,"native math.js",0x117bdce26c38,~ -code-creation,LazyCompile,0,0x2a6a4f93b0a0,184,"MathConstructor native math.js:4:25",0x117bdce25d20,~ -code-creation,LazyCompile,0,0x2a6a4f93b160,1700,"SetUpMath native math.js:153:19",0x117bdce268f0,~ -code-creation,LoadIC,6,0x2a6a4f93b820,132,"length" -code-creation,LoadIC,6,0x2a6a4f93b8c0,132,"length" -code-creation,Stub,2,0x2a6a4f93b960,234,"CallFunctionStub_Args7" -code-creation,Stub,2,0x2a6a4f93ba60,234,"CallFunctionStub_Args14" -code-creation,Stub,2,0x2a6a4f93bb60,234,"CallFunctionStub_Args5" -code-creation,Stub,2,0x2a6a4f93bc60,237,"CallFunctionStub_Args32" -code-creation,StoreInitialize,8,0x2a6a4f93bd60,121,"args_count: 0" -code-creation,Script,0,0x2a6a4f93bde0,3364,"native messages.js",0x117bdce2cc88,~ -code-creation,LazyCompile,0,0x2a6a4f93cb20,264," native messages.js:241:25",0x117bdce2cb80,~ -code-creation,LazyCompile,0,0x2a6a4f93cb20,264," native messages.js:241:25",0x117bdce2cb80,~ -code-creation,LoadIC,6,0x2a6a4f93cc40,132,"length" -code-creation,LoadMegamorphic,6,0x2a6a4f93cce0,343,"args_count: 0" -code-creation,Stub,2,0x2a6a4f93ce40,524,"CallFunctionStub_Args1_Recording" -code-creation,LazyCompile,0,0x2a6a4f93d060,600,"SetUpError native messages.js:832:20",0x117bdce29710,~ -code-creation,LazyCompile,0,0x2a6a4f93d2c0,944,"SetUpError.a native messages.js:833:15",0x117bdce32370,~ -code-creation,Stub,2,0x2a6a4f93d680,1157,"BinaryOpWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -code-creation,Stub,10,0x2a6a4f93db20,111,"BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -code-creation,Stub,10,0x2a6a4f93dba0,111,"BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -code-creation,Stub,11,0x2a6a4f93dc20,211,"CompareICStub" -code-creation,LazyCompile,0,0x2a6a4f93dd00,184,"d native messages.js:838:15",0x117bdce32868,~ -code-creation,LazyCompile,0,0x2a6a4f93ddc0,540," native messages.js:848:20",0x117bdce328f8,~ -code-creation,LazyCompile,0,0x2a6a4f93ddc0,540," native messages.js:848:20",0x117bdce328f8,~ -code-creation,LoadIC,6,0x2a6a4f93dfe0,132,"name" -code-creation,Stub,3,0x2a6a4f93e080,114,"global" -code-creation,LoadIC,6,0x2a6a4f93e100,132,"global" -code-creation,Stub,3,0x2a6a4f93e1a0,114,"builtins" -code-creation,LoadIC,6,0x2a6a4f93e220,132,"builtins" -code-creation,Stub,2,0x2a6a4f93e2c0,382,"FastNewContextStub" -code-creation,LazyCompile,0,0x2a6a4f93e440,804,"captureStackTrace native messages.js:808:27",0x117bdce29680,~ -code-creation,Stub,13,0x2a6a4f93e780,164,"ToBooleanStub(Undefined)" -code-creation,LazyCompile,0,0x2a6a4f93ddc0,540," native messages.js:848:20",0x117bdce328f8,~ -code-creation,Stub,3,0x2a6a4f93e840,114,"$Error" -code-creation,LoadIC,6,0x2a6a4f93e8c0,132,"$Error" -code-creation,Stub,3,0x2a6a4f93e960,114,"captureStackTrace" -code-creation,LoadIC,6,0x2a6a4f93e9e0,132,"captureStackTrace" -code-creation,Stub,3,0x2a6a4f93ea80,171,symbol(hash 253492a7) -code-creation,LoadIC,6,0x2a6a4f93eb40,132,"stackTraceLimit" -code-creation,LazyCompile,0,0x2a6a4f93ddc0,540," native messages.js:848:20",0x117bdce328f8,~ -code-creation,LazyCompile,0,0x2a6a4f93ddc0,540," native messages.js:848:20",0x117bdce328f8,~ -code-creation,LazyCompile,0,0x2a6a4f93ddc0,540," native messages.js:848:20",0x117bdce328f8,~ -code-creation,LazyCompile,0,0x2a6a4f93ddc0,540," native messages.js:848:20",0x117bdce328f8,~ -code-creation,LazyCompile,0,0x2a6a4f93ddc0,540," native messages.js:848:20",0x117bdce328f8,~ -code-creation,StorePreMonomorphic,8,0x2a6a4f93ebe0,121,"args_count: 0" -code-creation,Stub,12,0x2a6a4f93ec60,172,"CompareNilICStub(NullValue)(Undefined)" -code-creation,LazyCompile,0,0x2a6a4f93ed20,560,"SetUpStackOverflowBoilerplate native messages.js:922:39",0x117bdce29950,~ -code-creation,LazyCompile,0,0x2a6a4f93ef60,268,"MakeRangeError native messages.js:268:24",0x117bdce27f70,~ -code-creation,LazyCompile,0,0x2a6a4f93f080,376,"MakeGenericError native messages.js:234:26",0x117bdce27ca0,~ -code-creation,LazyCompile,0,0x2a6a4f93f200,348,"FormatMessage native messages.js:244:23",0x117bdce27d30,~ -code-creation,LazyCompile,0,0x2a6a4f93f360,2248,"FormatString native messages.js:152:22",0x117bdce279d0, -code-creation,Stub,10,0x2a6a4f93fc40,111,"BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -code-creation,LoadIC,6,0x2a6a4f93fcc0,132,"length" -code-creation,Stub,3,0x2a6a4f93fd60,171,symbol(hash 253492a7) -code-creation,LoadPolymorphicIC,6,0x2a6a4f93fe20,151,"stackTraceLimit" -code-creation,Stub,10,0x2a6a4f93fec0,111,"BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -code-creation,Stub,10,0x2a6a4f93ff40,111,"BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -code-creation,Script,0,0x2a6a4f93ffc0,360,"native apinatives.js",0x117bdce33978,~ -code-creation,Script,0,0x2a6a4f940140,956,"native date.js",0x117bdce36948,~ -code-creation,Stub,2,0x2a6a4f940500,237,"CallFunctionStub_Args92" -code-creation,LazyCompile,0,0x2a6a4f940600,2300,"SetUpDate native date.js:488:19",0x117bdce362b0,~ -code-creation,Stub,2,0x2a6a4f940f00,349,"CallFunctionStub_Args0" -code-creation,Stub,11,0x2a6a4f941060,170,"CompareICStub" -code-creation,LazyCompile,0,0x2a6a4f941120,2616,"DateConstructor native date.js:61:25",0x117bdce34180,~ -code-creation,LazyCompile,0,0x2a6a4f941120,2616,"DateConstructor native date.js:61:25",0x117bdce34180,~ -code-creation,Script,0,0x2a6a4f941b60,360,"native json.js",0x117bdce390e8,~ -code-creation,LazyCompile,0,0x2a6a4f941ce0,392,"SetUpJSON native json.js:192:19",0x117bdce38ed0,~ -code-creation,Script,0,0x2a6a4f941e80,584,"native regexp.js",0x117bdce3a130,~ -code-creation,Stub,2,0x2a6a4f9420e0,234,"CallFunctionStub_Args8" -code-creation,LazyCompile,0,0x2a6a4f9421e0,2392,"SetUpRegExp native regexp.js:265:21",0x117bdce39ee8,~ -code-creation,LazyCompile,0,0x2a6a4f942b40,472,"RegExpConstructor native regexp.js:46:27",0x117bdce39708,~ -code-creation,LazyCompile,0,0x2a6a4f942b40,472,"RegExpConstructor native regexp.js:46:27",0x117bdce39708,~ -code-creation,LazyCompile,0,0x2a6a4f942d20,940,"ToPrimitive native runtime.js:292:21",0x117bdce12920,~ -code-creation,Stub,2,0x2a6a4f9430e0,188,"DoubleToIStub" -code-creation,Stub,2,0x2a6a4f9431a0,1324,"BinaryOpWithAllocationSiteStub(ADD_CreateAllocationMementos:String*Smi->String)" -code-creation,Stub,10,0x2a6a4f9436e0,111,"BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*Smi->String)" -code-creation,Stub,10,0x2a6a4f943760,111,"BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*Smi->String)" -code-creation,LazyCompile,0,0x2a6a4f9437e0,272,"RegExpMakeCaptureGetter native regexp.js:241:33",0x117bdce39e58,~ -code-creation,Stub,3,0x2a6a4f943900,114,"$RegExp" -code-creation,LoadIC,6,0x2a6a4f943980,132,"$RegExp" -code-creation,Stub,3,0x2a6a4f943a20,114,"RegExpMakeCaptureGetter" -code-creation,LoadIC,6,0x2a6a4f943aa0,132,"RegExpMakeCaptureGetter" -code-creation,Script,0,0x2a6a4f943b40,368,"native arraybuffer.js",0x117bdce3b7a8,~ -code-creation,LazyCompile,0,0x2a6a4f943cc0,888,"SetUpArrayBuffer native arraybuffer.js:53:26",0x117bdce3b650,~ -code-creation,LazyCompile,0,0x2a6a4f944040,456,"ArrayBufferConstructor native arraybuffer.js:4:32",0x117bdce3b410,~ -code-creation,LazyCompile,0,0x2a6a4f944040,456,"ArrayBufferConstructor native arraybuffer.js:4:32",0x117bdce3b410,~ -code-creation,LazyCompile,0,0x2a6a4f944220,304,"InstallGetter native v8natives.js:18:23",0x117bdce15b98,~ -code-creation,Script,0,0x2a6a4f944360,1436,"native typedarray.js",0x117bdce3e780,~ -code-creation,LazyCompile,0,0x2a6a4f944900,1108,"SetupTypedArray native typedarray.js:867:25",0x117bdce3d5d8,~ -code-creation,LazyCompile,0,0x2a6a4f944d60,884,"Uint8ArrayConstructor native typedarray.js:71:31",0x117bdce3bec8,~ -code-creation,LazyCompile,0,0x2a6a4f944d60,884,"Uint8ArrayConstructor native typedarray.js:71:31",0x117bdce3bec8,~ -code-creation,Stub,2,0x2a6a4f9450e0,370,"FastNewContextStub" -code-creation,Stub,2,0x2a6a4f945260,758,"FastNewClosureStub" -code-creation,LazyCompile,0,0x2a6a4f945560,324,"CreateSubArray native typedarray.js:755:24",0x117bdce3d398,~ -code-creation,LazyCompile,0,0x2a6a4f9456c0,884,"Int8ArrayConstructor native typedarray.js:153:30",0x117bdce3c108,~ -code-creation,LazyCompile,0,0x2a6a4f9456c0,884,"Int8ArrayConstructor native typedarray.js:153:30",0x117bdce3c108,~ -code-creation,Stub,3,0x2a6a4f945a40,114,"$Object" -code-creation,LoadIC,6,0x2a6a4f945ac0,132,"$Object" -code-creation,Stub,3,0x2a6a4f945b60,114,"InstallGetter" -code-creation,LoadIC,6,0x2a6a4f945be0,132,"InstallGetter" -code-creation,Stub,3,0x2a6a4f945c80,114,"TypedArrayGetBuffer" -code-creation,LoadIC,6,0x2a6a4f945d00,132,"TypedArrayGetBuffer" -code-creation,Stub,3,0x2a6a4f945da0,114,"TypedArrayGetByteOffset" -code-creation,LoadIC,6,0x2a6a4f945e20,132,"TypedArrayGetByteOffset" -code-creation,Stub,3,0x2a6a4f945ec0,114,"TypedArrayGetByteLength" -code-creation,LoadIC,6,0x2a6a4f945f40,132,"TypedArrayGetByteLength" -code-creation,Stub,3,0x2a6a4f945fe0,114,"TypedArrayGetLength" -code-creation,LoadIC,6,0x2a6a4f946060,132,"TypedArrayGetLength" -code-creation,Stub,3,0x2a6a4f946100,114,"InstallFunctions" -code-creation,LoadIC,6,0x2a6a4f946180,132,"InstallFunctions" -code-creation,Stub,3,0x2a6a4f946220,114,"$Array" -code-creation,LoadIC,6,0x2a6a4f9462a0,132,"$Array" -code-creation,Stub,3,0x2a6a4f946340,114,"CreateSubArray" -code-creation,LoadIC,6,0x2a6a4f9463c0,132,"CreateSubArray" -code-creation,Stub,3,0x2a6a4f946460,114,"TypedArraySet" -code-creation,LoadIC,6,0x2a6a4f9464e0,132,"TypedArraySet" -code-creation,LazyCompile,0,0x2a6a4f946580,884,"Uint16ArrayConstructor native typedarray.js:235:32",0x117bdce3c348,~ -code-creation,LazyCompile,0,0x2a6a4f946580,884,"Uint16ArrayConstructor native typedarray.js:235:32",0x117bdce3c348,~ -code-creation,LazyCompile,0,0x2a6a4f946900,884,"Int16ArrayConstructor native typedarray.js:317:31",0x117bdce3c588,~ -code-creation,LazyCompile,0,0x2a6a4f946900,884,"Int16ArrayConstructor native typedarray.js:317:31",0x117bdce3c588,~ -code-creation,LazyCompile,0,0x2a6a4f946c80,884,"Uint32ArrayConstructor native typedarray.js:399:32",0x117bdce3c7c8,~ -code-creation,LazyCompile,0,0x2a6a4f946c80,884,"Uint32ArrayConstructor native typedarray.js:399:32",0x117bdce3c7c8,~ -code-creation,LazyCompile,0,0x2a6a4f947000,884,"Int32ArrayConstructor native typedarray.js:481:31",0x117bdce3ca08,~ -code-creation,LazyCompile,0,0x2a6a4f947000,884,"Int32ArrayConstructor native typedarray.js:481:31",0x117bdce3ca08,~ -code-creation,LazyCompile,0,0x2a6a4f947380,884,"Float32ArrayConstructor native typedarray.js:563:33",0x117bdce3cc48,~ -code-creation,LazyCompile,0,0x2a6a4f947380,884,"Float32ArrayConstructor native typedarray.js:563:33",0x117bdce3cc48,~ -code-creation,LazyCompile,0,0x2a6a4f947700,884,"Float64ArrayConstructor native typedarray.js:645:33",0x117bdce3ce88,~ -code-creation,LazyCompile,0,0x2a6a4f947700,884,"Float64ArrayConstructor native typedarray.js:645:33",0x117bdce3ce88,~ -code-creation,LazyCompile,0,0x2a6a4f947a80,884,"Uint8ClampedArrayConstructor native typedarray.js:727:38",0x117bdce3d0c8,~ -code-creation,LazyCompile,0,0x2a6a4f947a80,884,"Uint8ClampedArrayConstructor native typedarray.js:727:38",0x117bdce3d0c8,~ -code-creation,LazyCompile,0,0x2a6a4f947e00,1448,"SetupDataView native typedarray.js:1167:23",0x117bdce3e238,~ -code-creation,LazyCompile,0,0x2a6a4f9483c0,1436,"DataViewConstructor native typedarray.js:907:29",0x117bdce3d668,~ -code-creation,LazyCompile,0,0x2a6a4f9483c0,1436,"DataViewConstructor native typedarray.js:907:29",0x117bdce3d668,~ -code-creation,Script,0,0x2a6a4f948960,560,"native object-observe.js",0x117bdce43b40,~ -code-creation,LazyCompile,0,0x2a6a4f948ba0,524,"TypeMapCreateFromList native object-observe.js:80:31",0x117bdce41ec8,~ -code-creation,LazyCompile,0,0x2a6a4f948dc0,240,"TypeMapCreate native object-observe.js:71:23",0x117bdce41d18,~ -code-creation,LazyCompile,0,0x2a6a4f948ec0,272,"nullProtoObject native object-observe.js:68:25",0x117bdce41c88,~ -code-creation,LazyCompile,0,0x2a6a4f948fe0,268,"TypeMapAddType native object-observe.js:74:24",0x117bdce41da8,~ -code-creation,LoadIC,6,0x2a6a4f949100,132,"length" -code-creation,Stub,3,0x2a6a4f9491a0,114,"TypeMapAddType" -code-creation,LoadIC,6,0x2a6a4f949220,132,"TypeMapAddType" -code-creation,LazyCompile,0,0x2a6a4f9492c0,836,"SetupObjectObserve native object-observe.js:456:28",0x117bdce43668,~ -code-creation,Stub,2,0x2a6a4f949620,1831,"RecordWriteStub" -code-creation,StoreInitialize,8,0x2a6a4f949d60,121,"args_count: 0" -code-creation,Stub,2,0x2a6a4f949de0,524,"CallFunctionStub_Args4_Recording" -code-creation,Stub,2,0x2a6a4f94a000,355,"CallFunctionStub_Args3" -code-creation,Function,0,0x2a6a4f94a180,12588," native i18n.js:2:71",0x117bdce48da8,~ -code-creation,Stub,2,0x2a6a4f94d2c0,518,"CallFunctionStub_Args0_Recording" -code-creation,Script,0,0x2a6a4f94d4e0,444,"native i18n.js",0x117bdce48e90,~ -code-creation,StorePreMonomorphic,8,0x2a6a4f94d6a0,121,"args_count: 0" -code-creation,LazyCompile,0,0x2a6a4f94d720,612,"addBoundMethod native i18n.js:112:24",0x117bdce45e18,~ -code-creation,LazyCompile,0,0x2a6a4f94d9a0,1280,"defineProperty native v8natives.js:831:30",0x117bdce17698,~ -code-creation,LazyCompile,0,0x2a6a4f94dea0,2216,"ToPropertyDescriptor native v8natives.js:270:30",0x117bdce16ac8,~ -code-creation,LazyCompile,0,0x2a6a4f94e760,516,"PropertyDescriptor native v8natives.js:319:28",0x117bdce16be8,~ -code-creation,LazyCompile,0,0x2a6a4f94e980,236,"$Array.writable_ native v8natives.js:360:25",0x117bdce19518,~ -code-creation,LoadIC,6,0x2a6a4f94ea80,132,"ToName" -code-creation,LazyCompile,0,0x2a6a4f94eb20,236,"$Array.get_ native v8natives.js:380:27",0x117bdce19878,~ -code-creation,Stub,11,0x2a6a4f94ec20,211,"CompareICStub" -code-creation,LazyCompile,0,0x2a6a4f94ed00,236,"$Array.set_ native v8natives.js:390:18",0x117bdce19a28,~ -code-creation,LazyCompile,0,0x2a6a4f94ee00,320,"IsInconsistentDescriptor native v8natives.js:229:34",0x117bdce16918,~ -code-creation,LazyCompile,0,0x2a6a4f94ef40,380,"IsAccessorDescriptor native v8natives.js:217:30",0x117bdce16768,~ -code-creation,LazyCompile,0,0x2a6a4f94f0c0,208,"$Array.set_ native v8natives.js:397:21",0x117bdce19b48,~ -code-creation,LazyCompile,0,0x2a6a4f94f1a0,380,"IsDataDescriptor native v8natives.js:221:26",0x117bdce167f8,~ -code-creation,LazyCompile,0,0x2a6a4f94f320,208,"$Array.enumerable_ native v8natives.js:357:20",0x117bdce19488,~ -code-creation,LazyCompile,0,0x2a6a4f94f400,208,"$Array.configurable_ native v8natives.js:377:23",0x117bdce197e8,~ -code-creation,LazyCompile,0,0x2a6a4f94f4e0,596,"DefineOwnProperty native v8natives.js:707:27",0x117bdce17218,~ -code-creation,LazyCompile,0,0x2a6a4f94f740,7056,"DefineObjectProperty native v8natives.js:495:30",0x117bdce170f8,~ -code-creation,LazyCompile,0,0x2a6a4f9512e0,776,"ToObject native runtime.js:345:18",0x117bdce12d10,~ -code-creation,Stub,12,0x2a6a4f951600,188,"CompareNilICStub(NullValue)(MonomorphicMap)" -code-creation,Stub,12,0x2a6a4f9516c0,188,"CompareNilICStub(NullValue)(MonomorphicMap)" -code-creation,Stub,11,0x2a6a4f951780,643,"CompareICStub" -code-creation,LazyCompile,0,0x2a6a4f951a20,796,"ConvertDescriptorArrayToDescriptor native v8natives.js:410:44",0x117bdce16c78,~ -code-creation,LazyCompile,0,0x2a6a4f951d40,208,"$Array.writable_ native v8natives.js:367:25",0x117bdce19638,~ -code-creation,LazyCompile,0,0x2a6a4f951e20,208,"$Array.writable_ native v8natives.js:364:24",0x117bdce195a8,~ -code-creation,Stub,10,0x2a6a4f951f00,188,"BinaryOpICStub(BIT_OR:Smi*Smi->Smi)" -code-creation,LazyCompile,0,0x2a6a4f951fc0,208,"$Array.get_ native v8natives.js:384:27",0x117bdce19908,~ -code-creation,LazyCompile,0,0x2a6a4f9520a0,208,"$Array.get_ native v8natives.js:387:26",0x117bdce19998,~ -code-creation,Stub,3,0x2a6a4f952180,148,"hasValue" -code-creation,LoadIC,6,0x2a6a4f952220,132,"hasValue" -code-creation,Stub,3,0x2a6a4f9522c0,112,"LoadFieldStub" -code-creation,LoadIC,6,0x2a6a4f952340,132,"hasValue_" -code-creation,Stub,3,0x2a6a4f9523e0,148,"hasWritable" -code-creation,LoadIC,6,0x2a6a4f952480,132,"hasWritable" -code-creation,Stub,3,0x2a6a4f952520,112,"LoadFieldStub" -code-creation,LoadIC,6,0x2a6a4f9525a0,132,"hasWritable_" -code-creation,LazyCompile,0,0x2a6a4f952640,404,"IsGenericDescriptor native v8natives.js:225:29",0x117bdce16888,~ -code-creation,Stub,3,0x2a6a4f9527e0,148,"hasGetter" -code-creation,LoadIC,6,0x2a6a4f952880,132,"hasGetter" -code-creation,Stub,3,0x2a6a4f952920,112,"LoadFieldStub" -code-creation,LoadIC,6,0x2a6a4f9529a0,132,"hasGetter_" -code-creation,LazyCompile,0,0x2a6a4f952a40,208,"$Array.set_ native v8natives.js:394:18",0x117bdce19ab8,~ -code-creation,LazyCompile,0,0x2a6a4f952b20,208," native v8natives.js:407:21",0x117bdce19cf8,~ -code-creation,Stub,3,0x2a6a4f952c00,107,"defineProperty" -code-creation,LoadIC,6,0x2a6a4f952c80,132,"defineProperty" -code-creation,Stub,2,0x2a6a4f952d20,1792,"RecordWriteStub" -code-creation,Stub,3,0x2a6a4f953420,155,"get" -code-creation,StoreIC,8,0x2a6a4f9534c0,133,"get" -code-creation,Stub,3,0x2a6a4f953560,114,"ToPropertyDescriptor" -code-creation,LoadIC,6,0x2a6a4f9535e0,132,"ToPropertyDescriptor" -code-creation,Stub,3,0x2a6a4f953680,114,"PropertyDescriptor" -code-creation,LoadIC,6,0x2a6a4f953700,132,"PropertyDescriptor" -code-creation,Stub,3,0x2a6a4f9537a0,281,"value_" -code-creation,StoreIC,8,0x2a6a4f9538c0,133,"value_" -code-creation,Stub,3,0x2a6a4f953960,281,"hasValue_" -code-creation,StoreIC,8,0x2a6a4f953a80,133,"hasValue_" -code-creation,Stub,3,0x2a6a4f953b20,281,"writable_" -code-creation,StoreIC,8,0x2a6a4f953c40,133,"writable_" -code-creation,Stub,3,0x2a6a4f953ce0,281,"hasWritable_" -code-creation,StoreIC,8,0x2a6a4f953e00,133,"hasWritable_" -code-creation,Stub,3,0x2a6a4f953ea0,281,"enumerable_" -code-creation,StoreIC,8,0x2a6a4f953fc0,133,"enumerable_" -code-creation,Stub,3,0x2a6a4f954060,281,"hasEnumerable_" -code-creation,StoreIC,8,0x2a6a4f954180,133,"hasEnumerable_" -code-creation,Stub,3,0x2a6a4f954220,281,"configurable_" -code-creation,StoreIC,8,0x2a6a4f954340,133,"configurable_" -code-creation,Stub,3,0x2a6a4f9543e0,281,"hasConfigurable_" -code-creation,StoreIC,8,0x2a6a4f954500,133,"hasConfigurable_" -code-creation,Stub,3,0x2a6a4f9545a0,281,"get_" -code-creation,StoreIC,8,0x2a6a4f9546c0,133,"get_" -code-creation,Stub,3,0x2a6a4f954760,281,"hasGetter_" -code-creation,StoreIC,8,0x2a6a4f954880,133,"hasGetter_" -code-creation,Stub,3,0x2a6a4f954920,281,"set_" -code-creation,StoreIC,8,0x2a6a4f954a40,133,"set_" -code-creation,Stub,3,0x2a6a4f954ae0,281,"hasSetter_" -code-creation,StoreIC,8,0x2a6a4f954c00,133,"hasSetter_" -code-creation,Stub,3,0x2a6a4f954ca0,148,"setEnumerable" -code-creation,LoadIC,6,0x2a6a4f954d40,132,"setEnumerable" -code-creation,Stub,3,0x2a6a4f954de0,114,"ToBoolean" -code-creation,LoadIC,6,0x2a6a4f954e60,132,"ToBoolean" -code-creation,LoadIC,6,0x2a6a4f954f00,132,"enumerable" -code-creation,Stub,3,0x2a6a4f954fa0,155,"enumerable_" -code-creation,StoreIC,8,0x2a6a4f955040,133,"enumerable_" -code-creation,Stub,3,0x2a6a4f9550e0,155,"hasEnumerable_" -code-creation,StoreIC,8,0x2a6a4f955180,133,"hasEnumerable_" -code-creation,Stub,3,0x2a6a4f955220,148,"setConfigurable" -code-creation,LoadIC,6,0x2a6a4f9552c0,132,"setConfigurable" -code-creation,Stub,3,0x2a6a4f955360,112,"LoadFieldStub" -code-creation,LoadIC,6,0x2a6a4f9553e0,132,"configurable" -code-creation,Stub,3,0x2a6a4f955480,155,"configurable_" -code-creation,StoreIC,8,0x2a6a4f955520,133,"configurable_" -code-creation,Stub,3,0x2a6a4f9555c0,155,"hasConfigurable_" -code-creation,StoreIC,8,0x2a6a4f955660,133,"hasConfigurable_" -code-creation,LoadIC,6,0x2a6a4f955700,132,"get" -code-creation,Stub,3,0x2a6a4f9557a0,148,"setGet" -code-creation,LoadIC,6,0x2a6a4f955840,132,"setGet" -code-creation,Stub,3,0x2a6a4f9558e0,155,"get_" -code-creation,StoreIC,8,0x2a6a4f955980,133,"get_" -code-creation,Stub,3,0x2a6a4f955a20,155,"hasGetter_" -code-creation,StoreIC,8,0x2a6a4f955ac0,133,"hasGetter_" -code-creation,Stub,3,0x2a6a4f955b60,114,"IsInconsistentDescriptor" -code-creation,LoadIC,6,0x2a6a4f955be0,132,"IsInconsistentDescriptor" -code-creation,Stub,3,0x2a6a4f955c80,114,"IsAccessorDescriptor" -code-creation,LoadIC,6,0x2a6a4f955d00,132,"IsAccessorDescriptor" -code-creation,Stub,3,0x2a6a4f955da0,114,"IsDataDescriptor" -code-creation,LoadIC,6,0x2a6a4f955e20,132,"IsDataDescriptor" -code-creation,Stub,3,0x2a6a4f955ec0,114,"DefineOwnProperty" -code-creation,LoadIC,6,0x2a6a4f955f40,132,"DefineOwnProperty" -code-creation,Stub,3,0x2a6a4f955fe0,114,"DefineObjectProperty" -code-creation,LoadIC,6,0x2a6a4f956060,132,"DefineObjectProperty" -code-creation,Stub,3,0x2a6a4f956100,114,"ToObject" -code-creation,LoadIC,6,0x2a6a4f956180,132,"ToObject" -code-creation,Stub,12,0x2a6a4f956220,172,"CompareNilICStub(NullValue)(Generic)" -code-creation,Stub,3,0x2a6a4f9562e0,114,"ConvertDescriptorArrayToDescriptor" -code-creation,LoadIC,6,0x2a6a4f956360,132,"ConvertDescriptorArrayToDescriptor" -code-creation,Stub,3,0x2a6a4f956400,148,"hasEnumerable" -code-creation,LoadIC,6,0x2a6a4f9564a0,132,"hasEnumerable" -code-creation,Stub,3,0x2a6a4f956540,112,"LoadFieldStub" -code-creation,LoadIC,6,0x2a6a4f9565c0,132,"hasEnumerable_" -code-creation,Stub,3,0x2a6a4f956660,148,"isEnumerable" -code-creation,LoadIC,6,0x2a6a4f956700,132,"isEnumerable" -code-creation,Stub,3,0x2a6a4f9567a0,112,"LoadFieldStub" -code-creation,LoadIC,6,0x2a6a4f956820,132,"enumerable_" -code-creation,Stub,3,0x2a6a4f9568c0,148,"hasConfigurable" -code-creation,LoadIC,6,0x2a6a4f956960,132,"hasConfigurable" -code-creation,Stub,3,0x2a6a4f956a00,112,"LoadFieldStub" -code-creation,LoadIC,6,0x2a6a4f956a80,132,"hasConfigurable_" -code-creation,Stub,3,0x2a6a4f956b20,148,"isConfigurable" -code-creation,LoadIC,6,0x2a6a4f956bc0,132,"isConfigurable" -code-creation,Stub,3,0x2a6a4f956c60,112,"LoadFieldStub" -code-creation,LoadIC,6,0x2a6a4f956ce0,132,"configurable_" -code-creation,Stub,3,0x2a6a4f956d80,114,"IsGenericDescriptor" -code-creation,LoadIC,6,0x2a6a4f956e00,132,"IsGenericDescriptor" -code-creation,LoadIC,6,0x2a6a4f956ea0,132,"hasGetter" -code-creation,Stub,3,0x2a6a4f956f40,148,"getGet" -code-creation,LoadIC,6,0x2a6a4f956fe0,132,"getGet" -code-creation,Stub,3,0x2a6a4f957080,112,"LoadFieldStub" -code-creation,LoadIC,6,0x2a6a4f957100,132,"get_" -code-creation,Stub,3,0x2a6a4f9571a0,148,"hasSetter" -code-creation,LoadIC,6,0x2a6a4f957240,132,"hasSetter" -code-creation,Stub,3,0x2a6a4f9572e0,112,"LoadFieldStub" -code-creation,LoadIC,6,0x2a6a4f957360,132,"hasSetter_" -code-creation,LoadPolymorphicIC,6,0x2a6a4f957400,151,"enumerable" -code-creation,LoadPolymorphicIC,6,0x2a6a4f9574a0,151,"configurable" -code-creation,LazyCompile,0,0x2a6a4f957540,236,"$Array.enumerable_ native v8natives.js:350:20",0x117bdce19368,~ -code-creation,LazyCompile,0,0x2a6a4f957640,236,"$Array.configurable_ native v8natives.js:370:23",0x117bdce196c8,~ -code-creation,Stub,2,0x2a6a4f957740,260,"KeyedLoadElementStub" -code-creation,KeyedLoadIC,7,0x2a6a4f957860,130,"" -code-creation,Stub,3,0x2a6a4f957900,155,"value_" -code-creation,StoreIC,8,0x2a6a4f9579a0,133,"value_" -code-creation,Stub,3,0x2a6a4f957a40,155,"hasValue_" -code-creation,StoreIC,8,0x2a6a4f957ae0,133,"hasValue_" -code-creation,Stub,3,0x2a6a4f957b80,155,"writable_" -code-creation,StoreIC,8,0x2a6a4f957c20,133,"writable_" -code-creation,Stub,3,0x2a6a4f957cc0,155,"hasWritable_" -code-creation,StoreIC,8,0x2a6a4f957d60,133,"hasWritable_" -code-creation,LoadIC,6,0x2a6a4f957e00,132,"hasSetter" -code-creation,Stub,11,0x2a6a4f957ea0,596,"CompareICStub" -code-creation,LazyCompile,0,0x2a6a4f958100,812,"SameValue native runtime.js:367:19",0x117bdce12f50,~ -code-creation,LazyCompile,0,0x2a6a4f958440,208,"$Array.configurable_ native v8natives.js:374:22",0x117bdce19758,~ -code-creation,LoadIC,6,0x2a6a4f958520,132,"writable_" -code-creation,LazyCompile,0,0x2a6a4f9585c0,208,"$Array.enumerable_ native v8natives.js:354:20",0x117bdce193f8,~ -code-creation,LoadIC,6,0x2a6a4f9586a0,132,"value_" -code-creation,Stub,3,0x2a6a4f958740,148,"setValue" -code-creation,LoadIC,6,0x2a6a4f9587e0,132,"setValue" -code-creation,LoadIC,6,0x2a6a4f958880,132,"value" -code-creation,Stub,3,0x2a6a4f958920,148,"setWritable" -code-creation,LoadIC,6,0x2a6a4f9589c0,132,"setWritable" -code-creation,LoadIC,6,0x2a6a4f958a60,132,"writable" -code-creation,LoadIC,6,0x2a6a4f958b00,132,"setValue" -code-creation,LoadIC,6,0x2a6a4f958ba0,132,"setWritable" -code-creation,LoadIC,6,0x2a6a4f958c40,132,"setEnumerable" -code-creation,LoadIC,6,0x2a6a4f958ce0,132,"setConfigurable" -code-creation,LoadIC,6,0x2a6a4f958d80,132,"hasEnumerable" -code-creation,Stub,3,0x2a6a4f958e20,114,"SameValue" -code-creation,LoadIC,6,0x2a6a4f958ea0,132,"SameValue" -code-creation,LoadIC,6,0x2a6a4f958f40,132,"isEnumerable" -code-creation,LoadIC,6,0x2a6a4f958fe0,132,"isEnumerable" -code-creation,LoadIC,6,0x2a6a4f959080,132,"hasConfigurable" -code-creation,LoadIC,6,0x2a6a4f959120,132,"isConfigurable" -code-creation,LoadIC,6,0x2a6a4f9591c0,132,"isConfigurable" -code-creation,LoadIC,6,0x2a6a4f959260,132,"hasWritable" -code-creation,Stub,3,0x2a6a4f959300,148,"isWritable" -code-creation,LoadIC,6,0x2a6a4f9593a0,132,"isWritable" -code-creation,LoadIC,6,0x2a6a4f959440,132,"isWritable" -code-creation,LoadIC,6,0x2a6a4f9594e0,132,"hasValue" -code-creation,Stub,3,0x2a6a4f959580,148,"getValue" -code-creation,LoadIC,6,0x2a6a4f959620,132,"getValue" -code-creation,LoadIC,6,0x2a6a4f9596c0,132,"getValue" -code-creation,LoadIC,6,0x2a6a4f959760,132,"isConfigurable" -code-creation,LoadIC,6,0x2a6a4f959800,132,"hasWritable" -code-creation,LoadIC,6,0x2a6a4f9598a0,132,"isWritable" -code-creation,LoadIC,6,0x2a6a4f959940,132,"hasValue" -code-creation,LoadIC,6,0x2a6a4f9599e0,132,"getValue" -code-creation,LoadPolymorphicIC,6,0x2a6a4f959a80,170,"enumerable" -code-creation,LoadPolymorphicIC,6,0x2a6a4f959b40,151,"value" -code-creation,Function,0,0x2a6a4f959be0,236,"sampleFunction app.bin:7:27",0x117bdce4aa40,~ -code-creation,Function,0,0x2a6a4f959ce0,324," app.bin:3:10",0x117bdce4ab30,~ -code-creation,Script,0,0x2a6a4f959e40,376,"app.bin",0x117bdce4ac18,~ -snapshot-code-name,7786,"Stub:BinaryOpICStub(BIT_OR_ReuseRight:Smi*Int32->Smi)" -snapshot-code-name,8290,"Stub:DoubleToIStub" -snapshot-code-name,8537,"Stub:BinaryOpICStub(BIT_AND:None*None->None)" -snapshot-code-name,8735,"Stub:CEntryStub" -snapshot-code-name,9724,"Stub:BinaryOpICStub(ADD:Int32*Smi->Int32)" -snapshot-code-name,10261,"Stub:BinaryOpICStub(MOD_ReuseLeft:Number*Smi->Number)" -snapshot-code-name,11023,"Stub:CEntryStub" -snapshot-code-name,12389,"Stub:BinaryOpICStub(SAR_ReuseLeft:None*None->None)" -snapshot-code-name,12607,"Stub:CallFunctionStub_Args2" -snapshot-code-name,12892,"Builtin:ArgumentsAdaptorTrampoline" -snapshot-code-name,13230,"Stub:BinaryOpICStub(SHR:Number*Smi->Smi)" -snapshot-code-name,13920,"Stub:BinaryOpICStub(MUL_ReuseLeft:Number*Smi->Number)" -snapshot-code-name,14609,"Stub:CallFunctionStub_Args20" -snapshot-code-name,14928,"Stub:RecordWriteStub" -snapshot-code-name,16789,"Stub:StoreBufferOverflowStub" -snapshot-code-name,17106,"Stub:RecordWriteStub" -snapshot-code-name,19871,"Stub:StoreBufferOverflowStub" -snapshot-code-name,20419,"Stub:BinaryOpICStub(BIT_XOR_ReuseRight:Int32*Smi->Int32)" -snapshot-code-name,20923,"Stub:DoubleToIStub" -snapshot-code-name,21170,"Stub:BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*Smi->String)" -snapshot-code-name,21330,"Stub:BinaryOpWithAllocationSiteStub(ADD_CreateAllocationMementos:String*Smi->String)" -snapshot-code-name,23215,"Stub:DoubleToIStub" -snapshot-code-name,23491,"Stub:ArraySingleArgumentConstructorStub_FAST_ELEMENTS" -snapshot-code-name,24319,"Stub:BinaryOpICStub(BIT_XOR:Int32*Smi->Int32)" -snapshot-code-name,24858,"Stub:BinaryOpICStub(SUB_ReuseLeft:Number*Smi->Number)" -snapshot-code-name,25547,"Stub:CallFunctionStub_Args16" -snapshot-code-name,25864,"Stub:StoreArrayLiteralElementStub" -snapshot-code-name,26256,"Stub:RecordWriteStub" -snapshot-code-name,28249,"Stub:BinaryOpICStub(SUB:Smi*Smi->Smi)" -snapshot-code-name,28720,"Stub:ToNumberStub" -snapshot-code-name,29170,"Stub:BinaryOpICStub(ADD:Smi*Smi->Smi)" -snapshot-code-name,29645,"Stub:ArrayConstructorStub_Any" -snapshot-code-name,30274,"Stub:ArrayNoArgumentConstructorStub_FAST_SMI_ELEMENTS" -snapshot-code-name,30834,"Stub:ArrayNoArgumentConstructorStub_FAST_HOLEY_SMI_ELEMENTS" -snapshot-code-name,31394,"Stub:ArrayNoArgumentConstructorStub_FAST_DOUBLE_ELEMENTS" -snapshot-code-name,31870,"Stub:ArrayNoArgumentConstructorStub_FAST_HOLEY_DOUBLE_ELEMENTS" -snapshot-code-name,32346,"Stub:ArrayNoArgumentConstructorStub_FAST_ELEMENTS" -snapshot-code-name,32871,"Stub:ArrayNoArgumentConstructorStub_FAST_HOLEY_ELEMENTS" -snapshot-code-name,33406,"Stub:ArraySingleArgumentConstructorStub_FAST_SMI_ELEMENTS" -snapshot-code-name,34220,"Stub:ArraySingleArgumentConstructorStub_FAST_HOLEY_SMI_ELEMENTS" -snapshot-code-name,35066,"Stub:ArraySingleArgumentConstructorStub_FAST_DOUBLE_ELEMENTS" -snapshot-code-name,35876,"Stub:ArraySingleArgumentConstructorStub_FAST_HOLEY_DOUBLE_ELEMENTS" -snapshot-code-name,36690,"Stub:ArraySingleArgumentConstructorStub_FAST_HOLEY_ELEMENTS" -snapshot-code-name,37510,"Stub:ArrayNArgumentsConstructorStub_FAST_SMI_ELEMENTS" -snapshot-code-name,38324,"Stub:ArrayNArgumentsConstructorStub_FAST_HOLEY_SMI_ELEMENTS" -snapshot-code-name,39138,"Stub:ArrayNArgumentsConstructorStub_FAST_DOUBLE_ELEMENTS" -snapshot-code-name,39915,"Stub:ArrayNArgumentsConstructorStub_FAST_HOLEY_DOUBLE_ELEMENTS" -snapshot-code-name,40691,"Stub:ArrayNArgumentsConstructorStub_FAST_ELEMENTS" -snapshot-code-name,41350,"Stub:ArrayNArgumentsConstructorStub_FAST_HOLEY_ELEMENTS" -snapshot-code-name,42018,"Stub:ArrayNoArgumentConstructorStub_FAST_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -snapshot-code-name,42511,"Stub:ArraySingleArgumentConstructorStub_FAST_HOLEY_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -snapshot-code-name,43322,"Stub:ArraySingleArgumentConstructorStub_FAST_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -snapshot-code-name,44101,"Stub:ArrayNArgumentsConstructorStub_FAST_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -snapshot-code-name,44867,"Stub:BinaryOpICStub(BIT_OR:Number*Smi->Smi)" -snapshot-code-name,45403,"Stub:BinaryOpICStub(SHL_ReuseRight:Int32*Smi->Smi)" -snapshot-code-name,45939,"Stub:BinaryOpICStub(SHL_ReuseRight:Smi*Smi->Int32)" -snapshot-code-name,46388,"Stub:BinaryOpICStub(SUB_ReuseLeft:Int32*Int32->Int32)" -snapshot-code-name,47029,"Stub:BinaryOpICStub(MOD_ReuseLeft:Smi*Smi->Smi)" -snapshot-code-name,47533,"Stub:CompareICStub" -snapshot-code-name,47784,"Stub:BinaryOpICStub(MUL:Smi*Number->Number)" -snapshot-code-name,48470,"Stub:BinaryOpICStub(ADD_ReuseLeft:Number*Number->Number)" -snapshot-code-name,49188,"Stub:BinaryOpICStub(BIT_AND_ReuseLeft:Int32*Int32->Int32)" -snapshot-code-name,49857,"Stub:CompareNilICStub(NullValue)(Generic)" -snapshot-code-name,50100,"Stub:BinaryOpICStub(BIT_AND_ReuseRight:Number*Int32->Int32)" -snapshot-code-name,50769,"Stub:BinaryOpICStub(MOD:Smi*32->Smi)" -snapshot-code-name,51330,"Stub:CallFunctionStub_Args1_Recording" -snapshot-code-name,51998,"Stub:CreateAllocationSiteStub" -snapshot-code-name,52746,"Stub:RecordWriteStub" -snapshot-code-name,55690,"Stub:RecordWriteStub" -snapshot-code-name,57663,"Stub:BinaryOpICStub(BIT_XOR:Int32*Int32->Int32)" -snapshot-code-name,58303,"Stub:BinaryOpICStub(MOD_ReuseLeft:Smi*16->Smi)" -snapshot-code-name,58864,"Stub:BinaryOpICStub(DIV_ReuseLeft:Int32*Number->Number)" -snapshot-code-name,59670,"Stub:BinaryOpICStub(SAR_ReuseRight:None*None->None)" -snapshot-code-name,59888,"Stub:BinaryOpICStub(ADD_ReuseLeft:Smi*Int32->Int32)" -snapshot-code-name,60424,"Stub:BinaryOpICStub(MOD_ReuseLeft:Smi*4->Smi)" -snapshot-code-name,60982,"Stub:RecordWriteStub" -snapshot-code-name,63005,"Stub:BinaryOpICStub(SAR_ReuseRight:Int32*Smi->Int32)" -snapshot-code-name,63541,"Stub:BinaryOpICStub(SHL:None*None->None)" -snapshot-code-name,63759,"Stub:BinaryOpICStub(ADD:Smi*Number->Number)" -snapshot-code-name,64448,"Stub:BinaryOpICStub(MUL:Int32*Smi->Number)" -snapshot-code-name,65165,"Stub:BinaryOpICStub(ROR:None*None->None)" -snapshot-code-name,65386,"Stub:BinaryOpICStub(ADD:Number*Smi->Number)" -snapshot-code-name,66075,"Stub:BinaryOpICStub(SHL_ReuseRight:Number*Smi->Smi)" -snapshot-code-name,66646,"Stub:BinaryOpICStub(DIV_ReuseLeft:Smi*Smi->Number)" -snapshot-code-name,67293,"Stub:BinaryOpICStub(MUL:Number*Int32->Number)" -snapshot-code-name,68046,"Stub:BinaryOpICStub(MOD:Smi*8->Smi)" -snapshot-code-name,68607,"Stub:BinaryOpICStub(ADD_ReuseLeft:Int32*Int32->Number)" -snapshot-code-name,69390,"Stub:BinaryOpICStub(BIT_XOR:Number*Smi->Int32)" -snapshot-code-name,69926,"Stub:BinaryOpICStub(DIV:Int32*Smi->Int32)" -snapshot-code-name,70527,"Stub:BinaryOpICStub(ADD:Int32*Number->Number)" -snapshot-code-name,71277,"Stub:BinaryOpICStub(BIT_OR_ReuseLeft:Smi*Smi->Smi)" -snapshot-code-name,71674,"Stub:BinaryOpICStub(SHR:Smi*Smi->Smi)" -snapshot-code-name,72234,"Stub:BinaryOpICStub(SAR_ReuseRight:Smi*Smi->Smi)" -snapshot-code-name,72663,"Stub:BinaryOpICStub(SUB_ReuseRight:Int32*Smi->Int32)" -snapshot-code-name,73203,"Stub:BinaryOpICStub(BIT_XOR:Number*Int32->Int32)" -snapshot-code-name,73843,"Stub:BinaryOpICStub(MUL:Int32*Int32->Int32)" -snapshot-code-name,74489,"Stub:CallFunctionStub_Args0_Recording" -snapshot-code-name,75156,"Stub:BinaryOpICStub(ADD_ReuseRight:Smi*Smi->Smi)" -snapshot-code-name,75627,"Stub:BinaryOpICStub(SUB:Smi*Int32->Int32)" -snapshot-code-name,76167,"Stub:FastNewClosureStub" -snapshot-code-name,77113,"Stub:RecordWriteStub" -snapshot-code-name,79968,"Stub:RecordWriteStub" -snapshot-code-name,82883,"Stub:CompareICStub" -snapshot-code-name,83137,"Stub:BinaryOpICStub(SUB:Number*Number->Number)" -snapshot-code-name,83858,"Stub:BinaryOpICStub(BIT_OR:Smi*Smi->Smi)" -snapshot-code-name,84256,"Stub:ToBooleanStub(Bool)" -snapshot-code-name,84608,"Stub:BinaryOpICStub(SAR:None*None->None)" -snapshot-code-name,84826,"Stub:BinaryOpICStub(BIT_OR_ReuseLeft:None*None->None)" -snapshot-code-name,85048,"Stub:BinaryOpICStub(BIT_OR_ReuseRight:None*None->None)" -snapshot-code-name,85269,"Stub:BinaryOpICStub(SHL_ReuseLeft:None*None->None)" -snapshot-code-name,85490,"Stub:FastNewContextStub" -snapshot-code-name,85956,"Stub:BinaryOpICStub(ADD_ReuseRight:None*None->None)" -snapshot-code-name,86174,"Stub:CallFunctionStub_Args5" -snapshot-code-name,86493,"Stub:BinaryOpICStub(SUB:Int32*Number->Number)" -snapshot-code-name,87243,"Stub:BinaryOpICStub(SUB_ReuseLeft:Smi*Number->Number)" -snapshot-code-name,87929,"Stub:CallFunctionStub_Args0" -snapshot-code-name,88343,"Stub:BinaryOpICStub(BIT_XOR_ReuseLeft:Int32*Int32->Int32)" -snapshot-code-name,89012,"Stub:BinaryOpICStub(SAR:Number*Smi->Smi)" -snapshot-code-name,89580,"Stub:BinaryOpICStub(DIV:Number*Number->Number)" -snapshot-code-name,90298,"Stub:BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -snapshot-code-name,90458,"Stub:BinaryOpWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -snapshot-code-name,92153,"Stub:RecordWriteStub" -snapshot-code-name,94113,"Stub:BinaryOpICStub(DIV_ReuseLeft:None*None->None)" -snapshot-code-name,94334,"Stub:CallFunctionStub_Args4" -snapshot-code-name,94651,"Stub:BinaryOpICStub(BIT_AND_ReuseRight:Int32*Int32->Smi)" -snapshot-code-name,95288,"Stub:BinaryOpICStub(DIV_ReuseRight:Number*Number->Number)" -snapshot-code-name,96006,"Stub:BinaryOpICStub(BIT_OR_ReuseLeft:Number*Smi->Int32)" -snapshot-code-name,96598,"Stub:BinaryOpICStub(BIT_OR_ReuseLeft:Int32*Smi->Int32)" -snapshot-code-name,97169,"Stub:BinaryOpICStub(DIV_ReuseLeft:Number*Smi->Number)" -snapshot-code-name,97911,"Stub:BinaryOpICStub(BIT_OR_ReuseRight:Smi*Smi->Smi)" -snapshot-code-name,98310,"Stub:BinaryOpICStub(DIV_ReuseLeft:Number*Int32->Number)" -snapshot-code-name,99096,"Stub:BinaryOpICStub(ADD_ReuseLeft:Int32*Smi->Int32)" -snapshot-code-name,99668,"Stub:BinaryOpICStub(SUB_ReuseLeft:Number*Int32->Number)" -snapshot-code-name,100454,"Stub:BinaryOpICStub(SHR_ReuseLeft:Number*Smi->Smi)" -snapshot-code-name,101148,"Stub:BinaryOpICStub(SUB_ReuseRight:Int32*Number->Number)" -snapshot-code-name,101934,"Stub:InternalArrayNArgumentsConstructorStub" -snapshot-code-name,102600,"Stub:BinaryOpICStub(MOD:None*None->None)" -snapshot-code-name,102819,"Stub:MathPowStub" -snapshot-code-name,103504,"Stub:BinaryOpICStub(SUB:Number*Int32->Number)" -snapshot-code-name,104255,"Stub:NumberToStringStub" -snapshot-code-name,105012,"Stub:DoubleToIStub" -snapshot-code-name,105256,"Stub:BinaryOpICStub(SUB:Smi*Number->Number)" -snapshot-code-name,105945,"Stub:BinaryOpICStub(MUL_ReuseLeft:None*None->None)" -snapshot-code-name,106213,"Stub:BinaryOpICStub(DIV:None*None->None)" -snapshot-code-name,106434,"Stub:BinaryOpICStub(BIT_XOR:Smi*Smi->Smi)" -snapshot-code-name,106855,"Stub:CompareNilICStub(NullValue)(MonomorphicMap)" -snapshot-code-name,107251,"Stub:BinaryOpICStub(BIT_AND:Number*Smi->Smi)" -snapshot-code-name,107788,"Stub:RecordWriteStub" -snapshot-code-name,108663,"Stub:CallFunctionStub_Args14" -snapshot-code-name,108977,"Stub:BinaryOpICStub(BIT_OR_ReuseLeft:Smi*Int32->Int32)" -snapshot-code-name,109516,"Stub:BinaryOpICStub(BIT_AND:Smi*Smi->Smi)" -snapshot-code-name,109910,"Stub:BinaryOpICStub(DIV:Number*Smi->Number)" -snapshot-code-name,110596,"Stub:BinaryOpICStub(ADD:Smi*Int32->Int32)" -snapshot-code-name,111136,"Stub:NameDictionaryLookupStub" -snapshot-code-name,112215,"Stub:BinaryOpICStub(SAR_ReuseRight:Number*Smi->Smi)" -snapshot-code-name,112806,"Stub:CompareNilICStub(NullValue)(Undefined)" -snapshot-code-name,113161,"Stub:BinaryOpICStub(BIT_AND_ReuseLeft:Int32*Smi->Smi)" -snapshot-code-name,113700,"Stub:CompareICStub" -snapshot-code-name,113952,"Stub:BinaryOpICStub(MUL_ReuseRight:Number*Int32->Number)" -snapshot-code-name,114758,"Stub:LoadFieldStub" -snapshot-code-name,114928,"Stub:CallFunctionStub_Args2_Recording" -snapshot-code-name,115573,"Stub:CompareICStub" -snapshot-code-name,115827,"Stub:BinaryOpICStub(ADD:None*None->None)" -snapshot-code-name,116045,"Stub:BinaryOpICStub(MUL_ReuseRight:Smi*Number->Number)" -snapshot-code-name,116734,"Stub:BinaryOpICStub(ADD_ReuseLeft:Smi*Smi->Int32)" -snapshot-code-name,117253,"Stub:BinaryOpICStub(DIV:Int32*Number->Number)" -snapshot-code-name,118006,"Stub:BinaryOpICStub(MOD:Smi*2->Smi)" -snapshot-code-name,118563,"Stub:BinaryOpICStub(MUL:Smi*Smi->Int32)" -snapshot-code-name,119068,"Stub:RecordWriteStub" -snapshot-code-name,121027,"Stub:BinaryOpICStub(BIT_XOR_ReuseLeft:None*None->None)" -snapshot-code-name,121245,"Stub:StubFailureTrampolineStub" -snapshot-code-name,121423,"Stub:BinaryOpICStub(BIT_XOR:Int32*Number->Smi)" -snapshot-code-name,122060,"Stub:FastNewContextStub" -snapshot-code-name,122493,"Stub:BinaryOpICStub(ADD:Int32*Int32->Int32)" -snapshot-code-name,123106,"Stub:NameDictionaryLookupStub" -snapshot-code-name,124188,"Stub:ArrayNoArgumentConstructorStub_FAST_HOLEY_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -snapshot-code-name,124728,"Stub:LoadFieldStub" -snapshot-code-name,124898,"Stub:LoadFieldStub" -snapshot-code-name,125065,"Stub:CompareICStub" -snapshot-code-name,125739,"Stub:BinaryOpICStub(SHL:Int32*Smi->Int32)" -snapshot-code-name,126279,"Stub:BinaryOpICStub(DIV_ReuseRight:Smi*Smi->Smi)" -snapshot-code-name,126818,"Stub:InternalArrayNArgumentsConstructorStub" -snapshot-code-name,127507,"Stub:BinaryOpICStub(BIT_AND:Int32*Smi->Int32)" -snapshot-code-name,128086,"Stub:BinaryOpICStub(ADD_ReuseRight:Number*Smi->Number)" -snapshot-code-name,128772,"Stub:CallFunctionStub_Args12" -snapshot-code-name,129089,"Stub:BinaryOpICStub(DIV_ReuseRight:None*None->None)" -snapshot-code-name,129311,"Stub:BinaryOpICStub(SAR_ReuseRight:Int32*Smi->Smi)" -snapshot-code-name,129847,"Stub:BinaryOpICStub(ADD_ReuseLeft:Number*Smi->Number)" -snapshot-code-name,130533,"Stub:CallFunctionStub_Args7" -snapshot-code-name,130847,"Stub:CallFunctionStub_Args72" -snapshot-code-name,131162,"Stub:FastCloneShallowArrayStub" -snapshot-code-name,131959,"Stub:BinaryOpICStub(SAR_ReuseLeft:Smi*Smi->Smi)" -snapshot-code-name,132385,"Stub:BinaryOpICStub(BIT_OR_ReuseLeft:Number*Smi->Smi)" -snapshot-code-name,132921,"Stub:CompareICStub" -snapshot-code-name,133207,"Stub:BinaryOpICStub(ADD:Smi*Int32->Number)" -snapshot-code-name,133927,"Stub:LoadFieldStub" -snapshot-code-name,134096,"Stub:BinaryOpICStub(SUB:None*None->None)" -snapshot-code-name,134314,"Stub:BinaryOpICStub(MUL:Number*Smi->Number)" -snapshot-code-name,135004,"Stub:BinaryOpICStub(MUL_ReuseRight:Smi*Smi->Smi)" -snapshot-code-name,135511,"Stub:BinaryOpICStub(BIT_AND_ReuseLeft:Smi*Smi->Smi)" -snapshot-code-name,135905,"Stub:JSConstructEntryStub" -snapshot-code-name,136443,"Stub:RecordWriteStub" -snapshot-code-name,138435,"Stub:BinaryOpICStub(ADD:Number*Int32->Number)" -snapshot-code-name,139188,"Stub:CompareNilICStub(NullValue)(None)" -snapshot-code-name,139409,"Stub:CompareICStub" -snapshot-code-name,139664,"Stub:CallConstructStub_Recording" -snapshot-code-name,140285,"Stub:BinaryOpICStub(MUL_ReuseLeft:Int32*Smi->Int32)" -snapshot-code-name,140909,"Stub:BinaryOpICStub(ROR_ReuseLeft:None*None->None)" -snapshot-code-name,141127,"Stub:BinaryOpICStub(MOD:Smi*4->Smi)" -snapshot-code-name,141687,"Stub:BinaryOpICStub(DIV:Smi*Int32->Int32)" -snapshot-code-name,142287,"Stub:LoadFieldStub" -snapshot-code-name,142476,"Stub:BinaryOpICStub(BIT_AND_ReuseRight:Smi*Int32->Smi)" -snapshot-code-name,143015,"Stub:BinaryOpICStub(SUB_ReuseLeft:Number*Number->Number)" -snapshot-code-name,143780,"Stub:BinaryOpICStub(DIV_ReuseLeft:Smi*Smi->Smi)" -snapshot-code-name,144319,"Stub:BinaryOpICStub(SHR_ReuseRight:None*None->None)" -snapshot-code-name,144538,"Stub:FastNewClosureStub" -snapshot-code-name,145526,"Stub:ToBooleanStub(SpecObject)" -snapshot-code-name,145878,"Stub:KeyedLoadElementStub" -snapshot-code-name,146340,"Stub:BinaryOpICStub(BIT_XOR:Number*Smi->Smi)" -snapshot-code-name,146880,"Stub:RecordWriteStub" -snapshot-code-name,148872,"Stub:BinaryOpICStub(MUL_ReuseLeft:Int32*Number->Number)" -snapshot-code-name,149658,"Stub:BinaryOpICStub(BIT_AND_ReuseRight:None*None->None)" -snapshot-code-name,149876,"Stub:LoadFieldStub" -snapshot-code-name,150042,"Stub:BinaryOpICStub(DIV:Smi*Smi->Smi)" -snapshot-code-name,150581,"Stub:BinaryOpICStub(SHL:Int32*Smi->Smi)" -snapshot-code-name,151117,"Stub:BinaryOpICStub(SHL:Smi*Smi->Int32)" -snapshot-code-name,151546,"Stub:BinaryOpICStub(BIT_XOR_ReuseLeft:Smi*Smi->Smi)" -snapshot-code-name,151944,"Stub:BinaryOpICStub(BIT_OR:Int32*Smi->Smi)" -snapshot-code-name,152483,"Stub:CallFunctionStub_Args38" -snapshot-code-name,152797,"Stub:LoadFieldStub" -snapshot-code-name,152963,"Stub:BinaryOpICStub(DIV:Int32*Int32->Int32)" -snapshot-code-name,153636,"Stub:BinaryOpICStub(DIV_ReuseLeft:Number*Number->Number)" -snapshot-code-name,154357,"Stub:LoadFieldStub" -snapshot-code-name,154527,"Stub:BinaryOpICStub(ADD_ReuseRight:Number*Int32->Number)" -snapshot-code-name,155314,"Stub:BinaryOpICStub(MUL_ReuseLeft:Smi*Smi->Smi)" -snapshot-code-name,155821,"Stub:LoadFieldStub" -snapshot-code-name,155991,"Stub:InternalArraySingleArgumentConstructorStub" -snapshot-code-name,156780,"Stub:BinaryOpICStub(MUL:Int32*Int32->Number)" -snapshot-code-name,157563,"Stub:BinaryOpICStub(BIT_OR:Number*Smi->Int32)" -snapshot-code-name,158102,"Stub:BinaryOpICStub(MUL_ReuseRight:None*None->None)" -snapshot-code-name,158324,"Stub:FastNewContextStub" -snapshot-code-name,158792,"Stub:BinaryOpICStub(BIT_AND_ReuseRight:Number*Smi->Smi)" -snapshot-code-name,159329,"Stub:BinaryOpICStub(DIV:Int32*Int32->Number)" -snapshot-code-name,160115,"Stub:BinaryOpICStub(DIV:Smi*Number->Number)" -snapshot-code-name,160801,"Stub:BinaryOpICStub(DIV:Smi*Int32->Number)" -snapshot-code-name,161518,"Stub:BinaryOpICStub(BIT_XOR_ReuseRight:Int32*Int32->Int32)" -snapshot-code-name,162187,"Stub:BinaryOpICStub(MUL:Smi*Smi->Smi)" -snapshot-code-name,162695,"Stub:BinaryOpICStub(MUL:None*None->None)" -snapshot-code-name,162916,"Stub:BinaryOpICStub(ADD_ReuseLeft:None*None->None)" -snapshot-code-name,163137,"Stub:BinaryOpICStub(BIT_OR_ReuseRight:Number*Smi->Int32)" -snapshot-code-name,163673,"Stub:CallFunctionStub_Args3" -snapshot-code-name,163990,"Stub:BinaryOpICStub(ADD_ReuseLeft:Int32*Int32->Int32)" -snapshot-code-name,164634,"Stub:BinaryOpICStub(MUL_ReuseLeft:Smi*Smi->Number)" -snapshot-code-name,165284,"Stub:BinaryOpICStub(SAR:Int32*Smi->Smi)" -snapshot-code-name,165820,"Stub:InternalArrayNoArgumentConstructorStub" -snapshot-code-name,166327,"Stub:BinaryOpICStub(MUL:Smi*Int32->Int32)" -snapshot-code-name,166898,"Stub:BinaryOpICStub(BIT_OR_ReuseRight:Int32*Smi->Smi)" -snapshot-code-name,167439,"Stub:BinaryOpICStub(ADD_ReuseRight:Int32*Number->Number)" -snapshot-code-name,168222,"Stub:BinaryOpICStub(BIT_AND:Int32*Int32->Int32)" -snapshot-code-name,168859,"Stub:CompareICStub" -snapshot-code-name,169111,"Stub:ArgumentsAccessStub_NewSloppyFast" -snapshot-code-name,169731,"Stub:LoadFieldStub" -snapshot-code-name,169900,"Stub:BinaryOpICStub(BIT_XOR_ReuseRight:None*None->None)" -snapshot-code-name,170142,"Stub:BinaryOpICStub(BIT_XOR_ReuseLeft:Smi*Int32->Smi)" -snapshot-code-name,170705,"Stub:BinaryOpICStub(ADD_ReuseLeft:Number*Int32->Number)" -snapshot-code-name,171491,"Stub:BinaryOpICStub(MUL_ReuseLeft:Number*Number->Number)" -snapshot-code-name,172213,"Stub:NameDictionaryLookupStub" -snapshot-code-name,173294,"Stub:BinaryOpICStub(MUL_ReuseLeft:Smi*Int32->Int32)" -snapshot-code-name,173862,"Stub:BinaryOpICStub(SHL:Smi*Smi->Smi)" -snapshot-code-name,174292,"Stub:StringAddStub_CheckBoth" -snapshot-code-name,175863,"Stub:BinaryOpICStub(BIT_OR_ReuseRight:Int32*Smi->Int32)" -snapshot-code-name,176399,"Stub:BinaryOpICStub(SHL_ReuseRight:Smi*Smi->Smi)" -snapshot-code-name,176828,"Stub:CallFunctionStub_Args32" -snapshot-code-name,177145,"Stub:BinaryOpICStub(DIV:Smi*Smi->Number)" -snapshot-code-name,177817,"Stub:BinaryOpICStub(BIT_OR_ReuseRight:Int32*Int32->Int32)" -snapshot-code-name,178489,"Stub:BinaryOpICStub(BIT_AND:Int32*Smi->Smi)" -snapshot-code-name,179028,"Stub:BinaryOpICStub(BIT_OR_ReuseLeft:Int32*Int32->Smi)" -snapshot-code-name,179665,"Stub:BinaryOpICStub(BIT_XOR:None*None->None)" -snapshot-code-name,179883,"Stub:ToBooleanStub(Undefined)" -snapshot-code-name,180233,"Stub:BinaryOpICStub(BIT_AND_ReuseLeft:None*None->None)" -snapshot-code-name,180477,"Stub:CallFunctionStub_Args92" -snapshot-code-name,180795,"Stub:CallFunctionStub_Args4_Recording" -snapshot-code-name,181439,"Stub:InternalArrayConstructorStub" -snapshot-code-name,181697,"Stub:InternalArraySingleArgumentConstructorStub" -snapshot-code-name,182471,"Stub:InternalArrayNoArgumentConstructorStub" -snapshot-code-name,182995,"Stub:BinaryOpICStub(BIT_XOR:Int32*Int32->Smi)" -snapshot-code-name,183632,"Stub:CallFunctionStub_Args1" -snapshot-code-name,184083,"Stub:BinaryOpICStub(BIT_AND:Int32*Int32->Smi)" -snapshot-code-name,184724,"Stub:BinaryOpICStub(MUL:Int32*Number->Number)" -snapshot-code-name,185474,"Stub:FunctionPrototypeStub" -snapshot-code-name,185697,"Builtin:LoadIC_Miss" -snapshot-code-name,185882,"Stub:BinaryOpICStub(ADD_ReuseRight:Int32*Smi->Int32)" -snapshot-code-name,186421,"Stub:ToBooleanStub(None)" -snapshot-code-name,186639,"Stub:BinaryOpICStub(BIT_XOR_ReuseRight:Smi*Smi->Smi)" -snapshot-code-name,187033,"Stub:CompareICStub" -snapshot-code-name,187337,"Stub:CallFunctionStub_Args3_Recording" -snapshot-code-name,187981,"Stub:BinaryOpICStub(SHR_ReuseLeft:Int32*Smi->Smi)" -snapshot-code-name,188675,"Stub:CallFunctionStub_Args42" -snapshot-code-name,188992,"Stub:CallFunctionStub_Args6" -snapshot-code-name,189309,"Stub:BinaryOpICStub(SHR_ReuseLeft:None*None->None)" -snapshot-code-name,189553,"Stub:CallFunctionStub_Args3" -snapshot-code-name,190000,"Stub:BinaryOpICStub(MUL:Number*Number->Number)" -snapshot-code-name,190719,"Stub:BinaryOpICStub(SHR_ReuseRight:Number*Smi->Int32)" -snapshot-code-name,191508,"Stub:BinaryOpICStub(SUB_ReuseRight:Smi*Number->Number)" -snapshot-code-name,192197,"Stub:BinaryOpICStub(SUB_ReuseLeft:Smi*Smi->Smi)" -snapshot-code-name,192672,"Stub:BinaryOpICStub(SHL_ReuseLeft:Smi*Smi->Smi)" -snapshot-code-name,193098,"Stub:BinaryOpICStub(BIT_AND_ReuseRight:Int32*Int32->Int32)" -snapshot-code-name,193769,"Stub:RecordWriteStub" -snapshot-code-name,195757,"Stub:BinaryOpICStub(ADD_ReuseLeft:Smi*Number->Number)" -snapshot-code-name,196444,"Stub:BinaryOpICStub(MOD:Smi*Smi->Smi)" -snapshot-code-name,196952,"Stub:BinaryOpICStub(BIT_OR:None*None->None)" -snapshot-code-name,197174,"Stub:JSEntryStub" -snapshot-code-name,197709,"Stub:BinaryOpICStub(DIV:Number*Int32->Number)" -snapshot-code-name,198461,"Stub:CompareICStub" -snapshot-code-name,199207,"Stub:CompareICStub" -snapshot-code-name,199459,"Stub:BinaryOpICStub(MUL_ReuseLeft:Smi*Number->Number)" -snapshot-code-name,200149,"Stub:BinaryOpICStub(DIV_ReuseRight:Smi*Number->Number)" -snapshot-code-name,200868,"Stub:BinaryOpICStub(BIT_OR:Int32*Smi->Int32)" -snapshot-code-name,201405,"Stub:RecordWriteStub" -snapshot-code-name,203479,"Stub:BinaryOpICStub(ADD:Int32*Int32->Number)" -snapshot-code-name,204267,"Stub:BinaryOpICStub(SHL_ReuseRight:Int32*Smi->Int32)" -snapshot-code-name,204803,"Stub:BinaryOpICStub(SUB_ReuseRight:Smi*Smi->Smi)" -snapshot-code-name,205278,"Stub:BinaryOpICStub(SHL_ReuseLeft:Smi*Smi->Int32)" -snapshot-code-name,205708,"Stub:BinaryOpICStub(BIT_AND_ReuseRight:Int32*Smi->Int32)" -snapshot-code-name,206245,"Stub:BinaryOpICStub(MUL_ReuseLeft:Number*Int32->Number)" -snapshot-code-name,207049,"Stub:BinaryOpICStub(MOD_ReuseRight:None*None->None)" -snapshot-code-name,207268,"Stub:BinaryOpICStub(SHR:None*None->None)" -snapshot-code-name,207490,"Stub:BinaryOpICStub(ROR_ReuseRight:None*None->None)" -snapshot-code-name,207712,"Stub:BinaryOpICStub(BIT_AND:Smi*Int32->Int32)" -snapshot-code-name,208253,"Stub:BinaryOpICStub(ADD_ReuseLeft:Smi*Smi->Smi)" -snapshot-code-name,208724,"Stub:BinaryOpICStub(BIT_XOR_ReuseLeft:Smi*Int32->Int32)" -snapshot-code-name,209264,"Stub:BinaryOpICStub(SUB_ReuseLeft:None*None->None)" -snapshot-code-name,209529,"Stub:KeyedLoadElementStub" -snapshot-code-name,210089,"Stub:BinaryOpICStub(SHR:Int32*Smi->Smi)" -snapshot-code-name,210804,"Stub:ArgumentsAccessStub_ReadElement" -snapshot-code-name,211089,"Stub:BinaryOpICStub(MOD_ReuseLeft:None*None->None)" -snapshot-code-name,211308,"Stub:BinaryOpICStub(BIT_XOR_ReuseLeft:Int32*Int32->Smi)" -snapshot-code-name,211951,"Stub:BinaryOpICStub(BIT_OR_ReuseRight:Smi*Int32->Int32)" -snapshot-code-name,212520,"Stub:BinaryOpICStub(SUB_ReuseRight:None*None->None)" -snapshot-code-name,212742,"Stub:StringCompareStub" -snapshot-code-name,213087,"Stub:CompareICStub" -snapshot-code-name,213342,"Stub:CallFunctionStub_Args30" -snapshot-code-name,213659,"Stub:BinaryOpICStub(SUB:Int32*Int32->Int32)" -snapshot-code-name,214272,"Stub:ArrayNArgumentsConstructorStub_FAST_HOLEY_SMI_ELEMENTS_DISABLE_ALLOCATION_SITES" -snapshot-code-name,215070,"Stub:BinaryOpICStub(BIT_XOR:Smi*Int32->Int32)" -snapshot-code-name,215607,"Stub:BinaryOpICStub(SUB:Number*Smi->Number)" -snapshot-code-name,216297,"Stub:BinaryOpICStub(MOD:Smi*2048->Smi)" -snapshot-code-name,216886,"Stub:CallFunctionStub_Args8" -snapshot-code-name,217207,"Stub:CallFunctionStub_Args1" -snapshot-code-name,217527,"Stub:BinaryOpICStub(SUB_ReuseLeft:Int32*Smi->Int32)" -snapshot-code-name,218095,"Stub:StubFailureTrampolineStub" -snapshot-code-name,218274,"Stub:BinaryOpICStub(SHR_ReuseRight:Smi*Smi->Smi)" -snapshot-code-name,218834,"Stub:BinaryOpICStub(MUL:Int32*Smi->Int32)" -snapshot-code-name,219428,"Stub:BinaryOpICStub(SHL_ReuseRight:None*None->None)" -snapshot-code-name,219647,"Stub:BinaryOpICStub(BIT_AND_ReuseRight:Int32*Smi->Smi)" -snapshot-code-name,220184,"Stub:LoadFieldStub" -snapshot-code-name,220354,"Stub:BinaryOpICStub(DIV_ReuseLeft:Smi*Int32->Number)" -snapshot-code-name,221072,"Stub:BinaryOpICStub(DIV_ReuseRight:Smi*Smi->Number)" -snapshot-code-name,221719,"Stub:BinaryOpICStub(SUB_ReuseRight:Number*Number->Number)" -snapshot-code-name,222441,"Stub:BinaryOpICStub(SHR_ReuseRight:Int32*Smi->Smi)" -snapshot-code-name,223156,"Stub:BinaryOpICStub(ADD_ReuseLeft:Int32*Number->Number)" -snapshot-code-name,223940,"Stub:BinaryOpICStub(ADD:Number*Number->Number)" -snapshot-code-name,224662,"Stub:BinaryOpICStub(ADD_ReuseRight:Smi*Number->Number)" -snapshot-code-name,225349,"Stub:BinaryOpICStub(BIT_XOR_ReuseLeft:Int32*Smi->Int32)" -snapshot-code-name,225939,"Stub:BinaryOpICStub(DIV_ReuseLeft:Smi*Number->Number)" -snapshot-code-name,226652,"Stub:BinaryOpICStub(DIV:Int32*Smi->Number)" -snapshot-code-name,227374,"Stub:BinaryOpICStub(ADD_ReuseRight:Number*Number->Number)" -snapshot-code-name,228093,"Stub:BinaryOpICStub(SUB_ReuseRight:Number*Smi->Number)" -snapshot-code-name,228783,"Stub:BinaryOpICStub(MUL_ReuseRight:Number*Smi->Number)" -snapshot-code-name,229470,"Stub:BinaryOpICStub(MUL:Smi*Int32->Number)" -snapshot-code-name,230192,"Stub:BinaryOpICStub(BIT_AND_ReuseRight:Smi*Smi->Smi)" -snapshot-code-name,230608,"Stub:RecordWriteStub" -snapshot-code-name,232574,"Stub:CallConstructStub" -snapshot-code-name,232853,"Stub:CompareICStub" -snapshot-code-name,233105,"Stub:BinaryOpICStub(SHR_ReuseLeft:Smi*Smi->Smi)" -snapshot-code-name,233662,"Stub:CallFunctionStub_Args10" -snapshot-code-name,233982,"Stub:BinaryOpICStub(BIT_OR_ReuseLeft:Int32*Int32->Int32)" -snapshot-code-name,234656,"Stub:BinaryOpICStub(SAR:Smi*Smi->Smi)" -snapshot-code-name,235106,"Stub:BinaryOpICStub(BIT_AND_ReuseRight:Smi*Number->Smi)" -snapshot-code-name,235643,"Stub:BinaryOpICStub(MUL:Smi*Smi->Number)" -snapshot-code-name,236290,"Stub:CallFunctionStub_Args0" -snapshot-code-name,236661,"LoadPreMonomorphic:0" -snapshot-code-name,236849,"StorePreMonomorphic:0" -snapshot-code-name,237033,"StoreInitialize:0" -snapshot-code-name,237221,"LoadInitialize:0" -snapshot-code-name,237409,"LoadPreMonomorphic:0" -snapshot-code-name,237597,"StoreInitialize:0" -snapshot-code-name,237785,"LoadInitialize:0" -snapshot-code-name,237973,"StorePreMonomorphic:0" -snapshot-code-name,238161,"LoadMegamorphic:0" -snapshot-code-name,268484,"Builtin:Return_DebugBreak" -snapshot-code-name,268721,"Builtin:Slot_DebugBreak" -snapshot-code-name,269042,"Builtin:EmptyFunction" -snapshot-code-name,269220,"Builtin:JSConstructStubGeneric" -snapshot-code-name,270081,"Script:~native apinatives.js" -snapshot-code-name,270632,"Builtin:CompileUnoptimized" -snapshot-code-name,271501,"Builtin:StackCheck" -snapshot-code-name,271768,"Builtin:InterruptCheck" -snapshot-code-name,272104,"Script:~native math.js" -snapshot-code-name,273484,"LazyCompile:~MathConstructor native math.js:4" -snapshot-code-name,278991,"LazyCompile:~SetUpMath native math.js:153" -snapshot-code-name,282691,"Script:~native i18n.js" -snapshot-code-name,283428,"Function:~ native i18n.js:2" -snapshot-code-name,310099,"LazyCompile:~addBoundMethod native i18n.js:112" -snapshot-code-name,328357,"Script:~native regexp.js" -snapshot-code-name,332075,"LazyCompile:~RegExpConstructor native regexp.js:46" -snapshot-code-name,334468,"LazyCompile:~RegExpMakeCaptureGetter native regexp.js:241" -snapshot-code-name,335212,"LazyCompile:~SetUpRegExp native regexp.js:265" -snapshot-code-name,339841,"Stub:BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*Smi->String)" -snapshot-code-name,340641,"Script:~native array.js" -snapshot-code-name,356360,"LazyCompile:~SetUpArray native array.js:1166" -snapshot-code-name,361073,"LazyCompile:~SetUpArray.b native array.js:1173" -snapshot-code-name,361612,"Builtin:KeyedLoadIC_PreMonomorphic" -snapshot-code-name,363486,"Script:~native string.js" -snapshot-code-name,364367,"LazyCompile:~StringConstructor native string.js:2" -snapshot-code-name,376693,"LazyCompile:~SetUpString native string.js:617" -snapshot-code-name,380227,"Script:~native v8natives.js" -snapshot-code-name,382670,"LazyCompile:~InstallFunctions native v8natives.js:4" -snapshot-code-name,394945,"LazyCompile:~InstallGetter native v8natives.js:18" -snapshot-code-name,395607,"LazyCompile:~InstallGetterSetter native v8natives.js:24" -snapshot-code-name,396340,"LazyCompile:~InstallConstants native v8natives.js:33" -snapshot-code-name,397443,"LazyCompile:~SetUpLockedPrototype native v8natives.js:45" -snapshot-code-name,399836,"LazyCompile:~SetUpGlobal native v8natives.js:113" -snapshot-code-name,401515,"LazyCompile:~hasOwnProperty native v8natives.js:140" -snapshot-code-name,403883,"LazyCompile:~IsAccessorDescriptor native v8natives.js:217" -snapshot-code-name,404656,"LazyCompile:~IsDataDescriptor native v8natives.js:221" -snapshot-code-name,405429,"LazyCompile:~IsGenericDescriptor native v8natives.js:225" -snapshot-code-name,406177,"LazyCompile:~IsInconsistentDescriptor native v8natives.js:229" -snapshot-code-name,407062,"LazyCompile:~ToPropertyDescriptor native v8natives.js:270" -snapshot-code-name,411054,"LazyCompile:~PropertyDescriptor native v8natives.js:319" -snapshot-code-name,412472,"LazyCompile:~ConvertDescriptorArrayToDescriptor native v8natives.js:410" -snapshot-code-name,413625,"Builtin:KeyedLoadIC_Initialize" -snapshot-code-name,414810,"LazyCompile:~DefineObjectProperty native v8natives.js:495" -snapshot-code-name,425815,"LazyCompile:~DefineOwnProperty native v8natives.js:707" -snapshot-code-name,427910,"LazyCompile:~defineProperty native v8natives.js:831" -snapshot-code-name,429624,"Builtin:KeyedStoreIC_Initialize" -snapshot-code-name,431729,"LazyCompile:~ObjectConstructor native v8natives.js:1010" -snapshot-code-name,432586,"LazyCompile:~SetUpObject native v8natives.js:1019" -snapshot-code-name,435383,"LazyCompile:~BooleanConstructor native v8natives.js:1058" -snapshot-code-name,436375,"LazyCompile:~SetUpBoolean native v8natives.js:1081" -snapshot-code-name,437602,"LazyCompile:~NumberConstructor native v8natives.js:1092" -snapshot-code-name,439691,"LazyCompile:~SetUpNumber native v8natives.js:1200" -snapshot-code-name,443094,"LazyCompile:~FunctionConstructor native v8natives.js:1318" -snapshot-code-name,444095,"LazyCompile:~SetUpFunction native v8natives.js:1325" -snapshot-code-name,445786,"LazyCompile:~$Array.enumerable_ native v8natives.js:350" -snapshot-code-name,446362,"LazyCompile:~$Array.enumerable_ native v8natives.js:354" -snapshot-code-name,446826,"LazyCompile:~$Array.enumerable_ native v8natives.js:357" -snapshot-code-name,447290,"LazyCompile:~$Array.writable_ native v8natives.js:360" -snapshot-code-name,447866,"LazyCompile:~$Array.writable_ native v8natives.js:364" -snapshot-code-name,448330,"LazyCompile:~$Array.writable_ native v8natives.js:367" -snapshot-code-name,448794,"LazyCompile:~$Array.configurable_ native v8natives.js:370" -snapshot-code-name,449360,"LazyCompile:~$Array.configurable_ native v8natives.js:374" -snapshot-code-name,449824,"LazyCompile:~$Array.configurable_ native v8natives.js:377" -snapshot-code-name,450289,"LazyCompile:~$Array.get_ native v8natives.js:380" -snapshot-code-name,450841,"LazyCompile:~$Array.get_ native v8natives.js:384" -snapshot-code-name,451305,"LazyCompile:~$Array.get_ native v8natives.js:387" -snapshot-code-name,451769,"LazyCompile:~$Array.set_ native v8natives.js:390" -snapshot-code-name,452321,"LazyCompile:~$Array.set_ native v8natives.js:394" -snapshot-code-name,452785,"LazyCompile:~$Array.set_ native v8natives.js:397" -snapshot-code-name,453451,"LazyCompile:~ native v8natives.js:407" -snapshot-code-name,454156,"Script:~native date.js" -snapshot-code-name,460951,"LazyCompile:~DateConstructor native date.js:61" -snapshot-code-name,473464,"LazyCompile:~SetUpDate native date.js:488" -snapshot-code-name,478931,"Script:~native arraybuffer.js" -snapshot-code-name,479506,"LazyCompile:~ArrayBufferConstructor native arraybuffer.js:4" -snapshot-code-name,481548,"LazyCompile:~SetUpArrayBuffer native arraybuffer.js:53" -snapshot-code-name,483290,"Script:~native runtime.js" -snapshot-code-name,484412,"LazyCompile:~EQUALS native runtime.js:9" -snapshot-code-name,491541,"LazyCompile:~STRICT_EQUALS native runtime.js:55" -snapshot-code-name,492355,"LazyCompile:~COMPARE native runtime.js:66" -snapshot-code-name,494343,"LazyCompile:~ADD native runtime.js:98" -snapshot-code-name,495797,"LazyCompile:~STRING_ADD_LEFT native runtime.js:111" -snapshot-code-name,496994,"LazyCompile:~STRING_ADD_RIGHT native runtime.js:123" -snapshot-code-name,498192,"LazyCompile:~SUB native runtime.js:136" -snapshot-code-name,498999,"LazyCompile:~MUL native runtime.js:141" -snapshot-code-name,499762,"LazyCompile:~DIV native runtime.js:146" -snapshot-code-name,500525,"LazyCompile:~MOD native runtime.js:151" -snapshot-code-name,501288,"LazyCompile:~BIT_OR native runtime.js:156" -snapshot-code-name,502052,"LazyCompile:~BIT_AND native runtime.js:161" -snapshot-code-name,503049,"LazyCompile:~BIT_XOR native runtime.js:173" -snapshot-code-name,503814,"LazyCompile:~SHL native runtime.js:178" -snapshot-code-name,504580,"LazyCompile:~SAR native runtime.js:183" -snapshot-code-name,505577,"LazyCompile:~SHR native runtime.js:195" -snapshot-code-name,506342,"LazyCompile:~DELETE native runtime.js:200" -snapshot-code-name,506995,"LazyCompile:~IN native runtime.js:203" -snapshot-code-name,508015,"LazyCompile:~INSTANCE_OF native runtime.js:210" -snapshot-code-name,509644,"LazyCompile:~FILTER_KEY native runtime.js:228" -snapshot-code-name,510273,"LazyCompile:~CALL_NON_FUNCTION native runtime.js:233" -snapshot-code-name,511270,"LazyCompile:~CALL_NON_FUNCTION_AS_CONSTRUCTOR native runtime.js:240" -snapshot-code-name,512214,"LazyCompile:~CALL_FUNCTION_PROXY native runtime.js:247" -snapshot-code-name,512911,"LazyCompile:~CALL_FUNCTION_PROXY_AS_CONSTRUCTOR native runtime.js:253" -snapshot-code-name,513533,"LazyCompile:~APPLY_PREPARE native runtime.js:258" -snapshot-code-name,515943,"LazyCompile:~APPLY_OVERFLOW native runtime.js:280" -snapshot-code-name,516591,"LazyCompile:~TO_OBJECT native runtime.js:283" -snapshot-code-name,517110,"LazyCompile:~TO_NUMBER native runtime.js:286" -snapshot-code-name,517629,"LazyCompile:~TO_STRING native runtime.js:289" -snapshot-code-name,518116,"LazyCompile:~ToPrimitive native runtime.js:292" -snapshot-code-name,519639,"LazyCompile:~ToBoolean native runtime.js:299" -snapshot-code-name,520566,"LazyCompile:~ToNumber native runtime.js:306" -snapshot-code-name,521771,"LazyCompile:~ToString native runtime.js:327" -snapshot-code-name,523097,"LazyCompile:~ToName native runtime.js:342" -snapshot-code-name,523661,"LazyCompile:~ToObject native runtime.js:345" -snapshot-code-name,525284,"LazyCompile:~SameValue native runtime.js:367" -snapshot-code-name,527315,"Script:~native uri.js" -snapshot-code-name,532943,"LazyCompile:~SetUpUri native uri.js:312" -snapshot-code-name,534118,"Script:~native typedarray.js" -snapshot-code-name,546025,"LazyCompile:~Uint8ArrayConstructor native typedarray.js:71" -snapshot-code-name,547828,"LazyCompile:~Int8ArrayConstructor native typedarray.js:153" -snapshot-code-name,549639,"LazyCompile:~Uint16ArrayConstructor native typedarray.js:235" -snapshot-code-name,551442,"LazyCompile:~Int16ArrayConstructor native typedarray.js:317" -snapshot-code-name,553253,"LazyCompile:~Uint32ArrayConstructor native typedarray.js:399" -snapshot-code-name,555056,"LazyCompile:~Int32ArrayConstructor native typedarray.js:481" -snapshot-code-name,556867,"LazyCompile:~Float32ArrayConstructor native typedarray.js:563" -snapshot-code-name,558678,"LazyCompile:~Float64ArrayConstructor native typedarray.js:645" -snapshot-code-name,560513,"LazyCompile:~Uint8ClampedArrayConstructor native typedarray.js:727" -snapshot-code-name,562254,"LazyCompile:~CreateSubArray native typedarray.js:755" -snapshot-code-name,563425,"LazyCompile:~SetupTypedArray native typedarray.js:867" -snapshot-code-name,565392,"LazyCompile:~DataViewConstructor native typedarray.js:907" -snapshot-code-name,569998,"LazyCompile:~SetupDataView native typedarray.js:1167" -snapshot-code-name,573047,"Script:~native json.js" -snapshot-code-name,576118,"LazyCompile:~SetUpJSON native json.js:192" -snapshot-code-name,577237,"Script:~native object-observe.js" -snapshot-code-name,583083,"LazyCompile:~nullProtoObject native object-observe.js:68" -snapshot-code-name,583654,"LazyCompile:~TypeMapCreate native object-observe.js:71" -snapshot-code-name,584174,"LazyCompile:~TypeMapAddType native object-observe.js:74" -snapshot-code-name,584568,"Builtin:KeyedStoreIC_PreMonomorphic_Strict" -snapshot-code-name,585062,"LazyCompile:~TypeMapCreateFromList native object-observe.js:80" -snapshot-code-name,591515,"LazyCompile:~SetupObjectObserve native object-observe.js:456" -snapshot-code-name,593407,"Script:~native messages.js" -snapshot-code-name,597623,"LazyCompile:FormatString native messages.js:152" -snapshot-code-name,600680,"Stub:BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -snapshot-code-name,609289,"LazyCompile:~MakeGenericError native messages.js:234" -snapshot-code-name,610028,"LazyCompile:~FormatMessage native messages.js:244" -snapshot-code-name,611056,"LazyCompile:~MakeRangeError native messages.js:268" -snapshot-code-name,616837,"LazyCompile:~captureStackTrace native messages.js:808" -snapshot-code-name,618428,"LazyCompile:~SetUpError native messages.js:832" -snapshot-code-name,619210,"LazyCompile:~SetUpError.a native messages.js:833" -snapshot-code-name,620479,"Stub:BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -snapshot-code-name,620728,"LazyCompile:~d native messages.js:838" -snapshot-code-name,621278,"LazyCompile:~ native messages.js:848" -snapshot-code-name,623976,"LazyCompile:~SetUpStackOverflowBoilerplate native messages.js:922" -snapshot-code-name,624792,"Stub:BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -snapshot-code-name,624997,"Stub:BinaryOpICWithAllocationSiteStub(ADD_CreateAllocationMementos:String*String->String)" -snapshot-code-name,648645,"LazyCompile:~ native messages.js:241" -snapshot-code-name,652108,"Builtin:Illegal" -snapshot-code-name,652278,"Builtin:ArrayPush" -snapshot-code-name,652445,"Builtin:ArrayPop" -snapshot-code-name,652612,"Builtin:ArrayShift" -snapshot-code-name,652779,"Builtin:ArrayUnshift" -snapshot-code-name,652946,"Builtin:ArraySlice" -snapshot-code-name,653113,"Builtin:ArraySplice" -snapshot-code-name,653280,"Builtin:ArrayConcat" -snapshot-code-name,653447,"Builtin:HandleApiCall" -snapshot-code-name,653614,"Builtin:HandleApiCallConstruct" -snapshot-code-name,653781,"Builtin:HandleApiCallAsFunction" -snapshot-code-name,653948,"Builtin:HandleApiCallAsConstructor" -snapshot-code-name,654115,"Builtin:StrictModePoisonPill" -snapshot-code-name,654286,"Builtin:InOptimizationQueue" -snapshot-code-name,654521,"Builtin:JSConstructStubCountdown" -snapshot-code-name,655270,"Builtin:JSConstructStubApi" -snapshot-code-name,655940,"Builtin:JSEntryTrampoline" -snapshot-code-name,656201,"Builtin:JSConstructEntryTrampoline" -snapshot-code-name,656432,"Builtin:CompileOptimized" -snapshot-code-name,656668,"Builtin:CompileOptimizedConcurrent" -snapshot-code-name,656904,"Builtin:NotifyDeoptimized" -snapshot-code-name,657180,"Builtin:NotifySoftDeoptimized" -snapshot-code-name,657456,"Builtin:NotifyLazyDeoptimized" -snapshot-code-name,657732,"Builtin:NotifyStubFailure" -snapshot-code-name,657966,"Builtin:NotifyStubFailureSaveDoubles" -snapshot-code-name,658204,"Builtin:KeyedLoadIC_Miss" -snapshot-code-name,658371,"Builtin:StoreIC_Miss" -snapshot-code-name,658538,"Builtin:KeyedStoreIC_Miss" -snapshot-code-name,658705,"Builtin:LoadIC_Getter_ForDeopt" -snapshot-code-name,658904,"Builtin:KeyedLoadIC_Generic" -snapshot-code-name,660013,"Builtin:KeyedLoadIC_String" -snapshot-code-name,660865,"Builtin:KeyedLoadIC_IndexedInterceptor" -snapshot-code-name,661106,"Builtin:KeyedLoadIC_SloppyArguments" -snapshot-code-name,661481,"Builtin:StoreIC_Setter_ForDeopt" -snapshot-code-name,661676,"Builtin:KeyedStoreIC_PreMonomorphic" -snapshot-code-name,661844,"Builtin:KeyedStoreIC_Generic" -snapshot-code-name,665085,"Builtin:KeyedStoreIC_Initialize_Strict" -snapshot-code-name,665256,"Builtin:KeyedStoreIC_Generic_Strict" -snapshot-code-name,668497,"Builtin:KeyedStoreIC_SloppyArguments" -snapshot-code-name,668979,"Builtin:FunctionCall" -snapshot-code-name,669518,"Builtin:FunctionApply" -snapshot-code-name,670045,"Builtin:InternalArrayCode" -snapshot-code-name,670207,"Builtin:ArrayCode" -snapshot-code-name,670370,"Builtin:StringConstructCode" -snapshot-code-name,670959,"Builtin:OnStackReplacement" -snapshot-code-name,671197,"Builtin:OsrAfterStackCheck" -snapshot-code-name,671438,"Builtin:MarkCodeAsExecutedOnce" -snapshot-code-name,671697,"Builtin:MarkCodeAsExecutedTwice" -snapshot-code-name,671956,"Builtin:MakeQuadragenarianCodeYoungAgainOddMarking" -snapshot-code-name,672215,"Builtin:MakeQuadragenarianCodeYoungAgainEvenMarking" -snapshot-code-name,672474,"Builtin:MakeQuinquagenarianCodeYoungAgainOddMarking" -snapshot-code-name,672733,"Builtin:MakeQuinquagenarianCodeYoungAgainEvenMarking" -snapshot-code-name,672992,"Builtin:MakeSexagenarianCodeYoungAgainOddMarking" -snapshot-code-name,673251,"Builtin:MakeSexagenarianCodeYoungAgainEvenMarking" -snapshot-code-name,673510,"Builtin:MakeSeptuagenarianCodeYoungAgainOddMarking" -snapshot-code-name,673769,"Builtin:MakeSeptuagenarianCodeYoungAgainEvenMarking" -snapshot-code-name,674028,"Builtin:MakeOctogenarianCodeYoungAgainOddMarking" -snapshot-code-name,674287,"Builtin:MakeOctogenarianCodeYoungAgainEvenMarking" -snapshot-code-name,674546,"Builtin:LoadIC_Slow" -snapshot-code-name,674713,"Builtin:KeyedLoadIC_Slow" -snapshot-code-name,674880,"Builtin:StoreIC_Slow" -snapshot-code-name,675047,"Builtin:KeyedStoreIC_Slow" -snapshot-code-name,675214,"Builtin:LoadIC_Normal" -snapshot-code-name,675643,"Builtin:StoreIC_Normal" -snapshot-code-name,676154,"Builtin:CallFunctionStub_DebugBreak" -snapshot-code-name,676391,"Builtin:CallFunctionStub_Recording_DebugBreak" -snapshot-code-name,676628,"Builtin:CallConstructStub_DebugBreak" -snapshot-code-name,676897,"Builtin:CallConstructStub_Recording_DebugBreak" -snapshot-code-name,677166,"Builtin:LoadIC_DebugBreak" -snapshot-code-name,677403,"Builtin:KeyedLoadIC_DebugBreak" -snapshot-code-name,677640,"Builtin:StoreIC_DebugBreak" -snapshot-code-name,677877,"Builtin:KeyedStoreIC_DebugBreak" -snapshot-code-name,678114,"Builtin:CompareNilIC_DebugBreak" -snapshot-code-name,678355,"Builtin:PlainReturn_LiveEdit" -snapshot-code-name,678504,"Builtin:FrameDropper_LiveEdit" -snapshot-code-name,681683,"Function:~sampleFunction app.bin:7" -snapshot-code-name,682396,"Function:~ app.bin:3" diff --git a/tests/automation/user-agent-app/mocha_test.js b/tests/automation/user-agent-app/mocha_test.js index f4954e4ccb..a395d0c7b9 100644 --- a/tests/automation/user-agent-app/mocha_test.js +++ b/tests/automation/user-agent-app/mocha_test.js @@ -25,10 +25,10 @@ describe('user-agent-app', function() { setTimeout(function(){ if (!result) { - child.close(); + child.kill(); done('loaded event does not been fired'); } - }, 10000); + }, 7000); }); From 5315fc2ecb936a15349b8ebfde089f5b821f571f Mon Sep 17 00:00:00 2001 From: yejingfu Date: Tue, 2 Dec 2014 16:36:12 +0800 Subject: [PATCH 347/492] Fix automation bugs, more test case would be run smoothly. Update failure list. --- tests/automation/config.json | 6 +--- tests/automation/console/internal/index.html | 4 +-- tests/automation/console/mocha_test.js | 4 +++ tests/automation/crash_dump/mocha_test.js | 15 +++++++-- tests/automation/failures.md | 31 +++++++++++++++++-- tests/automation/node/mocha_test.js | 23 +++++++++----- .../source-maps/internal/index.html | 14 ++++----- tests/automation/source-maps/mocha_test.js | 10 +++++- 8 files changed, 80 insertions(+), 27 deletions(-) diff --git a/tests/automation/config.json b/tests/automation/config.json index 55129e7dae..bccfd0d0ac 100644 --- a/tests/automation/config.json +++ b/tests/automation/config.json @@ -1,11 +1,7 @@ { "format": "xunit-file", "exclude": ["node_modules", "output", "internal", "res", "app", "node-remote", "save_devtools_settings", "single_instance", - "source-maps", "temp_dir", - "call_require_with_node-main_set", "show_devtool_after_http_server_created_in_node_main", "reference-node-main", - "start_app", "chromedriver2_server", "console", "crash_dump", "datapath", "fast_open_and_close_devtools", - "loaded_event", "node", "nw-in-mem", "process", "quit_with_secondary_window_on_top", "reload_application" -], + "call_require_with_node-main_set", "show_devtool_after_http_server_created_in_node_main", "reference-node-main"], "single": "", "timeout": "8000", "slow": "200", diff --git a/tests/automation/console/internal/index.html b/tests/automation/console/internal/index.html index 1fd95c72f0..b7c3e037d4 100644 --- a/tests/automation/console/internal/index.html +++ b/tests/automation/console/internal/index.html @@ -59,7 +59,7 @@ iframe_devtools.width = '1000'; function get_results() { - var console_logs = devtools.document.getElementsByClassName('console-log-level'); + var console_logs = devtools.getElementsByClassName('console-log-level'); for (var i = 0; i < console_logs.length; i++) results.push(console_logs[i].childNodes[0].childNodes[0].innerHTML); @@ -70,7 +70,7 @@ } function get_console_logs() { - var console_msgs = devtools.document.getElementsByClassName('console'); + var console_msgs = devtools.getElementsByClassName('console'); if(console_msgs == undefined || console_msgs[0] == undefined || console_msgs[0].click == undefined) diff --git a/tests/automation/console/mocha_test.js b/tests/automation/console/mocha_test.js index 17ec39a5c0..9775adb7c5 100644 --- a/tests/automation/console/mocha_test.js +++ b/tests/automation/console/mocha_test.js @@ -43,6 +43,10 @@ describe('console.log', function() { }); }); + setTimeout(function() { + done('timeout'); + }, 4500); + }); after(function(done){ diff --git a/tests/automation/crash_dump/mocha_test.js b/tests/automation/crash_dump/mocha_test.js index 5939393fe6..9136221a03 100644 --- a/tests/automation/crash_dump/mocha_test.js +++ b/tests/automation/crash_dump/mocha_test.js @@ -16,10 +16,21 @@ describe('crash dump', function() { var server; before(function(done) { - if (!fs.existsSync(tmpDir)) - fs.mkdirSync(tmpDir); + + var ready = function() { + fs.mkdirSync(tmpDir); server = createTCPServer(13013); done(); + }; + + if (fs.existsSync(tmpDir)) { + fs_extra.remove(tmpDir, function() { + ready(); + }); + } else { + ready(); + } + }); after(function () { diff --git a/tests/automation/failures.md b/tests/automation/failures.md index e3622911ff..6823a8072a 100644 --- a/tests/automation/failures.md +++ b/tests/automation/failures.md @@ -1,16 +1,41 @@ Failed test cases ======================= -* cookies_api + + +* chromedriver2_server + +* chromium-args + +* console + +* cookies_api (bad bad bad) * document_cookies -* website +* node + +* node-remote + +* process + +* reload_application + +* save_devtools_settings + +* single_instance + +* source-maps + +* temp_dir * user-agent * user-agent-app -* chromium-args +* website + + + diff --git a/tests/automation/node/mocha_test.js b/tests/automation/node/mocha_test.js index d9d8034d12..f853a5218f 100644 --- a/tests/automation/node/mocha_test.js +++ b/tests/automation/node/mocha_test.js @@ -190,38 +190,47 @@ describe('performance', function() { }); }); + describe('IO', function() { var fs = require('fs'); var path = require('path'); var exec = require('child_process').exec; var tar = require('tar'); + var result = false; it('file reading should be quick even when we have a child process running', function(done) { - this.timeout(100); - exec('sleep 1000', function () { }); + this.timeout(0); var mochaPath = path.join(curDir, 'mocha_test.js'); fs.readFile(mochaPath, 'utf8', function(err, data) { + result = true; done(); }); + + setTimeout(function() { + if (!result) done('timeout'); + }, 1000); }); it('untar a file should be quick', function(done) { this.timeout(100); var testPath = path.join(curDir, 'test.tar'); fs.createReadStream(testPath) - .pipe(tar.Extract({ path: 'ddtmp' })) + .pipe(tar.Extract({ path: 'tmp' })) .on('error', function (er) { assert.equal(false, true); }) .on('end', function () { - var content = fs.readFileSync('ddtmp/text', 'utf8'); - assert.equal(content, 'I love luyao\n'); - fs.unlinkSync('ddtmp/text'); - fs.rmdirSync('ddtmp'); + var content = fs.readFileSync('tmp/text', 'utf8'); + assert.equal(content, 'I love luyao\n'); // who is luyao ? + fs.unlinkSync('tmp/text'); + fs.rmdirSync('tmp'); done(); }); }); + }); + + }); ///////////////////////////// 5 diff --git a/tests/automation/source-maps/internal/index.html b/tests/automation/source-maps/internal/index.html index 60dd34da75..8d22e007a0 100644 --- a/tests/automation/source-maps/internal/index.html +++ b/tests/automation/source-maps/internal/index.html @@ -24,7 +24,7 @@ iframe_devtools.width = '1000'; function get_scripts() { - var scripts = devtools.document.getElementsByClassName('scripts'); + var scripts = devtools.getElementsByClassName('scripts'); if(scripts == undefined || scripts[0] == undefined || scripts[0].click == undefined) @@ -34,17 +34,17 @@ devtools.WebInspector.SettingsController.prototype.showSettingsScreen(); // source map feature must be enabled first // We cannot to reload it automatically or it will crash - if(!devtools.document.getElementsByName('Enable JS source maps')[0].checked || !devtools.document.getElementsByName('Enable CSS source maps')[0].checked) { - devtools.document.getElementsByName('Enable JS source maps')[0].checked = true; - devtools.document.getElementsByName('Enable CSS source maps')[0].checked = true; + if(!devtools.getElementsByName('Enable JS source maps')[0].checked || !devtools.document.getElementsByName('Enable CSS source maps')[0].checked) { + devtools.getElementsByName('Enable JS source maps')[0].checked = true; + devtools.getElementsByName('Enable CSS source maps')[0].checked = true; } else { // open scripts panel scripts[0].click(); - devtools.document.getElementsByClassName('scripts-navigator-show-hide-button')[0].click(); - devtools.document.getElementsByClassName('parent navigator-folder-tree-item')[1].treeElement.expand(); - var scripts_files = devtools.document.getElementsByClassName('navigator-script-tree-item'); + devtools.getElementsByClassName('scripts-navigator-show-hide-button')[0].click(); + devtools.getElementsByClassName('parent navigator-folder-tree-item')[1].treeElement.expand(); + var scripts_files = devtools.getElementsByClassName('navigator-script-tree-item'); for (var i = 0; i < scripts_files.length; i++) results.push(scripts_files[i].childNodes[2].innerHTML); diff --git a/tests/automation/source-maps/mocha_test.js b/tests/automation/source-maps/mocha_test.js index 7d0ae72327..f7144463c3 100644 --- a/tests/automation/source-maps/mocha_test.js +++ b/tests/automation/source-maps/mocha_test.js @@ -6,7 +6,7 @@ var curDir = fs.realpathSync('.'); describe('source maps', function() { - var server, child, results; + var server, child, results, ok = false; before(function(done) { this.timeout(0); @@ -15,12 +15,20 @@ describe('source maps', function() { server.on('connection', function(socket) { socket.setEncoding('utf8'); socket.on('data', function(data) { + ok = true; results = JSON.parse(data); child.kill(); done(); }); }); + setTimeout(function() { + if (!ok) { + child.kill(); + done('timeout'); + } + }, 4500); + }); after(function () { From d217a8e25f6c7dbb004f52321d48af81e16ab51d Mon Sep 17 00:00:00 2001 From: yejingfu Date: Tue, 2 Dec 2014 16:50:59 +0800 Subject: [PATCH 348/492] Fix automation minor bugs. --- tests/automation/app/index.html | 30 +++++++---------- tests/automation/app/index2.html | 33 ------------------- tests/automation/app/mocha_test.js | 53 ++++++++++++++++++++---------- tests/automation/app/package.json | 5 +-- tests/automation/config.json | 2 +- tests/automation/failures.md | 2 +- 6 files changed, 53 insertions(+), 72 deletions(-) delete mode 100644 tests/automation/app/index2.html diff --git a/tests/automation/app/index.html b/tests/automation/app/index.html index 808e75c8d6..893dc667f5 100644 --- a/tests/automation/app/index.html +++ b/tests/automation/app/index.html @@ -1,22 +1,16 @@ - - - - Test Case for 'App.clearCache' - - -

                      Please wait to be closed.

                      - - - + + + + app test + + +

                      app test

                      + + + + + diff --git a/tests/automation/app/index2.html b/tests/automation/app/index2.html deleted file mode 100644 index 99c17b5c12..0000000000 --- a/tests/automation/app/index2.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - Test Case for 'App.clearCache' - - -

                      Please wait to be closed.

                      - - - - - diff --git a/tests/automation/app/mocha_test.js b/tests/automation/app/mocha_test.js index b3bec638c2..09ab7c488c 100644 --- a/tests/automation/app/mocha_test.js +++ b/tests/automation/app/mocha_test.js @@ -1,25 +1,44 @@ var gui = require('nw.gui'); +var path = require('path'); var assert = require('assert'); -var app_test = require('../../nw_test_app'); -//var local_server = require('../../server/server'); -var global = require('../globals'); +var fs = require('fs-extra'); +var curDir = fs.realpathSync('.'); describe('gui.App', function() { - before(function(done) { - this.timeout(0); - var checkDone = function() { - if (test_done) - done(); - else - setTimeout(function() {checkDone();}, 2000); - } - checkDone(); + + var server, child, result = false; + + before(function(done) { + this.timeout(0); + server = createTCPServer(13013); + child = spawnChildProcess(path.join(curDir, 'internal')); + server.on('connection', function(socket) { + socket.setEncoding('utf8'); + socket.on('data', function(data) { + result = true; + child.kill(); + done(); + }); }); + setTimeout(function() { + if (!result) { + child.kill(); + done('timeout'); + } + }, 4500); + + }); + + after(function () { + server.close(); + }); + + describe('manifest', function() { it('`gui.App.manifest` should equle to value of package.json', function() { - assert.equal(gui.App.manifest.name, 'nw-gui.App-test'); + assert.equal(gui.App.manifest.name, 'nw-gui.App-test.wrapper'); }); it('have main', function() { @@ -27,7 +46,7 @@ describe('gui.App', function() { assert.equal(gui.App.manifest.main, 'index.html'); }); -/* + it('have window', function() { console.log('====have window:' + typeof gui.App.manifest.window); assert.equal(typeof gui.App.manifest.window, 'object'); @@ -36,9 +55,9 @@ describe('gui.App', function() { it('have dependencies', function() { assert.equal(typeof gui.App.manifest.dependencies, 'object'); }); -*/ + }); -/* + describe('clearCache()', function(done) { it('should clear the HTTP cache in memory and the one on disk', function() { var res_save = global.local_server.res_save; @@ -49,7 +68,7 @@ describe('gui.App', function() { assert.equal(res_save[2].pathname, 'img.jpg'); }); }); -*/ + }); diff --git a/tests/automation/app/package.json b/tests/automation/app/package.json index 8509f5d10e..b76d2e98ac 100644 --- a/tests/automation/app/package.json +++ b/tests/automation/app/package.json @@ -1,4 +1,5 @@ { - "name": "nw-gui.App-test", - "main": "index.html" + "name":"nw-gui.App-test.wrapper", + "main":"index.html" } + diff --git a/tests/automation/config.json b/tests/automation/config.json index bccfd0d0ac..03f8af248b 100644 --- a/tests/automation/config.json +++ b/tests/automation/config.json @@ -1,6 +1,6 @@ { "format": "xunit-file", - "exclude": ["node_modules", "output", "internal", "res", "app", "node-remote", "save_devtools_settings", "single_instance", + "exclude": ["node_modules", "output", "internal", "res", "node-remote", "save_devtools_settings", "single_instance", "call_require_with_node-main_set", "show_devtool_after_http_server_created_in_node_main", "reference-node-main"], "single": "", "timeout": "8000", diff --git a/tests/automation/failures.md b/tests/automation/failures.md index 6823a8072a..71d49ff7d2 100644 --- a/tests/automation/failures.md +++ b/tests/automation/failures.md @@ -1,7 +1,7 @@ Failed test cases ======================= - +* app * chromedriver2_server From 8ad7050e181f1bfd7ace79236d2152b2e548a92c Mon Sep 17 00:00:00 2001 From: Jimi Ford Date: Fri, 5 Dec 2014 11:34:23 -0500 Subject: [PATCH 349/492] Update README.md Minor grammar error --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d4464605cb..9eb46b822b 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ It's created and developed in the Intel Open Source Technology Center. * Apps written in modern HTML5, CSS3, JS and WebGL. * Complete support for [Node.js APIs](http://nodejs.org/api/) and all its [third party modules](https://npmjs.org). -* Good performance: Node and WebKit runs in the same thread: Function calls are made straightforward; objects are in the same heap and can just reference each other; +* Good performance: Node and WebKit run in the same thread: Function calls are made straightforward; objects are in the same heap and can just reference each other; * Easy to package and distribute apps. * Available on Linux, Mac OS X and Windows From fd240ae64ac0daed0e83c390f6894889181644a0 Mon Sep 17 00:00:00 2001 From: Marco Fabbri Date: Tue, 9 Dec 2014 16:39:47 +0100 Subject: [PATCH 350/492] [OSX] Fix alticon property of Tray not being updated properly - Fix the setter of the `alticon` property (typo in method name). Fix rogerwang/node-webkit#703 --- src/api/tray/tray.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/api/tray/tray.js b/src/api/tray/tray.js index 4f55cbfd94..5e4d6064cc 100644 --- a/src/api/tray/tray.js +++ b/src/api/tray/tray.js @@ -100,7 +100,7 @@ Tray.prototype.__defineSetter__('icon', function(val) { Tray.prototype.__defineSetter__('alticon', function(val) { v8_util.getHiddenValue(this, 'option').shadowAlticon = String(val); var real_path = val == '' ? '' : nw.getAbsolutePath(val); - this.handleSetter('alticon', 'SetAlticon', String, real_path); + this.handleSetter('alticon', 'SetAltIcon', String, real_path); }); Tray.prototype.__defineGetter__('tooltip', function() { From 92ec44c78bb272a3487c116e7de5de769c501760 Mon Sep 17 00:00:00 2001 From: Marco Fabbri Date: Tue, 9 Dec 2014 00:22:56 +0100 Subject: [PATCH 351/492] [OSX] Add iconsAreTemplates property to Tray API objects Add boolean property (defaults to `true`) `iconsAreTemplates` to `Tray` objects to allow for proper display of icons in Mac OS X (Yosemite) Dark Menus. When `iconsAreTemplates` is set to true, both `icon` and `altIcon` are treated as "templates" and the system automatically ensures proper styling according to the various states of the status item (e.g. dark menu, light menu, etc.). Template images should consist only of black and clear colours and can use the alpha channel in the image to adjust the opacity of black content. See [Dark Menus in AppKit Release Notes for OS X v10.10](https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKit/#10_10DarkMenus) and [`NSImage setTemplate:`](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSImage_Class/index.html#//apple_ref/occ/instm/NSImage/setTemplate:). On Linux and Windows setting the property has no effect. FIX rogerwang/node-webkit#2476 --- src/api/tray/tray.cc | 8 ++++++++ src/api/tray/tray.h | 3 +++ src/api/tray/tray.js | 13 +++++++++++++ src/api/tray/tray_aura.cc | 3 +++ src/api/tray/tray_gtk.cc | 3 +++ src/api/tray/tray_mac.mm | 12 ++++++++++++ 6 files changed, 42 insertions(+) diff --git a/src/api/tray/tray.cc b/src/api/tray/tray.cc index 2371b10cc6..5d8bdbeb7d 100644 --- a/src/api/tray/tray.cc +++ b/src/api/tray/tray.cc @@ -37,6 +37,10 @@ Tray::Tray(int id, if (option.GetString("title", &title)) SetTitle(title); + bool areTemplates; + if (option.GetBoolean("iconsAreTemplates", &areTemplates)) + SetIconsAreTemplates(areTemplates); + std::string icon; if (option.GetString("icon", &icon) && !icon.empty()) SetIcon(icon); @@ -74,6 +78,10 @@ void Tray::Call(const std::string& method, std::string alticon; arguments.GetString(0, &alticon); SetAltIcon(alticon); + } else if (method == "SetIconsAreTemplates") { + bool areTemplates; + arguments.GetBoolean(0, &areTemplates); + SetIconsAreTemplates(areTemplates); } else if (method == "SetTooltip") { std::string tooltip; arguments.GetString(0, &tooltip); diff --git a/src/api/tray/tray.h b/src/api/tray/tray.h index 8f54eccb99..6795e59e5d 100644 --- a/src/api/tray/tray.h +++ b/src/api/tray/tray.h @@ -69,10 +69,13 @@ class Tray : public Base { void Remove(); // Alternate icons only work with Macs void SetAltIcon(const std::string& alticon_path); + // Template icons only work with Macs + void SetIconsAreTemplates(bool areTemplates); #if defined(OS_MACOSX) __block NSStatusItem* status_item_; MacTrayObserver* status_observer_; + bool iconsAreTemplates; #elif 0 GtkStatusIcon* status_item_; diff --git a/src/api/tray/tray.js b/src/api/tray/tray.js index 4f55cbfd94..512dfb961e 100644 --- a/src/api/tray/tray.js +++ b/src/api/tray/tray.js @@ -42,6 +42,11 @@ function Tray(option) { option.alticon = nw.getAbsolutePath(option.alticon); } + if (option.hasOwnProperty('iconsAreTemplates')) + option.iconsAreTemplates = Boolean(option.iconsAreTemplates); + else + option.iconsAreTemplates = true; + if (option.hasOwnProperty('tooltip')) option.tooltip = String(option.tooltip); @@ -103,6 +108,14 @@ Tray.prototype.__defineSetter__('alticon', function(val) { this.handleSetter('alticon', 'SetAlticon', String, real_path); }); +Tray.prototype.__defineGetter__('iconsAreTemplates', function() { + return this.handleGetter('iconsAreTemplates'); +}); + +Tray.prototype.__defineSetter__('iconsAreTemplates', function(val) { + this.handleSetter('iconsAreTemplates', 'SetIconsAreTemplates', Boolean, val); +}); + Tray.prototype.__defineGetter__('tooltip', function() { return this.handleGetter('tooltip'); }); diff --git a/src/api/tray/tray_aura.cc b/src/api/tray/tray_aura.cc index 4c0c677da1..404530c8a2 100644 --- a/src/api/tray/tray_aura.cc +++ b/src/api/tray/tray_aura.cc @@ -107,4 +107,7 @@ void Tray::Remove() { void Tray::SetAltIcon(const std::string& alticon_path) { } +void Tray::SetIconsAreTemplates(bool areTemplates) { +} + } // namespace nwapi diff --git a/src/api/tray/tray_gtk.cc b/src/api/tray/tray_gtk.cc index 33a9078e6d..12b5990ef2 100644 --- a/src/api/tray/tray_gtk.cc +++ b/src/api/tray/tray_gtk.cc @@ -83,4 +83,7 @@ void Tray::OnPopupMenu(GtkWidget* widget, guint button, guint time) { void Tray::SetAltIcon(const std::string& alticon_path) { } +void Tray::SetIconsAreTemplates(bool areTemplates) { +} + } // namespace nwapi diff --git a/src/api/tray/tray_mac.mm b/src/api/tray/tray_mac.mm index c983063883..26dc56910a 100644 --- a/src/api/tray/tray_mac.mm +++ b/src/api/tray/tray_mac.mm @@ -72,6 +72,7 @@ - (void)onClick:(id)sender { if (!icon.empty()) { NSImage* image = [[NSImage alloc] initWithContentsOfFile:[NSString stringWithUTF8String:icon.c_str()]]; + [image setTemplate:iconsAreTemplates]; [status_item_ setImage:image]; [image release]; } else { @@ -83,6 +84,7 @@ - (void)onClick:(id)sender { if (!alticon.empty()) { NSImage* image = [[NSImage alloc] initWithContentsOfFile:[NSString stringWithUTF8String:alticon.c_str()]]; + [image setTemplate:iconsAreTemplates]; [status_item_ setAlternateImage:image]; [image release]; } else { @@ -90,6 +92,16 @@ - (void)onClick:(id)sender { } } +void Tray::SetIconsAreTemplates(bool areTemplates) { + iconsAreTemplates = areTemplates; + if ([status_item_ image] != nil) { + [[status_item_ image] setTemplate:areTemplates]; + } + if ([status_item_ alternateImage] != nil) { + [[status_item_ alternateImage] setTemplate:areTemplates]; + } +} + void Tray::SetTooltip(const std::string& tooltip) { [status_item_ setToolTip:[NSString stringWithUTF8String:tooltip.c_str()]]; } From 0b3fda020606bfd5d6390db086fa558c9571c9da Mon Sep 17 00:00:00 2001 From: Marco Fabbri Date: Tue, 9 Dec 2014 16:17:38 +0100 Subject: [PATCH 352/492] [OSX] Add iconIsTemplate property to MenuItem API objects Add boolean property (defaults to `true`) `iconsIsTemplate` to `MenuItem` objects to allow for proper display of icons in Mac OS X (Yosemite) Dark Menus. When `iconsIsTemplate` is set to true, the `icon` is treated as a "template" and the system automatically ensures proper styling according to the various states of the menu item (e.g. dark menu, light menu, etc.). Template images should consist only of black and clear colours and can use the alpha channel in the image to adjust the opacity of black content. See [Dark Menus in AppKit Release Notes for OS X v10.10](https://developer.apple.com/library/mac/releasenotes/AppKit/RN-AppKit/#10_10DarkMenus) and [`NSImage setTemplate:`](https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ApplicationKit/Classes/NSImage_Class/index.html#//apple_ref/occ/instm/NSImage/setTemplate:). On Linux and Windows setting the property has no effect. FIX rogerwang/node-webkit#2773 --- src/api/menuitem/menuitem.cc | 4 ++++ src/api/menuitem/menuitem.h | 4 ++++ src/api/menuitem/menuitem.js | 13 +++++++++++++ src/api/menuitem/menuitem_gtk.cc | 3 +++ src/api/menuitem/menuitem_mac.mm | 11 +++++++++++ src/api/menuitem/menuitem_views.cc | 3 +++ 6 files changed, 38 insertions(+) diff --git a/src/api/menuitem/menuitem.cc b/src/api/menuitem/menuitem.cc index 2765e4ac0c..d6b6d1ae92 100644 --- a/src/api/menuitem/menuitem.cc +++ b/src/api/menuitem/menuitem.cc @@ -50,6 +50,10 @@ void MenuItem::Call(const std::string& method, std::string icon; arguments.GetString(0, &icon); SetIcon(icon); + } else if (method == "SetIconIsTemplate") { + bool isTemplate; + arguments.GetBoolean(0, &isTemplate); + SetIconIsTemplate(isTemplate); } else if (method == "SetTooltip") { std::string tooltip; arguments.GetString(0, &tooltip); diff --git a/src/api/menuitem/menuitem.h b/src/api/menuitem/menuitem.h index b1a5bc7e8e..6060b8a5db 100644 --- a/src/api/menuitem/menuitem.h +++ b/src/api/menuitem/menuitem.h @@ -82,11 +82,15 @@ class MenuItem : public Base { void SetChecked(bool checked); void SetSubmenu(Menu* sub_menu); + // Template icon works only on Mac OS X + void SetIconIsTemplate(bool isTemplate); + #if defined(OS_MACOSX) std::string type_; NSMenuItem* menu_item_; MenuItemDelegate* delegate_; + bool iconIsTemplate; #elif defined(OS_WIN) || defined(OS_LINUX) friend class MenuDelegate; diff --git a/src/api/menuitem/menuitem.js b/src/api/menuitem/menuitem.js index bacff28344..f0f1bd4e72 100644 --- a/src/api/menuitem/menuitem.js +++ b/src/api/menuitem/menuitem.js @@ -46,6 +46,11 @@ function MenuItem(option) { option.icon = nw.getAbsolutePath(option.icon); } + if (option.hasOwnProperty('iconIsTemplate')) + option.iconIsTemplate = Boolean(option.iconIsTemplate); + else + option.iconIsTemplate = true; + if (option.hasOwnProperty('tooltip')) option.tooltip = String(option.tooltip); @@ -116,6 +121,14 @@ MenuItem.prototype.__defineSetter__('icon', function(val) { this.handleSetter('icon', 'SetIcon', String, real_path); }); +MenuItem.prototype.__defineGetter__('iconIsTemplate', function() { + return this.handleGetter('iconIsTemplate'); +}); + +MenuItem.prototype.__defineSetter__('iconIsTemplate', function(val) { + this.handleSetter('iconIsTemplate', 'SetIconIsTemplate', Boolean, val); +}); + MenuItem.prototype.__defineGetter__('tooltip', function() { return this.handleGetter('tooltip'); }); diff --git a/src/api/menuitem/menuitem_gtk.cc b/src/api/menuitem/menuitem_gtk.cc index b9b4f39e7f..91955e2924 100644 --- a/src/api/menuitem/menuitem_gtk.cc +++ b/src/api/menuitem/menuitem_gtk.cc @@ -124,6 +124,9 @@ void MenuItem::SetIcon(const std::string& icon) { } } +void MenuItem::SetIconIsTemplate(bool isTemplate) { +} + void MenuItem::SetTooltip(const std::string& tooltip) { gtk_widget_set_tooltip_text(menu_item_, tooltip.c_str()); } diff --git a/src/api/menuitem/menuitem_mac.mm b/src/api/menuitem/menuitem_mac.mm index 36c8f6c55c..5d3e2960fc 100644 --- a/src/api/menuitem/menuitem_mac.mm +++ b/src/api/menuitem/menuitem_mac.mm @@ -71,6 +71,10 @@ if (option.GetBoolean("enabled", &enabled)) SetEnabled(enabled); + bool isTemplate; + if (option.GetBoolean("iconIsTemplate", &isTemplate)) + SetIconIsTemplate(isTemplate); + std::string icon; if (option.GetString("icon", &icon) && !icon.empty()) SetIcon(icon); @@ -131,6 +135,7 @@ if (!icon.empty()) { NSImage* image = [[NSImage alloc] initWithContentsOfFile:[NSString stringWithUTF8String:icon.c_str()]]; + [image setTemplate:iconIsTemplate]; [menu_item_ setImage:image]; [image release]; } else { @@ -138,6 +143,12 @@ } } +void MenuItem::SetIconIsTemplate(bool isTemplate) { + iconIsTemplate = isTemplate; + if ([menu_item_ image] != nil) + [[menu_item_ image] setTemplate:isTemplate]; +} + void MenuItem::SetTooltip(const std::string& tooltip) { [menu_item_ setToolTip:[NSString stringWithUTF8String:tooltip.c_str()]]; } diff --git a/src/api/menuitem/menuitem_views.cc b/src/api/menuitem/menuitem_views.cc index 20dcc4b6ee..238a7c46fc 100644 --- a/src/api/menuitem/menuitem_views.cc +++ b/src/api/menuitem/menuitem_views.cc @@ -134,6 +134,9 @@ void MenuItem::SetIcon(const std::string& icon) { package->GetImage(base::FilePath::FromUTF8Unsafe(icon), &icon_); } +void MenuItem::SetIconIsTemplate(bool isTemplate) { +} + void MenuItem::SetTooltip(const std::string& tooltip) { tooltip_ = base::UTF8ToUTF16(tooltip); if (menu_) From aa9e3935610b42335ff92857ce6497fd3ee1c2ff Mon Sep 17 00:00:00 2001 From: Marco Fabbri Date: Tue, 9 Dec 2014 21:34:09 +0100 Subject: [PATCH 353/492] [OSX] Fix Window.focus() not taking focus FIX rogerwang/node-webkit#2724 and also rogerwang/node-webkit#2735 --- src/browser/native_window_mac.mm | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/browser/native_window_mac.mm b/src/browser/native_window_mac.mm index 5d5f1fd94b..75454e7982 100644 --- a/src/browser/native_window_mac.mm +++ b/src/browser/native_window_mac.mm @@ -481,6 +481,8 @@ - (void)drawRect:(NSRect)dirtyRect { } void NativeWindowCocoa::Focus(bool focus) { + NSApplication *myApp = [NSApplication sharedApplication]; + [myApp activateIgnoringOtherApps:YES]; if (focus && [window() isVisible]) [window() makeKeyAndOrderFront:nil]; else From 4effdaf6a7487a12698edac162a7ef4859c11b54 Mon Sep 17 00:00:00 2001 From: Marco Fabbri Date: Sun, 14 Dec 2014 23:42:39 +0100 Subject: [PATCH 354/492] Extend Tray click event with position - Add a parameter to the `click` event of the `Tray` API object containing the coordinates of the tray icon/mouse pointer. The parameter has `x` and `y` fields for the coordinates. On Mac OS X the coordinates always refer to the position (lower left corner) of the tray item (NSStatusItem). On Aura (Linux, Windows) the coordinates refer to the cursor position (which would be inside the bounding box of the status icon but with slight differences depending on where effectively the user clicked). Usage example: tray.on('click', function(pos) { // pos.x is x coordinate of the tray icon // pos.y is y coordinate of the tray icon showCustomTrayMenuAt(pos); } FIX rogerwang/node-webkit#1874 --- src/api/tray/tray_aura.cc | 7 +++++++ src/api/tray/tray_mac.mm | 10 ++++++++++ 2 files changed, 17 insertions(+) diff --git a/src/api/tray/tray_aura.cc b/src/api/tray/tray_aura.cc index 404530c8a2..2dfdc2c85e 100644 --- a/src/api/tray/tray_aura.cc +++ b/src/api/tray/tray_aura.cc @@ -30,6 +30,7 @@ #include "content/nw/src/api/menu/menu.h" #include "content/nw/src/nw_package.h" #include "content/nw/src/nw_shell.h" +#include "ui/gfx/screen.h" #include "ui/gfx/image/image.h" namespace nwapi { @@ -47,6 +48,12 @@ class TrayObserver : public StatusIconObserver { virtual void OnStatusIconClicked() OVERRIDE { base::ListValue args; + base::DictionaryValue* data = new base::DictionaryValue; + gfx::Point cursor_pos( + gfx::Screen::GetNativeScreen()->GetCursorScreenPoint()); + data->SetInteger("x", cursor_pos.x()); + data->SetInteger("y", cursor_pos.y()); + args.Append(data); tray_->dispatcher_host()->SendEvent(tray_, "click", args); } diff --git a/src/api/tray/tray_mac.mm b/src/api/tray/tray_mac.mm index 26dc56910a..8ae519fd8a 100644 --- a/src/api/tray/tray_mac.mm +++ b/src/api/tray/tray_mac.mm @@ -22,6 +22,7 @@ #include "base/values.h" #import +#include "ui/gfx/screen.h" #include "content/nw/src/api/dispatcher_host.h" #include "content/nw/src/api/menu/menu.h" @@ -40,6 +41,15 @@ - (void)setBacking:(nwapi::Tray*)newTray { } - (void)onClick:(id)sender { base::ListValue args; + base::DictionaryValue* data = new base::DictionaryValue; + // Get the position of the frame of the NSStatusItem + NSPoint pos = ([[[NSApp currentEvent] window] frame]).origin; + // Flip coordinates to gfx (0,0 in top-left corner) using primary screen. + NSScreen* screen = [[NSScreen screens] objectAtIndex:0]; + pos.y = NSMaxY([screen frame]) - pos.y; + data->SetInteger("x", pos.x); + data->SetInteger("y", pos.y); + args.Append(data); tray_->dispatcher_host()->SendEvent(tray_,"click",args); } @end From 882b611bb82575b993e24a3b9c9aef5723d6a269 Mon Sep 17 00:00:00 2001 From: Marco Fabbri Date: Mon, 15 Dec 2014 00:08:00 +0100 Subject: [PATCH 355/492] Add manual test for position parameter in Tray click event - Add a manual test and an example usage (tray only application with a custom tray menu) of the position parameter in `Tray` `click` event as discussed in rogerwang/node-webkit#1874 --- .../custom_tray_menu/custom-tray-menu.html | 17 +++++++ tests/manual_tests/custom_tray_menu/icon.png | Bin 0 -> 3335 bytes .../manual_tests/custom_tray_menu/index.html | 48 ++++++++++++++++++ .../custom_tray_menu/package.json | 24 +++++++++ 4 files changed, 89 insertions(+) create mode 100644 tests/manual_tests/custom_tray_menu/custom-tray-menu.html create mode 100644 tests/manual_tests/custom_tray_menu/icon.png create mode 100644 tests/manual_tests/custom_tray_menu/index.html create mode 100644 tests/manual_tests/custom_tray_menu/package.json diff --git a/tests/manual_tests/custom_tray_menu/custom-tray-menu.html b/tests/manual_tests/custom_tray_menu/custom-tray-menu.html new file mode 100644 index 0000000000..8a122b0e6d --- /dev/null +++ b/tests/manual_tests/custom_tray_menu/custom-tray-menu.html @@ -0,0 +1,17 @@ + + + +

                      A custom tray menu

                      +

                      +

                      + + \ No newline at end of file diff --git a/tests/manual_tests/custom_tray_menu/icon.png b/tests/manual_tests/custom_tray_menu/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..50d9c17541b98b5be3e30bc015bddee0d2af36fb GIT binary patch literal 3335 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 RhIaq}002ovPDHLkV1g`3G^+pr literal 0 HcmV?d00001 diff --git a/tests/manual_tests/custom_tray_menu/index.html b/tests/manual_tests/custom_tray_menu/index.html new file mode 100644 index 0000000000..82441e8b7c --- /dev/null +++ b/tests/manual_tests/custom_tray_menu/index.html @@ -0,0 +1,48 @@ + + + + + \ No newline at end of file diff --git a/tests/manual_tests/custom_tray_menu/package.json b/tests/manual_tests/custom_tray_menu/package.json new file mode 100644 index 0000000000..a61be4902e --- /dev/null +++ b/tests/manual_tests/custom_tray_menu/package.json @@ -0,0 +1,24 @@ +{ + "main": "index.html", + "name": "nw-test", + "description": "test app", + "window": { + "title": "My Node-Webkit App", + "icon": "icon.png", + "toolbar": false, + "frame": true, + "width": 800, + "height": 500, + "always-on-top": false, + "kiosk": false, + "fullscreen": false, + "show": false, + "show_in_taskbar": false, + "resizable": true + }, + "webkit": { + "plugin": false, + "java": false, + "page-cache": false + } +} \ No newline at end of file From 4315a197f1f439707edaa1e6e7dcbcef11b7807e Mon Sep 17 00:00:00 2001 From: Roger Date: Mon, 8 Dec 2014 14:34:16 +0800 Subject: [PATCH 356/492] update with latest content API for nw12 --- nw.gypi | 159 ++-- src/api/api_messages.h | 2 + src/api/clipboard/clipboard.h | 4 +- src/api/dispatcher.h | 8 +- src/api/dispatcher_bindings.cc | 6 +- src/api/dispatcher_bindings.h | 2 +- src/api/dispatcher_host.h | 6 +- src/api/menu/menu.h | 4 +- src/api/menu/menu_delegate.h | 16 +- src/api/menuitem/menuitem.h | 6 +- src/api/screen/screen.cc | 40 +- .../shortcut/global_shortcut_listener_x11.h | 10 +- src/api/shortcut/shortcut.h | 2 +- src/api/tray/tray.h | 2 +- src/api/tray/tray_aura.cc | 2 +- src/api/window/window.h | 6 +- src/api/window_bindings.cc | 14 +- src/api/window_bindings.h | 2 +- src/browser/autofill_popup_base_view.h | 20 +- src/browser/autofill_popup_controller_impl.h | 48 +- src/browser/autofill_popup_view_views.h | 10 +- src/browser/browser_view_layout.h | 6 +- src/browser/capture_page_helper.cc | 6 +- src/browser/capture_page_helper.h | 7 +- src/browser/chrome_crash_reporter_client.cc | 377 +++++++++ src/browser/chrome_crash_reporter_client.h | 76 ++ .../chrome_crash_reporter_client_mac.mm | 60 ++ src/browser/color_chooser_aura.h | 8 +- src/browser/file_select_helper.cc | 271 ++++--- src/browser/file_select_helper.h | 118 +-- src/browser/media_capture_util.cc | 88 ++ src/browser/media_capture_util.h | 38 + src/browser/menubar_controller.h | 2 +- src/browser/menubar_view.cc | 4 +- src/browser/menubar_view.h | 6 +- src/browser/native_window_aura.cc | 32 +- src/browser/native_window_aura.h | 148 ++-- src/browser/native_window_toolbar_aura.h | 12 +- src/browser/nw_autofill_client.h | 28 +- src/browser/nw_form_database_service.h | 2 +- src/browser/printing/print_job_worker_owner.h | 24 +- src/browser/printing/print_view_manager.h | 12 +- .../printing/printing_message_filter.cc | 303 ++++--- .../printing/printing_message_filter.h | 69 +- ...ll_component_extension_resource_manager.cc | 61 ++ ...ell_component_extension_resource_manager.h | 41 + src/browser/shell_devtools_delegate.h | 14 +- .../shell_devtools_manager_delegate.cc | 280 +++++++ src/browser/shell_devtools_manager_delegate.h | 45 ++ src/browser/shell_display_info_provider.cc | 38 + src/browser/shell_display_info_provider.h | 32 + .../shell_download_manager_delegate.cc | 2 +- src/browser/shell_download_manager_delegate.h | 12 +- .../shell_download_manager_delegate_gtk.cc | 2 +- src/browser/shell_extension_host_delegate.cc | 64 ++ src/browser/shell_extension_host_delegate.h | 43 + src/browser/shell_extension_system.cc | 242 ++++++ src/browser/shell_extension_system.h | 100 +++ src/browser/shell_extension_system_factory.cc | 52 ++ src/browser/shell_extension_system_factory.h | 40 + .../shell_extension_web_contents_observer.cc | 20 + .../shell_extension_web_contents_observer.h | 29 + .../shell_extensions_browser_client.cc | 244 ++++++ src/browser/shell_extensions_browser_client.h | 101 +++ src/browser/shell_javascript_dialog_creator.h | 8 +- src/browser/shell_login_dialog.h | 24 +- .../shell_resource_dispatcher_host_delegate.h | 4 +- src/browser/shell_runtime_api_delegate.cc | 66 ++ src/browser/shell_runtime_api_delegate.h | 36 + src/common/common_message_generator.h | 1 + src/common/print_messages.cc | 2 +- src/common/print_messages.h | 97 +-- src/common/shell_extensions_client.cc | 217 +++++ src/common/shell_extensions_client.h | 60 ++ src/geolocation/shell_access_token_store.h | 4 +- src/media/media_internals.h | 12 +- src/net/app_protocol_handler.cc | 6 +- src/net/app_protocol_handler.h | 4 +- src/net/resource_request_job.cc | 2 +- src/net/resource_request_job.h | 8 +- src/net/shell_network_delegate.cc | 58 +- src/net/shell_network_delegate.h | 96 +-- src/net/shell_url_request_context_getter.cc | 8 +- src/net/shell_url_request_context_getter.h | 6 +- src/nw_package.cc | 2 +- src/nw_protocol_handler.h | 2 +- src/nw_shell.cc | 60 +- src/nw_shell.h | 63 +- src/renderer/nw_render_view_observer.cc | 2 +- src/renderer/nw_render_view_observer.h | 6 +- src/renderer/prerenderer/prerenderer_client.h | 2 +- .../printing/print_web_view_helper.cc | 755 +++++++++++------- src/renderer/printing/print_web_view_helper.h | 202 +++-- .../printing/print_web_view_helper_linux.cc | 65 +- .../printing/print_web_view_helper_mac.mm | 56 +- .../printing/print_web_view_helper_pdf_win.cc | 62 +- src/renderer/shell_content_renderer_client.cc | 160 ++-- src/renderer/shell_content_renderer_client.h | 40 +- .../shell_extensions_renderer_client.cc | 27 + .../shell_extensions_renderer_client.h | 28 + src/renderer/shell_render_process_observer.cc | 2 +- src/renderer/shell_render_process_observer.h | 6 +- .../component_extension_resources.grd | 20 + src/resources/nwapp/background.js | 1 + src/shell_browser_context.cc | 23 +- src/shell_browser_context.h | 28 +- src/shell_browser_main_parts.cc | 91 ++- src/shell_browser_main_parts.h | 46 +- src/shell_content_browser_client.cc | 85 +- src/shell_content_browser_client.h | 74 +- src/shell_content_client.cc | 6 + src/shell_content_client.h | 14 +- src/shell_devtools_frontend.cc | 59 +- src/shell_devtools_frontend.h | 19 +- src/shell_main_delegate.cc | 12 +- src/shell_main_delegate.h | 12 +- src/shell_quota_permission_context.cc | 2 +- src/shell_quota_permission_context.h | 2 +- 118 files changed, 4674 insertions(+), 1607 deletions(-) create mode 100644 src/browser/chrome_crash_reporter_client.cc create mode 100644 src/browser/chrome_crash_reporter_client.h create mode 100644 src/browser/chrome_crash_reporter_client_mac.mm create mode 100644 src/browser/media_capture_util.cc create mode 100644 src/browser/media_capture_util.h create mode 100644 src/browser/shell_component_extension_resource_manager.cc create mode 100644 src/browser/shell_component_extension_resource_manager.h create mode 100644 src/browser/shell_devtools_manager_delegate.cc create mode 100644 src/browser/shell_devtools_manager_delegate.h create mode 100644 src/browser/shell_display_info_provider.cc create mode 100644 src/browser/shell_display_info_provider.h create mode 100644 src/browser/shell_extension_host_delegate.cc create mode 100644 src/browser/shell_extension_host_delegate.h create mode 100644 src/browser/shell_extension_system.cc create mode 100644 src/browser/shell_extension_system.h create mode 100644 src/browser/shell_extension_system_factory.cc create mode 100644 src/browser/shell_extension_system_factory.h create mode 100644 src/browser/shell_extension_web_contents_observer.cc create mode 100644 src/browser/shell_extension_web_contents_observer.h create mode 100644 src/browser/shell_extensions_browser_client.cc create mode 100644 src/browser/shell_extensions_browser_client.h create mode 100644 src/browser/shell_runtime_api_delegate.cc create mode 100644 src/browser/shell_runtime_api_delegate.h create mode 100644 src/common/shell_extensions_client.cc create mode 100644 src/common/shell_extensions_client.h create mode 100644 src/renderer/shell_extensions_renderer_client.cc create mode 100644 src/renderer/shell_extensions_renderer_client.h create mode 100644 src/resources/component_extension_resources.grd create mode 100644 src/resources/nwapp/background.js diff --git a/nw.gypi b/nw.gypi index a7681f5324..017475d0e4 100644 --- a/nw.gypi +++ b/nw.gypi @@ -49,7 +49,9 @@ }, 'dependencies': [ '<(DEPTH)/base/base.gyp:base', + '<(DEPTH)/base/base.gyp:base_prefs_test_support', '<(DEPTH)/base/third_party/dynamic_annotations/dynamic_annotations.gyp:dynamic_annotations', + '<(DEPTH)/chrome/common/extensions/api/api.gyp:chrome_api', '<(DEPTH)/components/components.gyp:autofill_content_renderer', '<(DEPTH)/components/components.gyp:keyed_service_content', '<(DEPTH)/components/components_resources.gyp:components_resources', @@ -63,7 +65,10 @@ '<(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)/content/app/resources/content_resources.gyp:content_resources', + '<(DEPTH)/device/core/core.gyp:device_core', + '<(DEPTH)/device/hid/hid.gyp:device_hid', + '<(DEPTH)/extensions/extensions.gyp:extensions_common_constants', '<(DEPTH)/ipc/ipc.gyp:ipc', '<(DEPTH)/media/media.gyp:media', '<(DEPTH)/net/net.gyp:net_with_v8', @@ -77,6 +82,14 @@ '<(DEPTH)/v8/tools/gyp/v8.gyp:v8', '<(DEPTH)/third_party/zlib/zlib.gyp:minizip', '<(DEPTH)/third_party/WebKit/public/blink.gyp:blink', + '<(DEPTH)/extensions/browser/api/api_registration.gyp:extensions_api_registration', + '<(DEPTH)/extensions/common/api/api.gyp:extensions_api', + '<(DEPTH)/extensions/extensions.gyp:extensions_browser', + '<(DEPTH)/extensions/extensions.gyp:extensions_common', + '<(DEPTH)/extensions/extensions.gyp:extensions_renderer', + '<(DEPTH)/extensions/extensions.gyp:extensions_shell_and_test_pak', + '<(DEPTH)/extensions/extensions.gyp:extensions_utility', + '<(DEPTH)/extensions/extensions_resources.gyp:extensions_resources', 'nw_resources', 'commit_id', ], @@ -136,8 +149,8 @@ '<(DEPTH)/chrome/common/chrome_switches.h', '<(DEPTH)/extensions/common/draggable_region.cc', '<(DEPTH)/extensions/common/draggable_region.h', - '<(DEPTH)/extensions/renderer/static_v8_external_ascii_string_resource.cc', - '<(DEPTH)/extensions/renderer/static_v8_external_ascii_string_resource.h', + '<(DEPTH)/extensions/renderer/static_v8_external_one_byte_string_resource.cc', + '<(DEPTH)/extensions/renderer/static_v8_external_one_byte_string_resource.h', '<(DEPTH)/third_party/zlib/google/zip.cc', '<(DEPTH)/third_party/zlib/google/zip.h', '<(DEPTH)/third_party/zlib/google/zip_reader.cc', @@ -207,8 +220,8 @@ 'src/browser/autofill_popup_view_cocoa.mm', 'src/browser/autofill_popup_view_bridge.h', 'src/browser/autofill_popup_view_bridge.mm', - 'src/browser/autofill_popup_controller_impl.cc', - 'src/browser/autofill_popup_controller_impl.h', + '<(DEPTH)/chrome/browser/ui/autofill/autofill_popup_controller_impl.cc', + '<(DEPTH)/chrome/browser/ui/autofill/autofill_popup_controller_impl.h', 'src/browser/browser_view_layout.cc', 'src/browser/browser_view_layout.h', 'src/browser/nw_autofill_client.cc', @@ -243,29 +256,50 @@ 'src/browser/nw_form_database_service.h', 'src/browser/popup_controller_common.cc', 'src/browser/popup_controller_common.h', - 'src/browser/printing/print_job.cc', - 'src/browser/printing/print_job.h', - 'src/browser/printing/print_job_manager.cc', - 'src/browser/printing/print_job_manager.h', - 'src/browser/printing/print_job_worker.cc', - 'src/browser/printing/print_job_worker.h', - 'src/browser/printing/print_job_worker_owner.h', + 'src/browser/shell_component_extension_resource_manager.cc', + 'src/browser/shell_component_extension_resource_manager.h', + '<(DEPTH)/chrome/browser/printing/print_job.cc', + '<(DEPTH)/chrome/browser/printing/print_job.h', + '<(DEPTH)/chrome/browser/printing/print_job_manager.cc', + '<(DEPTH)/chrome/browser/printing/print_job_manager.h', + '<(DEPTH)/chrome/browser/printing/print_job_worker.cc', + '<(DEPTH)/chrome/browser/printing/print_job_worker.h', + '<(DEPTH)/chrome/browser/printing/print_job_worker_owner.h', + '<(DEPTH)/chrome/browser/printing/print_job_worker_owner.cc', 'src/browser/printing/printing_message_filter.cc', 'src/browser/printing/printing_message_filter.h', - 'src/browser/printing/printing_ui_web_contents_observer.cc', - 'src/browser/printing/printing_ui_web_contents_observer.h', - 'src/browser/printing/printer_query.cc', - 'src/browser/printing/printer_query.h', - 'src/browser/printing/print_view_manager.cc', - 'src/browser/printing/print_view_manager.h', + '<(DEPTH)/chrome/browser/printing/printer_query.cc', + '<(DEPTH)/chrome/browser/printing/printer_query.h', + '<(DEPTH)/chrome/browser/printing/print_view_manager.cc', + '<(DEPTH)/chrome/browser/printing/print_view_manager.h', + '<(DEPTH)/chrome/browser/printing/print_view_manager_base.cc', + '<(DEPTH)/chrome/browser/printing/print_view_manager_base.h', + '<(DEPTH)/chrome/browser/printing/print_view_manager_basic.cc', + '<(DEPTH)/chrome/browser/printing/print_view_manager_basic.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_devtools_manager_delegate.cc', + 'src/browser/shell_devtools_manager_delegate.h', 'src/browser/shell_download_manager_delegate.cc', 'src/browser/shell_download_manager_delegate.h', 'src/browser/shell_download_manager_delegate_win.cc', 'src/browser/shell_download_manager_delegate_mac.mm', + 'src/browser/shell_extension_system.cc', + 'src/browser/shell_extension_system.h', + 'src/browser/shell_extension_system_factory.cc', + 'src/browser/shell_extension_system_factory.h', + 'src/browser/shell_extensions_browser_client.cc', + 'src/browser/shell_extensions_browser_client.h', + 'src/browser/shell_extension_host_delegate.cc', + 'src/browser/shell_extension_host_delegate.h', + 'src/browser/shell_extension_web_contents_observer.cc', + 'src/browser/shell_extension_web_contents_observer.h', + 'src/browser/shell_display_info_provider.cc', + 'src/browser/shell_display_info_provider.h', + 'src/browser/shell_runtime_api_delegate.cc', + 'src/browser/shell_runtime_api_delegate.h', + 'src/browser/media_capture_util.cc', + 'src/browser/media_capture_util.h', 'src/browser/shell_javascript_dialog_creator.cc', 'src/browser/shell_javascript_dialog_creator.h', # 'src/browser/shell_javascript_dialog_gtk.cc', @@ -283,28 +317,28 @@ 'src/browser/shell_toolbar_delegate_mac.mm', 'src/browser/standard_menus_mac.h', 'src/browser/standard_menus_mac.mm', - 'src/chrome_breakpad_client.cc', - 'src/chrome_breakpad_client.h', - 'src/chrome_breakpad_client_mac.mm', + 'src/browser/chrome_crash_reporter_client.cc', + 'src/browser/chrome_crash_reporter_client.h', + 'src/browser/chrome_crash_reporter_client_mac.mm', 'src/common/print_messages.cc', 'src/common/print_messages.h', 'src/common/shell_switches.cc', 'src/common/shell_switches.h', + 'src/common/shell_extensions_client.cc', + 'src/common/shell_extensions_client.h', 'src/breakpad_linux_impl.h', 'src/hard_error_handler_win.cc', 'src/hard_error_handler_win.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/browser/media_capture_devices_dispatcher.cc', +# 'src/browser/media_capture_devices_dispatcher.h', +# 'src/browser/media_stream_devices_controller.cc', +# 'src/browser/media_stream_devices_controller.h', 'src/net/app_protocol_handler.cc', 'src/net/app_protocol_handler.h', - 'src/net/clear_on_exit_policy.h', - 'src/net/clear_on_exit_policy.cc', +# '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', @@ -326,24 +360,27 @@ 'src/renderer/printing/print_web_view_helper.h', 'src/renderer/printing/print_web_view_helper_linux.cc', 'src/renderer/printing/print_web_view_helper_mac.mm', + 'src/renderer/printing/print_web_view_helper_pdf_win.cc', 'src/renderer/nw_render_view_observer.cc', 'src/renderer/nw_render_view_observer.h', 'src/renderer/shell_content_renderer_client.cc', 'src/renderer/shell_content_renderer_client.h', + 'src/renderer/shell_extensions_renderer_client.cc', + 'src/renderer/shell_extensions_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/nw_notification_manager.h', - 'src/nw_notification_manager.cc', - 'src/nw_notification_manager_win.h', - 'src/nw_notification_manager_win.cc', - 'src/nw_notification_manager_toast_win.h', - 'src/nw_notification_manager_toast_win.cc', - 'src/nw_notification_manager_mac.h', - 'src/nw_notification_manager_mac.mm', - 'src/nw_notification_manager_linux.h', - 'src/nw_notification_manager_linux.cc', +# 'src/nw_notification_manager.h', +# 'src/nw_notification_manager.cc', +# 'src/nw_notification_manager_win.h', +# 'src/nw_notification_manager_win.cc', +# 'src/nw_notification_manager_toast_win.h', +# 'src/nw_notification_manager_toast_win.cc', +# 'src/nw_notification_manager_mac.h', +# 'src/nw_notification_manager_mac.mm', +# 'src/nw_notification_manager_linux.h', +# 'src/nw_notification_manager_linux.cc', 'src/shell_browser_context.cc', 'src/shell_browser_context.h', 'src/shell_browser_main.cc', @@ -361,6 +398,7 @@ 'src/shell_main_delegate.h', 'src/shell_quota_permission_context.cc', 'src/shell_quota_permission_context.h', + '<(SHARED_INTERMEDIATE_DIR)/content/grit/nw_component_resources_map.cc', ], 'msvs_settings': { 'VCLinkerTool': { @@ -385,12 +423,12 @@ }], ['use_aura==1', { 'sources': [ - '<(DEPTH)/chrome/browser/ui/views/constrained_window_views.cc', '<(DEPTH)/chrome/browser/ui/views/web_contents_modal_dialog_manager_views.cc', 'src/browser/login_view.cc', 'src/browser/login_view.h', ], 'dependencies': [ + '<(DEPTH)/components/components.gyp:constrained_window', '<(DEPTH)/components/components.gyp:web_modal', '<(DEPTH)/ui/resources/ui_resources.gyp:ui_resources', '<(DEPTH)/ui/views/views.gyp:views', @@ -404,15 +442,6 @@ '<(DEPTH)/base/allocator/allocator.gyp:allocator', ], }], - ['win_pdf_metafile_for_printing==1', { - 'sources': [ - 'src/renderer/printing/print_web_view_helper_pdf_win.cc', - ], - }, { - 'sources': [ - 'src/renderer/printing/print_web_view_helper_win.cc', - ], - }], ['OS=="win" or OS=="linux"', { 'sources': [ 'src/browser/autofill_popup_base_view.cc', @@ -425,13 +454,13 @@ 'dependencies': [ '<(DEPTH)/breakpad/breakpad.gyp:breakpad_handler', '<(DEPTH)/breakpad/breakpad.gyp:breakpad_sender', - '<(DEPTH)/components/components.gyp:breakpad_component', + '<(DEPTH)/components/components.gyp:crash_component', ], }], ['os_posix==1 and OS != "mac" and OS != "ios"', { 'dependencies': [ '<(DEPTH)/breakpad/breakpad.gyp:breakpad_client', - '<(DEPTH)/components/components.gyp:breakpad_component', + '<(DEPTH)/components/components.gyp:crash_component', ], }], ['OS=="linux"', { @@ -456,7 +485,7 @@ ], 'dependencies': [ '<(DEPTH)/breakpad/breakpad.gyp:breakpad', - '<(DEPTH)/components/components.gyp:breakpad_component', + '<(DEPTH)/components/components.gyp:crash_component', ], 'link_settings': { 'libraries': [ @@ -589,6 +618,13 @@ }, 'includes': [ '../../build/grit_action.gypi' ], }, + { + 'action_name': 'nw_components', + 'variables': { + 'grit_grd_file': 'src/resources/component_extension_resources.grd', + }, + 'includes': [ '../../build/grit_action.gypi' ], + }, ], }, { @@ -629,7 +665,7 @@ '<(DEPTH)/net/net.gyp:net_resources', '<(DEPTH)/third_party/WebKit/public/blink_resources.gyp:blink_resources', '<(DEPTH)/ui/strings/ui_strings.gyp:ui_strings', - '<(DEPTH)/webkit/glue/resources/webkit_resources.gyp:webkit_resources', + '<(DEPTH)/content/app/resources/content_resources.gyp:content_resources', 'nw_resources', ], 'variables': { @@ -642,6 +678,7 @@ 'pak_inputs': [ '<(SHARED_INTERMEDIATE_DIR)/content/content_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/content/nw_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/content/nw_components.pak', '<(SHARED_INTERMEDIATE_DIR)/net/net_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/ui/resources/ui_resources_100_percent.pak', '<(SHARED_INTERMEDIATE_DIR)/ui/resources/webui_resources.pak', @@ -649,8 +686,12 @@ '<(SHARED_INTERMEDIATE_DIR)/ui/strings/ui_strings_en-US.pak', '<(SHARED_INTERMEDIATE_DIR)/webkit/devtools_resources.pak', '<(SHARED_INTERMEDIATE_DIR)/blink/public/resources/blink_resources.pak', - '<(SHARED_INTERMEDIATE_DIR)/webkit/webkit_resources_100_percent.pak', + '<(SHARED_INTERMEDIATE_DIR)/content/app/resources/content_resources_100_percent.pak', '<(SHARED_INTERMEDIATE_DIR)/content/app/strings/content_strings_en-US.pak', + '<(SHARED_INTERMEDIATE_DIR)/extensions/extensions_browser_resources_100_percent.pak', + '<(SHARED_INTERMEDIATE_DIR)/extensions/extensions_renderer_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/extensions/extensions_resources.pak', + '<(SHARED_INTERMEDIATE_DIR)/extensions/strings/extensions_strings_en-US.pak', ], }, 'inputs': [ @@ -757,7 +798,7 @@ { 'action_name': 'strip_nw_binaries', 'inputs': [ - '<(PRODUCT_DIR)/nwsnapshot', + #'<(PRODUCT_DIR)/nwsnapshot', '<(PRODUCT_DIR)/chromedriver', ], 'outputs': [ @@ -769,7 +810,7 @@ }, ], 'dependencies': [ - '<(DEPTH)/v8/tools/gyp/v8.gyp:nwsnapshot', + #'<(DEPTH)/v8/tools/gyp/v8.gyp:nwsnapshot', '<(DEPTH)/chrome/chrome.gyp:chromedriver', ], }], @@ -882,7 +923,7 @@ }], # OS=="win" or (toolkit_uses_gtk == 1 and selinux == 0) ['OS=="linux"', { 'dependencies': [ - '<(DEPTH)/build/linux/system.gyp:notify', + #'<(DEPTH)/build/linux/system.gyp:notify', ], }], # OS=="linux" ['OS=="mac"', { diff --git a/src/api/api_messages.h b/src/api/api_messages.h index a8e9658a14..fd6232eae0 100644 --- a/src/api/api_messages.h +++ b/src/api/api_messages.h @@ -29,10 +29,12 @@ #define IPC_MESSAGE_START ShellMsgStart +#if 0 IPC_STRUCT_TRAITS_BEGIN(extensions::DraggableRegion) IPC_STRUCT_TRAITS_MEMBER(draggable) IPC_STRUCT_TRAITS_MEMBER(bounds) IPC_STRUCT_TRAITS_END() +#endif IPC_MESSAGE_ROUTED3(ShellViewHostMsg_Allocate_Object, int /* object id */, diff --git a/src/api/clipboard/clipboard.h b/src/api/clipboard/clipboard.h index e0ed72f622..0bb6921f04 100644 --- a/src/api/clipboard/clipboard.h +++ b/src/api/clipboard/clipboard.h @@ -34,10 +34,10 @@ class Clipboard : public Base { virtual ~Clipboard(); virtual void Call(const std::string& method, - const base::ListValue& arguments) OVERRIDE; + const base::ListValue& arguments) override; virtual void CallSync(const std::string& method, const base::ListValue& arguments, - base::ListValue* result) OVERRIDE; + base::ListValue* result) override; private: void SetText(std::string& text); diff --git a/src/api/dispatcher.h b/src/api/dispatcher.h index 8e24c41707..315513bc43 100644 --- a/src/api/dispatcher.h +++ b/src/api/dispatcher.h @@ -59,10 +59,10 @@ class Dispatcher : public content::RenderViewObserver { private: // RenderViewObserver implementation. - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void DraggableRegionsChanged(blink::WebFrame* frame) OVERRIDE; - virtual void DidFinishDocumentLoad(blink::WebLocalFrame* frame) OVERRIDE; - virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) override; + virtual void DraggableRegionsChanged(blink::WebFrame* frame) override; + virtual void DidFinishDocumentLoad(blink::WebLocalFrame* frame) override; + virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) override; void documentCallback(const char* ev, blink::WebLocalFrame* frame); diff --git a/src/api/dispatcher_bindings.cc b/src/api/dispatcher_bindings.cc index 359c47e57a..5246338ecc 100644 --- a/src/api/dispatcher_bindings.cc +++ b/src/api/dispatcher_bindings.cc @@ -21,7 +21,7 @@ #include "content/nw/src/api/dispatcher_bindings.h" #include "base/files/file_path.h" -#include "base/file_util.h" +#include "base/files/file_util.h" #include "base/logging.h" #include "base/values.h" #include "base/command_line.h" @@ -31,7 +31,7 @@ #include "content/public/renderer/render_view.h" #include "content/public/renderer/render_thread.h" #include "content/public/renderer/v8_value_converter.h" -#include "extensions/renderer/static_v8_external_ascii_string_resource.h" +#include "extensions/renderer/static_v8_external_one_byte_string_resource.h" #include "grit/nw_resources.h" #include "third_party/node/src/node.h" #undef CHECK @@ -69,7 +69,7 @@ void RequireFromResource(v8::Handle root, v8::HandleScope handle_scope(isolate); v8::Handle source = v8::String::NewExternal(isolate, - new extensions::StaticV8ExternalAsciiStringResource( + new extensions::StaticV8ExternalOneByteStringResource( GetStringResource(resource_id))); v8::Handle wrapped_source = WrapSource(source); diff --git a/src/api/dispatcher_bindings.h b/src/api/dispatcher_bindings.h index f44f23aedf..068c78376e 100644 --- a/src/api/dispatcher_bindings.h +++ b/src/api/dispatcher_bindings.h @@ -36,7 +36,7 @@ class DispatcherBindings : public v8::Extension { virtual v8::Handle GetNativeFunctionTemplate( v8::Isolate* isolate, - v8::Handle name) OVERRIDE; + v8::Handle name) override; private: // Helper functions for bindings. diff --git a/src/api/dispatcher_host.h b/src/api/dispatcher_host.h index 5e92867ea3..702e6e2d77 100644 --- a/src/api/dispatcher_host.h +++ b/src/api/dispatcher_host.h @@ -69,9 +69,9 @@ class DispatcherHost : public content::WebContentsObserver { const std::string& event, const base::ListValue& arguments); - virtual bool Send(IPC::Message* message) OVERRIDE; + virtual bool Send(IPC::Message* message) override; virtual void RenderViewHostChanged(content::RenderViewHost* old_host, - content::RenderViewHost* new_host) OVERRIDE; + content::RenderViewHost* new_host) override; content::RenderViewHost* render_view_host() const { return render_view_host_; } @@ -92,7 +92,7 @@ class DispatcherHost : public content::WebContentsObserver { // WebContentsObserver implementation: virtual bool OnMessageReceived( content::RenderViewHost* render_view_host, - const IPC::Message& message) OVERRIDE; + const IPC::Message& message) override; void OnAllocateObject(int object_id, diff --git a/src/api/menu/menu.h b/src/api/menu/menu.h index 70db2361ee..91cf479ba1 100644 --- a/src/api/menu/menu.h +++ b/src/api/menu/menu.h @@ -66,7 +66,7 @@ class NwMenuModel : public SimpleMenuModel { NwMenuModel(Delegate* delegate); // Overridden from MenuModel: - virtual bool HasIcons() const OVERRIDE; + virtual bool HasIcons() const override; protected: friend class nwapi::Menu; @@ -92,7 +92,7 @@ class Menu : public Base { virtual ~Menu(); virtual void Call(const std::string& method, - const base::ListValue& arguments) OVERRIDE; + const base::ListValue& arguments) override; #if defined(OS_WIN) || defined(OS_LINUX) void UpdateKeys(views::FocusManager *focus_manager); diff --git a/src/api/menu/menu_delegate.h b/src/api/menu/menu_delegate.h index 376323fa1c..89e60e6d59 100644 --- a/src/api/menu/menu_delegate.h +++ b/src/api/menu/menu_delegate.h @@ -32,21 +32,21 @@ class MenuDelegate : public ui::SimpleMenuModel::Delegate { MenuDelegate(DispatcherHost* dispatcher_host); virtual ~MenuDelegate(); - virtual bool IsCommandIdChecked(int command_id) const OVERRIDE; - virtual bool IsCommandIdEnabled(int command_id) const OVERRIDE; + virtual bool IsCommandIdChecked(int command_id) const override; + virtual bool IsCommandIdEnabled(int command_id) const override; virtual bool GetAcceleratorForCommandId( int command_id, - ui::Accelerator* accelerator) OVERRIDE; + ui::Accelerator* accelerator) override; - virtual bool IsItemForCommandIdDynamic(int command_id) const OVERRIDE; - virtual base::string16 GetLabelForCommandId(int command_id) const OVERRIDE; + virtual bool IsItemForCommandIdDynamic(int command_id) const override; + virtual base::string16 GetLabelForCommandId(int command_id) const override; virtual bool GetIconForCommandId(int command_id, - gfx::Image* icon) const OVERRIDE; + gfx::Image* icon) const override; - virtual void ExecuteCommand(int command_id, int event_flags) OVERRIDE; + virtual void ExecuteCommand(int command_id, int event_flags) override; - virtual bool HasIcon(int command_id) OVERRIDE; + virtual bool HasIcon(int command_id) override; private: DispatcherHost* dispatcher_host_; diff --git a/src/api/menuitem/menuitem.h b/src/api/menuitem/menuitem.h index b1a5bc7e8e..90b91d5dc3 100644 --- a/src/api/menuitem/menuitem.h +++ b/src/api/menuitem/menuitem.h @@ -58,11 +58,11 @@ class MenuItem : public Base { virtual ~MenuItem(); virtual void Call(const std::string& method, - const base::ListValue& arguments) OVERRIDE; + const base::ListValue& arguments) override; #if defined(OS_WIN) || defined(OS_LINUX) - virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; - virtual bool CanHandleAccelerators() const OVERRIDE; + virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) override; + virtual bool CanHandleAccelerators() const override; void UpdateKeys(views::FocusManager *focus_manager); #endif diff --git a/src/api/screen/screen.cc b/src/api/screen/screen.cc index 74b6d12070..6c3236cdf1 100644 --- a/src/api/screen/screen.cc +++ b/src/api/screen/screen.cc @@ -30,26 +30,26 @@ namespace nwapi { std::string DisplayToJSON(const gfx::Display& display) { std::stringstream ret; gfx::Rect rect = display.bounds(); - + ret << "{\"id\":" << display.id(); - + ret << ",\"bounds\":{\"x\":" << rect.x() << ", \"y\":" << rect.y() << ", \"width\":" << rect.width() << ", \"height\":" << rect.height() << "}"; - + rect = display.work_area(); ret << ",\"work_area\":{\"x\":" << rect.x() << ", \"y\":" << rect.y() << ", \"width\":" << rect.width() << ", \"height\":" << rect.height() << "}"; - + ret << ",\"scaleFactor\":" << display.device_scale_factor(); ret << ",\"isBuiltIn\":" << (display.IsInternal() ? "true" : "false"); ret << ",\"rotation\":" << display.RotationAsDegree(); ret << ",\"touchSupport\":" << display.touch_support(); ret << "}"; - + return ret.str(); } @@ -57,40 +57,40 @@ class JavaScriptDisplayObserver : BaseEvent, public gfx::DisplayObserver { friend class EventListener; EventListener* object_; gfx::Screen* screen_; - + // Called when the |display|'s bound has changed. - virtual void OnDisplayMetricsChanged(const gfx::Display& display, uint32_t changed_metrics) OVERRIDE { + virtual void OnDisplayMetricsChanged(const gfx::Display& display, uint32_t changed_metrics) override { base::ListValue arguments; arguments.AppendString(DisplayToJSON(display)); arguments.AppendInteger(changed_metrics); object_->dispatcher_host()->SendEvent(object_, "displayBoundsChanged", arguments); } - + // Called when |new_display| has been added. - virtual void OnDisplayAdded(const gfx::Display& new_display) OVERRIDE { + virtual void OnDisplayAdded(const gfx::Display& new_display) override { base::ListValue arguments; arguments.AppendString(DisplayToJSON(new_display)); object_->dispatcher_host()->SendEvent(object_, "displayAdded", arguments); - + } - + // Called when |old_display| has been removed. - virtual void OnDisplayRemoved(const gfx::Display& old_display) OVERRIDE { + virtual void OnDisplayRemoved(const gfx::Display& old_display) override { base::ListValue arguments; arguments.AppendString(DisplayToJSON(old_display)); object_->dispatcher_host()->SendEvent(object_, "displayRemoved", arguments); } - + static const int id; - + JavaScriptDisplayObserver(EventListener* object) : object_(object), screen_(NULL){ } - + virtual ~JavaScriptDisplayObserver() { if(screen_) screen_->RemoveObserver(this); } - + public: void setScreen(gfx::Screen* screen) { if(screen_) screen_->RemoveObserver(this); @@ -100,7 +100,7 @@ class JavaScriptDisplayObserver : BaseEvent, public gfx::DisplayObserver { }; const int JavaScriptDisplayObserver::id = EventListener::getUID(); - + // static void Screen::Call(DispatcherHost* dispatcher_host, const std::string& method, @@ -110,12 +110,12 @@ void Screen::Call(DispatcherHost* dispatcher_host, if (method == "GetScreens") { std::stringstream ret; const std::vector& displays = gfx::Screen::GetNativeScreen()->GetAllDisplays(); - + if (displays.size() == 0) { result->AppendString("{}"); return; } - + for (size_t i=0; iAppendBoolean(res); return; } - + } } // namespace nwapi diff --git a/src/api/shortcut/global_shortcut_listener_x11.h b/src/api/shortcut/global_shortcut_listener_x11.h index 473edac78c..3c46b2ceca 100644 --- a/src/api/shortcut/global_shortcut_listener_x11.h +++ b/src/api/shortcut/global_shortcut_listener_x11.h @@ -49,16 +49,16 @@ class GlobalShortcutListenerX11 virtual ~GlobalShortcutListenerX11(); // base::MessagePumpDispatcher implementation. - virtual uint32_t Dispatch(const base::NativeEvent& event) OVERRIDE; + virtual uint32_t Dispatch(const base::NativeEvent& event) override; private: // GlobalShortcutListener implementation. - virtual void StartListening() OVERRIDE; - virtual void StopListening() OVERRIDE; + virtual void StartListening() override; + virtual void StopListening() override; virtual bool RegisterAcceleratorImpl( - const ui::Accelerator& accelerator) OVERRIDE; + const ui::Accelerator& accelerator) override; virtual void UnregisterAcceleratorImpl( - const ui::Accelerator& accelerator) OVERRIDE; + const ui::Accelerator& accelerator) override; #if defined(OS_LINUX) // Callback for XEvents of the default root window. diff --git a/src/api/shortcut/shortcut.h b/src/api/shortcut/shortcut.h index 3da6a9f195..2a9b446226 100644 --- a/src/api/shortcut/shortcut.h +++ b/src/api/shortcut/shortcut.h @@ -44,7 +44,7 @@ class Shortcut : public Base, public GlobalShortcutListener::Observer { void OnFailed(const std::string failed_msg); // GlobalShortcutListener::Observer implementation. - virtual void OnKeyPressed(const ui::Accelerator& accelerator) OVERRIDE; + virtual void OnKeyPressed(const ui::Accelerator& accelerator) override; private: ui::Accelerator accelerator_; diff --git a/src/api/tray/tray.h b/src/api/tray/tray.h index 8f54eccb99..0f1cffbad8 100644 --- a/src/api/tray/tray.h +++ b/src/api/tray/tray.h @@ -55,7 +55,7 @@ class Tray : public Base { virtual ~Tray(); virtual void Call(const std::string& method, - const base::ListValue& arguments) OVERRIDE; + const base::ListValue& arguments) override; private: // Platform-independent implementations diff --git a/src/api/tray/tray_aura.cc b/src/api/tray/tray_aura.cc index 4c0c677da1..806534fddc 100644 --- a/src/api/tray/tray_aura.cc +++ b/src/api/tray/tray_aura.cc @@ -45,7 +45,7 @@ class TrayObserver : public StatusIconObserver { virtual ~TrayObserver() { } - virtual void OnStatusIconClicked() OVERRIDE { + virtual void OnStatusIconClicked() override { base::ListValue args; tray_->dispatcher_host()->SendEvent(tray_, "click", args); } diff --git a/src/api/window/window.h b/src/api/window/window.h index 6824547707..50cd25c67c 100644 --- a/src/api/window/window.h +++ b/src/api/window/window.h @@ -65,10 +65,10 @@ class Window : public Base, public content::NotificationObserver { virtual ~Window(); virtual void Call(const std::string& method, - const base::ListValue& arguments) OVERRIDE; + const base::ListValue& arguments) override; virtual void CallSync(const std::string& method, const base::ListValue& arguments, - base::ListValue* result) OVERRIDE; + base::ListValue* result) override; void CookieGet(const base::ListValue& arguments, bool get_all = false); void GetCookieOnIOThread(CookieAPIContext*); @@ -89,7 +89,7 @@ class Window : public Base, public content::NotificationObserver { // content::NotificationObserver implementation. virtual void Observe(int type, const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; + const content::NotificationDetails& details) override; // Handler for the COOKIE_CHANGED event. The method takes the details of such // an event and constructs a suitable JSON formatted extension event from it. diff --git a/src/api/window_bindings.cc b/src/api/window_bindings.cc index 9d0b2c3589..7083aa4dc6 100644 --- a/src/api/window_bindings.cc +++ b/src/api/window_bindings.cc @@ -49,16 +49,16 @@ using namespace blink; #define BLINK_IMPLEMENTATION 1 #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/Source/platform/heap/Handle.h" -#include "third_party/WebKit/Source/core/inspector/InspectorInstrumentation.h" -#include "third_party/WebKit/Source/core/inspector/InspectorResourceAgent.h" +//#include "third_party/WebKit/Source/core/inspector/InspectorInstrumentation.h" +//#include "third_party/WebKit/Source/core/inspector/InspectorResourceAgent.h" #undef CHECK #include "V8HTMLIFrameElement.h" using blink::WebScriptSource; using blink::WebFrame; -using blink::InstrumentingAgents; -using blink::InspectorResourceAgent; +//using blink::InstrumentingAgents; +//using blink::InspectorResourceAgent; namespace nwapi { @@ -140,7 +140,7 @@ WindowBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args if (frm->IsNull()) { web_frame = main_frame; }else{ - blink::HTMLIFrameElement* iframe = blink::V8HTMLIFrameElement::toNative(frm); + blink::HTMLIFrameElement* iframe = blink::V8HTMLIFrameElement::toImpl(frm); web_frame = blink::WebFrame::fromFrame(iframe->contentFrame()); } #if defined(OS_WIN) @@ -158,12 +158,13 @@ WindowBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args if (frm->IsNull()) { main_frame->setDevtoolsJail(NULL); }else{ - blink::HTMLIFrameElement* iframe = blink::V8HTMLIFrameElement::toNative(frm); + blink::HTMLIFrameElement* iframe = blink::V8HTMLIFrameElement::toImpl(frm); main_frame->setDevtoolsJail(blink::WebFrame::fromFrame(iframe->contentFrame())); } args.GetReturnValue().Set(v8::Undefined(isolate)); return; } else if (method == "setCacheDisabled") { +#if 0 //FIXME RefPtrWillBePersistent document = static_cast >(main_frame->document()); InstrumentingAgents* instrumentingAgents = instrumentationForPage(document->page()); if (instrumentingAgents) { @@ -174,6 +175,7 @@ WindowBindings::CallObjectMethod(const v8::FunctionCallbackInfo& args } else args.GetReturnValue().Set(false); return; +#endif } args.GetReturnValue().Set(remote::CallObjectMethod(render_view->GetRoutingID(), diff --git a/src/api/window_bindings.h b/src/api/window_bindings.h index 4e2fddca32..35498ad4ae 100644 --- a/src/api/window_bindings.h +++ b/src/api/window_bindings.h @@ -36,7 +36,7 @@ class WindowBindings : public v8::Extension { virtual v8::Handle GetNativeFunctionTemplate( v8::Isolate* isolate, - v8::Handle name) OVERRIDE; + v8::Handle name) override; private: static void AllocateId(const v8::FunctionCallbackInfo& args); diff --git a/src/browser/autofill_popup_base_view.h b/src/browser/autofill_popup_base_view.h index 72c4162952..b34ed71056 100644 --- a/src/browser/autofill_popup_base_view.h +++ b/src/browser/autofill_popup_base_view.h @@ -52,22 +52,22 @@ class AutofillPopupBaseView : public views::WidgetDelegateView, friend class AutofillPopupBaseViewTest; // views::Views implementation. - virtual void OnMouseCaptureLost() OVERRIDE; - virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE; - virtual void OnMouseExited(const ui::MouseEvent& event) OVERRIDE; - virtual void OnMouseMoved(const ui::MouseEvent& event) OVERRIDE; - virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE; - virtual void OnMouseReleased(const ui::MouseEvent& event) OVERRIDE; - virtual void OnGestureEvent(ui::GestureEvent* event) OVERRIDE; - virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; + virtual void OnMouseCaptureLost() override; + virtual bool OnMouseDragged(const ui::MouseEvent& event) override; + virtual void OnMouseExited(const ui::MouseEvent& event) override; + virtual void OnMouseMoved(const ui::MouseEvent& event) override; + virtual bool OnMousePressed(const ui::MouseEvent& event) override; + virtual void OnMouseReleased(const ui::MouseEvent& event) override; + virtual void OnGestureEvent(ui::GestureEvent* event) override; + virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) override; // views::WidgetFocusChangeListener implementation. virtual void OnNativeFocusChange(gfx::NativeView focused_before, - gfx::NativeView focused_now) OVERRIDE; + gfx::NativeView focused_now) override; // views::WidgetObserver implementation. virtual void OnWidgetBoundsChanged(views::Widget* widget, - const gfx::Rect& new_bounds) OVERRIDE; + const gfx::Rect& new_bounds) override; // Stop observing the |observing_widget_|. void RemoveObserver(); diff --git a/src/browser/autofill_popup_controller_impl.h b/src/browser/autofill_popup_controller_impl.h index ca4de53c81..d0b84d8076 100644 --- a/src/browser/autofill_popup_controller_impl.h +++ b/src/browser/autofill_popup_controller_impl.h @@ -49,10 +49,10 @@ class AutofillPopupControllerImpl : public AutofillPopupController { // Hides the popup and destroys the controller. This also invalidates // |delegate_|. - virtual void Hide() OVERRIDE; + virtual void Hide() override; // Invoked when the view was destroyed by by someone other than this class. - virtual void ViewDestroyed() OVERRIDE; + virtual void ViewDestroyed() override; bool HandleKeyPressEvent(const content::NativeWebKeyboardEvent& event); @@ -73,32 +73,32 @@ class AutofillPopupControllerImpl : public AutofillPopupController { virtual ~AutofillPopupControllerImpl(); // AutofillPopupController implementation. - virtual void UpdateBoundsAndRedrawPopup() OVERRIDE; - virtual void SetSelectionAtPoint(const gfx::Point& point) OVERRIDE; - virtual bool AcceptSelectedLine() OVERRIDE; - virtual void SelectionCleared() OVERRIDE; - virtual void AcceptSuggestion(size_t index) OVERRIDE; + virtual void UpdateBoundsAndRedrawPopup() override; + virtual void SetSelectionAtPoint(const gfx::Point& point) override; + virtual bool AcceptSelectedLine() override; + virtual void SelectionCleared() override; + virtual void AcceptSuggestion(size_t index) override; virtual int GetIconResourceID( - const base::string16& resource_name) const OVERRIDE; - virtual bool CanDelete(size_t index) const OVERRIDE; - virtual bool IsWarning(size_t index) const OVERRIDE; - virtual gfx::Rect GetRowBounds(size_t index) OVERRIDE; - virtual void SetPopupBounds(const gfx::Rect& bounds) OVERRIDE; - virtual const gfx::Rect& popup_bounds() const OVERRIDE; - virtual gfx::NativeView container_view() OVERRIDE; - virtual const gfx::RectF& element_bounds() const OVERRIDE; - virtual bool IsRTL() const OVERRIDE; - - virtual const std::vector& names() const OVERRIDE; - virtual const std::vector& subtexts() const OVERRIDE; - virtual const std::vector& icons() const OVERRIDE; - virtual const std::vector& identifiers() const OVERRIDE; + const base::string16& resource_name) const override; + virtual bool CanDelete(size_t index) const override; + virtual bool IsWarning(size_t index) const override; + virtual gfx::Rect GetRowBounds(size_t index) override; + virtual void SetPopupBounds(const gfx::Rect& bounds) override; + virtual const gfx::Rect& popup_bounds() const override; + virtual gfx::NativeView container_view() override; + virtual const gfx::RectF& element_bounds() const override; + virtual bool IsRTL() const override; + + virtual const std::vector& names() const override; + virtual const std::vector& subtexts() const override; + virtual const std::vector& icons() const override; + virtual const std::vector& identifiers() const override; #if !defined(OS_ANDROID) virtual const gfx::FontList& GetNameFontListForRow( - size_t index) const OVERRIDE; - virtual const gfx::FontList& subtext_font_list() const OVERRIDE; + size_t index) const override; + virtual const gfx::FontList& subtext_font_list() const override; #endif - virtual int selected_line() const OVERRIDE; + virtual int selected_line() const override; content::WebContents* web_contents(); diff --git a/src/browser/autofill_popup_view_views.h b/src/browser/autofill_popup_view_views.h index a10f9d1a3f..4c5ce14130 100644 --- a/src/browser/autofill_popup_view_views.h +++ b/src/browser/autofill_popup_view_views.h @@ -26,13 +26,13 @@ class AutofillPopupViewViews : public AutofillPopupBaseView, virtual ~AutofillPopupViewViews(); // AutofillPopupView implementation. - virtual void Show() OVERRIDE; - virtual void Hide() OVERRIDE; - virtual void InvalidateRow(size_t row) OVERRIDE; - virtual void UpdateBoundsAndRedrawPopup() OVERRIDE; + virtual void Show() override; + virtual void Hide() override; + virtual void InvalidateRow(size_t row) override; + virtual void UpdateBoundsAndRedrawPopup() override; // views::Views implementation - virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; + virtual void OnPaint(gfx::Canvas* canvas) override; // Draw the given autofill entry in |entry_rect|. void DrawAutofillEntry(gfx::Canvas* canvas, diff --git a/src/browser/browser_view_layout.h b/src/browser/browser_view_layout.h index 7854d06de4..82dcbabf8e 100644 --- a/src/browser/browser_view_layout.h +++ b/src/browser/browser_view_layout.h @@ -22,10 +22,10 @@ class BrowserViewLayout : public views::LayoutManager { virtual ~BrowserViewLayout(); // Overridden from LayoutManager: - virtual void Layout(views::View* host) OVERRIDE; - virtual gfx::Size GetPreferredSize(const views::View* host) const OVERRIDE; + virtual void Layout(views::View* host) override; + virtual gfx::Size GetPreferredSize(const views::View* host) const override; virtual int GetPreferredHeightForWidth(const views::View* host, - int width) const OVERRIDE; + int width) const override; void set_menu_bar(views::View* menu_bar) { menu_bar_ = menu_bar; } views::View* menu_bar() { return menu_bar_; } diff --git a/src/browser/capture_page_helper.cc b/src/browser/capture_page_helper.cc index 8743582ae2..89d0597f2d 100644 --- a/src/browser/capture_page_helper.cc +++ b/src/browser/capture_page_helper.cc @@ -91,10 +91,8 @@ void CapturePageHelper::StartCapturePage(const std::string& image_format_str) { this), kN32_SkColorType); } -void CapturePageHelper::CopyFromBackingStoreComplete( - bool succeeded, - const SkBitmap& bitmap) { - if (succeeded) { +void CapturePageHelper::CopyFromBackingStoreComplete(const SkBitmap& bitmap, content::ReadbackResponse response) { + if (response == content::READBACK_SUCCESS) { // Get image from backing store. SendResultFromBitmap(bitmap); return; diff --git a/src/browser/capture_page_helper.h b/src/browser/capture_page_helper.h index 0c76d9e2bc..9986a7fca1 100644 --- a/src/browser/capture_page_helper.h +++ b/src/browser/capture_page_helper.h @@ -24,6 +24,7 @@ #include "base/memory/ref_counted.h" #include "base/memory/weak_ptr.h" #include "content/public/browser/web_contents_observer.h" +#include "content/public/browser/readback_types.h" namespace content { class Shell; @@ -71,13 +72,11 @@ class CapturePageHelper : public base::RefCountedThreadSafe, // Message handler. void OnSnapshot(const SkBitmap& bitmap); - void CopyFromBackingStoreComplete( - bool succeeded, - const SkBitmap& bitmap); + void CopyFromBackingStoreComplete(const SkBitmap& bitmap, content::ReadbackResponse response); void SendResultFromBitmap(const SkBitmap& screen_capture); // content::WebContentsObserver overrides: - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) override; base::WeakPtr shell_; diff --git a/src/browser/chrome_crash_reporter_client.cc b/src/browser/chrome_crash_reporter_client.cc new file mode 100644 index 0000000000..e3f487f686 --- /dev/null +++ b/src/browser/chrome_crash_reporter_client.cc @@ -0,0 +1,377 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/app/chrome_crash_reporter_client.h" + +#include "base/atomicops.h" +#include "base/command_line.h" +#include "base/environment.h" +#include "base/files/file_path.h" +#include "base/logging.h" +#include "base/memory/scoped_ptr.h" +#include "base/path_service.h" +#include "base/strings/safe_sprintf.h" +#include "base/strings/string_split.h" +#include "base/strings/utf_string_conversions.h" +#include "chrome/common/chrome_constants.h" +#include "chrome/common/chrome_paths.h" +#include "chrome/common/chrome_result_codes.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/crash_keys.h" +#include "chrome/common/env_vars.h" +#include "chrome/installer/util/google_update_settings.h" + +#if defined(OS_WIN) +#include + +#include "base/file_version_info.h" +#include "base/win/registry.h" +#include "chrome/installer/util/google_chrome_sxs_distribution.h" +#include "chrome/installer/util/install_util.h" +#include "chrome/installer/util/util_constants.h" +#include "policy/policy_constants.h" +#endif + +#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS) +#include "chrome/browser/crash_upload_list.h" +#include "chrome/common/chrome_version_info_values.h" +#endif + +#if defined(OS_POSIX) +#include "base/debug/dump_without_crashing.h" +#endif + +#if defined(OS_ANDROID) +#include "chrome/common/descriptors_android.h" +#endif + +#if defined(OS_CHROMEOS) +#include "chrome/common/chrome_version_info.h" +#include "chromeos/chromeos_switches.h" +#endif + +namespace chrome { + +namespace { + +#if defined(OS_WIN) +// This is the minimum version of google update that is required for deferred +// crash uploads to work. +const char kMinUpdateVersion[] = "1.3.21.115"; + +// The value name prefix will be of the form {chrome-version}-{pid}-{timestamp} +// (i.e., "#####.#####.#####.#####-########-########") which easily fits into a +// 63 character buffer. +const char kBrowserCrashDumpPrefixTemplate[] = "%s-%08x-%08x"; +const size_t kBrowserCrashDumpPrefixLength = 63; +char g_browser_crash_dump_prefix[kBrowserCrashDumpPrefixLength + 1] = {}; + +// These registry key to which we'll write a value for each crash dump attempt. +HKEY g_browser_crash_dump_regkey = NULL; + +// A atomic counter to make each crash dump value name unique. +base::subtle::Atomic32 g_browser_crash_dump_count = 0; +#endif + +} // namespace + +ChromeCrashReporterClient::ChromeCrashReporterClient() {} + +ChromeCrashReporterClient::~ChromeCrashReporterClient() {} + +void ChromeCrashReporterClient::SetCrashReporterClientIdFromGUID( + const std::string& client_guid) { + crash_keys::SetCrashClientIdFromGUID(client_guid); +} + +#if defined(OS_WIN) +bool ChromeCrashReporterClient::GetAlternativeCrashDumpLocation( + base::FilePath* crash_dir) { + // By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate + // location to write breakpad crash dumps can be set. + scoped_ptr env(base::Environment::Create()); + std::string alternate_crash_dump_location; + if (env->GetVar("BREAKPAD_DUMP_LOCATION", &alternate_crash_dump_location)) { + *crash_dir = base::FilePath::FromUTF8Unsafe(alternate_crash_dump_location); + return true; + } + + return false; +} + +void ChromeCrashReporterClient::GetProductNameAndVersion( + const base::FilePath& exe_path, + base::string16* product_name, + base::string16* version, + base::string16* special_build, + base::string16* channel_name) { + DCHECK(product_name); + DCHECK(version); + DCHECK(special_build); + DCHECK(channel_name); + + scoped_ptr version_info( + FileVersionInfo::CreateFileVersionInfo(exe_path)); + + if (version_info.get()) { + // Get the information from the file. + *version = version_info->product_version(); + if (!version_info->is_official_build()) + version->append(base::ASCIIToUTF16("-devel")); + + *product_name = version_info->product_short_name(); + *special_build = version_info->special_build(); + } else { + // No version info found. Make up the values. + *product_name = base::ASCIIToUTF16("Chrome"); + *version = base::ASCIIToUTF16("0.0.0.0-devel"); + } + + GoogleUpdateSettings::GetChromeChannelAndModifiers( + !GetIsPerUserInstall(exe_path), channel_name); +} + +bool ChromeCrashReporterClient::ShouldShowRestartDialog(base::string16* title, + base::string16* message, + bool* is_rtl_locale) { + scoped_ptr env(base::Environment::Create()); + if (!env->HasVar(env_vars::kShowRestart) || + !env->HasVar(env_vars::kRestartInfo) || + env->HasVar(env_vars::kMetroConnected)) { + return false; + } + + std::string restart_info; + env->GetVar(env_vars::kRestartInfo, &restart_info); + + // The CHROME_RESTART var contains the dialog strings separated by '|'. + // See ChromeBrowserMainPartsWin::PrepareRestartOnCrashEnviroment() + // for details. + std::vector dlg_strings; + base::SplitString(restart_info, '|', &dlg_strings); + + if (dlg_strings.size() < 3) + return false; + + *title = base::UTF8ToUTF16(dlg_strings[0]); + *message = base::UTF8ToUTF16(dlg_strings[1]); + *is_rtl_locale = dlg_strings[2] == env_vars::kRtlLocale; + return true; +} + +bool ChromeCrashReporterClient::AboutToRestart() { + scoped_ptr env(base::Environment::Create()); + if (!env->HasVar(env_vars::kRestartInfo)) + return false; + + env->SetVar(env_vars::kShowRestart, "1"); + return true; +} + +bool ChromeCrashReporterClient::GetDeferredUploadsSupported( + bool is_per_user_install) { + Version update_version = GoogleUpdateSettings::GetGoogleUpdateVersion( + !is_per_user_install); + if (!update_version.IsValid() || + update_version.IsOlderThan(std::string(kMinUpdateVersion))) + return false; + + return true; +} + +bool ChromeCrashReporterClient::GetIsPerUserInstall( + const base::FilePath& exe_path) { + return InstallUtil::IsPerUserInstall(exe_path.value().c_str()); +} + +bool ChromeCrashReporterClient::GetShouldDumpLargerDumps( + bool is_per_user_install) { + base::string16 channel_name = + GoogleUpdateSettings::GetChromeChannel(!is_per_user_install); + + // Capture more detail in crash dumps for beta and dev channel builds. + return (channel_name == installer::kChromeChannelDev || + channel_name == installer::kChromeChannelBeta || + channel_name == GoogleChromeSxSDistribution::ChannelName()); +} + +int ChromeCrashReporterClient::GetResultCodeRespawnFailed() { + return chrome::RESULT_CODE_RESPAWN_FAILED; +} + +void ChromeCrashReporterClient::InitBrowserCrashDumpsRegKey() { + DCHECK(g_browser_crash_dump_regkey == NULL); + + base::win::RegKey regkey; + if (regkey.Create(HKEY_CURRENT_USER, + chrome::kBrowserCrashDumpAttemptsRegistryPath, + KEY_ALL_ACCESS) != ERROR_SUCCESS) { + return; + } + + // We use the current process id and the current tick count as a (hopefully) + // unique combination for the crash dump value. There's a small chance that + // across a reboot we might have a crash dump signal written, and the next + // browser process might have the same process id and tick count, but crash + // before consuming the signal (overwriting the signal with an identical one). + // For now, we're willing to live with that risk. + if (base::strings::SafeSPrintf(g_browser_crash_dump_prefix, + kBrowserCrashDumpPrefixTemplate, + chrome::kChromeVersion, + ::GetCurrentProcessId(), + ::GetTickCount()) <= 0) { + NOTREACHED(); + g_browser_crash_dump_prefix[0] = '\0'; + return; + } + + // Hold the registry key in a global for update on crash dump. + g_browser_crash_dump_regkey = regkey.Take(); +} + +void ChromeCrashReporterClient::RecordCrashDumpAttempt(bool is_real_crash) { + // If we're not a browser (or the registry is unavailable to us for some + // reason) then there's nothing to do. + if (g_browser_crash_dump_regkey == NULL) + return; + + // Generate the final value name we'll use (appends the crash number to the + // base value name). + const size_t kMaxValueSize = 2 * kBrowserCrashDumpPrefixLength; + char value_name[kMaxValueSize + 1] = {}; + if (base::strings::SafeSPrintf( + value_name, "%s-%x", g_browser_crash_dump_prefix, + base::subtle::NoBarrier_AtomicIncrement(&g_browser_crash_dump_count, + 1)) > 0) { + DWORD value_dword = is_real_crash ? 1 : 0; + ::RegSetValueExA(g_browser_crash_dump_regkey, value_name, 0, REG_DWORD, + reinterpret_cast(&value_dword), + sizeof(value_dword)); + } +} + +bool ChromeCrashReporterClient::ReportingIsEnforcedByPolicy( + bool* breakpad_enabled) { +// Determine whether configuration management allows loading the crash reporter. +// Since the configuration management infrastructure is not initialized at this +// point, we read the corresponding registry key directly. The return status +// indicates whether policy data was successfully read. If it is true, +// |breakpad_enabled| contains the value set by policy. + base::string16 key_name = + base::UTF8ToUTF16(policy::key::kMetricsReportingEnabled); + DWORD value = 0; + base::win::RegKey hklm_policy_key(HKEY_LOCAL_MACHINE, + policy::kRegistryChromePolicyKey, KEY_READ); + if (hklm_policy_key.ReadValueDW(key_name.c_str(), &value) == ERROR_SUCCESS) { + *breakpad_enabled = value != 0; + return true; + } + + base::win::RegKey hkcu_policy_key(HKEY_CURRENT_USER, + policy::kRegistryChromePolicyKey, KEY_READ); + if (hkcu_policy_key.ReadValueDW(key_name.c_str(), &value) == ERROR_SUCCESS) { + *breakpad_enabled = value != 0; + return true; + } + + return false; +} +#endif // defined(OS_WIN) + +#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS) +void ChromeCrashReporterClient::GetProductNameAndVersion( + const char** product_name, + const char** version) { + DCHECK(product_name); + DCHECK(version); +#if defined(OS_ANDROID) + *product_name = "Chrome_Android"; +#elif defined(OS_CHROMEOS) + *product_name = "Chrome_ChromeOS"; +#else // OS_LINUX +#if !defined(ADDRESS_SANITIZER) + *product_name = "Chrome_Linux"; +#else + *product_name = "Chrome_Linux_ASan"; +#endif +#endif + + *version = PRODUCT_VERSION; +} + +base::FilePath ChromeCrashReporterClient::GetReporterLogFilename() { + return base::FilePath(CrashUploadList::kReporterLogFilename); +} +#endif + +bool ChromeCrashReporterClient::GetCrashDumpLocation( + base::FilePath* crash_dir) { + // By setting the BREAKPAD_DUMP_LOCATION environment variable, an alternate + // location to write breakpad crash dumps can be set. + scoped_ptr env(base::Environment::Create()); + std::string alternate_crash_dump_location; + if (env->GetVar("BREAKPAD_DUMP_LOCATION", &alternate_crash_dump_location)) { + base::FilePath crash_dumps_dir_path = + base::FilePath::FromUTF8Unsafe(alternate_crash_dump_location); + PathService::Override(chrome::DIR_CRASH_DUMPS, crash_dumps_dir_path); + } + + return PathService::Get(chrome::DIR_CRASH_DUMPS, crash_dir); +} + +size_t ChromeCrashReporterClient::RegisterCrashKeys() { + // Note: This is not called on Windows because Breakpad is initialized in the + // EXE module, but code that uses crash keys is in the DLL module. + // RegisterChromeCrashKeys() will be called after the DLL is loaded. + return crash_keys::RegisterChromeCrashKeys(); +} + +bool ChromeCrashReporterClient::IsRunningUnattended() { + scoped_ptr env(base::Environment::Create()); + return env->HasVar(env_vars::kHeadless); +} + +bool ChromeCrashReporterClient::GetCollectStatsConsent() { +#if defined(GOOGLE_CHROME_BUILD) + bool is_official_chrome_build = true; +#else + // bool is_official_chrome_build = false; +#endif + +#if defined(OS_CHROMEOS) + bool is_guest_session = CommandLine::ForCurrentProcess()->HasSwitch( + chromeos::switches::kGuestSession); + bool is_stable_channel = + chrome::VersionInfo::GetChannel() == chrome::VersionInfo::CHANNEL_STABLE; + + if (is_guest_session && is_stable_channel) + return false; +#endif // defined(OS_CHROMEOS) + +#if defined(OS_ANDROID) + // TODO(jcivelli): we should not initialize the crash-reporter when it was not + // enabled. Right now if it is disabled we still generate the minidumps but we + // do not upload them. + return is_official_chrome_build; +#else // !defined(OS_ANDROID) + return false; +#endif // defined(OS_ANDROID) +} + +#if defined(OS_ANDROID) +int ChromeCrashReporterClient::GetAndroidMinidumpDescriptor() { + return kAndroidMinidumpDescriptor; +} +#endif + +bool ChromeCrashReporterClient::EnableBreakpadForProcess( + const std::string& process_type) { + return process_type == switches::kRendererProcess || + process_type == switches::kPluginProcess || + process_type == switches::kPpapiPluginProcess || + process_type == switches::kZygoteProcess || + process_type == switches::kGpuProcess; +} + +} // namespace chrome diff --git a/src/browser/chrome_crash_reporter_client.h b/src/browser/chrome_crash_reporter_client.h new file mode 100644 index 0000000000..d3eb42f1f3 --- /dev/null +++ b/src/browser/chrome_crash_reporter_client.h @@ -0,0 +1,76 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CHROME_APP_CHROME_CRASH_REPORTER_CLIENT_H_ +#define CHROME_APP_CHROME_CRASH_REPORTER_CLIENT_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "components/crash/app/crash_reporter_client.h" + +namespace chrome { + +class ChromeCrashReporterClient : public crash_reporter::CrashReporterClient { + public: + ChromeCrashReporterClient(); + ~ChromeCrashReporterClient() override; + + // crash_reporter::CrashReporterClient implementation. + void SetCrashReporterClientIdFromGUID( + const std::string& client_guid) override; +#if defined(OS_WIN) + virtual bool GetAlternativeCrashDumpLocation(base::FilePath* crash_dir) + override; + virtual void GetProductNameAndVersion(const base::FilePath& exe_path, + base::string16* product_name, + base::string16* version, + base::string16* special_build, + base::string16* channel_name) override; + virtual bool ShouldShowRestartDialog(base::string16* title, + base::string16* message, + bool* is_rtl_locale) override; + virtual bool AboutToRestart() override; + virtual bool GetDeferredUploadsSupported(bool is_per_user_install) override; + virtual bool GetIsPerUserInstall(const base::FilePath& exe_path) override; + virtual bool GetShouldDumpLargerDumps(bool is_per_user_install) override; + virtual int GetResultCodeRespawnFailed() override; + virtual void InitBrowserCrashDumpsRegKey() override; + virtual void RecordCrashDumpAttempt(bool is_real_crash) override; +#endif + +#if defined(OS_POSIX) && !defined(OS_MACOSX) && !defined(OS_IOS) + void GetProductNameAndVersion(const char** product_name, + const char** version) override; + base::FilePath GetReporterLogFilename() override; +#endif + + bool GetCrashDumpLocation(base::FilePath* crash_dir) override; + + size_t RegisterCrashKeys() override; + + bool IsRunningUnattended() override; + + bool GetCollectStatsConsent() override; + +#if defined(OS_WIN) || defined(OS_MACOSX) + bool ReportingIsEnforcedByPolicy(bool* breakpad_enabled) override; +#endif + +#if defined(OS_ANDROID) + virtual int GetAndroidMinidumpDescriptor() override; +#endif + +#if defined(OS_MACOSX) + void InstallAdditionalFilters(BreakpadRef breakpad) override; +#endif + + bool EnableBreakpadForProcess(const std::string& process_type) override; + + private: + DISALLOW_COPY_AND_ASSIGN(ChromeCrashReporterClient); +}; + +} // namespace chrome + +#endif // CHROME_APP_CHROME_CRASH_REPORTER_CLIENT_H_ diff --git a/src/browser/chrome_crash_reporter_client_mac.mm b/src/browser/chrome_crash_reporter_client_mac.mm new file mode 100644 index 0000000000..6bfa05d7e0 --- /dev/null +++ b/src/browser/chrome_crash_reporter_client_mac.mm @@ -0,0 +1,60 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "chrome/app/chrome_crash_reporter_client.h" + +#include + +#include "base/mac/scoped_cftyperef.h" +#include "base/strings/sys_string_conversions.h" +#include "policy/policy_constants.h" + +#if !defined(DISABLE_NACL) +#include "base/command_line.h" +#import "breakpad/src/client/mac/Framework/Breakpad.h" +#include "chrome/common/chrome_switches.h" +#include "components/nacl/common/nacl_switches.h" +#include "native_client/src/trusted/service_runtime/osx/crash_filter.h" +#endif + +namespace chrome { + +namespace { + +#if !defined(DISABLE_NACL) +bool NaClBreakpadCrashFilter(int exception_type, + int exception_code, + mach_port_t crashing_thread, + void* context) { + return !NaClMachThreadIsInUntrusted(crashing_thread); +} +#endif + +} // namespace + +void ChromeCrashReporterClient::InstallAdditionalFilters(BreakpadRef breakpad) { +#if !defined(DISABLE_NACL) + if (CommandLine::ForCurrentProcess()->GetSwitchValueASCII( + switches::kProcessType) == switches::kNaClLoaderProcess) { + BreakpadSetFilterCallback(breakpad, NaClBreakpadCrashFilter, NULL); + } +#endif +} + +bool ChromeCrashReporterClient::ReportingIsEnforcedByPolicy( + bool* breakpad_enabled) { + base::ScopedCFTypeRef key( + base::SysUTF8ToCFStringRef(policy::key::kMetricsReportingEnabled)); + Boolean key_valid; + Boolean metrics_reporting_enabled = CFPreferencesGetAppBooleanValue(key, + kCFPreferencesCurrentApplication, &key_valid); + if (key_valid && + CFPreferencesAppValueIsForced(key, kCFPreferencesCurrentApplication)) { + *breakpad_enabled = metrics_reporting_enabled; + return true; + } + return false; +} + +} // namespace chrome diff --git a/src/browser/color_chooser_aura.h b/src/browser/color_chooser_aura.h index e625550891..77b64c56e6 100644 --- a/src/browser/color_chooser_aura.h +++ b/src/browser/color_chooser_aura.h @@ -31,12 +31,12 @@ class ColorChooserAura : public content::ColorChooser, ColorChooserAura(content::WebContents* web_contents, SkColor initial_color); // content::ColorChooser overrides: - virtual void End() OVERRIDE; - virtual void SetSelectedColor(SkColor color) OVERRIDE; + virtual void End() override; + virtual void SetSelectedColor(SkColor color) override; // views::ColorChooserListener overrides: - virtual void OnColorChosen(SkColor color) OVERRIDE; - virtual void OnColorChooserDialogClosed() OVERRIDE; + virtual void OnColorChosen(SkColor color) override; + virtual void OnColorChooserDialogClosed() override; void DidEndColorChooser(); diff --git a/src/browser/file_select_helper.cc b/src/browser/file_select_helper.cc index 484859dd7e..7361815a83 100644 --- a/src/browser/file_select_helper.cc +++ b/src/browser/file_select_helper.cc @@ -1,34 +1,26 @@ -// 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. +// Copyright (c) 2012 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #include "content/nw/src/browser/file_select_helper.h" #include +#include #include "base/bind.h" -#include "base/file_util.h" -#include "base/logging.h" -#include "base/strings/string_util.h" +#include "base/files/file_enumerator.h" +#include "base/files/file_util.h" #include "base/strings/string_split.h" +#include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +//#include "chrome/browser/browser_process.h" #include "chrome/browser/platform_util.h" +//#include "chrome/browser/profiles/profile.h" +//#include "chrome/browser/profiles/profile_manager.h" +// #include "chrome/browser/ui/browser.h" +// #include "chrome/browser/ui/browser_list.h" +// #include "chrome/browser/ui/chrome_select_file_policy.h" +#include "grit/nw_resources.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/notification_details.h" #include "content/public/browser/notification_source.h" @@ -36,18 +28,22 @@ #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 "content/public/common/file_chooser_file_info.h" #include "content/public/common/file_chooser_params.h" -#include "grit/nw_resources.h" #include "net/base/mime_util.h" -#include "ui/shell_dialogs/selected_file_info.h" #include "ui/base/l10n/l10n_util.h" +#include "ui/shell_dialogs/selected_file_info.h" + +#if defined(OS_CHROMEOS) +#include "chrome/browser/chromeos/file_manager/fileapi_util.h" +#include "content/public/browser/site_instance.h" +#endif using content::BrowserThread; using content::FileChooserParams; using content::RenderViewHost; using content::RenderWidgetHost; using content::WebContents; -using base::FilePath; namespace { @@ -56,15 +52,9 @@ namespace { // the renderer must start at 0 and increase. const int kFileSelectEnumerationId = -1; -void NotifyRenderViewHost(RenderViewHost* render_view_host, - const std::vector& files, - FileChooserParams::Mode dialog_mode) { - render_view_host->FilesSelectedInChooser(files, dialog_mode); -} - // Converts a list of FilePaths to a list of ui::SelectedFileInfo. std::vector FilePathListToSelectedFileInfoList( - const std::vector& paths) { + const std::vector& paths) { std::vector selected_files; for (size_t i = 0; i < paths.size(); ++i) { selected_files.push_back( @@ -73,6 +63,11 @@ std::vector FilePathListToSelectedFileInfoList( return selected_files; } +void DeleteFiles(const std::vector& paths) { + for (auto& file_path : paths) + base::DeleteFile(file_path, false); +} + } // namespace struct FileSelectHelper::ActiveDirectoryEnumeration { @@ -81,17 +76,17 @@ struct FileSelectHelper::ActiveDirectoryEnumeration { scoped_ptr delegate_; scoped_ptr lister_; RenderViewHost* rvh_; - std::vector results_; + std::vector results_; }; FileSelectHelper::FileSelectHelper() - : render_view_host_(NULL), + : + render_view_host_(NULL), web_contents_(NULL), select_file_dialog_(), select_file_types_(), dialog_type_(ui::SelectFileDialog::SELECT_OPEN_FILE), - dialog_mode_(FileChooserParams::Open) -{ + dialog_mode_(FileChooserParams::Open) { } FileSelectHelper::~FileSelectHelper() { @@ -120,7 +115,7 @@ void FileSelectHelper::DirectoryListerDispatchDelegate::OnListDone(int error) { parent_->OnListDone(id_, error); } -void FileSelectHelper::FileSelected(const FilePath& path, +void FileSelectHelper::FileSelected(const base::FilePath& path, int index, void* params) { FileSelectedWithExtraInfo(ui::SelectedFileInfo(path, path), index, params); } @@ -129,26 +124,34 @@ void FileSelectHelper::FileSelectedWithExtraInfo( const ui::SelectedFileInfo& file, int index, void* params) { - if (!render_view_host_) + + if (!render_view_host_) { + RunFileChooserEnd(); return; + } - const FilePath& path = file.local_path; - if (dialog_type_ == ui::SelectFileDialog::SELECT_UPLOAD_FOLDER && - extract_directory_) { + const base::FilePath& path = file.local_path; + if (dialog_type_ == ui::SelectFileDialog::SELECT_UPLOAD_FOLDER) { StartNewEnumeration(path, kFileSelectEnumerationId, render_view_host_); return; } std::vector files; files.push_back(file); - NotifyRenderViewHost(render_view_host_, files, dialog_mode_); - // No members should be accessed from here on. - RunFileChooserEnd(); +#if defined(OS_MACOSX) && !defined(OS_IOS) + content::BrowserThread::PostTask( + content::BrowserThread::FILE_USER_BLOCKING, + FROM_HERE, + base::Bind(&FileSelectHelper::ProcessSelectedFilesMac, this, files)); +#else + NotifyRenderViewHostAndEnd(files); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) } -void FileSelectHelper::MultiFilesSelected(const std::vector& files, - void* params) { +void FileSelectHelper::MultiFilesSelected( + const std::vector& files, + void* params) { std::vector selected_files = FilePathListToSelectedFileInfoList(files); @@ -158,30 +161,22 @@ void FileSelectHelper::MultiFilesSelected(const std::vector& files, void FileSelectHelper::MultiFilesSelectedWithExtraInfo( const std::vector& files, void* params) { - if (!render_view_host_) - return; - NotifyRenderViewHost(render_view_host_, files, dialog_mode_); - - // No members should be accessed from here on. - RunFileChooserEnd(); +#if defined(OS_MACOSX) && !defined(OS_IOS) + content::BrowserThread::PostTask( + content::BrowserThread::FILE_USER_BLOCKING, + FROM_HERE, + base::Bind(&FileSelectHelper::ProcessSelectedFilesMac, this, files)); +#else + NotifyRenderViewHostAndEnd(files); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) } void FileSelectHelper::FileSelectionCanceled(void* params) { - if (!render_view_host_) - return; - - // If the user cancels choosing a file to upload we pass back an - // empty vector. - NotifyRenderViewHost( - render_view_host_, std::vector(), - dialog_mode_); - - // No members should be accessed from here on. - RunFileChooserEnd(); + NotifyRenderViewHostAndEnd(std::vector()); } -void FileSelectHelper::StartNewEnumeration(const FilePath& path, +void FileSelectHelper::StartNewEnumeration(const base::FilePath& path, int request_id, RenderViewHost* render_view_host) { scoped_ptr entry(new ActiveDirectoryEnumeration); @@ -207,13 +202,11 @@ void FileSelectHelper::OnListFile( const net::DirectoryLister::DirectoryListerData& data) { ActiveDirectoryEnumeration* entry = directory_enumerations_[id]; - // Directory upload returns directories via a "." file, so that - // empty directories are included. This util call just checks - // the flags in the structure; there's no file I/O going on. + // Directory upload only cares about files. if (data.info.IsDirectory()) - entry->results_.push_back(data.path.Append(FILE_PATH_LITERAL("."))); - else - entry->results_.push_back(data.path); + return; + + entry->results_.push_back(data.path); } void FileSelectHelper::OnListDone(int id, int error) { @@ -230,17 +223,71 @@ void FileSelectHelper::OnListDone(int id, int error) { std::vector selected_files = FilePathListToSelectedFileInfoList(entry->results_); - if (id == kFileSelectEnumerationId) - NotifyRenderViewHost(entry->rvh_, selected_files, dialog_mode_); - else + if (id == kFileSelectEnumerationId) { + NotifyRenderViewHostAndEnd(selected_files); + } else { entry->rvh_->DirectoryEnumerationFinished(id, entry->results_); + EnumerateDirectoryEnd(); + } +} + +void FileSelectHelper::NotifyRenderViewHostAndEnd( + const std::vector& files) { + if (!render_view_host_) { + RunFileChooserEnd(); + return; + } + +#if defined(OS_CHROMEOS) + if (!files.empty()) { + if (!IsValidProfile(profile_)) { + RunFileChooserEnd(); + return; + } + // Converts |files| into FileChooserFileInfo with handling of non-native + // files. + file_manager::util::ConvertSelectedFileInfoListToFileChooserFileInfoList( + file_manager::util::GetFileSystemContextForRenderViewHost( + profile_, render_view_host_), + web_contents_->GetSiteInstance()->GetSiteURL(), + files, + base::Bind( + &FileSelectHelper::NotifyRenderViewHostAndEndAfterConversion, + this)); + return; + } +#endif // defined(OS_CHROMEOS) + + std::vector chooser_files; + for (const auto& file : files) { + content::FileChooserFileInfo chooser_file; + chooser_file.file_path = file.local_path; + chooser_file.display_name = file.display_name; + chooser_files.push_back(chooser_file); + } + + NotifyRenderViewHostAndEndAfterConversion(chooser_files); +} + +void FileSelectHelper::NotifyRenderViewHostAndEndAfterConversion( + const std::vector& list) { + if (render_view_host_) + render_view_host_->FilesSelectedInChooser(list, dialog_mode_); - EnumerateDirectoryEnd(); + // No members should be accessed from here on. + RunFileChooserEnd(); +} + +void FileSelectHelper::DeleteTemporaryFiles() { + BrowserThread::PostTask(BrowserThread::FILE, + FROM_HERE, + base::Bind(&DeleteFiles, temporary_files_)); + temporary_files_.clear(); } scoped_ptr FileSelectHelper::GetFileTypesFromAcceptType( - const std::vector& accept_types) { + const std::vector& accept_types) { scoped_ptr base_file_type( new ui::SelectFileDialog::FileTypeInfo()); if (accept_types.empty()) @@ -251,7 +298,8 @@ FileSelectHelper::GetFileTypesFromAcceptType( new ui::SelectFileDialog::FileTypeInfo(*base_file_type)); file_type->include_all_files = true; file_type->extensions.resize(1); - std::vector* extensions = &file_type->extensions.back(); + std::vector* extensions = + &file_type->extensions.back(); // Find the corresponding extensions. int valid_type_count = 0; @@ -311,14 +359,13 @@ void FileSelectHelper::RunFileChooser(content::WebContents* tab, // FileSelectHelper will keep itself alive until it sends the result message. scoped_refptr file_select_helper( new FileSelectHelper()); - file_select_helper->extract_directory_ = params.extract_directory; file_select_helper->RunFileChooser(tab->GetRenderViewHost(), tab, params); } // static void FileSelectHelper::EnumerateDirectory(content::WebContents* tab, int request_id, - const FilePath& path) { + const base::FilePath& path) { // FileSelectHelper will keep itself alive until it sends the result message. scoped_refptr file_select_helper( new FileSelectHelper()); @@ -334,8 +381,12 @@ void FileSelectHelper::RunFileChooser(RenderViewHost* render_view_host, render_view_host_ = render_view_host; web_contents_ = web_contents; notification_registrar_.RemoveAll(); + notification_registrar_.Add(this, + content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED, + content::Source(web_contents_)); notification_registrar_.Add( - this, content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, + this, + content::NOTIFICATION_RENDER_WIDGET_HOST_DESTROYED, content::Source(render_view_host_)); notification_registrar_.Add( this, content::NOTIFICATION_WEB_CONTENTS_DESTROYED, @@ -355,8 +406,8 @@ void FileSelectHelper::RunFileChooser(RenderViewHost* render_view_host, void FileSelectHelper::RunFileChooserOnFileThread( const FileChooserParams& params) { - select_file_types_ = - GetFileTypesFromAcceptType(params.accept_types); + select_file_types_ = GetFileTypesFromAcceptType(params.accept_types); + select_file_types_->support_drive = !params.need_local_path; BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, @@ -372,7 +423,10 @@ void FileSelectHelper::RunFileChooserOnUIThread( return; } - select_file_dialog_ = ui::SelectFileDialog::Create(this, NULL); + select_file_dialog_ = ui::SelectFileDialog::Create( + this, NULL); + if (!select_file_dialog_.get()) + return; dialog_mode_ = params.mode; switch (params.mode) { @@ -383,7 +437,7 @@ void FileSelectHelper::RunFileChooserOnUIThread( dialog_type_ = ui::SelectFileDialog::SELECT_OPEN_MULTI_FILE; break; case FileChooserParams::UploadFolder: - dialog_type_ = ui::SelectFileDialog::SELECT_FOLDER; + dialog_type_ = ui::SelectFileDialog::SELECT_UPLOAD_FOLDER; break; case FileChooserParams::Save: dialog_type_ = ui::SelectFileDialog::SELECT_SAVEAS_FILE; @@ -394,15 +448,16 @@ void FileSelectHelper::RunFileChooserOnUIThread( NOTREACHED(); } - FilePath default_file_name = params.default_file_name; - FilePath working_path = params.initial_path; + base::FilePath default_file_name = params.default_file_name; + base::FilePath working_path = params.initial_path; -#if defined(OS_WIN) - gfx::NativeWindow owning_window = - (gfx::NativeWindow)::GetAncestor((HWND)render_view_host_->GetView()->GetNativeView(), GA_ROOT); -#else gfx::NativeWindow owning_window = platform_util::GetTopLevel(render_view_host_->GetView()->GetNativeView()); + +#if defined(OS_ANDROID) + // Android needs the original MIME types and an additional capture value. + std::pair, bool> accept_types = + std::make_pair(params.accept_types, params.capture); #endif select_file_dialog_->SelectFile( @@ -410,11 +465,17 @@ void FileSelectHelper::RunFileChooserOnUIThread( params.title, default_file_name, select_file_types_.get(), - select_file_types_.get() ? 1 : 0, // 1-based index. - FILE_PATH_LITERAL(""), + select_file_types_.get() && !select_file_types_->extensions.empty() + ? 1 + : 0, // 1-based index of default extension to show. + base::FilePath::StringType(), owning_window, - const_cast(¶ms), - working_path); +#if defined(OS_ANDROID) + &accept_types); +#else + NULL, + working_path); +#endif select_file_types_.reset(); } @@ -423,6 +484,12 @@ void FileSelectHelper::RunFileChooserOnUIThread( // chooser dialog. Perform any cleanup and release the reference we added // in RunFileChooser(). void FileSelectHelper::RunFileChooserEnd() { + // If there are temporary files, then this instance needs to stick around + // until web_contents_ is destroyed, so that this instance can delete the + // temporary files. + if (!temporary_files_.empty()) + return; + render_view_host_ = NULL; web_contents_ = NULL; Release(); @@ -430,7 +497,7 @@ void FileSelectHelper::RunFileChooserEnd() { void FileSelectHelper::EnumerateDirectory(int request_id, RenderViewHost* render_view_host, - const FilePath& path) { + const base::FilePath& path) { // Because this class returns notifications to the RenderViewHost, it is // difficult for callers to know how long to keep a reference to this @@ -462,9 +529,20 @@ void FileSelectHelper::Observe(int type, case content::NOTIFICATION_WEB_CONTENTS_DESTROYED: { DCHECK(content::Source(source).ptr() == web_contents_); web_contents_ = NULL; - break; } + // Intentional fall through. + case content::NOTIFICATION_RENDER_VIEW_HOST_CHANGED: + if (!temporary_files_.empty()) { + DeleteTemporaryFiles(); + + // Now that the temporary files have been scheduled for deletion, there + // is no longer any reason to keep this instance around. + Release(); + } + + break; + default: NOTREACHED(); } @@ -478,7 +556,8 @@ bool FileSelectHelper::IsAcceptTypeValid(const std::string& accept_type) { std::string unused; if (accept_type.length() <= 1 || base::StringToLowerASCII(accept_type) != accept_type || - base::TrimWhitespaceASCII(accept_type, base::TRIM_ALL, &unused) != base::TRIM_NONE) { + base::TrimWhitespaceASCII(accept_type, base::TRIM_ALL, &unused) != + base::TRIM_NONE) { return false; } return true; diff --git a/src/browser/file_select_helper.h b/src/browser/file_select_helper.h index e488a4ad1b..cb04dcafb5 100644 --- a/src/browser/file_select_helper.h +++ b/src/browser/file_select_helper.h @@ -1,25 +1,9 @@ -// 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_FILE_SELECT_HELPER_H_ -#define CONTENT_NW_SRC_BROWSER_FILE_SELECT_HELPER_H_ +// 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. + +#ifndef CHROME_BROWSER_FILE_SELECT_HELPER_H_ +#define CHROME_BROWSER_FILE_SELECT_HELPER_H_ #include #include @@ -32,7 +16,10 @@ #include "net/base/directory_lister.h" #include "ui/shell_dialogs/select_file_dialog.h" +class Profile; + namespace content { +struct FileChooserFileInfo; class RenderViewHost; class WebContents; } @@ -41,9 +28,6 @@ namespace ui { struct SelectedFileInfo; } -namespace base { -class FilePath; -} // This class handles file-selection requests coming from WebUI elements // (via the extensions::ExtensionHost class). It implements both the // initialisation and listener functions for file-selection dialogs. @@ -65,8 +49,9 @@ class FileSelectHelper private: friend class base::RefCountedThreadSafe; FRIEND_TEST_ALL_PREFIXES(FileSelectHelperTest, IsAcceptTypeValid); + FRIEND_TEST_ALL_PREFIXES(FileSelectHelperTest, ZipPackage); explicit FileSelectHelper(); - virtual ~FileSelectHelper(); + ~FileSelectHelper() override; // Utility class which can listen for directory lister events and relay // them to the main object with the correct tracking id. @@ -76,10 +61,11 @@ class FileSelectHelper DirectoryListerDispatchDelegate(FileSelectHelper* parent, int id) : parent_(parent), id_(id) {} - virtual ~DirectoryListerDispatchDelegate() {} - virtual void OnListFile( - const net::DirectoryLister::DirectoryListerData& data) OVERRIDE; - virtual void OnListDone(int error) OVERRIDE; + ~DirectoryListerDispatchDelegate() override {} + void OnListFile( + const net::DirectoryLister::DirectoryListerData& data) override; + void OnListDone(int error) override; + private: // This FileSelectHelper owns this object. FileSelectHelper* parent_; @@ -89,7 +75,7 @@ class FileSelectHelper }; void RunFileChooser(content::RenderViewHost* render_view_host, - content::WebContents* tab_contents, + content::WebContents* web_contents, const content::FileChooserParams& params); void RunFileChooserOnFileThread( const content::FileChooserParams& params); @@ -101,23 +87,23 @@ class FileSelectHelper void RunFileChooserEnd(); // SelectFileDialog::Listener overrides. - virtual void FileSelected( - const base::FilePath& path, int index, void* params) OVERRIDE; - virtual void FileSelectedWithExtraInfo( - const ui::SelectedFileInfo& file, - int index, - void* params) OVERRIDE; - virtual void MultiFilesSelected(const std::vector& files, - void* params) OVERRIDE; - virtual void MultiFilesSelectedWithExtraInfo( + void FileSelected(const base::FilePath& path, + int index, + void* params) override; + void FileSelectedWithExtraInfo(const ui::SelectedFileInfo& file, + int index, + void* params) override; + void MultiFilesSelected(const std::vector& files, + void* params) override; + void MultiFilesSelectedWithExtraInfo( const std::vector& files, - void* params) OVERRIDE; - virtual void FileSelectionCanceled(void* params) OVERRIDE; + void* params) override; + void FileSelectionCanceled(void* params) override; // content::NotificationObserver overrides. - virtual void Observe(int type, - const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; + void Observe(int type, + const content::NotificationSource& source, + const content::NotificationDetails& details) override; void EnumerateDirectory(int request_id, content::RenderViewHost* render_view_host, @@ -138,15 +124,45 @@ class FileSelectHelper // callback is received from the enumeration code. void EnumerateDirectoryEnd(); - bool extract_directory_; +#if defined(OS_MACOSX) && !defined(OS_IOS) + // Must be called on the FILE_USER_BLOCKING thread. Each selected file that is + // a package will be zipped, and the zip will be passed to the render view + // host in place of the package. + void ProcessSelectedFilesMac(const std::vector& files); + + // Saves the paths of |zipped_files| for later deletion. Passes |files| to the + // render view host. + void ProcessSelectedFilesMacOnUIThread( + const std::vector& files, + const std::vector& zipped_files); + + // Zips the package at |path| into a temporary destination. Returns the + // temporary destination, if the zip was successful. Otherwise returns an + // empty path. + static base::FilePath ZipPackage(const base::FilePath& path); +#endif // defined(OS_MACOSX) && !defined(OS_IOS) + + // Utility method that passes |files| to the render view host, and ends the + // file chooser. + void NotifyRenderViewHostAndEnd( + const std::vector& files); + + // Sends the result to the render process, and call |RunFileChooserEnd|. + void NotifyRenderViewHostAndEndAfterConversion( + const std::vector& list); + + // Schedules the deletion of the files in |temporary_files_| and clears the + // vector. + void DeleteTemporaryFiles(); // Helper method to get allowed extensions for select file dialog from // the specified accept types as defined in the spec: // http://whatwg.org/html/number-state.html#attr-input-accept // |accept_types| contains only valid lowercased MIME types or file extensions // beginning with a period (.). - scoped_ptr GetFileTypesFromAcceptType( - const std::vector& accept_types); + static scoped_ptr + GetFileTypesFromAcceptType( + const std::vector& accept_types); // Check the accept type is valid. It is expected to be all lower case with // no whitespace. @@ -176,7 +192,11 @@ class FileSelectHelper // Registrar for notifications regarding our RenderViewHost. content::NotificationRegistrar notification_registrar_; + // Temporary files only used on OSX. This class is responsible for deleting + // these files when they are no longer needed. + std::vector temporary_files_; + DISALLOW_COPY_AND_ASSIGN(FileSelectHelper); }; -#endif // CONTENT_NW_SRC_BROWSER_FILE_SELECT_HELPER_H_ +#endif // CHROME_BROWSER_FILE_SELECT_HELPER_H_ diff --git a/src/browser/media_capture_util.cc b/src/browser/media_capture_util.cc new file mode 100644 index 0000000000..30e3fb63c7 --- /dev/null +++ b/src/browser/media_capture_util.cc @@ -0,0 +1,88 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/shell/browser/media_capture_util.h" + +#include + +#include "base/callback.h" +#include "base/logging.h" +#include "content/public/browser/media_capture_devices.h" +#include "extensions/common/permissions/permissions_data.h" + +using content::MediaCaptureDevices; +using content::MediaStreamDevice; +using content::MediaStreamDevices; +using content::MediaStreamUI; + +namespace extensions { + +const MediaStreamDevice* GetRequestedDeviceOrDefault( + const MediaStreamDevices& devices, + const std::string& requested_device_id) { + if (!requested_device_id.empty()) + return devices.FindById(requested_device_id); + + if (!devices.empty()) + return &devices[0]; + + return NULL; +} + +namespace media_capture_util { + +// See also Chrome's MediaCaptureDevicesDispatcher. +void GrantMediaStreamRequest(content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const Extension* extension) { + // app_shell only supports audio and video capture, not tab or screen capture. + DCHECK(request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE || + request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE); + + MediaStreamDevices devices; + + if (request.audio_type == content::MEDIA_DEVICE_AUDIO_CAPTURE) { + VerifyMediaAccessPermission(request.audio_type, extension); + const MediaStreamDevice* device = GetRequestedDeviceOrDefault( + MediaCaptureDevices::GetInstance()->GetAudioCaptureDevices(), + request.requested_audio_device_id); + if (device) + devices.push_back(*device); + } + + if (request.video_type == content::MEDIA_DEVICE_VIDEO_CAPTURE) { + VerifyMediaAccessPermission(request.video_type, extension); + const MediaStreamDevice* device = GetRequestedDeviceOrDefault( + MediaCaptureDevices::GetInstance()->GetVideoCaptureDevices(), + request.requested_video_device_id); + if (device) + devices.push_back(*device); + } + + // TODO(jamescook): Should we show a recording icon somewhere? If so, where? + scoped_ptr ui; + callback.Run(devices, + devices.empty() ? content::MEDIA_DEVICE_INVALID_STATE + : content::MEDIA_DEVICE_OK, + ui.Pass()); +} + +void VerifyMediaAccessPermission(content::MediaStreamType type, + const Extension* extension) { + const PermissionsData* permissions_data = extension->permissions_data(); + if (type == content::MEDIA_DEVICE_AUDIO_CAPTURE) { + // app_shell has no UI surface to show an error, and on an embedded device + // it's better to crash than to have a feature not work. + CHECK(permissions_data->HasAPIPermission(APIPermission::kAudioCapture)) + << "Audio capture request but no audioCapture permission in manifest."; + } else { + DCHECK(type == content::MEDIA_DEVICE_VIDEO_CAPTURE); + CHECK(permissions_data->HasAPIPermission(APIPermission::kVideoCapture)) + << "Video capture request but no videoCapture permission in manifest."; + } +} + +} // namespace media_capture_util +} // namespace extensions diff --git a/src/browser/media_capture_util.h b/src/browser/media_capture_util.h new file mode 100644 index 0000000000..b1b15ba98c --- /dev/null +++ b/src/browser/media_capture_util.h @@ -0,0 +1,38 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_SHELL_BROWSER_MEDIA_CAPTURE_UTIL_H_ +#define EXTENSIONS_SHELL_BROWSER_MEDIA_CAPTURE_UTIL_H_ + +#include "base/macros.h" +#include "content/public/common/media_stream_request.h" + +namespace content { +class WebContents; +} + +namespace extensions { + +class Extension; + +namespace media_capture_util { + +// Grants access to audio and video capture devices. +// * If the caller requests specific device ids, grants access to those. +// * If the caller does not request specific ids, grants access to the first +// available device. +// Usually used as a helper for media capture ProcessMediaAccessRequest(). +void GrantMediaStreamRequest(content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const Extension* extension); + +// Verifies that the extension has permission for |type|. If not, crash. +void VerifyMediaAccessPermission(content::MediaStreamType type, + const Extension* extension); + +} // namespace media_capture_util +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_MEDIA_CAPTURE_UTIL_H_ diff --git a/src/browser/menubar_controller.h b/src/browser/menubar_controller.h index 90be4c0209..f6c3351985 100644 --- a/src/browser/menubar_controller.h +++ b/src/browser/menubar_controller.h @@ -27,7 +27,7 @@ class MenuBarController : public views::MenuModelAdapter { const gfx::Point& screen_point, views::MenuAnchorPosition* anchor, bool* has_mnemonics, - views::MenuButton** button) OVERRIDE; + views::MenuButton** button) override; private: typedef std::map ModelToMenuMap; diff --git a/src/browser/menubar_view.cc b/src/browser/menubar_view.cc index 9aba44e7de..35c5936f95 100644 --- a/src/browser/menubar_view.cc +++ b/src/browser/menubar_view.cc @@ -41,13 +41,13 @@ class MenuBarButton : public views::MenuButton { } virtual bool GetTooltipText(const gfx::Point& p, - base::string16* tooltip) const OVERRIDE { + base::string16* tooltip) const override { if (label()->GetPreferredSize().width() > label()->size().width()) *tooltip = GetText(); return !tooltip->empty(); } - virtual bool IsTriggerableEvent(const ui::Event& e) OVERRIDE { + virtual bool IsTriggerableEvent(const ui::Event& e) override { // Left clicks and taps should show the menu contents and right clicks // should show the context menu. They should not trigger the opening of // underlying urls. diff --git a/src/browser/menubar_view.h b/src/browser/menubar_view.h index 51615101a8..5d524a4c1c 100644 --- a/src/browser/menubar_view.h +++ b/src/browser/menubar_view.h @@ -50,12 +50,12 @@ class MenuBarView : // views::MenuButtonListener: virtual void OnMenuButtonClicked(views::View* view, - const gfx::Point& point) OVERRIDE; + const gfx::Point& point) override; // views::ButtonListener: virtual void ButtonPressed(views::Button* sender, - const ui::Event& event) OVERRIDE; - virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) OVERRIDE; + const ui::Event& event) override; + virtual void OnNativeThemeChanged(const ui::NativeTheme* theme) override; private: ui::MenuModel* model_; diff --git a/src/browser/native_window_aura.cc b/src/browser/native_window_aura.cc index 27c1fc30ee..f7fbd0f2e0 100644 --- a/src/browser/native_window_aura.cc +++ b/src/browser/native_window_aura.cc @@ -121,7 +121,7 @@ class NativeWindowClientView : public views::ClientView { } virtual ~NativeWindowClientView() {} - virtual bool CanClose() OVERRIDE { + virtual bool CanClose() override { if (shell_) return shell_->ShouldCloseWindow(); else @@ -142,23 +142,24 @@ class NativeWindowFrameView : public views::NonClientFrameView { void Init(views::Widget* frame); // views::NonClientFrameView implementation. - virtual gfx::Rect GetBoundsForClientView() const OVERRIDE; + virtual gfx::Rect GetBoundsForClientView() const override; virtual gfx::Rect GetWindowBoundsForClientBounds( - const gfx::Rect& client_bounds) const OVERRIDE; - virtual int NonClientHitTest(const gfx::Point& point) OVERRIDE; + const gfx::Rect& client_bounds) const override; + virtual int NonClientHitTest(const gfx::Point& point) override; virtual void GetWindowMask(const gfx::Size& size, - gfx::Path* window_mask) OVERRIDE; - virtual void ResetWindowControls() OVERRIDE {} - virtual void UpdateWindowIcon() OVERRIDE {} - virtual void UpdateWindowTitle() OVERRIDE {} + gfx::Path* window_mask) override; + virtual void ResetWindowControls() override {} + virtual void UpdateWindowIcon() override {} + virtual void UpdateWindowTitle() override {} + virtual void SizeConstraintsChanged() override {} // views::View implementation. - virtual gfx::Size GetPreferredSize() const OVERRIDE; - virtual void Layout() OVERRIDE; - virtual const char* GetClassName() const OVERRIDE; - virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE; - virtual gfx::Size GetMinimumSize() const OVERRIDE; - virtual gfx::Size GetMaximumSize() const OVERRIDE; + virtual gfx::Size GetPreferredSize() const override; + virtual void Layout() override; + virtual const char* GetClassName() const override; + virtual void OnPaint(gfx::Canvas* canvas) override; + virtual gfx::Size GetMinimumSize() const override; + virtual gfx::Size GetMaximumSize() const override; private: NativeWindowAura* window_; @@ -488,7 +489,8 @@ void NativeWindowAura::SetTransparent(bool transparent) { content::RenderWidgetHostView* rwhv = shell_->web_contents()->GetRenderWidgetHostView(); if (rwhv) { - rwhv->SetBackgroundOpaque(!transparent); + if (transparent) + rwhv->SetBackgroundColor(SK_ColorTRANSPARENT); } transparent_ = transparent; diff --git a/src/browser/native_window_aura.h b/src/browser/native_window_aura.h index eed8560284..68de9fd225 100644 --- a/src/browser/native_window_aura.h +++ b/src/browser/native_window_aura.h @@ -67,61 +67,61 @@ class NativeWindowAura : public NativeWindow, BrowserViewLayout* GetBrowserViewLayout() const; // NativeWindow implementation. - virtual void Close() OVERRIDE; - virtual void Move(const gfx::Rect& pos) OVERRIDE; - virtual void Focus(bool focus) OVERRIDE; - virtual void Show() OVERRIDE; - virtual void Hide() OVERRIDE; - virtual void Maximize() OVERRIDE; - virtual void Unmaximize() OVERRIDE; - virtual void Minimize() OVERRIDE; - virtual void Restore() OVERRIDE; - virtual void SetFullscreen(bool fullscreen) OVERRIDE; - virtual bool IsFullscreen() OVERRIDE; - virtual void SetTransparent(bool transparent) OVERRIDE; - virtual void SetSize(const gfx::Size& size) OVERRIDE; - virtual gfx::Size GetSize() OVERRIDE; - virtual void SetMinimumSize(int width, int height) OVERRIDE; - virtual void SetMaximumSize(int width, int height) OVERRIDE; - virtual void SetResizable(bool resizable) OVERRIDE; - virtual void SetAlwaysOnTop(bool top) OVERRIDE; - virtual void SetShowInTaskbar(bool show = true) OVERRIDE; - virtual void SetVisibleOnAllWorkspaces(bool all_workspaces) OVERRIDE; - virtual void SetPosition(const std::string& position) OVERRIDE; - virtual void SetPosition(const gfx::Point& position) OVERRIDE; - virtual gfx::Point GetPosition() OVERRIDE; - virtual void SetTitle(const std::string& title) OVERRIDE; - virtual void FlashFrame(int count) OVERRIDE; - virtual void SetKiosk(bool kiosk) OVERRIDE; - virtual void SetBadgeLabel(const std::string& badge) OVERRIDE; - virtual void SetProgressBar(double progress) OVERRIDE; - virtual bool IsKiosk() OVERRIDE; - virtual void SetMenu(nwapi::Menu* menu) OVERRIDE; + virtual void Close() override; + virtual void Move(const gfx::Rect& pos) override; + virtual void Focus(bool focus) override; + virtual void Show() override; + virtual void Hide() override; + virtual void Maximize() override; + virtual void Unmaximize() override; + virtual void Minimize() override; + virtual void Restore() override; + virtual void SetFullscreen(bool fullscreen) override; + virtual bool IsFullscreen() override; + virtual void SetTransparent(bool transparent) override; + virtual void SetSize(const gfx::Size& size) override; + virtual gfx::Size GetSize() override; + virtual void SetMinimumSize(int width, int height) override; + virtual void SetMaximumSize(int width, int height) override; + virtual void SetResizable(bool resizable) override; + virtual void SetAlwaysOnTop(bool top) override; + virtual void SetShowInTaskbar(bool show = true) override; + virtual void SetVisibleOnAllWorkspaces(bool all_workspaces) override; + virtual void SetPosition(const std::string& position) override; + virtual void SetPosition(const gfx::Point& position) override; + virtual gfx::Point GetPosition() override; + virtual void SetTitle(const std::string& title) override; + virtual void FlashFrame(int count) override; + virtual void SetKiosk(bool kiosk) override; + virtual void SetBadgeLabel(const std::string& badge) override; + virtual void SetProgressBar(double progress) override; + virtual bool IsKiosk() override; + virtual void SetMenu(nwapi::Menu* menu) override; virtual void SetToolbarButtonEnabled(TOOLBAR_BUTTON button, - bool enabled) OVERRIDE; - virtual void SetToolbarUrlEntry(const std::string& url) OVERRIDE; - virtual void SetToolbarIsLoading(bool loading) OVERRIDE; - virtual void SetInitialFocus(bool initial_focus) OVERRIDE; - virtual bool InitialFocus() OVERRIDE; + bool enabled) override; + virtual void SetToolbarUrlEntry(const std::string& url) override; + virtual void SetToolbarIsLoading(bool loading) override; + virtual void SetInitialFocus(bool initial_focus) override; + virtual bool InitialFocus() override; // WidgetDelegate implementation. - virtual void OnWidgetMove() OVERRIDE; - virtual views::View* GetContentsView() OVERRIDE; - virtual views::ClientView* CreateClientView(views::Widget*) OVERRIDE; + virtual void OnWidgetMove() override; + virtual views::View* GetContentsView() override; + virtual views::ClientView* CreateClientView(views::Widget*) override; virtual views::NonClientFrameView* CreateNonClientFrameView( - views::Widget* widget) OVERRIDE; - virtual bool CanResize() const OVERRIDE; - virtual bool CanMaximize() const OVERRIDE; - virtual views::Widget* GetWidget() OVERRIDE; - virtual const views::Widget* GetWidget() const OVERRIDE; - virtual base::string16 GetWindowTitle() const OVERRIDE; - virtual void DeleteDelegate() OVERRIDE; - virtual views::View* GetInitiallyFocusedView() OVERRIDE; - virtual gfx::ImageSkia GetWindowAppIcon() OVERRIDE; - virtual gfx::ImageSkia GetWindowIcon() OVERRIDE; - virtual bool ShouldShowWindowTitle() const OVERRIDE; - virtual bool ShouldHandleOnSize() const OVERRIDE; - virtual void HandleWMStateUpdate() OVERRIDE; + views::Widget* widget) override; + virtual bool CanResize() const override; + virtual bool CanMaximize() const override; + virtual views::Widget* GetWidget() override; + virtual const views::Widget* GetWidget() const override; + virtual base::string16 GetWindowTitle() const override; + virtual void DeleteDelegate() override; + virtual views::View* GetInitiallyFocusedView() override; + virtual gfx::ImageSkia GetWindowAppIcon() override; + virtual gfx::ImageSkia GetWindowIcon() override; + virtual bool ShouldShowWindowTitle() const override; + virtual bool ShouldHandleOnSize() const override; + virtual void HandleWMStateUpdate() override; views::UnhandledKeyboardEventHandler unhandled_keyboard_event_handler_; @@ -129,48 +129,48 @@ class NativeWindowAura : public NativeWindow, // WidgetFocusChangeListener implementation. virtual void OnNativeFocusChange(gfx::NativeView focused_before, - gfx::NativeView focused_now) OVERRIDE; + gfx::NativeView focused_now) override; // WidgetObserver implementation - virtual void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) OVERRIDE; + virtual void OnWidgetBoundsChanged(views::Widget* widget, const gfx::Rect& new_bounds) override; virtual void OnWidgetActivationChanged(views::Widget* widget, - bool active) OVERRIDE; + bool active) override; - virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) OVERRIDE; + virtual bool AcceleratorPressed(const ui::Accelerator& accelerator) override; - virtual bool CanHandleAccelerators() const OVERRIDE; + virtual bool CanHandleAccelerators() const override; - virtual gfx::NativeView GetHostView() const OVERRIDE; - virtual gfx::Point GetDialogPosition(const gfx::Size& size) OVERRIDE; - virtual void AddObserver(web_modal::ModalDialogHostObserver* observer) OVERRIDE; - virtual void RemoveObserver(web_modal::ModalDialogHostObserver* observer) OVERRIDE; - virtual gfx::Size GetMaximumDialogSize() OVERRIDE; + virtual gfx::NativeView GetHostView() const override; + virtual gfx::Point GetDialogPosition(const gfx::Size& size) override; + virtual void AddObserver(web_modal::ModalDialogHostObserver* observer) override; + virtual void RemoveObserver(web_modal::ModalDialogHostObserver* observer) override; + virtual gfx::Size GetMaximumDialogSize() override; protected: // NativeWindow implementation. - virtual void AddToolbar() OVERRIDE; + virtual void AddToolbar() override; virtual void UpdateDraggableRegions( - const std::vector& regions) OVERRIDE; + const std::vector& regions) override; virtual void HandleKeyboardEvent( - const content::NativeWebKeyboardEvent& event) OVERRIDE; + const content::NativeWebKeyboardEvent& event) override; // views::View implementation. - // virtual void Layout() OVERRIDE; + // virtual void Layout() override; virtual void ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) OVERRIDE; - virtual gfx::Size GetMinimumSize() const OVERRIDE; - virtual gfx::Size GetMaximumSize() const OVERRIDE; - virtual void OnFocus() OVERRIDE; + const ViewHierarchyChangedDetails& details) override; + virtual gfx::Size GetMinimumSize() const override; + virtual gfx::Size GetMaximumSize() const override; + virtual void OnFocus() override; // views::WidgetDelegate implementation. - virtual bool ExecuteWindowsCommand(int command_id) OVERRIDE; - virtual bool HandleSize(unsigned int param, const gfx::Size& size) OVERRIDE; - virtual bool ExecuteAppCommand(int command_id) OVERRIDE; + virtual bool ExecuteWindowsCommand(int command_id) override; + virtual bool HandleSize(unsigned int param, const gfx::Size& size) override; + virtual bool ExecuteAppCommand(int command_id) override; virtual void SaveWindowPlacement(const gfx::Rect& bounds, - ui::WindowShowState show_state) OVERRIDE; + ui::WindowShowState show_state) override; virtual bool ShouldDescendIntoChildForEventHandling( gfx::NativeView child, - const gfx::Point& location) OVERRIDE; + const gfx::Point& location) override; private: friend class content::Shell; friend class nwapi::Menu; diff --git a/src/browser/native_window_toolbar_aura.h b/src/browser/native_window_toolbar_aura.h index 54ef8cfb95..8100be5b7a 100644 --- a/src/browser/native_window_toolbar_aura.h +++ b/src/browser/native_window_toolbar_aura.h @@ -52,22 +52,22 @@ class NativeWindowToolbarAura : public views::WidgetDelegateView, protected: // Overridden from WidgetDelegateView: - virtual views::View* GetContentsView() OVERRIDE; + virtual views::View* GetContentsView() override; // Overridden from View: - virtual void Layout() OVERRIDE; + virtual void Layout() override; virtual void ViewHierarchyChanged( - const ViewHierarchyChangedDetails& details) OVERRIDE; + const ViewHierarchyChangedDetails& details) override; // Overridden from TextfieldController: virtual void ContentsChanged(views::Textfield* sender, - const base::string16& new_contents) OVERRIDE; + const base::string16& new_contents) override; virtual bool HandleKeyEvent(views::Textfield* sender, - const ui::KeyEvent& key_event) OVERRIDE; + const ui::KeyEvent& key_event) override; // Overridden from ButtonListener: virtual void ButtonPressed(views::Button* sender, - const ui::Event& event) OVERRIDE; + const ui::Event& event) override; private: void InitToolbar(); diff --git a/src/browser/nw_autofill_client.h b/src/browser/nw_autofill_client.h index d4c02a1d12..22b3d0c831 100644 --- a/src/browser/nw_autofill_client.h +++ b/src/browser/nw_autofill_client.h @@ -38,18 +38,18 @@ class NWAutofillClient void TabActivated(); // AutofillClient: - virtual PersonalDataManager* GetPersonalDataManager() OVERRIDE; - virtual scoped_refptr GetDatabase() OVERRIDE; - virtual PrefService* GetPrefs() OVERRIDE; - virtual void HideRequestAutocompleteDialog() OVERRIDE; - virtual void ShowAutofillSettings() OVERRIDE; + virtual PersonalDataManager* GetPersonalDataManager() override; + virtual scoped_refptr GetDatabase() override; + virtual PrefService* GetPrefs() override; + virtual void HideRequestAutocompleteDialog() override; + virtual void ShowAutofillSettings() override; virtual void ConfirmSaveCreditCard( const AutofillMetrics& metric_logger, - const base::Closure& save_card_callback) OVERRIDE; + const base::Closure& save_card_callback) override; virtual void ShowRequestAutocompleteDialog( const FormData& form, const GURL& source_url, - const ResultCallback& callback) OVERRIDE; + const ResultCallback& callback) override; virtual void ShowAutofillPopup( const gfx::RectF& element_bounds, base::i18n::TextDirection text_direction, @@ -57,20 +57,20 @@ class NWAutofillClient const std::vector& labels, const std::vector& icons, const std::vector& identifiers, - base::WeakPtr delegate) OVERRIDE; + base::WeakPtr delegate) override; virtual void UpdateAutofillPopupDataListValues( const std::vector& values, - const std::vector& labels) OVERRIDE; - virtual void HideAutofillPopup() OVERRIDE; - virtual bool IsAutocompleteEnabled() OVERRIDE; + const std::vector& labels) override; + virtual void HideAutofillPopup() override; + virtual bool IsAutocompleteEnabled() override; virtual void DetectAccountCreationForms( - const std::vector& forms) OVERRIDE; + const std::vector& forms) override; virtual void DidFillOrPreviewField( const base::string16& autofilled_value, - const base::string16& profile_full_name) OVERRIDE; + const base::string16& profile_full_name) override; // content::WebContentsObserver implementation. - virtual void WebContentsDestroyed() OVERRIDE; + virtual void WebContentsDestroyed() override; private: #if defined(OS_MACOSX) && !defined(OS_IOS) diff --git a/src/browser/nw_form_database_service.h b/src/browser/nw_form_database_service.h index ce7b132ce2..a9c55fa127 100644 --- a/src/browser/nw_form_database_service.h +++ b/src/browser/nw_form_database_service.h @@ -42,7 +42,7 @@ class NwFormDatabaseService : public WebDataServiceConsumer { // WebDataServiceConsumer implementation. virtual void OnWebDataServiceRequestDone( WebDataServiceBase::Handle h, - const WDTypedResult* result) OVERRIDE; + const WDTypedResult* result) override; private: struct PendingQuery { diff --git a/src/browser/printing/print_job_worker_owner.h b/src/browser/printing/print_job_worker_owner.h index 8f9f58509f..00a561a39b 100644 --- a/src/browser/printing/print_job_worker_owner.h +++ b/src/browser/printing/print_job_worker_owner.h @@ -10,8 +10,12 @@ namespace base { class MessageLoop; +class SequencedTaskRunner; } +namespace tracked_objects { +class Location; +} namespace printing { @@ -21,6 +25,8 @@ class PrintSettings; class PrintJobWorkerOwner : public base::RefCountedThreadSafe { public: + PrintJobWorkerOwner(); + // Finishes the initialization began by PrintJobWorker::GetSettings(). // Creates a new PrintedDocument if necessary. Solely meant to be called by // PrintJobWorker. @@ -30,19 +36,29 @@ class PrintJobWorkerOwner // Detach the PrintJobWorker associated to this object. virtual PrintJobWorker* DetachWorker(PrintJobWorkerOwner* new_owner) = 0; - // Retrieves the message loop that is expected to process GetSettingsDone. - virtual base::MessageLoop* message_loop() = 0; - // Access the current settings. virtual const PrintSettings& settings() const = 0; // Cookie uniquely identifying the PrintedDocument and/or loaded settings. virtual int cookie() const = 0; + // Returns true if the current thread is a thread on which a task + // may be run, and false if no task will be run on the current + // thread. + bool RunsTasksOnCurrentThread() const; + + // Posts the given task to be run. + bool PostTask(const tracked_objects::Location& from_here, + const base::Closure& task); + protected: friend class base::RefCountedThreadSafe; - virtual ~PrintJobWorkerOwner() {} + virtual ~PrintJobWorkerOwner(); + + // Task runner reference. Used to send notifications in the right + // thread. + scoped_refptr task_runner_; }; } // namespace printing diff --git a/src/browser/printing/print_view_manager.h b/src/browser/printing/print_view_manager.h index 6d2898f060..f4640bcb95 100644 --- a/src/browser/printing/print_view_manager.h +++ b/src/browser/printing/print_view_manager.h @@ -59,25 +59,25 @@ class PrintViewManager : public content::NotificationObserver, void set_observer(PrintViewManagerObserver* observer); // PrintedPagesSource implementation. - virtual base::string16 RenderSourceName() OVERRIDE; + virtual base::string16 RenderSourceName() override; // content::NotificationObserver implementation. virtual void Observe(int type, const content::NotificationSource& source, - const content::NotificationDetails& details) OVERRIDE; + const content::NotificationDetails& details) override; // content::WebContentsObserver implementation. virtual void DidStartLoading( - content::RenderViewHost* render_view_host) OVERRIDE; + content::RenderViewHost* render_view_host) override; // content::WebContentsObserver implementation. - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) override; // Terminates or cancels the print job if one was pending. - virtual void RenderProcessGone(base::TerminationStatus status) OVERRIDE; + virtual void RenderProcessGone(base::TerminationStatus status) override; // Cancels the print job. - virtual void NavigationStopped() OVERRIDE; + virtual void NavigationStopped() override; private: explicit PrintViewManager(content::WebContents* web_contents); diff --git a/src/browser/printing/printing_message_filter.cc b/src/browser/printing/printing_message_filter.cc index b3ee115e96..c683f95a37 100644 --- a/src/browser/printing/printing_message_filter.cc +++ b/src/browser/printing/printing_message_filter.cc @@ -2,32 +2,45 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/nw/src/browser/printing/printing_message_filter.h" +#include "chrome/browser/printing/printing_message_filter.h" #include #include "base/bind.h" -#include "content/nw/src/browser/printing/printer_query.h" -#include "content/nw/src/browser/printing/print_job_manager.h" -#include "content/nw/src/common/print_messages.h" -#include "content/nw/src/shell_content_browser_client.h" +#include "chrome/browser/browser_process.h" +#include "chrome/browser/printing/print_job_manager.h" +#include "chrome/browser/printing/printer_query.h" +#include "chrome/common/print_messages.h" #include "content/public/browser/browser_thread.h" #include "content/public/browser/render_view_host.h" #include "content/public/browser/web_contents.h" -#include "content/public/common/content_client.h" +#include "content/public/common/child_process_host.h" +#include "content/nw/src/shell_content_browser_client.h" + +#if defined(ENABLE_PRINT_PREVIEW) +#include "chrome/browser/ui/webui/print_preview/print_preview_ui.h" +#endif #if defined(OS_CHROMEOS) #include #include -#include "base/file_util.h" +#include "base/files/file_util.h" #include "base/lazy_instance.h" #include "chrome/browser/printing/print_dialog_cloud.h" #endif +#if defined(OS_ANDROID) +#include "base/strings/string_number_conversions.h" +#include "chrome/browser/printing/print_view_manager_basic.h" +#include "printing/printing_context_android.h" +#endif + using content::BrowserThread; +namespace printing { + namespace { #if defined(OS_CHROMEOS) @@ -43,7 +56,7 @@ static base::LazyInstance g_printing_file_descriptor_map = LAZY_INSTANCE_INITIALIZER; #endif -void RenderParamsFromPrintSettings(const printing::PrintSettings& settings, +void RenderParamsFromPrintSettings(const PrintSettings& settings, PrintMsg_Print_Params* params) { params->page_size = settings.page_setup_device_units().physical_size(); params->content_size.SetSize( @@ -76,12 +89,13 @@ void RenderParamsFromPrintSettings(const printing::PrintSettings& settings, } // namespace PrintingMessageFilter::PrintingMessageFilter(int render_process_id) - : BrowserMessageFilter(PrintMsgStart), print_job_manager_(NULL), - render_process_id_(render_process_id) { - + : BrowserMessageFilter(PrintMsgStart), + render_process_id_(render_process_id) { content::ShellContentBrowserClient* browser_client = static_cast(content::GetContentClient()->browser()); - print_job_manager_ = browser_client->print_job_manager(); + queue_ = browser_client->print_job_manager()->queue(); + + DCHECK(queue_.get()); } PrintingMessageFilter::~PrintingMessageFilter() { @@ -94,17 +108,21 @@ void PrintingMessageFilter::OverrideThreadForMessage( message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) { *thread = BrowserThread::FILE; } +#elif defined(OS_ANDROID) + if (message.type() == PrintHostMsg_AllocateTempFileForPrinting::ID || + message.type() == PrintHostMsg_TempFileForPrintingWritten::ID) { + *thread = BrowserThread::UI; + } #endif } bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) { - bool handled = true; IPC_BEGIN_MESSAGE_MAP(PrintingMessageFilter, message) #if defined(OS_WIN) IPC_MESSAGE_HANDLER(PrintHostMsg_DuplicateSection, OnDuplicateSection) #endif -#if defined(OS_CHROMEOS) +#if defined(OS_CHROMEOS) || defined(OS_ANDROID) IPC_MESSAGE_HANDLER(PrintHostMsg_AllocateTempFileForPrinting, OnAllocateTempFileForPrinting) IPC_MESSAGE_HANDLER(PrintHostMsg_TempFileForPrintingWritten, @@ -116,7 +134,9 @@ bool PrintingMessageFilter::OnMessageReceived(const IPC::Message& message) { IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_ScriptedPrint, OnScriptedPrint) IPC_MESSAGE_HANDLER_DELAY_REPLY(PrintHostMsg_UpdatePrintSettings, OnUpdatePrintSettings) +#if defined(ENABLE_PRINT_PREVIEW) IPC_MESSAGE_HANDLER(PrintHostMsg_CheckForCancel, OnCheckForCancel) +#endif IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -133,10 +153,14 @@ void PrintingMessageFilter::OnDuplicateSection( } #endif -#if defined(OS_CHROMEOS) +#if defined(OS_CHROMEOS) || defined(OS_ANDROID) void PrintingMessageFilter::OnAllocateTempFileForPrinting( - base::FileDescriptor* temp_file_fd, int* sequence_number) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); + int render_view_id, + base::FileDescriptor* temp_file_fd, + int* sequence_number) { +#if defined(OS_CHROMEOS) + // TODO(thestig): Use |render_view_id| for Chrome OS. + DCHECK_CURRENTLY_ON(BrowserThread::FILE); temp_file_fd->fd = *sequence_number = -1; temp_file_fd->auto_close = false; @@ -144,7 +168,7 @@ void PrintingMessageFilter::OnAllocateTempFileForPrinting( *sequence_number = g_printing_file_descriptor_map.Get().sequence++; base::FilePath path; - if (file_util::CreateTemporaryFile(&path)) { + if (base::CreateTemporaryFile(&path)) { int fd = open(path.value().c_str(), O_WRONLY); if (fd >= 0) { SequenceToPathMap::iterator it = map->find(*sequence_number); @@ -158,11 +182,26 @@ void PrintingMessageFilter::OnAllocateTempFileForPrinting( } } } +#elif defined(OS_ANDROID) + DCHECK_CURRENTLY_ON(BrowserThread::UI); + content::WebContents* wc = GetWebContentsForRenderView(render_view_id); + if (!wc) + return; + PrintViewManagerBasic* print_view_manager = + PrintViewManagerBasic::FromWebContents(wc); + // The file descriptor is originally created in & passed from the Android + // side, and it will handle the closing. + const base::FileDescriptor& file_descriptor = + print_view_manager->file_descriptor(); + temp_file_fd->fd = file_descriptor.fd; + temp_file_fd->auto_close = false; +#endif } void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_view_id, int sequence_number) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); +#if defined(OS_CHROMEOS) + DCHECK_CURRENTLY_ON(BrowserThread::FILE); SequenceToPathMap* map = &g_printing_file_descriptor_map.Get().map; SequenceToPathMap::iterator it = map->find(sequence_number); if (it == map->end()) { @@ -177,107 +216,80 @@ void PrintingMessageFilter::OnTempFileForPrintingWritten(int render_view_id, // Erase the entry in the map. map->erase(it); +#elif defined(OS_ANDROID) + DCHECK_CURRENTLY_ON(BrowserThread::UI); + content::WebContents* wc = GetWebContentsForRenderView(render_view_id); + if (!wc) + return; + PrintViewManagerBasic* print_view_manager = + PrintViewManagerBasic::FromWebContents(wc); + const base::FileDescriptor& file_descriptor = + print_view_manager->file_descriptor(); + PrintingContextAndroid::PdfWritingDone(file_descriptor.fd, true); + // Invalidate the file descriptor so it doesn't accidentally get reused. + print_view_manager->set_file_descriptor(base::FileDescriptor(-1, false)); +#endif } +#endif // defined(OS_CHROMEOS) || defined(OS_ANDROID) +#if defined(OS_CHROMEOS) void PrintingMessageFilter::CreatePrintDialogForFile( int render_view_id, const base::FilePath& path) { content::WebContents* wc = GetWebContentsForRenderView(render_view_id); + if (!wc) + return; print_dialog_cloud::CreatePrintDialogForFile( wc->GetBrowserContext(), - wc->GetView()->GetTopLevelNativeWindow(), + wc->GetTopLevelNativeWindow(), path, - string16(), - string16(), - std::string("application/pdf"), - false); + wc->GetTitle(), + base::string16(), + std::string("application/pdf")); } #endif // defined(OS_CHROMEOS) content::WebContents* PrintingMessageFilter::GetWebContentsForRenderView( int render_view_id) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); + DCHECK_CURRENTLY_ON(BrowserThread::UI); content::RenderViewHost* view = content::RenderViewHost::FromID( render_process_id_, render_view_id); - return content::WebContents::FromRenderViewHost(view); -} - -struct PrintingMessageFilter::GetPrintSettingsForRenderViewParams { - printing::PrinterQuery::GetSettingsAskParam ask_user_for_settings; - int expected_page_count; - bool has_selection; - printing::MarginType margin_type; -}; - -void PrintingMessageFilter::GetPrintSettingsForRenderView( - int render_view_id, - GetPrintSettingsForRenderViewParams params, - const base::Closure& callback, - scoped_refptr printer_query) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); - content::WebContents* wc = GetWebContentsForRenderView(render_view_id); - if (wc) { - scoped_ptr wc_observer( - new PrintingUIWebContentsObserver(wc)); - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&printing::PrinterQuery::GetSettings, printer_query, - params.ask_user_for_settings, base::Passed(&wc_observer), - params.expected_page_count, params.has_selection, - params.margin_type, callback)); - } else { - BrowserThread::PostTask( - BrowserThread::IO, FROM_HERE, - base::Bind(&PrintingMessageFilter::OnGetPrintSettingsFailed, this, - callback, printer_query)); - } + return view ? content::WebContents::FromRenderViewHost(view) : NULL; } void PrintingMessageFilter::OnIsPrintingEnabled(bool* is_enabled) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); + DCHECK_CURRENTLY_ON(BrowserThread::IO); *is_enabled = true; } -void PrintingMessageFilter::OnGetPrintSettingsFailed( - const base::Closure& callback, - scoped_refptr printer_query) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - printer_query->GetSettingsDone(printing::PrintSettings(), - printing::PrintingContext::FAILED); - callback.Run(); -} - void PrintingMessageFilter::OnGetDefaultPrintSettings(IPC::Message* reply_msg) { - DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); - scoped_refptr printer_query; - print_job_manager_->PopPrinterQuery(0, &printer_query); + DCHECK_CURRENTLY_ON(BrowserThread::IO); + scoped_refptr printer_query; + printer_query = queue_->PopPrinterQuery(0); if (!printer_query.get()) { - printer_query = new printing::PrinterQuery; - printer_query->SetWorkerDestination(print_job_manager_->destination()); + printer_query = + queue_->CreatePrinterQuery(render_process_id_, reply_msg->routing_id()); } // Loads default settings. This is asynchronous, only the IPC message sender // will hang until the settings are retrieved. - GetPrintSettingsForRenderViewParams params; - params.ask_user_for_settings = printing::PrinterQuery::DEFAULTS; - params.expected_page_count = 0; - params.has_selection = false; - params.margin_type = printing::DEFAULT_MARGINS; - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this, - reply_msg->routing_id(), params, - base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply, - this, printer_query, reply_msg), - printer_query)); + printer_query->GetSettings( + PrinterQuery::DEFAULTS, + 0, + false, + DEFAULT_MARGINS, + base::Bind(&PrintingMessageFilter::OnGetDefaultPrintSettingsReply, + this, + printer_query, + reply_msg)); } void PrintingMessageFilter::OnGetDefaultPrintSettingsReply( - scoped_refptr printer_query, + scoped_refptr printer_query, IPC::Message* reply_msg) { PrintMsg_Print_Params params; if (!printer_query.get() || - printer_query->last_status() != printing::PrintingContext::OK) { + printer_query->last_status() != PrintingContext::OK) { params.Reset(); } else { RenderParamsFromPrintSettings(printer_query->settings(), ¶ms); @@ -289,7 +301,7 @@ void PrintingMessageFilter::OnGetDefaultPrintSettingsReply( if (printer_query.get()) { // If user hasn't cancelled. if (printer_query->cookie() && printer_query->settings().dpi()) { - print_job_manager_->QueuePrinterQuery(printer_query.get()); + queue_->QueuePrinterQuery(printer_query.get()); } else { printer_query->StopWorker(); } @@ -299,90 +311,133 @@ void PrintingMessageFilter::OnGetDefaultPrintSettingsReply( void PrintingMessageFilter::OnScriptedPrint( const PrintHostMsg_ScriptedPrint_Params& params, IPC::Message* reply_msg) { - scoped_refptr printer_query; - print_job_manager_->PopPrinterQuery(params.cookie, &printer_query); + scoped_refptr printer_query = + queue_->PopPrinterQuery(params.cookie); if (!printer_query.get()) { - printer_query = new printing::PrinterQuery; - printer_query->SetWorkerDestination(print_job_manager_->destination()); + printer_query = + queue_->CreatePrinterQuery(render_process_id_, reply_msg->routing_id()); } - GetPrintSettingsForRenderViewParams settings_params; - settings_params.ask_user_for_settings = printing::PrinterQuery::ASK_USER; - settings_params.expected_page_count = params.expected_pages_count; - settings_params.has_selection = params.has_selection; - settings_params.margin_type = params.margin_type; - - BrowserThread::PostTask( - BrowserThread::UI, FROM_HERE, - base::Bind(&PrintingMessageFilter::GetPrintSettingsForRenderView, this, - reply_msg->routing_id(), settings_params, - base::Bind(&PrintingMessageFilter::OnScriptedPrintReply, this, - printer_query, reply_msg), - printer_query)); + printer_query->GetSettings( + PrinterQuery::ASK_USER, + params.expected_pages_count, + params.has_selection, + params.margin_type, + base::Bind(&PrintingMessageFilter::OnScriptedPrintReply, + this, + printer_query, + reply_msg)); } void PrintingMessageFilter::OnScriptedPrintReply( - scoped_refptr printer_query, + scoped_refptr printer_query, IPC::Message* reply_msg) { PrintMsg_PrintPages_Params params; - if (printer_query->last_status() != printing::PrintingContext::OK || +#if defined(OS_ANDROID) + // We need to save the routing ID here because Send method below deletes the + // |reply_msg| before we can get the routing ID for the Android code. + int routing_id = reply_msg->routing_id(); +#endif + if (printer_query->last_status() != PrintingContext::OK || !printer_query->settings().dpi()) { params.Reset(); } else { RenderParamsFromPrintSettings(printer_query->settings(), ¶ms.params); params.params.document_cookie = printer_query->cookie(); - params.pages = - printing::PageRange::GetPages(printer_query->settings().ranges()); + params.pages = PageRange::GetPages(printer_query->settings().ranges()); } PrintHostMsg_ScriptedPrint::WriteReplyParams(reply_msg, params); Send(reply_msg); if (params.params.dpi && params.params.document_cookie) { - print_job_manager_->QueuePrinterQuery(printer_query.get()); +#if defined(OS_ANDROID) + int file_descriptor; + const base::string16& device_name = printer_query->settings().device_name(); + if (base::StringToInt(device_name, &file_descriptor)) { + BrowserThread::PostTask( + BrowserThread::UI, FROM_HERE, + base::Bind(&PrintingMessageFilter::UpdateFileDescriptor, this, + routing_id, file_descriptor)); + } +#endif + queue_->QueuePrinterQuery(printer_query.get()); } else { printer_query->StopWorker(); } } +#if defined(OS_ANDROID) +void PrintingMessageFilter::UpdateFileDescriptor(int render_view_id, int fd) { + DCHECK_CURRENTLY_ON(BrowserThread::UI); + content::WebContents* wc = GetWebContentsForRenderView(render_view_id); + if (!wc) + return; + PrintViewManagerBasic* print_view_manager = + PrintViewManagerBasic::FromWebContents(wc); + print_view_manager->set_file_descriptor(base::FileDescriptor(fd, false)); +} +#endif + void PrintingMessageFilter::OnUpdatePrintSettings( - int document_cookie, const base::DictionaryValue& job_settings, - IPC::Message* reply_msg) { - scoped_refptr printer_query; + int document_cookie, const base::DictionaryValue& job_settings, + IPC::Message* reply_msg) { + scoped_ptr new_settings(job_settings.DeepCopy()); - print_job_manager_->PopPrinterQuery(document_cookie, &printer_query); + scoped_refptr printer_query; + + printer_query = queue_->PopPrinterQuery(document_cookie); if (!printer_query.get()) { - printer_query = new printing::PrinterQuery; - printer_query->SetWorkerDestination(print_job_manager_->destination()); + int host_id = render_process_id_; + int routing_id = reply_msg->routing_id(); + if (!new_settings->GetInteger(printing::kPreviewInitiatorHostId, + &host_id) || + !new_settings->GetInteger(printing::kPreviewInitiatorRoutingId, + &routing_id)) { + host_id = content::ChildProcessHost::kInvalidUniqueID; + routing_id = content::ChildProcessHost::kInvalidUniqueID; + } + printer_query = queue_->CreatePrinterQuery(host_id, routing_id); } printer_query->SetSettings( - job_settings, + new_settings.Pass(), base::Bind(&PrintingMessageFilter::OnUpdatePrintSettingsReply, this, printer_query, reply_msg)); } void PrintingMessageFilter::OnUpdatePrintSettingsReply( - scoped_refptr printer_query, + scoped_refptr printer_query, IPC::Message* reply_msg) { PrintMsg_PrintPages_Params params; if (!printer_query.get() || - printer_query->last_status() != printing::PrintingContext::OK) { + printer_query->last_status() != PrintingContext::OK) { params.Reset(); } else { RenderParamsFromPrintSettings(printer_query->settings(), ¶ms.params); params.params.document_cookie = printer_query->cookie(); - params.pages = - printing::PageRange::GetPages(printer_query->settings().ranges()); + params.pages = PageRange::GetPages(printer_query->settings().ranges()); } - PrintHostMsg_UpdatePrintSettings::WriteReplyParams(reply_msg, params); + PrintHostMsg_UpdatePrintSettings::WriteReplyParams( + reply_msg, + params, + printer_query.get() && + (printer_query->last_status() == printing::PrintingContext::CANCEL)); Send(reply_msg); // If user hasn't cancelled. if (printer_query.get()) { - if (printer_query->cookie() && printer_query->settings().dpi()) - print_job_manager_->QueuePrinterQuery(printer_query.get()); - else + if (printer_query->cookie() && printer_query->settings().dpi()) { + queue_->QueuePrinterQuery(printer_query.get()); + } else { printer_query->StopWorker(); + } } } +#if defined(ENABLE_PRINT_PREVIEW) void PrintingMessageFilter::OnCheckForCancel(int32 preview_ui_id, int preview_request_id, bool* cancel) { + PrintPreviewUI::GetCurrentPrintPreviewStatus(preview_ui_id, + preview_request_id, + cancel); } +#endif + +} // namespace printing diff --git a/src/browser/printing/printing_message_filter.h b/src/browser/printing/printing_message_filter.h index b858505947..336693f8fc 100644 --- a/src/browser/printing/printing_message_filter.h +++ b/src/browser/printing/printing_message_filter.h @@ -2,8 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#ifndef NW_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_ -#define NW_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_ +#ifndef CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_ +#define CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_ #include @@ -15,6 +15,8 @@ #endif struct PrintHostMsg_ScriptedPrint_Params; +class Profile; +class ProfileIOData; namespace base { class DictionaryValue; @@ -26,9 +28,10 @@ class WebContents; } namespace printing { -class PrinterQuery; + class PrintJobManager; -} +class PrintQueriesQueue; +class PrinterQuery; // This class filters out incoming printing related IPC messages for the // renderer process on the IPC thread. @@ -37,13 +40,12 @@ class PrintingMessageFilter : public content::BrowserMessageFilter { PrintingMessageFilter(int render_process_id); // content::BrowserMessageFilter methods. - virtual void OverrideThreadForMessage( - const IPC::Message& message, - content::BrowserThread::ID* thread) OVERRIDE; - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + void OverrideThreadForMessage(const IPC::Message& message, + content::BrowserThread::ID* thread) override; + bool OnMessageReceived(const IPC::Message& message) override; private: - virtual ~PrintingMessageFilter(); + ~PrintingMessageFilter() override; #if defined(OS_WIN) // Used to pass resulting EMF from renderer to browser in printing. @@ -51,15 +53,25 @@ class PrintingMessageFilter : public content::BrowserMessageFilter { base::SharedMemoryHandle* browser_handle); #endif -#if defined(OS_CHROMEOS) +#if defined(OS_CHROMEOS) || defined(OS_ANDROID) // Used to ask the browser allocate a temporary file for the renderer // to fill in resulting PDF in renderer. - void OnAllocateTempFileForPrinting(base::FileDescriptor* temp_file_fd, + void OnAllocateTempFileForPrinting(int render_view_id, + base::FileDescriptor* temp_file_fd, int* sequence_number); void OnTempFileForPrintingWritten(int render_view_id, int sequence_number); +#endif + +#if defined(OS_CHROMEOS) void CreatePrintDialogForFile(int render_view_id, const base::FilePath& path); #endif +#if defined(OS_ANDROID) + // Updates the file descriptor for the PrintViewManagerBasic of a given + // render_view_id. + void UpdateFileDescriptor(int render_view_id, int fd); +#endif + // Given a render_view_id get the corresponding WebContents. // Must be called on the UI thread. content::WebContents* GetWebContentsForRenderView(int render_view_id); @@ -70,35 +82,21 @@ class PrintingMessageFilter : public content::BrowserMessageFilter { // to base::Bind. struct GetPrintSettingsForRenderViewParams; - // Retrieve print settings. Uses |render_view_id| to get a parent - // for any UI created if needed. - void GetPrintSettingsForRenderView( - int render_view_id, - GetPrintSettingsForRenderViewParams params, - const base::Closure& callback, - scoped_refptr printer_query); - - void OnGetPrintSettingsFailed( - const base::Closure& callback, - scoped_refptr printer_query); - // Checks if printing is enabled. void OnIsPrintingEnabled(bool* is_enabled); // Get the default print setting. void OnGetDefaultPrintSettings(IPC::Message* reply_msg); - void OnGetDefaultPrintSettingsReply( - scoped_refptr printer_query, - IPC::Message* reply_msg); + void OnGetDefaultPrintSettingsReply(scoped_refptr printer_query, + IPC::Message* reply_msg); // The renderer host have to show to the user the print dialog and returns // the selected print settings. The task is handled by the print worker // thread and the UI thread. The reply occurs on the IO thread. void OnScriptedPrint(const PrintHostMsg_ScriptedPrint_Params& params, IPC::Message* reply_msg); - void OnScriptedPrintReply( - scoped_refptr printer_query, - IPC::Message* reply_msg); + void OnScriptedPrintReply(scoped_refptr printer_query, + IPC::Message* reply_msg); // Modify the current print settings based on |job_settings|. The task is // handled by the print worker thread and the UI thread. The reply occurs on @@ -106,20 +104,23 @@ class PrintingMessageFilter : public content::BrowserMessageFilter { void OnUpdatePrintSettings(int document_cookie, const base::DictionaryValue& job_settings, IPC::Message* reply_msg); - void OnUpdatePrintSettingsReply( - scoped_refptr printer_query, - IPC::Message* reply_msg); + void OnUpdatePrintSettingsReply(scoped_refptr printer_query, + IPC::Message* reply_msg); +#if defined(ENABLE_PRINT_PREVIEW) // Check to see if print preview has been cancelled. void OnCheckForCancel(int32 preview_ui_id, int preview_request_id, bool* cancel); +#endif - printing::PrintJobManager* print_job_manager_; + const int render_process_id_; - int render_process_id_; + scoped_refptr queue_; DISALLOW_COPY_AND_ASSIGN(PrintingMessageFilter); }; +} // namespace printing + #endif // CHROME_BROWSER_PRINTING_PRINTING_MESSAGE_FILTER_H_ diff --git a/src/browser/shell_component_extension_resource_manager.cc b/src/browser/shell_component_extension_resource_manager.cc new file mode 100644 index 0000000000..9c39018c37 --- /dev/null +++ b/src/browser/shell_component_extension_resource_manager.cc @@ -0,0 +1,61 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/shell_component_extension_resource_manager.h" + +#include "base/logging.h" +#include "base/path_service.h" +#include "grit/nw_component_resources_map.h" + +namespace extensions { + +ShellComponentExtensionResourceManager:: +ShellComponentExtensionResourceManager() { + + AddComponentResourceEntries( + kNwComponentResources, kNwComponentResourcesSize); +} + +ShellComponentExtensionResourceManager:: +~ShellComponentExtensionResourceManager() {} + +bool ShellComponentExtensionResourceManager::IsComponentExtensionResource( + const base::FilePath& extension_path, + const base::FilePath& resource_path, + int* resource_id) { + base::FilePath directory_path = extension_path; + base::FilePath resources_dir; + base::FilePath relative_path; +#if 0 + if (!PathService::Get(chrome::DIR_RESOURCES, &resources_dir) || + !resources_dir.AppendRelativePath(directory_path, &relative_path)) { + return false; + } +#endif + relative_path = relative_path.Append(resource_path); + relative_path = relative_path.NormalizePathSeparators(); + + std::map::const_iterator entry = + path_to_resource_id_.find(relative_path); + if (entry != path_to_resource_id_.end()) + *resource_id = entry->second; + + return entry != path_to_resource_id_.end(); +} + +void ShellComponentExtensionResourceManager::AddComponentResourceEntries( + const GritResourceMap* entries, + size_t size) { + for (size_t i = 0; i < size; ++i) { + base::FilePath resource_path = base::FilePath().AppendASCII( + entries[i].name); + resource_path = resource_path.NormalizePathSeparators(); + + DCHECK(path_to_resource_id_.find(resource_path) == + path_to_resource_id_.end()); + path_to_resource_id_[resource_path] = entries[i].value; + } +} + +} // namespace extensions diff --git a/src/browser/shell_component_extension_resource_manager.h b/src/browser/shell_component_extension_resource_manager.h new file mode 100644 index 0000000000..91a77c2084 --- /dev/null +++ b/src/browser/shell_component_extension_resource_manager.h @@ -0,0 +1,41 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef NW_BROWSER_EXTENSIONS_CHROME_COMPONENT_EXTENSION_RESOURCE_MANAGER_H_ +#define NW_BROWSER_EXTENSIONS_CHROME_COMPONENT_EXTENSION_RESOURCE_MANAGER_H_ + +#include + +#include "base/basictypes.h" +#include "base/files/file_path.h" +#include "extensions/browser/component_extension_resource_manager.h" + +struct GritResourceMap; + +namespace extensions { + +class ShellComponentExtensionResourceManager + : public ComponentExtensionResourceManager { + public: + ShellComponentExtensionResourceManager(); + ~ShellComponentExtensionResourceManager() override; + + // Overridden from ComponentExtensionResourceManager: + bool IsComponentExtensionResource(const base::FilePath& extension_path, + const base::FilePath& resource_path, + int* resource_id) override; + + private: + void AddComponentResourceEntries(const GritResourceMap* entries, size_t size); + + // A map from a resource path to the resource ID. Used by + // IsComponentExtensionResource. + std::map path_to_resource_id_; + + DISALLOW_COPY_AND_ASSIGN(ShellComponentExtensionResourceManager); +}; + +} // namespace extensions + +#endif // NW_BROWSER_EXTENSIONS_CHROME_COMPONENT_EXTENSION_RESOURCE_MANAGER_H_ diff --git a/src/browser/shell_devtools_delegate.h b/src/browser/shell_devtools_delegate.h index 111e28e55d..cdde5b7f7f 100644 --- a/src/browser/shell_devtools_delegate.h +++ b/src/browser/shell_devtools_delegate.h @@ -48,15 +48,15 @@ class ShellDevToolsDelegate : public DevToolsHttpHandlerDelegate { void Stop(); // DevToolsHttpProtocolHandler::Delegate overrides. - virtual std::string GetDiscoveryPageHTML() OVERRIDE; - virtual bool BundlesFrontendResources() OVERRIDE; - virtual base::FilePath GetDebugFrontendDir() OVERRIDE; - virtual std::string GetPageThumbnailData(const GURL& url) OVERRIDE; - virtual scoped_ptr CreateNewTarget(const GURL& url) OVERRIDE; - virtual void EnumerateTargets(TargetCallback callback) OVERRIDE; + virtual std::string GetDiscoveryPageHTML() override; + virtual bool BundlesFrontendResources() override; + virtual base::FilePath GetDebugFrontendDir() override; + virtual std::string GetPageThumbnailData(const GURL& url) override; + virtual scoped_ptr CreateNewTarget(const GURL& url) override; + virtual void EnumerateTargets(TargetCallback callback) override; virtual scoped_ptr CreateSocketForTethering( net::StreamListenSocket::Delegate* delegate, - std::string* name) OVERRIDE; + std::string* name) override; DevToolsHttpHandler* devtools_http_handler() { return devtools_http_handler_; diff --git a/src/browser/shell_devtools_manager_delegate.cc b/src/browser/shell_devtools_manager_delegate.cc new file mode 100644 index 0000000000..166eaf1e63 --- /dev/null +++ b/src/browser/shell_devtools_manager_delegate.cc @@ -0,0 +1,280 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/shell/browser/shell_devtools_manager_delegate.h" + +#include + +#include "base/bind.h" +#include "base/command_line.h" +#include "base/files/file_path.h" +#include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" +#include "base/strings/utf_string_conversions.h" +#include "content/public/browser/devtools_agent_host.h" +#include "content/public/browser/devtools_http_handler.h" +#include "content/public/browser/devtools_target.h" +#include "content/public/browser/favicon_status.h" +#include "content/public/browser/navigation_entry.h" +#include "content/public/browser/render_view_host.h" +#include "content/public/browser/web_contents.h" +#include "content/public/common/content_switches.h" +#include "content/public/common/url_constants.h" +#include "content/public/common/user_agent.h" +#include "content/nw/src/nw_shell.h" +#include "grit/shell_resources.h" +#include "net/socket/tcp_server_socket.h" +#include "ui/base/resource/resource_bundle.h" + +#if defined(OS_ANDROID) +#include "content/public/browser/android/devtools_auth.h" +#include "net/socket/unix_domain_server_socket_posix.h" +#endif + +namespace content { + +namespace { + +#if defined(OS_ANDROID) +const char kFrontEndURL[] = + "http://chrome-devtools-frontend.appspot.com/serve_rev/%s/inspector.html"; +#endif +const char kTargetTypePage[] = "page"; +const char kTargetTypeServiceWorker[] = "service_worker"; +const char kTargetTypeOther[] = "other"; + +#if defined(OS_ANDROID) +class UnixDomainServerSocketFactory + : public DevToolsHttpHandler::ServerSocketFactory { + public: + explicit UnixDomainServerSocketFactory(const std::string& socket_name) + : DevToolsHttpHandler::ServerSocketFactory(socket_name, 0, 1) {} + + private: + // DevToolsHttpHandler::ServerSocketFactory. + virtual scoped_ptr Create() const override { + return scoped_ptr( + new net::UnixDomainServerSocket( + base::Bind(&CanUserConnectToDevTools), + true /* use_abstract_namespace */)); + } + + DISALLOW_COPY_AND_ASSIGN(UnixDomainServerSocketFactory); +}; +#else +class TCPServerSocketFactory + : public DevToolsHttpHandler::ServerSocketFactory { + public: + TCPServerSocketFactory(const std::string& address, uint16 port, int backlog) + : DevToolsHttpHandler::ServerSocketFactory( + address, port, backlog) {} + + private: + // DevToolsHttpHandler::ServerSocketFactory. + scoped_ptr Create() const override { + return scoped_ptr( + new net::TCPServerSocket(NULL, net::NetLog::Source())); + } + + DISALLOW_COPY_AND_ASSIGN(TCPServerSocketFactory); +}; +#endif + +scoped_ptr +CreateSocketFactory() { + const CommandLine& command_line = *CommandLine::ForCurrentProcess(); +#if defined(OS_ANDROID) + std::string socket_name = "content_shell_devtools_remote"; + if (command_line.HasSwitch(switches::kRemoteDebuggingSocketName)) { + socket_name = command_line.GetSwitchValueASCII( + switches::kRemoteDebuggingSocketName); + } + return scoped_ptr( + new UnixDomainServerSocketFactory(socket_name)); +#else + // See if the user specified a port on the command line (useful for + // automation). If not, use an ephemeral port by specifying 0. + uint16 port = 0; + if (command_line.HasSwitch(switches::kRemoteDebuggingPort)) { + int temp_port; + std::string port_str = + command_line.GetSwitchValueASCII(switches::kRemoteDebuggingPort); + if (base::StringToInt(port_str, &temp_port) && + temp_port > 0 && temp_port < 65535) { + port = static_cast(temp_port); + } else { + DLOG(WARNING) << "Invalid http debugger port number " << temp_port; + } + } + return scoped_ptr( + new TCPServerSocketFactory("127.0.0.1", port, 1)); +#endif +} + +class Target : public DevToolsTarget { + public: + explicit Target(scoped_refptr agent_host); + + std::string GetId() const override { return agent_host_->GetId(); } + std::string GetParentId() const override { return std::string(); } + std::string GetType() const override { + switch (agent_host_->GetType()) { + case DevToolsAgentHost::TYPE_WEB_CONTENTS: + return kTargetTypePage; + case DevToolsAgentHost::TYPE_SERVICE_WORKER: + return kTargetTypeServiceWorker; + default: + break; + } + return kTargetTypeOther; + } + std::string GetTitle() const override { return agent_host_->GetTitle(); } + std::string GetDescription() const override { return std::string(); } + GURL GetURL() const override { return agent_host_->GetURL(); } + GURL GetFaviconURL() const override { return favicon_url_; } + base::TimeTicks GetLastActivityTime() const override { + return last_activity_time_; + } + bool IsAttached() const override { return agent_host_->IsAttached(); } + scoped_refptr GetAgentHost() const override { + return agent_host_; + } + bool Activate() const override; + bool Close() const override; + + private: + scoped_refptr agent_host_; + GURL favicon_url_; + base::TimeTicks last_activity_time_; +}; + +Target::Target(scoped_refptr agent_host) + : agent_host_(agent_host) { + if (WebContents* web_contents = agent_host_->GetWebContents()) { + NavigationController& controller = web_contents->GetController(); + NavigationEntry* entry = controller.GetActiveEntry(); + if (entry != NULL && entry->GetURL().is_valid()) + favicon_url_ = entry->GetFavicon().url; + last_activity_time_ = web_contents->GetLastActiveTime(); + } +} + +bool Target::Activate() const { + return agent_host_->Activate(); +} + +bool Target::Close() const { + return agent_host_->Close(); +} + +// ShellDevToolsDelegate ---------------------------------------------------- + +class ShellDevToolsDelegate : public DevToolsHttpHandlerDelegate { + public: + explicit ShellDevToolsDelegate(BrowserContext* browser_context); + ~ShellDevToolsDelegate() override; + + // DevToolsHttpHandlerDelegate implementation. + std::string GetDiscoveryPageHTML() override; + bool BundlesFrontendResources() override; + base::FilePath GetDebugFrontendDir() override; + scoped_ptr CreateSocketForTethering( + std::string* name) override; + + private: + BrowserContext* browser_context_; + + DISALLOW_COPY_AND_ASSIGN(ShellDevToolsDelegate); +}; + +ShellDevToolsDelegate::ShellDevToolsDelegate(BrowserContext* browser_context) + : browser_context_(browser_context) { +} + +ShellDevToolsDelegate::~ShellDevToolsDelegate() { +} + +std::string ShellDevToolsDelegate::GetDiscoveryPageHTML() { +#if defined(OS_ANDROID) + return std::string(); +#else + return ResourceBundle::GetSharedInstance().GetRawDataResource( + IDR_CONTENT_SHELL_DEVTOOLS_DISCOVERY_PAGE).as_string(); +#endif +} + +bool ShellDevToolsDelegate::BundlesFrontendResources() { +#if defined(OS_ANDROID) + return false; +#else + return true; +#endif +} + +base::FilePath ShellDevToolsDelegate::GetDebugFrontendDir() { + return base::FilePath(); +} + +scoped_ptr +ShellDevToolsDelegate::CreateSocketForTethering(std::string* name) { + return scoped_ptr(); +} + +} // namespace + +// ShellDevToolsManagerDelegate ---------------------------------------------- + +// static +DevToolsHttpHandler* +ShellDevToolsManagerDelegate::CreateHttpHandler( + BrowserContext* browser_context) { + std::string frontend_url; +#if defined(OS_ANDROID) + frontend_url = base::StringPrintf(kFrontEndURL, GetWebKitRevision().c_str()); +#endif + return DevToolsHttpHandler::Start(CreateSocketFactory(), + frontend_url, + new ShellDevToolsDelegate(browser_context), + base::FilePath()); +} + +ShellDevToolsManagerDelegate::ShellDevToolsManagerDelegate( + BrowserContext* browser_context) + : browser_context_(browser_context) { +} + +ShellDevToolsManagerDelegate::~ShellDevToolsManagerDelegate() { +} + +base::DictionaryValue* ShellDevToolsManagerDelegate::HandleCommand( + DevToolsAgentHost* agent_host, + base::DictionaryValue* command) { + return NULL; +} + +std::string ShellDevToolsManagerDelegate::GetPageThumbnailData( + const GURL& url) { + return std::string(); +} + +scoped_ptr +ShellDevToolsManagerDelegate::CreateNewTarget(const GURL& url) { + Shell* shell = Shell::Create(browser_context_, + url, + NULL, + MSG_ROUTING_NONE, + NULL); + return scoped_ptr( + new Target(DevToolsAgentHost::GetOrCreateFor(shell->web_contents()))); +} + +void ShellDevToolsManagerDelegate::EnumerateTargets(TargetCallback callback) { + TargetList targets; + for (const auto& agent_host : DevToolsAgentHost::GetOrCreateAll()) { + targets.push_back(new Target(agent_host)); + } + callback.Run(targets); +} + +} // namespace content diff --git a/src/browser/shell_devtools_manager_delegate.h b/src/browser/shell_devtools_manager_delegate.h new file mode 100644 index 0000000000..061562d9de --- /dev/null +++ b/src/browser/shell_devtools_manager_delegate.h @@ -0,0 +1,45 @@ +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_MANAGER_DELEGATE_H_ +#define CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_MANAGER_DELEGATE_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "content/public/browser/devtools_http_handler_delegate.h" +#include "content/public/browser/devtools_manager_delegate.h" + +namespace content { + +class BrowserContext; +class DevToolsHttpHandler; + +class ShellDevToolsManagerDelegate : public DevToolsManagerDelegate { + public: + static DevToolsHttpHandler* CreateHttpHandler( + BrowserContext* browser_context); + + explicit ShellDevToolsManagerDelegate(BrowserContext* browser_context); + ~ShellDevToolsManagerDelegate() override; + + // DevToolsManagerDelegate implementation. + void Inspect(BrowserContext* browser_context, + DevToolsAgentHost* agent_host) override {} + void DevToolsAgentStateChanged(DevToolsAgentHost* agent_host, + bool attached) override {} + base::DictionaryValue* HandleCommand(DevToolsAgentHost* agent_host, + base::DictionaryValue* command) override; + scoped_ptr CreateNewTarget(const GURL& url) override; + void EnumerateTargets(TargetCallback callback) override; + std::string GetPageThumbnailData(const GURL& url) override; + + private: + BrowserContext* browser_context_; + + DISALLOW_COPY_AND_ASSIGN(ShellDevToolsManagerDelegate); +}; + +} // namespace content + +#endif // CONTENT_SHELL_BROWSER_SHELL_DEVTOOLS_MANAGER_DELEGATE_H_ diff --git a/src/browser/shell_display_info_provider.cc b/src/browser/shell_display_info_provider.cc new file mode 100644 index 0000000000..a86173fa93 --- /dev/null +++ b/src/browser/shell_display_info_provider.cc @@ -0,0 +1,38 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/shell/browser/shell_display_info_provider.h" + +namespace extensions { + +ShellDisplayInfoProvider::ShellDisplayInfoProvider() { +} + +ShellDisplayInfoProvider::~ShellDisplayInfoProvider() { +} + +bool ShellDisplayInfoProvider::SetInfo( + const std::string& display_id, + const core_api::system_display::DisplayProperties& info, + std::string* error) { + *error = "Not implemented"; + return false; +} + +void ShellDisplayInfoProvider::UpdateDisplayUnitInfoForPlatform( + const gfx::Display& display, + extensions::core_api::system_display::DisplayUnitInfo* unit) { + NOTIMPLEMENTED(); +} + +gfx::Screen* ShellDisplayInfoProvider::GetActiveScreen() { + return NULL; +} + +// static +DisplayInfoProvider* DisplayInfoProvider::Create() { + return new ShellDisplayInfoProvider(); +} + +} // namespace extensions diff --git a/src/browser/shell_display_info_provider.h b/src/browser/shell_display_info_provider.h new file mode 100644 index 0000000000..61cea1cc7f --- /dev/null +++ b/src/browser/shell_display_info_provider.h @@ -0,0 +1,32 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_SHELL_BROWSER_SHELL_DISPLAY_INFO_PROVIDER_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_DISPLAY_INFO_PROVIDER_H_ + +#include "extensions/browser/api/system_display/display_info_provider.h" + +namespace extensions { + +class ShellDisplayInfoProvider : public DisplayInfoProvider { + public: + ShellDisplayInfoProvider(); + ~ShellDisplayInfoProvider() override; + + // DisplayInfoProvider implementation. + bool SetInfo(const std::string& display_id, + const core_api::system_display::DisplayProperties& info, + std::string* error) override; + void UpdateDisplayUnitInfoForPlatform( + const gfx::Display& display, + extensions::core_api::system_display::DisplayUnitInfo* unit) override; + gfx::Screen* GetActiveScreen() override; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellDisplayInfoProvider); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_DISPLAY_INFO_PROVIDER_H_ diff --git a/src/browser/shell_download_manager_delegate.cc b/src/browser/shell_download_manager_delegate.cc index 133220ed46..f5dd1b73d0 100644 --- a/src/browser/shell_download_manager_delegate.cc +++ b/src/browser/shell_download_manager_delegate.cc @@ -30,7 +30,7 @@ #endif #include "base/bind.h" -#include "base/file_util.h" +#include "base/files/file_util.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" diff --git a/src/browser/shell_download_manager_delegate.h b/src/browser/shell_download_manager_delegate.h index 3f7c623923..dc7d546e5a 100644 --- a/src/browser/shell_download_manager_delegate.h +++ b/src/browser/shell_download_manager_delegate.h @@ -44,22 +44,22 @@ class ShellDownloadManagerDelegate void SetDownloadManager(DownloadManager* manager); - virtual void Shutdown() OVERRIDE; + virtual void Shutdown() override; virtual bool DetermineDownloadTarget( DownloadItem* download, - const DownloadTargetCallback& callback) OVERRIDE; + const DownloadTargetCallback& callback) override; virtual bool ShouldOpenDownload( DownloadItem* item, - const DownloadOpenDelayedCallback& callback) OVERRIDE; - virtual void GetNextId(const DownloadIdCallback& callback) OVERRIDE; + const DownloadOpenDelayedCallback& callback) override; + virtual void GetNextId(const DownloadIdCallback& callback) override; // Inhibits prompting and sets the default download path. void SetDownloadBehaviorForTesting( const base::FilePath& default_download_path); #if defined(OS_WIN) virtual void FileSelected( - const base::FilePath& path, int index, void* params) OVERRIDE; - virtual void FileSelectionCanceled(void* params) OVERRIDE; + const base::FilePath& path, int index, void* params) override; + virtual void FileSelectionCanceled(void* params) override; #endif protected: diff --git a/src/browser/shell_download_manager_delegate_gtk.cc b/src/browser/shell_download_manager_delegate_gtk.cc index 5fd7b4dbaf..b782e30546 100644 --- a/src/browser/shell_download_manager_delegate_gtk.cc +++ b/src/browser/shell_download_manager_delegate_gtk.cc @@ -25,7 +25,7 @@ #endif #include "base/bind.h" -#include "base/file_util.h" +#include "base/files/file_util.h" #include "base/logging.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" diff --git a/src/browser/shell_extension_host_delegate.cc b/src/browser/shell_extension_host_delegate.cc new file mode 100644 index 0000000000..a02d604df4 --- /dev/null +++ b/src/browser/shell_extension_host_delegate.cc @@ -0,0 +1,64 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/shell/browser/shell_extension_host_delegate.h" + +#include "base/logging.h" +#include "extensions/shell/browser/media_capture_util.h" +#include "extensions/shell/browser/shell_extension_web_contents_observer.h" + +namespace extensions { + +ShellExtensionHostDelegate::ShellExtensionHostDelegate() { +} + +ShellExtensionHostDelegate::~ShellExtensionHostDelegate() { +} + +void ShellExtensionHostDelegate::OnExtensionHostCreated( + content::WebContents* web_contents) { + ShellExtensionWebContentsObserver::CreateForWebContents(web_contents); +} + +void ShellExtensionHostDelegate::OnRenderViewCreatedForBackgroundPage( + ExtensionHost* host) { +} + +content::JavaScriptDialogManager* +ShellExtensionHostDelegate::GetJavaScriptDialogManager() { + // TODO(jamescook): Create a JavaScriptDialogManager or reuse the one from + // content_shell. + NOTREACHED(); + return NULL; +} + +void ShellExtensionHostDelegate::CreateTab(content::WebContents* web_contents, + const std::string& extension_id, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) { + // TODO(jamescook): Should app_shell support opening popup windows? + NOTREACHED(); +} + +void ShellExtensionHostDelegate::ProcessMediaAccessRequest( + content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const Extension* extension) { + // Allow access to the microphone and/or camera. + media_capture_util::GrantMediaStreamRequest( + web_contents, request, callback, extension); +} + +bool ShellExtensionHostDelegate::CheckMediaAccessPermission( + content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const Extension* extension) { + media_capture_util::VerifyMediaAccessPermission(type, extension); + return true; +} + +} // namespace extensions diff --git a/src/browser/shell_extension_host_delegate.h b/src/browser/shell_extension_host_delegate.h new file mode 100644 index 0000000000..4f7960163e --- /dev/null +++ b/src/browser/shell_extension_host_delegate.h @@ -0,0 +1,43 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_HOST_DELEGATE_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_HOST_DELEGATE_H_ + +#include "base/macros.h" +#include "extensions/browser/extension_host_delegate.h" + +namespace extensions { + +// A minimal ExtensionHostDelegate. +class ShellExtensionHostDelegate : public ExtensionHostDelegate { + public: + ShellExtensionHostDelegate(); + ~ShellExtensionHostDelegate() override; + + // ExtensionHostDelegate implementation. + void OnExtensionHostCreated(content::WebContents* web_contents) override; + void OnRenderViewCreatedForBackgroundPage(ExtensionHost* host) override; + content::JavaScriptDialogManager* GetJavaScriptDialogManager() override; + void CreateTab(content::WebContents* web_contents, + const std::string& extension_id, + WindowOpenDisposition disposition, + const gfx::Rect& initial_pos, + bool user_gesture) override; + void ProcessMediaAccessRequest(content::WebContents* web_contents, + const content::MediaStreamRequest& request, + const content::MediaResponseCallback& callback, + const Extension* extension) override; + bool CheckMediaAccessPermission(content::WebContents* web_contents, + const GURL& security_origin, + content::MediaStreamType type, + const Extension* extension) override; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellExtensionHostDelegate); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_HOST_DELEGATE_H_ diff --git a/src/browser/shell_extension_system.cc b/src/browser/shell_extension_system.cc new file mode 100644 index 0000000000..f0aec5f0db --- /dev/null +++ b/src/browser/shell_extension_system.cc @@ -0,0 +1,242 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/shell_extension_system.h" + +#include + +#include "base/files/file_path.h" +#include "base/files/file_util.h" +#include "base/path_service.h" +#include "content/public/browser/browser_context.h" +#include "content/public/browser/browser_thread.h" +#include "content/public/browser/notification_details.h" +#include "content/public/browser/notification_service.h" +#include "content/public/browser/notification_source.h" +#include "extensions/browser/api/app_runtime/app_runtime_api.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/browser/extension_registry.h" +#include "extensions/browser/info_map.h" +#include "extensions/browser/lazy_background_task_queue.h" +#include "extensions/browser/notification_types.h" +#include "extensions/browser/quota_service.h" +#include "extensions/browser/runtime_data.h" +#include "extensions/common/constants.h" +#include "extensions/common/file_util.h" +#include "extensions/common/manifest_constants.h" + +#include "components/crx_file/id_util.h" + +using content::BrowserContext; +using content::BrowserThread; + +namespace extensions { + +ShellExtensionSystem::ShellExtensionSystem(BrowserContext* browser_context) + : browser_context_(browser_context) { +} + +ShellExtensionSystem::~ShellExtensionSystem() { +} + +const Extension* ShellExtensionSystem::LoadInternalApp() { + base::DictionaryValue manifest; + manifest.SetString("name", "node-webkit"); + manifest.SetString("version", "1"); + manifest.SetInteger("manifest_version", 2); + base::ListValue* list = new base::ListValue(); + list->Append(new base::StringValue("nw:*")); + list->Append(new base::StringValue("file://*")); + manifest.Set(extensions::manifest_keys::kWebURLs, list); + + scoped_ptr scripts(new base::ListValue); + scripts->AppendString("nwapp/background.js"); + manifest.Set(extensions::manifest_keys::kPlatformAppBackgroundScripts, scripts.release()); + + base::ListValue* permission_list = new base::ListValue; + permission_list->Append(new base::StringValue("webview")); + manifest.Set(extensions::manifest_keys::kPermissions, permission_list); + + std::string error; + base::FilePath path; + PathService::Get(base::FILE_EXE, &path); + scoped_refptr extension(Extension::Create( + path, Manifest::INTERNAL, manifest, Extension::NO_FLAGS, + // crx_file::id_util::GenerateId("io-blink"), + &error)); + + if (!extension.get()) { + LOG(ERROR) << "Loading internal extension " + << " failed with: " << error; + return nullptr; + } + + ExtensionRegistry::Get(browser_context_)->AddEnabled(extension.get()); + + RegisterExtensionWithRequestContexts(extension.get()); + + content::NotificationService::current()->Notify( + extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, + content::Source(browser_context_), + content::Details(extension.get())); + + return extension.get(); +} + +const Extension* ShellExtensionSystem::LoadApp(const base::FilePath& app_dir) { + // app_shell only supports unpacked extensions. + // NOTE: If you add packed extension support consider removing the flag + // FOLLOW_SYMLINKS_ANYWHERE below. Packed extensions should not have symlinks. + CHECK(base::DirectoryExists(app_dir)) << app_dir.AsUTF8Unsafe(); + int load_flags = Extension::FOLLOW_SYMLINKS_ANYWHERE; + std::string load_error; + scoped_refptr extension = file_util::LoadExtension( + app_dir, Manifest::COMMAND_LINE, load_flags, &load_error); + if (!extension.get()) { + LOG(ERROR) << "Loading extension at " << app_dir.value() + << " failed with: " << load_error; + return nullptr; + } + + // TODO(jamescook): We may want to do some of these things here: + // * Create a PermissionsUpdater. + // * Call PermissionsUpdater::GrantActivePermissions(). + // * Call ExtensionService::SatisfyImports(). + // * Call ExtensionPrefs::OnExtensionInstalled(). + // * Send NOTIFICATION_EXTENSION_WILL_BE_INSTALLED_DEPRECATED. + + ExtensionRegistry::Get(browser_context_)->AddEnabled(extension.get()); + + RegisterExtensionWithRequestContexts(extension.get()); + + content::NotificationService::current()->Notify( + extensions::NOTIFICATION_EXTENSION_LOADED_DEPRECATED, + content::Source(browser_context_), + content::Details(extension.get())); + + return extension.get(); +} + +void ShellExtensionSystem::Init() { + // Inform the rest of the extensions system to start. + ready_.Signal(); + content::NotificationService::current()->Notify( + extensions::NOTIFICATION_EXTENSIONS_READY_DEPRECATED, + content::Source(browser_context_), + content::NotificationService::NoDetails()); +} + +void ShellExtensionSystem::LaunchApp(const ExtensionId& extension_id) { + // Send the onLaunched event. + DCHECK(ExtensionRegistry::Get(browser_context_) + ->enabled_extensions() + .Contains(extension_id)); + const Extension* extension = ExtensionRegistry::Get(browser_context_) + ->enabled_extensions() + .GetByID(extension_id); + AppRuntimeEventRouter::DispatchOnLaunchedEvent( + browser_context_, extension, extensions::SOURCE_UNTRACKED); +} + +void ShellExtensionSystem::Shutdown() { +} + +void ShellExtensionSystem::InitForRegularProfile(bool extensions_enabled) { + runtime_data_.reset( + new RuntimeData(ExtensionRegistry::Get(browser_context_))); + lazy_background_task_queue_.reset( + new LazyBackgroundTaskQueue(browser_context_)); + event_router_.reset( + new EventRouter(browser_context_, ExtensionPrefs::Get(browser_context_))); + quota_service_.reset(new QuotaService); +} + +ExtensionService* ShellExtensionSystem::extension_service() { + return NULL; +} + +RuntimeData* ShellExtensionSystem::runtime_data() { + return runtime_data_.get(); +} + +ManagementPolicy* ShellExtensionSystem::management_policy() { + return NULL; +} + +SharedUserScriptMaster* ShellExtensionSystem::shared_user_script_master() { + return NULL; +} + +StateStore* ShellExtensionSystem::state_store() { + return NULL; +} + +StateStore* ShellExtensionSystem::rules_store() { + return NULL; +} + +InfoMap* ShellExtensionSystem::info_map() { + if (!info_map_.get()) + info_map_ = new InfoMap; + return info_map_.get(); +} + +LazyBackgroundTaskQueue* ShellExtensionSystem::lazy_background_task_queue() { + return lazy_background_task_queue_.get(); +} + +EventRouter* ShellExtensionSystem::event_router() { + return event_router_.get(); +} + +ErrorConsole* ShellExtensionSystem::error_console() { + return NULL; +} + +InstallVerifier* ShellExtensionSystem::install_verifier() { + return NULL; +} + +QuotaService* ShellExtensionSystem::quota_service() { + return quota_service_.get(); +} + +void ShellExtensionSystem::RegisterExtensionWithRequestContexts( + const Extension* extension) { + BrowserThread::PostTask(BrowserThread::IO, + FROM_HERE, + base::Bind(&InfoMap::AddExtension, + info_map(), + make_scoped_refptr(extension), + base::Time::Now(), + false, + false)); +} + +void ShellExtensionSystem::UnregisterExtensionWithRequestContexts( + const std::string& extension_id, + const UnloadedExtensionInfo::Reason reason) { +} + +const OneShotEvent& ShellExtensionSystem::ready() const { + return ready_; +} + +ContentVerifier* ShellExtensionSystem::content_verifier() { + return NULL; +} + +scoped_ptr ShellExtensionSystem::GetDependentExtensions( + const Extension* extension) { + return make_scoped_ptr(new ExtensionSet()); +} + +DeclarativeUserScriptMaster* +ShellExtensionSystem::GetDeclarativeUserScriptMasterByExtension( + const ExtensionId& extension_id) { + return NULL; +} + +} // namespace extensions diff --git a/src/browser/shell_extension_system.h b/src/browser/shell_extension_system.h new file mode 100644 index 0000000000..1a22fdb5d4 --- /dev/null +++ b/src/browser/shell_extension_system.h @@ -0,0 +1,100 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_H_ + +#include + +#include "base/compiler_specific.h" +#include "extensions/browser/extension_system.h" +#include "extensions/common/one_shot_event.h" + +class BrowserContextKeyedServiceFactory; + +namespace base { +class FilePath; +} + +namespace content { +class BrowserContext; +} + +namespace extensions { + +class DeclarativeUserScriptMaster; +class EventRouter; +class InfoMap; +class LazyBackgroundTaskQueue; +class ProcessManager; +class RendererStartupHelper; +class SharedUserScriptMaster; + +// A simplified version of ExtensionSystem for app_shell. Allows +// app_shell to skip initialization of services it doesn't need. +class ShellExtensionSystem : public ExtensionSystem { + public: + explicit ShellExtensionSystem(content::BrowserContext* browser_context); + ~ShellExtensionSystem() override; + + // Loads an unpacked application from a directory. Returns the extension on + // success, or null otherwise. + const Extension* LoadApp(const base::FilePath& app_dir); + const Extension* LoadInternalApp(); + + // Initializes the extension system. + void Init(); + + // Launch the app with id |extension_id|. + void LaunchApp(const std::string& extension_id); + + // KeyedService implementation: + void Shutdown() override; + + // ExtensionSystem implementation: + void InitForRegularProfile(bool extensions_enabled) override; + ExtensionService* extension_service() override; + RuntimeData* runtime_data() override; + ManagementPolicy* management_policy() override; + SharedUserScriptMaster* shared_user_script_master() override; + StateStore* state_store() override; + StateStore* rules_store() override; + InfoMap* info_map() override; + LazyBackgroundTaskQueue* lazy_background_task_queue() override; + EventRouter* event_router() override; + ErrorConsole* error_console() override; + InstallVerifier* install_verifier() override; + QuotaService* quota_service() override; + void RegisterExtensionWithRequestContexts( + const Extension* extension) override; + void UnregisterExtensionWithRequestContexts( + const std::string& extension_id, + const UnloadedExtensionInfo::Reason reason) override; + const OneShotEvent& ready() const override; + ContentVerifier* content_verifier() override; + scoped_ptr GetDependentExtensions( + const Extension* extension) override; + DeclarativeUserScriptMaster* GetDeclarativeUserScriptMasterByExtension( + const ExtensionId& extension_id) override; + + private: + content::BrowserContext* browser_context_; // Not owned. + + // Data to be accessed on the IO thread. Must outlive process_manager_. + scoped_refptr info_map_; + + scoped_ptr runtime_data_; + scoped_ptr lazy_background_task_queue_; + scoped_ptr event_router_; + scoped_ptr quota_service_; + + // Signaled when the extension system has completed its startup tasks. + OneShotEvent ready_; + + DISALLOW_COPY_AND_ASSIGN(ShellExtensionSystem); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_H_ diff --git a/src/browser/shell_extension_system_factory.cc b/src/browser/shell_extension_system_factory.cc new file mode 100644 index 0000000000..73ad7d0182 --- /dev/null +++ b/src/browser/shell_extension_system_factory.cc @@ -0,0 +1,52 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/shell/browser/shell_extension_system_factory.h" + +#include "components/keyed_service/content/browser_context_dependency_manager.h" +#include "extensions/browser/extension_prefs_factory.h" +#include "extensions/browser/extension_registry_factory.h" +#include "extensions/shell/browser/shell_extension_system.h" + +using content::BrowserContext; + +namespace extensions { + +ExtensionSystem* ShellExtensionSystemFactory::GetForBrowserContext( + BrowserContext* context) { + return static_cast( + GetInstance()->GetServiceForBrowserContext(context, true)); +} + +// static +ShellExtensionSystemFactory* ShellExtensionSystemFactory::GetInstance() { + return Singleton::get(); +} + +ShellExtensionSystemFactory::ShellExtensionSystemFactory() + : ExtensionSystemProvider("ShellExtensionSystem", + BrowserContextDependencyManager::GetInstance()) { + DependsOn(ExtensionPrefsFactory::GetInstance()); + DependsOn(ExtensionRegistryFactory::GetInstance()); +} + +ShellExtensionSystemFactory::~ShellExtensionSystemFactory() { +} + +KeyedService* ShellExtensionSystemFactory::BuildServiceInstanceFor( + BrowserContext* context) const { + return new ShellExtensionSystem(context); +} + +BrowserContext* ShellExtensionSystemFactory::GetBrowserContextToUse( + BrowserContext* context) const { + // Use a separate instance for incognito. + return context; +} + +bool ShellExtensionSystemFactory::ServiceIsCreatedWithBrowserContext() const { + return true; +} + +} // namespace extensions diff --git a/src/browser/shell_extension_system_factory.h b/src/browser/shell_extension_system_factory.h new file mode 100644 index 0000000000..5478d81628 --- /dev/null +++ b/src/browser/shell_extension_system_factory.h @@ -0,0 +1,40 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_FACTORY_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_FACTORY_H_ + +#include "base/memory/singleton.h" +#include "extensions/browser/extension_system_provider.h" + +namespace extensions { + +// A factory that provides ShellExtensionSystem for app_shell. +class ShellExtensionSystemFactory : public ExtensionSystemProvider { + public: + // ExtensionSystemProvider implementation: + ExtensionSystem* GetForBrowserContext( + content::BrowserContext* context) override; + + static ShellExtensionSystemFactory* GetInstance(); + + private: + friend struct DefaultSingletonTraits; + + ShellExtensionSystemFactory(); + ~ShellExtensionSystemFactory() override; + + // BrowserContextKeyedServiceFactory implementation: + KeyedService* BuildServiceInstanceFor( + content::BrowserContext* context) const override; + content::BrowserContext* GetBrowserContextToUse( + content::BrowserContext* context) const override; + bool ServiceIsCreatedWithBrowserContext() const override; + + DISALLOW_COPY_AND_ASSIGN(ShellExtensionSystemFactory); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_SYSTEM_FACTORY_H_ diff --git a/src/browser/shell_extension_web_contents_observer.cc b/src/browser/shell_extension_web_contents_observer.cc new file mode 100644 index 0000000000..9dc369103d --- /dev/null +++ b/src/browser/shell_extension_web_contents_observer.cc @@ -0,0 +1,20 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/shell/browser/shell_extension_web_contents_observer.h" + +DEFINE_WEB_CONTENTS_USER_DATA_KEY( + extensions::ShellExtensionWebContentsObserver); + +namespace extensions { + +ShellExtensionWebContentsObserver::ShellExtensionWebContentsObserver( + content::WebContents* web_contents) + : ExtensionWebContentsObserver(web_contents) { +} + +ShellExtensionWebContentsObserver::~ShellExtensionWebContentsObserver() { +} + +} // namespace extensions diff --git a/src/browser/shell_extension_web_contents_observer.h b/src/browser/shell_extension_web_contents_observer.h new file mode 100644 index 0000000000..a2a187fdae --- /dev/null +++ b/src/browser/shell_extension_web_contents_observer.h @@ -0,0 +1,29 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_WEB_CONTENTS_OBSERVER_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_WEB_CONTENTS_OBSERVER_H_ + +#include "content/public/browser/web_contents_user_data.h" +#include "extensions/browser/extension_web_contents_observer.h" + +namespace extensions { + +// The app_shell version of ExtensionWebContentsObserver. +class ShellExtensionWebContentsObserver + : public ExtensionWebContentsObserver, + public content::WebContentsUserData { + private: + friend class content::WebContentsUserData; + + explicit ShellExtensionWebContentsObserver( + content::WebContents* web_contents); + ~ShellExtensionWebContentsObserver() override; + + DISALLOW_COPY_AND_ASSIGN(ShellExtensionWebContentsObserver); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSION_WEB_CONTENTS_OBSERVER_H_ diff --git a/src/browser/shell_extensions_browser_client.cc b/src/browser/shell_extensions_browser_client.cc new file mode 100644 index 0000000000..6f97628d74 --- /dev/null +++ b/src/browser/shell_extensions_browser_client.cc @@ -0,0 +1,244 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/nw/src/browser/shell_extensions_browser_client.h" + +#include "base/prefs/pref_service.h" +#include "base/prefs/pref_service_factory.h" +#include "base/prefs/testing_pref_store.h" +#include "components/pref_registry/pref_registry_syncable.h" +#include "components/user_prefs/user_prefs.h" +#include "content/public/browser/browser_thread.h" +#include "extensions/browser/api/extensions_api_client.h" +#include "extensions/browser/api/generated_api_registration.h" +#include "extensions/browser/app_sorting.h" +#include "extensions/browser/event_router.h" +#include "extensions/browser/extension_function_registry.h" +#include "extensions/browser/extension_prefs.h" +#include "extensions/browser/null_app_sorting.h" +#include "extensions/browser/updater/null_extension_cache.h" +#include "extensions/browser/url_request_util.h" +#include "extensions/shell/browser/api/generated_api_registration.h" +#include "extensions/shell/browser/shell_extension_host_delegate.h" +#include "extensions/shell/browser/shell_extension_system_factory.h" +#include "extensions/shell/browser/shell_runtime_api_delegate.h" + +#include "content/nw/src/browser/shell_component_extension_resource_manager.h" + +using content::BrowserContext; +using content::BrowserThread; + +namespace extensions { +namespace { + +// See chrome::RegisterProfilePrefs() in chrome/browser/prefs/browser_prefs.cc +void RegisterPrefs(user_prefs::PrefRegistrySyncable* registry) { + ExtensionPrefs::RegisterProfilePrefs(registry); +} + +} // namespace + +ShellExtensionsBrowserClient::ShellExtensionsBrowserClient( + BrowserContext* context) + : browser_context_(context), + api_client_(new ExtensionsAPIClient), + extension_cache_(new NullExtensionCache()) { + // Set up the preferences service. + base::PrefServiceFactory factory; + factory.set_user_prefs(new TestingPrefStore); + factory.set_extension_prefs(new TestingPrefStore); + + // TODO(jamescook): Convert this to PrefRegistrySimple. + user_prefs::PrefRegistrySyncable* pref_registry = + new user_prefs::PrefRegistrySyncable; + // Prefs should be registered before the PrefService is created. + RegisterPrefs(pref_registry); + prefs_ = factory.Create(pref_registry).Pass(); + user_prefs::UserPrefs::Set(browser_context_, prefs_.get()); +} + +ShellExtensionsBrowserClient::~ShellExtensionsBrowserClient() { +} + +bool ShellExtensionsBrowserClient::IsShuttingDown() { + return false; +} + +bool ShellExtensionsBrowserClient::AreExtensionsDisabled( + const base::CommandLine& command_line, + BrowserContext* context) { + return false; +} + +bool ShellExtensionsBrowserClient::IsValidContext(BrowserContext* context) { + return context == browser_context_; +} + +bool ShellExtensionsBrowserClient::IsSameContext(BrowserContext* first, + BrowserContext* second) { + return first == second; +} + +bool ShellExtensionsBrowserClient::HasOffTheRecordContext( + BrowserContext* context) { + return false; +} + +BrowserContext* ShellExtensionsBrowserClient::GetOffTheRecordContext( + BrowserContext* context) { + // app_shell only supports a single context. + return NULL; +} + +BrowserContext* ShellExtensionsBrowserClient::GetOriginalContext( + BrowserContext* context) { + return context; +} + +bool ShellExtensionsBrowserClient::IsGuestSession( + BrowserContext* context) const { + return false; +} + +bool ShellExtensionsBrowserClient::IsExtensionIncognitoEnabled( + const std::string& extension_id, + content::BrowserContext* context) const { + return false; +} + +bool ShellExtensionsBrowserClient::CanExtensionCrossIncognito( + const Extension* extension, + content::BrowserContext* context) const { + return false; +} + +net::URLRequestJob* +ShellExtensionsBrowserClient::MaybeCreateResourceBundleRequestJob( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const base::FilePath& directory_path, + const std::string& content_security_policy, + bool send_cors_header) { + return NULL; +} + +bool ShellExtensionsBrowserClient::AllowCrossRendererResourceLoad( + net::URLRequest* request, + bool is_incognito, + const Extension* extension, + InfoMap* extension_info_map) { + bool allowed = false; + if (url_request_util::AllowCrossRendererResourceLoad( + request, is_incognito, extension, extension_info_map, &allowed)) { + return allowed; + } + + // Couldn't determine if resource is allowed. Block the load. + return false; +} + +PrefService* ShellExtensionsBrowserClient::GetPrefServiceForContext( + BrowserContext* context) { + return prefs_.get(); +} + +void ShellExtensionsBrowserClient::GetEarlyExtensionPrefsObservers( + content::BrowserContext* context, + std::vector* observers) const { +} + +ProcessManagerDelegate* +ShellExtensionsBrowserClient::GetProcessManagerDelegate() const { + return NULL; +} + +scoped_ptr +ShellExtensionsBrowserClient::CreateExtensionHostDelegate() { + return scoped_ptr(new ShellExtensionHostDelegate); +} + +bool ShellExtensionsBrowserClient::DidVersionUpdate(BrowserContext* context) { + // TODO(jamescook): We might want to tell extensions when app_shell updates. + return false; +} + +void ShellExtensionsBrowserClient::PermitExternalProtocolHandler() { +} + +scoped_ptr ShellExtensionsBrowserClient::CreateAppSorting() { + return scoped_ptr(new NullAppSorting); +} + +bool ShellExtensionsBrowserClient::IsRunningInForcedAppMode() { + return false; +} + +ApiActivityMonitor* ShellExtensionsBrowserClient::GetApiActivityMonitor( + BrowserContext* context) { + // app_shell doesn't monitor API function calls or events. + return NULL; +} + +ExtensionSystemProvider* +ShellExtensionsBrowserClient::GetExtensionSystemFactory() { + return ShellExtensionSystemFactory::GetInstance(); +} + +void ShellExtensionsBrowserClient::RegisterExtensionFunctions( + ExtensionFunctionRegistry* registry) const { + // Register core extension-system APIs. + core_api::GeneratedFunctionRegistry::RegisterAll(registry); + + //shell::api::GeneratedFunctionRegistry::RegisterAll(registry); +} + +scoped_ptr +ShellExtensionsBrowserClient::CreateRuntimeAPIDelegate( + content::BrowserContext* context) const { + return scoped_ptr(new ShellRuntimeAPIDelegate()); +} + +ComponentExtensionResourceManager* +ShellExtensionsBrowserClient::GetComponentExtensionResourceManager() { + if (!resource_manager_) + resource_manager_.reset(new ShellComponentExtensionResourceManager()); + return resource_manager_.get(); +} + +void ShellExtensionsBrowserClient::BroadcastEventToRenderers( + const std::string& event_name, + scoped_ptr args) { + if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) { + BrowserThread::PostTask( + BrowserThread::UI, + FROM_HERE, + base::Bind(&ShellExtensionsBrowserClient::BroadcastEventToRenderers, + base::Unretained(this), + event_name, + base::Passed(&args))); + return; + } + + scoped_ptr event(new Event(event_name, args.Pass())); + EventRouter::Get(browser_context_)->BroadcastEvent(event.Pass()); +} + +net::NetLog* ShellExtensionsBrowserClient::GetNetLog() { + return NULL; +} + +ExtensionCache* ShellExtensionsBrowserClient::GetExtensionCache() { + return extension_cache_.get(); +} + +bool ShellExtensionsBrowserClient::IsBackgroundUpdateAllowed() { + return true; +} + +bool ShellExtensionsBrowserClient::IsMinBrowserVersionSupported( + const std::string& min_version) { + return true; +} + +} // namespace extensions diff --git a/src/browser/shell_extensions_browser_client.h b/src/browser/shell_extensions_browser_client.h new file mode 100644 index 0000000000..9d6e42f2b3 --- /dev/null +++ b/src/browser/shell_extensions_browser_client.h @@ -0,0 +1,101 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSIONS_BROWSER_CLIENT_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSIONS_BROWSER_CLIENT_H_ + +#include "base/compiler_specific.h" +#include "extensions/browser/extensions_browser_client.h" + +class PrefService; + +namespace extensions { + +class ExtensionsAPIClient; +class ShellComponentExtensionResourceManager; +// An ExtensionsBrowserClient that supports a single content::BrowserContent +// with no related incognito context. +class ShellExtensionsBrowserClient : public ExtensionsBrowserClient { + public: + // |context| is the single BrowserContext used for IsValidContext() below. + explicit ShellExtensionsBrowserClient(content::BrowserContext* context); + ~ShellExtensionsBrowserClient() override; + + // ExtensionsBrowserClient overrides: + bool IsShuttingDown() override; + bool AreExtensionsDisabled(const base::CommandLine& command_line, + content::BrowserContext* context) override; + bool IsValidContext(content::BrowserContext* context) override; + bool IsSameContext(content::BrowserContext* first, + content::BrowserContext* second) override; + bool HasOffTheRecordContext(content::BrowserContext* context) override; + content::BrowserContext* GetOffTheRecordContext( + content::BrowserContext* context) override; + content::BrowserContext* GetOriginalContext( + content::BrowserContext* context) override; + bool IsGuestSession(content::BrowserContext* context) const override; + bool IsExtensionIncognitoEnabled( + const std::string& extension_id, + content::BrowserContext* context) const override; + bool CanExtensionCrossIncognito( + const Extension* extension, + content::BrowserContext* context) const override; + net::URLRequestJob* MaybeCreateResourceBundleRequestJob( + net::URLRequest* request, + net::NetworkDelegate* network_delegate, + const base::FilePath& directory_path, + const std::string& content_security_policy, + bool send_cors_header) override; + bool AllowCrossRendererResourceLoad(net::URLRequest* request, + bool is_incognito, + const Extension* extension, + InfoMap* extension_info_map) override; + PrefService* GetPrefServiceForContext( + content::BrowserContext* context) override; + void GetEarlyExtensionPrefsObservers( + content::BrowserContext* context, + std::vector* observers) const override; + ProcessManagerDelegate* GetProcessManagerDelegate() const override; + scoped_ptr CreateExtensionHostDelegate() override; + bool DidVersionUpdate(content::BrowserContext* context) override; + void PermitExternalProtocolHandler() override; + scoped_ptr CreateAppSorting() override; + bool IsRunningInForcedAppMode() override; + ApiActivityMonitor* GetApiActivityMonitor( + content::BrowserContext* context) override; + ExtensionSystemProvider* GetExtensionSystemFactory() override; + void RegisterExtensionFunctions( + ExtensionFunctionRegistry* registry) const override; + scoped_ptr CreateRuntimeAPIDelegate( + content::BrowserContext* context) const override; + ComponentExtensionResourceManager* GetComponentExtensionResourceManager() + override; + void BroadcastEventToRenderers(const std::string& event_name, + scoped_ptr args) override; + net::NetLog* GetNetLog() override; + ExtensionCache* GetExtensionCache() override; + bool IsBackgroundUpdateAllowed() override; + bool IsMinBrowserVersionSupported(const std::string& min_version) override; + + private: + // The single BrowserContext for app_shell. Not owned. + content::BrowserContext* browser_context_; + + // Support for extension APIs. + scoped_ptr api_client_; + + // The PrefService for |browser_context_|. + scoped_ptr prefs_; + + // The extension cache used for download and installation. + scoped_ptr extension_cache_; + + scoped_ptr resource_manager_; + + DISALLOW_COPY_AND_ASSIGN(ShellExtensionsBrowserClient); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_EXTENSIONS_BROWSER_CLIENT_H_ diff --git a/src/browser/shell_javascript_dialog_creator.h b/src/browser/shell_javascript_dialog_creator.h index cddf0510ad..062384e561 100644 --- a/src/browser/shell_javascript_dialog_creator.h +++ b/src/browser/shell_javascript_dialog_creator.h @@ -28,20 +28,20 @@ class ShellJavaScriptDialogCreator : public JavaScriptDialogManager { const base::string16& message_text, const base::string16& default_prompt_text, const DialogClosedCallback& callback, - bool* did_suppress_message) OVERRIDE; + bool* did_suppress_message) override; virtual void RunBeforeUnloadDialog( WebContents* web_contents, const base::string16& message_text, bool is_reload, - const DialogClosedCallback& callback) OVERRIDE; + const DialogClosedCallback& callback) override; virtual void CancelActiveAndPendingDialogs( - WebContents* web_contents) OVERRIDE; + WebContents* web_contents) override; // Called by the ShellJavaScriptDialog when it closes. void DialogClosed(ShellJavaScriptDialog* dialog); - virtual void WebContentsDestroyed(WebContents* web_contents) OVERRIDE; + virtual void WebContentsDestroyed(WebContents* web_contents) override; // Used for content_browsertests. void set_dialog_request_callback( diff --git a/src/browser/shell_login_dialog.h b/src/browser/shell_login_dialog.h index 55c39d34eb..5696964dde 100644 --- a/src/browser/shell_login_dialog.h +++ b/src/browser/shell_login_dialog.h @@ -46,7 +46,7 @@ class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate { // ResourceDispatcherHostLoginDelegate implementation: // Threading: IO thread. - virtual void OnRequestCancelled() OVERRIDE; + virtual void OnRequestCancelled() override; // Called by the platform specific code when the user responds. Public because // the aforementioned platform specific code may not have access to private @@ -58,17 +58,17 @@ class ShellLoginDialog : public ResourceDispatcherHostLoginDelegate { #if defined(OS_WIN) || defined(OS_LINUX) // views::DialogDelegate methods: - virtual base::string16 GetDialogButtonLabel(ui::DialogButton button) const OVERRIDE; - virtual base::string16 GetWindowTitle() const OVERRIDE; - virtual void WindowClosing() OVERRIDE; - virtual void DeleteDelegate() OVERRIDE; - virtual ui::ModalType GetModalType() const OVERRIDE; - virtual bool Cancel() OVERRIDE; - virtual bool Accept() OVERRIDE; - virtual views::View* GetInitiallyFocusedView() OVERRIDE; - virtual views::View* GetContentsView() OVERRIDE; - virtual views::Widget* GetWidget() OVERRIDE; - virtual const views::Widget* GetWidget() const OVERRIDE; + virtual base::string16 GetDialogButtonLabel(ui::DialogButton button) const override; + virtual base::string16 GetWindowTitle() const override; + virtual void WindowClosing() override; + virtual void DeleteDelegate() override; + virtual ui::ModalType GetModalType() const override; + virtual bool Cancel() override; + virtual bool Accept() override; + virtual views::View* GetInitiallyFocusedView() override; + virtual views::View* GetContentsView() override; + virtual views::Widget* GetWidget() override; + virtual const views::Widget* GetWidget() const override; #endif protected: diff --git a/src/browser/shell_resource_dispatcher_host_delegate.h b/src/browser/shell_resource_dispatcher_host_delegate.h index 3679ba7d40..dce40e1925 100644 --- a/src/browser/shell_resource_dispatcher_host_delegate.h +++ b/src/browser/shell_resource_dispatcher_host_delegate.h @@ -19,10 +19,10 @@ class ShellResourceDispatcherHostDelegate // ResourceDispatcherHostDelegate implementation. virtual ResourceDispatcherHostLoginDelegate* CreateLoginDelegate( - net::AuthChallengeInfo* auth_info, net::URLRequest* request) OVERRIDE; + net::AuthChallengeInfo* auth_info, net::URLRequest* request) override; virtual bool HandleExternalProtocol(const GURL& url, int child_id, - int route_id) OVERRIDE; + int route_id) override; // Used for content_browsertests. void set_login_request_callback( diff --git a/src/browser/shell_runtime_api_delegate.cc b/src/browser/shell_runtime_api_delegate.cc new file mode 100644 index 0000000000..3c63da7b43 --- /dev/null +++ b/src/browser/shell_runtime_api_delegate.cc @@ -0,0 +1,66 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/shell/browser/shell_runtime_api_delegate.h" + +#include "extensions/common/api/runtime.h" + +#if defined(OS_CHROMEOS) +#include "chromeos/dbus/dbus_thread_manager.h" +#include "chromeos/dbus/power_manager_client.h" +#endif + +using extensions::core_api::runtime::PlatformInfo; + +namespace extensions { + +ShellRuntimeAPIDelegate::ShellRuntimeAPIDelegate() { +} + +ShellRuntimeAPIDelegate::~ShellRuntimeAPIDelegate() { +} + +void ShellRuntimeAPIDelegate::AddUpdateObserver(UpdateObserver* observer) { +} + +void ShellRuntimeAPIDelegate::RemoveUpdateObserver(UpdateObserver* observer) { +} + +base::Version ShellRuntimeAPIDelegate::GetPreviousExtensionVersion( + const Extension* extension) { + return base::Version(); +} + +void ShellRuntimeAPIDelegate::ReloadExtension(const std::string& extension_id) { +} + +bool ShellRuntimeAPIDelegate::CheckForUpdates( + const std::string& extension_id, + const UpdateCheckCallback& callback) { + return false; +} + +void ShellRuntimeAPIDelegate::OpenURL(const GURL& uninstall_url) { +} + +bool ShellRuntimeAPIDelegate::GetPlatformInfo(PlatformInfo* info) { +#if defined(OS_CHROMEOS) + info->os = PlatformInfo::OS_CROS_; +#elif defined(OS_LINUX) + info->os = PlatformInfo::OS_LINUX_; +#endif + return true; +} + +bool ShellRuntimeAPIDelegate::RestartDevice(std::string* error_message) { +// We allow chrome.runtime.restart() to request a device restart on ChromeOS. +#if defined(OS_CHROMEOS) + chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart(); + return true; +#endif + *error_message = "Restart is only supported on ChromeOS."; + return false; +} + +} // namespace extensions diff --git a/src/browser/shell_runtime_api_delegate.h b/src/browser/shell_runtime_api_delegate.h new file mode 100644 index 0000000000..816423b097 --- /dev/null +++ b/src/browser/shell_runtime_api_delegate.h @@ -0,0 +1,36 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ +#define EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ + +#include "base/macros.h" +#include "extensions/browser/api/runtime/runtime_api_delegate.h" + +namespace extensions { + +class ShellRuntimeAPIDelegate : public RuntimeAPIDelegate { + public: + ShellRuntimeAPIDelegate(); + ~ShellRuntimeAPIDelegate() override; + + // RuntimeAPIDelegate implementation. + void AddUpdateObserver(UpdateObserver* observer) override; + void RemoveUpdateObserver(UpdateObserver* observer) override; + base::Version GetPreviousExtensionVersion( + const Extension* extension) override; + void ReloadExtension(const std::string& extension_id) override; + bool CheckForUpdates(const std::string& extension_id, + const UpdateCheckCallback& callback) override; + void OpenURL(const GURL& uninstall_url) override; + bool GetPlatformInfo(core_api::runtime::PlatformInfo* info) override; + bool RestartDevice(std::string* error_message) override; + + private: + DISALLOW_COPY_AND_ASSIGN(ShellRuntimeAPIDelegate); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_BROWSER_SHELL_RUNTIME_API_DELEGATE_H_ diff --git a/src/common/common_message_generator.h b/src/common/common_message_generator.h index 1879cedc93..2ff37bee05 100644 --- a/src/common/common_message_generator.h +++ b/src/common/common_message_generator.h @@ -1,2 +1,3 @@ +#include "extensions/common/extension_messages.h" #include "content/nw/src/api/api_messages.h" #include "content/nw/src/common/print_messages.h" diff --git a/src/common/print_messages.cc b/src/common/print_messages.cc index 21a359412e..401cef43c7 100644 --- a/src/common/print_messages.cc +++ b/src/common/print_messages.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/nw/src/common/print_messages.h" +#include "chrome/common/print_messages.h" #include "base/basictypes.h" #include "base/strings/string16.h" diff --git a/src/common/print_messages.h b/src/common/print_messages.h index e638450da3..5d28f9937d 100644 --- a/src/common/print_messages.h +++ b/src/common/print_messages.h @@ -15,11 +15,12 @@ #include "printing/page_size_margins.h" #include "printing/print_job_constants.h" #include "third_party/WebKit/public/web/WebPrintScalingOption.h" +#include "ui/gfx/ipc/gfx_param_traits.h" #include "ui/gfx/native_widget_types.h" #include "ui/gfx/rect.h" -#ifndef NW_COMMON_PRINT_MESSAGES_H_ -#define NW_COMMON_PRINT_MESSAGES_H_ +#ifndef CHROME_COMMON_PRINT_MESSAGES_H_ +#define CHROME_COMMON_PRINT_MESSAGES_H_ struct PrintMsg_Print_Params { PrintMsg_Print_Params(); @@ -179,24 +180,6 @@ IPC_STRUCT_TRAITS_BEGIN(PrintHostMsg_RequestPrintPreview_Params) IPC_STRUCT_TRAITS_MEMBER(selection_only) IPC_STRUCT_TRAITS_END() -IPC_STRUCT_TRAITS_BEGIN(printing::PageSizeMargins) - IPC_STRUCT_TRAITS_MEMBER(content_width) - IPC_STRUCT_TRAITS_MEMBER(content_height) - IPC_STRUCT_TRAITS_MEMBER(margin_left) - IPC_STRUCT_TRAITS_MEMBER(margin_right) - IPC_STRUCT_TRAITS_MEMBER(margin_top) - IPC_STRUCT_TRAITS_MEMBER(margin_bottom) -IPC_STRUCT_TRAITS_END() - -IPC_STRUCT_TRAITS_BEGIN(PrintMsg_PrintPages_Params) - // Parameters to render the page as a printed page. It must always be the same - // value for all the document. - IPC_STRUCT_TRAITS_MEMBER(params) - - // If empty, this means a request to render all the printed pages. - IPC_STRUCT_TRAITS_MEMBER(pages) -IPC_STRUCT_TRAITS_END() - IPC_STRUCT_TRAITS_BEGIN(printing::PageRange) IPC_STRUCT_TRAITS_MEMBER(from) IPC_STRUCT_TRAITS_MEMBER(to) @@ -216,12 +199,26 @@ IPC_STRUCT_TRAITS_BEGIN(PrintHostMsg_SetOptionsFromDocument_Params) IPC_STRUCT_TRAITS_MEMBER(page_ranges) IPC_STRUCT_TRAITS_END() +IPC_STRUCT_TRAITS_BEGIN(printing::PageSizeMargins) + IPC_STRUCT_TRAITS_MEMBER(content_width) + IPC_STRUCT_TRAITS_MEMBER(content_height) + IPC_STRUCT_TRAITS_MEMBER(margin_left) + IPC_STRUCT_TRAITS_MEMBER(margin_right) + IPC_STRUCT_TRAITS_MEMBER(margin_top) + IPC_STRUCT_TRAITS_MEMBER(margin_bottom) +IPC_STRUCT_TRAITS_END() + +IPC_STRUCT_TRAITS_BEGIN(PrintMsg_PrintPages_Params) + // Parameters to render the page as a printed page. It must always be the same + // value for all the document. + IPC_STRUCT_TRAITS_MEMBER(params) + + // If empty, this means a request to render all the printed pages. + IPC_STRUCT_TRAITS_MEMBER(pages) +IPC_STRUCT_TRAITS_END() + // Parameters to describe a rendered document. IPC_STRUCT_BEGIN(PrintHostMsg_DidPreviewDocument_Params) - // True when we can reuse existing preview data. |metafile_data_handle| and - // |data_size| should not be used when this is true. - IPC_STRUCT_MEMBER(bool, reuse_existing_data) - // A shared memory handle to metafile data. IPC_STRUCT_MEMBER(base::SharedMemoryHandle, metafile_data_handle) @@ -290,9 +287,6 @@ IPC_STRUCT_BEGIN(PrintHostMsg_DidPrintPage_Params) // Page number. IPC_STRUCT_MEMBER(int, page_number) - // Shrink factor used to render this page. - IPC_STRUCT_MEMBER(double, actual_shrink) - // The size of the page the page author specified. IPC_STRUCT_MEMBER(gfx::Size, page_size) @@ -314,8 +308,8 @@ IPC_STRUCT_END() // Tells the render view to initiate print preview for the entire document. IPC_MESSAGE_ROUTED1(PrintMsg_InitiatePrintPreview, bool /* selection_only */) -// Tells the render view to initiate printing or print preview for a particular -// node, depending on which mode the render view is in. +// Tells the render frame to initiate printing or print preview for a particular +// node, depending on which mode the render frame is in. IPC_MESSAGE_ROUTED0(PrintMsg_PrintNodeUnderContextMenu) // Tells the renderer to print the print preview tab's PDF plugin without @@ -324,10 +318,15 @@ IPC_MESSAGE_ROUTED0(PrintMsg_PrintNodeUnderContextMenu) IPC_MESSAGE_ROUTED1(PrintMsg_PrintForPrintPreview, base::DictionaryValue /* settings */) +#if defined(ENABLE_BASIC_PRINTING) // Tells the render view to switch the CSS to print media type, renders every // requested pages and switch back the CSS to display media type. IPC_MESSAGE_ROUTED0(PrintMsg_PrintPages) +// Like PrintMsg_PrintPages, but using the print preview document's frame/node. +IPC_MESSAGE_ROUTED0(PrintMsg_PrintForSystemDialog) +#endif // ENABLE_BASIC_PRINTING + // Tells the render view that printing is done so it can clean up. IPC_MESSAGE_ROUTED1(PrintMsg_PrintingDone, bool /* success */) @@ -342,12 +341,6 @@ IPC_MESSAGE_ROUTED1(PrintMsg_SetScriptedPrintingBlocked, IPC_MESSAGE_ROUTED1(PrintMsg_PrintPreview, base::DictionaryValue /* settings */) -// Like PrintMsg_PrintPages, but using the print preview document's frame/node. -IPC_MESSAGE_ROUTED0(PrintMsg_PrintForSystemDialog) - -// Tells a renderer to stop blocking script initiated printing. -IPC_MESSAGE_ROUTED0(PrintMsg_ResetScriptedPrintCount) - // Messages sent from the renderer to the browser. #if defined(OS_WIN) @@ -358,6 +351,10 @@ IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_DuplicateSection, base::SharedMemoryHandle /* browser handle */) #endif +// Check if printing is enabled. +IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_IsPrintingEnabled, + bool /* is_enabled */) + // Tells the browser that the renderer is done calculating the number of // rendered pages according to the specified settings. IPC_MESSAGE_ROUTED2(PrintHostMsg_DidGetPrintedPagesCount, @@ -383,10 +380,11 @@ IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_GetDefaultPrintSettings, // The renderer wants to update the current print settings with new // |job_settings|. -IPC_SYNC_MESSAGE_ROUTED2_1(PrintHostMsg_UpdatePrintSettings, +IPC_SYNC_MESSAGE_ROUTED2_2(PrintHostMsg_UpdatePrintSettings, int /* document_cookie */, base::DictionaryValue /* job_settings */, - PrintMsg_PrintPages_Params /* current_settings */) + PrintMsg_PrintPages_Params /* current_settings */, + bool /* canceled */) // It's the renderer that controls the printing process when it is generated // by javascript. This step is about showing UI to the user to select the @@ -397,17 +395,6 @@ IPC_SYNC_MESSAGE_ROUTED1_1(PrintHostMsg_ScriptedPrint, PrintMsg_PrintPages_Params /* settings chosen by the user*/) -#if defined(USE_X11) -// Asks the browser to create a temporary file for the renderer to fill -// in resulting NativeMetafile in printing. -IPC_SYNC_MESSAGE_CONTROL0_2(PrintHostMsg_AllocateTempFileForPrinting, - base::FileDescriptor /* temp file fd */, - int /* fd in browser*/) -IPC_MESSAGE_CONTROL2(PrintHostMsg_TempFileForPrintingWritten, - int /* render_view_id */, - int /* fd in browser */) -#endif - // Asks the browser to do print preview. IPC_MESSAGE_ROUTED1(PrintHostMsg_RequestPrintPreview, PrintHostMsg_RequestPrintPreview_Params /* params */) @@ -465,16 +452,12 @@ IPC_MESSAGE_ROUTED1(PrintHostMsg_PrintPreviewInvalidPrinterSettings, // Run a nested message loop in the renderer until print preview for // window.print() finishes. -IPC_SYNC_MESSAGE_ROUTED1_0(PrintHostMsg_ScriptedPrintPreview, - bool /* is_modifiable */) - -// Notify the browser that the PDF in the initiator renderer has disabled print -// scaling option. -IPC_MESSAGE_ROUTED0(PrintHostMsg_PrintPreviewScalingDisabled) +IPC_SYNC_MESSAGE_ROUTED0_0(PrintHostMsg_SetupScriptedPrintPreview) -// Check if printing is enabled. -IPC_SYNC_MESSAGE_ROUTED0_1(PrintHostMsg_IsPrintingEnabled, - bool /* is_enabled */) +// Tell the browser to show the print preview, when the document is sufficiently +// loaded such that the renderer can determine whether it is modifiable or not. +IPC_MESSAGE_ROUTED1(PrintHostMsg_ShowScriptedPrintPreview, + bool /* is_modifiable */) // Notify the browser to set print presets based on source PDF document. IPC_MESSAGE_ROUTED1(PrintHostMsg_SetOptionsFromDocument, diff --git a/src/common/shell_extensions_client.cc b/src/common/shell_extensions_client.cc new file mode 100644 index 0000000000..0a3913829e --- /dev/null +++ b/src/common/shell_extensions_client.cc @@ -0,0 +1,217 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "extensions/shell/common/shell_extensions_client.h" + +#include "base/lazy_instance.h" +#include "base/logging.h" +#include "extensions/common/api/generated_schemas.h" +#include "extensions/common/common_manifest_handlers.h" +#include "extensions/common/extension_urls.h" +#include "extensions/common/features/api_feature.h" +#include "extensions/common/features/base_feature_provider.h" +#include "extensions/common/features/json_feature_provider_source.h" +#include "extensions/common/features/manifest_feature.h" +#include "extensions/common/features/permission_feature.h" +#include "extensions/common/features/simple_feature.h" +#include "extensions/common/manifest_handler.h" +#include "extensions/common/permissions/permission_message_provider.h" +#include "extensions/common/permissions/permissions_info.h" +#include "extensions/common/permissions/permissions_provider.h" +#include "extensions/common/url_pattern_set.h" +#include "extensions/shell/common/api/generated_schemas.h" +//#include "grit/app_shell_resources.h" +#include "grit/extensions_resources.h" + +namespace extensions { + +namespace { + +template +SimpleFeature* CreateFeature() { + return new FeatureClass; +} + +// TODO(jamescook): Refactor ChromePermissionsMessageProvider so we can share +// code. For now, this implementation does nothing. +class ShellPermissionMessageProvider : public PermissionMessageProvider { + public: + ShellPermissionMessageProvider() {} + ~ShellPermissionMessageProvider() override {} + + // PermissionMessageProvider implementation. + PermissionMessages GetPermissionMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const override { + return PermissionMessages(); + } + + std::vector GetWarningMessages( + const PermissionSet* permissions, + Manifest::Type extension_type) const override { + return std::vector(); + } + + std::vector GetWarningMessagesDetails( + const PermissionSet* permissions, + Manifest::Type extension_type) const override { + return std::vector(); + } + + bool IsPrivilegeIncrease(const PermissionSet* old_permissions, + const PermissionSet* new_permissions, + Manifest::Type extension_type) const override { + // Ensure we implement this before shipping. + CHECK(false); + return false; + } + + private: + DISALLOW_COPY_AND_ASSIGN(ShellPermissionMessageProvider); +}; + +base::LazyInstance + g_permission_message_provider = LAZY_INSTANCE_INITIALIZER; + +} // namespace + +ShellExtensionsClient::ShellExtensionsClient() + : extensions_api_permissions_(ExtensionsAPIPermissions()) { +} + +ShellExtensionsClient::~ShellExtensionsClient() { +} + +void ShellExtensionsClient::Initialize() { + RegisterCommonManifestHandlers(); + ManifestHandler::FinalizeRegistration(); + // TODO(jamescook): Do we need to whitelist any extensions? + + PermissionsInfo::GetInstance()->AddProvider(extensions_api_permissions_); +} + +const PermissionMessageProvider& +ShellExtensionsClient::GetPermissionMessageProvider() const { + NOTIMPLEMENTED(); + return g_permission_message_provider.Get(); +} + +const std::string ShellExtensionsClient::GetProductName() { + return "app_shell"; +} + +scoped_ptr ShellExtensionsClient::CreateFeatureProvider( + const std::string& name) const { + scoped_ptr provider; + scoped_ptr source( + CreateFeatureProviderSource(name)); + if (name == "api") { + provider.reset(new BaseFeatureProvider(source->dictionary(), + CreateFeature)); + } else if (name == "manifest") { + provider.reset(new BaseFeatureProvider(source->dictionary(), + CreateFeature)); + } else if (name == "permission") { + provider.reset(new BaseFeatureProvider(source->dictionary(), + CreateFeature)); + } else { + NOTREACHED(); + } + return provider.Pass(); +} + +scoped_ptr +ShellExtensionsClient::CreateFeatureProviderSource( + const std::string& name) const { + scoped_ptr source( + new JSONFeatureProviderSource(name)); + if (name == "api") { + source->LoadJSON(IDR_EXTENSION_API_FEATURES); + //source->LoadJSON(IDR_SHELL_EXTENSION_API_FEATURES); + } else if (name == "manifest") { + source->LoadJSON(IDR_EXTENSION_MANIFEST_FEATURES); + } else if (name == "permission") { + source->LoadJSON(IDR_EXTENSION_PERMISSION_FEATURES); + } else { + NOTREACHED(); + source.reset(); + } + return source.Pass(); +} + +void ShellExtensionsClient::FilterHostPermissions( + const URLPatternSet& hosts, + URLPatternSet* new_hosts, + std::set* messages) const { + NOTIMPLEMENTED(); +} + +void ShellExtensionsClient::SetScriptingWhitelist( + const ScriptingWhitelist& whitelist) { + scripting_whitelist_ = whitelist; +} + +const ExtensionsClient::ScriptingWhitelist& +ShellExtensionsClient::GetScriptingWhitelist() const { + // TODO(jamescook): Real whitelist. + return scripting_whitelist_; +} + +URLPatternSet ShellExtensionsClient::GetPermittedChromeSchemeHosts( + const Extension* extension, + const APIPermissionSet& api_permissions) const { + NOTIMPLEMENTED(); + return URLPatternSet(); +} + +bool ShellExtensionsClient::IsScriptableURL(const GURL& url, + std::string* error) const { + NOTIMPLEMENTED(); + return true; +} + +bool ShellExtensionsClient::IsAPISchemaGenerated( + const std::string& name) const { + return core_api::GeneratedSchemas::IsGenerated(name); // || + // shell::api::GeneratedSchemas::IsGenerated(name); +} + +base::StringPiece ShellExtensionsClient::GetAPISchema( + const std::string& name) const { + // Schema for app_shell-only APIs. + // if (shell::api::GeneratedSchemas::IsGenerated(name)) + // return shell::api::GeneratedSchemas::Get(name); + + // Core extensions APIs. + return core_api::GeneratedSchemas::Get(name); +} + +void ShellExtensionsClient::RegisterAPISchemaResources( + ExtensionAPI* api) const { +} + +bool ShellExtensionsClient::ShouldSuppressFatalErrors() const { + return true; +} + +std::string ShellExtensionsClient::GetWebstoreBaseURL() const { + return extension_urls::kChromeWebstoreBaseURL; +} + +std::string ShellExtensionsClient::GetWebstoreUpdateURL() const { + return extension_urls::kChromeWebstoreUpdateURL; +} + +bool ShellExtensionsClient::IsBlacklistUpdateURL(const GURL& url) const { + // TODO(rockot): Maybe we want to do something else here. For now we accept + // any URL as a blacklist URL because we don't really care. + return true; +} + +std::set ShellExtensionsClient::GetBrowserImagePaths( + const Extension* extension) { + return std::set(); +} + +} // namespace extensions diff --git a/src/common/shell_extensions_client.h b/src/common/shell_extensions_client.h new file mode 100644 index 0000000000..cbb72e12aa --- /dev/null +++ b/src/common/shell_extensions_client.h @@ -0,0 +1,60 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#ifndef EXTENSIONS_SHELL_COMMON_SHELL_EXTENSIONS_CLIENT_H_ +#define EXTENSIONS_SHELL_COMMON_SHELL_EXTENSIONS_CLIENT_H_ + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "extensions/common/extensions_client.h" +#include "extensions/common/permissions/extensions_api_permissions.h" + +namespace extensions { + +// The app_shell implementation of ExtensionsClient. +class ShellExtensionsClient : public ExtensionsClient { + public: + ShellExtensionsClient(); + ~ShellExtensionsClient() override; + + // ExtensionsClient overrides: + void Initialize() override; + const PermissionMessageProvider& GetPermissionMessageProvider() + const override; + const std::string GetProductName() override; + scoped_ptr CreateFeatureProvider( + const std::string& name) const override; + scoped_ptr CreateFeatureProviderSource( + const std::string& name) const override; + void FilterHostPermissions( + const URLPatternSet& hosts, + URLPatternSet* new_hosts, + std::set* messages) const override; + void SetScriptingWhitelist(const ScriptingWhitelist& whitelist) override; + const ScriptingWhitelist& GetScriptingWhitelist() const override; + URLPatternSet GetPermittedChromeSchemeHosts( + const Extension* extension, + const APIPermissionSet& api_permissions) const override; + bool IsScriptableURL(const GURL& url, std::string* error) const override; + bool IsAPISchemaGenerated(const std::string& name) const override; + base::StringPiece GetAPISchema(const std::string& name) const override; + void RegisterAPISchemaResources(ExtensionAPI* api) const override; + bool ShouldSuppressFatalErrors() const override; + std::string GetWebstoreBaseURL() const override; + std::string GetWebstoreUpdateURL() const override; + bool IsBlacklistUpdateURL(const GURL& url) const override; + std::set GetBrowserImagePaths( + const Extension* extension) override; + + private: + const ExtensionsAPIPermissions extensions_api_permissions_; + + ScriptingWhitelist scripting_whitelist_; + + DISALLOW_COPY_AND_ASSIGN(ShellExtensionsClient); +}; + +} // namespace extensions + +#endif // EXTENSIONS_SHELL_COMMON_SHELL_EXTENSIONS_CLIENT_H_ diff --git a/src/geolocation/shell_access_token_store.h b/src/geolocation/shell_access_token_store.h index 205d89ffc9..48c5910ce0 100644 --- a/src/geolocation/shell_access_token_store.h +++ b/src/geolocation/shell_access_token_store.h @@ -25,10 +25,10 @@ class ShellAccessTokenStore : public content::AccessTokenStore { // AccessTokenStore virtual void LoadAccessTokens( - const LoadAccessTokensCallbackType& callback) OVERRIDE; + const LoadAccessTokensCallbackType& callback) override; virtual void SaveAccessToken( - const GURL& server_url, const base::string16& access_token) OVERRIDE; + const GURL& server_url, const base::string16& access_token) override; content::ShellBrowserContext* shell_browser_context_; net::URLRequestContextGetter* system_request_context_; diff --git a/src/media/media_internals.h b/src/media/media_internals.h index d90855214d..cef21cb575 100644 --- a/src/media/media_internals.h +++ b/src/media/media_internals.h @@ -42,28 +42,28 @@ class MediaInternals : public content::MediaObserver { static MediaInternals* GetInstance(); // Overridden from content::MediaObserver: - virtual void OnAudioCaptureDevicesChanged() OVERRIDE; - virtual void OnVideoCaptureDevicesChanged() OVERRIDE; + virtual void OnAudioCaptureDevicesChanged() override; + virtual void OnVideoCaptureDevicesChanged() override; virtual void OnMediaRequestStateChanged( int render_process_id, int render_frame_id, int page_request_id, const GURL& security_origin, content::MediaStreamType stream_type, - content::MediaRequestState state) OVERRIDE; + content::MediaRequestState state) override; virtual void OnCreatingAudioStream(int render_process_id, - int render_view_id) OVERRIDE; + int render_view_id) override; virtual void OnAudioStreamPlaying( int render_process_id, int render_frame_id, int stream_id, - const ReadPowerAndClipCallback& power_read_callback) OVERRIDE {} + const ReadPowerAndClipCallback& power_read_callback) override {} virtual void OnAudioStreamStopped( int render_process_id, int render_frame_id, - int stream_id) OVERRIDE {} + int stream_id) override {} // Methods for observers. // Observers should add themselves on construction and remove themselves // on destruction. diff --git a/src/net/app_protocol_handler.cc b/src/net/app_protocol_handler.cc index 3f7ec69b16..9fff3fb1c0 100644 --- a/src/net/app_protocol_handler.cc +++ b/src/net/app_protocol_handler.cc @@ -5,7 +5,7 @@ #include "content/nw/src/net/app_protocol_handler.h" #include "base/base64.h" -#include "base/file_util.h" +#include "base/files/file_util.h" #include "base/files/file_path.h" #include "base/format_macros.h" #include "base/logging.h" @@ -102,11 +102,11 @@ class URLRequestNWAppJob : public net::URLRequestFileJob { // base::Time()); } - virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE { + virtual void GetResponseInfo(net::HttpResponseInfo* info) override { *info = response_info_; } - virtual void Start() OVERRIDE { + virtual void Start() override { base::Time* last_modified_time = new base::Time(); bool posted = content::BrowserThread::PostBlockingPoolTaskAndReply( FROM_HERE, diff --git a/src/net/app_protocol_handler.h b/src/net/app_protocol_handler.h index ed8222bee0..5bfe145b60 100644 --- a/src/net/app_protocol_handler.h +++ b/src/net/app_protocol_handler.h @@ -24,8 +24,8 @@ class AppProtocolHandler : public: AppProtocolHandler(const base::FilePath& root); virtual URLRequestJob* MaybeCreateJob( - URLRequest* request, NetworkDelegate* network_delegate) const OVERRIDE; - virtual bool IsSafeRedirectTarget(const GURL& location) const OVERRIDE; + URLRequest* request, NetworkDelegate* network_delegate) const override; + virtual bool IsSafeRedirectTarget(const GURL& location) const override; private: base::FilePath root_path_; diff --git a/src/net/resource_request_job.cc b/src/net/resource_request_job.cc index 191a5ffe53..20ce91a4c6 100644 --- a/src/net/resource_request_job.cc +++ b/src/net/resource_request_job.cc @@ -90,7 +90,7 @@ void ResourceRequestJob::DataAvailable(base::RefCountedMemory* bytes) { int bytes_read; if (pending_buf_.get()) { CHECK(pending_buf_->data()); - CompleteRead(pending_buf_, pending_buf_size_, &bytes_read); + CompleteRead(pending_buf_.get(), pending_buf_size_, &bytes_read); pending_buf_ = NULL; NotifyReadComplete(bytes_read); } diff --git a/src/net/resource_request_job.h b/src/net/resource_request_job.h index 5726a52e00..c8bf45ad61 100644 --- a/src/net/resource_request_job.h +++ b/src/net/resource_request_job.h @@ -39,11 +39,11 @@ class ResourceRequestJob : public net::URLRequestJob { int resource_id); // net::URLRequestJob methods. - virtual void Start() OVERRIDE; + virtual void Start() override; virtual bool ReadRawData(net::IOBuffer* dest, int dest_size, int* bytes_read) - OVERRIDE; - virtual bool GetMimeType(std::string* mime_type) const OVERRIDE; - virtual void GetResponseInfo(net::HttpResponseInfo* info) OVERRIDE; + override; + virtual bool GetMimeType(std::string* mime_type) const override; + virtual void GetResponseInfo(net::HttpResponseInfo* info) override; static ResourceRequestJob* Factory(net::URLRequest* request, net::NetworkDelegate* network_delegate); diff --git a/src/net/shell_network_delegate.cc b/src/net/shell_network_delegate.cc index 3be947bc1c..633fb46890 100644 --- a/src/net/shell_network_delegate.cc +++ b/src/net/shell_network_delegate.cc @@ -1,35 +1,29 @@ -// 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" +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "content/shell/browser/shell_network_delegate.h" #include "net/base/net_errors.h" +#include "net/base/static_cookie_policy.h" +#include "net/url_request/url_request.h" namespace content { +namespace { +bool g_accept_all_cookies = true; +} + ShellNetworkDelegate::ShellNetworkDelegate() { } ShellNetworkDelegate::~ShellNetworkDelegate() { } +void ShellNetworkDelegate::SetAcceptAllCookies(bool accept) { + g_accept_all_cookies = accept; +} + int ShellNetworkDelegate::OnBeforeURLRequest( net::URLRequest* request, const net::CompletionCallback& callback, @@ -89,13 +83,25 @@ ShellNetworkDelegate::AuthRequiredResponse ShellNetworkDelegate::OnAuthRequired( bool ShellNetworkDelegate::OnCanGetCookies(const net::URLRequest& request, const net::CookieList& cookie_list) { - return true; + net::StaticCookiePolicy::Type policy_type = g_accept_all_cookies ? + net::StaticCookiePolicy::ALLOW_ALL_COOKIES : + net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES; + net::StaticCookiePolicy policy(policy_type); + int rv = policy.CanGetCookies( + request.url(), request.first_party_for_cookies()); + return rv == net::OK; } bool ShellNetworkDelegate::OnCanSetCookie(const net::URLRequest& request, const std::string& cookie_line, net::CookieOptions* options) { - return true; + net::StaticCookiePolicy::Type policy_type = g_accept_all_cookies ? + net::StaticCookiePolicy::ALLOW_ALL_COOKIES : + net::StaticCookiePolicy::BLOCK_ALL_THIRD_PARTY_COOKIES; + net::StaticCookiePolicy policy(policy_type); + int rv = policy.CanSetCookie( + request.url(), request.first_party_for_cookies()); + return rv == net::OK; } bool ShellNetworkDelegate::OnCanAccessFile(const net::URLRequest& request, @@ -108,10 +114,4 @@ bool ShellNetworkDelegate::OnCanThrottleRequest( return false; } -int ShellNetworkDelegate::OnBeforeSocketStreamConnect( - net::SocketStream* socket, - const net::CompletionCallback& callback) { - return net::OK; -} - } // namespace content diff --git a/src/net/shell_network_delegate.h b/src/net/shell_network_delegate.h index 6f381d72be..df0608e83f 100644 --- a/src/net/shell_network_delegate.h +++ b/src/net/shell_network_delegate.h @@ -1,29 +1,12 @@ -// 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. +// Copyright 2013 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. -#ifndef CONTENT_NW_SRC_NET_SHELL_NETWORK_DELEGATE_H_ -#define CONTENT_NW_SRC_NET_SHELL_NETWORK_DELEGATE_H_ +#ifndef CONTENT_SHELL_BROWSER_SHELL_NETWORK_DELEGATE_H_ +#define CONTENT_SHELL_BROWSER_SHELL_NETWORK_DELEGATE_H_ #include "base/basictypes.h" #include "base/compiler_specific.h" -#include "base/files/file_path.h" #include "net/base/network_delegate.h" namespace content { @@ -31,55 +14,50 @@ namespace content { class ShellNetworkDelegate : public net::NetworkDelegate { public: ShellNetworkDelegate(); - virtual ~ShellNetworkDelegate(); + ~ShellNetworkDelegate() override; + + static void SetAcceptAllCookies(bool accept); private: // net::NetworkDelegate implementation. - virtual int OnBeforeURLRequest(net::URLRequest* request, - const net::CompletionCallback& callback, - GURL* new_url) OVERRIDE; - virtual int OnBeforeSendHeaders(net::URLRequest* request, - const net::CompletionCallback& callback, - net::HttpRequestHeaders* headers) OVERRIDE; - virtual void OnSendHeaders(net::URLRequest* request, - const net::HttpRequestHeaders& headers) OVERRIDE; - virtual int OnHeadersReceived( + int OnBeforeURLRequest(net::URLRequest* request, + const net::CompletionCallback& callback, + GURL* new_url) override; + int OnBeforeSendHeaders(net::URLRequest* request, + const net::CompletionCallback& callback, + net::HttpRequestHeaders* headers) override; + void OnSendHeaders(net::URLRequest* request, + const net::HttpRequestHeaders& headers) override; + int OnHeadersReceived( net::URLRequest* request, const net::CompletionCallback& callback, const net::HttpResponseHeaders* original_response_headers, - scoped_refptr* - override_response_headers, - GURL* allowed_unsafe_redirect_url) OVERRIDE; - virtual void OnBeforeRedirect(net::URLRequest* request, - const GURL& new_location) OVERRIDE; - virtual void OnResponseStarted(net::URLRequest* request) OVERRIDE; - virtual void OnRawBytesRead(const net::URLRequest& request, - int bytes_read) OVERRIDE; - virtual void OnCompleted(net::URLRequest* request, bool started) OVERRIDE; - virtual void OnURLRequestDestroyed(net::URLRequest* request) OVERRIDE; - virtual void OnPACScriptError(int line_number, - const base::string16& error) OVERRIDE; - virtual AuthRequiredResponse OnAuthRequired( + scoped_refptr* override_response_headers, + GURL* allowed_unsafe_redirect_url) override; + void OnBeforeRedirect(net::URLRequest* request, + const GURL& new_location) override; + void OnResponseStarted(net::URLRequest* request) override; + void OnRawBytesRead(const net::URLRequest& request, int bytes_read) override; + void OnCompleted(net::URLRequest* request, bool started) override; + void OnURLRequestDestroyed(net::URLRequest* request) override; + void OnPACScriptError(int line_number, const base::string16& error) override; + AuthRequiredResponse OnAuthRequired( net::URLRequest* request, const net::AuthChallengeInfo& auth_info, const AuthCallback& callback, - net::AuthCredentials* credentials) OVERRIDE; - virtual bool OnCanGetCookies(const net::URLRequest& request, - const net::CookieList& cookie_list) OVERRIDE; - virtual bool OnCanSetCookie(const net::URLRequest& request, - const std::string& cookie_line, - net::CookieOptions* options) OVERRIDE; - virtual bool OnCanAccessFile(const net::URLRequest& request, - const base::FilePath& path) const OVERRIDE; - virtual bool OnCanThrottleRequest( - const net::URLRequest& request) const OVERRIDE; - virtual int OnBeforeSocketStreamConnect( - net::SocketStream* stream, - const net::CompletionCallback& callback) OVERRIDE; + net::AuthCredentials* credentials) override; + bool OnCanGetCookies(const net::URLRequest& request, + const net::CookieList& cookie_list) override; + bool OnCanSetCookie(const net::URLRequest& request, + const std::string& cookie_line, + net::CookieOptions* options) override; + bool OnCanAccessFile(const net::URLRequest& request, + const base::FilePath& path) const override; + bool OnCanThrottleRequest(const net::URLRequest& request) const override; DISALLOW_COPY_AND_ASSIGN(ShellNetworkDelegate); }; } // namespace content -#endif // CONTENT_NW_SRC_NET_SHELL_NETWORK_DELEGATE_H_ +#endif // CONTENT_SHELL_BROWSER_SHELL_NETWORK_DELEGATE_H_ diff --git a/src/net/shell_url_request_context_getter.cc b/src/net/shell_url_request_context_getter.cc index 8a70eec2cd..f101c83703 100644 --- a/src/net/shell_url_request_context_getter.cc +++ b/src/net/shell_url_request_context_getter.cc @@ -94,13 +94,13 @@ class NWCookieMonsterDelegate : public net::CookieMonster::Delegate { virtual void OnCookieChanged( const net::CanonicalCookie& cookie, bool removed, - net::CookieMonster::Delegate::ChangeCause cause) OVERRIDE { + net::CookieMonster::Delegate::ChangeCause cause) override { BrowserThread::PostTask( BrowserThread::UI, FROM_HERE, base::Bind(&NWCookieMonsterDelegate::OnCookieChangedAsyncHelper, this, cookie, removed, cause)); } - virtual void OnLoaded() OVERRIDE { + virtual void OnLoaded() override { } private: @@ -157,7 +157,7 @@ ShellURLRequestContextGetter::ShellURLRequestContextGetter( // the URLRequestContextStorage on the IO thread in GetURLRequestContext(). proxy_config_service_.reset( net::ProxyService::CreateSystemProxyConfigService( - io_loop_->message_loop_proxy(), file_loop_)); + io_loop_->message_loop_proxy(), file_loop_->message_loop_proxy())); } ShellURLRequestContextGetter::~ShellURLRequestContextGetter() { @@ -185,7 +185,7 @@ net::URLRequestContext* ShellURLRequestContextGetter::GetURLRequestContext() { NULL, new NWCookieMonsterDelegate(browser_context_)); cookie_store = content::CreateCookieStore(cookie_config); cookie_store->GetCookieMonster()->SetPersistSessionCookies(true); - storage_->set_cookie_store(cookie_store); + storage_->set_cookie_store(cookie_store.get()); const char* schemes[] = {"http", "https", "file", "app"}; cookie_store->GetCookieMonster()->SetCookieableSchemes(schemes, 4); diff --git a/src/net/shell_url_request_context_getter.h b/src/net/shell_url_request_context_getter.h index 7419d27251..7b3fe867b3 100644 --- a/src/net/shell_url_request_context_getter.h +++ b/src/net/shell_url_request_context_getter.h @@ -64,16 +64,16 @@ class ShellBrowserContext; const std::string& gssapi_library_name); // net::URLRequestContextGetter implementation. - virtual net::URLRequestContext* GetURLRequestContext() OVERRIDE; + virtual net::URLRequestContext* GetURLRequestContext() override; virtual scoped_refptr - GetNetworkTaskRunner() const OVERRIDE; + GetNetworkTaskRunner() const override; net::HostResolver* host_resolver(); void SetAdditionalTrustAnchors(const net::CertificateList& trust_anchors); // net::CertTrustAnchorProvider implementation. - virtual const net::CertificateList& GetAdditionalTrustAnchors() OVERRIDE; + virtual const net::CertificateList& GetAdditionalTrustAnchors() override; protected: virtual ~ShellURLRequestContextGetter(); diff --git a/src/nw_package.cc b/src/nw_package.cc index 845f2a6868..670405d7d8 100644 --- a/src/nw_package.cc +++ b/src/nw_package.cc @@ -23,7 +23,7 @@ #include #include "base/command_line.h" -#include "base/file_util.h" +#include "base/files/file_util.h" #include "base/files/scoped_temp_dir.h" #include "base/json/json_file_value_serializer.h" #include "base/json/json_string_value_serializer.h" diff --git a/src/nw_protocol_handler.h b/src/nw_protocol_handler.h index 60439e3786..3ed2445cd1 100644 --- a/src/nw_protocol_handler.h +++ b/src/nw_protocol_handler.h @@ -39,7 +39,7 @@ class NwProtocolHandler : NwProtocolHandler(); virtual net::URLRequestJob* MaybeCreateJob( net::URLRequest* request, - net::NetworkDelegate* network_delegate) const OVERRIDE; + net::NetworkDelegate* network_delegate) const override; private: DISALLOW_COPY_AND_ASSIGN(NwProtocolHandler); diff --git a/src/nw_shell.cc b/src/nw_shell.cc index 5e23d0e4a4..baf827867d 100644 --- a/src/nw_shell.cc +++ b/src/nw_shell.cc @@ -27,12 +27,10 @@ #include "base/strings/utf_string_conversions.h" #include "base/values.h" #include "content/browser/child_process_security_policy_impl.h" -#include "content/browser/devtools/devtools_http_handler_impl.h" #include "content/browser/renderer_host/render_view_host_impl.h" #include "content/browser/web_contents/web_contents_impl.h" #include "content/public/browser/devtools_agent_host.h" #include "content/public/browser/devtools_http_handler.h" -#include "content/public/browser/devtools_manager.h" #include "content/public/browser/navigation_entry.h" #include "content/public/browser/navigation_controller.h" #include "content/public/browser/notification_details.h" @@ -51,7 +49,6 @@ #include "content/nw/src/browser/browser_dialogs.h" #include "content/nw/src/browser/file_select_helper.h" #include "content/nw/src/browser/native_window.h" -#include "content/nw/src/browser/shell_devtools_delegate.h" #include "content/nw/src/browser/shell_javascript_dialog_creator.h" #include "content/nw/src/browser/nw_autofill_client.h" #include "content/nw/src/common/shell_switches.h" @@ -61,6 +58,7 @@ #include "content/nw/src/shell_browser_main_parts.h" #include "content/nw/src/shell_content_browser_client.h" #include "content/nw/src/shell_devtools_frontend.h" +//#include "content/nw/src/browser/shell_devtools_delegate.h" #include "grit/nw_resources.h" #include "net/base/escape.h" @@ -77,11 +75,11 @@ using nw::NativeWindowAura; #endif -#include "content/nw/src/browser/printing/print_view_manager.h" +#include "chrome/browser/printing/print_view_manager_basic.h" +#include "extensions/common/extension_messages.h" using base::MessageLoop; -using content::DevToolsHttpHandlerImpl; namespace content { std::vector Shell::windows_; @@ -113,7 +111,7 @@ Shell* Shell::Create(BrowserContext* browser_context, Shell* shell = new Shell(web_contents, GetPackage()->window()); NavigationController::LoadURLParams params(url); - params.transition_type = PageTransitionFromInt(PAGE_TRANSITION_TYPED); + params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED); params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE; params.frame_name = std::string(); @@ -131,7 +129,7 @@ Shell* Shell::Create(WebContents* source_contents, if (!target_url.is_empty()) { NavigationController::LoadURLParams params(target_url); - params.transition_type = PageTransitionFromInt(PAGE_TRANSITION_TYPED); + params.transition_type = PageTransitionFromInt(ui::PAGE_TRANSITION_TYPED); params.override_user_agent = NavigationController::UA_OVERRIDE_TRUE; params.frame_name = std::string(); @@ -187,6 +185,8 @@ Shell::Shell(WebContents* web_contents, base::DictionaryValue* manifest) enable_nodejs_ = GetPackage()->GetUseNode(); VLOG(1) << "enable nodejs from manifest: " << enable_nodejs_; + extension_function_dispatcher_.reset( + new extensions::ExtensionFunctionDispatcher(web_contents->GetBrowserContext(), this)); // Add web contents. web_contents_.reset(web_contents); content::WebContentsObserver::Observe(web_contents); @@ -196,7 +196,7 @@ Shell::Shell(WebContents* web_contents, base::DictionaryValue* manifest) window_.reset(nw::NativeWindow::Create(weak_ptr_factory_.GetWeakPtr(), manifest)); #if defined(ENABLE_PRINTING) - printing::PrintViewManager::CreateForWebContents(web_contents); + printing::PrintViewManagerBasic::CreateForWebContents(web_contents); #endif // Initialize window after we set window_, because some operations of @@ -208,12 +208,14 @@ Shell::Shell(WebContents* web_contents, base::DictionaryValue* manifest) web_modal::WebContentsModalDialogManager::FromWebContents(web_contents)->SetDelegate(this); #endif +#if 0 autofill::NWAutofillClient::CreateForWebContents(web_contents); autofill::ContentAutofillDriver::CreateForWebContentsAndDelegate( web_contents, autofill::NWAutofillClient::FromWebContents(web_contents), "", autofill::AutofillManager::DISABLE_AUTOFILL_DOWNLOAD_MANAGER); +#endif //FIXME } Shell::~Shell() { @@ -335,8 +337,8 @@ void Shell::LoadURL(const GURL& url) { return; } NavigationController::LoadURLParams params(url); - params.transition_type = PageTransitionFromInt( - PAGE_TRANSITION_TYPED | PAGE_TRANSITION_FROM_ADDRESS_BAR); + params.transition_type = ui::PageTransitionFromInt( + ui::PAGE_TRANSITION_TYPED | ui::PAGE_TRANSITION_FROM_ADDRESS_BAR); web_contents_->GetController().LoadURLWithParams(params); // web_contents_->GetController().LoadURL( // url, @@ -429,19 +431,18 @@ void Shell::ShowDevTools(const char* jail_id, bool headless) { } scoped_refptr agent(DevToolsAgentHost::GetOrCreateFor(web_contents())); - DevToolsManager* manager = DevToolsManager::GetInstance(); if (agent->IsAttached()) { // Break remote debugging debugging session. - manager->CloseAllClientHosts(); + content::DevToolsAgentHost::DetachAllClients(); } - ShellDevToolsDelegate* delegate = - browser_client->shell_browser_main_parts()->devtools_delegate(); - GURL url = delegate->devtools_http_handler()->GetFrontendURL(agent.get()); - DevToolsHttpHandlerImpl* http_handler = static_cast(delegate->devtools_http_handler()); + DevToolsHttpHandler* http_handler = + browser_client->shell_browser_main_parts()->devtools_handler(); + GURL url = http_handler->GetFrontendURL(agent.get()); http_handler->EnumerateTargets(); +#if 0 if (headless) { DevToolsAgentHost* agent_host = DevToolsAgentHost::GetOrCreateFor(web_contents()).get(); @@ -451,7 +452,7 @@ void Shell::ShowDevTools(const char* jail_id, bool headless) { SendEvent("devtools-opened", url.spec()); return; } - +#endif SendEvent("devtools-opened", url.spec()); // Use our minimum set manifest base::DictionaryValue manifest; @@ -500,6 +501,7 @@ bool Shell::OnMessageReceived(const IPC::Message& message) { IPC_BEGIN_MESSAGE_MAP(Shell, message) IPC_MESSAGE_HANDLER(ShellViewHostMsg_UpdateDraggableRegions, UpdateDraggableRegions) + IPC_MESSAGE_HANDLER(ExtensionHostMsg_Request, OnRequest) IPC_MESSAGE_UNHANDLED(handled = false) IPC_END_MESSAGE_MAP() return handled; @@ -604,7 +606,7 @@ void Shell::WebContentsCreated(WebContents* source_contents, new nwapi::DispatcherHost(new_contents->GetRenderViewHost()); #if defined(ENABLE_PRINTING) - printing::PrintViewManager::CreateForWebContents(new_contents); + printing::PrintViewManagerBasic::CreateForWebContents(new_contents); #endif #if defined(OS_WIN) || defined(OS_LINUX) @@ -651,7 +653,7 @@ void Shell::DidNavigateMainFramePostCommit(WebContents* web_contents) { window()->SetToolbarUrlEntry(web_contents->GetURL().spec()); } -JavaScriptDialogManager* Shell::GetJavaScriptDialogManager() { +JavaScriptDialogManager* Shell::GetJavaScriptDialogManager(WebContents* source) { if (!dialog_creator_.get()) dialog_creator_.reset(new ShellJavaScriptDialogCreator()); return dialog_creator_.get(); @@ -680,10 +682,6 @@ void Shell::RequestMediaAccessPermission( WebContents* web_contents, const MediaStreamRequest& request, const MediaResponseCallback& callback) { - scoped_ptr - controller(new MediaStreamDevicesController(request, - callback)); - controller->DismissInfoBarAndTakeActionOnSettings(); } void Shell::Observe(int type, @@ -705,7 +703,7 @@ void Shell::Observe(int type, if (WIFEXITED(exit_code_)) exit_code_ = WEXITSTATUS(exit_code_); #endif - MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); + //MessageLoop::current()->PostTask(FROM_HERE, MessageLoop::QuitClosure()); } } @@ -750,4 +748,18 @@ void Shell::Cleanup() { } } +extensions::WindowController* Shell::GetExtensionWindowController() const { + return NULL; +} + +content::WebContents* Shell::GetAssociatedWebContents() const { + return web_contents_.get(); +} + +void Shell::OnRequest( + const ExtensionHostMsg_Request_Params& params) { + extension_function_dispatcher_->Dispatch( + params, web_contents_->GetRenderViewHost()); +} + } // namespace content diff --git a/src/nw_shell.h b/src/nw_shell.h index 2b75f2c35d..bad23f4187 100644 --- a/src/nw_shell.h +++ b/src/nw_shell.h @@ -35,6 +35,8 @@ #endif #include "ipc/ipc_channel.h" +#include "extensions/browser/extension_function_dispatcher.h" + namespace base { class DictionaryValue; class FilePath; @@ -42,6 +44,7 @@ class FilePath; namespace extensions { struct DraggableRegion; +class ExtensionFunctionDispatcher; } class GURL; @@ -68,6 +71,7 @@ class Shell : public WebContentsDelegate, public web_modal::WebContentsModalDialogManagerDelegate, #endif public content::WebContentsObserver, + public extensions::ExtensionFunctionDispatcher::Delegate, public NotificationObserver { public: enum ReloadType { @@ -140,81 +144,88 @@ class Shell : public WebContentsDelegate, void set_id(int id) { id_ = id; } int id() const { return id_; } - virtual void RenderViewCreated(RenderViewHost* render_view_host) OVERRIDE; + virtual void RenderViewCreated(RenderViewHost* render_view_host) override; #if defined(OS_WIN) || defined(OS_LINUX) - virtual void SetWebContentsBlocked(content::WebContents* web_contents, bool) OVERRIDE {} - virtual bool IsWebContentsVisible(content::WebContents* web_contents) OVERRIDE; - virtual web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost() OVERRIDE; + virtual void SetWebContentsBlocked(content::WebContents* web_contents, bool) override {} + virtual bool IsWebContentsVisible(content::WebContents* web_contents) override; + virtual web_modal::WebContentsModalDialogHost* GetWebContentsModalDialogHost() override; #endif protected: // content::WebContentsObserver implementation. - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) override; // content::WebContentsDelegate implementation. virtual WebContents* OpenURLFromTab(WebContents* source, - const OpenURLParams& params) OVERRIDE; + const OpenURLParams& params) override; virtual void LoadingStateChanged(WebContents* source, - bool to_different_document) 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; + bool to_different_document) 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, int source_frame_id, const base::string16& frame_name, const GURL& target_url, WebContents* new_contents, - const base::string16& nw_window_manifest) OVERRIDE; + const base::string16& nw_window_manifest) override; virtual void ToggleFullscreenModeForTab(WebContents* web_contents, - bool enter_fullscreen) OVERRIDE; + bool enter_fullscreen) override; virtual bool IsFullscreenForTabOrPending( - const WebContents* web_contents) const OVERRIDE; + const WebContents* web_contents) const override; #if defined(OS_WIN) || defined(OS_LINUX) - virtual void WebContentsFocused(WebContents* contents) OVERRIDE; + virtual void WebContentsFocused(WebContents* contents) override; #endif virtual content::ColorChooser* OpenColorChooser( content::WebContents* web_contents, SkColor color, - const std::vector& suggestions) OVERRIDE; + const std::vector& suggestions) override; virtual void RunFileChooser( content::WebContents* web_contents, - const content::FileChooserParams& params) OVERRIDE; + const content::FileChooserParams& params) override; virtual void EnumerateDirectory(content::WebContents* web_contents, int request_id, - const FilePath& path) OVERRIDE; + const FilePath& path) override; virtual void DidNavigateMainFramePostCommit( - WebContents* web_contents) OVERRIDE; - virtual JavaScriptDialogManager* GetJavaScriptDialogManager() OVERRIDE; + WebContents* web_contents) override; + virtual JavaScriptDialogManager* GetJavaScriptDialogManager(WebContents* source) override; virtual void RequestToLockMouse(WebContents* web_contents, bool user_gesture, - bool last_unlocked_by_target) OVERRIDE; + bool last_unlocked_by_target) override; virtual void HandleKeyboardEvent( WebContents* source, - const NativeWebKeyboardEvent& event) OVERRIDE; + const NativeWebKeyboardEvent& event) override; virtual bool AddMessageToConsole(WebContents* source, int32 level, const base::string16& message, int32 line_no, - const base::string16& source_id) OVERRIDE; + const base::string16& source_id) override; virtual void RequestMediaAccessPermission( WebContents* web_contents, const MediaStreamRequest& request, - const MediaResponseCallback& callback) OVERRIDE; + const MediaResponseCallback& callback) override; private: + // ExtensionFunctionDispatcher::Delegate + extensions::WindowController* GetExtensionWindowController() const override; + content::WebContents* GetAssociatedWebContents() const override; + + void OnRequest(const ExtensionHostMsg_Request_Params& params); + void UpdateDraggableRegions( const std::vector& regions); // NotificationObserver virtual void Observe(int type, const NotificationSource& source, - const NotificationDetails& details) OVERRIDE; + const NotificationDetails& details) override; scoped_ptr dialog_creator_; scoped_ptr web_contents_; scoped_ptr window_; + scoped_ptr extension_function_dispatcher_; // Notification manager. NotificationRegistrar registrar_; diff --git a/src/renderer/nw_render_view_observer.cc b/src/renderer/nw_render_view_observer.cc index 297de10d31..50c0b66877 100644 --- a/src/renderer/nw_render_view_observer.cc +++ b/src/renderer/nw_render_view_observer.cc @@ -22,7 +22,7 @@ #include -#include "base/file_util.h" +#include "base/files/file_util.h" #include "base/strings/utf_string_conversions.h" #include "content/nw/src/renderer/common/render_messages.h" #include "content/public/renderer/render_view.h" diff --git a/src/renderer/nw_render_view_observer.h b/src/renderer/nw_render_view_observer.h index 79a6002723..817b4fae5e 100644 --- a/src/renderer/nw_render_view_observer.h +++ b/src/renderer/nw_render_view_observer.h @@ -41,9 +41,9 @@ class NwRenderViewObserver : public content::RenderViewObserver { virtual ~NwRenderViewObserver(); // RenderViewObserver implementation. - virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE; - virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) OVERRIDE; - virtual void DidFinishDocumentLoad(blink::WebLocalFrame* frame) OVERRIDE; + virtual bool OnMessageReceived(const IPC::Message& message) override; + virtual void DidCreateDocumentElement(blink::WebLocalFrame* frame) override; + virtual void DidFinishDocumentLoad(blink::WebLocalFrame* frame) override; private: diff --git a/src/renderer/prerenderer/prerenderer_client.h b/src/renderer/prerenderer/prerenderer_client.h index 42ed0063b9..6ca52d6626 100644 --- a/src/renderer/prerenderer/prerenderer_client.h +++ b/src/renderer/prerenderer/prerenderer_client.h @@ -36,7 +36,7 @@ class PrerendererClient : public content::RenderViewObserver, virtual ~PrerendererClient(); // Implements blink::WebPrerendererClient - virtual void willAddPrerender(blink::WebPrerender* prerender) OVERRIDE; + virtual void willAddPrerender(blink::WebPrerender* prerender) override; }; } // namespace prerender diff --git a/src/renderer/printing/print_web_view_helper.cc b/src/renderer/printing/print_web_view_helper.cc index 8ebfa58af0..e0f4ade66f 100644 --- a/src/renderer/printing/print_web_view_helper.cc +++ b/src/renderer/printing/print_web_view_helper.cc @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#include "content/nw/src/renderer/printing/print_web_view_helper.h" +#include "chrome/renderer/printing/print_web_view_helper.h" #include @@ -12,50 +12,66 @@ #include "base/logging.h" #include "base/message_loop/message_loop.h" #include "base/metrics/histogram.h" -#include "base/strings/stringprintf.h" +#include "base/process/process_handle.h" #include "base/strings/string_number_conversions.h" +#include "base/strings/stringprintf.h" #include "base/strings/utf_string_conversions.h" -#include "content/public/common/web_preferences.h" #include "chrome/common/chrome_switches.h" -#include "content/nw/src/common/print_messages.h" +#include "chrome/common/print_messages.h" #include "chrome/common/render_messages.h" +#include "chrome/grit/browser_resources.h" #include "chrome/renderer/prerender/prerender_helper.h" +#include "content/public/common/web_preferences.h" +#include "content/public/renderer/render_frame.h" #include "content/public/renderer/render_thread.h" #include "content/public/renderer/render_view.h" -#include "grit/nw_resources.h" -//#include "grit/generated_resources.h" #include "net/base/escape.h" -#include "printing/metafile.h" -#include "printing/metafile_impl.h" +#include "printing/pdf_metafile_skia.h" #include "printing/units.h" -#include "skia/ext/vector_platform_device_skia.h" #include "third_party/WebKit/public/platform/WebSize.h" #include "third_party/WebKit/public/platform/WebURLRequest.h" #include "third_party/WebKit/public/web/WebConsoleMessage.h" #include "third_party/WebKit/public/web/WebDocument.h" #include "third_party/WebKit/public/web/WebElement.h" -#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebFrameClient.h" +#include "third_party/WebKit/public/web/WebLocalFrame.h" #include "third_party/WebKit/public/web/WebPlugin.h" #include "third_party/WebKit/public/web/WebPluginDocument.h" #include "third_party/WebKit/public/web/WebPrintParams.h" +#include "third_party/WebKit/public/web/WebPrintPresetOptions.h" #include "third_party/WebKit/public/web/WebPrintScalingOption.h" #include "third_party/WebKit/public/web/WebScriptSource.h" #include "third_party/WebKit/public/web/WebSettings.h" #include "third_party/WebKit/public/web/WebView.h" #include "third_party/WebKit/public/web/WebViewClient.h" -#include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" -using base::MessageLoop; +#if defined(ENABLE_EXTENSIONS) +#include "chrome/common/extensions/extension_constants.h" +#include "extensions/common/constants.h" +#endif // defined(ENABLE_EXTENSIONS) + using content::WebPreferences; namespace printing { namespace { +enum PrintPreviewHelperEvents { + PREVIEW_EVENT_REQUESTED, + PREVIEW_EVENT_CACHE_HIT, // Unused + PREVIEW_EVENT_CREATE_DOCUMENT, + PREVIEW_EVENT_NEW_SETTINGS, // Unused + PREVIEW_EVENT_MAX, +}; + const double kMinDpi = 1.0; +#if !defined(ENABLE_PRINT_PREVIEW) +bool g_is_preview_enabled_ = false; +#else +bool g_is_preview_enabled_ = true; + const char kPageLoadScriptFormat[] = "document.open(); document.write(%s); document.close();"; @@ -69,6 +85,7 @@ void ExecuteScript(blink::WebFrame* frame, std::string script = base::StringPrintf(script_format, json.c_str()); frame->executeScript(blink::WebString(base::UTF8ToUTF16(script))); } +#endif // !defined(ENABLE_PRINT_PREVIEW) int GetDPI(const PrintMsg_Print_Params* print_params) { #if defined(OS_MACOSX) @@ -84,10 +101,10 @@ bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params& params) { return !params.content_size.IsEmpty() && !params.page_size.IsEmpty() && !params.printable_area.IsEmpty() && params.document_cookie && params.desired_dpi && params.max_shrink && params.min_shrink && - params.dpi && (params.margin_top >= 0) && (params.margin_left >= 0); + params.dpi && (params.margin_top >= 0) && (params.margin_left >= 0) && + params.dpi > kMinDpi && params.document_cookie != 0; } - PrintMsg_Print_Params GetCssPrintParams( blink::WebFrame* frame, int page_index, @@ -272,14 +289,16 @@ void ComputeWebKitPrintParamsInDesiredDpi( print_params.desired_dpi); } +blink::WebPlugin* GetPlugin(const blink::WebFrame* frame) { + return frame->document().isPluginDocument() ? + frame->document().to().plugin() : NULL; +} + bool PrintingNodeOrPdfFrame(const blink::WebFrame* frame, const blink::WebNode& node) { if (!node.isNull()) return true; - if (!frame->document().isPluginDocument()) - return false; - blink::WebPlugin* plugin = - frame->document().to().plugin(); + blink::WebPlugin* plugin = GetPlugin(frame); return plugin && plugin->supportsPaginatedPrint(); } @@ -313,6 +332,41 @@ bool FitToPageEnabled(const base::DictionaryValue& job_settings) { return fit_to_paper_size; } +// Returns the print scaling option to retain/scale/crop the source page size +// to fit the printable area of the paper. +// +// We retain the source page size when the current destination printer is +// SAVE_AS_PDF. +// +// We crop the source page size to fit the printable area or we print only the +// left top page contents when +// (1) Source is PDF and the user has requested not to fit to printable area +// via |job_settings|. +// (2) Source is PDF. This is the first preview request and print scaling +// option is disabled for initiator renderer plugin. +// +// In all other cases, we scale the source page to fit the printable area. +blink::WebPrintScalingOption GetPrintScalingOption( + blink::WebFrame* frame, + const blink::WebNode& node, + bool source_is_html, + const base::DictionaryValue& job_settings, + const PrintMsg_Print_Params& params) { + if (params.print_to_pdf) + return blink::WebPrintScalingOptionSourceSize; + + if (!source_is_html) { + if (!FitToPageEnabled(job_settings)) + return blink::WebPrintScalingOptionNone; + + bool no_plugin_scaling = frame->isPrintScalingDisabledForPlugin(node); + + if (params.is_first_request && no_plugin_scaling) + return blink::WebPrintScalingOptionNone; + } + return blink::WebPrintScalingOptionFitToPrintableArea; +} + PrintMsg_Print_Params CalculatePrintParamsForCss( blink::WebFrame* frame, int page_index, @@ -356,38 +410,79 @@ PrintMsg_Print_Params CalculatePrintParamsForCss( return result_params; } -bool IsPrintPreviewEnabled() { - return CommandLine::ForCurrentProcess()->HasSwitch( - switches::kRendererPrintPreview); +// Return the PDF object element if |frame| is the out of process PDF extension. +blink::WebElement GetPdfElement(blink::WebLocalFrame* frame) { +#if 0 + GURL url = frame->document().url(); + if (url.SchemeIs(extensions::kExtensionScheme) && + url.host() == extension_misc::kPdfExtensionId) { + // with id="plugin" is created in + // chrome/browser/resources/pdf/pdf.js. + auto plugin_element = frame->document().getElementById("plugin"); + if (!plugin_element.isNull()) { + return plugin_element; + } + NOTREACHED(); + } +#endif // defined(ENABLE_EXTENSIONS) + return blink::WebElement(); } -bool IsPrintThrottlingDisabled() { - return CommandLine::ForCurrentProcess()->HasSwitch( - switches::kDisableScriptedPrintThrottling); +} // namespace + +FrameReference::FrameReference(blink::WebLocalFrame* frame) { + Reset(frame); } -} // namespace +FrameReference::FrameReference() { + Reset(NULL); +} + +FrameReference::~FrameReference() { +} + +void FrameReference::Reset(blink::WebLocalFrame* frame) { + if (frame) { + view_ = frame->view(); + frame_ = frame; + } else { + view_ = NULL; + frame_ = NULL; + } +} +blink::WebLocalFrame* FrameReference::GetFrame() { + if (view_ == NULL || frame_ == NULL) + return NULL; + for (blink::WebFrame* frame = view_->mainFrame(); frame != NULL; + frame = frame->traverseNext(false)) { + if (frame == frame_) + return frame_; + } + return NULL; +} + +blink::WebView* FrameReference::view() { + return view_; +} + +#if defined(ENABLE_PRINT_PREVIEW) // static - Not anonymous so that platform implementations can use it. void PrintWebViewHelper::PrintHeaderAndFooter( blink::WebCanvas* canvas, int page_number, int total_pages, + const blink::WebFrame& source_frame, float webkit_scale_factor, const PageSizeMargins& page_layout, - const base::DictionaryValue& header_footer_info, const PrintMsg_Print_Params& params) { - skia::VectorPlatformDeviceSkia* device = - static_cast(canvas->getTopDevice()); - device->setDrawingArea(SkPDFDevice::kMargin_DrawingArea); - SkAutoCanvasRestore auto_restore(canvas, true); canvas->scale(1 / webkit_scale_factor, 1 / webkit_scale_factor); blink::WebSize page_size(page_layout.margin_left + page_layout.margin_right + - page_layout.content_width, - page_layout.margin_top + page_layout.margin_bottom + - page_layout.content_height); + page_layout.content_width, + page_layout.margin_top + page_layout.margin_bottom + + page_layout.content_height); blink::WebView* web_view = blink::WebView::create(NULL); web_view->settings()->setJavaScriptEnabled(true); @@ -395,13 +490,14 @@ void PrintWebViewHelper::PrintHeaderAndFooter( blink::WebLocalFrame* frame = blink::WebLocalFrame::create(NULL); web_view->setMainFrame(frame); - base::StringValue html( - ResourceBundle::GetSharedInstance().GetLocalizedString( - IDR_PRINT_PREVIEW_PAGE)); + base::StringValue html(ResourceBundle::GetSharedInstance().GetLocalizedString( + IDR_PRINT_PREVIEW_PAGE)); // Load page with script to avoid async operations. ExecuteScript(frame, kPageLoadScriptFormat, html); - scoped_ptr options(header_footer_info.DeepCopy()); + scoped_ptr options(new base::DictionaryValue()); + options.reset(new base::DictionaryValue()); + options->SetDouble(kSettingHeaderFooterDate, base::Time::Now().ToJsTime()); options->SetDouble("width", page_size.width); options->SetDouble("height", page_size.height); options->SetDouble("topMargin", page_layout.margin_top); @@ -409,6 +505,12 @@ void PrintWebViewHelper::PrintHeaderAndFooter( options->SetString("pageNumber", base::StringPrintf("%d/%d", page_number, total_pages)); + // Fallback to initiator URL and title if it's empty for printed frame. + base::string16 url = source_frame.document().url().string(); + options->SetString("url", url.empty() ? params.url : url); + base::string16 title = source_frame.document().title(); + options->SetString("title", title.empty() ? params.title : title); + ExecuteScript(frame, kPageSetupScriptFormat, *options); blink::WebPrintParams webkit_params(page_size); @@ -419,9 +521,9 @@ void PrintWebViewHelper::PrintHeaderAndFooter( frame->printEnd(); web_view->close(); - - device->setDrawingArea(SkPDFDevice::kContent_DrawingArea); + frame->close(); } +#endif // defined(ENABLE_PRINT_PREVIEW) // static - Not anonymous so that platform implementations can use it. float PrintWebViewHelper::RenderPageContent(blink::WebFrame* frame, @@ -466,8 +568,8 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient, // Prepares frame for printing. void StartPrinting(); - blink::WebLocalFrame* frame() const { - return frame_; + blink::WebLocalFrame* frame() { + return frame_.GetFrame(); } const blink::WebNode& node() const { @@ -478,29 +580,36 @@ class PrepareFrameAndViewForPrint : public blink::WebViewClient, return expected_pages_count_; } - gfx::Size GetPrintCanvasSize() const; - void FinishPrinting(); - bool IsLoadingSelection() const { + bool IsLoadingSelection() { // It's not selection if not |owns_web_view_|. - return owns_web_view_ && frame_ && frame_->isLoading(); + return owns_web_view_ && frame() && frame()->isLoading(); } + // TODO(ojan): Remove this override and have this class use a non-null + // layerTreeView. + // blink::WebViewClient override: + virtual bool allowsBrokenNullLayerTreeView() const; + protected: // blink::WebViewClient override: virtual void didStopLoading(); - virtual void CallOnReady(); + // blink::WebFrameClient override: + virtual blink::WebFrame* createChildFrame(blink::WebLocalFrame* parent, + const blink::WebString& name); + virtual void frameDetached(blink::WebFrame* frame); private: + void CallOnReady(); void ResizeForPrinting(); void RestoreSize(); void CopySelection(const WebPreferences& preferences); base::WeakPtrFactory weak_ptr_factory_; - blink::WebLocalFrame* frame_; + FrameReference frame_; blink::WebNode node_to_print_; bool owns_web_view_; blink::WebPrintParams web_print_params_; @@ -530,15 +639,17 @@ PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint( is_printing_started_(false) { PrintMsg_Print_Params print_params = params; if (!should_print_selection_only_ || - !PrintingNodeOrPdfFrame(frame_, node_to_print_)) { + !PrintingNodeOrPdfFrame(frame, node_to_print_)) { bool fit_to_page = ignore_css_margins && print_params.print_scaling_option == blink::WebPrintScalingOptionFitToPrintableArea; - print_params = CalculatePrintParamsForCss(frame_, 0, print_params, + ComputeWebKitPrintParamsInDesiredDpi(params, &web_print_params_); + frame->printBegin(web_print_params_, node_to_print_); + print_params = CalculatePrintParamsForCss(frame, 0, print_params, ignore_css_margins, fit_to_page, NULL); + frame->printEnd(); } - ComputeWebKitPrintParamsInDesiredDpi(print_params, &web_print_params_); } @@ -557,11 +668,9 @@ void PrepareFrameAndViewForPrint::ResizeForPrinting() { print_layout_size.set_height( static_cast(static_cast(print_layout_size.height()) * 1.25)); - if (!frame_) + if (!frame()) return; - - blink::WebView* web_view = frame_->view(); - + blink::WebView* web_view = frame_.view(); // Backup size and offset. if (blink::WebFrame* web_frame = web_view->mainFrame()) prev_scroll_offset_ = web_frame->scrollOffset(); @@ -573,11 +682,10 @@ void PrepareFrameAndViewForPrint::ResizeForPrinting() { void PrepareFrameAndViewForPrint::StartPrinting() { ResizeForPrinting(); - blink::WebView* web_view = frame_->view(); + blink::WebView* web_view = frame_.view(); web_view->settings()->setShouldPrintBackgrounds(should_print_backgrounds_); - // TODO(vitalybuka): Update call after - // https://bugs.webkit.org/show_bug.cgi?id=107718 is fixed. - expected_pages_count_ = frame_->printBegin(web_print_params_, node_to_print_); + expected_pages_count_ = + frame()->printBegin(web_print_params_, node_to_print_); is_printing_started_ = true; } @@ -585,10 +693,12 @@ void PrepareFrameAndViewForPrint::CopySelectionIfNeeded( const WebPreferences& preferences, const base::Closure& on_ready) { on_ready_ = on_ready; - if (should_print_selection_only_) + if (should_print_selection_only_) { CopySelection(preferences); - else - didStopLoading(); + } else { + // Call immediately, async call crashes scripting printing. + CallOnReady(); + } } void PrepareFrameAndViewForPrint::CopySelection( @@ -609,35 +719,49 @@ void PrepareFrameAndViewForPrint::CopySelection( owns_web_view_ = true; content::RenderView::ApplyWebPreferences(prefs, web_view); web_view->setMainFrame(blink::WebLocalFrame::create(this)); - frame_ = web_view->mainFrame()->toWebLocalFrame(); + frame_.Reset(web_view->mainFrame()->toWebLocalFrame()); node_to_print_.reset(); // When loading is done this will call didStopLoading() and that will do the // actual printing. - frame_->loadRequest(blink::WebURLRequest(GURL(url_str))); + frame()->loadRequest(blink::WebURLRequest(GURL(url_str))); +} + +bool PrepareFrameAndViewForPrint::allowsBrokenNullLayerTreeView() const { + return true; } void PrepareFrameAndViewForPrint::didStopLoading() { DCHECK(!on_ready_.is_null()); // Don't call callback here, because it can delete |this| and WebView that is // called didStopLoading. - MessageLoop::current()->PostTask(FROM_HERE, + base::MessageLoop::current()->PostTask( + FROM_HERE, base::Bind(&PrepareFrameAndViewForPrint::CallOnReady, weak_ptr_factory_.GetWeakPtr())); } -void PrepareFrameAndViewForPrint::CallOnReady() { - return on_ready_.Run(); // Can delete |this|. +blink::WebFrame* PrepareFrameAndViewForPrint::createChildFrame( + blink::WebLocalFrame* parent, + const blink::WebString& name) { + blink::WebFrame* frame = blink::WebLocalFrame::create(this); + parent->appendChild(frame); + return frame; +} + +void PrepareFrameAndViewForPrint::frameDetached(blink::WebFrame* frame) { + if (frame->parent()) + frame->parent()->removeChild(frame); + frame->close(); } -gfx::Size PrepareFrameAndViewForPrint::GetPrintCanvasSize() const { - return gfx::Size(web_print_params_.printContentArea.width, - web_print_params_.printContentArea.height); +void PrepareFrameAndViewForPrint::CallOnReady() { + return on_ready_.Run(); // Can delete |this|. } void PrepareFrameAndViewForPrint::RestoreSize() { - if (frame_) { - blink::WebView* web_view = frame_->view(); + if (frame()) { + blink::WebView* web_view = frame_.GetFrame()->view(); web_view->resize(prev_view_size_); if (blink::WebFrame* web_frame = web_view->mainFrame()) web_frame->setScrollOffset(prev_scroll_offset_); @@ -645,23 +769,24 @@ void PrepareFrameAndViewForPrint::RestoreSize() { } void PrepareFrameAndViewForPrint::FinishPrinting() { - if (frame_) { - blink::WebView* web_view = frame_->view(); + blink::WebLocalFrame* frame = frame_.GetFrame(); + if (frame) { + blink::WebView* web_view = frame->view(); if (is_printing_started_) { is_printing_started_ = false; - frame_->printEnd(); + frame->printEnd(); if (!owns_web_view_) { web_view->settings()->setShouldPrintBackgrounds(false); RestoreSize(); } } if (owns_web_view_) { - DCHECK(!frame_->isLoading()); + DCHECK(!frame->isLoading()); owns_web_view_ = false; web_view->close(); } } - frame_ = NULL; + frame_.Reset(NULL); on_ready_.Reset(); } @@ -669,11 +794,8 @@ PrintWebViewHelper::PrintWebViewHelper(content::RenderView* render_view) : content::RenderViewObserver(render_view), content::RenderViewObserverTracker(render_view), reset_prep_frame_view_(false), - is_preview_enabled_(IsPrintPreviewEnabled()), - is_scripted_print_throttling_disabled_(IsPrintThrottlingDisabled()), is_print_ready_metafile_sent_(false), ignore_css_margins_(false), - user_cancelled_scripted_print_count_(0), is_scripted_printing_blocked_(false), notify_browser_of_print_failure_(true), print_for_preview_(false), @@ -681,23 +803,43 @@ PrintWebViewHelper::PrintWebViewHelper(content::RenderView* render_view) is_loading_(false), is_scripted_preview_delayed_(false), weak_ptr_factory_(this) { + if (CommandLine::ForCurrentProcess()->HasSwitch( + switches::kDisablePrintPreview)) { + DisablePreview(); + } } PrintWebViewHelper::~PrintWebViewHelper() {} +// static +void PrintWebViewHelper::DisablePreview() { + g_is_preview_enabled_ = false; +} + bool PrintWebViewHelper::IsScriptInitiatedPrintAllowed( blink::WebFrame* frame, bool user_initiated) { - if (is_scripted_printing_blocked_) - return false; +#if defined(OS_ANDROID) + return false; +#endif // defined(OS_ANDROID) // If preview is enabled, then the print dialog is tab modal, and the user // can always close the tab on a mis-behaving page (the system print dialog // is app modal). If the print was initiated through user action, don't // throttle. Or, if the command line flag to skip throttling has been set. - if (!is_scripted_print_throttling_disabled_ && - !is_preview_enabled_ && - !user_initiated) - return !IsScriptInitiatedPrintTooFrequent(frame); - return true; + return !is_scripted_printing_blocked_ && + (user_initiated || g_is_preview_enabled_ || + scripting_throttler_.IsAllowed(frame)); +} + +void PrintWebViewHelper::DidStartLoading() { + is_loading_ = true; +} + +void PrintWebViewHelper::DidStopLoading() { + is_loading_ = false; + if (!on_stop_loading_closure_.is_null()) { + on_stop_loading_closure_.Run(); + on_stop_loading_closure_.Reset(); + } } // Prints |frame| which called window.print(). @@ -705,29 +847,36 @@ void PrintWebViewHelper::PrintPage(blink::WebLocalFrame* frame, bool user_initiated) { DCHECK(frame); +#if 0 + // Allow Prerendering to cancel this print request if necessary. + if (prerender::PrerenderHelper::IsPrerendering( + render_view()->GetMainRenderFrame())) { + Send(new ChromeViewHostMsg_CancelPrerenderForPrinting(routing_id())); + return; + } +#endif if (!IsScriptInitiatedPrintAllowed(frame, user_initiated)) return; - IncrementScriptedPrintCount(); - if (is_preview_enabled_) { + if (!g_is_preview_enabled_) { + Print(frame, blink::WebNode()); + } else { print_preview_context_.InitWithFrame(frame); RequestPrintPreview(PRINT_PREVIEW_SCRIPTED); - } else { - Print(frame, blink::WebNode()); } } bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) { bool handled = true; IPC_BEGIN_MESSAGE_MAP(PrintWebViewHelper, message) +#if defined(ENABLE_BASIC_PRINTING) IPC_MESSAGE_HANDLER(PrintMsg_PrintPages, OnPrintPages) IPC_MESSAGE_HANDLER(PrintMsg_PrintForSystemDialog, OnPrintForSystemDialog) +#endif // ENABLE_BASIC_PRINTING IPC_MESSAGE_HANDLER(PrintMsg_InitiatePrintPreview, OnInitiatePrintPreview) IPC_MESSAGE_HANDLER(PrintMsg_PrintPreview, OnPrintPreview) IPC_MESSAGE_HANDLER(PrintMsg_PrintForPrintPreview, OnPrintForPrintPreview) IPC_MESSAGE_HANDLER(PrintMsg_PrintingDone, OnPrintingDone) - IPC_MESSAGE_HANDLER(PrintMsg_ResetScriptedPrintCount, - ResetScriptedPrintCount) IPC_MESSAGE_HANDLER(PrintMsg_SetScriptedPrintingBlocked, SetScriptedPrintBlocked) IPC_MESSAGE_UNHANDLED(handled = false) @@ -736,8 +885,7 @@ bool PrintWebViewHelper::OnMessageReceived(const IPC::Message& message) { } void PrintWebViewHelper::OnPrintForPrintPreview( - const base::DictionaryValue& job_settings) { - DCHECK(is_preview_enabled_); + const base::DictionaryValue& job_settings) { // If still not finished with earlier print request simply ignore. if (prep_frame_view_) return; @@ -749,7 +897,7 @@ void PrintWebViewHelper::OnPrintForPrintPreview( return; blink::WebDocument document = main_frame->document(); - // with id="pdf-viewer" is created in + // /

                      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%0D^>FLq&x8QvtOL(9hU_X1$oFhB_NB#U;j|e)P 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%0A5%m_PO*V84?fv&&Duq6nw{Lpti^Twxo|kNT1Q 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 S2?iX6O(SjR}|-qqqr?Y=#6DQ9+SxzU+mS zft_f&Wt)Oy#jS6YZqB)OYkPOSUVG=$MT{|C^4uR!e&6r&d49j=i_tU&|NbZyom2i$ z(Tl~K*41Wbn>2mjI)~kp(=X{*O+FV-SQJHZqq4|9f{elawZCP*vH8fpG2h)0Wx_M6 zctURFy|&kuR_0I*Uv|GU+kWHm!I8ThrfTK({nHQ=X~Z0#LoIh+MAkMHY`P# z(1}S%Awfn=sVL|h_yK0-!Vrz|@YUr{m*MeNNy!4c%?5f_tq2Jbya5gbE^8I} zbbYm4WYvMmtcS=_9O9e^TOTfjva&U*$;r_2s7p%oanw!trl(t(o99st4{Dtj?%eTV zL~fqt((7*>+s+GVG|mL@$eq@**v698TcXiOVng9NTivee0|SFDL)D{?VWpc2uu1O> zc&Geu>HLKr^bE0M9iM*uW^wU)SVRO#Q3NR^1BphbrA0`m0A$d@??G4k#&8JRv7;Vu zefPNQ$7?_JAh>n{{U*XOeosx^Q+g?#h74*FQAm;qi;F1`5E&hdj{DM?HsGZ_ey09MZc&vRg2RfwmB z2=w*epyxs}XVAza_;MbobZ2yKw)D4&+cwKeYL=pDz%xP}0|9?fIn(i3RFW0cA09@= z16+Ss?=u3=doo(`eyE%dhp(}z(KL3`A2#NULP>D}Xc!$hdIy8fD~{TGKHujw!;)i8 zXA`2n`oC%XJK7d>{PT>#c<}*i{#7-jdj%!Wfc8~r;s34wOMn3Y*EgJK6ii?p00000 LNkvXXu0mjfnWFNZ literal 0 HcmV?d00001 diff --git a/tests/automation/nw-in-mem/package/icon-32.png b/tests/automation/nw-in-mem/package/icon-32.png new file mode 100644 index 0000000000000000000000000000000000000000..02edf8c2b4d07fd8eeaae2fb1f1e31eb2c46426c GIT binary patch literal 2967 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 N002ovPDHLkV1g8}tnB~* literal 0 HcmV?d00001 diff --git a/tests/automation/nw-in-mem/package/index.html b/tests/automation/nw-in-mem/package/index.html new file mode 100644 index 0000000000..ea89fa8452 --- /dev/null +++ b/tests/automation/nw-in-mem/package/index.html @@ -0,0 +1,107 @@ + + + + + + Veille + + + + + + + + + + + + + + +

                      D^HT2-oL=l2Bvnn&%(647*mu+6~#B~9=l<{ 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
                      $M3PO=Zr^t3K-&76MK_fFprJMGjoqV}Y(Kji}RCxNN6-EHtu((hvVH@6x% zIw??cy)1c~#_C9F^1UU5g&h_Up+taOOMDE^tHamwjTNE$E3Cei1RS>oHmo%_iYdQC zQ*2aUjg7R=>S1?On#W)RpxW8+tuj+YiF61^K304IRN%(s8YZF#YDu@p&u)uawQK83 zqeYC<+xe&++vk9diL(I0En5< zhs6d4)G-k*FYocTrW{?P0cbyb?pPekbX4)Y(chG(N7Kt_DneaZ5h3cyFLiG zotJy7Nw%H%9_SLqrX@&Y*sb@Ept^MGGlcWU?d8X$!$(-9#yrZNyHR>wQL?ywySh2A|1X7Wr(ttu_Z{}`?l6Ddh zly+oGp4~H4vP@PRv42Gt^#x9nNrY1 zo2SoA3BWd}U0yg$?aNSa_D~xS21L8@^H7R>4(5^eOs~O&Vn!((N8f7_pvACWn~7Vp?JN$+HEj56R}Sj zubbpExxK0b?A(O$(XXL<_WE~vdI7&2dJ^=22-&>uO%fvxa$&)^k}O5PVH>DSyN5ol zrHp!E+Tg&Jvcs0`uZ={YMH;;>KDdBdy#aS{RR7jtu|Djk zh%G5N@CKRqQ@-opAb9HP!>>u9okjir3wBCR1lNk1{}pV?qs3}#bf)RgDa6cLoZJ53 zb2MLfsLm<`Gti$wKVK@AsZSzwc4QJf+_2((@-B5O|63kGAk$rKDcF7cd6U|~#csl} zICd4^D=eL%L$6jp=`O6?@!t`*kQR114JebmpRK%Z|D5f&;jf03!J(0Y=X7yV8Fc|; zc6F970+)w(*g;(2sVPfx@}otYK{fAFr#J9VOS`5Eez)s!~6sRQkusIMONPrOC-_4W2j@ z89q7;BCPse-zHmAPOJJgrC+5=l7{WIg>4?@Sp-XZmbLNrOsW6>5%twkQN7>S&&<#* zO1Dyi0@BSWs30mR0-~g}A`BrN11eaQh;&J}f^-d_bP3WmbO_9lL(hBl^Zl*&uEk#i zcP-95an3&b>>a8zF(Yv_?a8SsjP-*&LZYjKQ!h8L9o>EL^1Lvh$62aDW6coxClNIk zltFbGH_Ux{PKWKnoadwecx|+hR!%MbHtCy~w-sB>g~9BvJ*HC|8O z)TK?B@R5hmWq?+6@;P1P@J_~VJN`C5XO>!_-K@SHEc|e>W5~~K{i2XDe!ixttKiP- z_F+ANX`6{Z;a&F~-8Ja-gY}e-WzSQ^Id~P7rSk`81My@cKA_YcvF)C+2<1vCQz4gV zl#Y7B{Enpd>RtV=Vx*CXx`sSHtZ;910zU(CXWV=__@Fl6BFqrY!sUV8uU#)Yx4Aj#4SNqfb^$&DqO8bBON)yic?+pNE$qNOQF~YL z$-EJ_rARuxaFMj?dA`w^04S1Z9sm$BG}uWsTI?R9p3e+pUu9|w3^nxriPafCP7&?D zeGsH?`HiJhlq2P`85zK{C7X6z8O~q#MJ8-fzR{_gnajA zf=UunA1*z#p>S}O6KsAX*2Ee=m;Ljs9`{j!&3c7eJ>k!Y>a!O5{a+uKS5e=8?0x?J z`kS%b$)g{{JMuz?j?%3a`DcD6p#q`5Xea=WbBFWryNv!ONU zRM<39h`b-`$DBjbcRyb5sXF~_aQ`FFFA}JJ)aO4?9=qGfuks;krZ;D;4E_@!)SXnm z{?Vt5PwWh*r~4LM>vR24z@kvdRARy0q>{DB6B}jW6EnIV zP(^MxUvQSYNsIl^x`(Gl4NnI(jL2(s2zVYex!Yv~D>oY$t93&FXk`B>*I>%5!j1fX zPJ>OS?_ug@qxyDn?ukbGe+!M;-kK!pQF(`Sok?PEtZaq)B1S&vDu%2SUTdoyN&v5dFL&@1aFN%pE8c2o zZEjr{A%|Oi^kNAzgkKNY6XoS)-{3EpoO0m6*N@Av503a=mwsOG`|*p0NB6n~^6zwg zwQ`PRveG#}KNH|la0dzZts_8;8vf}*X&_mH>O}U7ohmGI7_n3`En z?50>QrE+9GwDOY*Q>w)?-R_GpABz-f@6~u!-}m;bNxI+qFAJ=Pfsru$!H6mJJ@`{j z$b#W>*xQi3w=`D6V&b1byi42>UfMBB@wWYIJWH~h}u=q4K?~Z2V)HC=1 ztpr9%IbfwxDV%V+l^EX4L`R^+w+|xF9*`RyK-+MWfkgPk-z7>9HUIq|sZ`>gT(*8N zx{eQSU;TLUG)yEtZ^gZXS(Negzx7V$ccDIDCkD_r9kr{&3tW${hrE1@u)P{8#GBIa z3`UMz)Ut{@EP(PJ=4SC;BpMT0!1K_)q#u@|DD`jg+Dcd5O(3E5VG*%COsvExaFMRjo0X`7sCwhy4@Md zXAeYET?fjt-FEXwdY2}654FX-Un5*hV1*f6z3$zOt3iB@9V*I(xRsqEr|AtZ81 z6VO#YJtM1a(@we(Ji zhvLq1VwKXUjM&3wyP(xV-1Soa}~$&&wmi4 zB@hF5AoB){`nCi;W`_o-)MC^T81mi#f77IjG#)#1GKkui)Lfhh=}zo9+h5v#`1~Mc zi`M#n$G}IXe-Orgfuot&kEH!(FG77;etx#kj(bY+_bkCwl|50GqUYF3H@ETM((due%FK&CrG|-RH5YG% z#KiTOJ=f}n_Z?G{f)YO+*Uh$eLiM5*yeN3`bs7YB zAB-u~SuU1QdCSvr)Q%aRR*PrlI%n2o-}M+Sb47R5x(981ppLz=G>&i^_-bUk6)b|k z=;xTsL|zkfvNM}BNAp7L>GL=&V~TfQfNY2l9#{}^^f#NAxxR#s~jfMTG2`K_`-dWyCYn7N*#6-~P zW3KT{6NE7fmJ|(P&fHL2EZm(w-TJ3<9k1x3&+I2t8*F>SxokDi^Q<2#wQJ|E;`w4vV+|NCKUTI4$EPv?UJ(u z*<*c->N7eoaH5#h2s_3GY{E}Z_90I-M)bbdy}nFg5nWv8&0BC}ui?QpcE#AXqf+nT zB!DalcmX15YIXgGnK9JyMP|l;x1Ya1nZ;H~{o0t13+Jz&diTR$kqAGe1{A5kH+VLD z=Ypx|FuuoG)$Ae`h%iS+y7xlUa!4Cn!J`Dw_kg*qY&Gg9j@T<3HG@_tZ;r{W7x(ri z>|osdH%z>27b1juF_x_CfJ`;HMsXJH`r4INMaGZ@vE#ZVGFAfzBBF)*Lt_K#^x#3$ z+vYd556P@x*f99isL49ywp#w(L0;1kw2DJ7HQCuf*#ZnP1UpnC{5&5@z;)HZe6I&-e;KqQNP>XY??N=(Sqs~n<2Y#%kP-FM!6huU+7#cPVKa=z!qkp9V#=A!Tr=xXT z{22UB7L~-glO$VP*!3oi@&E$1&qbx}NV{`tBx`j0LDx?+1mHquO$?|1q?X1==o$eP zYil%F5k5JNo?c0-NC6=Y+Iq|b))I7zVm3xz^&v|mNFJ;^0yedS4wC!=^(;c|+b;NTVKzw)`IcPPiPhFk5)@|9~J4fF?#Y%$zKDl3dtv z^|eQzkS;@)7CGkbGa4D%|B@>_h)hu@;oUe3x`qS4bTiy_454-{A3r}Da_S4ieQiZ6 z(++2Rs$=z3haDF$h*tcWNAeORK`_-&ovWE4we8sel}1MojbEjMQL+`wqhGZIK3}|Z zm7o~4Lv9s6Z657W ztEC1Sfrotv;L*Rp+m2bd6FxG4My(DPPrWks5sjvaPGTKc|r3W zi3oDjYL#f*-e_D+45!qC`!|m~4tTB$$s7EKwL@sbVe1Q3V@}~)iOw%V5vkGdpRncq z-<~CVGkgJXiy=T_NN7aG)q;ws3rlDDsC>O$EwdS*^kHZYzCNDwBK!qpR?m|6vtZYZ zD)k0+1maQrm`_WiJNLCOc@J#OuCFGn(kOKdxQxEN_&TeDx5V~`3l2p)`#wKCD*HL& z)6!rx^Mj5N-~CVwH;f6^lxXcpS{s1pnn)(AJhB3^o#PM@-9#jJl$6!Ro|O|A_FTJ$ zzQRq1`SCcW?3IQFf>;K4+r_B7HEk8)iKxt;lIguUJV+I3$aA|oi&0T+m=0M9Jv`Jt z9-RAKQ1htO8BN|AGs9(jZJ?`58ZQQc27XvCI!_*ya)>qxPlx)eC2@eWS8EC`e484n zxZoe{#KP$CpPwgGGkF>WG#`cXkS$BG1j+@jzp@RLPF1@eIr!y2>7N(ng(bEicB1j zCXaGHhc{HN4j6BpJDpMc?kN7dx45CcI`-IkcGE;C#gPM4Zo zG=*k7_0i9#jaK?K;C2S++H+ID^PqGL@VXT_6Ufj2fkD?8v)m)`K$pzi?z%di^!7mq zTTZV%5DEQ!@LiRGA6)yo8*L6Bl2|(NAEw0I>Ae;6K6e#TRRqbWOHZD|r9(dx(Z!5W z(LU&wuR@llLhnY>z9|V6~*?N>@WC9$!lT1x;{452o^^mw%-e z(zgraTl5J*G+otfdG>pT^~l$4_tVuE$~P@}=L)Yjn6%XpLTJ*nydy!Q-VgGFIG;!r zpr_1um+q(}YocLn+Ob|Fz?m4Pzha^&z<)aM+wwT2pw&2Cnika{h@Mcpan}N9lwg^ z%84FmoXNCZ@jMNd8Q(q&B)*rVT4G$C#MaXTi*lCE(f84!isG}fVawSoD~msQ_Fwf> z`>>~GlV`ClCnsAZFTIZAhAeu_<2Pb#wwqMToHDS#+kN;2n zgcf2?tm|wzqVvg)*_?RUzSx{8{2Y;bj-MBLFEB$+-J$FwN(!dn;s+ zKw3KD`b^>0KG$^kC`YU*Zz?u0aF^x7i2vzBdC3p@hF0b{&eR%SzA(Pl2U1$?$z?Fb z)KWtx#ki>}hld|wzn?t6I=VSE9KeDB83UBHhE7YftFZ1JKUzRjNwbs7_Vibh43a=2 z-3)fz)T;Dw;YOg{*)R|8o2Zx*Wjjb4?0t zsV)5O0>NBu{4X($0N$71dMW*naYgO>lL7t^W7m7;X!c08VF)Z&0?X---+ENOWu*1% z-y(&&8~n#Uq30e^?}f$zxj#P^Ge_SOgQt80w*3-|{f50`K8byrzZfg#;W7+{@Qp^c!3cy)lYKBd)0nCND69ZGnHC04z)>d*u3hs!2IA zuKS)=bb1E7{y?SBLp12}bf6^&G*H{m_l#eby`BGWl0yEl*~1^Q89o&QT!_jI;5dD+ zi5x2kWai7mtYe?%Sn~coMSyQLlVysvEarIR>cn+>GwLcM#{wn0p(0Z_U=_`PtC>AC zP@ym2sL~)a%|P}QGL?|q-F#-Z5$2q^-@<|5MjPX>9$9bnF3|5QPjZCP0xBd$^g0O} zT7s2z$7(D`ocpMp;=6_DTIc zay%XeNNLh*5k0>j`w)&DIOrpcg|wsJkQDHLwa+Ow8<4nU=CT4Snu;BZ3x%O=N{Zq~ zIq~xJD6F~fvza<+C*4N-USGdu0 z&4abQlrws}B2@7t*W&(E?DxY0JABl{$jt=YPVB|Oxp#uah8ID71czwD`4L}CxvzEj z^Q8{q!#U?>dtN4i?=~q_{HAk<98({Qm^W*-^UV3I9`X`PCIO!*Pzjj}U@+tatH$-S z*Lj;7Z@!jPAr=8RZ%JCiOp!g!)!w~t{@UggZ6wL3U5@5X@DXf2b53YU#za81|z=Y+aniI#OECNf@v6Q$ec1jtt8Gh9zbF` zo*}OLqM*_@c~nKRSg`ux-MRX}ra#g`?&m(^~0IGJ*m| z7PCV3$3U-E*;St2d_>z0pacC|xWZa}ls!4I6EAf
                      Z@SIucwK-Q(T}E}8RGg>(4u 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

                      Ny_uUR#1>1wS=O!!da$%+s$@69+ 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

                      N^)b@^@jw4$W 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

                      ub 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

                      8182 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

                      W&@s`rA6Hs5l(ftLSS9((4%~#Ql+G8e5IG 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