From b249ee20d5c1e68115de0239f78e0cf791e98052 Mon Sep 17 00:00:00 2001 From: Michael Scholz Date: Thu, 2 May 2013 20:37:07 +0200 Subject: [PATCH] web mining addon aufgabe --- .../Uebungen/1_Uebung/keaddon/bootstrap.js | 152 ++ .../1_Uebung/keaddon/components/harness.js | 678 ++++++++ .../1_Uebung/keaddon/harness-options.json | 1546 +++++++++++++++++ .../Uebungen/1_Uebung/keaddon/icon.png | Bin 0 -> 674 bytes .../Uebungen/1_Uebung/keaddon/install.rdf | 35 + .../moz_favicon.ico | Bin 0 -> 1406 bytes .../test-page-worker.html | 8 + .../test-page-worker.js | 27 + .../test.html | 8 + .../clipboard.js | 248 +++ .../context-menu.js | 1162 +++++++++++++ .../notifications.js | 110 ++ .../page-mod.js | 198 +++ .../page-worker.js | 97 ++ .../panel.js | 358 ++++ .../passwords.js | 82 + .../private-browsing.js | 94 + .../request.js | 299 ++++ .../selection.js | 353 ++++ .../simple-storage.js | 258 +++ .../tabs.js | 62 + .../widget.js | 656 +++++++ .../windows.js | 236 +++ .../bootstrap-remote-process.js | 212 +++ .../test-content-symbiont.js | 0 .../api-utils.js | 184 ++ .../app-strings.js | 93 + .../byte-streams.js | 133 ++ .../collection.js | 139 ++ .../content.js | 44 + .../content/loader.js | 198 +++ .../content/symbiont.js | 174 ++ .../content/worker.js | 376 ++++ .../cortex.js | 139 ++ .../cuddlefish.js | 267 +++ .../e10s.js | 243 +++ .../errors.js | 90 + .../es5.js | 587 +++++++ .../events.js | 196 +++ .../file.js | 213 +++ .../find-tests-e10s-adapter.js | 110 ++ .../find-tests.js | 1 + .../hidden-frame.js | 198 +++ .../light-traits.js | 626 +++++++ .../list.js | 147 ++ .../match-pattern.js | 102 ++ .../memory.js | 144 ++ .../observer-service.js | 209 +++ .../passwords/utils.js | 134 ++ .../plain-text-console.js | 112 ++ .../preferences-service.js | 137 ++ .../securable-module.js | 630 +++++++ .../self-e10s-adapter.js | 95 + .../self.js | 59 + .../tab-browser.js | 761 ++++++++ .../tabs/events.js | 56 + .../tabs/tab.js | 296 ++++ .../test.js | 126 ++ .../test/assert.js | 360 ++++ .../text-streams.js | 271 +++ .../timer-e10s-adapter.js | 73 + .../timer.js | 139 ++ .../traceback.js | 153 ++ .../traits.js | 215 +++ .../traits/core.js | 337 ++++ .../type.js | 372 ++++ .../unit-test-finder.js | 112 ++ .../unit-test.js | 276 +++ .../unload.js | 49 + .../url-e10s-adapter.js | 91 + .../url.js | 121 ++ .../utils/data.js | 104 ++ .../utils/function.js | 64 + .../utils/registry.js | 90 + .../utils/thumbnail.js | 76 + .../window-utils.js | 176 ++ .../windows/dom.js | 60 + .../windows/loader.js | 151 ++ .../windows/tabs.js | 202 +++ .../xhr.js | 179 ++ .../xpcom.js | 217 +++ .../xul-app.js | 91 + .../contentScripts/keworker.js | 26 + .../flag/Flag_of_France.svg | 3 + .../flag/Flag_of_Germany.svg | 8 + .../flag/Flag_of_Spain.svg | 631 +++++++ .../flag/Flag_of_the_United_Kingdom.svg | 10 + .../flag/de.png | Bin 0 -> 760 bytes .../flag/en.png | Bin 0 -> 2467 bytes .../flag/es.png | Bin 0 -> 10142 bytes .../flag/fr.png | Bin 0 -> 835 bytes .../keicon.png | Bin 0 -> 674 bytes .../language.js | 4 + .../main.js | 65 + .../student.js | 54 + .../utility.js | 13 + .../test-main.js | 83 + .../1_Uebung/keaddonWithHeuristic.xpi | Bin 0 -> 293933 bytes 98 files changed, 18774 insertions(+) create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/bootstrap.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/components/harness.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/harness-options.json create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/icon.png create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/install.rdf create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/moz_favicon.ico create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test-page-worker.html create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test-page-worker.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test.html create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/clipboard.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/context-menu.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/notifications.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-mod.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-worker.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/panel.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/passwords.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/private-browsing.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/request.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/selection.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/simple-storage.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/tabs.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/widget.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/windows.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-data/bootstrap-remote-process.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-data/test-content-symbiont.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/app-strings.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/byte-streams.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/collection.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/loader.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/symbiont.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/worker.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cortex.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cuddlefish.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/e10s.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/es5.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests-e10s-adapter.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/hidden-frame.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/light-traits.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/list.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/match-pattern.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/memory.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/observer-service.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/passwords/utils.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/plain-text-console.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/preferences-service.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/securable-module.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self-e10s-adapter.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tab-browser.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/events.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/tab.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test/assert.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/text-streams.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer-e10s-adapter.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traceback.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits/core.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/type.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test-finder.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url-e10s-adapter.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/data.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/function.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/registry.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/thumbnail.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/window-utils.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/dom.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/loader.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/tabs.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xhr.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/contentScripts/keworker.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_France.svg create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_Germany.svg create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_Spain.svg create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_the_United_Kingdom.svg create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/de.png create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/en.png create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/es.png create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/fr.png create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/keicon.png create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/language.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/main.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/student.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/utility.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-tests/test-main.js create mode 100644 ss2013/1_Web Mining/Uebungen/1_Uebung/keaddonWithHeuristic.xpi diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/bootstrap.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/bootstrap.js new file mode 100644 index 00000000..f04ef28b --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/bootstrap.js @@ -0,0 +1,152 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Weave. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Mills + * Atul Varma + * Drew Willcoxon + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// For more information on the context in which this script is executed, see: +// https://developer.mozilla.org/en/Extensions/Bootstrapped_extensions + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; +const Cr = Components.results; + +// Object containing information about the XPCOM harness service +// that manages our addon. + +var gHarness; + +var ios = Cc['@mozilla.org/network/io-service;1'] + .getService(Ci.nsIIOService); + +var manager = Components.manager.QueryInterface(Ci.nsIComponentRegistrar); + +// Dynamically evaluate and initialize the XPCOM component in +// components/harness.js, which bootstraps our addon. (We want to keep +// components/harness.js around so that versions of Gecko that don't +// support rebootless addons can still work.) + +function setupHarness(installPath, loadReason) { + var harnessJs = installPath.clone(); + harnessJs.append("components"); + harnessJs.append("harness.js"); + var path = ios.newFileURI(harnessJs).spec; + var harness = {}; + var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader); + loader.loadSubScript(path, harness); + + var HarnessService = harness.buildHarnessService(installPath); + var factory = HarnessService.prototype._xpcom_factory; + var proto = HarnessService.prototype; + + // We want to keep this factory around for the lifetime of + // the addon so legacy code with access to Components can + // access the addon if needed. + manager.registerFactory(proto.classID, + proto.classDescription, + proto.contractID, + factory); + + var harnessService = factory.createInstance(null, Ci.nsISupports); + harnessService = harnessService.wrappedJSObject; + + gHarness = { + service: harnessService, + classID: proto.classID, + contractID: proto.contractID, + factory: factory + }; + + if (loadReason == "startup") + // Simulate a startup event; the harness service will take care of + // waiting until the app is ready for the extension's code to run. + harnessService.observe(null, "profile-after-change", null); + else + harnessService.load(loadReason); +} + +function reasonToString(reason) { + // If you change these names, change them in harness.js's lifeCycleObserver192 + // too. + switch (reason) { + case ADDON_INSTALL: + return "install"; + case ADDON_UNINSTALL: + return "uninstall"; + case ADDON_ENABLE: + return "enable"; + case ADDON_DISABLE: + return "disable"; + case ADDON_UPGRADE: + return "upgrade"; + case ADDON_DOWNGRADE: + return "downgrade"; + // The startup and shutdown strings are also used outside of + // lifeCycleObserver192. + case APP_STARTUP: + return "startup"; + case APP_SHUTDOWN: + return "shutdown"; + } + return undefined; +} + +function install(data, reason) { + // We shouldn't start up here; startup() will always be called when + // an extension should load, and install() sometimes gets called when + // an extension has been installed but is disabled. +} + +function startup(data, reason) { + if (!gHarness) + setupHarness(data.installPath, reasonToString(reason)); +} + +function shutdown(data, reason) { + if (gHarness) { + var harness = gHarness; + gHarness = undefined; + harness.service.unload(reasonToString(reason)); + manager.unregisterFactory(harness.classID, harness.factory); + } +} + +function uninstall(data, reason) { + // We shouldn't shutdown here; shutdown() will always be called when + // an extension should shutdown, and uninstall() sometimes gets + // called when startup() has never been called before it. +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/components/harness.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/components/harness.js new file mode 100644 index 00000000..086f329f --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/components/harness.js @@ -0,0 +1,678 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Weave. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dan Mills + * Atul Varma + * Drew Willcoxon + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// This file contains an XPCOM component which "bootstraps" a Jetpack +// program. +// +// The main entry point, `NSGetModule()`, is data-driven, and obtains +// a lot of its configuration information from either the +// `HARNESS_OPTIONS` environment variable (if present) or a JSON file +// called `harness-options.json` in the root directory of the extension +// or application it's a part of. +// +// `NSGetModule()` then uses this configuration information to +// dynamically create an XPCOM component called a "Harness Service", +// which is responsible for setting up and shutting down the Jetpack +// program's CommonJS environment. It's also the main mechanism through +// which other parts of the application can communicate with the Jetpack +// program. +// +// If we're on Gecko 1.9.3, which supports rebootless extensions, the +// bootstrap.js file actually evaluates this file and calls parts of +// it automatically. +// +// It should be noted that a lot of what's done by the Harness Service is +// very similar to what's normally done by a `chrome.manifest` file: the +// difference here is that everything the Harness Service does is +// undoable during the lifetime of the application. This is the +// foundation of what makes it possible for Jetpack-based extensions +// to be installed and uninstalled without needing to reboot the +// application being extended. + +const Cc = Components.classes; +const Ci = Components.interfaces; +const Cu = Components.utils; + +Cu.import("resource://gre/modules/XPCOMUtils.jsm"); + +const obSvc = Cc["@mozilla.org/observer-service;1"] + .getService(Ci.nsIObserverService); + +const ioSvc = Cc["@mozilla.org/network/io-service;1"] + .getService(Ci.nsIIOService); + +const FIREFOX_ID = "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"; +const THUNDERBIRD_ID = "{3550f703-e582-4d05-9a08-453d09bdfdc6}"; +const FENNEC_ID = "{a23983c0-fd0e-11dc-95ff-0800200c9a66}"; + +// This function builds and returns a Harness Service XPCOM component. +// +// Parameters: +// +// rootFileSpec - nsILocalFile corresponding to root of extension +// (required). +// +// dump - function to output string to console (required). +// +// logError - function to log an exception (required). +// +// onQuit - function called when the app quits (required). +// +// options - JSON configuration information passed in from the +// environment (required). + +function buildHarnessService(rootFileSpec, dump, logError, + onQuit, options) { + if (arguments.length == 1) { + ({dump, logError, onQuit, options}) = getDefaults(rootFileSpec); + } + + // The loader for securable modules, typically a Cuddlefish loader. + var loader; + + // Singleton Harness Service. + var harnessService; + + // Whether we've initialized or not yet. + var isStarted; + + // Whether we've been asked to quit or not yet. + var isQuitting; + + // The Jetpack program's main module. + var program; + + var ioService = Cc["@mozilla.org/network/io-service;1"] + .getService(Ci.nsIIOService); + var resProt = ioService.getProtocolHandler("resource") + .QueryInterface(Ci.nsIResProtocolHandler); + + function quit(status) { + if (status === undefined) + status = "OK"; + if (status != "OK" && status != "FAIL") { + dump("Warning: quit() expected 'OK' or 'FAIL' as an " + + "argument, but got '" + status + "' instead."); + status = "FAIL"; + } + + if (isQuitting) + return; + + isQuitting = true; + + if (harnessService) + harnessService.unload(); + + onQuit(status); + } + + function logErrorAndBail(e) { + logError(e); + quit("FAIL"); + } + + function ensureIsDir(dir) { + if (!(dir.exists() && dir.isDirectory)) + throw new Error("directory not found: " + dir.path); + } + + function getDir(path) { + var dir = Cc['@mozilla.org/file/local;1'] + .createInstance(Ci.nsILocalFile); + dir.initWithPath(path); + ensureIsDir(dir); + return dir; + } + + function buildLoader() { + // TODO: This variable doesn't seem to be used, we should + // be able to remove it. + var compMgr = Components.manager; + compMgr = compMgr.QueryInterface(Ci.nsIComponentRegistrar); + + for (name in options.resources) { + var path = options.resources[name]; + var dir; + if (typeof(path) == "string") + dir = getDir(path); + else { + dir = rootFileSpec.clone(); + path.forEach(function(part) { dir.append(part); }); + ensureIsDir(dir); + } + var dirUri = ioService.newFileURI(dir); + resProt.setSubstitution(name, dirUri); + } + + var jsm = {}; + Cu.import(options.loader, jsm); + var packaging = new Packaging(); + var loader = new jsm.Loader({rootPaths: options.rootPaths.slice(), + print: dump, + packaging: packaging, + globals: { packaging: packaging } + }); + packaging.__setLoader(loader); + return loader; + } + + // This will be exposed as the 'packaging' global to all + // modules loaded within our loader. + + function Packaging() { + this.__packages = options.manifest; + } + + Packaging.prototype = { + __setLoader: function setLoader(loader) { + this.__loader = loader; + }, + + get root() { + return rootFileSpec.clone(); + }, + + get harnessService() { + return harnessService; + }, + + get buildHarnessService() { + return buildHarnessService; + }, + + get options() { + return options; + }, + + enableE10s: options.enable_e10s, + + jetpackID: options.jetpackID, + + bundleID: options.bundleID, + + getModuleInfo: function getModuleInfo(path) { + var i = this.__packages[path]; + var info = { dependencies: i.requires, + needsChrome: i.chrome, + 'e10s-adapter': i['e10s-adapter'], + name: i.name, + packageName: i.packageName, + hash: i.hash + }; + if (info.packageName in options.packageData) + info.packageData = options.packageData[info.packageName]; + return info; + }, + + // TODO: This has been superseded by require('self').getURL() and + // should be deprecated. + getURLForData: function getURLForData(path) { + var traceback = this.__loader.require("traceback"); + var callerInfo = traceback.get().slice(-2)[0]; + var info = this.getModuleInfo(callerInfo.filename); + if ('packageData' in info) { + var url = this.__loader.require("url"); + return url.URL(path, info.packageData).toString(); + } else + throw new Error("No data for package " + pkgName); + }, + + createLoader: function createLoader() { + return buildLoader(); + } + }; + + // Singleton XPCOM component that is responsible for instantiating + // a Cuddlefish loader and running the main program, if any. + + function HarnessService() { + this.wrappedJSObject = this; + } + + HarnessService.prototype = { + get classDescription() { + // This needs to be unique, lest we regress bug 554489. + return "Harness Service for " + options.bootstrap.contractID; + }, + + get contractID() { return options.bootstrap.contractID; }, + + get classID() { return Components.ID(options.bootstrap.classID); }, + + _xpcom_categories: [{ category: "profile-after-change" }], + + _xpcom_factory: { + get singleton() { + return harnessService; + }, + + createInstance: function(outer, iid) { + if (outer) + throw Cr.NS_ERROR_NO_AGGREGATION; + if (!harnessService) + harnessService = new HarnessService(); + return harnessService.QueryInterface(iid); + } + }, + + QueryInterface: XPCOMUtils.generateQI([Ci.nsIObserver, + Ci.nsISupportsWeakReference]), + + get loader() { + if (!loader) + loader = buildLoader(); + return loader; + }, + + get options() { + return options; + }, + + load: function Harness_load(reason) { + if (isStarted) + return; + + isStarted = true; + obSvc.addObserver(this, "quit-application-granted", true); + if (options.main) { + try { + + if (reason) + options.loadReason = reason; + program = this.loader.require(options.main); + if ('main' in program) + program.main(options, {quit: quit, print: dump}); + + // Send application readiness notification + const APP_READY_TOPIC = options.jetpackID + "_APPLICATION_READY"; + obSvc.notifyObservers(null, APP_READY_TOPIC, null); + + } catch (e) { + this.loader.console.exception(e); + quit("FAIL"); + } + } + }, + + unload: function Harness_unload(reason) { + if (!isStarted) + return; + + isStarted = false; + harnessService = null; + + obSvc.removeObserver(this, "quit-application-granted"); + + lifeCycleObserver192.unload(); + + // Notify the program of unload. + if (program) { + if (typeof(program.onUnload) === "function") { + try { + program.onUnload(reason); + } + catch (err) { + if (loader) + loader.console.exception(err); + } + } + program = null; + } + + // Notify the loader of unload. + if (loader) { + loader.unload(reason); + loader = null; + } + + for (name in options.resources) + resProt.setSubstitution(name, null); + }, + + observe: function Harness_observe(subject, topic, data) { + try { + switch (topic) { + case "profile-after-change": + var appInfo = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULAppInfo); + switch (appInfo.ID) { + case THUNDERBIRD_ID: + case FENNEC_ID: + obSvc.addObserver(this, "xul-window-visible", true); + break; + case FIREFOX_ID: + obSvc.addObserver(this, "sessionstore-windows-restored", true); + break; + default: + obSvc.addObserver(this, "final-ui-startup", true); + break; + } + lifeCycleObserver192.init(options.bundleID, logError); + break; + case "final-ui-startup": // XULRunner + case "sessionstore-windows-restored": // Firefox + case "xul-window-visible": // Thunderbird, Fennec + obSvc.removeObserver(this, topic); + this.load(lifeCycleObserver192.loadReason || "startup"); + break; + case "quit-application-granted": + this.unload(lifeCycleObserver192.unloadReason || "shutdown"); + quit("OK"); + break; + } + } catch (e) { + logErrorAndBail(e); + } + } + }; + + var factory = HarnessService.prototype._xpcom_factory; + if (!factory.wrappedJSObject) + factory.wrappedJSObject = factory; + + return HarnessService; +} + +// This is an error logger of last resort; if we're here, then +// we weren't able to initialize Cuddlefish and display a nice +// traceback through it. + +function defaultLogError(e, print) { + if (!print) + print = dump; + + print(e + " (" + e.fileName + ":" + e.lineNumber + ")\n"); + if (e.stack) + print("stack:\n" + e.stack + "\n"); +} + +// Builds an onQuit() function that writes a result file if necessary +// and does some other extra things to enhance developer ergonomics. + +function buildDevQuit(options, dump) { + // Absolute path to a file that we put our result code in. Ordinarily + // we'd just exit the process with a zero or nonzero return code, but + // there doesn't appear to be a way to do this in XULRunner. + var resultFile = options.resultFile; + + // Whether we've written resultFile or not. + var fileWritten = false; + + function attemptQuit() { + var appStartup = Cc['@mozilla.org/toolkit/app-startup;1']. + getService(Ci.nsIAppStartup); + appStartup.quit(Ci.nsIAppStartup.eAttemptQuit); + } + + return function onQuit(result) { + dump(result + "\n"); + + function writeResult() { + if (!fileWritten) + try { + var file = Cc["@mozilla.org/file/local;1"] + .createInstance(Ci.nsILocalFile); + file.initWithPath(resultFile); + + var foStream = Cc["@mozilla.org/network/file-output-stream;1"] + .createInstance(Ci.nsIFileOutputStream); + foStream.init(file, -1, -1, 0); + foStream.write(result, result.length); + foStream.close(); + fileWritten = true; + } catch (e) { + dump(e + "\n"); + } + } + + writeResult(); + attemptQuit(); + }; +} + +function buildForsakenConsoleDump(dump) { + var buffer = ""; + var cService = Cc['@mozilla.org/consoleservice;1'].getService() + .QueryInterface(Ci.nsIConsoleService); + + function stringify(arg) { + try { + return String(arg); + } + catch(ex) { + return ""; + } + } + + return function forsakenConsoleDump(msg) { + // No harm in calling dump() just in case the + // end-user *can* see the console... + dump(msg); + + msg = stringify(msg); + if (msg.indexOf('\n') >= 0) { + cService.logStringMessage(buffer + msg); + buffer = ""; + } else { + buffer += msg; + } + }; +} + +function getDefaults(rootFileSpec) { + // Default options to pass back. + var options; + + try { + var environ = Cc["@mozilla.org/process/environment;1"] + .getService(Ci.nsIEnvironment); + + var jsonData; + if (environ.exists("HARNESS_OPTIONS")) + jsonData = environ.get("HARNESS_OPTIONS"); + else { + var optionsFile = rootFileSpec.clone(); + optionsFile.append('harness-options.json'); + if (optionsFile.exists()) { + var fiStream = Cc['@mozilla.org/network/file-input-stream;1'] + .createInstance(Ci.nsIFileInputStream); + var siStream = Cc['@mozilla.org/scriptableinputstream;1'] + .createInstance(Ci.nsIScriptableInputStream); + fiStream.init(optionsFile, 1, 0, false); + siStream.init(fiStream); + var data = new String(); + data += siStream.read(-1); + siStream.close(); + fiStream.close(); + jsonData = data; + } else + throw new Error("HARNESS_OPTIONS env var must exist."); + } + + options = JSON.parse(jsonData); + } catch (e) { + defaultLogError(e); + throw e; + } + + var onQuit = function() {}; + var doDump = dump; + + if ('resultFile' in options) + onQuit = buildDevQuit(options, print); + else + // If we're not being run by cfx or some other kind of tool that is + // ensuring dump() calls are visible, we'll have to log to the + // forsaken Error Console. + doDump = buildForsakenConsoleDump(doDump); + + var logFile; + var logStream; + + if ('logFile' in options) { + logFile = Cc["@mozilla.org/file/local;1"] + .createInstance(Ci.nsILocalFile); + logFile.initWithPath(options.logFile); + + logStream = Cc["@mozilla.org/network/file-output-stream;1"] + .createInstance(Ci.nsIFileOutputStream); + logStream.init(logFile, -1, -1, 0); + } + + function print(msg) { + doDump(msg); + if (logStream && typeof(msg) == "string") { + logStream.write(msg, msg.length); + logStream.flush(); + } + } + + function logError(e) { + defaultLogError(e, print); + } + + return {options: options, onQuit: onQuit, dump: print, + logError: logError}; +} + +// Gecko 2, entry point for non-bootstrapped extensions (which register this +// component via chrome.manifest.) +// FIXME: no install/uninstall notifications on 2.0 for non-bootstrapped addons +function NSGetFactory(cid) { + try { + if (!NSGetFactory.fn) { + var rootFileSpec = __LOCATION__.parent.parent; + var HarnessService = buildHarnessService(rootFileSpec); + NSGetFactory.fn = XPCOMUtils.generateNSGetFactory([HarnessService]); + } + } catch(e) { + Components.utils.reportError(e); + dump(e); + throw e; + } + return NSGetFactory.fn(cid); +} + +// Everything below is only used on Gecko 1.9.2 or below. + +function NSGetModule(compMgr, fileSpec) { + var rootFileSpec = fileSpec.parent.parent; + var HarnessService = buildHarnessService(rootFileSpec); + return XPCOMUtils.generateModule([HarnessService]); +} + +// Program life-cycle events originate in bootstrap.js on 1.9.3. But 1.9.2 +// doesn't use bootstrap.js, so we need to do a little extra work there to +// determine the reasons for app startup and shutdown. That's what this +// singleton is for. On 1.9.3 all methods are no-ops. +var lifeCycleObserver192 = { + get loadReason() { + if (this._inited) { + // If you change these names, change them in bootstrap.js too. + if (this._addonIsNew) + return "install"; + return "startup"; + } + return undefined; + }, + + get unloadReason() { + if (this._inited) { + // If you change these names, change them in bootstrap.js too. + switch (this._emState) { + case "item-uninstalled": + return "uninstall"; + case "item-disabled": + return "disable"; + } + return "shutdown"; + } + return undefined; + }, + + // This must be called first to initialize the singleton. It must be called + // on profile-after-change. + init: function lifeCycleObserver192_init(bundleID, logError) { + // This component is present in 1.9.2 but not 2.0. + if ("@mozilla.org/extensions/manager;1" in Cc && !this._inited) { + obSvc.addObserver(this, "em-action-requested", true); + this._bundleID = bundleID; + this._logError = logError; + this._inited = true; + + try { + // This throws if the pref doesn't exist, which is the case when no + // new add-ons were installed. + var addonIdStr = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefBranch). + getCharPref("extensions.newAddons"); + } + catch (err) {} + if (addonIdStr) { + var addonIds = addonIdStr.split(","); + this._addonIsNew = addonIds.indexOf(this._bundleID) >= 0; + } + } + }, + + unload: function lifeCycleObserver192_unload() { + if (this._inited && !this._unloaded) { + obSvc.removeObserver(this, "em-action-requested"); + delete this._logError; + this._unloaded = true; + } + }, + + observe: function lifeCycleObserver192_observe(subj, topic, data) { + try { + if (topic === "em-action-requested") { + if (subj instanceof Ci.nsIUpdateItem && subj.id === this._bundleID) + this._emState = data; + } + } + catch (err) { + this._logError(err); + } + }, + + QueryInterface: XPCOMUtils.generateQI([ + Ci.nsIObserver, + Ci.nsISupportsWeakReference, + ]) +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/harness-options.json b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/harness-options.json new file mode 100644 index 00000000..82185a30 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/harness-options.json @@ -0,0 +1,1546 @@ +{ + "bootstrap": { + "classID": "{f8303718-cc14-491a-9cb0-136bae928869}", + "contractID": "@mozilla.org/harness-service;1?id=jid0-GN3ivO79cgfs9k4P3lxdo7TPFa4" + }, + "bundleID": "jid0-GN3ivO79cgfs9k4P3lxdo7TPFa4@jetpack", + "enable_e10s": false, + "jetpackID": "jid0-GN3ivO79cgfs9k4P3lxdo7TPFa4", + "loader": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cuddlefish.js", + "main": "main", + "manifest": { + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/clipboard.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "32e367d215cd8b0f64b40e2ef75c354bff070d210402b76d8bb8fc643cafa602", + "name": "clipboard", + "packageName": "addon-kit", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "errors": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/clipboard.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/context-menu.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "d94ba2656230f30a3bbe8e8f98ae1245fa06354b2987be5fd16c7546bbf1178f", + "name": "context-menu", + "packageName": "addon-kit", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "collection": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/collection.js" + }, + "content": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content.js" + }, + "match-pattern": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/match-pattern.js" + }, + "preferences-service": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/preferences-service.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "url": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js" + }, + "window-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/window-utils.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/context-menu.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/notifications.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "f2cf98492973a48a690d7f3a2faedf6277b71d0ffe3a822842889890c69f62d0", + "name": "notifications", + "packageName": "addon-kit", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "errors": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/notifications.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-mod.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "a2b9d05d83fbf97a9faaa3085590057ea59ac232fcde5714cb6ea2c3f167bc44", + "name": "page-mod", + "packageName": "addon-kit", + "requires": { + "content": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content.js" + }, + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "list": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/list.js" + }, + "match-pattern": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/match-pattern.js" + }, + "observer-service": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/observer-service.js" + }, + "utils/registry": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/registry.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-mod.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-worker.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "717f5962e59ca0c4cf4aefd39fa9fc707646362ce396c0cfd879ac2cd751fa1c", + "name": "page-worker", + "packageName": "addon-kit", + "requires": { + "content": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content.js" + }, + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-worker.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/panel.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "6363508cfd7fbf1603c13e935550f21d352719166c029376e0a0862c1ae3c894", + "name": "panel", + "packageName": "addon-kit", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "content": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content.js" + }, + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "xpcom": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/panel.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/passwords.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "961e296634110085838120a7349d7b5d4bd8c3b20e86c72fa703d7553d4b6fc3", + "name": "passwords", + "packageName": "addon-kit", + "requires": { + "light-traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/light-traits.js" + }, + "passwords/utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/passwords/utils.js" + }, + "utils/function": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/function.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/passwords.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/private-browsing.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "917ff8e567f3e8f34babf4749feaa81bbaffa4355251d2659ff38fb21b6c5a32", + "name": "private-browsing", + "packageName": "addon-kit", + "requires": { + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "observer-service": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/observer-service.js" + }, + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/private-browsing.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/request.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "e0b23d6bee5416e9df61b8d1780cdae174a51dc63b3a2831aecc046096f7a135", + "name": "request", + "packageName": "addon-kit", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "errors": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js" + }, + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "xhr": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xhr.js" + }, + "xpcom": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/request.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/selection.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "c9933aeb3613bff5c04bc1eef0cf059883534a808286536f7a47bfce4600111d", + "name": "selection", + "packageName": "addon-kit", + "requires": { + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "tab-browser": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tab-browser.js" + }, + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "xpcom": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/selection.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/simple-storage.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "9df61d6315421b32be95e396879229c8d0b968901c6bebdd79f97f50d7b1da4b", + "name": "simple-storage", + "packageName": "addon-kit", + "requires": { + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "file": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js" + }, + "preferences-service": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/preferences-service.js" + }, + "self": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js" + }, + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/simple-storage.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/tabs.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "2bae0d4c19770be1e73d87a2303cb395f6378bb59fa944324c3427599ac01543", + "name": "tabs", + "packageName": "addon-kit", + "requires": { + "windows": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/windows.js" + }, + "windows/tabs": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/tabs.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/tabs.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/widget.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "3e31bef66e56ccb0088698bce6cf63ac2c613e3c0e2e1b7413001f7bbff3c007", + "name": "widget", + "packageName": "addon-kit", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "content": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content.js" + }, + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "panel": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/panel.js" + }, + "self": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js" + }, + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "window-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/window-utils.js" + }, + "xpcom": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/widget.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/windows.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "a5864932e0c54695c9df8003a079d19dcee0dcfc1388b1629e67b7b0ff690960", + "name": "windows", + "packageName": "addon-kit", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "list": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/list.js" + }, + "tabs/tab": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/tab.js" + }, + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "window-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/window-utils.js" + }, + "windows/dom": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/dom.js" + }, + "windows/loader": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/loader.js" + }, + "windows/tabs": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/tabs.js" + }, + "xpcom": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/windows.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "a5afc1236d022272bd80a6b4b4dda55f606d4ddbd678cc245a95236642c32c77", + "name": "api-utils", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/app-strings.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "af30f57b0b38cc2cb32be69137d0a2d39fba0739222e2af43150fe756fcd537d", + "name": "app-strings", + "packageName": "api-utils", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/app-strings.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/byte-streams.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "c84fa1e69d76534a48c01be775821ee4cf646c44c3c70b76774427ae87e1f358", + "name": "byte-streams", + "packageName": "api-utils", + "requires": { + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/byte-streams.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/collection.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "422060b69ac06c2f17b3b210641f890c7242561e08c5144fb8f6971f4f5f6903", + "name": "collection", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/collection.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "9e250d23b61f987920af698c10be725aafefc741caa0120311018223cbd99f95", + "name": "content", + "packageName": "api-utils", + "requires": { + "content/loader": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/loader.js" + }, + "content/symbiont": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/symbiont.js" + }, + "content/worker": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/worker.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/loader.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "4587833e017b469ecec61dc339ff14839e739dd509ae4fb7c4a1d5f52d29d66f", + "name": "content/loader", + "packageName": "api-utils", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "file": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js" + }, + "url": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/loader.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/symbiont.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "3e06cb87bf3755e4772b92cd8cb831fd1bfa9551ede57c4d53a207379fe4a2aa", + "name": "content/symbiont", + "packageName": "api-utils", + "requires": { + "./loader": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/loader.js" + }, + "./worker": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/worker.js" + }, + "hidden-frame": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/hidden-frame.js" + }, + "observer-service": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/observer-service.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/symbiont.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/worker.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "84381ed00e07b919100778656cba30d180aa742d7aab20b2af5d1b1165d016ef", + "name": "content/worker", + "packageName": "api-utils", + "requires": { + "cuddlefish": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cuddlefish.js" + }, + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "file": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js" + }, + "tabs/tab": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/tab.js" + }, + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "url": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/worker.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cortex.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "c0f1cd0975149d431c45b674ff88119d8c69d265cf7c9ffe6e8e7076397b27c5", + "name": "cortex", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cortex.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cuddlefish.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "ee62eeb0270f45de89fc7481c7f7374bad28728eebc243a6ad0ca6bab93037fb", + "name": "cuddlefish", + "packageName": "api-utils", + "requires": { + "e10s": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/e10s.js" + }, + "memory": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/memory.js" + }, + "plain-text-console": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/plain-text-console.js" + }, + "securable-module": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/securable-module.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cuddlefish.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/e10s.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "a38f1bb2b20725fce989ee6ff06be0a17243913bc2c0761fc627b2cc9f3fb557", + "name": "e10s", + "packageName": "api-utils", + "requires": { + "cuddlefish": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cuddlefish.js" + }, + "errors": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js" + }, + "file": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js" + }, + "parent-loader": {}, + "self": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js" + }, + "traceback": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traceback.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "url": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/e10s.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "73e305e41752c451f01a93703c5ce38d6f18efe639d7307148caf99e8decfea0", + "name": "errors", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/es5.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "245c7302ea14bf0c2d87c629662701fd3312a3d83c6e396a7cb65f7a3b11bd22", + "name": "es5", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/es5.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "761f5ed76ce06ddc4bec267b0a225c32aa2f67ff63ddacd5883ed652f0e646c0", + "name": "events", + "packageName": "api-utils", + "requires": { + "light-traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/light-traits.js" + }, + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "843f37d5008cda06764f1ded60ae1bc290fe0684791964ae5c89e7e17edb99a2", + "name": "file", + "packageName": "api-utils", + "requires": { + "byte-streams": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/byte-streams.js" + }, + "text-streams": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/text-streams.js" + }, + "xpcom": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests-e10s-adapter.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "a986a1663580ef3fcd121d87f636d87c69ed37b4345da40d136cc8fb06d31a5f", + "name": "find-tests-e10s-adapter", + "packageName": "api-utils", + "requires": { + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "unit-test": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests-e10s-adapter.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests.js": { + "chrome": false, + "e10s-adapter": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests-e10s-adapter.js", + "hash": "39483cb19b93ce82a99434c94d82ca0d852f994d4a41d5ce6df6b446c0ad8426", + "name": "find-tests", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/hidden-frame.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "84d23d836193f98e5f6e0db78d4fee33d97c04b1a7799b8f3ec48a83f5392cc6", + "name": "hidden-frame", + "packageName": "api-utils", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "collection": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/collection.js" + }, + "errors": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js" + }, + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/hidden-frame.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/light-traits.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "eb07416982e7ccfb3dee68efd256c0dd09a04d65f34cbdab90b88f0874af00c4", + "name": "light-traits", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/light-traits.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/list.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "ebbdc29aee0774e96833f548cb587c7a61754ba66c3a27f993933323556ffec4", + "name": "list", + "packageName": "api-utils", + "requires": { + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/list.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/match-pattern.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "987de1cb34bb0409caab66c0c584d1abdf243b1798c56f70a4c1537c7071a4f9", + "name": "match-pattern", + "packageName": "api-utils", + "requires": { + "url": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/match-pattern.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/memory.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "86fa63a9b8597b3d79eee674b1d4c71462a61019a143681bb2b7e00d17462e65", + "name": "memory", + "packageName": "api-utils", + "requires": { + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/memory.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/observer-service.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "8ba7c79769994139a4d386fa188e596951f9de10bee009fb153d3a035927116d", + "name": "observer-service", + "packageName": "api-utils", + "requires": { + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "xpcom": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/observer-service.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/passwords/utils.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "a16a234992e20c8837c9315ef6d403f4adb4363e12dedcda5bf97ebe1e73fd9c", + "name": "passwords/utils", + "packageName": "api-utils", + "requires": { + "self": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js" + }, + "url": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/passwords/utils.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/plain-text-console.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "c962983d9259f0f68ae83d427f47e00c1349a0cc116ac8bf48842176795febe8", + "name": "plain-text-console", + "packageName": "api-utils", + "requires": { + "traceback": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traceback.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/plain-text-console.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/preferences-service.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "17caf4bb572a892e2dbd08ad3ccb90d61a9355e955e709f55bdff3181c90d2e9", + "name": "preferences-service", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/preferences-service.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/securable-module.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "cb9d85ebc358dc85751dfba11e6c529cf7adc2162f5b1cb5ff512998ecad96dc", + "name": "securable-module", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/securable-module.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self-e10s-adapter.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "bd1e29595c1e7f733e1d33ee6c80fc4476ae50dacd6c2c9e7d10ce529f447fba", + "name": "self-e10s-adapter", + "packageName": "api-utils", + "requires": { + "file": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js" + }, + "traceback": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traceback.js" + }, + "url": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self-e10s-adapter.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js": { + "chrome": false, + "e10s-adapter": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self-e10s-adapter.js", + "hash": "74b5e2d52427aa129f2ae8c4d6c3a31f773c2441c8c980b32542c2d872b8994f", + "name": "self", + "packageName": "api-utils", + "requires": { + "file": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js" + }, + "traceback": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traceback.js" + }, + "url": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tab-browser.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "a41230a4661d1007c74dc82da3d25a80adcd1976f9232ea1762b4e7e74fed35e", + "name": "tab-browser", + "packageName": "api-utils", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "collection": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/collection.js" + }, + "errors": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js" + }, + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "window-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/window-utils.js" + }, + "xul-app": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tab-browser.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/events.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "163e7b0758a0d07fa4dd6b26d50d3085e85e88a1babce6d232a33bf9c9ecc551", + "name": "tabs/events", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/events.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/tab.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "9008eb1fdc274f73ce81a671434aea12b6bbe3c0ebe912a59c125c151290aef2", + "name": "tabs/tab", + "packageName": "api-utils", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + }, + "content/worker": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/worker.js" + }, + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "tabs/events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/events.js" + }, + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + }, + "utils/data": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/data.js" + }, + "utils/function": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/function.js" + }, + "utils/thumbnail": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/thumbnail.js" + }, + "windows": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/windows.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/tab.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "9f22a022313aabcb0a4fcb08e2f8e806212580167130521efcee0b284df3e741", + "name": "test", + "packageName": "api-utils", + "requires": { + "./test/assert": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test/assert.js" + }, + "type": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/type.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test/assert.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "35c87dedaad26f419439eef7f41fdc668df977dd2985b189bb04cb70cace4971", + "name": "test/assert", + "packageName": "api-utils", + "requires": { + "type": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/type.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test/assert.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/text-streams.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "aa3ba9bf8fcb0ff1bd6d71d904851c6b658aa0e0b5269fc61e3ed07367699165", + "name": "text-streams", + "packageName": "api-utils", + "requires": { + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/text-streams.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer-e10s-adapter.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "a08690ac530902d587e202d97690af8f62087e1a9e4a0fc98ab9707b4fb9cb63", + "name": "timer-e10s-adapter", + "packageName": "api-utils", + "requires": { + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer-e10s-adapter.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js": { + "chrome": true, + "e10s-adapter": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer-e10s-adapter.js", + "hash": "c82d4c17b3ebe9753a1f2eecd8f730a7cfa3eebf823e14615bcaff9f7ecfd8da", + "name": "timer", + "packageName": "api-utils", + "requires": { + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "xpcom": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traceback.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "47857e60c19cefbbec79182a724a0d9ffe51442cc484ff2ebd8e52fb766c4a9f", + "name": "traceback", + "packageName": "api-utils", + "requires": { + "url": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traceback.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "0689e903d8dd172cff8fc88f3444d9082ea0909be8188fcfff69385d0813e170", + "name": "traits", + "packageName": "api-utils", + "requires": { + "traits/core": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits/core.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits/core.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "327d31bdb5e20294cd35ffac1ac1a964eb553a89e3d10cdedfb5401d7dac9d98", + "name": "traits/core", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits/core.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/type.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "0d8ad1fd731a7e254ea631ea31dc479738d59910a0c217f71863eedac8a182a7", + "name": "type", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/type.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test-finder.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "4a1fe3b8bf696bd4a9cd72ceb174b2c77673c15a19773adef516cd5ab65881f2", + "name": "unit-test-finder", + "packageName": "api-utils", + "requires": { + "e10s": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/e10s.js" + }, + "file": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js" + }, + "parent-loader": {} + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test-finder.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "d8112a61a7736de269ca5800542c5e27b4e7a4e85b1e59c54ac02eff5b0e9ea1", + "name": "unit-test", + "packageName": "api-utils", + "requires": { + "cuddlefish": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cuddlefish.js" + }, + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "unit-test-finder": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test-finder.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "604f33e2cdc44bb89c6e344b8536bd1160cce7e8938c8db23775c05d9d88bad6", + "name": "unload", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url-e10s-adapter.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "0a5f769b33424ca3c1c306c721ccb490a267d0ac843ae3bb0afc73a9ce62db73", + "name": "url-e10s-adapter", + "packageName": "api-utils", + "requires": { + "url": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url-e10s-adapter.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js": { + "chrome": true, + "e10s-adapter": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url-e10s-adapter.js", + "hash": "f4ab8fd0d3f93fc645aea23535e14753a4a4ce0c399ee4c28087b3c888101476", + "name": "url", + "packageName": "api-utils", + "requires": { + "api-utils": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/data.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "2ac7da43a127ef1e4a5ee1f3c031f3b4e1d6f4d0a36bc31c1d5ae283c80ad95f", + "name": "utils/data", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/data.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/function.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "9ef84f8a1231c68f7aa5af2bc902e1bd5ec0c28b97e53310c40974903b0795fd", + "name": "utils/function", + "packageName": "api-utils", + "requires": { + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/function.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/registry.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "0a103b720994006069b814f35cb720703638d965f3cda2633d46dcbd754efa3b", + "name": "utils/registry", + "packageName": "api-utils", + "requires": { + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/registry.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/thumbnail.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "a8cd4d1e6d90fcd992fec3edd092b6a92c4df89693e9a46e11d8b67d4743f961", + "name": "utils/thumbnail", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/thumbnail.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/window-utils.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "7df67366cca8658f66ea269b927015132ab8e4ebda88df3dd5e65a13a30f17b6", + "name": "window-utils", + "packageName": "api-utils", + "requires": { + "errors": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js" + }, + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + }, + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/window-utils.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/dom.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "481073a676547a612878b43e87c33ce28db03b24e2674484046cd6b626fc69a9", + "name": "windows/dom", + "packageName": "api-utils", + "requires": { + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/dom.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/loader.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "28f7b3e1242cb1569032d1e11b229efd27728ff4098481fb52dae70b43978f23", + "name": "windows/loader", + "packageName": "api-utils", + "requires": { + "timer": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js" + }, + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/loader.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/tabs.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "bd56b2f5355947be343c9ed657f4d623ccfa23b909a336ef9c043c2657f3639f", + "name": "windows/tabs", + "packageName": "api-utils", + "requires": { + "events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js" + }, + "list": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/list.js" + }, + "tabs/events": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/events.js" + }, + "tabs/tab": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/tab.js" + }, + "traits": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/tabs.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xhr.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "821dd0b9f22f91cc930c59f06237c0bf9e83b0076bd59f23473f7582fd385c23", + "name": "xhr", + "packageName": "api-utils", + "requires": { + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xhr.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "464f1b5d1388b98966b67614ffb96a9edb7592a2d3756084623bfc6a56b852b2", + "name": "xpcom", + "packageName": "api-utils", + "requires": { + "unload": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js": { + "chrome": true, + "e10s-adapter": null, + "hash": "c4929c0d714aac061560c110e6344efcaa9107d77c5929114282ea5914cee010", + "name": "xul-app", + "packageName": "api-utils", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/language.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "6c41e063677b6e8f0704430b0bd690c8f2dbd3c6836ca8938a17bb2b997a7b1b", + "name": "language", + "packageName": "keaddon", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/language.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/main.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "3989f1860f600277a5cb719bb5bdbe14dcac318d501844f181b27940bce7fc0b", + "name": "main", + "packageName": "keaddon", + "requires": { + "language": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/language.js" + }, + "page-mod": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-mod.js" + }, + "self": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js" + }, + "student": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/student.js" + }, + "widget": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/widget.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/main.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/student.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "08c1e260c5558fbbf43c7ae20884805fa09ff2b607cf7b63a8905d0ddc6f439b", + "name": "student", + "packageName": "keaddon", + "requires": { + "language": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/language.js" + }, + "utility": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/utility.js" + } + }, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/student.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/utility.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "360cea06ba2a478a1b6ecb98ea53240b615862e4558ad08c937b027f28ca0c27", + "name": "utility", + "packageName": "keaddon", + "requires": {}, + "sectionName": "lib", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/utility.js" + }, + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-tests/test-main.js": { + "chrome": false, + "e10s-adapter": null, + "hash": "9fe70050af04cb25e2eea4501e4478719b0ce8c14a465dc99e6ba782d15d8971", + "name": "test-main", + "packageName": "keaddon", + "requires": { + "language": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/language.js" + }, + "main": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/main.js" + }, + "request": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/request.js" + }, + "self": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js" + }, + "student": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/student.js" + }, + "tabs": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/tabs.js" + }, + "utility": { + "url": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/utility.js" + } + }, + "sectionName": "tests", + "zipname": "resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-tests/test-main.js" + } + }, + "metadata": { + "addon-kit": { + "author": "Atul Varma (http://toolness.com/) ", + "contributors": [ + "Myk Melez (http://melez.com/) ", + "Daniel Aquino " + ], + "description": "Add-on development made easy.", + "keywords": [ + "javascript", + "engine", + "platform", + "xulrunner" + ], + "license": "MPL 1.1/GPL 2.0/LGPL 2.1", + "name": "addon-kit", + "version": "1.0b4" + }, + "api-utils": { + "author": "Atul Varma (http://toolness.com/) ", + "contributors": [ + "Myk Melez (http://melez.com/) ", + "Daniel Aquino " + ], + "description": "Foundational infrastructure and utilities.", + "keywords": [ + "javascript", + "engine", + "platform", + "xulrunner", + "jetpack-low-level" + ], + "license": "MPL 1.1/GPL 2.0/LGPL 2.1", + "name": "api-utils", + "version": "1.0b4" + }, + "keaddon": { + "author": "Clemens D\u00f6rrh\u00f6fer", + "description": "a basic add-on", + "license": "MPL 1.1/GPL 2.0/LGPL 2.1", + "name": "keaddon", + "version": "0.1" + } + }, + "name": "keaddon", + "packageData": { + "addon-kit": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/", + "api-utils": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-data/", + "keaddon": "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/" + }, + "resourcePackages": { + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data": "addon-kit", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib": "addon-kit", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-data": "api-utils", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib": "api-utils", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data": "keaddon", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib": "keaddon", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-tests": "keaddon" + }, + "resources": { + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data": [ + "resources", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data" + ], + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib": [ + "resources", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib" + ], + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-data": [ + "resources", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-data" + ], + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib": [ + "resources", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib" + ], + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data": [ + "resources", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data" + ], + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib": [ + "resources", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib" + ], + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-tests": [ + "resources", + "jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-tests" + ] + }, + "rootPaths": [ + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/", + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/", + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/", + "resource://jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-tests/" + ], + "sdkVersion": "1.0b4", + "staticArgs": {}, + "verbose": false +} \ No newline at end of file diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/icon.png b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/icon.png new file mode 100644 index 0000000000000000000000000000000000000000..bd813f78edfab3c3e5af7bde0c2dd11eaf4fc3e6 GIT binary patch literal 674 zcmV;T0$u%yP)N*gruUR6cP+~})HopJ>00DGTPE!Ct=GbNc0004EOGiWi zhy@);00009a7bBm000XU000XU0RWnu7ytkO2XskIMF-Xc4huUjL;Y1}0002RNkl4BL)55;;er6Twa#DM&p={N0Y ztb>Ud0@(S>%26F65`*k;rCK}E!aOTgP3AF(s?<}(LUlfGynhq07*qo IM6N<$f>G%q;{X5v literal 0 HcmV?d00001 diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/install.rdf b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/install.rdf new file mode 100644 index 00000000..3b00ec57 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/install.rdf @@ -0,0 +1,35 @@ + + + jid0-GN3ivO79cgfs9k4P3lxdo7TPFa4@jetpack + 0.1 + 2 + true + true + + + + + + + {ec8030f7-c20a-464f-9b0e-13a3a9e97384} + 4.0b7 + 4.0.* + + + + + keaddon + a basic add-on + Clemens Dörrhöfer + + + + + + + \ No newline at end of file diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/moz_favicon.ico b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/moz_favicon.ico new file mode 100644 index 0000000000000000000000000000000000000000..d44438903b751f4732f5365783eb0229b0501f9a GIT binary patch literal 1406 zcmZvcze^lJ6vy9y;f`fV)+?@Ze|W?Y>#3{^YAe`S+YM=~Z34NW`?g{0%{Gm#-zuW37pASug&9hEW%I5<8GkmQYMp$Ony#e@#BjuEiFmE-c}V zrd^0bcjyk?p*!@r%%gjB&%~p9bOs6N0X?7xgn+KhmAQuGZ0RljmPD3CR#cKborS@| zU}3N@BqSIt3>F3pgM}es!eC*rFjyEY3<(_u3xkEh!eC*riUx;;!$uC(Q~?ymczRl( zp~pvt#bNF+awK)Iq%v^Rap7Qbu%xoU;oxv^I5->}sZ?+{7#s`^hFCfWhl9bv5b#p^ zR6=~ZlX)s{tPWIod!kaQ@%AuzOg#o3CXcu0rYDKV+vAsduroh z@GyAl5Vwu0q^Cz=q>tN34FY}vwg5-KFKun)paubs5IK0TwB0NUumo5F5COyV3cwOr z7zhdo0TzBV@~|fXmJsWaSmN6dcL5Csg+XCZ7!(GDA-zs81Q-+sg(1K|8XEC1C=3dN z!a!;oIt&Vf!k_>s{()r5LM6zN!!dVoXv!U9oUF=cIXF0wqoX4^K0cO{lM^{VKbNz! zGr7FHl<9OTS65eZb8{oNx3_YCe=mzaDxXeI`5%v|Zu}3#fqZEe^Tw%4_Mf9?On&&F zi}beZwkZd!>yBC3w&vx-=SH%5uQV+Iv+k~DdEGL9UJhoPqdUoZxoMl$(3xtsdZBU89L3N8 literal 0 HcmV?d00001 diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test-page-worker.html b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test-page-worker.html new file mode 100644 index 00000000..e89a2835 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test-page-worker.html @@ -0,0 +1,8 @@ + + + Page Worker test + + +

Lorem ipsum dolor sit amet.

+ + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test-page-worker.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test-page-worker.js new file mode 100644 index 00000000..27327514 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test-page-worker.js @@ -0,0 +1,27 @@ +function testLoadContentPage() { + // get title directly + postMessage(["assertEqual", document.title, "Page Worker test", + "Correct page title accessed directly"]); + + // get

directly + let p = document.getElementById("paragraph"); + postMessage(["assert", !!p, "

can be accessed directly"]); + postMessage(["assertEqual", p.firstChild.nodeValue, + "Lorem ipsum dolor sit amet.", + "Correct text node expected"]); + + // Modify page + let div = document.createElement("div"); + div.setAttribute("id", "block"); + div.appendChild(document.createTextNode("Test text created")); + document.body.appendChild(div); + + // Check back the modification + div = document.getElementById("block"); + postMessage(["assert", !!div, "

can be accessed directly"]); + postMessage(["assertEqual", div.firstChild.nodeValue, + "Test text created", "Correct text node expected"]); + postMessage(["done"]); +} + +window.addEventListener("DOMContentLoaded", testLoadContentPage, true); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test.html b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test.html new file mode 100644 index 00000000..39de4776 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-data/test.html @@ -0,0 +1,8 @@ + + + foo + + +

bar

+ + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/clipboard.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/clipboard.js new file mode 100644 index 00000000..60a2992d --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/clipboard.js @@ -0,0 +1,248 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Paul O’Shannessy (Original Author) + * Dietrich Ayala + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci} = require("chrome"); +const errors = require("errors"); +const apiUtils = require("api-utils"); + +/* +While these data flavors resemble Internet media types, they do +no directly map to them. +*/ +const kAllowableFlavors = [ + "text/unicode", + "text/html" + /* CURRENTLY UNSUPPORTED FLAVORS + "text/plain", + "image/png", + "image/jpg", + "image/gif" + "text/x-moz-text-internal", + "AOLMAIL", + "application/x-moz-file", + "text/x-moz-url", + "text/x-moz-url-data", + "text/x-moz-url-desc", + "text/x-moz-url-priv", + "application/x-moz-nativeimage", + "application/x-moz-nativehtml", + "application/x-moz-file-promise-url", + "application/x-moz-file-promise-dest-filename", + "application/x-moz-file-promise", + "application/x-moz-file-promise-dir" + */ +]; + +/* +Aliases for common flavors. Not all flavors will +get an alias. New aliases must be approved by a +Jetpack API druid. +*/ +const kFlavorMap = [ + { short: "text", long: "text/unicode" }, + { short: "html", long: "text/html" } + // Images are currently unsupported. + //{ short: "image", long: "image/png" }, +]; + +let clipboardService = Cc["@mozilla.org/widget/clipboard;1"]. + getService(Ci.nsIClipboard); + +let clipboardHelper = Cc["@mozilla.org/widget/clipboardhelper;1"]. + getService(Ci.nsIClipboardHelper); + + +exports.set = function(aData, aDataType) { + let options = { + data: aData, + datatype: aDataType || "text" + }; + options = apiUtils.validateOptions(options, { + data: { + is: ["string"] + }, + datatype: { + is: ["string"] + } + }); + + var flavor = fromJetpackFlavor(options.datatype); + + if (!flavor) + throw new Error("Invalid flavor"); + + // Additional checks for using the simple case + if (flavor == "text/unicode") { + clipboardHelper.copyString(options.data); + return true; + } + + // Below are the more complex cases where we actually have to work with a + // nsITransferable object + var xferable = Cc["@mozilla.org/widget/transferable;1"]. + createInstance(Ci.nsITransferable); + if (!xferable) + throw new Error("Couldn't set the clipboard due to an internal error " + + "(couldn't create a Transferable object)."); + + switch (flavor) { + case "text/html": + var str = Cc["@mozilla.org/supports-string;1"]. + createInstance(Ci.nsISupportsString); + str.data = options.data; + xferable.addDataFlavor(flavor); + xferable.setTransferData(flavor, str, options.data.length * 2); + break; + // TODO: images! + // TODO: add a text/unicode flavor for HTML text that + // returns a plaintextified representation of the HTML. + default: + throw new Error("Unable to handle the flavor " + flavor + "."); + } + + // TODO: Not sure if this will ever actually throw. -zpao + try { + clipboardService.setData( + xferable, + null, + clipboardService.kGlobalClipboard + ); + } catch (e) { + throw new Error("Couldn't set clipboard data due to an internal error: " + e); + } + return true; +}; + + +exports.get = function(aDataType) { + let options = { + datatype: aDataType || "text" + }; + options = apiUtils.validateOptions(options, { + datatype: { + is: ["string"] + } + }); + + var xferable = Cc["@mozilla.org/widget/transferable;1"]. + createInstance(Ci.nsITransferable); + if (!xferable) + throw new Error("Couldn't set the clipboard due to an internal error " + + "(couldn't create a Transferable object)."); + + var flavor = fromJetpackFlavor(options.datatype); + + // Ensure that the user hasn't requested a flavor that we don't support. + if (!flavor) + throw new Error("Getting the clipboard with the flavor '" + flavor + + "' is > not supported."); + + // TODO: Check for matching flavor first? Probably not worth it. + + xferable.addDataFlavor(flavor); + + // Get the data into our transferable. + clipboardService.getData( + xferable, + clipboardService.kGlobalClipboard + ); + + var data = {}; + var dataLen = {}; + try { + xferable.getTransferData(flavor, data, dataLen); + } catch (e) { + // Clipboard doesn't contain data in flavor, return null. + return null; + } + + // There's no data available, return. + if (data.value === null) + return null; + + // TODO: Add flavors here as we support more in kAllowableFlavors. + switch (flavor) { + case "text/unicode": + case "text/html": + data = data.value.QueryInterface(Ci.nsISupportsString).data; + break; + default: + data = null; + } + + return data; +}; + +exports.__defineGetter__("currentFlavors", function() { + // Loop over kAllowableFlavors, calling hasDataMatchingFlavors for each. + // This doesn't seem like the most efficient way, but we can't get + // confirmation for specific flavors any other way. This is supposed to be + // an inexpensive call, so performance shouldn't be impacted (much). + var currentFlavors = []; + for each (var flavor in kAllowableFlavors) { + var matches = clipboardService.hasDataMatchingFlavors( + [flavor], + 1, + clipboardService.kGlobalClipboard + ); + if (matches) + currentFlavors.push(toJetpackFlavor(flavor)); + } + return currentFlavors; +}); + +// SUPPORT FUNCTIONS //////////////////////////////////////////////////////// + +function toJetpackFlavor(aFlavor) { + for each (flavorMap in kFlavorMap) + if (flavorMap.long == aFlavor) + return flavorMap.short; + // Return null in the case where we don't match + return null; +} + +function fromJetpackFlavor(aJetpackFlavor) { + // TODO: Handle proper flavors better + for each (flavorMap in kFlavorMap) + if (flavorMap.short == aJetpackFlavor || flavorMap.long == aJetpackFlavor) + return flavorMap.long; + // Return null in the case where we don't match. + return null; +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/context-menu.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/context-menu.js new file mode 100644 index 00000000..7a9952fd --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/context-menu.js @@ -0,0 +1,1162 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Drew Willcoxon (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Ci} = require("chrome"); + +if (!require("xul-app").is("Firefox")) { + throw new Error([ + "The context-menu module currently supports only Firefox. In the future ", + "we would like it to support other applications, however. Please see ", + "https://bugzilla.mozilla.org/show_bug.cgi?id=560716 for more information." + ].join("")); +} + +const apiUtils = require("api-utils"); +const collection = require("collection"); +const { Worker } = require("content"); +const url = require("url"); +const { MatchPattern } = require("match-pattern"); + +// All user items we add have this class name. +const ITEM_CLASS = "jetpack-context-menu-item"; + +// Items in the top-level context menu also have this class. +const TOPLEVEL_ITEM_CLASS = "jetpack-context-menu-item-toplevel"; + +// Items in the overflow submenu also have this class. +const OVERFLOW_ITEM_CLASS = "jetpack-context-menu-item-overflow"; + +// The ID of the menu separator that separates standard context menu items from +// our user items. +const SEPARATOR_ID = "jetpack-context-menu-separator"; + +// If more than this number of items are added to the context menu, all items +// overflow into a "Jetpack" submenu. +const OVERFLOW_THRESH_DEFAULT = 10; +const OVERFLOW_THRESH_PREF = + "extensions.addon-sdk.context-menu.overflowThreshold"; + +// The label of the overflow sub-. +// +// TODO: Localize this. +const OVERFLOW_MENU_LABEL = "Add-ons"; + +// The ID of the overflow sub-. +const OVERFLOW_MENU_ID = "jetpack-content-menu-overflow-menu"; + +// The ID of the overflow submenu's . +const OVERFLOW_POPUP_ID = "jetpack-content-menu-overflow-popup"; + +// These are used by PageContext.isCurrent below. If the popupNode or any of +// its ancestors is one of these, Firefox uses a tailored context menu, and so +// the page context doesn't apply. +const NON_PAGE_CONTEXT_ELTS = [ + Ci.nsIDOMHTMLAnchorElement, + Ci.nsIDOMHTMLAppletElement, + Ci.nsIDOMHTMLAreaElement, + Ci.nsIDOMHTMLButtonElement, + Ci.nsIDOMHTMLCanvasElement, + Ci.nsIDOMHTMLEmbedElement, + Ci.nsIDOMHTMLImageElement, + Ci.nsIDOMHTMLInputElement, + Ci.nsIDOMHTMLIsIndexElement, + Ci.nsIDOMHTMLMapElement, + Ci.nsIDOMHTMLMediaElement, + Ci.nsIDOMHTMLMenuElement, + Ci.nsIDOMHTMLObjectElement, + Ci.nsIDOMHTMLOptionElement, + Ci.nsIDOMHTMLSelectElement, + Ci.nsIDOMHTMLTextAreaElement, +]; + + +exports.Item = apiUtils.publicConstructor(Item); +exports.Menu = apiUtils.publicConstructor(Menu); +exports.Separator = apiUtils.publicConstructor(Separator); + + +function Item(options) { + let rules = optionsRules(); + rules.data = { + map: function (v) v.toString(), + is: ["string", "undefined"] + }; + options = apiUtils.validateOptions(options, rules); + + defineItemProps(this, options); + + // TODO: Add setter for this? + this.__defineGetter__("data", function () { + return "data" in options ? options.data : undefined; + }); + + this.toString = function Item_toString() { + return '[object Item "' + options.label + '"]'; + }; + + browserManager.addItem(this); +} + +function Menu(options) { + let rules = optionsRules(); + rules.items = { + is: ["array"] + }; + options = apiUtils.validateOptions(options, rules); + + defineItemProps(this, options); + + // TODO: Add setter for this? + this.__defineGetter__("items", function () options.items.slice(0)); + + this.toString = function Menu_toString() { + return '[object Menu "' + options.label + '"]'; + }; + + browserManager.addItem(this); + options.items.forEach(function (i) browserManager.removeItem(i)); +} + +function Separator() { + this.toString = function Separator_toString() { + return "[object Separator]"; + }; +} + + +function Context() {} + +function PageContext() { + this.isCurrent = function PageContext_isCurrent(popupNode) { + let win = popupNode.ownerDocument.defaultView; + if (win && !win.getSelection().isCollapsed) + return false; + + let cursor = popupNode; + while (cursor && !(cursor instanceof Ci.nsIDOMHTMLHtmlElement)) { + if (NON_PAGE_CONTEXT_ELTS.some(function (iface) cursor instanceof iface)) + return false; + cursor = cursor.parentNode; + } + return true; + }; +} + +PageContext.prototype = new Context(); + +function SelectorContext(selector) { + let opts = apiUtils.validateOptions({ selector: selector }, { + selector: { + is: ["string"], + msg: "selector must be a string." + } + }); + + this.adjustPopupNode = function SelectorContext_adjustPopupNode(node) { + return closestMatchingAncestor(node); + }; + + this.isCurrent = function SelectorContext_isCurrent(popupNode) { + return !!closestMatchingAncestor(popupNode); + }; + + // Returns node if it matches selector, or the closest ancestor of node that + // matches, or null if node and none of its ancestors matches. + function closestMatchingAncestor(node) { + let cursor = node; + while (cursor) { + if (cursor.mozMatchesSelector(selector)) + return cursor; + if (cursor instanceof Ci.nsIDOMHTMLHtmlElement) + break; + cursor = cursor.parentNode; + } + return null; + } +} + +SelectorContext.prototype = new Context(); + +function SelectionContext() { + this.isCurrent = function SelectionContext_isCurrent(popupNode) { + let win = popupNode.ownerDocument.defaultView; + if (!win) + return false; + return !win.getSelection().isCollapsed; + }; +} + +SelectionContext.prototype = new Context(); + +function URLContext(patterns) { + let opts = apiUtils.validateOptions({ patterns: patterns }, { + patterns: { + map: function (v) apiUtils.getTypeOf(v) === "array" ? v : [v], + ok: function (v) v.every(function (p) typeof(p) === "string"), + msg: "patterns must be a string or an array of strings." + } + }); + try { + patterns = opts.patterns.map(function (p) new MatchPattern(p)); + } + catch (err) { + console.error("Error creating URLContext match pattern:"); + throw err; + } + + this.isCurrent = function URLContext_isCurrent(popupNode) { + let url = popupNode.ownerDocument.URL; + return patterns.some(function (p) p.test(url)); + }; +} + +URLContext.prototype = new Context(); + +exports.PageContext = apiUtils.publicConstructor(PageContext); +exports.SelectorContext = apiUtils.publicConstructor(SelectorContext); +exports.SelectionContext = apiUtils.publicConstructor(SelectionContext); +exports.URLContext = apiUtils.publicConstructor(URLContext); + + +// Returns rules for apiUtils.validateOptions() common to Item and Menu. +function optionsRules() { + return { + context: { + is: ["undefined", "object", "array"], + ok: function (v) { + if (!v) + return true; + let arr = apiUtils.getTypeOf(v) === "array" ? v : [v]; + return arr.every(function (o) o instanceof Context); + }, + msg: "The 'context' option must be a Context object or an array of " + + "Context objects." + }, + label: { + map: function (v) v.toString(), + is: ["string"], + ok: function (v) !!v, + msg: "The item must have a non-empty string label." + }, + contentScript: { + is: ["string", "array", "undefined"], + ok: function (v) { + return apiUtils.getTypeOf(v) !== "array" || + v.every(function (s) typeof(s) === "string"); + } + }, + contentScriptFile: { + is: ["string", "array", "undefined"], + ok: function (v) { + if (!v) + return true; + let arr = apiUtils.getTypeOf(v) === "array" ? v : [v]; + try { + return arr.every(function (s) { + return apiUtils.getTypeOf(s) === "string" && url.toFilename(s); + }); + } + catch (err) {} + return false; + }, + msg: "The 'contentScriptFile' option must be a local file URL or " + + "an array of local file URLs." + }, + onMessage: { + is: ["function", "undefined"] + } + }; +} + +// Defines some getters and other properties that are common to Item and Menu. +// item is the Item or Menu object on which to define the properties, and +// options is a validated options object. +function defineItemProps(item, options) { + // TODO: Add setter for label? It would require finding the item's DOM + // element and changing its attributes as well. Note however that + // WorkerRegistry relies on label remaining constant, so if setters are added, + // that would need fixing. + item.__defineGetter__("label", function () options.label); + + // Stupid ternaries to avoid Spidermonkey strict warnings. + item.__defineGetter__("contentScript", function () { + return "contentScript" in options ? options.contentScript : undefined; + }); + item.__defineGetter__("contentScriptFile", function () { + return "contentScriptFile" in options ? options.contentScriptFile : undefined; + }); + item.__defineGetter__("onMessage", function () { + return "onMessage" in options ? options.onMessage : undefined; + }); + + collection.addCollectionProperty(item, "context"); + if (options.context) + item.context.add(options.context); + + item.destroy = function Item_destroy() { + browserManager.removeItem(item); + }; +} + +// Does a binary search on elts, a NodeList, and returns the DOM element +// before which an item with targetLabel should be inserted. null is returned +// if the new item should be inserted at the end. +function insertionPoint(targetLabel, elts) { + let from = 0; + let to = elts.length - 1; + + while (from <= to) { + let i = Math.floor((from + to) / 2); + let comp = targetLabel.localeCompare(elts[i].getAttribute("label")); + if (comp < 0) + to = i - 1; + else if (comp > 0) + from = i + 1; + else + return elts[i]; + } + return elts[from] || null; +} + + +// Keeps track of all browser windows. +let browserManager = { + items: [], + windows: [], + + // Registers an item with the manager. It's added to the context menus of + // all currently registered windows, and when new windows are registered it + // will be added to them, too. + addItem: function browserManager_addItem(item) { + this.items.push(item); + this.windows.forEach(function (w) w.addItems([item])); + }, + + // Registers the manager to listen for window openings and closings. Note + // that calling this method can cause onTrack to be called immediately if + // there are open windows. + init: function browserManager_init() { + let windowTracker = new (require("window-utils").WindowTracker)(this); + require("unload").ensure(windowTracker); + }, + + // Registers a window with the manager. This is a WindowTracker callback. + onTrack: function browserManager_onTrack(window) { + if (this._isBrowserWindow(window)) { + let win = new BrowserWindow(window); + this.windows.push(win); + win.addItems(this.items); + } + }, + + // Unregisters a window from the manager. It's told to undo all menu + // modifications. This is a WindowTracker callback. Note that when + // WindowTracker is unloaded, it calls onUntrack for every currently opened + // window. The browserManager therefore doesn't need to specially handle + // unload itself, since unloading the browserManager means untracking all + // currently opened windows. + onUntrack: function browserManager_onUntrack(window) { + if (this._isBrowserWindow(window)) { + for (let i = 0; i < this.windows.length; i++) { + if (this.windows[i].window == window) { + let win = this.windows.splice(i, 1)[0]; + win.destroy(); + return; + } + } + } + }, + + // Unregisters an item from the manager. It's removed from the context menus + // of all windows that are currently registered. If the item is not + // registered, this is a no-op. + removeItem: function browserManager_removeItem(item) { + let idx = this.items.indexOf(item); + if (idx >= 0) { + this.items.splice(idx, 1); + this.windows.forEach(function (w) w.removeItems([item])); + } + }, + + _isBrowserWindow: function browserManager__isBrowserWindow(win) { + let winType = win.document.documentElement.getAttribute("windowtype"); + return winType === "navigator:browser"; + } +}; + + +// A type of Worker tailored to our uses. +const ContextMenuWorker = Worker.compose({ + destroy: Worker.required, + + // Returns true if any context listeners are defined in the worker's port. + anyContextListeners: function CMW_anyContextListeners() { + return this._port._listeners("context").length > 0; + }, + + // Returns true if any of the context listeners in the worker's port return + // true. popupNode is the node that was context-clicked. + isAnyContextCurrent: function CMW_isAnyContextCurrent(popupNode) { + let listeners = this._port._listeners("context"); + for (let i = 0; i < listeners.length; i++) + if (listeners[i].call(this._port._sandbox, popupNode)) + return true; + return false; + }, + + // Emits a click event in the worker's port. popupNode is the node that was + // context-clicked, and clickedItemData is the data of the item that was + // clicked. + fireClick: function CMW_fireClick(popupNode, clickedItemData) { + this._port._emit("click", popupNode, clickedItemData); + } + +}); + + +// This class creates and stores content workers for pairs of menu items and +// content windows. Since workers need to be looked up every time the context +// menu is shown, the main purpose of this class, in addition to creating and +// storing workers, is to provide fast lookup of workers given a menu item and +// content window. +function WorkerRegistry() { + // This is a matrix. The rows are menu item keys, the columns content window + // keys. Each entry in the matrix stores workers for pairs of content windows + // and menu items. + // + // workers[i][w] is an array of objects { item, win, worker }. item is a menu + // item whose key is i, win is a content window whose key is w, and worker is + // the content worker created from the pair. The reason workers[i][w] is an + // array and not a single object is that we don't require menu item keys and + // content window keys to be unique. + // + // This structure is fairly simple and allows worker lookups in constant time + // in the best case. In the worst case, however -- when all content windows + // have the same key and all menu items have the same key -- lookup is O(I*W), + // where I is the number of items and W is the number of windows in the + // registry. I don't expect users to open many duplicate pages or developers + // to create many identical items, so I think it's a good trade-off. + this.workers = {}; + + // These are simple lists of registered menu items and content windows. For + // better performance in the best and common cases (i.e., O(1) instead of + // O(n)) these could be hash tables with separate chaining... + this.items = []; + this.wins = []; +} + +WorkerRegistry.prototype = { + + // Registers a content window, creating workers for each pair formed by the + // window and all previously registered menu items. + registerContentWin: function WR_registerContentWin(win) { + let winKey = this._winKey(win); + let (self = this) this.items.forEach(function (item) { + self._registerPair(win, winKey, item, self._itemKey(item)); + }); + this.wins.push(win); + }, + + // Registers an array of menu items, creating workers for each pair formed by + // the items and all previously registered content windows. + registerItems: function WR_registerItems(items) { + let (self = this) items.forEach(function (item) { + let itemKey = self._itemKey(item); + self.workers[itemKey] = self.workers[itemKey] || {}; + self.wins.forEach(function (win) { + self._registerPair(win, self._winKey(win), item, itemKey); + }); + self.items.push(item); + }); + }, + + // Unregisters a content window, destroying all workers related to it. + unregisterContentWin: function WR_unregisterContentWin(win) { + let winKey = this._winKey(win); + let (self = this) this.items.forEach(function (item) { + let itemKey = self._itemKey(item); + let list = self._unregisterPair(win, winKey, item, itemKey); + + // Delete the window column (of this item row) if there are no more + // entries. + if (!list.length) + delete self.workers[itemKey][winKey]; + }); + + let idx = this.wins.indexOf(win); + if (idx < 0) + throw new Error("Internal error: window not registered."); + this.wins.splice(idx, 1); + }, + + // Unregisters an array of menu items, destroying all workers related to them. + unregisterItems: function WR_unregisterItems(items) { + let (self = this) items.forEach(function (item) { + let allEmpty = true; + let itemKey = self._itemKey(item); + self.wins.forEach(function (win) { + let list = self._unregisterPair(win, self._winKey(win), item, itemKey); + allEmpty = allEmpty && !list.length; + }); + + // Delete the item row if there are no more entries in any of its window + // columns. + if (allEmpty) + delete self.workers[itemKey]; + + let idx = self.items.indexOf(item); + if (idx < 0) + throw new Error("Internal error: item not registered."); + self.items.splice(idx, 1); + }); + }, + + // Returns the worker for the given content-window-item pair, or null if none + // exists. + find: function WR_find(contentWin, item) { + let itemKey = this._itemKey(item); + if (itemKey in this.workers) { + let wins = this.workers[itemKey]; + let winKey = this._winKey(contentWin); + if (winKey in wins) { + let list = wins[winKey]; + let idx = this._indexOfPair(list, contentWin, item); + if (idx >= 0) + return list[idx].worker; + } + } + return null; + }, + + _registerPair: function WR__registerPair(win, winKey, item, itemKey) { + let worker = this._makeWorker(win, item); + this.workers[itemKey][winKey] = this.workers[itemKey][winKey] || []; + this.workers[itemKey][winKey].push({ + win: win, + item: item, + worker: worker + }); + }, + + _unregisterPair: function WR__unregisterPair(win, winKey, item, itemKey) { + if (!(itemKey in this.workers)) + throw new Error("Internal error: item key not in registry."); + if (!(winKey in this.workers[itemKey])) + throw new Error("Internal error: window key not in registry."); + let list = this.workers[itemKey][winKey]; + let idx = this._indexOfPair(list, win, item); + if (idx < 0) + throw new Error("Internal error: target pair not found."); + list[idx].worker.destroy(); + list.splice(idx, 1); + return list; + }, + + _indexOfPair: function WR__indexOfPair(list, win, item) { + let idx = 0; + for (; idx < list.length; idx++) + if (list[idx].win === win && list[idx].item === item) + break; + return idx >= list.length ? -1 : idx; + }, + + _makeWorker: function WR__makeWorker(win, item) { + let worker = ContextMenuWorker({ + window: win.wrappedJSObject, + contentScript: item.contentScript, + contentScriptFile: item.contentScriptFile, + onError: function (err) console.exception(err) + }); + worker.on("message", function workerOnMessage(msg) { + if (item.onMessage) { + try { + item.onMessage(msg); + } + catch (err) { + console.exception(err); + } + } + }); + return worker; + }, + + _winKey: function WR__winKey(win) { + return win.document.URL; + }, + + _itemKey: function WR__itemKey(item) { + // We rely on label remaining constant over the lifetime of the item. + return item.label; + } +}; + + +// Keeps track of a single browser window. Responsible for providing a +// description of the window's current context and determining whether an item +// matches the current context. +// +// TODO: If other apps besides Firefox want to support the context menu in +// whatever way is appropriate for them, plugging in a substitute for this class +// should be the way to do it. Make it easy for them. See bug 560716. +function BrowserWindow(window) { + this.window = window; + this.doc = window.document; + + let popup = this.doc.getElementById("contentAreaContextMenu"); + if (!popup) + throw new Error("Internal error: Context menu popup not found."); + this.contextMenuPopup = new ContextMenuPopup(popup, this); + + // This browser window is responsible for workers related to its content + // windows. + this.workerReg = new WorkerRegistry(); + + // New workers are created when content windows are loaded. + window.gBrowser.addEventListener("DOMContentLoaded", this, false); + + // Register content windows that are already open and loaded. + let browsers = window.gBrowser.browsers; + for (let i = 0; i < browsers.length; i++) + if (browsers[i].contentDocument.readyState === "complete") + this._registerContentWin(browsers[i].contentWindow); +} + +BrowserWindow.prototype = { + + // Adds an array of items to the window's context menu. + addItems: function BW_addItems(items) { + this.contextMenuPopup.addItems(items); + this.workerReg.registerItems(items); + }, + + // The context specified for a top-level item may not match exactly the real + // context that triggers it. For example, if the user context-clicks a span + // inside an anchor, we want items that specify an anchor context to be + // triggered, but the real context will indicate that the span was clicked, + // not the anchor. Where the real context and an item's context conflict, + // clients should be given the item's context, and this method can be used to + // make such adjustments. Returns an adjusted popupNode. + adjustPopupNode: function BW_adjustPopupNode(popupNode, topLevelItem) { + for (let ctxt in topLevelItem.context) { + if (typeof(ctxt.adjustPopupNode) === "function") { + let ctxtNode = ctxt.adjustPopupNode(popupNode); + if (ctxtNode) { + popupNode = ctxtNode; + break; + } + } + } + return popupNode; + }, + + // Returns true if all of item's contexts are current in the window. + areAllContextsCurrent: function BW_areAllContextsCurrent(item, popupNode) { + let worker = this.workerReg.find(popupNode.ownerDocument.defaultView, item); + + // If the worker for the content-window-item pair doesn't exist (e.g., + // because the page hasn't loaded yet), we can't really make a good decision + // since the content script may have a context listener. So just don't show + // the item at all. + if (!worker) + return false; + + // If there are no contexts given at all, the page context applies. + let hasContentContext = worker.anyContextListeners(); + if (!hasContentContext && !item.context.length) + return new PageContext().isCurrent(popupNode); + + // Otherwise, determine if all given contexts are current. Evaluate the + // declarative contexts first and the worker's context listeners last. That + // way the listener might be able to avoid some work. + let curr = true; + for (let ctxt in item.context) { + curr = curr && ctxt.isCurrent(popupNode); + if (!curr) + return false; + } + return !hasContentContext || worker.isAnyContextCurrent(popupNode); + }, + + // Sets this.popupNode to the node the user context-clicked to invoke the + // context menu. For Gecko 2.0 and later, triggerNode is this node; if it's + // falsey, document.popupNode is used. Returns the popupNode. + capturePopupNode: function BW_capturePopupNode(triggerNode) { + this.popupNode = triggerNode || this.doc.popupNode; + if (!this.popupNode) + console.warn("popupNode is null."); + return this.popupNode; + }, + + // Undoes all modifications to the window's context menu. The BrowserWindow + // should not be used afterward. + destroy: function BW_destroy() { + this.contextMenuPopup.destroy(); + this.window.gBrowser.removeEventListener("DOMContentLoaded", this, false); + let (self = this) this.workerReg.wins.forEach(function (win) { + self._unregisterContentWin(win); + }); + }, + + // Emits a click event in the port of the content worker related to item and + // popupNode's content window. Listeners will be passed popupNode and + // clickedItemData. + fireClick: function BW_fireClick(item, popupNode, clickedItemData) { + let worker = this.workerReg.find(popupNode.ownerDocument.defaultView, item); + if (worker) + worker.fireClick(popupNode, clickedItemData); + }, + + // Removes an array of items from the window's context menu. + removeItems: function BW_removeItems(items) { + this.contextMenuPopup.removeItems(items); + this.workerReg.unregisterItems(items); + }, + + // Handles content window loads and unloads. + handleEvent: function BW_handleEvent(event) { + try { + switch (event.type) { + case "DOMContentLoaded": + if (event.target.defaultView) + this._registerContentWin(event.target.defaultView); + break; + case "unload": + this._unregisterContentWin(event.target.defaultView); + break; + } + } + catch (err) { + console.exception(err); + } + }, + + _registerContentWin: function BW__registerContentWin(win) { + win.addEventListener("unload", this, false); + this.workerReg.registerContentWin(win); + }, + + _unregisterContentWin: function BW__unregisterContentWin(win) { + win.removeEventListener("unload", this, false); + this.workerReg.unregisterContentWin(win); + } +}; + + +// Represents a container of items that's the child of the given Menu and Popup. +// popupElt is a that represents the popup in the DOM, and window is +// the BrowserWindow containing the popup. The popup is responsible for +// creating and adding items to poupElt and handling command events. +function Popup(parentMenu, parentPopup, popupElt, window) { + this.parentMenu = parentMenu; + this.parentPopup = parentPopup; + this.popupElt = popupElt; + this.window = window; + this.doc = popupElt.ownerDocument; + + // Keeps track of the DOM elements owned by this popup: { item, elt }. + this.itemWrappers = []; + + popupElt.addEventListener("command", this, false); +} + +Popup.prototype = { + + // Adds an array of items to the popup. + addItems: function Popup_addItems(items) { + for (let i = 0; i < items.length; i++) { + let wrapper = { item: items[i], elt: this._makeItemElt(items[i]) }; + this.itemWrappers.push(wrapper); + this.popupElt.appendChild(wrapper.elt); + } + }, + + // Undoes all modifications to the popup. The popup should not be used + // afterward. + destroy: function Popup_destroy() { + this.popupElt.removeEventListener("command", this, false); + }, + + // The popup is responsible for two command events: those originating at items + // in the popup and those bubbling to the popup's parent menu. In the first + // case the popup dispatches a click to the item, and in the second the popup + // dispatches a click to its parent menu -- in that order. + handleEvent: function Popup_handleEvent(event) { + try { + let elt = event.target; + if (elt.className.split(/\s+/).indexOf(ITEM_CLASS) >= 0) { + // If the event originated at an item in the popup, dispatch a click. + // Also set Popup.clickedItem and popupNode so ancestor popups know + // which item was clicked and under what context. + let childItemWrapper = this._findItemWrapper(elt); + if (childItemWrapper) { + let clickedItem = childItemWrapper.item; + let topLevelItem = this._topLevelItem(clickedItem); + let popupNode = this.window.adjustPopupNode(this.window.popupNode, + topLevelItem); + Popup.clickedItem = clickedItem; + Popup.popupNode = popupNode; + this.window.fireClick(clickedItem, popupNode, clickedItem.data); + } + + // Dispatch a click to this popup's parent menu. + if (this.parentMenu) { + this.window.fireClick(this.parentMenu, Popup.popupNode, + Popup.clickedItem.data); + } + } + } + catch (err) { + console.exception(err); + } + }, + + // Returns true if the DOM element is owned by the wrapper. + _eltMatchesItemWrapper: function Popup__eltMatchesItemWrap(elt, itemWrapper) { + return elt == itemWrapper.elt; + }, + + // Given a DOM element, returns the item wrapper that owns it or null if none. + _findItemWrapper: function Popup__findItemWrapper(elt) { + for (let i = 0; i < this.itemWrappers.length; i++) { + let wrapper = this.itemWrappers[i]; + if (this._eltMatchesItemWrapper(elt, wrapper)) + return wrapper; + } + return null; + }, + + // Returns a DOM element representing the item. All elements will have the + // ITEM_CLASS class, and className can optionally be used to add another. + _makeItemElt: function Popup__makeItemElt(item, className) { + let elt = item instanceof Item ? this._makeMenuitem(item, className) : + item instanceof Menu ? this._makeMenu(item, className) : + item instanceof Separator ? this._makeSeparator(className) : + null; + if (!elt) + throw new Error("Internal error: can't make element, unknown item type"); + + return elt; + }, + + // Returns a new representing the menu. + _makeMenu: function Popup__makeMenu(menu, className) { + let menuElt = this.doc.createElement("menu"); + menuElt.className = ITEM_CLASS + (className ? " " + className : ""); + menuElt.setAttribute("label", menu.label); + let popupElt = this.doc.createElement("menupopup"); + menuElt.appendChild(popupElt); + + // Once items are added, this value can be thrown away. The popup handles + // popupshowing on its own. + let popup = new Popup(menu, this, popupElt, this.window); + popup.addItems(menu.items); + + return menuElt; + }, + + // Returns a new representing the item. + _makeMenuitem: function Popup__makeMenuitem(item, className) { + let elt = this.doc.createElement("menuitem"); + elt.className = ITEM_CLASS + (className ? " " + className : ""); + elt.setAttribute("label", item.label); + if (item.data) + elt.setAttribute("value", item.data); + return elt; + }, + + // Returns a new . + _makeSeparator: function Popup__makeSeparator(className) { + let elt = this.doc.createElement("menuseparator"); + elt.className = ITEM_CLASS + (className ? " " + className : ""); + return elt; + }, + + // Returns the top-level menu that contains item or item if it is top-level. + _topLevelItem: function Popup__topLevelItem(item) { + let popup = this; + let topLevelItem = item; + while (popup.parentPopup) { + topLevelItem = popup.parentMenu; + popup = popup.parentPopup; + } + return topLevelItem; + } +}; + + +// A subclass of Popup, this represents a window's context menu popup. It's +// responsible for hiding and showing items according to the window's current +// context. +function ContextMenuPopup(popupElt, window) { + const self = this; + Popup.call(this, null, null, popupElt, window); + + // Adds an array of items to the popup. + this.addItems = function CMP_addItems(items) { + // Don't do anything if there are no items. + if (items.length) { + ensureStaticEltsExist(); + ensureListeningForPopups(); + + // Add each item to the top-level menu and the overflow submenu. + let submenuPopup = overflowPopup(); + for (let i = 0; i < items.length; i++) { + let item = items[i]; + let wrapper = { + item: item, + elt: this._makeItemElt(item, TOPLEVEL_ITEM_CLASS), + overflowElt: this._makeItemElt(item, OVERFLOW_ITEM_CLASS) + }; + this.itemWrappers.push(wrapper); + + let targetElt = insertionPoint(item.label, topLevelElts()); + this.popupElt.insertBefore(wrapper.elt, targetElt); + + targetElt = insertionPoint(item.label, overflowElts()); + submenuPopup.insertBefore(wrapper.overflowElt, targetElt); + } + } + }; + + // Undoes all modifications to the popup. The popup should not be used + // afterward. + this.destroy = function CMP_destroy() { + // Remove all the items registered with this instance of the module from the + // top-level menu and overflow submenu. + let submenuPopup = overflowPopup(); + for (let i = 0; i < this.itemWrappers.length; i++) { + this.popupElt.removeChild(this.itemWrappers[i].elt); + if (submenuPopup) + submenuPopup.removeChild(this.itemWrappers[i].overflowElt); + } + + // If there are no more items from any instance of the module, remove the + // separator and overflow submenu, if they exist. + let elts = topLevelElts(); + if (!elts.length) { + let submenu = overflowMenu(); + if (submenu) + this.popupElt.removeChild(submenu); + + let sep = separator(); + if (sep) + this.popupElt.removeChild(sep); + } + + // Remove event listeners. + if (this._listeningForPopups) { + this.popupElt.removeEventListener("popupshowing", this, false); + delete this._listeningForPopups; + } + this.__proto__.destroy.call(this); + }; + + // The context menu popup needs to handle popupshowing in addition to command + // events. popupshowing is used to show top-level items that match the + // window's current context and hide items that don't. Each module instance + // is responsible for showing and hiding the items it owns. + this.handleEvent = function CMP_handleEvent(event) { + if (event.type === "command") { + this.__proto__.handleEvent.call(this, event); + } + else if (event.type === "popupshowing" && event.target === popupElt) { + try { + // popupElt.triggerNode was added in Gecko 2.0 by bug 383930. The || is + // to avoid a Spidermonkey strict warning on earlier versions. + let triggerNode = popupElt.triggerNode || undefined; + let popupNode = window.capturePopupNode(triggerNode); + + // Show and hide items. Set a "jetpackContextCurrent" property on the + // DOM elements to signal which of our items match the current context. + this.itemWrappers.forEach(function (wrapper) { + let contextCurr = window.areAllContextsCurrent(wrapper.item, + popupNode); + wrapper.elt.jetpackContextCurrent = contextCurr; + wrapper.overflowElt.jetpackContextCurrent = contextCurr; + wrapper.elt.hidden = !contextCurr; + wrapper.overflowElt.hidden = !contextCurr; + }); + + // Get the total number of items that match the current context. It's a + // little tricky: There may be other instances of this module loaded, + // each hiding and showing their items. So we can't base this number on + // only our items, or on the hidden state of items. That's why we set + // the jetpackContextCurrent property above. The last instance to run + // will leave the menupopup in the correct state. + let elts = topLevelElts(); + let numShown = Array.reduce(elts, function (total, elt) { + return total + (elt.jetpackContextCurrent ? 1 : 0); + }, 0); + + // If too many items are shown, show the submenu and hide the top-level + // items. Otherwise, hide the submenu and show the top-level items. + let overflow = numShown > overflowThreshold(); + if (overflow) + Array.forEach(elts, function (e) e.hidden = true); + + let submenu = overflowMenu(); + if (submenu) + submenu.hidden = !overflow; + + // If no items are shown, hide the menu separator. + let sep = separator(); + if (sep) + sep.hidden = numShown === 0; + } + catch (err) { + console.exception(err); + } + } + }; + + // Removes an array of items from the popup. + this.removeItems = function CMP_removeItems(items) { + let overPopup = overflowPopup(); + for (let i = 0; i < items.length; i++) { + let idx = indexOfItemWrapper(items[i]); + if (idx < 0) { + // Don't throw here; continue the loop. + let err = new Error("Internal error: item for removal not found."); + console.exception(err); + } + + let wrapper = this.itemWrappers[idx]; + this.popupElt.removeChild(wrapper.elt); + overPopup.removeChild(wrapper.overflowElt); + this.itemWrappers.splice(idx, 1); + } + }; + + // Returns true if the DOM element is owned by the wrapper. + this._eltMatchesItemWrapper = function CMP__eltMatchesWrap(elt, itemWrapper) { + return elt == itemWrapper.elt || elt == itemWrapper.overflowElt; + }; + + // Adds the popupshowing listener if it hasn't been added already. + function ensureListeningForPopups() { + if (!self._listeningForPopups) { + self.popupElt.addEventListener("popupshowing", self, false); + self._listeningForPopups = true; + } + } + + // Adds the menu separator and overflow submenu if they don't exist. + function ensureStaticEltsExist() { + let sep = separator(); + if (!sep) { + sep = makeSeparator(); + self.popupElt.appendChild(sep); + } + + let submenu = overflowMenu(); + if (!submenu) { + submenu = makeOverflowMenu(); + self.popupElt.insertBefore(submenu, sep.nextSibling); + } + } + + // Returns the index of the item wrapper containing item, -1 if none. + function indexOfItemWrapper(item) { + for (let i = 0; i < self.itemWrappers.length; i++) { + if (self.itemWrappers[i].item === item) + return i; + } + return -1; + } + + // Creates and returns the that's shown when too many items are added + // to the popup. + function makeOverflowMenu() { + let submenu = self.doc.createElement("menu"); + submenu.id = OVERFLOW_MENU_ID; + submenu.setAttribute("label", OVERFLOW_MENU_LABEL); + let popup = self.doc.createElement("menupopup"); + popup.id = OVERFLOW_POPUP_ID; + submenu.appendChild(popup); + return submenu; + } + + // Creates and returns the that separates the standard context + // menu items from our items. + function makeSeparator() { + let elt = self.doc.createElement("menuseparator"); + elt.id = SEPARATOR_ID; + return elt; + } + + // Returns the item elements contained in the overflow menu, a NodeList. + function overflowElts() { + return overflowPopup().getElementsByClassName(OVERFLOW_ITEM_CLASS); + } + + // Returns the overflow . + function overflowMenu() { + return self.doc.getElementById(OVERFLOW_MENU_ID); + } + + // Returns the overflow . + function overflowPopup() { + return self.doc.getElementById(OVERFLOW_POPUP_ID); + } + + // Returns the OVERFLOW_THRESH_PREF pref value if it exists or + // OVERFLOW_THRESH_DEFAULT if it doesn't. + function overflowThreshold() { + let prefs = require("preferences-service"); + return prefs.get(OVERFLOW_THRESH_PREF, OVERFLOW_THRESH_DEFAULT); + } + + // Returns the . + function separator() { + return self.doc.getElementById(SEPARATOR_ID); + } + + // Returns the item elements contained in the top-level menu, a NodeList. + function topLevelElts() { + return self.popupElt.getElementsByClassName(TOPLEVEL_ITEM_CLASS); + } +}; + +ContextMenuPopup.prototype = Popup.prototype; + + +// Init the browserManager only after setting prototypes and such above, because +// it will cause browserManager.onTrack to be called immediately if there are +// open windows. +browserManager.init(); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/notifications.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/notifications.js new file mode 100644 index 00000000..df103522 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/notifications.js @@ -0,0 +1,110 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim:set ts=2 sw=2 sts=2 et filetype=javascript + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Drew Willcoxon (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const { Cc, Ci, Cr } = require("chrome"); +const apiUtils = require("api-utils"); +const errors = require("errors"); + +try { + let alertServ = Cc["@mozilla.org/alerts-service;1"]. + getService(Ci.nsIAlertsService); + + // The unit test sets this to a mock notification function. + var notify = alertServ.showAlertNotification.bind(alertServ); +} +catch (err) { + // An exception will be thrown if the platform doesn't provide an alert + // service, e.g., if Growl is not installed on OS X. In that case, use a + // mock notification function that just logs to the console. + notify = notifyUsingConsole; +} + +exports.notify = function notifications_notify(options) { + let valOpts = validateOptions(options); + let clickObserver = !valOpts.onClick ? null : { + observe: function notificationClickObserved(subject, topic, data) { + if (topic === "alertclickcallback") + errors.catchAndLog(valOpts.onClick).call(exports, valOpts.data); + } + }; + function notifyWithOpts(notifyFn) { + notifyFn(valOpts.iconURL, valOpts.title, valOpts.text, !!clickObserver, + valOpts.data, clickObserver); + } + try { + notifyWithOpts(notify); + } + catch (err if err instanceof Ci.nsIException && + err.result == Cr.NS_ERROR_FILE_NOT_FOUND) { + console.warn("The notification icon named by " + valOpts.iconURL + + " does not exist. A default icon will be used instead."); + delete valOpts.iconURL; + notifyWithOpts(notify); + } + catch (err) { + notifyWithOpts(notifyUsingConsole); + } +}; + +function notifyUsingConsole(iconURL, title, text) { + title = title ? "[" + title + "]" : ""; + text = text || ""; + let str = [title, text].filter(function (s) s).join(" "); + console.log(str); +} + +function validateOptions(options) { + return apiUtils.validateOptions(options, { + data: { + is: ["string", "undefined"] + }, + iconURL: { + is: ["string", "undefined"] + }, + onClick: { + is: ["function", "undefined"] + }, + text: { + is: ["string", "undefined"] + }, + title: { + is: ["string", "undefined"] + } + }); +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-mod.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-mod.js new file mode 100644 index 00000000..3b39e9b8 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-mod.js @@ -0,0 +1,198 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack Packages. + * + * The Initial Developer of the Original Code is Nickolay Ponomarev. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Nickolay Ponomarev (Original Author) + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +const observers = require("observer-service"); +const { Worker, Loader } = require('content'); +const { EventEmitter } = require('events'); +const { List } = require('list'); +const { Registry } = require('utils/registry'); +const xulApp = require("xul-app"); +const { MatchPattern } = require('match-pattern'); + +// Whether or not the host application dispatches a document-element-inserted +// notification when the document element is inserted into the DOM of a page. +// The notification was added in Gecko 2.0b6, it's a better time to attach +// scripts with contentScriptWhen "start" than content-document-global-created, +// since libraries like jQuery assume the presence of the document element. +const HAS_DOCUMENT_ELEMENT_INSERTED = + xulApp.versionInRange(xulApp.platformVersion, "2.0b6", "*"); +const ON_CONTENT = HAS_DOCUMENT_ELEMENT_INSERTED ? 'document-element-inserted' : + 'content-document-global-created'; +const ON_READY = 'DOMContentLoaded'; +const ERR_INCLUDE = 'The PageMod must have a string or array `include` option.'; + +// rules registry +const RULES = {}; + +const Rules = EventEmitter.resolve({ toString: null }).compose(List, { + add: function() Array.slice(arguments).forEach(function onAdd(rule) { + if (this._has(rule)) return; + // registering rule to the rules registry + if (!(rule in RULES)) + RULES[rule] = new MatchPattern(rule); + this._add(rule); + this._emit('add', rule); + }.bind(this)), + remove: function() Array.slice(arguments).forEach(function onRemove(rule) { + if (!this._has(rule)) return; + this._remove(rule); + this._emit('remove', rule); + }.bind(this)), +}); + +/** + * PageMod constructor (exported below). + * @constructor + */ +const PageMod = Loader.compose(EventEmitter, { + on: EventEmitter.required, + _listeners: EventEmitter.required, + contentScript: Loader.required, + contentScriptFile: Loader.required, + contentScriptWhen: Loader.required, + include: null, + constructor: function PageMod(options) { + this._onAttach = this._onAttach.bind(this); + this._onReady = this._onReady.bind(this); + this._onContent = this._onContent.bind(this); + options = options || {}; + + if ('contentScript' in options) + this.contentScript = options.contentScript; + if ('contentScriptFile' in options) + this.contentScriptFile = options.contentScriptFile; + if ('contentScriptWhen' in options) + this.contentScriptWhen = options.contentScriptWhen; + if ('onAttach' in options) + this.on('attach', options.onAttach); + if ('onError' in options) + this.on('error', options.onError); + + let include = options.include; + let rules = this.include = Rules(); + rules.on('add', this._onRuleAdd = this._onRuleAdd.bind(this)); + rules.on('remove', this._onRuleRemove = this._onRuleRemove.bind(this)); + + // Validate 'include' + if (typeof(include) == "object" && !Array.isArray(include)) + throw new Error(ERR_INCLUDE); + if (typeof(include) == "number" || typeof(include) == "undefined") + throw new Error(ERR_INCLUDE); + + if (Array.isArray(include)) + rules.add.apply(null, include); + else + rules.add(include); + + this.on('error', this._onUncaughtError = this._onUncaughtError.bind(this)); + pageModManager.add(this._public); + }, + destroy: function destroy() { + pageModManager.remove(this._public); + }, + _onContent: function _onContent(window) { + if (!pageModManager.has(this)) + return; // not registered yet + if ('ready' == this.contentScriptWhen) + window.addEventListener(ON_READY, this._onReady , false); + else + this._onAttach(window); + }, + _onReady: function _onReady(event) { + let window = event.target.defaultView; + window.removeEventListener(ON_READY, this._onReady, false); + this._onAttach(window); + }, + _onAttach: function _onAttach(window) { + this._emit('attach', Worker({ + window: window.wrappedJSObject, + contentScript: this.contentScript, + contentScriptFile: this.contentScriptFile, + onError: this._onUncaughtError + })); + }, + _onRuleAdd: function _onRuleAdd(url) { + pageModManager.on(url, this._onContent); + }, + _onRuleRemove: function _onRuleRemove(url) { + pageModManager.off(url, this._onContent); + }, + _onUncaughtError: function _onUncaughtError(e) { + if (this._listeners('error').length == 1) + console.exception(e); + } +}); +exports.PageMod = function(options) PageMod(options) +exports.PageMod.prototype = PageMod.prototype; + +const PageModManager = Registry.resolve({ + constructor: '_init', + _destructor: '_registryDestructor' +}).compose({ + constructor: function PageModRegistry(constructor) { + this._init(PageMod); + observers.add( + ON_CONTENT, this._onContentWindow = this._onContentWindow.bind(this) + ); + }, + _destructor: function _destructor() { + observers.remove(ON_CONTENT, this._onContentWindow); + for (let rule in RULES) { + this._removeAllListeners(rule); + delete RULES[rule]; + } + this._registryDestructor(); + }, + _onContentWindow: function _onContentWindow(domObj) { + let window = HAS_DOCUMENT_ELEMENT_INSERTED ? domObj.defaultView : domObj; + // XML documents don't have windows, and we don't yet support them. + if (!window) + return; + for (let rule in RULES) + if (RULES[rule].test(window.document.URL)) + this._emit(rule, window); + }, + off: function off(topic, listener) { + this.removeListener(topic, listener); + if (!this._listeners(topic).length) + delete RULES[topic]; + } +}); +const pageModManager = PageModManager(); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-worker.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-worker.js new file mode 100644 index 00000000..5c6c22c5 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/page-worker.js @@ -0,0 +1,97 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Felipe Gomes (Original Author) + * Myk Melez + * Irakli Gozalishvili + * Drew Willcoxon + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +const { Symbiont } = require("content"); +const { Trait } = require("traits"); + +if (!require("xul-app").isOneOf(["Firefox", "Thunderbird"])) { + throw new Error([ + "The page-worker module currently supports only Firefox and Thunderbird. ", + "In the future, we would like it to support other applications, however. ", + "Please see https://bugzilla.mozilla.org/show_bug.cgi?id=546740 for more ", + "information." + ].join("")); +} + +const Page = Trait.compose( + Symbiont.resolve({ + constructor: '_initSymbiont' + }), + { + _frame: Trait.required, + _initFrame: Trait.required, + postMessage: Symbiont.required, + on: Symbiont.required, + destroy: Symbiont.required, + + constructor: function Page(options) { + options = options || {}; + + this.contentURL = 'contentURL' in options ? options.contentURL + : 'about:blank'; + if ('contentScriptWhen' in options) + this.contentScriptWhen = options.contentScriptWhen; + if ('contentScriptFile' in options) + this.contentScriptFile = options.contentScriptFile; + if ('contentScript' in options) + this.contentScript = options.contentScript; + if ('allow' in options) + this.allow = options.allow; + if ('onError' in options) + this.on('error', options.onError); + if ('onMessage' in options) + this.on('message', options.onMessage); + + this.on('propertyChange', this._onChange.bind(this)); + + this._initSymbiont(); + }, + + _onChange: function _onChange(e) { + if ('contentURL' in e) + this._initFrame(this._frame); + } + } +); +exports.Page = function(options) Page(options); +exports.Page.prototype = Page.prototype; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/panel.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/panel.js new file mode 100644 index 00000000..48996205 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/panel.js @@ -0,0 +1,358 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Myk Melez (Original Author) + * Irakli Gozalishvili + * Mihai Sucan + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +if (!require("xul-app").is("Firefox")) { + throw new Error([ + "The panel module currently supports only Firefox. In the future ", + "we would like it to support other applications, however. Please see ", + "https://bugzilla.mozilla.org/show_bug.cgi?id=jetpack-panel-apps ", + "for more information." + ].join("")); +} + +const { Ci } = require("chrome"); +const { validateOptions: valid } = require("api-utils"); +const { Symbiont } = require("content"); +const { EventEmitter } = require('events'); +const timer = require("timer"); + +require("xpcom").utils.defineLazyServiceGetter( + this, + "windowMediator", + "@mozilla.org/appshell/window-mediator;1", + "nsIWindowMediator" +); + +const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul", + ON_SHOW = 'popupshown', + ON_HIDE = 'popuphidden', + validNumber = { is: ['number', 'undefined', 'null'] }; + +/** + * Emits show and hide events. + */ +const Panel = Symbiont.resolve({ + constructor: '_init', + _onInit: '_onSymbiontInit', + destroy: '_symbiontDestructor' +}).compose({ + _frame: Symbiont.required, + _init: Symbiont.required, + _onSymbiontInit: Symbiont.required, + _symbiontDestructor: Symbiont.required, + _emit: Symbiont.required, + _asyncEmit: Symbiont.required, + on: Symbiont.required, + removeListener: Symbiont.required, + _destructor: Symbiont.required, + + _inited: false, + + /** + * If set to `true` frame loaders between xul panel frame and + * hidden frame are swapped. If set to `false` frame loaders are + * set back to normal. Setting the value that was already set will + * have no effect. + */ + set _frameLoadersSwapped(value) { + if (this.__frameLoadersSwapped == value) return; + this._frame.QueryInterface(Ci.nsIFrameLoaderOwner) + .swapFrameLoaders(this._viewFrame); + this.__frameLoadersSwapped = value; + }, + __frameLoadersSwapped: false, + + constructor: function Panel(options) { + this._onShow = this._onShow.bind(this); + this._onHide = this._onHide.bind(this); + this.on('inited', this._onSymbiontInit.bind(this)); + + options = options || {}; + if ('onShow' in options) + this.on('show', options.onShow); + if ('onHide' in options) + this.on('hide', options.onHide); + if ('width' in options) + this.width = options.width; + if ('height' in options) + this.height = options.height; + if ('contentURL' in options) + this.contentURL = options.contentURL; + + this._init(options); + }, + _destructor: function _destructor() { + this.hide(); + this._removeAllListeners('show'); + // defer cleanup to be performed after panel gets hidden + this._xulPanel = null; + this._symbiontDestructor(this); + this._removeAllListeners(this, 'hide'); + }, + destroy: function destroy() { + this._destructor(); + }, + /* Public API: Panel.width */ + get width() this._width, + set width(value) + this._width = valid({ $: value }, { $: validNumber }).$ || this._width, + _width: 320, + /* Public API: Panel.height */ + get height() this._height, + set height(value) + this._height = valid({ $: value }, { $: validNumber }).$ || this._height, + _height: 240, + + /* Public API: Panel.isShowing */ + get isShowing() !!this._xulPanel && this._xulPanel.state == "open", + + /* Public API: Panel.show */ + show: function show(anchor) { + anchor = anchor || null; + let document = getWindow(anchor).document; + let xulPanel = this._xulPanel; + if (!xulPanel) { + xulPanel = this._xulPanel = document.createElementNS(XUL_NS, 'panel'); + xulPanel.setAttribute("type", "arrow"); + + // One anonymous node has a big padding that doesn't work well with + // Jetpack, as we would like to display an iframe that completely fills + // the panel. + // -> Use a XBL wrapper with inner stylesheet to remove this padding. + let css = ".panel-inner-arrowcontent, .panel-arrowcontent {padding: 0;}"; + let originalXBL = "chrome://global/content/bindings/popup.xml#arrowpanel"; + let binding = + '' + + '' + + '' + + '' + + '' + + '' + + ''; + xulPanel.style.MozBinding = 'url("data:text/xml,' + + document.defaultView.encodeURIComponent(binding) + '")'; + + let frame = document.createElementNS(XUL_NS, 'iframe'); + frame.setAttribute('type', 'content'); + frame.setAttribute('flex', '1'); + frame.setAttribute('transparent', 'transparent'); + + // Load an empty document in order to have an immediatly loaded iframe, + // so swapFrameLoaders is going to work without having to wait for load. + frame.setAttribute("src","data:,"); + + xulPanel.appendChild(frame); + document.getElementById("mainPopupSet").appendChild(xulPanel); + } + let { width, height } = this, x, y, position; + + if (!anchor) { + // Open the popup in the middle of the window. + x = document.documentElement.clientWidth / 2 - width / 2; + y = document.documentElement.clientHeight / 2 - height / 2; + position = null; + } + else { + // Open the popup by the anchor. + let rect = anchor.getBoundingClientRect(); + + let window = anchor.ownerDocument.defaultView; + + let zoom = window.mozScreenPixelsPerCSSPixel; + let screenX = rect.left + window.mozInnerScreenX * zoom; + let screenY = rect.top + window.mozInnerScreenY * zoom; + + // Set up the vertical position of the popup relative to the anchor + // (always display the arrow on anchor center) + let horizontal, vertical; + if (screenY > window.screen.availHeight / 2 + height) + vertical = "top"; + else + vertical = "bottom"; + + if (screenY > window.screen.availWidth / 2 + width) + horizontal = "left"; + else + horizontal = "right"; + + let verticalInverse = vertical == "top" ? "bottom" : "top"; + position = vertical + "center " + verticalInverse + horizontal; + + // Allow panel to flip itself if the panel can't be displayed at the + // specified position (useful if we compute a bad position or if the + // user moves the window and panel remains visible) + xulPanel.setAttribute("flip","both"); + } + + // Resize the iframe instead of using panel.sizeTo + // because sizeTo doesn't work with arrow panels + xulPanel.firstChild.style.width = width + "px"; + xulPanel.firstChild.style.height = height + "px"; + + // Wait for the XBL binding to be constructed + function waitForBinding() { + if (!xulPanel.openPopup) { + timer.setTimeout(waitForBinding, 50); + return; + } + xulPanel.openPopup(anchor, position, x, y); + } + waitForBinding(); + + return this._public; + }, + /* Public API: Panel.hide */ + hide: function hide() { + // The popuphiding handler takes care of swapping back the frame loaders + // and removing the XUL panel from the application window, we just have to + // trigger it by hiding the popup. + // XXX Sometimes I get "TypeError: xulPanel.hidePopup is not a function" + // when quitting the host application while a panel is visible. To suppress + // them, this now checks for "hidePopup" in xulPanel before calling it. + // It's not clear if there's an actual issue or the error is just normal. + let xulPanel = this._xulPanel; + if (xulPanel && "hidePopup" in xulPanel) + xulPanel.hidePopup(); + return this._public; + }, + + /* Public API: Panel.resize */ + resize: function resize(width, height) { + this.width = width; + this.height = height; + this._xulPanel.sizeTo(width, height); + }, + + // While the panel is visible, this is the XUL we use to display it. + // Otherwise, it's null. + get _xulPanel() this.__xulPanel, + set _xulPanel(value) { + let xulPanel = this.__xulPanel; + if (value === xulPanel) return; + if (xulPanel) { + xulPanel.removeEventListener(ON_HIDE, this._onHide, false); + xulPanel.removeEventListener(ON_SHOW, this._onShow, false); + xulPanel.parentNode.removeChild(xulPanel); + } + if (value) { + value.addEventListener(ON_HIDE, this._onHide, false); + value.addEventListener(ON_SHOW, this._onShow, false); + } + this.__xulPanel = value; + }, + __xulPanel: null, + get _viewFrame() this.__xulPanel.children[0], + /** + * When the XUL panel becomes hidden, we swap frame loaders back to move + * the content of the panel to the hidden frame & remove panel element. + */ + _onHide: function _onHide() { + try { + this._frameLoadersSwapped = false; + this._xulPanel = null; + this._emit('hide'); + } catch(e) { + this._emit('error', e); + } + }, + /** + * When the XUL panel becomes shown, we swap frame loaders between panel + * frame and hidden frame to preserve state of the content dom. + */ + _onShow: function _onShow() { + try { + if (!this._inited) // defer if not initialized yet + return this.on('inited', this._onShow.bind(this)); + this._frameLoadersSwapped = true; + this._emit('show'); + } catch(e) { + this._emit('error', e); + } + }, + /** + * Notification that panel was fully initialized. + */ + _onInit: function _onInit() { + this._inited = true; + // perform all deferred tasks like initSymbiont, show, hide ... + // TODO: We're publicly exposing a private event here; this + // 'inited' event should really be made private, somehow. + this._emit('inited'); + this._removeAllListeners('inited'); + } +}); +exports.Panel = function(options) Panel(options) +exports.Panel.prototype = Panel.prototype; + +function getWindow(anchor) { + let window; + + if (anchor) { + let anchorWindow = anchor.ownerDocument.defaultView.top; + let anchorDocument = anchorWindow.document; + + let enumerator = windowMediator.getEnumerator("navigator:browser"); + while (enumerator.hasMoreElements()) { + let enumWindow = enumerator.getNext(); + + // Check if the anchor is in this browser window. + if (enumWindow == anchorWindow) { + window = anchorWindow; + break; + } + + // Check if the anchor is in a browser tab in this browser window. + let browser = enumWindow.gBrowser.getBrowserForDocument(anchorDocument); + if (browser) { + window = enumWindow; + break; + } + + // Look in other subdocuments (sidebar, etc.)? + } + } + + // If we didn't find the anchor's window (or we have no anchor), + // return the most recent browser window. + if (!window) + window = windowMediator.getMostRecentWindow("navigator:browser"); + + return window; +} + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/passwords.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/passwords.js new file mode 100644 index 00000000..7a0d79ce --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/passwords.js @@ -0,0 +1,82 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const { Trait } = require("light-traits"); +const utils = require("passwords/utils"); +const defer = require("utils/function").Enqueued; + +/** + * Utility function that returns `onComplete` and `onError` callbacks form the + * given `options` objects. Also properties are removed from the passed + * `options` objects. + * @param {Object} options + * Object that is passed to the exported functions of this module. + * @returns {Function[]} + * Array with two elements `onComplete` and `onError` functions. + */ +function getCallbacks(options) { + let value = [ + 'onComplete' in options ? defer(options.onComplete) : null, + 'onError' in options ? defer(options.onError) : defer(console.exception) + ]; + + delete options.onComplete; + delete options.onError; + + return value; +}; + +/** + * Creates a wrapper function that tries to call `onComplete` with a return + * value of the wrapped function or falls back to `onError` if wrapped function + * throws an exception. + */ +function createWrapperMethod(wrapped) { + return function (options) { + let [ onComplete, onError ] = getCallbacks(options); + try { + onComplete(wrapped(options)); + } catch (exception) { + onError(exception); + } + }; +} + +exports.search = createWrapperMethod(utils.search); +exports.store = createWrapperMethod(utils.store); +exports.remove = createWrapperMethod(utils.remove); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/private-browsing.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/private-browsing.js new file mode 100644 index 00000000..c2cb3296 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/private-browsing.js @@ -0,0 +1,94 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Paul O’Shannessy + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci} = require("chrome"); +const observers = require("observer-service"); +const { EventEmitter } = require("events"); +const { setTimeout } = require("timer"); +const unload = require("unload"); + +const ON_START = "start"; +const ON_STOP = "stop"; +const ON_TRANSITION = "private-browsing-transition-complete"; + +let pbService; +// Currently, only Firefox implements the private browsing service. +if (require("xul-app").is("Firefox")) { + pbService = Cc["@mozilla.org/privatebrowsing;1"]. + getService(Ci.nsIPrivateBrowsingService); +} + +const privateBrowsing = EventEmitter.compose({ + constructor: function PrivateBrowsing() { + // Binding method to instance since it will be used with `setTimeout`. + this._emitOnObject = this._emitOnObject.bind(this); + this.unload = this.unload.bind(this); + // Report unhandled errors from listeners + this.on("error", console.exception.bind(console)); + unload.ensure(this); + // We only need to add observers if `pbService` exists. + if (pbService) { + observers.add(ON_TRANSITION, this.onTransition.bind(this)); + this._isActive = pbService.privateBrowsingEnabled; + } + }, + unload: function _destructor() { + this._removeAllListeners(ON_START); + this._removeAllListeners(ON_STOP); + }, + // We don't need to do anything with cancel here. + onTransition: function onTransition() { + let isActive = this._isActive = pbService.privateBrowsingEnabled; + setTimeout(this._emitOnObject, 0, exports, isActive ? ON_START : ON_STOP); + }, + get isActive() this._isActive, + set isActive(value) { + if (pbService) + pbService.privateBrowsingEnabled = !!value; + }, + _isActive: false +})() + +Object.defineProperty(exports, "isActive", { + get: function() privateBrowsing.isActive +}); +exports.activate = function activate() privateBrowsing.isActive = true; +exports.deactivate = function deactivate() privateBrowsing.isActive = false; +exports.on = privateBrowsing.on; +exports.removeListener = privateBrowsing.removeListener; + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/request.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/request.js new file mode 100644 index 00000000..50da22a5 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/request.js @@ -0,0 +1,299 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Paul O’Shannessy (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const xpcom = require("xpcom"); +const xhr = require("xhr"); +const errors = require("errors"); +const apiUtils = require("api-utils"); + +// Ugly but will fix with: https://bugzilla.mozilla.org/show_bug.cgi?id=596248 +const EventEmitter = require('events').EventEmitter.compose({ + constructor: function EventEmitter() this +}); + +// Instead of creating a new validator for each request, just make one and reuse it. +const validator = new OptionsValidator({ + url: { + //XXXzpao should probably verify that url is a valid url as well + is: ["string"] + }, + headers: { + map: function (v) v || {}, + is: ["object"], + }, + content: { + map: function (v) v || null, + is: ["string", "object", "null"], + }, + contentType: { + map: function (v) v || "application/x-www-form-urlencoded", + is: ["string"] + } +}); + +const REUSE_ERROR = "This request object has been used already. You must " + + "create a new one to make a new request." + +function Request(options) { + const self = EventEmitter(), + _public = self._public; + // request will hold the actual XHR object + let request; + let response; + + if ('onComplete' in options) + self.on('complete', options.onComplete) + options = validator.validateOptions(options); + + // function to prep the request since it's the same between GET and POST + function makeRequest(mode) { + // If this request has already been used, then we can't reuse it. Throw an error. + if (request) { + throw new Error(REUSE_ERROR); + } + + request = new xhr.XMLHttpRequest(); + + let url = options.url; + // Build the data to be set. For GET requests, we want to append that to + // the URL before opening the request. + let data = makeQueryString(options.content); + if (mode == "GET" && data) { + // If the URL already has ? in it, then we want to just use & + url = url + (/\?/.test(url) ? "&" : "?") + data; + } + + // open the request + request.open(mode, url); + + // request header must be set after open, but before send + request.setRequestHeader("Content-Type", options.contentType); + + // set other headers + for (let k in options.headers) { + request.setRequestHeader(k, options.headers[k]); + } + + // handle the readystate, create the response, and call the callback + request.onreadystatechange = function () { + if (request.readyState == 4) { + response = new Response(request); + errors.catchAndLog(function () { + self._emit('complete', response); + })(); + } + } + + // actually send the request. we only want to send data on POST requests + request.send(mode == "POST" ? data : null); + } + + // Map these setters/getters to the options + ["url", "headers", "content", "contentType"].forEach(function (k) { + _public.__defineGetter__(k, function () options[k]); + _public.__defineSetter__(k, function (v) { + // This will automatically rethrow errors from apiUtils.validateOptions. + return options[k] = validator.validateSingleOption(k, v); + }); + }); + + // response should be available as a getter + _public.__defineGetter__("response", function () response); + + _public.get = function () { + makeRequest("GET"); + return this; + }; + + _public.post = function () { + makeRequest("POST"); + return this; + }; + + return _public; +} +exports.Request = Request; + +// Converts an object of unordered key-vals to a string that can be passed +// as part of a request +function makeQueryString(content) { + // Explicitly return null if we have null, and empty string, or empty object. + if (!content) { + return null; + } + + // If content is already a string, just return it as is. + if (typeof(content) == "string") { + return content; + } + + // At this point we have a k:v object. Iterate over it and encode each value. + // Arrays and nested objects will get encoded as needed. For example... + // + // { foo: [1, 2, { omg: "bbq", "all your base!": "are belong to us" }], bar: "baz" } + // + // will be encoded as + // + // foo[0]=1&foo[1]=2&foo[2][omg]=bbq&foo[2][all+your+base!]=are+belong+to+us&bar=baz + // + // Keys (including "[" and "]") and values will be encoded with + // fixedEncodeURIComponent before returning. + // + // Execution was inspired by jQuery, but some details have changed and numeric + // array keys are included (whereas they are not in jQuery). + + let encodedContent = []; + function add(key, val) { + encodedContent.push(fixedEncodeURIComponent(key) + "=" + + fixedEncodeURIComponent(val)); + } + + function make(key, val) { + if (typeof(val) == "object") { + for ([k, v] in Iterator(val)) { + make(key + "[" + k + "]", v); + } + } + else { + add(key, val) + } + } + for ([k, v] in Iterator(content)) { + make(k, v); + } + return encodedContent.join("&"); + + //XXXzpao In theory, we can just use a FormData object on 1.9.3, but I had + // trouble getting that working. It would also be nice to stay + // backwards-compat as long as possible. Keeping this in for now... + // let formData = Cc["@mozilla.org/files/formdata;1"]. + // createInstance(Ci.nsIDOMFormData); + // for ([k, v] in Iterator(content)) { + // formData.append(k, v); + // } + // return formData; +} + + +// encodes a string safely for application/x-www-form-urlencoded +// adheres to RFC 3986 +// see https://developer.mozilla.org/en/Core_JavaScript_1.5_Reference/Global_Functions/encodeURIComponent +function fixedEncodeURIComponent (str) { + return encodeURIComponent(str).replace(/%20/g, "+").replace(/!/g, "%21"). + replace(/'/g, "%27").replace(/\(/g, "%28"). + replace(/\)/g, "%29").replace(/\*/g, "%2A"); +} + +function Response(request) { + // Define the straight mappings of our value to original request value + xpcom.utils.defineLazyGetter(this, "text", function () request.responseText); + xpcom.utils.defineLazyGetter(this, "xml", function () { + throw new Error("Sorry, the 'xml' property is no longer available. " + + "see bug 611042 for more information."); + }); + xpcom.utils.defineLazyGetter(this, "status", function () request.status); + xpcom.utils.defineLazyGetter(this, "statusText", function () request.statusText); + + // this.json should be the JS object, so we need to attempt to parse it. + xpcom.utils.defineLazyGetter(this, "json", function () { + let _json = null; + try { + _json = JSON.parse(this.text); + } + catch (e) {} + return _json; + }); + + // this.headers also should be a JS object, so we need to split up the raw + // headers string provided by the request. + xpcom.utils.defineLazyGetter(this, "headers", function () { + let _headers = {}; + let lastKey; + // Since getAllResponseHeaders() will return null if there are no headers, + // defend against it by defaulting to "" + let rawHeaders = request.getAllResponseHeaders() || ""; + rawHeaders.split("\n").forEach(function (h) { + // According to the HTTP spec, the header string is terminated by an empty + // line, so we can just skip it. + if (!h.length) { + return; + } + + let index = h.indexOf(":"); + // The spec allows for leading spaces, so instead of assuming a single + // leading space, just trim the values. + let key = h.substring(0, index).trim(), + val = h.substring(index + 1).trim(); + + // For empty keys, that means that the header value spanned multiple lines. + // In that case we should append the value to the value of lastKey with a + // new line. We'll assume lastKey will be set because there should never + // be an empty key on the first pass. + if (key) { + _headers[key] = val; + lastKey = key; + } + else { + _headers[lastKey] += "\n" + val; + } + }); + return _headers; + }) +} + +// apiUtils.validateOptions doesn't give the ability to easily validate single +// options, so this is a wrapper that provides that ability. +function OptionsValidator(rules) { + this.rules = rules; + + this.validateOptions = function (options) { + return apiUtils.validateOptions(options, this.rules); + } + + this.validateSingleOption = function (field, value) { + // We need to create a single rule object from our listed rules. To avoid + // JavaScript String warnings, check for the field & default to an empty object. + let singleRule = {}; + if (field in this.rules) { + singleRule[field] = this.rules[field]; + } + let singleOption = {}; + singleOption[field] = value; + // This should throw if it's invalid, which will bubble up & out. + return apiUtils.validateOptions(singleOption, singleRule)[field]; + } +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/selection.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/selection.js new file mode 100644 index 00000000..3f8df65f --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/selection.js @@ -0,0 +1,353 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Eric H. Jung + * Irakli Gozalishivili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +if (!require("xul-app").is("Firefox")) { + throw new Error([ + "The selection module currently supports only Firefox. In the future ", + "we would like it to support other applications, however. Please see ", + "https://bugzilla.mozilla.org/show_bug.cgi?id=560716 for more information." + ].join("")); +} + +let { Ci } = require("chrome"), + { setTimeout } = require("timer"), + { EventEmitter } = require('events'); + +// The selection type HTML +const HTML = 0x01; + +// The selection type TEXT +const TEXT = 0x02; + +// The selection type DOM (internal use only) +const DOM = 0x03; + +/** + * Creates an object from which a selection can be set, get, etc. Each + * object has an associated with a range number. Range numbers are the + * 0-indexed counter of selection ranges as explained at + * https://developer.mozilla.org/en/DOM/Selection. + * + * @param rangeNumber + * The zero-based range index into the selection + */ +function Selection(rangeNumber) { + + // In order to hide the private rangeNumber argument from API consumers while + // still enabling Selection getters/setters to access it, the getters/setters + // are defined as lexical closures in the Selector constructor. + + this.__defineGetter__("text", function () getSelection(TEXT, rangeNumber)); + this.__defineSetter__("text", function (str) setSelection(str, rangeNumber)); + + this.__defineGetter__("html", function () getSelection(HTML, rangeNumber)); + this.__defineSetter__("html", function (str) setSelection(str, rangeNumber)); + + this.__defineGetter__("isContiguous", function () { + let sel = getSelection(DOM, rangeNumber); + // It isn't enough to check that rangeCount is zero. If one or more ranges + // are selected and then unselected, rangeCount is set to one, not zero. + // Therefore, if rangeCount is one, we also check if the selection is + // collapsed. + if (sel.rangeCount == 0) + return null; + if (sel.rangeCount == 1) { + let range = safeGetRange(sel, 0); + return range && range.collapsed ? null : true; + } + return false; + }); +} + +require("xpcom").utils.defineLazyServiceGetter(this, "windowMediator", + "@mozilla.org/appshell/window-mediator;1", "nsIWindowMediator"); + +/** + * Returns the most recent content window + */ +function context() { + // Overlay names should probably go into the xul-app module instead of here + return windowMediator.getMostRecentWindow("navigator:browser").document. + commandDispatcher.focusedWindow; +} + +/** + * Returns the current selection from most recent content window. Depending on + * the specified |type|, the value returned can be a string of text, stringified + * HTML, or a DOM selection object as described at + * https://developer.mozilla.org/en/DOM/Selection. + * + * @param type + * Specifies the return type of the selection. Valid values are the one + * of the constants HTML, TEXT, or DOM. + * + * @param rangeNumber + * Specifies the zero-based range index of the returned selection. + */ +function getSelection(type, rangeNumber) { + let window, selection; + try { + window = context(); + selection = window.getSelection(); + } + catch (e) { + return null; + } + + // Get the selected content as the specified type + if (type == DOM) + return selection; + else if (type == TEXT) { + let range = safeGetRange(selection, rangeNumber); + return range ? range.toString() : null; + } + else if (type == HTML) { + let range = safeGetRange(selection, rangeNumber); + // Another way, but this includes the xmlns attribute for all elements in + // Gecko 1.9.2+ : + // return Cc["@mozilla.org/xmlextras/xmlserializer;1"]. + // createInstance(Ci.nsIDOMSerializer).serializeToSTring(range. + // cloneContents()); + if (!range) + return null; + let node = window.document.createElement("span"); + node.appendChild(range.cloneContents()); + return node.innerHTML; + } + throw new Error("Type " + type + " is unrecognized."); +} + +/** + * Returns the specified range in a selection without throwing an exception. + * + * @param selection + * A selection object as described at + * https://developer.mozilla.org/en/DOM/Selection + * + * @param rangeNumber + * Specifies the zero-based range index of the returned selection. + */ +function safeGetRange(selection, rangeNumber) { + try { + let range = selection.getRangeAt(rangeNumber); + if (!range || range.toString() == "") + return null; + return range; + } + catch (e) { + return null; + } +} + +/** + * Sets the current selection of the most recent content document by changing + * the existing selected text/HTML range to the specified value. + * + * @param val + * The value for the new selection + * + * @param rangeNumber + * The zero-based range index of the selection to be set + * + */ +function setSelection(val, rangeNumber) { + // Make sure we have a window context & that there is a current selection. + // Selection cannot be set unless there is an existing selection. + let window, range; + try { + window = context(); + range = window.getSelection().getRangeAt(rangeNumber); + } + catch (e) { + // Rethrow with a more developer-friendly message than the caught + // exception. + throw new Error("It isn't possible to change the selection, as there isn't currently a selection"); + } + // Get rid of the current selection and insert our own + range.deleteContents(); + let node = window.document.createElement("span"); + range.surroundContents(node); + + // Some relevant JEP-111 requirements: + + // Setting the text property replaces the selection with the value to + // which the property is set and sets the html property to the same value + // to which the text property is being set. + + // Setting the html property replaces the selection with the value to + // which the property is set and sets the text property to the text version + // of the HTML value. + + // This sets both the HTML and text properties. + node.innerHTML = val; +} + +function onLoad(event) { + SelectionListenerManager.onLoad(event); +} + +function onUnload(event) { + SelectionListenerManager.onUnload(event); +} + +let SelectionListenerManager = { + QueryInterface: require("xpcom").utils.generateQI([Ci.nsISelectionListener]), + + // The collection of listeners wanting to be notified of selection changes + listeners: EventEmitter.compose({ + emit: function emit(type) this._emitOnObject(exports, type), + off: function() this._removeAllListeners.apply(this, arguments) + })(), + /** + * This is the nsISelectionListener implementation. This function is called + * by Gecko when a selection is changed interactively. + * + * We only pay attention to the SELECTALL, KEYPRESS, and MOUSEUP selection + * reasons. All reasons are listed here: + * + * http://mxr.mozilla.org/mozilla1.9.2/source/content/base/public/ + * nsISelectionListener.idl + * + * The other reasons (NO_REASON, DRAG_REASON, MOUSEDOWN_REASON) aren't + * applicable to us. + */ + notifySelectionChanged: function notifySelectionChanged(document, selection, + reason) { + if (!["SELECTALL", "KEYPRESS", "MOUSEUP"].some(function(type) reason & + Ci.nsISelectionListener[type + "_REASON"]) || selection.toString() == "") + return; + setTimeout(this.listeners.emit, 0, 'select') + }, + + /** + * Part of the Tracker implementation. This function is called by the + * tabs module when a browser is being tracked. Often, that means a new tab + * has been opened, but it can also mean an addon has been installed while + * tabs are already opened. In that case, this function is called for those + * already-opened tabs. + * + * @param browser + * The browser being tracked + */ + onTrack: function onTrack(browser) { + browser.addEventListener("load", onLoad, true); + browser.addEventListener("unload", onUnload, true); + }, + + onLoad: function onLoad(event) { + // Nothing to do without a useful window + let window = event.target.defaultView; + if (!window) + return; + + // Wrap the add selection call with some number of setTimeout 0 because some + // reason it's possible to add a selection listener "too early". 2 sometimes + // works for gmail, and more consistently with 3, so make it 5 to be safe. + let count = 0; + let self = this; + function wrap(count, func) { + if (count-- > 0) + require("timer").setTimeout(wrap, 0); + else + self.addSelectionListener(window); + } + wrap(); + }, + + addSelectionListener: function addSelectionListener(window) { + if (window.jetpack_core_selection_listener) + return; + let selection = window.getSelection(); + if (selection instanceof Ci.nsISelectionPrivate) + selection.addSelectionListener(this); + window.jetpack_core_selection_listener = true; + }, + + onUnload: function onUnload(event) { + // Nothing to do without a useful window + let window = event.target.defaultView; + if (!window) + return; + this.removeSelectionListener(window); + this.listeners.off('error'); + this.listeners.off('selection'); + }, + + removeSelectionListener: function removeSelectionListener(window) { + if (!window.jetpack_core_selection_listener) + return; + let selection = window.getSelection(); + if (selection instanceof Ci.nsISelectionPrivate) + selection.removeSelectionListener(this); + window.jetpack_core_selection_listener = false; + }, + + /** + * Part of the TabTracker implementation. This function is called by the + * tabs module when a browser is being untracked. Usually, that means a tab + * has been closed. + * + * @param browser + * The browser being untracked + */ + onUntrack: function onUntrack(browser) { + browser.removeEventListener("load", onLoad, true); + browser.removeEventListener("unload", onUnload, true); + } +}; +SelectionListenerManager.listeners.on('error', console.error); + +/** + * Install |SelectionListenerManager| as tab tracker in order to watch + * tab opening/closing + */ +require("tab-browser").Tracker(SelectionListenerManager); + +/** + * Exports an iterator so that discontiguous selections can be iterated. + */ +exports.__iterator__ = function __iterator__() { + for (let i = 0, sel = getSelection(DOM); i < sel.rangeCount; i++) + yield new Selection(i); +}; + +exports.on = SelectionListenerManager.listeners.on; +exports.removeListener = SelectionListenerManager.listeners.removeListener; + +// Export the Selection singleton. Its rangeNumber is always zero. +Selection.call(exports, 0); + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/simple-storage.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/simple-storage.js new file mode 100644 index 00000000..a2565238 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/simple-storage.js @@ -0,0 +1,258 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim:set ts=2 sw=2 sts=2 et filetype=javascript + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Drew Willcoxon (Original Author) + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci} = require("chrome"); +const file = require("file"); +const prefs = require("preferences-service"); +const jpSelf = require("self"); +const timer = require("timer"); +const unload = require("unload"); +const { EventEmitter } = require("events"); +const { Trait } = require("traits"); + +const WRITE_PERIOD_PREF = "extensions.addon-sdk.simple-storage.writePeriod"; +const WRITE_PERIOD_DEFAULT = 300000; // 5 minutes + +const QUOTA_PREF = "extensions.addon-sdk.simple-storage.quota"; +const QUOTA_DEFAULT = 5242880; // 5 MiB + +const JETPACK_DIR_BASENAME = "jetpack"; + + +// simpleStorage.storage +exports.__defineGetter__("storage", function () manager.root); +exports.__defineSetter__("storage", function (val) manager.root = val); + +// simpleStorage.quotaUsage +exports.__defineGetter__("quotaUsage", function () manager.quotaUsage); + +// A generic JSON store backed by a file on disk. This should be isolated +// enough to move to its own module if need be... +function JsonStore(options) { + this.filename = options.filename; + this.quota = options.quota; + this.writePeriod = options.writePeriod; + this.onOverQuota = options.onOverQuota; + this.onWrite = options.onWrite; + + unload.ensure(this); + + this.writeTimer = timer.setInterval(this.write.bind(this), + this.writePeriod); +} + +JsonStore.prototype = { + // The store's root. + get root() { + return this._root === undefined ? {} : this._root; + }, + + // Performs some type checking. + set root(val) { + let types = ["array", "boolean", "null", "number", "object", "string"]; + if (types.indexOf(typeof(val)) < 0) { + throw new Error("storage must be one of the following types: " + + types.join(", ")); + } + this._root = val; + return val; + }, + + // Percentage of quota used, as a number [0, Inf). > 1 implies over quota. + // Undefined if there is no quota. + get quotaUsage() { + return this.quota > 0 ? + JSON.stringify(this.root).length / this.quota : + undefined; + }, + + // Removes the backing file and all empty subdirectories. + purge: function JsonStore_purge() { + try { + // This'll throw if the file doesn't exist. + file.remove(this.filename); + let parentPath = this.filename; + do { + parentPath = file.dirname(parentPath); + // This'll throw if the dir isn't empty. + file.rmdir(parentPath); + } while (file.basename(parentPath) !== JETPACK_DIR_BASENAME); + } + catch (err) {} + }, + + // Initializes the root by reading the backing file. + read: function JsonStore_read() { + try { + let str = file.read(this.filename); + + // Ideally we'd log the parse error with console.error(), but logged + // errors cause tests to fail. Supporting "known" errors in the test + // harness appears to be non-trivial. Maybe later. + this.root = JSON.parse(str); + } + catch (err) { + this.root = {}; + } + }, + + // If the store is under quota, writes the root to the backing file. + // Otherwise quota observers are notified and nothing is written. + write: function JsonStore_write() { + if (this.quotaUsage > 1) + this.onOverQuota(this); + else + this._write(); + }, + + // Cleans up on unload. If unloading because of uninstall, the store is + // purged; otherwise it's written. + unload: function JsonStore_unload(reason) { + timer.clearInterval(this.writeTimer); + this.writeTimer = null; + + if (reason === "uninstall") + this.purge(); + else + this._write(); + }, + + // True if the root is an empty object. + get _isEmpty() { + if (this.root && typeof(this.root) === "object") { + let empty = true; + for (let key in this.root) { + empty = false; + break; + } + return empty; + } + return false; + }, + + // Writes the root to the backing file, notifying write observers when + // complete. If the store is over quota or if it's empty and the store has + // never been written, nothing is written and write observers aren't notified. + _write: function JsonStore__write() { + // If the store is empty and the file doesn't yet exist, don't write. + if (this._isEmpty && !file.exists(this.filename)) + return; + + // If the store is over quota, don't write. The current under-quota state + // should persist. + if (this.quotaUsage > 1) + return; + + // Finally, write. + let stream = file.open(this.filename, "w"); + try { + stream.writeAsync(JSON.stringify(this.root), function writeAsync(err) { + if (err) + console.error("Error writing simple storage file: " + this.filename); + else if (this.onWrite) + this.onWrite(this); + }.bind(this)); + } + catch (err) { + // writeAsync closes the stream after it's done, so only close on error. + stream.close(); + } + } +}; + + +// This manages a JsonStore singleton and tailors its use to simple storage. +// The root of the JsonStore is lazy-loaded: The backing file is only read the +// first time the root's gotten. +let manager = Trait.compose(EventEmitter, Trait.compose({ + jsonStore: null, + + // The filename of the store, based on the profile dir and extension ID. + get filename() { + let storeFile = Cc["@mozilla.org/file/directory_service;1"]. + getService(Ci.nsIProperties). + get("ProfD", Ci.nsIFile); + storeFile.append(JETPACK_DIR_BASENAME); + storeFile.append(jpSelf.id); + storeFile.append("simple-storage"); + file.mkpath(storeFile.path); + storeFile.append("store.json"); + return storeFile.path; + }, + + get quotaUsage() { + return this.jsonStore.quotaUsage; + }, + + get root() { + if (!this.rootInited) { + this.jsonStore.read(); + this.rootInited = true; + } + return this.jsonStore.root; + }, + + set root(val) { + let rv = this.jsonStore.root = val; + this.rootInited = true; + return rv; + }, + + unload: function manager_unload() { + this._removeAllListeners("OverQuota"); + this._removeAllListeners("error"); + }, + + constructor: function manager_constructor() { + // Log unhandled errors. + this.on("error", console.exception.bind(console)); + unload.ensure(this); + + this.jsonStore = new JsonStore({ + filename: this.filename, + writePeriod: prefs.get(WRITE_PERIOD_PREF, WRITE_PERIOD_DEFAULT), + quota: prefs.get(QUOTA_PREF, QUOTA_DEFAULT), + onOverQuota: this._emitOnObject.bind(this, exports, "OverQuota") + }); + } +}))(); + +exports.on = manager.on; +exports.removeListener = manager.removeListener; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/tabs.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/tabs.js new file mode 100644 index 00000000..38fec362 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/tabs.js @@ -0,0 +1,62 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dietrich Ayala (Original author) + * Felipe Gomes + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +if (!require("xul-app").is("Firefox")) { + throw new Error([ + "The tabs module currently supports only Firefox. In the future ", + "we would like it to support other applications, however. Please see ", + "https://bugzilla.mozilla.org/show_bug.cgi?id=560716 for more information." + ].join("")); +} + +const { browserWindows } = require("windows"); +const { tabs } = require("windows/tabs"); + +Object.defineProperties(tabs, { + open: { value: function open(options) { + if (options.inNewWindow) + // `tabs` option is under review and may be removed. + return browserWindows.open({ tabs: [ options ] }); + // Open in active window if new window was not required. + return browserWindows.activeWindow.tabs.open(options); + }} +}); +// It's a hack but we will be able to remove it once will implemnet CommonJS +// feature that would allow us to override exports. +exports.__proto__ = tabs; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/widget.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/widget.js new file mode 100644 index 00000000..541218a0 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/widget.js @@ -0,0 +1,656 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Dietrich Ayala (Original Author) + * Drew Willcoxon + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc, Ci} = require("chrome"); + +// Widget content types +const CONTENT_TYPE_URI = 1; +const CONTENT_TYPE_HTML = 2; +const CONTENT_TYPE_IMAGE = 3; + +const ERR_CONTENT = "No content or contentURL property found. Widgets must " + + "have one or the other.", + ERR_LABEL = "The widget must have a non-empty label property."; + +// Supported events, mapping from DOM event names to our event names +const EVENTS = { + "click": "click", + "mouseover": "mouseover", + "mouseout": "mouseout", +}; + +if (!require("xul-app").is("Firefox")) { + throw new Error([ + "The widget module currently supports only Firefox. In the future ", + "it will support other applications. Please see ", + "https://bugzilla.mozilla.org/show_bug.cgi?id=560716 for more information." + ].join("")); +} + +const { validateOptions } = require("api-utils"); +const panels = require("panel"); +const { EventEmitter } = require("events"); +const { Trait } = require("traits"); +const { Loader, Symbiont } = require("content"); + +const valid = { + number: { is: ["null", "undefined", "number"] }, + string: { is: ["null", "undefined", "string"] }, + label: { + is: ["string"], + ok: function (v) v.length > 0, + msg: ERR_LABEL + }, + panel: { + is: ["null", "undefined", "object"], + ok: function(v) !v || v instanceof panels.Panel + } +} + +function validate(name, suspect, validation) { + let $1 = {} + $1[name] = suspect + let $2 = {} + $2[name] = validation + return validateOptions($1, $2)[name] +} + +const eventBus = Trait.compose(EventEmitter, Trait.compose({ + constructor: function EventBus() this +}))(); + +// The widget object. +const Widget = Trait.compose(Loader, Trait.compose({ + constructor: function Widget(options) { + + eventBus.on('event', this._onEvent.bind(this)); + this.on('error', this._defaultErrorHandler.bind(this)); + + this._label = validate("label", options.label, valid.label); + + this.tooltip = "tooltip" in options ? options.tooltip : this._label + + if ("id" in options) + this._id = options.id; + else + console.warn('You have to define an unique "id" attribute to your widget ' + + 'in order to be able to remember its position.'); + + browserManager.validate(this._public); + + if ("width" in options) + this.width = options.width; + if ("panel" in options) + this.panel = options.panel; + + if ("onClick" in options) + this.on("click", options.onClick); + if ("onMouseover" in options) + this.on("mouseover", options.onMouseover); + if ("onMouseout" in options) + this.on("mouseout", options.onMouseout); + if ("content" in options) + this._content = options.content; + if ("contentURL" in options) + this.contentURL = options.contentURL; + + if ("contentScriptWhen" in options) + this.contentScriptWhen = options.contentScriptWhen; + if ("contentScriptFile" in options) + this.contentScriptFile = options.contentScriptFile; + if ("contentScript" in options) + this.contentScript = options.contentScript; + if ("allow" in options) + this.allow = options.allow; + if ("onError" in options) + this.on("error", options.onError); + if ("onMessage" in options) + this.on("message", options.onMessage); + + if (!(this._content || this.contentURL)) + throw new Error(ERR_CONTENT); + + let self = this; + this.on('propertyChange', function(change) { + if ('contentURL' in change) + browserManager.updateItem(self._public, "contentURL", self.contentURL); + }); + + browserManager.addItem(this._public); + }, + + _defaultErrorHandler: function Widget__defaultErrorHandler(e) { + if (1 == this._listeners('error').length) + console.exception(e) + }, + + _onEvent: function Widget__onEvent(type, target, eventData, domNode) { + if (target === this._public) { + this._emit(type, eventData); + + // Special case for click events: if the widget doesn't have a click + // handler, but it does have a panel, display the panel. + if ("click" == type && !this._listeners("click").length && this.panel) + this.panel.show(domNode); + } + }, + + get id() this._id, + _id: null, + + get label() this._label, + _label: null, + + get width() this._width, + set width(value) { + value = validate("width", value, valid.number); + if (null === value || undefined === value) value = 16; + if (value !== this._width) + browserManager.updateItem(this._public, "width", this._width = value); + }, + _width: 16, + + get tooltip() this._tooltip, + set tooltip(value) { + value = validate("tooltip", value, valid.string); + if (value !== this._tooltip) + browserManager.updateItem(this._public, "tooltip", this._tooltip = value); + }, + _tooltip: null, + + get content() this._content, + set content(value) { + value = validate("content", value, valid.string); + if (value !== this._content) + browserManager.updateItem(this._public, "content", this._content = value); + }, + _content: null, + + get panel() this._panel, + set panel(value) { + value = validate("panel", value, valid.panel); + if (value !== this._panel) + this._panel = value; + }, + _panel: null, + + postMessage: function Widget_postMessage(message) { + browserManager.updateItem(this._public, "postMessage", message); + }, + + destroy: function Widget_destroy() { + browserManager.removeItem(this._public); + } +})); +exports.Widget = function(options) Widget(options); +exports.Widget.prototype = Widget.prototype; + +// Keeps track of all browser windows. +// Exposes methods for adding/removing/updating widgets +// across all open windows (and future ones). +let browserManager = { + items: [], + windows: [], + + // Registers the manager to listen for window openings and closings. Note + // that calling this method can cause onTrack to be called immediately if + // there are open windows. + init: function () { + let windowTracker = new (require("window-utils").WindowTracker)(this); + require("unload").ensure(windowTracker); + }, + + // Registers a window with the manager. This is a WindowTracker callback. + onTrack: function browserManager_onTrack(window) { + if (this._isBrowserWindow(window)) { + let win = new BrowserWindow(window); + win.addItems(this.items); + this.windows.push(win); + } + }, + + // Unregisters a window from the manager. It's told to undo all + // modifications. This is a WindowTracker callback. Note that when + // WindowTracker is unloaded, it calls onUntrack for every currently opened + // window. The browserManager therefore doesn't need to specially handle + // unload itself, since unloading the browserManager means untracking all + // currently opened windows. + onUntrack: function browserManager_onUntrack(window) { + if (this._isBrowserWindow(window)) { + for (let i = 0; i < this.windows.length; i++) { + if (this.windows[i].window == window) { + let win = this.windows.splice(i, 1)[0]; + win.destroy(); + return; + } + } + } + }, + + // Used to validate widget by browserManager before adding it, + // in order to check input very early in widget constructor + validate : function (item) { + let idx = this.items.indexOf(item); + if (idx > -1) + throw new Error("The widget " + item + " has already been added."); + if (item.id) { + let sameId = this.items.filter(function(i) i.id == item.id); + if (sameId.length > 0) + throw new Error("This widget ID is already used: " + item.id); + } else { + item.id = this.items.length; + } + }, + + // Registers an item with the manager. It's added to all currently registered + // windows, and when new windows are registered it will be added to them, too. + addItem: function browserManager_addItem(item) { + this.items.push(item); + this.windows.forEach(function (w) w.addItems([item])); + }, + + // Updates the content of an item registered with the manager, + // propagating the change to all windows. + updateItem: function browserManager_updateItem(item, property, value) { + let idx = this.items.indexOf(item); + if (idx != -1) + this.windows.forEach(function (w) w.updateItem(item, property, value)); + }, + + // Unregisters an item from the manager. It's removed from all windows that + // are currently registered. + removeItem: function browserManager_removeItem(item) { + let idx = this.items.indexOf(item); + if (idx > -1) { + this.items.splice(idx, 1); + if (item.panel) + item.panel.destroy(); + this.windows.forEach(function (w) w.removeItems([item])); + } + }, + + _isBrowserWindow: function browserManager__isBrowserWindow(win) { + let winType = win.document.documentElement.getAttribute("windowtype"); + return winType === "navigator:browser"; + } +}; + +// Keeps track of a single browser window. Responsible for providing a +// description of the window's current context and determining whether an item +// matches the current context. +// +// This is where the core of how a widget's content is added to a window lives. +// +// TODO: If other apps besides Firefox want to support the add-on bar in +// whatever way is appropriate for them, plugging in a substitute for this class +// should be the way to do it. Make it easy for them. See bug 560716. +function BrowserWindow(window) { + this.window = window; + this.doc = window.document; + this._init(); +} + +BrowserWindow.prototype = { + + _init: function BW__init() { + // Array of objects: + // { + // widget: widget object, + // node: dom node, + // eventListeners: hash of event listeners + // symbiont: contentSymbiont + // } + this._items = []; + + }, + + get container() { + if (!this._container) { + // If being run in a version of Firefox <4, create a separate + // addon bar. TODO: just use the status bar? + let container = this.doc.getElementById("addon-bar"); + if (!container) { + let toolbox = this.doc.createElement("toolbox"); + + // Share browser's palette. + let browserToolbox = this.doc.getElementById("navigator-toolbox"); + toolbox.palette = browserToolbox.palette; + + container = this.doc.createElement("toolbar"); + container.setAttribute("id", "addon-bar"); + container.setAttribute("customizable", "true"); + // TODO: needs localization + container.setAttribute("toolbarname", "Add-ons Toolbar"); + + container.setAttribute("align", "right"); + container.style.minHeight = "18px"; + container.style.padding = "2px"; + container.style.margin = "0px"; + + toolbox.appendChild(container); + + let statusbar = this.doc.getElementById("status-bar"); + statusbar.parentNode.insertBefore(toolbox, statusbar); + } + + this._container = container; + } + return this._container; + }, + + // Adds an array of items to the window. + addItems: function BW_addItems(items) { + items.forEach(this._addItemToWindow, this); + }, + + // Update a property of a widget. + updateItem: function BW_updateItem(updatedItem, property, value) { + let item = this._items.filter(function(item) item.widget == updatedItem).shift(); + if (item) { + switch(property) { + case "contentURL": + case "content": + this.setContent(item); + break; + case "width": + item.node.style.minWidth = value + "px"; + item.node.querySelector("iframe").style.width = value + "px"; + break; + case "tooltip": + item.node.setAttribute("tooltiptext", value); + break; + case "postMessage": + item.symbiont.postMessage(value); + break; + } + } + }, + + // Add a widget to this window. + _addItemToWindow: function BW__addItemToWindow(widget) { + // XUL element container for widget + let node = this.doc.createElement("toolbaritem"); + let guid = require("xpcom").makeUuid().toString(); + + // Temporary fix around require("self") failing on unit-test execution ... + let jetpackID = "testID"; + try { + jetpackID = require("self").id; + } catch(e) {} + + // Compute an unique and stable widget id with jetpack id and widget.id + let id = "widget:" + jetpackID + "-" + widget.id; + node.setAttribute("id", id); + node.setAttribute("label", widget.label); + node.setAttribute("tooltiptext", widget.tooltip); + node.setAttribute("align", "center"); + + // TODO move into a stylesheet, configurable by consumers. + // Either widget.style, exposing the style object, or a URL + // (eg, can load local stylesheet file). + node.setAttribute("style", [ + "overflow: hidden; margin: 1px 2px 1px 2px; padding: 0px;", + "min-height: 16px;", + ].join("")); + + node.style.minWidth = widget.width + "px"; + + // Add to the customization palette + let toolbox = this.doc.getElementById("navigator-toolbox"); + let palette = toolbox.palette; + palette.appendChild(node); + + // Search for widget toolbar by reading toolbar's currentset attribute + let container = null; + let toolbars = this.doc.getElementsByTagName("toolbar"); + for(let i = 0, l = toolbars.length; i < l; i++) { + let toolbar = toolbars[i]; + if (toolbar.getAttribute("currentset").indexOf(id) == -1) + continue; + container = toolbar; + } + + // if widget isn't in any toolbar, add it to the addon-bar + // TODO: we may want some "first-launch" module to do this only on very + // first execution + if (!container) { + // TODO: find a way to make the following code work when we use "cfx run": + // http://mxr.mozilla.org/mozilla-central/source/browser/base/content/browser.js#8586 + // until then, force display of addon bar directly from sdk code + // https://bugzilla.mozilla.org/show_bug.cgi?id=627484 + if (this.container.collapsed) + this.window.toggleAddonBar(); + container = this.container; + } + + // Now retrieve a reference to the next toolbar item + // by reading currentset attribute on the toolbar + let nextNode = null; + let currentSet = container.getAttribute("currentset"); + let ids = (currentSet == "__empty") ? [] : currentSet.split(","); + let idx = ids.indexOf(id); + if (idx != -1) { + for(let i = idx; i < ids.length; i++) { + nextNode = this.doc.getElementById(ids[i]); + if (nextNode) + break; + } + } + + // Finally insert our widget in the right toolbar and in the right position + container.insertItem(id, nextNode, null, false); + + let item = {widget: widget, node: node}; + + this._fillItem(item); + + this._items.push(item); + }, + + // Initial population of a widget's content. + _fillItem: function BS__fillItem(item) { + // Create element + var iframe = this.doc.createElement("iframe"); + iframe.setAttribute("type", "content"); + iframe.setAttribute("transparent", "transparent"); + iframe.style.overflow = "hidden"; + iframe.style.height = "16px"; + iframe.style.maxHeight = "16px"; + iframe.style.width = item.widget.width + "px"; + iframe.setAttribute("flex", "1"); + iframe.style.border = "none"; + iframe.style.padding = "0px"; + + // Do this early, because things like contentWindow are null + // until the node is attached to a document. + item.node.appendChild(iframe); + + // add event handlers + this.addEventHandlers(item); + + // set content + this.setContent(item); + }, + + // Get widget content type. + getContentType: function BW_getContentType(widget) { + if (widget.content) + return CONTENT_TYPE_HTML; + return (widget.contentURL && /\.(jpg|gif|png|ico)$/.test(widget.contentURL)) + ? CONTENT_TYPE_IMAGE : CONTENT_TYPE_URI; + }, + + // Set widget content. + setContent: function BW_setContent(item) { + let type = this.getContentType(item.widget); + let contentURL = null; + + switch (type) { + case CONTENT_TYPE_HTML: + contentURL = "data:text/html," + encodeURI(item.widget.content); + break; + case CONTENT_TYPE_URI: + contentURL = item.widget.contentURL; + break; + case CONTENT_TYPE_IMAGE: + let imageURL = item.widget.contentURL; + contentURL = "data:text/html,"; + break; + default: + throw new Error("The widget's type cannot be determined."); + } + + let iframe = item.node.firstElementChild; + + item.symbiont = Symbiont({ + frame: iframe, + contentURL: contentURL, + contentScriptFile: item.widget.contentScriptFile, + contentScript: item.widget.contentScript, + contentScriptWhen: item.widget.contentScriptWhen, + allow: item.widget.allow, + onMessage: function(message) { + require("timer").setTimeout(function() { + eventBus._emit("event", "message", item.widget, message); + }, 0); + } + }); + }, + + // Set up all supported events for a widget. + addEventHandlers: function BW_addEventHandlers(item) { + let contentType = this.getContentType(item.widget); + + // Detect if document consists of a single image. + function isImageDoc(doc) { + return doc.body.childNodes.length == 1 && + doc.body.firstElementChild && + doc.body.firstElementChild.tagName == "IMG"; + } + + let listener = function(e) { + // Ignore event firings that target the iframe. + if (e.target == item.node.firstElementChild) + return; + + // The widget only supports left-click for now, + // so ignore right-clicks. + if (e.type == "click" && e.button == 2) + return; + + // Proxy event to the widget + require("timer").setTimeout(function() { + eventBus._emit("event", EVENTS[e.type], item.widget, null, item.node); + }, 0); + }; + + item.eventListeners = {}; + let iframe = item.node.firstElementChild; + for (let [type, method] in Iterator(EVENTS)) { + iframe.addEventListener(type, listener, true, true); + + // Store listeners for later removal + item.eventListeners[type] = listener; + } + + // On document load, make modifications required for nice default + // presentation. + function loadListener(e) { + // Ignore event firings that target the iframe + if (e.target == iframe) + return; + // Ignore about:blank loads + if (e.type == "load" && e.target.location == "about:blank") + return; + let doc = e.target; + if (contentType == CONTENT_TYPE_IMAGE || isImageDoc(doc)) { + // Force image content to size. + // Add-on authors must size their images correctly. + doc.body.firstElementChild.style.width = item.widget.width + "px"; + doc.body.firstElementChild.style.height = "16px"; + } + + // Allow all content to fill the box by default. + doc.body.style.margin = "0"; + } + iframe.addEventListener("load", loadListener, true, true); + item.eventListeners["load"] = loadListener; + }, + + // Removes an array of items from the window. + removeItems: function BW_removeItems(removedItems) { + removedItems.forEach(function(removedItem) { + let entry = this._items.filter(function(entry) entry.widget == removedItem).shift(); + if (entry) { + // remove event listeners + for (let [type, listener] in Iterator(entry.eventListeners)) + entry.node.firstElementChild.removeEventListener(type, listener, true); + // remove dom node + entry.node.parentNode.removeChild(entry.node); + // remove entry + this._items.splice(this._items.indexOf(entry), 1); + // cleanup symbiont + entry.symbiont.destroy(); + // cleanup entry itself + entry.eventListeners = null; + entry.widget = null; + entry.symbiont = null; + } + }, this); + }, + + // Undoes all modifications to the window. The BrowserWindow + // should not be used afterward. + destroy: function BW_destroy() { + // Remove all items from the panel + let len = this._items.length; + for (let i = 0; i < len; i++) + this.removeItems([this._items[0].widget]); + + this.window.removeEventListener("keypress", this, false); + } +}; + +// Init the browserManager only after setting prototypes and such above, because +// it will cause browserManager.onTrack to be called immediately if there are +// open windows. +browserManager.init(); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/windows.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/windows.js new file mode 100644 index 00000000..0f82536b --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-addon-kit-lib/windows.js @@ -0,0 +1,236 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Felipe Gomes (Original author) + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +if (!require("xul-app").is("Firefox")) { + throw new Error([ + "The windows module currently supports only Firefox. In the future", + " we would like it to support other applications, however. Please see ", + "https://bugzilla.mozilla.org/show_bug.cgi?id=571449 for more information." + ].join("")); +} + +const { Cc, Ci } = require('chrome'), + { Trait } = require('traits'), + { List } = require('list'), + { EventEmitter } = require('events'), + { WindowTabs, WindowTabTracker } = require('windows/tabs'), + { WindowDom } = require('windows/dom'), + { WindowLoader } = require('windows/loader'), + { WindowTrackerTrait } = require('window-utils'), + { Options } = require('tabs/tab'), + // { Sidebars } = require('window/sidebars'); + { utils } = require('xpcom'), + apiUtils = require('api-utils'), + unload = require('unload'), + + WM = Cc['@mozilla.org/appshell/window-mediator;1']. + getService(Ci.nsIWindowMediator), + + BROWSER = 'navigator:browser'; + +/** + * Window trait composes safe wrappers for browser window that are E10S + * compatible. + */ +const BrowserWindowTrait = Trait.compose( + EventEmitter, + WindowDom.resolve({ close: '_close' }), + WindowTabs, + WindowTabTracker, + WindowLoader, + /* WindowSidebars, */ + Trait.compose({ + _emit: Trait.required, + _close: Trait.required, + _load: Trait.required, + /** + * Constructor returns wrapper of the specified chrome window. + * @param {nsIWindow} window + */ + constructor: function BrowserWindow(options) { + // make sure we don't have unhandled errors + this.on('error', console.exception.bind(console)); + + if ('onOpen' in options) + this.on('open', options.onOpen); + if ('onClose' in options) + this.on('close', options.onClose); + if ('window' in options) + this._window = options.window; + if ('tabs' in options) { + this._tabOptions = Array.isArray(options.tabs) ? + options.tabs.map(Options) : + [ Options(options.tabs) ]; + } + else if ('url' in options) { + this._tabOptions = [ Options(options.url) ]; + } + this._load(); + return this; + }, + _tabOptions: [], + _onLoad: function() { + try { + this._initWindowTabTracker(); + } catch(e) { + this._emit('error', e) + } + this._emitOnObject(browserWindows, 'open', this._public); + }, + _onUnload: function() { + this._destroyWindowTabTracker(); + this._emitOnObject(browserWindows, 'close', this._public); + this._window = null; + // Removing reference from the windows array. + windows.splice(windows.indexOf(this), 1); + this._removeAllListeners('close'); + this._removeAllListeners('open'); + this._removeAllListeners('ready'); + }, + close: function close(callback) { + // maybe we should deprecate this with message ? + if (callback) this.on('close', callback); + return this._close(); + } + }) +); +/** + * Wrapper for `BrowserWindowTrait`. Creates new instance if wrapper for + * window doesn't exists yet. If wrapper already exists then returns it + * instead. + * @params {Object} options + * Options that are passed to the the `BrowserWindowTrait` + * @returns {BrowserWindow} + * @see BrowserWindowTrait + */ +function BrowserWindow(options) { + let chromeWindow = options.window; + for each (let window in windows) { + if (chromeWindow == window._window) + return window._public + } + let window = BrowserWindowTrait(options); + windows.push(window); + return window._public; +} +// to have proper `instanceof` behavior will go away when #596248 is fixed. +BrowserWindow.prototype = BrowserWindowTrait.prototype; +exports.BrowserWindow = BrowserWindow +const windows = []; +/** + * `BrowserWindows` trait is composed out of `List` trait and it represents + * "live" list of currently open browser windows. Instance mutates itself + * whenever new browser window gets opened / closed. + */ +// Very stupid to resolve all `toStrings` but this will be fixed by #596248 +const browserWindows = Trait.resolve({ toString: null }).compose( + List.resolve({ constructor: '_initList' }), + EventEmitter.resolve({ toString: null }), + WindowTrackerTrait.resolve({ constructor: '_initTracker', toString: null }), + Trait.compose({ + _emit: Trait.required, + _add: Trait.required, + _remove: Trait.required, + + // public API + + /** + * Constructor creates instance of `Windows` that represents live list of open + * windows. + */ + constructor: function BrowserWindows() { + this._trackedWindows = []; + this._initList(); + this._initTracker(); + unload.when(this._destructor.bind(this)); + }, + _destructor: function _destructor() { + this._removeAllListeners('open'); + this._removeAllListeners('close'); + }, + /** + * This property represents currently active window. + * Property is non-enumerable, in order to preserve array like enumeration. + * @type {Window|null} + */ + get activeWindow() { + let window = WM.getMostRecentWindow(BROWSER); + return this._isBrowser(window) ? BrowserWindow({ window: window }) : null; + }, + open: function open(options) { + if (typeof options === "string") + // `tabs` option is under review and may be removed. + options = { tabs: [Options(options)] }; + return BrowserWindow(options); + }, + /** + * Returns true if specified window is a browser window. + * @param {nsIWindow} window + * @returns {Boolean} + */ + _isBrowser: function _isBrowser(window) + BROWSER === window.document.documentElement.getAttribute("windowtype") + , + /** + * Internal listener which is called whenever new window gets open. + * Creates wrapper and adds to this list. + * @param {nsIWindow} chromeWindow + */ + _onTrack: function _onTrack(chromeWindow) { + if (!this._isBrowser(chromeWindow)) return; + let window = BrowserWindow({ window: chromeWindow }); + this._add(window); + this._emit('open', window); + }, + /** + * Internal listener which is called whenever window gets closed. + * Cleans up references and removes wrapper from this list. + * @param {nsIWindow} window + */ + _onUntrack: function _onUntrack(chromeWindow) { + if (!this._isBrowser(chromeWindow)) return; + let window = BrowserWindow({ window: chromeWindow }); + // `_onUnload` method of the `BrowserWindow` will remove `chromeWindow` + // from the `windows` array. + this._remove(window); + this._emit('close', window); + } + }).resolve({ toString: null }) +)(); +exports.browserWindows = browserWindows; + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-data/bootstrap-remote-process.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-data/bootstrap-remote-process.js new file mode 100644 index 00000000..6fb17ebe --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-data/bootstrap-remote-process.js @@ -0,0 +1,212 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// This is the first code that's ever run in a Jetpack process. It sets up +// infrastructure and receivers needed to start a Jetpack-based addon +// in a separate process. + +// A list of scripts to inject into all new CommonJS module sandboxes. +var injectedSandboxScripts = []; + +// A table of all CommonJS modules currently loaded. +var modules = {}; + +// This object represents the chrome process, and can be used to +// communicate with it. +var chrome = { + createHandle: function() { + return createHandle(); + }, + on: function(type, listener) { + registerReceiver(type, listener); + }, + removeListener: function(type, listener) { + unregisterReceiver(type, listener); + }, + send: function(type) { + sendMessage.apply(this, arguments); + }, + call: function(name) { + var result = callMessage.apply(this, arguments); + + if (result.length > 1) + throw new Error("More than one result received for call '" + name + + "': " + result.length); + + if (result.length == 0) + throw new Error("No receiver registered for call '" + name + "'"); + + if (result[0].exception) { + throw Object.create(Error.prototype, { + message: { value: result[0].exception.message, enumerable: true }, + fileName: { value: result[0].exception.fileName, enumerable: true }, + lineNumber: { value: result[0].exception.lineNumber, enumerable: true }, + // Concatenate the stack from the other process with one from this + // process, so callers have access to the full stack. + stack: { value: result[0].exception.stack + (new Error()).stack, + enumerable: true } + }); + } + + return result[0].returnValue; + } +}; + +// Use this for really low-level debugging of this script. +function dump(msg) { + // Don't use chrome.send() to avoid infinite recursion when + // debugging chrome.send() itself. + sendMessage("dump", msg); +} + +// Taken from plain-text-console.js. +function stringify(arg) { + try { + return String(arg); + } + catch(ex) { + return ""; + } +} + +// Set up our "proxy" objects that just send messages to our parent +// process to do the real work. +var console = { + exception: function(e) { + chrome.send('console:exception', e); + }, + trace: function() { + chrome.send('console:trace', new Error()); + } +}; + +['log', 'debug', 'info', 'warn', 'error'].forEach(function(method) { + console[method] = function() { + chrome.send('console:' + method, Array.map(arguments, stringify)); + } +}); + +var memory = { + track: function() { + /* TODO */ + } +}; + +function makeRequire(base) { + var resolvedNames = {}; + + function require(name) { + // first, have we already require()d this name from this base? Just + // re-use the module + if (name && name in resolvedNames) + return resolvedNames[name].exports; + + // if not, resolve relative import names by asking the browser-process + // side for the URL/filename of the module this points to + var response = chrome.call("require", base, name); + switch (response.code) { + case "not-found": + throw new Error("Unknown module '" + name + "'."); + case "access-denied": + throw new Error("Module '" + name + "' requires chrome privileges " + + "and has no e10s adapter."); + case "error": + throw new Error("An unexpected error occurred in the chrome " + + "process."); + case "ok": + break; + default: + throw new Error("Internal error: unknown response code '" + + response.code + "'"); + }; + + // do we already have a module for this filename? + if (response.script.filename in modules) { + module = resolvedNames[name] = modules[response.script.filename]; + return module.exports; + } + + var module = createSandbox(); + + function injectScript(script) { + evalInSandbox(module, '//@line 1 "' + script.filename + + '"\n' + script.contents); + } + + injectedSandboxScripts.forEach(injectScript); + + modules[response.script.filename] = resolvedNames[name] = module; + + // Set up the globals of the sandbox. + module.exports = {}; + module.console = console; + module.memory = memory; + module.require = makeRequire(response.script.filename); + module.__url__ = response.script.filename; + + if (response.needsMessaging) + module.chrome = chrome; + + injectScript(response.script); + + return module.exports; + }; + return require; +} + +chrome.on( + "addInjectedSandboxScript", + function(name, script) { + injectedSandboxScripts.push(script); + }); + +chrome.on( + "startMain", + function(name, mainName, options) { + var mainRequire = makeRequire(null); + var main = mainRequire(mainName); + + var callbacks = { + quit: function quit(status) { + if (status === undefined) + status = "OK"; + chrome.send("quit", status); + } + }; + + if ('main' in main) + main.main(options, callbacks); + }); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-data/test-content-symbiont.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-data/test-content-symbiont.js new file mode 100644 index 00000000..e69de29b diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js new file mode 100644 index 00000000..a28aec20 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/api-utils.js @@ -0,0 +1,184 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Drew Willcoxon (Original Author) + * Edward Lee + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// The possible return values of getTypeOf. +const VALID_TYPES = [ + "array", + "boolean", + "function", + "null", + "number", + "object", + "string", + "undefined", +]; + +/** + * Returns a function C that creates instances of privateCtor. C may be called + * with or without the new keyword. The prototype of each instance returned + * from C is C.prototype, and C.prototype is an object whose prototype is + * privateCtor.prototype. Instances returned from C will therefore be instances + * of both C and privateCtor. Additionally, the constructor of each instance + * returned from C is C. + * + * @param privateCtor + * A constructor. + * @return A function that makes new instances of privateCtor. + */ +exports.publicConstructor = function publicConstructor(privateCtor) { + function PublicCtor() { + let obj = { constructor: PublicCtor, __proto__: PublicCtor.prototype }; + memory.track(obj, privateCtor.name); + privateCtor.apply(obj, arguments); + return obj; + } + PublicCtor.prototype = { __proto__: privateCtor.prototype }; + return PublicCtor; +}; + +/** + * Returns a validated options dictionary given some requirements. If any of + * the requirements are not met, an exception is thrown. + * + * @param options + * An object, the options dictionary to validate. It's not modified. + * If it's null or otherwise falsey, an empty object is assumed. + * @param requirements + * An object whose keys are the expected keys in options. Any key in + * options that is not present in requirements is ignored. Each value + * in requirements is itself an object describing the requirements of + * its key. There are four optional keys in this object: + * map: A function that's passed the value of the key in options. + * map's return value is taken as the key's value in the final + * validated options, is, and ok. If map throws an exception + * it's caught and discarded, and the key's value is its value in + * options. + * is: An array containing any number of the typeof type names. If + * the key's value is none of these types, it fails validation. + * Arrays and null are identified by the special type names + * "array" and "null"; "object" will not match either. No type + * coercion is done. + * ok: A function that's passed the key's value. If it returns + * false, the value fails validation. + * msg: If the key's value fails validation, an exception is thrown. + * This string will be used as its message. If undefined, a + * generic message is used, unless is is defined, in which case + * the message will state that the value needs to be one of the + * given types. + * @return An object whose keys are those keys in requirements that are also in + * options and whose values are the corresponding return values of map + * or the corresponding values in options. Note that any keys not + * shared by both requirements and options are not in the returned + * object. + */ +exports.validateOptions = function validateOptions(options, requirements) { + options = options || {}; + let validatedOptions = {}; + let mapThrew = false; + + for (let [key, req] in Iterator(requirements)) { + let [optsVal, keyInOpts] = (key in options) ? + [options[key], true] : + [undefined, false]; + if (req.map) { + try { + optsVal = req.map(optsVal); + } + catch (err) { + mapThrew = true; + } + } + if (req.is) { + // Sanity check the caller's type names. + req.is.forEach(function (typ) { + if (VALID_TYPES.indexOf(typ) < 0) { + let msg = 'Internal error: invalid requirement type "' + typ + '".'; + throw new Error(msg); + } + }); + if (req.is.indexOf(getTypeOf(optsVal)) < 0) + throw requirementError(key, req); + } + if (req.ok && !req.ok(optsVal)) + throw requirementError(key, req); + + if (keyInOpts || (req.map && !mapThrew)) + validatedOptions[key] = optsVal; + } + + return validatedOptions; +}; + +exports.addIterator = function addIterator(obj, keysValsGenerator) { + obj.__iterator__ = function(keysOnly, keysVals) { + let keysValsIterator = keysValsGenerator.call(this); + + // "for (.. in ..)" gets only keys, "for each (.. in ..)" gets values, + // and "for (.. in Iterator(..))" gets [key, value] pairs. + let index = keysOnly ? 0 : 1; + while (true) + yield keysVals ? keysValsIterator.next() : keysValsIterator.next()[index]; + }; +}; + +// Similar to typeof, except arrays and null are identified by "array" and +// "null", not "object". +let getTypeOf = exports.getTypeOf = function getTypeOf(val) { + let typ = typeof(val); + if (typ === "object") { + if (!val) + return "null"; + if (Array.isArray(val)) + return "array"; + } + return typ; +} + +// Returns a new Error with a nice message. +function requirementError(key, requirement) { + let msg = requirement.msg; + if (!msg) { + msg = 'The option "' + key + '" '; + msg += requirement.is ? + "must be one of the following types: " + requirement.is.join(", ") : + "is invalid."; + } + return new Error(msg); +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/app-strings.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/app-strings.js new file mode 100644 index 00000000..bd20025b --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/app-strings.js @@ -0,0 +1,93 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is String Bundle. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Myk Melez + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci} = require("chrome"); +const apiUtils = require("api-utils"); + +/** + * A bundle of strings. + * + * @param url {String} + * the URL of the string bundle + */ +exports.StringBundle = apiUtils.publicConstructor(function StringBundle(url) { + + let stringBundle = Cc["@mozilla.org/intl/stringbundle;1"]. + getService(Ci.nsIStringBundleService). + createBundle(url); + + this.__defineGetter__("url", function () url); + + /** + * Get a string from the bundle. + * + * @param name {String} + * the name of the string to get + * @param args {array} [optional] + * an array of arguments that replace occurrences of %S in the string + * + * @returns {String} the value of the string + */ + this.get = function strings_get(name, args) { + try { + if (args) + return stringBundle.formatStringFromName(name, args, args.length); + else + return stringBundle.GetStringFromName(name); + } + catch(ex) { + // f.e. "Component returned failure code: 0x80004005 (NS_ERROR_FAILURE) + // [nsIStringBundle.GetStringFromName]" + throw new Error("String '" + name + "' could not be retrieved from the " + + "bundle due to an unknown error (it doesn't exist?)."); + } + }, + + /** + * Iterate the strings in the bundle. + * + */ + apiUtils.addIterator( + this, + function keysValsGen() { + let enumerator = stringBundle.getSimpleEnumeration(); + while (enumerator.hasMoreElements()) { + let elem = enumerator.getNext().QueryInterface(Ci.nsIPropertyElement); + yield [elem.key, elem.value]; + } + } + ); +}); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/byte-streams.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/byte-streams.js new file mode 100644 index 00000000..fcc7ffd9 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/byte-streams.js @@ -0,0 +1,133 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim:set ts=2 sw=2 sts=2 et filetype=javascript + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Drew Willcoxon (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +exports.ByteReader = ByteReader; +exports.ByteWriter = ByteWriter; + +const {Cc, Ci} = require("chrome"); + +// This just controls the maximum number of bytes we read in at one time. +const BUFFER_BYTE_LEN = 0x8000; + +function ByteReader(inputStream) { + const self = this; + + let stream = Cc["@mozilla.org/binaryinputstream;1"]. + createInstance(Ci.nsIBinaryInputStream); + stream.setInputStream(inputStream); + + let manager = new StreamManager(this, stream); + + this.read = function ByteReader_read(numBytes) { + manager.ensureOpened(); + if (typeof(numBytes) !== "number") + numBytes = Infinity; + + let data = ""; + let read = 0; + try { + while (true) { + let avail = stream.available(); + let toRead = Math.min(numBytes - read, avail, BUFFER_BYTE_LEN); + if (toRead <= 0) + break; + data += stream.readBytes(toRead); + read += toRead; + } + } + catch (err) { + throw new Error("Error reading from stream: " + err); + } + + return data; + }; +} + +function ByteWriter(outputStream) { + const self = this; + + let stream = Cc["@mozilla.org/binaryoutputstream;1"]. + createInstance(Ci.nsIBinaryOutputStream); + stream.setOutputStream(outputStream); + + let manager = new StreamManager(this, stream); + + this.write = function ByteWriter_write(str) { + manager.ensureOpened(); + try { + stream.writeBytes(str, str.length); + } + catch (err) { + throw new Error("Error writing to stream: " + err); + } + }; +} + + +// This manages the lifetime of stream, a ByteReader or ByteWriter. It defines +// closed and close() on stream and registers an unload listener that closes +// rawStream if it's still opened. It also provides ensureOpened(), which +// throws an exception if the stream is closed. +function StreamManager(stream, rawStream) { + const self = this; + this.rawStream = rawStream; + this.opened = true; + + stream.__defineGetter__("closed", function stream_closed() { + return !self.opened; + }); + + stream.close = function stream_close() { + self.ensureOpened(); + self.unload(); + }; + + require("unload").ensure(this); +} + +StreamManager.prototype = { + ensureOpened: function StreamManager_ensureOpened() { + if (!this.opened) + throw new Error("The stream is closed and cannot be used."); + }, + unload: function StreamManager_unload() { + this.rawStream.close(); + this.opened = false; + } +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/collection.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/collection.js new file mode 100644 index 00000000..293e578d --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/collection.js @@ -0,0 +1,139 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Drew Willcoxon (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +exports.Collection = Collection; + +/** + * Adds a collection property to the given object. Setting the property to a + * scalar value empties the collection and adds the value. Setting it to an + * array empties the collection and adds all the items in the array. + * + * @param obj + * The property will be defined on this object. + * @param propName + * The name of the property. + * @param array + * If given, this will be used as the collection's backing array. + */ +exports.addCollectionProperty = function addCollProperty(obj, propName, array) { + array = array || []; + let publicIface = new Collection(array); + + obj.__defineSetter__(propName, function (itemOrItems) { + array.splice(0, array.length); + publicIface.add(itemOrItems); + }); + + obj.__defineGetter__(propName, function () { + return publicIface; + }); +}; + +/** + * A collection is ordered, like an array, but its items are unique, like a set. + * + * @param array + * The collection is backed by an array. If this is given, it will be + * used as the backing array. This way the caller can fully control the + * collection. Otherwise a new empty array will be used, and no one but + * the collection will have access to it. + */ +function Collection(array) { + array = array || []; + + /** + * Provides iteration over the collection. Items are yielded in the order + * they were added. + */ + this.__iterator__ = function Collection___iterator__() { + let items = array.slice(); + for (let i = 0; i < items.length; i++) + yield items[i]; + }; + + /** + * The number of items in the collection. + */ + this.__defineGetter__("length", function Collection_get_length() { + return array.length; + }); + + /** + * Adds a single item or an array of items to the collection. Any items + * already contained in the collection are ignored. + * + * @param itemOrItems + * An item or array of items. + * @return The collection. + */ + this.add = function Collection_add(itemOrItems) { + let items = toArray(itemOrItems); + for (let i = 0; i < items.length; i++) { + let item = items[i]; + if (array.indexOf(item) < 0) + array.push(item); + } + return this; + }; + + /** + * Removes a single item or an array of items from the collection. Any items + * not contained in the collection are ignored. + * + * @param itemOrItems + * An item or array of items. + * @return The collection. + */ + this.remove = function Collection_remove(itemOrItems) { + let items = toArray(itemOrItems); + for (let i = 0; i < items.length; i++) { + let idx = array.indexOf(items[i]); + if (idx >= 0) + array.splice(idx, 1); + } + return this; + }; +}; + +function toArray(itemOrItems) { + let isArr = itemOrItems && + itemOrItems.constructor && + itemOrItems.constructor.name === "Array"; + return isArr ? itemOrItems : [itemOrItems]; +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content.js new file mode 100644 index 00000000..8072a746 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content.js @@ -0,0 +1,44 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +exports.Loader = require('content/loader').Loader; +exports.Symbiont = require('content/symbiont').Symbiont; +exports.Worker = require('content/worker').Worker; + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/loader.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/loader.js new file mode 100644 index 00000000..3a05ead0 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/loader.js @@ -0,0 +1,198 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +const { EventEmitter } = require('events'); +const { validateOptions, getTypeOf } = require('api-utils'); +const { URL, toFilename } = require('url'); +const file = require("file"); + +// map of property validations +const valid = { + contentURL: { + ok: function (value) { + try { + URL(value); + } + catch(e) { + return false; + } + return true; + }, + msg: 'The `contentURL` option must be a valid URL.' + }, + contentScriptFile: { + is: ['undefined', 'null', 'string', 'array'], + map: function(value) 'undefined' === getTypeOf(value) ? null : value, + ok: function(value) { + if (getTypeOf(value) === 'array') { + // Make sure every item is a local file URL. + return value.every(function (item) { + try { + toFilename(item); + return true; + } + catch(e) { + return false; + } + }); + } + return true; + }, + msg: 'The `contentScriptFile` option must be a local file URL or an array of' + + 'URLs.' + }, + contentScript: { + is: ['undefined', 'null', 'string', 'array'], + map: function(value) 'undefined' === getTypeOf(value) ? null : value, + ok: function(value) 'array' !== getTypeOf(value) ? true : + value.every(function(item) 'string' === getTypeOf(item)) + , + msg: 'The script option must be a string or an array of strings.' + }, + contentScriptWhen: { + is: ['string'], + ok: function(value) ['start', 'ready'].indexOf(value) >= 0, + map: function(value) value || 'start', + msg: 'The `contentScriptWhen` option must be either "start" or "ready".' + } +}; + +/** + * Shortcut function to validate property with validation. + * @param {Object|Number|String} suspect + * value to validate + * @param {Object} validation + * validation rule passed to `api-utils` + */ +function validate(suspect, validation) validateOptions( + { $: suspect }, + { $: validation } +).$ + +function Allow(script) ({ + get script() script, + set script(value) script = !!value +}) + +/** + * Trait is intended to be used in some composition. It provides set of core + * properties and bounded validations to them. Trait is useful for all the + * compositions providing high level APIs for interaction with content. + * Property changes emit `"propertyChange"` events on instances. + */ +const Loader = EventEmitter.compose({ + /** + * Permissions for the content, with the following keys: + * @property {Object} [allow = { script: true }] + * @property {Boolean} [allow.script = true] + * Whether or not to execute script in the content. Defaults to true. + */ + get allow() this._allow || (this._allow = Allow(true)), + set allow(value) this.allow.script = value && value.script, + _allow: null, + /** + * The content to load. Either a string of HTML or a URL. + * @type {String} + */ + get contentURL() this._contentURL, + set contentURL(value) { + value = validate(value, valid.contentURL); + if (this._contentURL != value) { + this._emit('propertyChange', { + contentURL: this._contentURL = value + }); + } + }, + _contentURL: null, + /** + * When to load the content scripts. + * Possible values are "start" (default), which loads them as soon as + * the window object for the page has been created, and "ready", which + * loads them once the DOM content of the page has been loaded. + * Property change emits `propertyChange` event on instance with this key + * and new value. + * @type {'start'|'ready'} + */ + get contentScriptWhen() this._contentScriptWhen, + set contentScriptWhen(value) { + value = validate(value, valid.contentScriptWhen); + if (value !== this._contentScriptWhen) { + this._emit('propertyChange', { + contentScriptWhen: this._contentScriptWhen = value + }); + } + }, + _contentScriptWhen: 'start', + /** + * The URLs of content scripts. + * Property change emits `propertyChange` event on instance with this key + * and new value. + * @type {String[]} + */ + get contentScriptFile() this._contentScriptFile, + set contentScriptFile(value) { + value = validate(value, valid.contentScriptFile); + if (value != this._contentScriptFile) { + this._emit('propertyChange', { + contentScriptFile: this._contentScriptFile = value + }); + } + }, + _contentScriptFile: null, + /** + * The texts of content script. + * Property change emits `propertyChange` event on instance with this key + * and new value. + * @type {String|undefined} + */ + get contentScript() this._contentScript, + set contentScript(value) { + value = validate(value, valid.contentScript); + if (value != this._contentScript) { + this._emit('propertyChange', { + contentScript: this._contentScript = value + }); + } + }, + _contentScript: null +}); +exports.Loader = Loader; + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/symbiont.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/symbiont.js new file mode 100644 index 00000000..5c1e8174 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/symbiont.js @@ -0,0 +1,174 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Myk Melez (Original Author) + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +const { Worker } = require('./worker'); +const { Loader } = require('./loader'); +const hiddenFrames = require("hidden-frame"); +const observers = require('observer-service'); +const unload = require("unload"); +const xulApp = require("xul-app"); + +const HAS_DOCUMENT_ELEMENT_INSERTED = + xulApp.versionInRange(xulApp.platformVersion, "2.0b6", "*"); +const ON_START = HAS_DOCUMENT_ELEMENT_INSERTED ? 'document-element-inserted' : + 'content-document-global-created'; +const ON_READY = 'DOMContentLoaded'; + +/** + * This trait is layered on top of `Worker` and in contrast to symbiont + * Worker constructor requires `content` option that represents content + * that will be loaded in the provided frame, if frame is not provided + * Worker will create hidden one. + */ +const Symbiont = Worker.resolve({ + constructor: '_onInit', + destroy: '_workerDestroy' + }).compose({ + _window: Worker.required, + _onInit: Worker.required, + + /** + * The constructor requires all the options that are required by + * `require('content').Worker` with the difference that the `frame` option + * is optional. If `frame` is not provided, `contentURL` is expected. + * @param {Object} options + * @param {String} options.contentURL + * URL of a content to load into `this._frame` and create worker for. + * @param {Element} [options.frame] + * iframe element that is used to load `options.contentURL` into. + * if frame is not provided hidden iframe will be created. + */ + constructor: function Symbiont(options) { + options = options || {}; + + if ('contentURL' in options) + this.contentURL = options.contentURL; + if ('contentScriptWhen' in options) + this.contentScriptWhen = options.contentScriptWhen; + if ('contentScriptFile' in options) + this.contentScriptFile = options.contentScriptFile; + if ('contentScript' in options) + this.contentScript = options.contentScript; + if ('allow' in options) + this.allow = options.allow; + if ('onError' in options) + this.on('error', options.onError); + if ('onMessage' in options) + this.on('message', options.onMessage); + if ('frame' in options) { + this._initFrame(options.frame); + } + else { + let self = this; + hiddenFrames.add(hiddenFrames.HiddenFrame({ + onReady: function onFrame() { + self._initFrame(this.element); + } + })); + } + + unload.when(this.destroy.bind(this)); + }, + destroy: function destroy() { + // The frame might not have been initialized yet. + if (!this._frame) + return; + + if ('ready' === this.contentScriptWhen) + this._frame.removeEventListener(ON_READY, this._onReady, true); + else + observers.remove(ON_START, this._onStart); + + this._frame = null; + + this._workerDestroy(); + }, + /** + * XUL iframe or browser elements with attribute `type` being `content`. + * Used to create `ContentSymbiont` from. + * @type {nsIFrame|nsIBrowser} + */ + _frame: null, + /** + * Listener to the `'frameReady"` event (emitted when `iframe` is ready). + * Removes listener, sets right permissions to the frame and loads content. + */ + _initFrame: function _initFrame(frame) { + this._frame = frame; + frame.docShell.allowJavascript = this.allow.script; + frame.setAttribute("src", this._contentURL); + if ('ready' === this.contentScriptWhen) { + frame.addEventListener( + ON_READY, + this._onReady = this._onReady.bind(this), + true + ); + } else { + observers.add(ON_START, this._onStart = this._onStart.bind(this)); + } + }, + /** + * Creates port when the DOM is ready. Called if the value of + * `contentScriptWhen` is "ready". + */ + _onReady: function _onReady(event) { + let frame = this._frame; + if (event.target == frame.contentDocument) { + frame.removeEventListener(ON_READY, this._onReady, true); + this._window = frame.contentWindow.wrappedJSObject; + this._onInit(); + } + }, + /** + * Creates port when the global object is created. Called if the value of + * `contentScriptWhen` is "start". + */ + _onStart: function _onStart(domObj) { + let window = HAS_DOCUMENT_ELEMENT_INSERTED ? domObj.defaultView : domObj; + if (window && window == this._frame.contentWindow) { + observers.remove(ON_START, this._onStart); + this._window = window.wrappedJSObject; + this._onInit(); + } + } +}, Loader); +exports.Symbiont = Symbiont; + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/worker.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/worker.js new file mode 100644 index 00000000..fcc2d3e2 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/content/worker.js @@ -0,0 +1,376 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +const es5code = require('cuddlefish').es5code; +const { Trait } = require('traits'); +const { EventEmitter } = require('events'); +const { Ci, Cu, Cc } = require('chrome'); +const timer = require('timer'); +const { toFilename } = require('url'); +const file = require('file'); +const unload = require('unload'); + +const JS_VERSION = '1.8'; + +const ERR_DESTROYED = + "The page has been destroyed and can no longer be used."; + +/** + * Extended `EventEmitter` allowing us to emit events asynchronously. + */ +const AsyncEventEmitter = EventEmitter.compose({ + /** + * Emits event in the next turn of event loop. + */ + _asyncEmit: function _asyncEmit() { + timer.setTimeout(function emitter(emit, scope, params) { + emit.apply(scope, params); + }, 0, this._emit, this, arguments) + } +}); + +/** + * Function for sending data to the port. Used to send messages + * from the worker to the symbiont and other way round. + * Function validates that data is a `JSON` or primitive value and emits + * 'message' event on the port in the next turn of the event loop. + * _Later this will be sending data across process boundaries._ + * @param {JSON|String|Number|Boolean} data + */ +function postMessage(data) { + if (!this._port) + throw new Error(ERR_DESTROYED); + this._port._asyncEmit('message', JSON.parse(JSON.stringify(data))); +} + +/** + * Local trait providing implementation of the workers global scope. + * Used to configure global object in the sandbox. + * @see http://www.w3.org/TR/workers/#workerglobalscope + */ +const WorkerGlobalScope = AsyncEventEmitter.compose({ + on: Trait.required, + _removeAllListeners: Trait.required, + + // wrapped functions from `'timer'` module. + // Wrapper adds `try catch` blocks to the callbacks in order to + // emit `error` event on a symbiont if exception is thrown in + // the Worker global scope. + // @see http://www.w3.org/TR/workers/#workerutils + setTimeout: function setTimeout(callback, delay) { + let params = Array.slice(arguments, 2); + return timer.setTimeout(function(port) { + try { + callback.apply(null, params); + } catch(e) { + port._asyncEmit('error', e); + } + }, delay, this._port); + }, + clearTimeout: timer.clearTimeout, + + setInterval: function setInterval(callback, delay) { + let params = Array.slice(arguments, 2); + return timer.setInterval(function(port) { + try { + callback.apply(null, params); + } catch(e) { + port._asyncEmit('error', e); + } + }, delay, this._port); + }, + clearInterval: timer.clearInterval, + + /** + * `onMessage` function defined in the global scope of the worker context. + */ + get onMessage() this._onMessage, + set onMessage(value) { + let listener = this._onMessage; + if (listener && value !== listener) { + this.removeListener('message', listener); + this._onMessage = undefined; + } + if (value) + this.on('message', this._onMessage = value); + }, + _onMessage: undefined, + + /** + * @see postMesssage + */ + postMessage: postMessage, + + /** + * Alias to the global scope in the context of worker. Similar to + * `window` concept. + */ + get self() this._public, + + + /** + * Configures sandbox and loads content scripts into it. + * @param {Worker} port + * content worker + */ + constructor: function WorkerGlobalScope(port) { + // connect ports + this._port = port; + port._port = this; + + this.on('unload', this._destructor = this._destructor.bind(this)); + + // XXX I think the principal should be `this._port._frame.contentWindow`, + // but script doesn't work correctly when I set it to that value. + // Events don't get registered; even dump() fails. + // + // FIXME: figure out the problem and resolve it, so we can restrict + // the sandbox to the same set of privileges the page has (plus any others + // it gets to access through the object that created it). + // + // XXX when testing `this._port.frame.contentWindow`, I found that setting + // the principal to its `this._port.frame.contentWindow.wrappedJSObject` + // resolved some test leaks; that was before I started clearing the + // principal of the sandbox on unload, though, so perhaps it is no longer + // a problem. + let sandbox = this._sandbox = new Cu.Sandbox( + Cc["@mozilla.org/systemprincipal;1"].createInstance(Ci.nsIPrincipal) + ); + + // Shimming natives in sandbox so that they support ES5 features + Cu.evalInSandbox(es5code.contents, sandbox, "1.8", es5code.filename); + + let window = port._window; + let publicAPI = this._public; + + let keys = Object.getOwnPropertyNames(publicAPI); + for each (let key in keys) { + if ('onMessage' === key) continue; + Object.defineProperty( + sandbox, key, Object.getOwnPropertyDescriptor(publicAPI, key) + ); + } + Object.defineProperties(sandbox, { + onMessage: { + get: function() publicAPI.onMesssage, + set: function(value) publicAPI.onMessage = value, + configurable: true + }, + console: { value: console, configurable: true }, + }); + // Chain the global object for the sandbox to the global object for + // the frame. This supports JavaScript libraries like jQuery that depend + // on the presence of certain properties in the global object, like window, + // document, location, and navigator. + sandbox.__proto__ = window; + // Alternate approach: + // Define each individual global on which JavaScript libraries depend + // in the global object of the sandbox. This is hard to get right, + // since it requires a priori knowledge of the libraries developers use, + // and exceptions in those libraries aren't always reported. It's also + // brittle, prone to breaking when those libraries change. But it might + // make it easier to avoid namespace conflicts. + // In my testing with jQuery, I found that the library needed window, + // document, location, and navigator to avoid throwing exceptions, + // although even with those globals defined, the library still doesn't + // work, so it also needs something else about which it unfortunately does + // not complain. + // sandbox.window = window; + // sandbox.document = window.document; + // sandbox.location = window.location; + // sandbox.navigator = window.navigator; + + // The order of `contentScriptFile` and `contentScript` evaluation is + // intentional, so programs can load libraries like jQuery from script URLs + // and use them in scripts. + let contentScriptFile = ('contentScriptFile' in port) ? port.contentScriptFile + : null, + contentScript = ('contentScript' in port) ? port.contentScript : null; + + if (contentScriptFile) { + if (Array.isArray(contentScriptFile)) + this._importScripts.apply(this, contentScriptFile); + else + this._importScripts(contentScriptFile); + } + if (contentScript) { + this._evaluate( + Array.isArray(contentScript) ? contentScript.join(';\n') : contentScript + ); + } + }, + _destructor: function _destructor() { + this._removeAllListeners(); + let publicAPI = this._public, + sandbox = this._sandbox; + delete sandbox.__proto__; + for (let key in publicAPI) + delete sandbox[key]; + this._sandbox = null; + this._port = null; + this._onMessage = undefined; + }, + /** + * JavaScript sandbox where all the content scripts are evaluated. + * {Sandbox} + */ + _sandbox: null, + /** + * Reference to the worker. + * @type {Worker} + */ + _port: null, + /** + * Evaluates code in the sandbox. + * @param {String} code + * JavaScript source to evaluate. + * @param {String} [filename='javascript:' + code] + * Name of the file + */ + _evaluate: function(code, filename) { + filename = filename || 'javascript:' + code; + try { + Cu.evalInSandbox(code, this._sandbox, JS_VERSION, filename, 1); + } + catch(e) { + this._port._asyncEmit('error', e); + } + }, + /** + * Imports scripts to the sandbox by reading files under urls and + * evaluating its source. If exception occurs during evaluation + * `"error"` event is emitted on the worker. + * This is actually an analog to the `importScript` method in web + * workers but in our case it's not exposed even though content + * scripts may be able to do it synchronously since IO operation + * takes place in the UI process. + */ + _importScripts: function _importScripts(url) { + let urls = Array.slice(arguments, 0); + for each (let contentScriptFile in urls) { + try { + let filename = toFilename(contentScriptFile); + this._evaluate(file.read(filename), filename); + } + catch(e) { + this._port._asyncEmit('error', e) + } + } + } +}); + +/** + * Message-passing facility for communication between code running + * in the content and add-on process. + * @see https://jetpack.mozillalabs.com/sdk/latest/docs/#module/api-utils/content/worker + */ +const Worker = AsyncEventEmitter.compose({ + on: Trait.required, + _asyncEmit: Trait.required, + _removeAllListeners: Trait.required, + + /** + * Sends a message to the worker's global scope. Method takes single + * argument, which represents data to be sent to the worker. The data may + * be any primitive type value or `JSON`. Call of this method asynchronously + * emits `message` event with data value in the global scope of this + * symbiont. + * + * `message` event listeners can be set either by calling + * `self.on` with a first argument string `"message"` or by + * implementing `onMessage` function in the global scope of this worker. + * @param {Number|String|JSON} data + */ + postMessage: postMessage, + + constructor: function Worker(options) { + options = options || {}; + + if ('window' in options) + this._window = options.window; + if ('contentScriptFile' in options) + this.contentScriptFile = options.contentScriptFile; + if ('contentScript' in options) + this.contentScript = options.contentScript; + if ('onError' in options) + this.on('error', options.onError); + if ('onMessage' in options) + this.on('message', options.onMessage); + + unload.when(this.destroy.bind(this)); + + WorkerGlobalScope(this); // will set this._port pointing to the private API + }, + + get url() { + return this._window.document.location.href; + }, + + get tab() { + let tab = require("tabs/tab"); + return tab.getTabForWindow(this._window); + }, + + /** + * Tells _port to unload itself and removes all the references from itself. + */ + destroy: function destroy() { + this._removeAllListeners('message'); + this._removeAllListeners('error'); + if (this._port) // maybe unloaded before port is created + this._port._emit('unload'); + this._port = null; + this._window = null; + }, + /** + * Reference to the global scope of the worker. + * @type {WorkerGlobalScope} + */ + _port: null, + + /** + * Reference to the window that is accessible from + * the content scripts. + * @type {Object} + */ + _window: null, +}); +exports.Worker = Worker; + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cortex.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cortex.js new file mode 100644 index 00000000..6cd7ce99 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cortex.js @@ -0,0 +1,139 @@ +/* vim:set ts=2 sw=2 sts=2 + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +// `var` is being used in the module in order to make it reusable in +// environments in which `let` and `const` is not yet supported. + +// Returns `object`'s property value, where `name` is a name of the property. +function get(object, name) { + return object[name]; +} + +// Assigns `value` to the `object`'s property, where `name` is the name of the +// property. +function set(object, name, value) { + return object[name] = value; +} + +/** + * Given an `object` containing a property with the given `name`, create + * a property descriptor that can be used to define alias/proxy properties + * on other objects. A change in the value of an alias will propagate + * to the aliased property and vice versa. + */ +function createAliasProperty(object, name) { + // Getting own property descriptor of an `object` for the given `name` as + // we are going to create proxy analog. + var property = Object.getOwnPropertyDescriptor(object, name); + var descriptor = { + configurable: property.configurable, + enumerable: property.enumerable, + alias: true + }; + + // If the original property has a getter and/or setter, bind a + // corresponding getter/setter in the alias descriptor to the original + // object, so the `this` object in the getter/setter is the original object + // rather than the alias. + if ("get" in property) + descriptor.get = property.get.bind(object); + if ("set" in property) + descriptor.set = property.set.bind(object); + + // If original property was a value property. + if ("value" in property) { + // If original property is a method using it's `object` bounded copy. + if (typeof property.value === "function") { + descriptor.value = property.value.bind(object); + // Also preserving writability of the original property. + descriptor.writable = property.writable; + } + + // If the original property was just a data property, we create proxy + // accessors using our custom get/set functions to propagate changes to the + // original `object` and vice versa. + else { + descriptor.get = get.bind(null, object, name); + descriptor.set = set.bind(null, object, name); + } + } + return descriptor; +} + +// Defines property on `object` object with a name `alias` if given if not +// defaults to `name` that represents an alias of `source[name]`. If aliased +// property was an assessor or a method `this` pseudo-variable will be `source` +// when invoked. If aliased property was a data property changes on any of the +// aliases will propagate to the `source[name]` and also other way round. +function defineAlias(source, target, name, alias) { + return Object.defineProperty(target, alias || name, + createAliasProperty(source, name)); +} + +/** + * Function takes any `object` and returns a proxy for its own public + * properties. By default properties are considered to be public if they don't + * start with `"_"`, but default behavior can be overridden if needed, by + * passing array of public property `names` as a second argument. By default + * returned object will be direct decedent of the given `object`'s prototype, + * but this can be overridden by passing third optional argument, that will be + * used as `prototype` instead. + * @param {Object} object + * Object to create cortex for. + * @param {String[]} [names] + * Optional array of public property names. + * @param {Object} [prototype] + * Optional argument that will be used as `prototype` of the returned object, + * if not provided `Object.getPrototypeOf(object)` is used instead. + */ +exports.Cortex = function Cortex(object, names, prototype) { + // Creating a cortex object from the given `prototype`, if one was not + // provided then `prototype` of a given `object` is used. This allows + // consumer to define expected behavior `instanceof`. In common case + // `prototype` argument can be omitted to preserve same behavior of + // `instanceof` as on original `object`. + var cortex = Object.create(prototype || Object.getPrototypeOf(object)); + // Creating alias properties on the `cortex` object for all the own + // properties of the original `object` that are contained in `names` array. + // If `names` array is not provided then all the properties that don't + // start with `"_"` are aliased. + Object.getOwnPropertyNames(object).forEach(function (name) { + if ((!names && "_" !== name.charAt(0)) || (names && ~names.indexOf(name))) + defineAlias(object, cortex, name); + }); + return cortex; +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cuddlefish.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cuddlefish.js new file mode 100644 index 00000000..da99ca66 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/cuddlefish.js @@ -0,0 +1,267 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +(function(global) { + const Cc = Components.classes; + const Ci = Components.interfaces; + const Cu = Components.utils; + const Cr = Components.results; + + var exports = {}; + + // Load the SecurableModule prerequisite. + var securableModule; + var myURI = Components.stack.filename.split(" -> ").slice(-1)[0]; + + if (global.require) + // We're being loaded in a SecurableModule. + securableModule = require("securable-module"); + else { + var ios = Cc['@mozilla.org/network/io-service;1'] + .getService(Ci.nsIIOService); + var securableModuleURI = ios.newURI("securable-module.js", null, + ios.newURI(myURI, null, null)); + if (securableModuleURI.scheme == "chrome") { + // The securable-module module is at a chrome URI, so we can't + // simply load it via Cu.import(). Let's assume we're in a + // chrome-privileged document and use mozIJSSubScriptLoader. + var loader = Cc["@mozilla.org/moz/jssubscript-loader;1"] + .getService(Ci.mozIJSSubScriptLoader); + + // Import the script, don't pollute the global scope. + securableModule = {__proto__: global}; + loader.loadSubScript(securableModuleURI.spec, securableModule); + securableModule = securableModule.SecurableModule; + } else { + securableModule = {}; + try { + Cu.import(securableModuleURI.spec, securableModule); + } catch (e if e.result == Cr.NS_ERROR_ILLEGAL_VALUE) { + Cu.reportError("Failed to load " + securableModuleURI.spec); + } + } + } + + var localFS = new securableModule.LocalFileSystem(myURI); + var es5path = localFS.resolveModule(null, "es5"); + var es5code = exports.es5code = localFS.getFile(es5path); + + es5code.filename = es5path; + + function unloadLoader(reason) { + this.require("unload").send(reason); + } + + function maybeLoadMainInJetpackProcess(delegate, packaging) { + return function getModuleExports(basePath, module) { + if (module == packaging.options.main) { + var mainURL = this.fs.resolveModule(basePath, module); + var mainInfo = packaging.getModuleInfo(mainURL); + if (!mainInfo.needsChrome) { + var loader = this; + return { + main: function main(options, callbacks) { + var e10s = loader.require("e10s"); + var process = e10s.AddonProcess(); + loader.console.log("starting main in remote process."); + process.send("startMain", options.main); + } + }; + } else + return null; + } + return (delegate ? delegate.call(this, basePath, module) : null); + }; + } + + function makeGetModuleExports(delegate) { + return function getModuleExports(basePath, module) { + switch (module) { + case "chrome": + var chrome = { Cc: Components.classes, + Ci: Components.interfaces, + Cu: Components.utils, + Cr: Components.results, + Cm: Components.manager, + components: Components }; + return chrome; + case "parent-loader": + return this; + default: + return (delegate ? delegate.call(this, basePath, module) : null); + } + }; + } + + function modifyModuleSandbox(sandbox, options) { + sandbox.evaluate(es5code); + var filename = options.filename ? options.filename : null; + sandbox.defineProperty("__url__", filename); + } + + function makeManifestChecker(packaging) { + var mc = { + _allow: function _allow(loader, basePath, module, module_info) { + if (!basePath) { + return true; /* top-level import */ + } + let mi = packaging.getModuleInfo(basePath); + if (mi.needsChrome) + /* The module requires chrome, it can import whatever it + * wants. */ + return true; + if (!mi.dependencies) { + /* the parent isn't in the manifest: we know nothing about it */ + } else { + if (mi.dependencies[module]) { + /* they're on the list: the require() is allowed, but let's + check that they're loading the right thing */ + let parent_mi = packaging.getModuleInfo(basePath); + // parent_mi is the parent, who invoked require() + // module_info is the child, the output of resolveModule + var should_load = parent_mi.dependencies[module].url; + var is_loading = module_info.filename; + if (!should_load) { + /* the linker wasn't able to find the target module when the + XPI was constructed. */ + loader.console.warn("require("+ module +") (called from " + + basePath + ") is loading " + is_loading + + ", but the manifest couldn't find it"); + } else if (should_load != is_loading) { + loader.console.warn("require(" + module + ") (called from " + + basePath + ") is loading " + is_loading + + ", but is supposed to be loading " + + should_load); + //return false; // enable this in 0.9 + } + return true; + } + } + loader.console.warn("undeclared require(" + module + + ") called from " + basePath); + //return false; // enable this in 0.9 + return true; + }, + allowEval: function allowEval(loader, basePath, module, module_info) { + return this._allow(loader, basePath, module, module_info); + }, + + allowImport: function allowImport(loader, basePath, module, module_info, + exports) { + if (module == "chrome") { + let parent_mi = packaging.getModuleInfo(basePath); + if (parent_mi.needsChrome) + return true; /* chrome is on the list, allow it */ + loader.console.warn("undeclared require(chrome) called from " + + basePath); + //return false; // enable this in 0.9 + return true; + } + + return this._allow(loader, basePath, module, module_info); + } + }; + return mc; + } + + var Loader = exports.Loader = function Loader(options) { + var globals = {}; + + if (options.globals) + for (var name in options.globals) + globals[name] = options.globals[name]; + + if (options.console) + globals.console = options.console; + if (options.memory) + globals.memory = options.memory; + + if ('modules' in options) + throw new Error('options.modules is no longer supported'); + + var getModuleExports = makeGetModuleExports(options.getModuleExports); + + var manifestChecker = undefined; + if (options.packaging) { + manifestChecker = makeManifestChecker(options.packaging); + if (options.packaging.enableE10s) + getModuleExports = maybeLoadMainInJetpackProcess(getModuleExports, + options.packaging); + } + + var loaderOptions = {rootPath: options.rootPath, + rootPaths: options.rootPaths, + fs: options.fs, + defaultPrincipal: "system", + globals: globals, + modifyModuleSandbox: modifyModuleSandbox, + securityPolicy: manifestChecker, + getModuleExports: getModuleExports}; + + var loader = new securableModule.Loader(loaderOptions); + + if (!globals.console) { + var console = loader.require("plain-text-console"); + globals.console = new console.PlainTextConsole(options.print); + } + if (!globals.memory) + globals.memory = loader.require("memory"); + + loader.console = globals.console; + loader.memory = globals.memory; + loader.unload = unloadLoader; + + return loader; + }; + + if (global.window) { + // We're being loaded in a chrome window, or a web page with + // UniversalXPConnect privileges. + global.Cuddlefish = exports; + } else if (global.exports) { + // We're being loaded in a SecurableModule. + for (name in exports) { + global.exports[name] = exports[name]; + } + } else { + // We're being loaded in a JS module. + global.EXPORTED_SYMBOLS = []; + for (name in exports) { + global.EXPORTED_SYMBOLS.push(name); + global[name] = exports[name]; + } + } + })(this); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/e10s.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/e10s.js new file mode 100644 index 00000000..a315d10a --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/e10s.js @@ -0,0 +1,243 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +let {Cc, Ci, Cr} = require('chrome'); + +let url = require("url"); +let file = require("file"); +let errors = require("errors"); + +let jetpackService = Cc["@mozilla.org/jetpack/service;1"] + .getService(Ci.nsIJetpackService); + +function AddonProcess(jetpack) { + var syncListeners = {}; + + this.on = function(name, cb) { + jetpack.registerReceiver(name, function() { + try { + // Intentionally do not return the return value of + // the function; we want developers to use registerCall() for that. + cb.apply(undefined, arguments); + } catch (e) { + console.exception(e); + } + }); + }; + + this.registerCall = function(name, cb) { + if (name in syncListeners) + throw new Error("call already registered for '" + name + "'"); + syncListeners[name] = true; + jetpack.registerReceiver(name, errors.catchAndReturn(cb)); + }; + + this.send = function() { + return jetpack.sendMessage.apply(this, arguments); + }; + + this.createHandle = function() { + return jetpack.createHandle(); + }; + + this.destroy = function() { + try { + jetpack.destroy(); + } catch (e if e.result == Cr.NS_ERROR_NOT_INITIALIZED) {} + }; +} + +function makeScriptFrom(fs, moduleURL) { + // TODO: Why can't we just return fs.getFile(moduleURL) here? + return { + filename: moduleURL, + contents: fs.getFile(moduleURL).contents + }; +} + +var defaultConsole = console; + +exports.AddonProcess = function createAddonProcess(options) { + if (!options) + options = {}; + + var jetpack = jetpackService.createJetpack(); + var process = new AddonProcess(jetpack); + var registeredModules = {}; + + var console = options.console || defaultConsole; + var pkg = options.packaging || packaging; + + // Whenever our add-on is disabled or uninstalled, we want to + // destroy the remote process. + + require("unload").when(function() { + process.destroy(); + process = null; + }); + + // Set up message receivers that the remote process will use to + // communicate with us. + + ['log', 'debug', 'info', 'warn', 'error'].forEach(function(method) { + process.on("console:" + method, function(name, args) { + console[method].apply(console, args); + }); + }); + + function remoteException(exception) { + return { + toString: function toString() { + return "Error: " + this.message; + }, + __proto__: exception + }; + } + + process.on("quit", function(name, status) { + if (options.quit) + options.quit(status); + }); + + process.on("console:trace", function(name, exception) { + var traceback = require("traceback"); + var stack = traceback.fromException(remoteException(exception)); + console.log(traceback.format(stack.slice(0, -2))); + }); + + process.on("console:exception", function(name, exception) { + console.exception(remoteException(exception)); + }); + + jetpack.registerReceiver("dump", function(name, msg) { + dump(msg); + }); + + jetpack.registerReceiver( + "core:exception", + function(name, exception) { + console.log("An exception occurred in the child Jetpack process."); + console.exception(remoteException(exception)); + }); + + process.registerCall( + "require", + function(name, base, path) { + var loader = options.loader || require("parent-loader"); + var parentFS = loader.fs; + var moduleURL = parentFS.resolveModule(base, path); + + if (!moduleURL) + return {code: "not-found"}; + + var moduleInfo = pkg.getModuleInfo(moduleURL); + var moduleName = path; + + function maybeImportAdapterModule() { + var adapterModuleName = moduleName + "-e10s-adapter"; + var adapterModuleURL = parentFS.resolveModule(base, + adapterModuleName); + var adapterModuleInfo = null; + if (adapterModuleURL) + adapterModuleInfo = pkg.getModuleInfo(adapterModuleURL); + + if (moduleInfo['e10s-adapter'] != adapterModuleURL) { + console.warn("Adapter module URL is " + adapterModuleURL + + " but expected " + moduleInfo['e10s-adapter']); + return {code: "error"}; + } + + if (adapterModuleInfo) { + // e10s adapter found! + try { + if (!(adapterModuleURL in registeredModules)) { + // This e10s adapter has already been loaded for this + // addon process, and we only really need to give it the + // absolute URL of the adapter. + registeredModules[adapterModuleURL] = true; + loader.require(adapterModuleName).register(process); + } + } catch (e) { + console.exception(e); + return {code: "error"}; + } + return { + code: "ok", + needsMessaging: true, + script: makeScriptFrom(parentFS, adapterModuleURL) + }; + } + + return null; + } + + if (moduleInfo) { + if (moduleInfo.needsChrome) { + return maybeImportAdapterModule() || {code: "access-denied"}; + } else { + + // Even if a module doesn't explicitly require chrome privileges, if + // an e10s adapter exists for it, use it, because said module might + // import other modules that require chrome. + // + // In the future we may want to look at the module's dependencies to + // determine whether importing an adapter is a better idea. + + return maybeImportAdapterModule() || { + code: "ok", + needsMessaging: false, + script: makeScriptFrom(parentFS, moduleURL) + }; + } + } else { + return maybeImportAdapterModule() || {code: "not-found"}; + } + }); + + var bootURL = require("self").data.url("bootstrap-remote-process.js"); + var bootFilename = url.toFilename(bootURL); + var bootJS = file.read(bootFilename); + + // The try ... catch is a workaround for bug 589308. + jetpack.evalScript('//@line 1 "' + bootFilename + '"\n' + + "try { " + bootJS + " } catch (e) { " + + "sendMessage('core:exception', e); }"); + + process.send("addInjectedSandboxScript", + require("cuddlefish").es5code); + + return process; +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js new file mode 100644 index 00000000..7a8c38dc --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/errors.js @@ -0,0 +1,90 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +function logToConsole(e) { + console.exception(e); +} + +var catchAndLog = exports.catchAndLog = function(callback, + defaultResponse, + logException) { + if (!logException) + logException = logToConsole; + + return function() { + try { + return callback.apply(this, arguments); + } catch (e) { + logException(e); + return defaultResponse; + } + }; +}; + +exports.catchAndLogProps = function catchAndLogProps(object, + props, + defaultResponse, + logException) { + if (typeof(props) == "string") + props = [props]; + props.forEach( + function(property) { + object[property] = catchAndLog(object[property], + defaultResponse, + logException); + }); +}; + +/** + * Catch and return an exception while calling the callback. If the callback + * doesn't throw, return the return value of the callback in a way that makes it + * possible to distinguish between a return value and an exception. + * + * This function is useful when you need to pass the result of a call across + * a process boundary (across which exceptions don't propagate). It probably + * doesn't need to be factored out into this module, since it is only used by + * a single caller, but putting it here works around bug 625560. + */ +exports.catchAndReturn = function(callback) { + return function() { + try { + return { returnValue: callback.apply(this, arguments) }; + } + catch (exception) { + return { exception: exception }; + } + }; +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/es5.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/es5.js new file mode 100644 index 00000000..d7e1c5dc --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/es5.js @@ -0,0 +1,587 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// Override the default Iterator function with one that passes +// a second argument to custom iterator methods that identifies +// the call as originating from an Iterator function so the custom +// iterator method can return [key, value] pairs just like default +// iterators called via the default Iterator function. + +Iterator = (function(DefaultIterator) { + return function Iterator(obj, keysOnly) { + if ("__iterator__" in obj && !keysOnly) + return obj.__iterator__.call(obj, false, true); + return DefaultIterator(obj, keysOnly); + }; +})(Iterator); + +(function(exports) { +const // local shortcuts + hasOwn = Object.prototype.hasOwnProperty, + getGetter = Object.prototype.__lookupGetter__, + getSetter = Object.prototype.__lookupSetter__, + setGetter = Object.prototype.__defineGetter__, + setSetter = Object.prototype.__defineSetter__, + ObjectToString = Object.prototype.toString; +const + ID = '__es5_guid__', + PROTO = {}; +let // registry + GUID = 0, + REGISTRY = { + inextensible: {}, + frozen: {}, + sealed: {} + }, + DESCRIPTORS = {}; + +/** + * function gets `guid` for an object if it's in a registry. If + * object is not in a registry and `force` argument is `true` object + * gets unique identifier, special iterator hiding it & entry in registry. + * as a result of a call `guid` is returned if not in registry and `force` is + * not `true` `null` is returned. + * @param {Object} object + * object to get a `guid` for. + * @param {Boolean} force + * if `true` and object is not in registry it will be added there. + */ +function _guid(object, force) { + let guid = object[ID]; + if (!guid && force) { + guid = object[ID] = ++ GUID; + if (!('__iterator__' in object)) + defineIterator(object); + } + return guid || null +} +function noSetter() { + throw new TypeError('setting a property that has only a getter'); +} +function nonWritable() { + throw new TypeError('setting a property that is read-only'); +} + +/** + * Function that generates ES5 object mutation functions(freeze, seal + * preventExtensions). Since in ES3 we can't implement ES5 `object` mutations + * we have a local registry for tracking mutated objects. + * @param {String} name + * property in mutation phase registry that is set to `true` when called + */ +function Mutate(name) { + let registry = REGISTRY[name]; + return function(object) { + registry[_guid(object, true)] = true; + return object; + } +} + +/** + * Function that generates ES5 mutation phase checker functions. Since in + * ES3 we can't implement ES5 `object` mutations we have a local registry + * for tracking mutated objects in order to evaluate next statement to `true` + * `Object.isFrozen(Object.freeze({}))` + * @param {String} name + * property in mutation phase registry that represents mutation + * @param {Boolean} invert + * Weather or not registry values should be inverted by generated function. + * Values are inverted by `Object.isExtensible` because default is `true`. + */ +function IsMutated(name, invert) { + let registry = REGISTRY[name]; + return function(object) + invert ? !registry[_guid(object)] : !!registry[_guid(object)]; +} + +/** + * Defines custom `__iterator__` that wraps original `__iterator__` & uses + * locar object despriptor registry to iterate only on enumerable properties. + * '__iterator__' getter is used as a proxy to an iterator, what allows + * it to determine whether or not `Iterator` wrapper is used. + * @see https://developer.mozilla.org/en/New_in_JavaScript_1.7#Iterators + */ +function defineIterator(object) { + let onKeyValue = false, + ITERATOR = { __iterator__: undefined }; + function iterator(onKeys) { + ITERATOR.__proto__ = this; + for (let key in ITERATOR) { + if (key === ID || '__iterator__' === key) + continue; + let descriptor = getPropertyDescriptor(this, key); + if (descriptor && false === descriptor.enumerable) + continue; + yield onKeyValue ? [key, this[key]] : onKeys ? key : this[key]; + } + } + setGetter.call(object, '__iterator__', function __es5iterator__() { + let stack = Error().stack.split(/\n/); + onKeyValue = ( + stack[2].indexOf('Iterator(') == 0 || // native implementation of bind + stack[3].indexOf('Iterator(') == 0 // custom implementation of bind + ); + return iterator; + }); + setSetter.call(object, '__iterator__', function(value) iterator = value); +} + +/** + * Almost identical to the ES5 `Object.getOwnPropertyDescriptor` function. + * Only difference is that this function will return descriptors for + * inherited properties along with own. This helper function is used by custom + * iterators. They need to check each property (including inherited ones) + * whether or not it's enumerable. + * @see #__iterator__ + * @see #iterator + */ +function getPropertyDescriptor(object, name) { + let descriptor = getOwnPropertyDescriptor(object, name); + if (!descriptor) { + let proto = object.__proto__; + if (proto) + descriptor = getPropertyDescriptor(proto, name); + } + if (descriptor && ('value' in descriptor)) + descriptor.value = object[name]; + return descriptor; +} + +/** ES5 15.4.3.2 */ +function isArray(object) ObjectToString.call(object) == '[object Array]'; + +/** ES5 15.2.3.2 */ +function getPrototypeOf(object) object.__proto__; + +/** + * ES5 15.2.3.8 + * Can't implement this feature in ES3. Function just pretends to be + * doing whatever specs say, instead it registers state so that check + * calling `Object.isSealed` on sealed object will return `true` + */ +let seal = Mutate('sealed'); + +/** + * ES5 15.2.3.9 + * Can't implement this feature in ES3. Function just pretends to be + * doing whatever specs say, instead it registers state so that checking + * calling `Object.isFrozen` on frozen object will return `true`. + */ +let freeze = Mutate('frozen'); + +/** + * ES5 15.2.3.10 + * Can't implement this feature in ES3. Function just pretends to be + * doing whatever specs say, instead it registers state so that checking + * calling `Object.isExtensible` on inextensible object will return `true`. + */ +let preventExtensions = Mutate('inextensible'); + +/** + * ES5 15.2.3.11 + * Can't implement this feature in ES3. Function just pretends to be + * doing whatever specs say, instead it looks into state registry, where + * all the mutation functions store state. + */ +let isSealed = IsMutated('sealed'); + +/** + * ES5 15.2.3.12 + * Can't implement this feature in ES3. Function just pretends to be + * doing whatever specs say, instead it looks into state registry, where + * all the mutation functions store state. + */ +let isFrozen = IsMutated('frozen'); + +/** + * ES5 15.2.3.13 + * Can't implement this feature in ES3. Function just pretends to be + * doing whatever specs say, instead it looks into state registry, where + * all the mutation functions store state. + */ +let isExtensible = exports.isExtensible = IsMutated('inextensible', true); + +/** ES5 15.2.3.14 */ +function keys(object) { + let result = []; + for (let name in object) { + if (hasOwn.call(object, name)) + result.push(name); + } + return result; +} + +/** ES5 15.2.3.4 */ +function getOwnPropertyNames(object) { + let ITERATOR = { __proto__: object, __iterator__: undefined }; + let result = []; + for (let name in ITERATOR) { + if (hasOwn.call(object, name) && ID !== name) { + let skip = false; + if ('__iterator__' === name) { + let iteratror = getGetter.call(object, '__iterator__'); + skip = iteratror && '__es5iterator__' === iteratror.name; + } + if (!skip) + result.push(name); + } + } + return result; +} + +/** ES5 15.2.3.3 */ +function getOwnPropertyDescriptor(object, name) { + if (!hasOwn.call(object, name)) + return undefined; + let descriptor = { + configurable: true, + enumerable: true + }; + // lets override descriptor with values from registry if are any + let _descriptor, objectDescriptor = DESCRIPTORS[_guid(object)]; + if (objectDescriptor && (_descriptor = objectDescriptor[name])) { + descriptor.enumerable = _descriptor.enumerable; + descriptor.configurable = _descriptor.configurable; + if ('writable' in _descriptor) + descriptor.writable = _descriptor.writable; + } + if (false === descriptor.writable) { + // special case where want to pretend that we have value not a getter + descriptor.value = object[name] + } + else { + let get = getGetter.call(object, name), + set = getSetter.call(object, name); + if (!get && !set) { + descriptor.value = object[name]; + descriptor.writable = true; + } + else { + descriptor.get = get; + descriptor.set = set; + } + } + return descriptor; +} + +/** + * ES5 15.2.3.6 + * Partially implements ES5 `Object.defineProperty`. + * - Non configurable properties can't be implement in ES3, so all the non + * configurable properties will be created as configurable ones. + * - Non writable properties can't be implemented in ES3, getters and setters + * will be created instead, but `Object.getOwnPropertyDescriptor` will still + * behave as expected (will return descriptor for non writable property not a + * getter) + * - Defining properties using ES5 functions will break your custom iterators + * if you have any. Think twice before employing custom iterator cause in + * majority of cases you can just make properties non enumerable. In case you + * really need to have custom iterator be smart about it, make sure to add + * it after running ES5 functions and don't ignore previous iterators. Please + * see example below for inspiration: + * let object = Object.create({}, { + * myField: { value: 6 } + * }); + * object.__iterator__ = (function(original) { + * return function myIterator() { + * this.__iterator__ = original; + * for (let key in this) { + * // your logic here + * } + * this.__iterator__ = myIterator; + * } + * })(object.__iterator__); + */ +function defineProperty(object, name, descriptor) { + if ('object' !== typeof object && 'function' !== typeof object) + throw new TypeError('Object prototype may only be an Object or null.'); + if (descriptor && 'object' !== typeof descriptor) + throw new TypeError('Property descriptor list must be an Object.'); + + if ('value' in descriptor) { // if it's property + if ('get' in descriptor || 'set' in descriptor) { + throw new TypeError('Invalid property. "value" present on property' + + 'with getter or setter.'); + } + if (false === descriptor.writable) { + let value = descriptor.value; + setGetter.call(object, name, function() value); + setSetter.call(object, name, nonWritable); + } + else { + // temporary removing proto to avoid inherited getter / setter + let proto = object.__proto__; + object.__proto__ = PROTO; + delete object[name]; + object[name] = descriptor.value; + object.__proto__ = proto; + } + } + else { // if it's a setter / getter + if ('writable' in descriptor) + throw new TypeError('Invalid property. "writable" present on property' + + 'with getter or setter.'); + let get = descriptor.get, hasGet = (typeof get == "function"), + set = descriptor.set, hasSet = (typeof set == "function"); + if (hasGet) + setGetter.call(object, name, get); + if (hasSet) + setSetter.call(object, name, descriptor.set); + // should throw if only getter is assigned + else if (hasGet) + setSetter.call(object, name, noSetter); + } + // registering descriptor + let guid = _guid(object, true); + let ObjectRegistry = DESCRIPTORS[guid] || (DESCRIPTORS[guid] = {}); + let registry = ObjectRegistry[name] || (ObjectRegistry[name] = {}); + if ('writable' in descriptor) + registry.writable = !!descriptor.writable; + let enumerable = registry.enumerable = + 'enumerable' in descriptor ? !!descriptor.enumerable : false; + registry.configurable = + 'configurable' in descriptor ? !!descriptor.configurable : false; + return object; +} + +/** + * ES5 15.2.3.7 + * Some functionality can't be implemented using ES5. + * @see #defineProperty + */ +function defineProperties(object, descriptor) { + let names = getOwnPropertyNames(descriptor); + for each (let name in names) + defineProperty(object, name, descriptor[name]); + return object; +} + +/** + * ES5 15.2.3.5 + * Some functionality can't be implemented using ES5. + * @see #defineProperty + */ +function create(proto, descriptor) { + if (typeof proto != 'object') + throw new TypeError( + 'typeof prototype[' + (typeof proto) + '] != "object"' + ); + let inheritsIterator = ( + (!descriptor || !('__iterator__' in descriptor)) + && proto && '__iterator__' in proto + ); + let object = {}; + if (inheritsIterator) + object.__iterator__ = undefined; + if (typeof descriptor !== "undefined") + defineProperties(object, descriptor); + if (inheritsIterator) + delete object.__iterator__; + object.__proto__ = proto; + return object; +} + +/** ES-5 15.3.4.5 */ +function bind(that) { + /** 1. Let Target be the this value. **/ + let target = this; + /** + 2. If IsCallable(Target) is false, throw a TypeError exception. + XXX this gets pretty close, for all intents and purposes, letting + some duck-types slide + */ + if (typeof target.apply != "function" || typeof target.call != "function") + return new TypeError(); + /** + 3. Let A be a new (possibly empty) internal list of all of the + argument values provided after thisArg (arg1, arg2 etc), in order. + */ + let boundArgs = Array.slice(arguments); + /** + 4. Let F be a new native ECMAScript object. + 9. Set the [[Prototype]] internal property of F to the standard + built-in Function prototype object as specified in 15.3.3.1. + 10. Set the [[Call]] internal property of F as described in + 15.3.4.5.1. + 11. Set the [[Construct]] internal property of F as described in + 15.3.4.5.2. + 12. Set the [[HasInstance]] internal property of F as described in + 15.3.4.5.3. + 13. The [[Scope]] internal property of F is unused and need not + exist. + */ + function bound() { + let params = boundArgs.concat(Array.slice(arguments)) + if (this instanceof bound) { + /** + 15.3.4.5.2 [[Construct]] + When the [[Construct]] internal method of a function object, + F that was created using the bind function is called with a + list of arguments ExtraArgs the following steps are taken: + 1. Let target be the value of F's [[TargetFunction]] + internal property. + 2. If target has no [[Construct]] internal method, a + TypeError exception is thrown. + 3. Let boundArgs be the value of F's [[BoundArgs]] internal + property. + 4. Let args be a new list containing the same values as the + list boundArgs in the same order followed by the same + values as the list ExtraArgs in the same order. + */ + let self = create(target.prototype); + target.apply(self, params); + return self; + } + else { + /** + 15.3.4.5.1 [[Call]] + When the [[Call]] internal method of a function object, F, + which was created using the bind function is called with a + this value and a list of arguments ExtraArgs the following + steps are taken: + 1. Let boundArgs be the value of F's [[BoundArgs]] internal + property. + 2. Let boundThis be the value of F's [[BoundThis]] internal + property. + 3. Let target be the value of F's [[TargetFunction]] internal + property. + 4. Let args be a new list containing the same values as the + list boundArgs in the same order followed by the same + values as the list ExtraArgs in the same order. 5. Return + the result of calling the [[Call]] internal method of + target providing boundThis as the this value and providing + args as the arguments. + equiv: target.call(this, ...boundArgs, ...args) + */ + return target.call.apply(target, params); + } + } + /** + 5. Set the [[TargetFunction]] internal property of F to Target. + extra: + */ + bound.bound = target; + /** + 6. Set the [[BoundThis]] internal property of F to the value of + thisArg. + extra: + */ + bound.boundTo = that; + /** + 7. Set the [[BoundArgs]] internal property of F to A. + extra: + */ + bound.boundArgs = boundArgs; + /** + 14. If the [[Class]] internal property of Target is "Function", then + a. Let L be the length property of Target minus the length of A. + b. Set the length own property of F to either 0 or L, whichever is + larger. + 15. Else set the length own property of F to 0. + */ + // #Note can't modify length in es3. + /** + 16. The length own property of F is given attributes as specified in + 15.3.5.1. + #TODO + 17. Set the [[Extensible]] internal property of F to true. + #TODO + 18. Call the [[DefineOwnProperty]] internal method of F with + arguments "caller", PropertyDescriptor {[[Value]]: null, + [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: + false}, and false. + #TODO + 19. Call the [[DefineOwnProperty]] internal method of F with + arguments "arguments", PropertyDescriptor {[[Value]]: null, + [[Writable]]: false, [[Enumerable]]: false, [[Configurable]]: + false}, and false. + NOTE Function objects created using Function.prototype.bind do not + have a prototype property. + */ + // #Note can't delete prototype in es3. + return bound; +} + +/** + * Implements missing ES5 features in passed `Object`, `Array`, `Function`. + * @param {Object} + * `Object` to be extended with a missing ES5 features. + * @param {Array} + * `Array` to be extended with a missing ES5 features. + * @param {Function} + * `Function` to be extended with a missing ES5 features. + * @see http://www.ecmascript.org/docs/tc39-2009-043.pdf + */ +exports.init = function init(Object, Array, Function) { + if (Array) { + if (!Array.isArray) + Array.isArray = isArray; + } + if (Object) { + if (!Object.seal) + Object.seal = seal; + if (!Object.freeze) + Object.freeze = freeze; + if (!Object.preventExtensions) + Object.preventExtensions = preventExtensions; + if (!Object.isSealed) + Object.isSealed = isSealed; + if (!Object.isFrozen) + Object.isFrozen = isFrozen; + if (!Object.isExtensible) + Object.isExtensible = isExtensible; + if (!Object.keys) + Object.keys = keys; + if (!Object.getPrototypeOf) + Object.getPrototypeOf = getPrototypeOf; + if (!Object.getOwnPropertyNames) + Object.getOwnPropertyNames = getOwnPropertyNames; + if (!Object.getOwnPropertyDescriptor) + Object.getOwnPropertyDescriptor = getOwnPropertyDescriptor; + if (!Object.defineProperty) + Object.defineProperty = defineProperty; + if (!Object.defineProperties) + Object.defineProperties = defineProperties; + if (!Object.create) + Object.create = create; + } + if (Function) { + if (!Function.prototype.bind) + Function.prototype.bind = bind; + } +}; +exports.init(Object, Array, Function); +})(this.exports ? exports : {}); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js new file mode 100644 index 00000000..80429ecd --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/events.js @@ -0,0 +1,196 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original Author) + * Drew Willcoxon + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +const ERROR_TYPE = 'error', + UNCAUGHT_ERROR = 'An error event was dispatched for which there was' + + ' no listener.', + BAD_LISTENER = 'The event listener must be a function.'; +/** + * This object is used to create an `EventEmitter` that, useful for composing + * objects that emit events. It implements an interface like `EventTarget` from + * DOM Level 2, which is implemented by Node objects in implementations that + * support the DOM Event Model. + * @see http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-EventTarget + * @see http://nodejs.org/api.html#EventEmitter + * @see http://livedocs.adobe.com/flash/9.0/ActionScriptLangRefV3/flash/events/EventDispatcher.html + */ +const eventEmitter = { + /** + * Registers an event `listener` that is called every time events of + * specified `type` are emitted. + * @param {String} type + * The type of event. + * @param {Function} listener + * The listener function that processes the event. + * @example + * worker.on('message', function (data) { + * console.log('data received: ' + data) + * }) + */ + on: function on(type, listener) { + if ('function' !== typeof listener) + throw new Error(BAD_LISTENER); + let listeners = this._listeners(type); + if (0 > listeners.indexOf(listener)) + listeners.push(listener); + return this._public; + }, + + /** + * Registers an event `listener` that is called once the next time an event + * of the specified `type` is emitted. + * @param {String} type + * The type of the event. + * @param {Function} listener + * The listener function that processes the event. + */ + once: function once(type, listener) { + this.on(type, function selfRemovableListener() { + this.removeListener(type, selfRemovableListener); + listener.apply(this, arguments); + }); + }, + + /** + * Unregister `listener` for the specified event type. + * @param {String} type + * The type of event. + * @param {Function} listener + * The listener function that processes the event. + */ + removeListener: function removeListener(type, listener) { + if ('function' !== typeof listener) + throw new Error(BAD_LISTENER); + let listeners = this._listeners(type), + index = listeners.indexOf(listener); + if (0 <= index) + listeners.splice(index, 1); + return this._public; + }, + + /** + * Hash of listeners on this EventEmitter. + */ + _events: null, + + /** + * Returns an array of listeners for the specified event `type`. This array + * can be manipulated, e.g. to remove listeners. + * @param {String} type + * The type of event. + */ + _listeners: function listeners(type) { + let events = this._events || (this._events = {}); + return events[type] || (events[type] = []); + }, + + /** + * Execute each of the listeners in order with the supplied arguments. + * Returns `true` if listener for this event was called, `false` if there are + * no listeners for this event `type`. + * + * All the exceptions that are thrown by listeners during the emit + * are caught and can be handled by listeners of 'error' event. Thrown + * exceptions are passed as an argument to an 'error' event listener. + * If no 'error' listener is registered exception will propagate to a + * caller of this method. + * + * **It's recommended to have a default 'error' listener in all the complete + * composition that in worst case may dump errors to the console.** + * + * @param {String} type + * The type of event. + * @params {Object|Number|String|Boolean} + * Arguments that will be passed to listeners. + * @returns {Boolean} + */ + _emit: function _emit(type, event) { + let args = Array.slice(arguments); + args.unshift(this._public); + return this._emitOnObject.apply(this, args); + }, + + /** + * A version of _emit that lets you specify the object on which listeners are + * called. This is a hack that is sometimes necessary when such an object + * (exports, for example) cannot be an EventEmitter for some reason, but other + * object(s) managing events for the object are EventEmitters. Once bug + * 577782 is fixed, this method shouldn't be necessary. + * + * @param {object} targetObj + * The object on which listeners will be called. + * @param {string} type + * The event name. + * @param {value} event + * The first argument to pass to listeners. + * @param {value} ... + * More arguments to pass to listeners. + * @returns {boolean} + */ + _emitOnObject: function _emitOnObject(targetObj, type, event /* , ... */) { + let listeners = this._listeners(type).slice(0); + // If there is no 'error' event listener then throw. + if (type === ERROR_TYPE && !listeners.length) + console.exception(event); + if (!listeners.length) + return false; + let params = Array.slice(arguments, 2); + for each (let listener in listeners) { + try { + listener.apply(targetObj, params); + } catch(e) { + this._emit('error', e); + } + } + return true; + }, + + /** + * Removes all the event listeners for the specified event `type`. + * @param {String} type + * The type of event. + */ + _removeAllListeners: function _removeAllListeners(type) { + this._listeners(type).splice(0); + return this; + } +}; +exports.EventEmitter = require("traits").Trait.compose(eventEmitter); +exports.EventEmitterTrait = require('light-traits').Trait(eventEmitter); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js new file mode 100644 index 00000000..cd9c5259 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/file.js @@ -0,0 +1,213 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is nsINarwhal. + * + * The Initial Developer of the Original Code is + * Irakli Gozalishvili . + * Portions created by the Initial Developer are Copyright (C) 2009 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili + * Atul Varma + * Drew Willcoxon + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci,Cr} = require("chrome"); +const byteStreams = require("byte-streams"); +const textStreams = require("text-streams"); +const xpcom = require("xpcom"); + +// Flags passed when opening a file. See nsprpub/pr/include/prio.h. +const OPEN_FLAGS = { + RDONLY: 0x01, + WRONLY: 0x02, + CREATE_FILE: 0x08, + APPEND: 0x10, + TRUNCATE: 0x20, + EXCL: 0x80 +}; + +var dirsvc = Cc["@mozilla.org/file/directory_service;1"] + .getService(Ci.nsIProperties); + +function MozFile(path) { + var file = Cc['@mozilla.org/file/local;1'] + .createInstance(Ci.nsILocalFile); + file.initWithPath(path); + return file; +} + +function ensureReadable(file) { + if (!file.isReadable()) + throw new Error("path is not readable: " + file.path); +} + +function ensureDir(file) { + ensureExists(file); + if (!file.isDirectory()) + throw new Error("path is not a directory: " + file.path); +} + +function ensureFile(file) { + ensureExists(file); + if (!file.isFile()) + throw new Error("path is not a file: " + file.path); +} + +function ensureExists(file) { + if (!file.exists()) { + throw xpcom.friendlyError(Cr.NS_ERROR_FILE_NOT_FOUND, { + filename: file.path + }); + } +} + +exports.exists = function exists(filename) { + return MozFile(filename).exists(); +}; + +exports.isFile = function isFile(filename) { + return MozFile(filename).isFile(); +}; + +exports.read = function read(filename) { + var stream = exports.open(filename); + try { + var str = stream.read(); + } + finally { + stream.close(); + } + + return str; +}; + +exports.join = function join(base) { + if (arguments.length < 2) + throw new Error("need at least 2 args"); + base = MozFile(base); + for (var i = 1; i < arguments.length; i++) + base.append(arguments[i]); + return base.path; +}; + +exports.dirname = function dirname(path) { + var parent = MozFile(path).parent; + return parent ? parent.path : ""; +}; + +exports.basename = function basename(path) { + var leafName = MozFile(path).leafName; + + // On Windows, leafName when the path is a volume letter and colon ("c:") is + // the path itself. But such a path has no basename, so we want the empty + // string. + return leafName == path ? "" : leafName; +}; + +exports.list = function list(path) { + var file = MozFile(path); + ensureDir(file); + ensureReadable(file); + + var entries = file.directoryEntries; + var entryNames = []; + while(entries.hasMoreElements()) { + var entry = entries.getNext(); + entry.QueryInterface(Ci.nsIFile); + entryNames.push(entry.leafName); + } + return entryNames; +}; + +exports.open = function open(filename, mode) { + var file = MozFile(filename); + if (typeof(mode) !== "string") + mode = ""; + + // File opened for write only. + if (/w/.test(mode)) { + if (file.exists()) + ensureFile(file); + var stream = Cc['@mozilla.org/network/file-output-stream;1']. + createInstance(Ci.nsIFileOutputStream); + var openFlags = OPEN_FLAGS.WRONLY | + OPEN_FLAGS.CREATE_FILE | + OPEN_FLAGS.TRUNCATE; + var permFlags = 0644; // u+rw go+r + try { + stream.init(file, openFlags, permFlags, 0); + } + catch (err) { + throw xpcom.friendlyError(err, { filename: filename }); + } + return /b/.test(mode) ? + new byteStreams.ByteWriter(stream) : + new textStreams.TextWriter(stream); + } + + // File opened for read only, the default. + ensureFile(file); + stream = Cc['@mozilla.org/network/file-input-stream;1']. + createInstance(Ci.nsIFileInputStream); + try { + stream.init(file, OPEN_FLAGS.RDONLY, 0, 0); + } + catch (err) { + throw xpcom.friendlyError(err, { filename: filename }); + } + return /b/.test(mode) ? + new byteStreams.ByteReader(stream) : + new textStreams.TextReader(stream); +}; + +exports.remove = function remove(path) { + var file = MozFile(path); + ensureFile(file); + file.remove(false); +}; + +exports.mkpath = function mkpath(path) { + var file = MozFile(path); + if (!file.exists()) + file.create(Ci.nsIFile.DIRECTORY_TYPE, 0755); // u+rwx go+rx + else if (!file.isDirectory()) + throw new Error("The path already exists and is not a directory: " + path); +}; + +exports.rmdir = function rmdir(path) { + var file = MozFile(path); + ensureDir(file); + try { + file.remove(false); + } + catch (err) { + // Bug 566950 explains why we're not catching a specific exception here. + throw new Error("The directory is not empty: " + path); + } +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests-e10s-adapter.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests-e10s-adapter.js new file mode 100644 index 00000000..009947db --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests-e10s-adapter.js @@ -0,0 +1,110 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +if (this.chrome) { + var timer = require("timer"); + var ut = require("unit-test"); + + chrome.on( + "runTest", + function(name, test) { + var runner = new ut.TestRunner(); + runner.start({ + test: test.testHandle, + onDone: function() { + test.passed = runner.test.passed; + test.failed = runner.test.failed; + test.errors = runner.test.errors; + chrome.send("testDone", test); + } + }); + }); + + exports.main = function(options, callbacks) { + function makeTest(suite, name, test) { + return function runTest(runner) { + console.info("executing '" + suite + "." + name + "' remotely"); + test(runner); + }; + } + + var tests = []; + + options.suites.forEach(function(suite) { + var module = require(suite); + for (testName in module) { + var handle = chrome.createHandle(); + handle.testFunction = makeTest(suite, testName, module[testName]); + handle.name = suite + "." + testName; + tests.push({testHandle: handle, name: handle.name}); + } + }); + chrome.send("testsFound", tests, options.finderHandle); + } +} else { + exports.register = function(addon) { + addon.on("testDone", function(name, remoteTest) { + var runner = remoteTest.testHandle.runner; + runner.passed += remoteTest.passed; + runner.failed += remoteTest.failed; + runner.test.passed = remoteTest.passed; + runner.test.failed = remoteTest.failed; + runner.test.errors = remoteTest.errors; + runner.done(); + }); + addon.on("testPass", function(name, remoteTest, msg) { + remoteTest.testHandle.runner.pass(msg); + }); + addon.on("testFail", function(name, remoteTest, msg) { + remoteTest.testHandle.runner.fail(msg); + }); + addon.on("testsFound", function(name, remoteTests, + finderHandle) { + var tests = []; + remoteTests.forEach(function(remoteTest) { + tests.push({ + testFunction: function(runner) { + remoteTest.testHandle.runner = runner; + runner.waitUntilDone(); + addon.send("runTest", remoteTest); + }, + name: remoteTest.name + }); + }); + finderHandle.onTestsFound(tests); + }); + }; +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests.js new file mode 100644 index 00000000..be29d19e --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/find-tests.js @@ -0,0 +1 @@ +// this file left intentionally blank diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/hidden-frame.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/hidden-frame.js new file mode 100644 index 00000000..17ed5fd5 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/hidden-frame.js @@ -0,0 +1,198 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Felipe Gomes (Original Author) + * Myk Melez + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc, Ci} = require("chrome"); +const errors = require("errors"); +const apiUtils = require("api-utils"); +const timer = require("timer"); + +const XUL_NS = "http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul"; + +let hostFrame, hostDocument, hiddenWindow, isHostFrameReady = false; + +if (!require("xul-app").isOneOf(["Firefox", "Thunderbird"])) { + throw new Error([ + "The hidden-frame module currently supports only Firefox and Thunderbird. ", + "In the future, we would like it to support other applications, however. ", + "Please see https://bugzilla.mozilla.org/show_bug.cgi?id=546740 for more ", + "information." + ].join("")); +} + +let appShellService = Cc["@mozilla.org/appshell/appShellService;1"]. + getService(Ci.nsIAppShellService); +hiddenWindow = appShellService.hiddenDOMWindow; + +if (!hiddenWindow) { + throw new Error([ + "The hidden-frame module needs an app that supports a hidden window. ", + "We would like it to support other applications, however. Please see ", + "https://bugzilla.mozilla.org/show_bug.cgi?id=546740 for more information." + ].join("")); +} + +// Check if we can use the hidden window itself to host our iframes. +// If it's not a suitable host, the hostFrame will be lazily created +// by the first HiddenFrame instance. +if (hiddenWindow.location.protocol == "chrome:" && + (hiddenWindow.document.contentType == "application/vnd.mozilla.xul+xml" || + hiddenWindow.document.contentType == "application/xhtml+xml")) { + hostFrame = hiddenWindow; + hostDocument = hiddenWindow.document; + isHostFrameReady = true; +} + +function setHostFrameReady() { + hostDocument = hostFrame.contentDocument; + hostFrame.removeEventListener("DOMContentLoaded", setHostFrameReady, false); + isHostFrameReady = true; +} + +// This cache is used to access friend properties between functions +// without exposing them on the public API. +let cache = []; + +exports.HiddenFrame = apiUtils.publicConstructor(HiddenFrame); + +function HiddenFrame(options) { + options = options || {}; + let self = this; + + for each (let [key, val] in Iterator(apiUtils.validateOptions(options, { + onReady: { + is: ["undefined", "function", "array"], + ok: function(v) { + if (apiUtils.getTypeOf(v) === "array") { + // make sure every item is a function + return v.every(function (item) typeof(item) === "function") + } + return true; + } + } + }))) { + if (typeof(val) != "undefined") + options[key] = val; + } + + require("collection").addCollectionProperty(this, "onReady"); + if (options.onReady) + this.onReady.add(options.onReady); + + if (!hostFrame) { + hostFrame = hiddenWindow.document.createElement("iframe"); + + // ugly ugly hack. This is the most lightweight chrome:// file I could find on the tree + // This hack should be removed by proper platform support on bug 565388 + hostFrame.setAttribute("src", "chrome://global/content/mozilla.xhtml"); + hostFrame.addEventListener("DOMContentLoaded", setHostFrameReady, false); + + hiddenWindow.document.body.appendChild(hostFrame); + } + + this.toString = function toString() "[object Frame]"; +} + +exports.add = function JP_SDK_Frame_add(frame) { + if (!(frame instanceof HiddenFrame)) + throw new Error("The object to be added must be a HiddenFrame."); + + // This instance was already added. + if (cache.filter(function (v) v.frame === frame)[0]) + return frame; + + function createElement() { + hostFrame.removeEventListener("DOMContentLoaded", createElement, false); + + let element = hostDocument.createElementNS(XUL_NS, "iframe"); + + element.setAttribute("type", "content"); + hostDocument.documentElement.appendChild(element); + + /* Public API: hiddenFrame.element */ + frame.__defineGetter__("element", function () element); + + // Notify consumers that the frame is ready. + function onReadyListener(event) { + element.removeEventListener("DOMContentLoaded", onReadyListener, false); + if (event.target == element.contentDocument) { + for (let handler in frame.onReady) + errors.catchAndLog(function () handler.call(frame))(); + } + } + element.addEventListener("DOMContentLoaded", onReadyListener, false); + + cache.push({ + frame: frame, + element: element, + unload: function unload() { + hostDocument.documentElement.removeChild(element); + } + }); + } + + /* Begin element construction or schedule it for later */ + if (isHostFrameReady) { + createElement(); + } else { + hostFrame.addEventListener("DOMContentLoaded", createElement, false); + } + + return frame; +} + +exports.remove = function remove(frame) { + if (!(frame instanceof HiddenFrame)) + throw new Error("The object to be removed must be a HiddenFrame."); + + let entry = cache.filter(function (v) v.frame === frame)[0]; + if (!entry) + return; + + entry.unload(); + cache.splice(cache.indexOf(entry), 1); +} + +require("unload").when(function () { + for each (let entry in cache.slice()) + exports.remove(entry.frame); + + if (hostFrame && hostFrame !== hiddenWindow) + hiddenWindow.document.body.removeChild(hostFrame); +}); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/light-traits.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/light-traits.js new file mode 100644 index 00000000..1afaad5b --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/light-traits.js @@ -0,0 +1,626 @@ +/* vim:ts=2:sts=2:sw=2: + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +// `var` is being used in the module in order to make it reusable in +// environments in which `let` is not yet supported. + +// Shortcut to `Object.prototype.hasOwnProperty.call`. +// owns(object, name) would be the same as +// Object.prototype.hasOwnProperty.call(object, name); +var owns = Function.prototype.call.bind(Object.prototype.hasOwnProperty); + +/** + * Whether or not given property descriptors are equivalent. They are + * equivalent either if both are marked as 'conflict' or 'required' property + * or if all the properties of descriptors are equal. + * @param {Object} actual + * @param {Object} expected + */ +function equivalentDescriptors(actual, expected) { + return (actual.conflict && expected.conflict) || + (actual.required && expected.required) || + equalDescriptors(actual, expected); +} +/** + * Whether or not given property descriptors define equal properties. + */ +function equalDescriptors(actual, expected) { + return actual.get === expected.get && + actual.set === expected.set && + actual.value === expected.value && + !!actual.enumerable === !!expected.enumerable && + !!actual.configurable === !!expected.configurable && + !!actual.writable === !!expected.writable; +} + +// Utilities that throwing exceptions for a properties that are marked +// as "required" or "conflict" properties. +function throwConflictPropertyError(name) { + throw new Error("Remaining conflicting property: `" + name + "`"); +} +function throwRequiredPropertyError(name) { + throw new Error("Missing required property: `" + name + "`"); +} + +/** + * Generates custom **required** property descriptor. Descriptor contains + * non-standard property `required` that is equal to `true`. + * @param {String} name + * property name to generate descriptor for. + * @returns {Object} + * custom property descriptor + */ +function RequiredPropertyDescriptor(name) { + // Creating function by binding first argument to a property `name` on the + // `throwConflictPropertyError` function. Created function is used as a + // getter & setter of the created property descriptor. This way we ensure + // that we throw exception late (on property access) if object with + // `required` property was instantiated using built-in `Object.create`. + var accessor = throwRequiredPropertyError.bind(null, name); + return { get: accessor, set: accessor, required: true }; +} + +/** + * Generates custom **conflicting** property descriptor. Descriptor contains + * non-standard property `conflict` that is equal to `true`. + * @param {String} name + * property name to generate descriptor for. + * @returns {Object} + * custom property descriptor + */ +function ConflictPropertyDescriptor(name) { + // For details see `RequiredPropertyDescriptor` since idea is same. + var accessor = throwConflictPropertyError.bind(null, name); + return { get: accessor, set: accessor, conflict: true }; +} + +/** + * Tests if property is marked as `required` property. + */ +function isRequiredProperty(object, name) { + return !!object[name].required; +} + +/** + * Tests if property is marked as `conflict` property. + */ +function isConflictProperty(object, name) { + return !!object[name].conflict; +} + +/** + * Function tests whether or not method of the `source` object with a given + * `name` is inherited from `Object.prototype`. + */ +function isBuiltInMethod(name, source) { + var target = Object.prototype[name]; + + // If methods are equal then we know it's `true`. + return target == source || + // If `source` object comes form a different sandbox `==` will evaluate + // to `false`, in that case we check if functions names and sources match. + (String(target) === String(source) && target.name === source.name); +} + +/** + * Function overrides `toString` and `constructor` methods of a given `target` + * object with a same-named methods of a given `source` if methods of `target` + * object are inherited / copied from `Object.prototype`. + * @see create + */ +function overrideBuiltInMethods(target, source) { + if (isBuiltInMethod("toString", target.toString)) { + Object.defineProperty(target, "toString", { + value: source.toString, + configurable: true, + enumerable: false + }); + } + + if (isBuiltInMethod("constructor", target.constructor)) { + Object.defineProperty(target, "constructor", { + value: source.constructor, + configurable: true, + enumerable: false + }); + } +} + +/** + * Composes new trait with the same own properties as the original trait, + * except that all property names appearing in the first argument are replaced + * by "required" property descriptors. + * @param {String[]} keys + * Array of strings property names. + * @param {Object} trait + * A trait some properties of which should be excluded. + * @returns {Object} + * @example + * var newTrait = exclude(["name", ...], trait) + */ +function exclude(names, trait) { + var map = {}; + + Object.keys(trait).forEach(function(name) { + + // If property is not excluded (the array of names does not contain it), + // or it is a "required" property, copy it to the property descriptor `map` + // that will be used for creation of resulting trait. + if (!~names.indexOf(name) || isRequiredProperty(trait, name)) + map[name] = { value: trait[name], enumerable: true }; + + // For all the `names` in the exclude name array we create required + // property descriptors and copy them to the `map`. + else + map[name] = { value: RequiredPropertyDescriptor(name), enumerable: true }; + }); + + return Object.create(Trait.prototype, map); +} + +/** + * Composes new instance of `Trait` with a properties of a given `trait`, + * except that all properties whose name is an own property of `renames` will + * be renamed to `renames[name]` and a `"required"` property for name will be + * added instead. + * + * For each renamed property, a required property is generated. If + * the `renames` map two properties to the same name, a conflict is generated. + * If the `renames` map a property to an existing unrenamed property, a + * conflict is generated. + * + * @param {Object} renames + * An object whose own properties serve as a mapping from old names to new + * names. + * @param {Object} trait + * A new trait with renamed properties. + * @returns {Object} + * @example + * + * // Return trait with `bar` property equal to `trait.foo` and with + * // `foo` and `baz` "required" properties. + * var renamedTrait = rename({ foo: "bar", baz: null }), trait); + * + * // t1 and t2 are equivalent traits + * var t1 = rename({a: "b"}, t); + * var t2 = compose(exclude(["a"], t), { a: { required: true }, b: t[a] }); + */ +function rename(renames, trait) { + var map = {}; + + // Loop over all the properties of the given `trait` and copy them to a + // property descriptor `map` that will be used for the creation of the + // resulting trait. Also, rename properties in the `map` as specified by + // `renames`. + Object.keys(trait).forEach(function(name) { + var alias; + + // If the property is in the `renames` map, and it isn't a "required" + // property (which should never need to be aliased because "required" + // properties never conflict), then we must try to rename it. + if (owns(renames, name) && !isRequiredProperty(trait, name)) { + alias = renames[name]; + + // If the `map` already has the `alias`, and it isn't a "required" + // property, that means the `alias` conflicts with an existing name for a + // provided trait (that can happen if >=2 properties are aliased to the + // same name). In this case we mark it as a conflicting property. + // Otherwise, everything is fine, and we copy property with an `alias` + // name. + if (owns(map, alias) && !map[alias].value.required) { + map[alias] = { + value: ConflictPropertyDescriptor(alias), + enumerable: true + }; + } + else { + map[alias] = { + value: trait[name], + enumerable: true + }; + } + + // Regardless of whether or not the rename was successful, we check to + // see if the original `name` exists in the map (such a property + // could exist if previous another property was aliased to this `name`). + // If it isn't, we mark it as "required", to make sure the caller + // provides another value for the old name, which methods of the trait + // might continue to reference. + if (!owns(map, name)) { + map[name] = { + value: RequiredPropertyDescriptor(name), + enumerable: true + }; + } + } + + // Otherwise, either the property isn't in the `renames` map (thus the + // caller is not trying to rename it) or it is a "required" property. + // Either way, we don't have to alias the property, we just have to copy it + // to the map. + else { + // The property isn't in the map yet, so we copy it over. + if (!owns(map, name)) { + map[name] = { value: trait[name], enumerable: true }; + } + + // The property is already in the map (that means another property was + // aliased with this `name`, which creates a conflict if the property is + // not marked as "required"), so we have to mark it as a "conflict" + // property. + else if (!isRequiredProperty(trait, name)) { + map[name] = { + value: ConflictPropertyDescriptor(name), + enumerable: true + }; + } + } + }); + return Object.create(Trait.prototype, map); +} + +/** + * Composes new resolved trait, with all the same properties as the original + * `trait`, except that all properties whose name is an own property of + * `resolutions` will be renamed to `resolutions[name]`. + * + * If `resolutions[name]` is `null`, the value is mapped to a property + * descriptor that is marked as a "required" property. + */ +function resolve(resolutions, trait) { + var renames = {}; + var exclusions = []; + + // Go through each mapping in `resolutions` object and distribute it either + // to `renames` or `exclusions`. + Object.keys(resolutions).forEach(function(name) { + + // If `resolutions[name]` is a truthy value then it's a mapping old -> new + // so we copy it to `renames` map. + if (resolutions[name]) + renames[name] = resolutions[name]; + + // Otherwise it's not a mapping but an exclusion instead in which case we + // add it to the `exclusions` array. + else + exclusions.push(name); + }); + + // First `exclude` **then** `rename` and order is important since + // `exclude` and `rename` are not associative. + return rename(renames, exclude(exclusions, trait)); +} + +/** + * Create a Trait (a custom property descriptor map) that represents the given + * `object`'s own properties. Property descriptor map is a "custom", because it + * inherits from `Trait.prototype` and it's property descriptors may contain + * two attributes that is not part of the ES5 specification: + * + * - "required" (this property must be provided by another trait + * before an instance of this trait can be created) + * - "conflict" (when the trait is composed with another trait, + * a unique value for this property is provided by two or more traits) + * + * Data properties bound to the `Trait.required` singleton exported by + * this module will be marked as "required" properties. + * + * @param {Object} object + * Map of properties to compose trait from. + * @returns {Trait} + * Trait / Property descriptor map containing all the own properties of the + * given argument. + */ +function trait(object) { + var map; + var trait = object; + + if (!(object instanceof Trait)) { + // If the passed `object` is not already an instance of `Trait`, we create + // a property descriptor `map` containing descriptors for the own properties + // of the given `object`. `map` is then used to create a `Trait` instance + // after all properties are mapped. Note that we can't create a trait and + // then just copy properties into it since that will fail for inherited + // read-only properties. + map = {}; + + // Each own property of the given `object` is mapped to a data property + // whose value is a property descriptor. + Object.keys(object).forEach(function (name) { + + // If property of an `object` is equal to a `Trait.required`, it means + // that it was marked as "required" property, in which case we map it + // to "required" property. + if (Trait.required == + Object.getOwnPropertyDescriptor(object, name).value) { + map[name] = { + value: RequiredPropertyDescriptor(name), + enumerable: true + }; + } + // Otherwise property is mapped to it's property descriptor. + else { + map[name] = { + value: Object.getOwnPropertyDescriptor(object, name), + enumerable: true + }; + } + }); + + trait = Object.create(Trait.prototype, map); + } + return trait; +} + +/** + * Compose a property descriptor map that inherits from `Trait.prototype` and + * contains property descriptors for all the own properties of the passed + * traits. + * + * If two or more traits have own properties with the same name, the returned + * trait will contain a "conflict" property for that name. Composition is a + * commutative and associative operation, and the order of its arguments is + * irrelevant. + */ +function compose(trait1, trait2/*, ...*/) { + // Create a new property descriptor `map` to which all the own properties + // of the passed traits are copied. This map will be used to create a `Trait` + // instance that will be the result of this composition. + var map = {}; + + // Properties of each passed trait are copied to the composition. + Array.prototype.forEach.call(arguments, function(trait) { + // Copying each property of the given trait. + Object.keys(trait).forEach(function(name) { + + // If `map` already owns a property with the `name` and it is not + // marked "required". + if (owns(map, name) && !map[name].value.required) { + + // If the source trait's property with the `name` is marked as + // "required", we do nothing, as the requirement was already resolved + // by a property in the `map` (because it already contains a + // non-required property with that `name`). But if properties are just + // different, we have a name clash and we substitute it with a property + // that is marked "conflict". + if (!isRequiredProperty(trait, name) && + !equivalentDescriptors(map[name].value, trait[name]) + ) { + map[name] = { + value: ConflictPropertyDescriptor(name), + enumerable: true + }; + } + } + + // Otherwise, the `map` does not have an own property with the `name`, or + // it is marked "required". Either way, the trait's property is copied to + // the map (if the property of the `map` is marked "required", it is going + // to be resolved by the property that is being copied). + else { + map[name] = { value: trait[name], enumerable: true }; + } + }); + }); + + return Object.create(Trait.prototype, map); +} + +/** + * `defineProperties` is like `Object.defineProperties`, except that it + * ensures that: + * - An exception is thrown if any property in a given `properties` map + * is marked as "required" property and same named property is not + * found in a given `prototype`. + * - An exception is thrown if any property in a given `properties` map + * is marked as "conflict" property. + * @param {Object} object + * Object to define properties on. + * @param {Object} properties + * Properties descriptor map. + * @returns {Object} + * `object` that was passed as a first argument. + */ +function defineProperties(object, properties) { + + // Create a map into which we will copy each verified property from the given + // `properties` description map. We use it to verify that none of the + // provided properties is marked as a "conflict" property and that all + // "required" properties are resolved by a property of an `object`, so we + // can throw an exception before mutating object if that isn't the case. + var verifiedProperties = {}; + + // Coping each property from a given `properties` descriptor map to a + // verified map of property descriptors. + Object.keys(properties).forEach(function(name) { + + // If property is marked as "required" property and we don't have a same + // named property in a given `object` we throw an exception. If `object` + // has same named property just skip this property since required property + // is was inherited and there for requirement was satisfied. + if (isRequiredProperty(properties, name)) { + if (!(name in object)) + throwRequiredPropertyError(name); + } + + // If property is marked as "conflict" property we throw an exception. + else if (isConflictProperty(properties, name)) { + throwConflictPropertyError(name); + } + + // If property is not marked neither as "required" nor "conflict" property + // we copy it to verified properties map. + else { + verifiedProperties[name] = properties[name]; + } + }); + + // If no exceptions were thrown yet, we know that our verified property + // descriptor map has no properties marked as "conflict" or "required", + // so we just delegate to the built-in `Object.defineProperties`. + return Object.defineProperties(object, verifiedProperties); +} + +/** + * `create` is like `Object.create`, except that it ensures that: + * - An exception is thrown if any property in a given `properties` map + * is marked as "required" property and same named property is not + * found in a given `prototype`. + * - An exception is thrown if any property in a given `properties` map + * is marked as "conflict" property. + * @param {Object} prototype + * prototype of the composed object + * @param {Object} properties + * Properties descriptor map. + * @returns {Object} + * An object that inherits form a given `prototype` and implements all the + * properties defined by a given `properties` descriptor map. + */ +function create(prototype, properties) { + + // Creating an instance of the given `prototype`. + var object = Object.create(prototype); + + // Overriding `toString`, `constructor` methods if they are just inherited + // from `Object.prototype` with a same named methods of the `Trait.prototype` + // that will have more relevant behavior. + overrideBuiltInMethods(object, Trait.prototype); + + // Trying to define given `properties` on the `object`. We use our custom + // `defineProperties` function instead of build-in `Object.defineProperties` + // that behaves exactly the same, except that it will throw if any + // property in the given `properties` descriptor is marked as "required" or + // "conflict" property. + return defineProperties(object, properties); +} + +/** + * Composes new trait. If two or more traits have own properties with the + * same name, the new trait will contain a "conflict" property for that name. + * "compose" is a commutative and associative operation, and the order of its + * arguments is not significant. + * + * **Note:** Use `Trait.compose` instead of calling this function with more + * than one argument. The multiple-argument functionality is strictly for + * backward compatibility. + * + * @params {Object} trait + * Takes traits as an arguments + * @returns {Object} + * New trait containing the combined own properties of all the traits. + * @example + * var newTrait = compose(trait_1, trait_2, ..., trait_N) + */ +function Trait(trait1, trait2) { + + // If the function was called with one argument, the argument should be + // an object whose properties are mapped to property descriptors on a new + // instance of Trait, so we delegate to the trait function. + // If the function was called with more than one argument, those arguments + // should be instances of Trait or plain property descriptor maps + // whose properties should be mixed into a new instance of Trait, + // so we delegate to the compose function. + + return trait2 === undefined ? trait(trait1) : compose.apply(null, arguments); +} + +Object.freeze(Object.defineProperties(Trait.prototype, { + toString: { + value: function toString() { + return "[object " + this.constructor.name + "]"; + } + }, + + /** + * `create` is like `Object.create`, except that it ensures that: + * - An exception is thrown if this trait defines a property that is + * marked as required property and same named property is not + * found in a given `prototype`. + * - An exception is thrown if this trait contains property that is + * marked as "conflict" property. + * @param {Object} + * prototype of the compared object + * @returns {Object} + * An object with all of the properties described by the trait. + */ + create: { + value: function createTrait(prototype) { + return create(undefined === prototype ? Object.prototype : prototype, + this); + }, + enumerable: true + }, + + /** + * Composes a new resolved trait, with all the same properties as the original + * trait, except that all properties whose name is an own property of + * `resolutions` will be renamed to the value of `resolutions[name]`. If + * `resolutions[name]` is `null`, the property is marked as "required". + * @param {Object} resolutions + * An object whose own properties serve as a mapping from old names to new + * names, or to `null` if the property should be excluded. + * @returns {Object} + * New trait with the same own properties as the original trait but renamed. + */ + resolve: { + value: function resolveTrait(resolutions) { + return resolve(resolutions, this); + }, + enumerable: true + } +})); + +/** + * @see compose + */ +Trait.compose = Object.freeze(compose); +Object.freeze(compose.prototype); + +/** + * Constant singleton, representing placeholder for required properties. + * @type {Object} + */ +Trait.required = Object.freeze(Object.create(Object.prototype, { + toString: { + value: Object.freeze(function toString() { + return ""; + }) + } +})); +Object.freeze(Trait.required.toString.prototype); + +exports.Trait = Object.freeze(Trait); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/list.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/list.js new file mode 100644 index 00000000..e5ccecdf --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/list.js @@ -0,0 +1,147 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +const { Trait } = require('traits'); + +/** + * @see https://jetpack.mozillalabs.com/sdk/latest/docs/#module/api-utils/list + */ +const Iterable = Trait.compose({ + /** + * Hash map of key-values to iterate over. + * Note: That this property can be a getter if you need dynamic behavior. + * @type {Object} + */ + _keyValueMap: Trait.required, + /** + * Custom iterator providing `Iterable`s enumeration behavior. + * @param {Boolean} onKeys + */ + __iterator__: function __iterator__(onKeys, onKeyValue) { + let map = this._keyValueMap; + for (let key in map) + yield onKeyValue ? [key, map[key]] : onKeys ? key : map[key]; + } +}); +exports.Iterable = Iterable; + +/** + * An ordered collection (also known as a sequence) disallowing duplicate + * elements. List is composed out of `Iterable` there for it provides custom + * enumeration behavior that is similar to array (enumerates only on the + * elements of the list). List is a base trait and is meant to be a part of + * composition, since all of it's API is private except length property. + */ +const List = Trait.resolve({ toString: null }).compose({ + _keyValueMap: null, + /** + * List constructor can take any number of element to populate itself. + * @params {Object|String|Number} element + * @example + * List(1,2,3).length == 3 // true + */ + constructor: function List() { + this._keyValueMap = []; + for (let i = 0, ii = arguments.length; i < ii; i++) + this._add(arguments[i]); + }, + /** + * Number of elements in this list. + * @type {Number} + */ + get length() this._keyValueMap.length, + /** + * Returns a string representing this list. + * @returns {String} + */ + toString: function toString() 'List(' + this._keyValueMap + ')', + /** + * Returns `true` if this list contains the specified `element`. + * @param {Object|Number|String} element + * @returns {Boolean} + */ + _has: function _has(element) 0 <= this._keyValueMap.indexOf(element), + /** + * Appends the specified `element` to the end of this list, if it doesn't + * contains it. Ignores the call if `element` is already contained. + * @param {Object|Number|String} element + */ + _add: function _add(element) { + let list = this._keyValueMap, + index = list.indexOf(element); + if (0 > index) + list.push(this._public[list.length] = element); + }, + /** + * Removes specified `element` from this list, if it contains it. + * Ignores the call if `element` is not contained. + * @param {Object|Number|String} element + */ + _remove: function _remove(element) { + let list = this._keyValueMap, + index = list.indexOf(element); + if (0 <= index) { + delete this._public[list.length]; + list.splice(index, 1); + for (let length = list.length; index < length; index++) + this._public[index] = list[index]; + } + }, + /** + * Removes all of the elements from this list. + */ + _clear: function _clear() { + for (let i = 0, ii = this._keyValueMap.length; i < ii; i ++) + delete this._public[i]; + this._keyValueMap.splice(0); + }, + /** + * Custom iterator providing `List`s enumeration behavior. + * We cant reuse `_iterator` that is defined by `Iterable` since it provides + * iteration in an arbitrary order. + * @see https://developer.mozilla.org/en/JavaScript/Reference/Statements/for...in + * @param {Boolean} onKeys + */ + __iterator__: function __iterator__(onKeys, onKeyValue) { + let array = this._keyValueMap.slice(0), + i = -1; + for each(let element in array) + yield onKeyValue ? [++i, element] : onKeys ? ++i : element; + } +}); +exports.List = List; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/match-pattern.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/match-pattern.js new file mode 100644 index 00000000..69b603e3 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/match-pattern.js @@ -0,0 +1,102 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Nickolay Ponomarev. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Nickolay Ponomarev (Original Author) + * Irakli Gozalishvili + * Drew Willcoxon + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const { URL } = require("url"); + +exports.MatchPattern = MatchPattern; + +function MatchPattern(pattern) { + let firstWildcardPosition = pattern.indexOf("*"); + let lastWildcardPosition = pattern.lastIndexOf("*"); + if (firstWildcardPosition != lastWildcardPosition) + throw new Error("There can be at most one '*' character in a wildcard."); + + if (firstWildcardPosition == 0) { + if (pattern.length == 1) + this.anyWebPage = true; + else if (pattern[1] != ".") + throw new Error("Expected a *. string, got: " + pattern); + else + this.domain = pattern.substr(2); + } + else { + if (pattern.indexOf(":") == -1) { + throw new Error("When not using *.example.org wildcard, the string " + + "supplied is expected to be either an exact URL to " + + "match or a URL prefix. The provided string ('" + + pattern + "') is unlikely to match any pages."); + } + + if (firstWildcardPosition == -1) + this.exactURL = pattern; + else if (firstWildcardPosition == pattern.length - 1) + this.urlPrefix = pattern.substr(0, pattern.length - 1); + else { + throw new Error("The provided wildcard ('" + pattern + "') has a '*' " + + "in an unexpected position. It is expected to be the " + + "first or the last character in the wildcard."); + } + } +} + +MatchPattern.prototype = { + + test: function MatchPattern_test(urlStr) { + try { + var url = URL(urlStr); + } + catch (err) { + return false; + } + + if (this.anyWebPage && /^(https?|ftp)$/.test(url.scheme)) + return true; + if (this.exactURL && this.exactURL == urlStr) + return true; + if (this.domain && url.host && + url.host.slice(-this.domain.length) == this.domain) + return true; + if (this.urlPrefix && 0 == urlStr.indexOf(this.urlPrefix)) + return true; + + return false; + } + +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/memory.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/memory.js new file mode 100644 index 00000000..9faeb6cb --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/memory.js @@ -0,0 +1,144 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci,Cu,components} = require("chrome"); +var trackedObjects = {}; + +var Compacter = { + INTERVAL: 5000, + notify: function(timer) { + var newTrackedObjects = {}; + for (name in trackedObjects) { + var oldBin = trackedObjects[name]; + var newBin = []; + var strongRefs = []; + for (var i = 0; i < oldBin.length; i++) { + var strongRef = oldBin[i].weakref.get(); + if (strongRef && strongRefs.indexOf(strongRef) == -1) { + strongRefs.push(strongRef); + newBin.push(oldBin[i]); + } + } + if (newBin.length) + newTrackedObjects[name] = newBin; + } + trackedObjects = newTrackedObjects; + } +}; + +var timer = Cc["@mozilla.org/timer;1"] + .createInstance(Ci.nsITimer); + +timer.initWithCallback(Compacter, + Compacter.INTERVAL, + Ci.nsITimer.TYPE_REPEATING_SLACK); + +var track = exports.track = function track(object, bin, stackFrameNumber) { + var frame = components.stack.caller; + var weakref = Cu.getWeakReference(object); + if (!bin) + bin = object.constructor.name; + if (bin == "Object") + bin = frame.name; + if (!bin) + bin = "generic"; + if (!(bin in trackedObjects)) + trackedObjects[bin] = []; + + if (stackFrameNumber > 0) + for (var i = 0; i < stackFrameNumber; i++) + frame = frame.caller; + + trackedObjects[bin].push({weakref: weakref, + created: new Date(), + filename: frame.filename, + lineNo: frame.lineNumber, + bin: bin}); +}; + +var getBins = exports.getBins = function getBins() { + var names = []; + for (name in trackedObjects) + names.push(name); + return names; +}; + +var getObjects = exports.getObjects = function getObjects(bin) { + function getLiveObjectsInBin(bin, array) { + for (var i = 0; i < bin.length; i++) { + var object = bin[i].weakref.get(); + if (object) + array.push(bin[i]); + } + } + + var results = []; + if (bin) { + if (bin in trackedObjects) + getLiveObjectsInBin(trackedObjects[bin], results); + } else + for (name in trackedObjects) + getLiveObjectsInBin(trackedObjects[name], results); + return results; +}; + +var gc = exports.gc = function gc() { + // Components.utils.forceGC() doesn't currently perform + // cycle collection, which means that e.g. DOM elements + // won't be collected by it. Fortunately, there are + // other ways... + + var window = Cc["@mozilla.org/appshell/appShellService;1"] + .getService(Ci.nsIAppShellService) + .hiddenDOMWindow; + var test_utils = window.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils); + test_utils.garbageCollect(); + Compacter.notify(); + + // Not sure why, but sometimes it appears that we don't get + // them all with just one CC, so let's do it again. + test_utils.garbageCollect(); +}; + +require("unload").when( + function() { + trackedObjects = {}; + if (timer) { + timer.cancel(); + timer = null; + } + }); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/observer-service.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/observer-service.js new file mode 100644 index 00000000..aab68d57 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/observer-service.js @@ -0,0 +1,209 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Observers. + * + * The Initial Developer of the Original Code is Daniel Aquino. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Daniel Aquino + * Myk Melez + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci} = require("chrome"); +var xpcom = require("xpcom"); + +/** + * A service for adding, removing and notifying observers of notifications. + * Wraps the nsIObserverService interface. + * + * @version 0.2 + */ + +var service = Cc["@mozilla.org/observer-service;1"]. + getService(Ci.nsIObserverService); + +/** + * A cache of observers that have been added. + * + * We use this to remove observers when a caller calls |Observers.remove|. + */ +var cache = []; + +/** + * Topics specifically available to Jetpack-generated extensions. + * + * Using these predefined consts instead of the platform strings is good: + * - allows us to scope topics specifically for Jetpacks + * - addons aren't dependent on strings nor behavior of core platform topics + * - the core platform topics are not clearly named + * + */ +exports.topics = { + /** + * A topic indicating that the application is in a state usable + * by add-ons. + */ + get APPLICATION_READY() packaging.jetpackID + "_APPLICATION_READY" +}; + +/** + * Register the given callback as an observer of the given topic. + * + * @param topic {String} + * the topic to observe + * + * @param callback {Object} + * the callback; an Object that implements nsIObserver or a Function + * that gets called when the notification occurs + * + * @param thisObject {Object} [optional] + * the object to use as |this| when calling a Function callback + * + * @returns the observer + */ +var add = exports.add = function add(topic, callback, thisObject) { + var observer = new Observer(topic, callback, thisObject); + service.addObserver(observer, topic, true); + cache.push(observer); + + return observer; +}; + +/** + * Unregister the given callback as an observer of the given topic. + * + * @param topic {String} + * the topic being observed + * + * @param callback {Object} + * the callback doing the observing + * + * @param thisObject {Object} [optional] + * the object being used as |this| when calling a Function callback + */ +var remove = exports.remove = function remove(topic, callback, thisObject) { + // This seems fairly inefficient, but I'm not sure how much better + // we can make it. We could index by topic, but we can't index by callback + // or thisObject, as far as I know, since the keys to JavaScript hashes + // (a.k.a. objects) can apparently only be primitive values. + var [observer] = cache.filter(function(v) { + return (v.topic == topic && + v.callback == callback && + v.thisObject == thisObject); + }); + if (observer) { + service.removeObserver(observer, topic); + cache.splice(cache.indexOf(observer), 1); + } +}; + +/** + * Notify observers about something. + * + * @param topic {String} + * the topic to notify observers about + * + * @param subject {Object} [optional] + * some information about the topic; can be any JS object or primitive + * + * @param data {String} [optional] [deprecated] + * some more information about the topic; deprecated as the subject + * is sufficient to pass all needed information to the JS observers + * that this module targets; if you have multiple values to pass to + * the observer, wrap them in an object and pass them via the subject + * parameter (i.e.: { foo: 1, bar: "some string", baz: myObject }) + */ +var notify = exports.notify = function notify(topic, subject, data) { + subject = (typeof subject == "undefined") ? null : new Subject(subject); + data = (typeof data == "undefined") ? null : data; + service.notifyObservers(subject, topic, data); +}; + +function Observer(topic, callback, thisObject) { + memory.track(this); + this.topic = topic; + this.callback = callback; + this.thisObject = thisObject; +} + +Observer.prototype = { + QueryInterface: xpcom.utils.generateQI([Ci.nsIObserver, + Ci.nsISupportsWeakReference]), + observe: function(subject, topic, data) { + // Extract the wrapped object for subjects that are one of our + // wrappers around a JS object. This way we support both wrapped + // subjects created using this module and those that are real + // XPCOM components. + if (subject && typeof subject == "object" && + ("wrappedJSObject" in subject) && + ("observersModuleSubjectWrapper" in subject.wrappedJSObject)) + subject = subject.wrappedJSObject.object; + + try { + if (typeof this.callback == "function") { + if (this.thisObject) + this.callback.call(this.thisObject, subject, data); + else + this.callback(subject, data); + } else // typeof this.callback == "object" (nsIObserver) + this.callback.observe(subject, topic, data); + } catch (e) { + console.exception(e); + } + } +}; + +function Subject(object) { + // Double-wrap the object and set a property identifying the + // wrappedJSObject as one of our wrappers to distinguish between + // subjects that are one of our wrappers (which we should unwrap + // when notifying our observers) and those that are real JS XPCOM + // components (which we should pass through unaltered). + this.wrappedJSObject = { + observersModuleSubjectWrapper: true, + object: object + }; +} + +Subject.prototype = { + QueryInterface: xpcom.utils.generateQI([]), + getHelperForLanguage: function() {}, + getInterfaces: function() {} +}; + +require("unload").when( + function removeAllObservers() { + // Make a copy of cache first, since cache will be changing as we + // iterate through it. + cache.slice().forEach( + function(observer) { + remove(observer.topic, observer.callback, observer.thisObject); + }); + }); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/passwords/utils.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/passwords/utils.js new file mode 100644 index 00000000..e63840aa --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/passwords/utils.js @@ -0,0 +1,134 @@ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack Packages. + * + * The Initial Developer of the Original Code is Red Hat. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Matěj Cepl (Original Author) + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +const { Cc, Ci, components: { Constructor: CConstructor } } = require("chrome"); +const { uri: ADDON_URI } = require("self"); +const loginManager = Cc["@mozilla.org/login-manager;1"]. + getService(Ci.nsILoginManager); +const { URL: parseURL } = require("url"); +const LoginInfo = CConstructor("@mozilla.org/login-manager/loginInfo;1", + "nsILoginInfo", "init"); + +function filterMatchingLogins(loginInfo) + Object.keys(this).every(function(key) loginInfo[key] === this[key], this); + +/** + * Removes `user`, `password` and `path` fields from the given `url` if it's + * 'http', 'https' or 'ftp'. All other URLs are returned unchanged. + * @example + * http://user:pass@www.site.com/foo/?bar=baz#bang -> http://www.site.com + */ +function normalizeURL(url) { + let { scheme, host, port } = parseURL(url); + // We normalize URL only if it's `http`, `https` or `ftp`. All other types of + // URLs (`resource`, `chrome`, etc..) should not be normalized as they are + // used with add-on associated credentials path. + return scheme === "http" || scheme === "https" || scheme === "ftp" ? + scheme + "://" + (host || "") + (port ? ":" + port : "") : + url +} + +function Login(options) { + let login = Object.create(Login.prototype); + Object.keys(options || {}).forEach(function(key) { + if (key === 'url') + login.hostname = normalizeURL(options.url); + else if (key === 'formSubmitURL') + login.formSubmitURL = options.formSubmitURL ? + normalizeURL(options.formSubmitURL) : null; + else if (key === 'realm') + login.httpRealm = options.realm; + else + login[key] = options[key]; + }); + + return login; +} +Login.prototype.toJSON = function toJSON() { + return { + url: this.hostname || ADDON_URI, + realm: this.httpRealm || null, + formSubmitURL: this.formSubmitURL || null, + username: this.username || null, + password: this.password || null, + usernameField: this.usernameField || '', + passwordField: this.passwordField || '', + } +}; +Login.prototype.toLoginInfo = function toLoginInfo() { + let { url, realm, formSubmitURL, username, password, usernameField, + passwordField } = this.toJSON(); + + return new LoginInfo(url, formSubmitURL, realm, username, password, + usernameField, passwordField); +}; + +function loginToJSON(value) Login(value).toJSON() + +/** + * Returns array of `nsILoginInfo` objects that are stored in the login manager + * and have all the properties with matching values as a given `options` object. + * @param {Object} options + * @returns {nsILoginInfo[]} + */ +exports.search = function search(options) { + return loginManager.getAllLogins() + .filter(filterMatchingLogins, Login(options)) + .map(loginToJSON); +}; + +/** + * Stores login info created from the given `options` to the applications + * built-in login management system. + * @param {Object} options. + */ +exports.store = function store(options) { + loginManager.addLogin(Login(options).toLoginInfo()); +}; + +/** + * Removes login info from the applications built-in login management system. + * _Please note: When removing a login info the specified properties must + * exactly match to the one that is already stored or exception will be thrown._ + * @param {Object} options. + */ +exports.remove = function remove(options) { + loginManager.removeLogin(Login(options).toLoginInfo()); +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/plain-text-console.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/plain-text-console.js new file mode 100644 index 00000000..6adb3e8a --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/plain-text-console.js @@ -0,0 +1,112 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci} = require("chrome"); + +function stringify(arg) { + try { + return String(arg); + } + catch(ex) { + return ""; + } +} + +function stringifyArgs(args) { + return Array.map(args, stringify).join(" "); +} + +function message(print, level, args) { + print(level + ": " + stringifyArgs(args) + "\n"); +} + +var Console = exports.PlainTextConsole = function PlainTextConsole(print) { + if (!print) + print = dump; + if (print === dump) { + // If we're just using dump(), auto-enable preferences so + // that the developer actually sees the console output. + var prefs = Cc["@mozilla.org/preferences-service;1"] + .getService(Ci.nsIPrefBranch); + prefs.setBoolPref("browser.dom.window.dump.enabled", true); + } + this.print = print; + + // Binding all the public methods to an instance so that they can be used + // as callback / listener functions straightaway. + this.log = this.log.bind(this); + this.info = this.info.bind(this); + this.warn = this.warn.bind(this); + this.error = this.error.bind(this); + this.debug = this.debug.bind(this); + this.exception = this.exception.bind(this); + this.trace = this.trace.bind(this); +}; + +Console.prototype = { + log: function log() { + message(this.print, "info", arguments); + }, + + info: function info() { + message(this.print, "info", arguments); + }, + + warn: function warn() { + message(this.print, "warning", arguments); + }, + + error: function error() { + message(this.print, "error", arguments); + }, + + debug: function debug() { + message(this.print, "debug", arguments); + }, + + exception: function exception(e) { + var fullString = ("An exception occurred.\n" + + require("traceback").format(e) + "\n" + e); + this.error(fullString); + }, + + trace: function trace() { + var traceback = require("traceback"); + var stack = traceback.get(); + stack.splice(-1, 1); + message(this.print, "info", [traceback.format(stack)]); + } +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/preferences-service.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/preferences-service.js new file mode 100644 index 00000000..360a7811 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/preferences-service.js @@ -0,0 +1,137 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Preferences. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2008 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Myk Melez + * Daniel Aquino + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// The minimum and maximum integers that can be set as preferences. +// The range of valid values is narrower than the range of valid JS values +// because the native preferences code treats integers as NSPR PRInt32s, +// which are 32-bit signed integers on all platforms. +const MAX_INT = Math.pow(2, 31) - 1; +const MIN_INT = -MAX_INT; + +const {Cc,Ci,Cr} = require("chrome"); + +var prefSvc = Cc["@mozilla.org/preferences-service;1"]. + getService(Ci.nsIPrefService).getBranch(null); + +var get = exports.get = function get(name, defaultValue) { + switch (prefSvc.getPrefType(name)) { + case Ci.nsIPrefBranch.PREF_STRING: + return prefSvc.getComplexValue(name, Ci.nsISupportsString).data; + + case Ci.nsIPrefBranch.PREF_INT: + return prefSvc.getIntPref(name); + + case Ci.nsIPrefBranch.PREF_BOOL: + return prefSvc.getBoolPref(name); + + case Ci.nsIPrefBranch.PREF_INVALID: + return defaultValue; + + default: + // This should never happen. + throw new Error("Error getting pref " + name + + "; its value's type is " + + prefSvc.getPrefType(name) + + ", which I don't know " + + "how to handle."); + } +}; + +var set = exports.set = function set(name, value) { + var prefType; + if (typeof value != "undefined" && value != null) + prefType = value.constructor.name; + + switch (prefType) { + case "String": + { + var string = Cc["@mozilla.org/supports-string;1"]. + createInstance(Ci.nsISupportsString); + string.data = value; + prefSvc.setComplexValue(name, Ci.nsISupportsString, string); + } + break; + + case "Number": + // We throw if the number is outside the range, since the result + // will never be what the consumer wanted to store, but we only warn + // if the number is non-integer, since the consumer might not mind + // the loss of precision. + if (value > MAX_INT || value < MIN_INT) + throw new Error("you cannot set the " + name + + " pref to the number " + value + + ", as number pref values must be in the signed " + + "32-bit integer range -(2^31-1) to 2^31-1. " + + "To store numbers outside that range, store " + + "them as strings."); + if (value % 1 != 0) + throw new Error("cannot store non-integer number: " + value); + prefSvc.setIntPref(name, value); + break; + + case "Boolean": + prefSvc.setBoolPref(name, value); + break; + + default: + throw new Error("can't set pref " + name + " to value '" + value + + "'; it isn't a String, Number, or Boolean"); + } +}; + +var has = exports.has = function has(name) { + return (prefSvc.getPrefType(name) != Ci.nsIPrefBranch.PREF_INVALID); +}; + +var isSet = exports.isSet = function isSet(name) { + return (has(name) && prefSvc.prefHasUserValue(name)); +}; + +var reset = exports.reset = function reset(name) { + try { + prefSvc.clearUserPref(name); + } catch (e if e.result == Cr.NS_ERROR_UNEXPECTED) { + // The pref service throws NS_ERROR_UNEXPECTED when the caller tries + // to reset a pref that doesn't exist or is already set to its default + // value. This interface fails silently in those cases, so callers + // can unconditionally reset a pref without having to check if it needs + // resetting first or trap exceptions after the fact. It passes through + // other exceptions, however, so callers know about them, since we don't + // know what other exceptions might be thrown and what they might mean. + } +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/securable-module.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/securable-module.js new file mode 100644 index 00000000..eacdb7a7 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/securable-module.js @@ -0,0 +1,630 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Copyright (c) 2009-2010 the Mozilla Foundation + * All rights reserved. + * + * Redistribution and use 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 the Mozilla Foundation 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. + * + * ***** END LICENSE BLOCK ***** */ + +(function(global) { + const Cc = Components.classes; + const Ci = Components.interfaces; + const Cu = Components.utils; + const Cr = Components.results; + + var exports = {}; + + var ios = Cc['@mozilla.org/network/io-service;1'] + .getService(Ci.nsIIOService); + + var systemPrincipal = Cc["@mozilla.org/systemprincipal;1"] + .createInstance(Ci.nsIPrincipal); + + // Even though manifest.py does some dependency scanning, that + // scan is done as part of an evaluation of what the add-on needs + // for security purposes. The following regexps are used to scan for + // dependencies inside a simplified define() callback: + // define(function(require, exports, module){ var a = require('a'); }); + // and are used at runtime ensure the dependencies needed by + // the define factory function are already evaluated and ready. + // Even though this loader is a sync loader, and could fetch the module + // as the require() call happens, it would differ in behavior as + // compared to the async browser case, which would make sure to execute + // the dependencies first before executing the define() factory function. + // So this dependency scanning and evaluation is kept to match the + // async behavior. + var commentRegExp = /(\/\*([\s\S]*?)\*\/|\/\/(.*)$)/mg; + var cjsRequireRegExp = /require\(["']([\w\!\-_\.\/]+)["']\)/g; + var cjsStandardDeps = ['require', 'exports', 'module']; + + function resolvePrincipal(principal, defaultPrincipal) { + if (principal === undefined) + return defaultPrincipal; + if (principal == "system") + return systemPrincipal; + return principal; + } + + // The base URI to we use when we're given relative URLs, if any. + var baseURI = null; + if (global.window) + baseURI = ios.newURI(global.location.href, null, null); + exports.baseURI = baseURI; + + // The "parent" chrome URI to use if we're loading code that + // needs chrome privileges but may not have a filename that + // matches any of SpiderMonkey's defined system filename prefixes. + // The latter is needed so that wrappers can be automatically + // made for the code. For more information on this, see + // bug 418356: + // + // https://bugzilla.mozilla.org/show_bug.cgi?id=418356 + var parentChromeURIString; + if (baseURI) + // We're being loaded from a chrome-privileged document, so + // use its URL as the parent string. + parentChromeURIString = baseURI.spec; + else + // We're being loaded from a chrome-privileged JS module or + // SecurableModule, so use its filename (which may itself + // contain a reference to a parent). + parentChromeURIString = Components.stack.filename; + + function maybeParentifyFilename(filename) { + var doParentifyFilename = true; + try { + // TODO: Ideally we should just make + // nsIChromeRegistry.wrappersEnabled() available from script + // and use it here. Until that's in the platform, though, + // we'll play it safe and parentify the filename unless + // we're absolutely certain things will be ok if we don't. + var filenameURI = ios.newURI(options.filename, + null, + baseURI); + if (filenameURI.scheme == 'chrome' && + filenameURI.path.indexOf('/content/') == 0) + // Content packages will always have wrappers made for them; + // if automatic wrappers have been disabled for the + // chrome package via a chrome manifest flag, then + // this still works too, to the extent that the + // content package is insecure anyways. + doParentifyFilename = false; + } catch (e) {} + if (doParentifyFilename) + return parentChromeURIString + " -> " + filename; + return filename; + } + + function getRootDir(urlStr) { + // TODO: This feels hacky, and like there will be edge cases. + return urlStr.slice(0, urlStr.lastIndexOf("/") + 1); + } + + exports.SandboxFactory = function SandboxFactory(defaultPrincipal) { + // Unless specified otherwise, use a principal with limited + // privileges. + this._defaultPrincipal = resolvePrincipal(defaultPrincipal, + "http://www.mozilla.org"); + }, + + exports.SandboxFactory.prototype = { + createSandbox: function createSandbox(options) { + var principal = resolvePrincipal(options.principal, + this._defaultPrincipal); + + return { + _sandbox: new Cu.Sandbox(principal), + _principal: principal, + get globalScope() { + return this._sandbox; + }, + defineProperty: function defineProperty(name, value) { + this._sandbox[name] = value; + }, + getProperty: function getProperty(name) { + return this._sandbox[name]; + }, + evaluate: function evaluate(options) { + if (typeof(options) == 'string') + options = {contents: options}; + options = {__proto__: options}; + if (typeof(options.contents) != 'string') + throw new Error('Expected string for options.contents'); + if (options.lineNo === undefined) + options.lineNo = 1; + if (options.jsVersion === undefined) + options.jsVersion = "1.8"; + if (typeof(options.filename) != 'string') + options.filename = ''; + + if (this._principal == systemPrincipal) + options.filename = maybeParentifyFilename(options.filename); + + return Cu.evalInSandbox(options.contents, + this._sandbox, + options.jsVersion, + options.filename, + options.lineNo); + } + }; + } + }; + + exports.Loader = function Loader(options) { + options = {__proto__: options}; + if (options.fs === undefined) { + var rootPaths = options.rootPath || options.rootPaths; + if (rootPaths) { + if (rootPaths.constructor.name != "Array") + rootPaths = [rootPaths]; + var fses = [new exports.LocalFileSystem(path) + for each (path in rootPaths)]; + options.fs = new exports.CompositeFileSystem(fses); + } else + options.fs = new exports.LocalFileSystem(); + } + if (options.sandboxFactory === undefined) + options.sandboxFactory = new exports.SandboxFactory( + options.defaultPrincipal + ); + if ('modules' in options) + throw new Error('options.modules is no longer supported'); + // pathAccessed used to know if a module was accessed/required + // by another module, and in that case, assigning the module value + // via a define callback is not allowed. + if (options.pathAccessed === undefined) + options.pathAccessed = {}; + if (options.globals === undefined) + options.globals = {}; + + this.fs = options.fs; + this.sandboxFactory = options.sandboxFactory; + this.sandboxes = {}; + this.modules = {}; + this.pathAccessed = options.pathAccessed; + this.module_infos = {}; + this.pathToModule = {}; + this.defineUsed = {}; + this.globals = options.globals; + this.getModuleExports = options.getModuleExports; + this.modifyModuleSandbox = options.modifyModuleSandbox; + this.securityPolicy = options.securityPolicy; + }; + + exports.Loader.prototype = { + _makeApi: function _makeApi(basePath) { + var self = this; + + function syncRequire(module) { + var exports; + + if (self.getModuleExports) + exports = self.getModuleExports(basePath, module); + + var module_info = null; /* null for require("chrome") */ + if (!exports) { + var path = self.fs.resolveModule(basePath, module); + if (!path) + throw new Error('Module "' + module + '" not found'); + + // Track accesses to this module via its normalized path + if (!self.pathAccessed[path]) { + self.pathAccessed[path] = 0; + } + self.pathAccessed[path] += 1; + + // Remember the name of the module as it maps to its path + self.pathToModule[path] = module; + + if (path in self.modules) { + module_info = self.module_infos[path]; + } else { + module_info = self.fs.getFile(path); + /* module_info.filename is read by sandbox.evaluate() to + generate tracebacks, so the property must be named + ".filename" even though ".url" might be more accurate */ + if (module_info.filename === undefined) + module_info.filename = path; + + if (self.securityPolicy && + !self.securityPolicy.allowEval(self, basePath, module, + module_info)) + throw new Error("access denied to execute module: " + + module); + + var sandbox = self.sandboxFactory.createSandbox(module_info); + self.sandboxes[path] = sandbox; + for (name in self.globals) + sandbox.defineProperty(name, self.globals[name]); + var api = self._makeApi(path); + sandbox.defineProperty('require', api.require); + sandbox.defineProperty('define', api.define); + self.module_infos[path] = module_info; + if (self.modifyModuleSandbox) + self.modifyModuleSandbox(sandbox, module_info); + /* set up an environment in which module code can use CommonJS + patterns like: + module.exports = newobj; + module.setExports(newobj); + if (module.id == "main") stuff(); + define("async", function() {return newobj}); + */ + sandbox.evaluate("var module = {exports: {}};"); + sandbox.evaluate("module.setExports = function(obj) {module.exports = obj; return obj;};"); + sandbox.evaluate("var exports = module.exports;"); + sandbox.evaluate("module.id = '" + module + "';"); + var preeval_exports = sandbox.getProperty("exports"); + self.modules[path] = sandbox.getProperty("exports"); + sandbox.evaluate(module_info); + var posteval_exports = sandbox.getProperty("module").exports; + if (posteval_exports !== preeval_exports) { + /* if they used module.exports= or module.setExports(), get + the new value now. If they used define(), we must be + careful to leave self.modules[path] alone, as it will have + been modified in the asyncMain() callback-handling code, + fired during sandbox.evaluate(). */ + if (self.defineUsed[path]) { + // you can do one or the other, not both + throw new Error("define() was used, so module.exports= and " + + "module.setExports() may not be used: " + + path); + } + self.modules[path] = posteval_exports; + } + } + exports = self.modules[path]; + } + + if (self.securityPolicy && + !self.securityPolicy.allowImport(self, basePath, module, + module_info, exports)) + throw new Error("access denied to import module: " + module); + + return exports; + }; + + // START support Async module-style require and define calls. + // If the only argument to require is a string, then the module that + // is represented by that string is fetched for the appropriate context. + // + // If the first argument is an array, then it will be treated as an array + // of dependency string names to fetch. An optional function callback can + // be specified to execute when all of those dependencies are available. + function asyncRequire(deps, callback) { + if (typeof deps === "string" && !callback) { + // Just return the module wanted via sync require. + return syncRequire(deps); + } else { + asyncMain(null, basePath, null, deps, callback); + return undefined; + } + } + + // The function that handles definitions of modules. Differs from + // require() in that a string for the module should be the first + // argument, and the function to execute after dependencies are loaded + // should return a value to define the module corresponding to the first + // argument's name. + function define (name, deps, callback) { + + // Only allow one call to define per module/file. + if (self.defineUsed[basePath]) { + throw new Error("Only one call to define() allowed per file: " + + basePath); + } else { + self.defineUsed[basePath] = true; + } + + // For anonymous modules, the namePath is the basePath + var namePath = basePath, + exports = {}, exported; + + // Adjust args if an anonymous module + if (typeof name !== 'string') { + callback = deps; + deps = name; + name = null; + } + + // If just a define({}) call (no dependencies), + // adjust args accordingly. + if (!Array.isArray(deps)) { + callback = deps; + deps = null; + } + + // Set up the path if we have a name + if (name) { + // Make sure that the name matches the expected name, otherwise + // throw an error. + namePath = self.fs.resolveModule(basePath, name); + if (self.pathToModule[namePath] !== name) { + throw new Error("Mismatched define(). Named module " + name + + " does not match expected name of " + + self.pathToModule[basePath] + + " in " + basePath); + } + } + + // If the callback is not an actual function, it means it already + // has the definition of the module as a literal value. + if (!deps && callback && typeof callback !== 'function') { + self.modules[namePath] = callback; + return; + } + + // Set the exports value now in case other modules need a handle + // on it for cyclical cases. + self.modules[namePath] = exports; + + // Load dependencies and call the module's definition function. + exported = asyncMain(name, namePath, exports, deps, callback); + + // Assign output of function to name, if exports was not + // in play (which asyncMain already figured out). + if (exported !== undefined) { + if (self.pathAccessed[namePath] > 1) { + // Another module already accessed the exported value, + // need to throw to avoid nasty circular dependency weirdness + throw new Error('Module "' + (name || namePath) + '" cannot use ' + + 'return from define to define the module ' + + 'after another module has referenced its ' + + 'exported value.'); + } else { + self.modules[namePath] = exported; + } + } + } + + // The function that handles the main async module work, for both + // require([], function(){}) calls and define calls. + // It makes sure all the dependencies exist before calling the + // callback function. It will return the result of the callback + // function if "exports" is not a dependency. + function asyncMain (name, namePath, exports, deps, callback) { + + if (typeof deps === 'function') { + callback = deps; + deps = null; + } + + if (!deps) { + deps = []; + // The shortened form of the async wrapper for CommonJS modules: + // define(function (require, exports, module) {}); + // require calls could be inside the function, so toString it + // and pull out the dependencies. + + // Remove comments from the callback string, + // look for require calls, and pull them into the dependencies. + // The comment regexp is not very robust, but good enough to + // avoid commented out require calls and to find normal, sync + // require calls in the function. + callback + .toString() + .replace(commentRegExp, "") + .replace(cjsRequireRegExp, function (match, dep) { + deps.push(dep); + }); + // Prepend standard require, exports, and module dependencies + // (and in that *exact* order per spec), but only add as many as + // was asked for via the callback's function argument length. + // In particular, do *not* pass exports if it was not asked for. + // By asking for exports as a dependency the rest of this + // asyncRequire code assumes then that the return value from the + // function should not be used as the exported module value. + deps = cjsStandardDeps.slice(0, callback.length).concat(deps); + } + + var depModules = [], + usesExports = false, + exported; + + // Load all the dependencies, with the "require", "exports" and + // "module" ones getting special handling to match the traditional + // CommonJS sync module expectations. + deps.forEach(function (dep) { + if (dep === "require") { + depModules.push(asyncRequire); + } else if (dep === "module") { + depModules.push({ + id: name + }); + } else if (dep === "exports") { + usesExports = true; + depModules.push(exports); + } else { + var overridden; + if (self.getModuleExports) + overridden = self.getModuleExports(basePath, dep); + if (overridden) { + depModules.push(overridden); + return; + } + + var depPath = self.fs.resolveModule(basePath, dep); + + if (!self.modules[depPath]) { + syncRequire(dep); + } + depModules.push(self.modules[depPath]); + } + }); + + // Execute the function. + if (callback) { + exported = callback.apply(null, depModules); + } + + if (exported !== undefined) { + if (usesExports) { + throw new Error('Inside "' + namePath + '", cannot use exports ' + + 'and also return a value from a define ' + + 'definition function'); + } else { + return exported; + } + } + return undefined; + }; + + return { + require: asyncRequire, + define: define + }; + // END support for Async module-style + }, + + // This is only really used by unit tests and other + // development-related facilities, allowing access to symbols + // defined in the global scope of a module. + findSandboxForModule: function findSandboxForModule(module) { + var path = this.fs.resolveModule(null, module); + if (!path) + throw new Error('Module "' + module + '" not found'); + if (!(path in this.sandboxes)) + this.require(module); + if (!(path in this.sandboxes)) + throw new Error('Internal error: path not in sandboxes: ' + + path); + return this.sandboxes[path]; + }, + + require: function require(module, callback) { + return (this._makeApi(null).require)(module, callback); + }, + + runScript: function runScript(options, extraOutput) { + if (typeof(options) == 'string') + options = {contents: options}; + options = {__proto__: options}; + var sandbox = this.sandboxFactory.createSandbox(options); + if (extraOutput) + extraOutput.sandbox = sandbox; + for (name in this.globals) + sandbox.defineProperty(name, this.globals[name]); + var api = this._makeApi(null); + sandbox.defineProperty('require', api.require); + sandbox.defineProperty('define', api.define); + return sandbox.evaluate(options); + } + }; + + exports.CompositeFileSystem = function CompositeFileSystem(fses) { + this.fses = fses; + this._pathMap = {}; + }; + + exports.CompositeFileSystem.prototype = { + resolveModule: function resolveModule(base, path) { + for (var i = 0; i < this.fses.length; i++) { + var fs = this.fses[i]; + var absPath = fs.resolveModule(base, path); + if (absPath) { + this._pathMap[absPath] = fs; + return absPath; + } + } + return null; + }, + getFile: function getFile(path) { + return this._pathMap[path].getFile(path); + } + }; + + exports.LocalFileSystem = function LocalFileSystem(root) { + if (root === undefined) { + if (!baseURI) + throw new Error("Need a root path for module filesystem"); + root = baseURI; + } + if (typeof(root) == 'string') + root = ios.newURI(root, null, baseURI); + if (root instanceof Ci.nsIFile) + root = ios.newFileURI(root); + if (!(root instanceof Ci.nsIURI)) + throw new Error('Expected nsIFile, nsIURI, or string for root'); + + this.root = root.spec; + this._rootURI = root; + this._rootURIDir = getRootDir(root.spec); + }; + + exports.LocalFileSystem.prototype = { + resolveModule: function resolveModule(base, path) { + path = path + ".js"; + + var baseURI; + if (!base || path.charAt(0) != '.') + baseURI = this._rootURI; + else + baseURI = ios.newURI(base, null, null); + var newURI = ios.newURI(path, null, baseURI); + if (newURI.spec.indexOf(this._rootURIDir) == 0) { + var channel = ios.newChannelFromURI(newURI); + try { + channel.open().close(); + } catch (e if e.result == Cr.NS_ERROR_FILE_NOT_FOUND) { + return null; + } + return newURI.spec; + } + return null; + }, + getFile: function getFile(path) { + var channel = ios.newChannel(path, null, null); + var iStream = channel.open(); + var ciStream = Cc["@mozilla.org/intl/converter-input-stream;1"]. + createInstance(Ci.nsIConverterInputStream); + var bufLen = 0x8000; + ciStream.init(iStream, "UTF-8", bufLen, + Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + var chunk = {}; + var data = ""; + while (ciStream.readString(bufLen, chunk) > 0) + data += chunk.value; + ciStream.close(); + iStream.close(); + return {contents: data}; + } + }; + + if (global.window) { + // We're being loaded in a chrome window, or a web page with + // UniversalXPConnect privileges. + global.SecurableModule = exports; + } else if (global.exports) { + // We're being loaded in a SecurableModule. + for (name in exports) { + global.exports[name] = exports[name]; + } + } else { + // We're being loaded in a JS module. + global.EXPORTED_SYMBOLS = []; + for (name in exports) { + global.EXPORTED_SYMBOLS.push(name); + global[name] = exports[name]; + } + } + })(this); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self-e10s-adapter.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self-e10s-adapter.js new file mode 100644 index 00000000..9a07c3ea --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self-e10s-adapter.js @@ -0,0 +1,95 @@ +// While this adapter is complete, it most likely isn't very secure, +// in that it allows the remote addon process to ask for any content +// on the host filesystem. + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +if (this.chrome) { + exports.id = chrome.call("self:id"); + exports.data = { + load: function(path) { + return chrome.call("self:load", path, new Error().stack); + }, + url: function(path) { + return chrome.call("self:url", path, new Error().stack); + } + }; +} else { + // Here we basically have to reimplement the self module. + + let file = require("file"); + let url = require("url"); + let traceback = require("traceback"); + + let packageData = packaging.options.packageData; + let resourcePackages = packaging.options.resourcePackages; + let id = packaging.jetpackID; + + function caller(stack, levels) { + var e = { + stack: stack + }; + let callerInfo = traceback.fromException(e).slice(-2-levels)[0]; + let info = url.URL(callerInfo.filename); + let pkgName = resourcePackages[info.host]; + // pkgName is "my-package", suitable for lookup in options["packageData"] + return pkgName; + } + + function getURL(name, stack, level) { + let pkgName = caller(stack, level); + // packageData[] = "resource://jetpack-JID-PKGNAME-data/" + if (pkgName in packageData) + return url.URL(name, packageData[pkgName]).toString(); + throw new Error("No data for package " + pkgName); + } + + exports.register = function(addon) { + addon.registerCall("self:id", function(name) { + return id; + }); + addon.registerCall("self:load", function(name, path, stack) { + let data_url = getURL(path, stack, 1); + let fn = url.toFilename(data_url); + let data = file.read(fn); + return data; + }); + addon.registerCall("self:url", function(name, path, stack) { + return getURL(path, stack, 1); + }); + } +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js new file mode 100644 index 00000000..42d772d2 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/self.js @@ -0,0 +1,59 @@ + +let file = require("file"); +let url = require("url"); +let traceback = require("traceback"); + +let packageData = packaging.options.packageData; +let resourcePackages = packaging.options.resourcePackages; +let id = packaging.jetpackID; +exports.id = id; + +// Some XPCOM APIs require valid URIs as an argument for certain operations (see +// `nsILoginManager` for example). This property represents add-on associated +// unique URI string that can be used for that. +exports.uri = "addon:" + id; + +// what URI was our Nth parent stack frame loaded from? We use this to +// determine "who" has called our load() or url() methods. This is an +// unpleasant hack that needs to be replaced: the real question to ask is +// "who" did the require("self") call. The "self" module should not be a +// singleton: each invocation of require() could get a separate one. I +// *think* the right level of granularity is that each package gets a +// separate instance: all packages in an XPI bundle will share the same +// ID, but each package will have a separate resource/data directory. So +// package1.moduleA and package1.moduleB will both get the same data when +// they do require("self").data.load("foo.txt"), but package2.moduleC +// will get something different for the same code. + +// The biggest problem with using stack introspection at the time of +// load()/url() is confusion: the module is allowed to pass their +// require("self").data object to someone else, with the expectation that +// the recipient is going to get the same data they would have gotten. +// The second biggest problem is confused deputy. + +function caller(levels) { + let callerInfo = traceback.get().slice(-2-levels)[0]; + let info = url.URL(callerInfo.filename); + let pkgName = resourcePackages[info.host]; + // pkgName is "my-package", suitable for lookup in options["packageData"] + return pkgName; +} + +function getURL(name, level) { + let pkgName = caller(level+1); + // packageData[] = "resource://jetpack-JID-PKGNAME-data/" + if (pkgName in packageData) + return url.URL(name, packageData[pkgName]).toString(); + throw new Error("No data for package " + pkgName); +} + +exports.data = { + load: function load(name) { + let data_url = getURL(name, 1); + let fn = url.toFilename(data_url); + let data = file.read(fn); + return data; + }, + url: function url(name) { return getURL(name, 1); } +} + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tab-browser.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tab-browser.js new file mode 100644 index 00000000..ea244a36 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tab-browser.js @@ -0,0 +1,761 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * Dietrich Ayala + * Felipe Gomes + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci,Cu} = require("chrome"); +var NetUtil = {}; +Cu.import("resource://gre/modules/NetUtil.jsm", NetUtil); +NetUtil = NetUtil.NetUtil; +const errors = require("errors"); +const windowUtils = require("window-utils"); +const apiUtils = require("api-utils"); +const collection = require("collection"); + +// TODO: The hard-coding of app-specific info here isn't very nice; +// ideally such app-specific info should be more decoupled, and the +// module should be extensible, allowing for support of new apps at +// runtime, perhaps by inspecting supported packages (e.g. via +// dynamically-named modules or package-defined extension points). + +if (!require("xul-app").is("Firefox")) { + throw new Error([ + "The tab-browser module currently supports only Firefox. In the future ", + "it will support other applications. Please see ", + "https://bugzilla.mozilla.org/show_bug.cgi?id=560716 for more information." + ].join("")); +} + +// Utility function to open a new browser window. +function openBrowserWindow(callback, url) { + let ww = Cc["@mozilla.org/embedcomp/window-watcher;1"]. + getService(Ci.nsIWindowWatcher); + let urlString = Cc["@mozilla.org/supports-string;1"]. + createInstance(Ci.nsISupportsString); + urlString.data = url; + let window = ww.openWindow(null, "chrome://browser/content/browser.xul", + "_blank", "chrome,all,dialog=no", urlString); + if (callback) { + function onLoad(event) { + if (event.target && event.target.defaultView == window) { + window.removeEventListener("load", onLoad, true); + try { + require("timer").setTimeout(function () { + callback(event); + }, 10); + } catch (e) { console.exception(e); } + } + } + + window.addEventListener("load", onLoad, true); + } + + return window; +} + +// Open a URL in a new tab +exports.addTab = function addTab(url, options) { + if (!options) + options = {}; + options.url = url; + + options = apiUtils.validateOptions(options, { + // TODO: take URL object instead of string (bug 564524) + url: { + is: ["string"], + ok: function (v) !!v, + msg: "The url parameter must have be a non-empty string." + }, + inNewWindow: { + is: ["undefined", "null", "boolean"] + }, + inBackground: { + is: ["undefined", "null", "boolean"] + }, + onLoad: { + is: ["undefined", "null", "function"] + }, + isPinned: { + is: ["undefined", "boolean"] + } + }); + + var wm = Cc["@mozilla.org/appshell/window-mediator;1"] + .getService(Ci.nsIWindowMediator); + var win = wm.getMostRecentWindow("navigator:browser"); + if (!win || options.inNewWindow) { + openBrowserWindow(function(e) { + if(options.isPinned) { + //get the active tab in the recently created window + let mainWindow = e.target.defaultView; + mainWindow.gBrowser.pinTab(mainWindow.gBrowser.selectedTab); + } + require("errors").catchAndLog(function(e) options.onLoad(e))(e); + }, options.url); + } else { + let tab = win.gBrowser.addTab(options.url); + if (!options.inBackground) + win.gBrowser.selectedTab = tab; + if (options.onLoad) { + let tabBrowser = win.gBrowser.getBrowserForTab(tab); + tabBrowser.addEventListener("load", function(e) { + if (e.target.defaultView.content.location == "about:blank") + return; + // remove event handler from addTab - don't want notified + // for subsequent loads in same tab. + tabBrowser.removeEventListener("load", arguments.callee, true); + require("errors").catchAndLog(function(e) options.onLoad(e))(e); + }, true); + } + } +} + +// Iterate over a window's tabbrowsers +function tabBrowserIterator(window) { + var browsers = window.document.querySelectorAll("tabbrowser"); + for (var i = 0; i < browsers.length; i++) + yield browsers[i]; +} + +// Iterate over a tabbrowser's tabs +function tabIterator(tabbrowser) { + var tabs = tabbrowser.tabContainer; + for (var i = 0; i < tabs.children.length; i++) { + yield tabs.children[i]; + } +} + +// Tracker for all tabbrowsers across all windows, +// or a single tabbrowser if the window is given. +function Tracker(delegate, window) { + this._delegate = delegate; + this._browsers = []; + this._window = window; + this._windowTracker = new windowUtils.WindowTracker(this); + + require("unload").ensure(this); +} +Tracker.prototype = { + __iterator__: function __iterator__() { + for (var i = 0; i < this._browsers.length; i++) + yield this._browsers[i]; + }, + get: function get(index) { + return this._browsers[index]; + }, + onTrack: function onTrack(window) { + if (this._window && window != this._window) + return; + + for (browser in tabBrowserIterator(window)) + this._browsers.push(browser); + if (this._delegate) + for (browser in tabBrowserIterator(window)) + this._delegate.onTrack(browser); + }, + onUntrack: function onUntrack(window) { + if (this._window && window != this._window) + return; + + for (browser in tabBrowserIterator(window)) { + let index = this._browsers.indexOf(browser); + if (index != -1) + this._browsers.splice(index, 1); + else + console.error("internal error: browser tab not found"); + } + if (this._delegate) + for (browser in tabBrowserIterator(window)) + this._delegate.onUntrack(browser); + }, + get length() { + return this._browsers.length; + }, + unload: function unload() { + this._windowTracker.unload(); + } +}; +exports.Tracker = apiUtils.publicConstructor(Tracker); + +// Tracker for all tabs across all windows, +// or a single window if it's given. +function TabTracker(delegate, window) { + this._delegate = delegate; + this._tabs = []; + this._tracker = new Tracker(this, window); + require("unload").ensure(this); +} +TabTracker.prototype = { + _TAB_EVENTS: ["TabOpen", "TabClose"], + _safeTrackTab: function safeTrackTab(tab) { + this._tabs.push(tab); + try { + this._delegate.onTrack(tab); + } catch (e) { + console.exception(e); + } + }, + _safeUntrackTab: function safeUntrackTab(tab) { + var index = this._tabs.indexOf(tab); + if (index == -1) + console.error("internal error: tab not found"); + this._tabs.splice(index, 1); + try { + this._delegate.onUntrack(tab); + } catch (e) { + console.exception(e); + } + }, + handleEvent: function handleEvent(event) { + switch (event.type) { + case "TabOpen": + this._safeTrackTab(event.target); + break; + case "TabClose": + this._safeUntrackTab(event.target); + break; + default: + throw new Error("internal error: unknown event type: " + + event.type); + } + }, + onTrack: function onTrack(tabbrowser) { + for (tab in tabIterator(tabbrowser)) + this._safeTrackTab(tab); + var self = this; + this._TAB_EVENTS.forEach( + function(eventName) { + tabbrowser.tabContainer.addEventListener(eventName, self, true); + }); + }, + onUntrack: function onUntrack(tabbrowser) { + for (tab in tabIterator(tabbrowser)) + this._safeUntrackTab(tab); + var self = this; + this._TAB_EVENTS.forEach( + function(eventName) { + tabbrowser.tabContainer.removeEventListener(eventName, self, true); + }); + }, + unload: function unload() { + this._tracker.unload(); + } +}; +exports.TabTracker = apiUtils.publicConstructor(TabTracker); + +exports.whenContentLoaded = function whenContentLoaded(callback) { + var cb = require("errors").catchAndLog(function eventHandler(event) { + if (event.target && event.target.defaultView) + callback(event.target.defaultView); + }); + + var tracker = new Tracker({ + onTrack: function(tabBrowser) { + tabBrowser.addEventListener("DOMContentLoaded", cb, false); + }, + onUntrack: function(tabBrowser) { + tabBrowser.removeEventListener("DOMContentLoaded", cb, false); + } + }); + + return tracker; +}; + +exports.__defineGetter__("activeTab", function() { + const wm = Cc["@mozilla.org/appshell/window-mediator;1"]. + getService(Ci.nsIWindowMediator); + let mainWindow = wm.getMostRecentWindow("navigator:browser"); + return mainWindow.gBrowser.selectedTab; +}); + +/******************* TabModule *********************/ + +// Supported tab events +const events = [ + "onActivate", + "onDeactivate", + "onOpen", + "onClose", + "onReady", + "onLoad", + "onPaint" +]; +exports.tabEvents = events; + +/** + * TabModule + * + * Constructor for a module that implements the tabs API + */ +let TabModule = exports.TabModule = function TabModule(window) { + let self = this; + /** + * Tab + * + * Safe object representing a tab. + */ + let tabConstructor = apiUtils.publicConstructor(function(element) { + if (!element) + throw new Error("no tab element."); + let win = element.ownerDocument.defaultView; + if (!win) + throw new Error("element has no window."); + if (window && win != window) + throw new Error("module's window and element's window don't match."); + let browser = win.gBrowser.getBrowserForTab(element); + + this.__defineGetter__("title", function() browser.contentDocument.title); + this.__defineGetter__("location", function() browser.contentDocument.location); + this.__defineSetter__("location", function(val) browser.contentDocument.location = val); + this.__defineGetter__("contentWindow", function() browser.contentWindow); + this.__defineGetter__("contentDocument", function() browser.contentDocument); + this.__defineGetter__("favicon", function() { + let pageURI = NetUtil.newURI(browser.contentDocument.location); + let fs = Cc["@mozilla.org/browser/favicon-service;1"]. + getService(Ci.nsIFaviconService); + let faviconURL; + try { + let faviconURI = fs.getFaviconForPage(pageURI); + faviconURL = fs.getFaviconDataAsDataURL(faviconURI); + } catch(ex) { + let data = getChromeURLContents("chrome://mozapps/skin/places/defaultFavicon.png"); + let encoded = browser.contentWindow.btoa(data); + faviconURL = "data:image/png;base64," + encoded; + } + return faviconURL; + }); + this.__defineGetter__("style", function() null); // TODO + this.__defineGetter__("index", function() win.gBrowser.getBrowserIndexForDocument(browser.contentDocument)); + this.__defineGetter__("thumbnail", function() getThumbnailCanvasForTab(element, browser.contentWindow)); + + this.close = function() win.gBrowser.removeTab(element); + this.move = function(index) { + win.gBrowser.moveTabTo(element, index); + }; + + this.__defineGetter__("isPinned", function() element.pinned); + this.pin = function() win.gBrowser.pinTab(element); + this.unpin = function() win.gBrowser.unpinTab(element); + + // Set up the event handlers + let tab = this; + events.filter(function(e) e != "onOpen").forEach(function(e) { + // create a collection for each event + collection.addCollectionProperty(tab, e); + // make tabs setter for each event, for adding via property assignment + tab.__defineSetter__(e, function(val) tab[e].add(val)); + }); + + // listen for events, filtered on this tab + eventsTabDelegate.addTabDelegate(this); + }); + + /** + * tabs.activeTab + */ + this.__defineGetter__("activeTab", function() { + try { + return window ? tabConstructor(window.gBrowser.selectedTab) + : tabConstructor(exports.activeTab); + } + catch (e) { } + return null; + }); + this.__defineSetter__("activeTab", function(tab) { + let [tabElement, win] = getElementAndWindowForTab(tab, window); + if (tabElement) { + // set as active tab + win.gBrowser.selectedTab = tabElement; + // focus the window + win.focus(); + } + }); + + this.open = function TM_open(options) { + open(options, tabConstructor, window); + } + + // Set up the event handlers + events.forEach(function(eventHandler) { + // create a collection for each event + collection.addCollectionProperty(self, eventHandler); + // make tabs setter for each event, for adding via property assignment + self.__defineSetter__(eventHandler, function(val) self[eventHandler].add(val)); + }); + + // Tracker that listens for tab events, and proxies + // them to registered event listeners. + let eventsTabDelegate = { + selectedTab: null, + tabs: [], + addTabDelegate: function TETT_addTabDelegate(tabObj) { + this.tabs.push(tabObj); + }, + pushTabEvent: function TETT_pushTabEvent(event, tab) { + for (let callback in self[event]) { + require("errors").catchAndLog(function(tab) { + callback(new tabConstructor(tab)); + })(tab); + } + + if (event != "onOpen") { + this.tabs.forEach(function(tabObj) { + if (tabObj[event].length) { + let [tabEl,] = getElementAndWindowForTab(tabObj, window); + if (tabEl == tab) { + for (let callback in tabObj[event]) + require("errors").catchAndLog(function() callback())(); + } + } + // if being closed, remove the tab object from the cache + // of tabs to notify about events. + if (event == "onClose") + this.tabs.splice(this.tabs.indexOf(tabObj), 1); + }, this); + } + }, + unload: function() { + this.selectedTab = null; + this.tabs.splice(0); + } + }; + require("unload").ensure(eventsTabDelegate); + + let eventsTabTracker = new ModuleTabTracker({ + onTrack: function TETT_onTrack(tab) { + eventsTabDelegate.pushTabEvent("onOpen", tab); + }, + onUntrack: function TETT_onUntrack(tab) { + eventsTabDelegate.pushTabEvent("onClose", tab); + }, + onSelect: function TETT_onSelect(tab) { + if (eventsTabDelegate.selectedTab) + eventsTabDelegate.pushTabEvent("onDeactivate", tab); + + eventsTabDelegate.selectedTab = new tabConstructor(tab); + + eventsTabDelegate.pushTabEvent("onActivate", tab); + }, + onReady: function TETT_onReady(tab) { + eventsTabDelegate.pushTabEvent("onReady", tab); + }, + onLoad: function TETT_onLoad(tab) { + eventsTabDelegate.pushTabEvent("onLoad", tab); + }, + onPaint: function TETT_onPaint(tab) { + eventsTabDelegate.pushTabEvent("onPaint", tab); + } + }, window); + require("unload").ensure(eventsTabTracker); + + // Iterator for all tabs + this.__iterator__ = function tabsIterator() { + for (let i = 0; i < eventsTabTracker._tabs.length; i++) + yield tabConstructor(eventsTabTracker._tabs[i]); + } + + this.__defineGetter__("length", function() eventsTabTracker._tabs.length); + + // Cleanup when unloaded + this.unload = function TM_unload() { + // Unregister tabs event listeners + events.forEach(function(e) self[e] = []); + } + require("unload").ensure(this); + +} // End of TabModule constructor + +/** + * tabs.open - open a URL in a new tab + */ +function open(options, tabConstructor, window) { + if (typeof options === "string") + options = { url: options }; + + options = apiUtils.validateOptions(options, { + url: { + is: ["string"] + }, + inNewWindow: { + is: ["undefined", "boolean"] + }, + inBackground: { + is: ["undefined", "boolean"] + }, + isPinned: { + is: ["undefined", "boolean"] + }, + onOpen: { + is: ["undefined", "function"] + } + }); + + if (window) + options.inNewWindow = false; + + let win = window || require("window-utils").activeBrowserWindow; + + if (!win || options.inNewWindow) + openURLInNewWindow(options, tabConstructor); + else + openURLInNewTab(options, win, tabConstructor); +} + +function openURLInNewWindow(options, tabConstructor) { + let addTabOptions = { + inNewWindow: true + }; + if (options.onOpen) { + addTabOptions.onLoad = function(e) { + let win = e.target.defaultView; + let tabEl = win.gBrowser.tabContainer.childNodes[0]; + let tabBrowser = win.gBrowser.getBrowserForTab(tabEl); + tabBrowser.addEventListener("load", function(e) { + tabBrowser.removeEventListener("load", arguments.callee, true); + let tab = tabConstructor(tabEl); + require("errors").catchAndLog(function(e) options.onOpen(e))(tab); + }, true); + }; + } + if (options.isPinned) { + addTabOptions.isPinned = true; + } + exports.addTab(options.url.toString(), addTabOptions); +} + +function openURLInNewTab(options, window, tabConstructor) { + window.focus(); + let tabEl = window.gBrowser.addTab(options.url.toString()); + if (!options.inBackground) + window.gBrowser.selectedTab = tabEl; + if (options.isPinned) + window.gBrowser.pinTab(tabEl); + if (options.onOpen) { + let tabBrowser = window.gBrowser.getBrowserForTab(tabEl); + tabBrowser.addEventListener("load", function(e) { + // remove event handler from addTab - don't want to be notified + // for subsequent loads in same tab. + tabBrowser.removeEventListener("load", arguments.callee, true); + let tab = tabConstructor(tabEl); + require("timer").setTimeout(function() { + require("errors").catchAndLog(function(tab) options.onOpen(tab))(tab); + }, 10); + }, true); + } +} + +function getElementAndWindowForTab(tabObj, window) { + // iterate over open windows, or use single window if provided + let windowIterator = window ? function() { yield window; } + : require("window-utils").windowIterator; + for (let win in windowIterator()) { + if (win.gBrowser) { + // find the tab element at tab.index + let index = win.gBrowser.getBrowserIndexForDocument(tabObj.contentDocument); + if (index > -1) + return [win.gBrowser.tabContainer.getItemAtIndex(index), win]; + } + } + return [null, null]; +} + +// Tracker for all tabs across all windows +// This is tab-browser.TabTracker, but with +// support for additional events added. +function ModuleTabTracker(delegate, window) { + this._delegate = delegate; + this._tabs = []; + this._tracker = new Tracker(this, window); + require("unload").ensure(this); +} +ModuleTabTracker.prototype = { + _TAB_EVENTS: ["TabOpen", "TabClose", "TabSelect", "DOMContentLoaded", + "load", "MozAfterPaint"], + _safeTrackTab: function safeTrackTab(tab) { + tab.addEventListener("load", this, false); + tab.linkedBrowser.addEventListener("MozAfterPaint", this, false); + this._tabs.push(tab); + try { + this._delegate.onTrack(tab); + } catch (e) { + console.exception(e); + } + }, + _safeUntrackTab: function safeUntrackTab(tab) { + tab.removeEventListener("load", this, false); + tab.linkedBrowser.removeEventListener("MozAfterPaint", this, false); + var index = this._tabs.indexOf(tab); + if (index == -1) + throw new Error("internal error: tab not found"); + this._tabs.splice(index, 1); + try { + this._delegate.onUntrack(tab); + } catch (e) { + console.exception(e); + } + }, + _safeSelectTab: function safeSelectTab(tab) { + var index = this._tabs.indexOf(tab); + if (index == -1) + console.error("internal error: tab not found"); + try { + if (this._delegate.onSelect) + this._delegate.onSelect(tab); + } catch (e) { + console.exception(e); + } + }, + _safeDOMContentLoaded: function safeDOMContentLoaded(event) { + let tabBrowser = event.currentTarget; + let tabBrowserIndex = tabBrowser.getBrowserIndexForDocument(event.target); + // TODO: I'm seeing this when loading data url images + if (tabBrowserIndex == -1) + return; + let tab = tabBrowser.tabContainer.getItemAtIndex(tabBrowserIndex); + let index = this._tabs.indexOf(tab); + if (index == -1) + console.error("internal error: tab not found"); + try { + if (this._delegate.onReady) + this._delegate.onReady(tab); + } catch (e) { + console.exception(e); + } + }, + _safeLoad: function safeLoad(event) { + let tab = event.target; + let index = this._tabs.indexOf(tab); + if (index == -1) + console.error("internal error: tab not found"); + try { + if (this._delegate.onLoad) + this._delegate.onLoad(tab); + } catch (e) { + console.exception(e); + } + }, + _safeMozAfterPaint: function safeMozAfterPaint(event) { + let win = event.currentTarget.ownerDocument.defaultView; + let tabIndex = win.gBrowser.getBrowserIndexForDocument(event.target.document); + if (tabIndex == -1) + return; + let tab = win.gBrowser.tabContainer.getItemAtIndex(tabIndex); + let index = this._tabs.indexOf(tab); + if (index == -1) + console.error("internal error: tab not found"); + try { + if (this._delegate.onPaint) + this._delegate.onPaint(tab); + } catch (e) { + console.exception(e); + } + }, + handleEvent: function handleEvent(event) { + switch (event.type) { + case "TabOpen": + this._safeTrackTab(event.target); + break; + case "TabClose": + this._safeUntrackTab(event.target); + break; + case "TabSelect": + this._safeSelectTab(event.target); + break; + case "DOMContentLoaded": + this._safeDOMContentLoaded(event); + break; + case "load": + this._safeLoad(event); + break; + case "MozAfterPaint": + this._safeMozAfterPaint(event); + break; + default: + throw new Error("internal error: unknown event type: " + + event.type); + } + }, + onTrack: function onTrack(tabbrowser) { + for (tab in tabIterator(tabbrowser)) + this._safeTrackTab(tab); + tabbrowser.tabContainer.addEventListener("TabOpen", this, false); + tabbrowser.tabContainer.addEventListener("TabClose", this, false); + tabbrowser.tabContainer.addEventListener("TabSelect", this, false); + tabbrowser.ownerDocument.defaultView.gBrowser.addEventListener("DOMContentLoaded", this, false); + }, + onUntrack: function onUntrack(tabbrowser) { + for (tab in tabIterator(tabbrowser)) + this._safeUntrackTab(tab); + tabbrowser.tabContainer.removeEventListener("TabOpen", this, false); + tabbrowser.tabContainer.removeEventListener("TabClose", this, false); + tabbrowser.tabContainer.removeEventListener("TabSelect", this, false); + tabbrowser.ownerDocument.defaultView.gBrowser.removeEventListener("DOMContentLoaded", this, false); + }, + unload: function unload() { + this._tracker.unload(); + } +}; + +// Utility to get a thumbnail canvas from a tab object +function getThumbnailCanvasForTab(tabEl, window) { + var thumbnail = window.document.createElementNS("http://www.w3.org/1999/xhtml", "canvas"); + thumbnail.mozOpaque = true; + var window = tabEl.linkedBrowser.contentWindow; + thumbnail.width = Math.ceil(window.screen.availWidth / 5.75); + var aspectRatio = 0.5625; // 16:9 + thumbnail.height = Math.round(thumbnail.width * aspectRatio); + var ctx = thumbnail.getContext("2d"); + var snippetWidth = window.innerWidth * .6; + var scale = thumbnail.width / snippetWidth; + ctx.scale(scale, scale); + ctx.drawWindow(window, window.scrollX, window.scrollY, snippetWidth, snippetWidth * aspectRatio, "rgb(255,255,255)"); + return thumbnail; +} + +// Utility to return the contents of the target of a chrome URL +function getChromeURLContents(chromeURL) { + let io = Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService); + let channel = io.newChannel(chromeURL, null, null); + let input = channel.open(); + let stream = Cc["@mozilla.org/binaryinputstream;1"]. + createInstance(Ci.nsIBinaryInputStream); + stream.setInputStream(input); + let str = stream.readBytes(input.available()); + stream.close(); + input.close(); + return str; +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/events.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/events.js new file mode 100644 index 00000000..96309bb4 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/events.js @@ -0,0 +1,56 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +const ON_PREFIX = "on"; +const TAB_PREFIX = "Tab"; + +const EVENTS = { + ready: "DOMContentLoaded", + open: "TabOpen", + close: "TabClose", + activate: "TabSelect", + deactivate: null +} +exports.EVENTS = EVENTS; + +Object.keys(EVENTS).forEach(function(name) { + EVENTS[name] = { + name: name, + listener: ON_PREFIX + name.charAt(0).toUpperCase() + name.substr(1), + dom: EVENTS[name] + } +}); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/tab.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/tab.js new file mode 100644 index 00000000..3c3ce5b5 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/tabs/tab.js @@ -0,0 +1,296 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +const { Ci } = require('chrome'); +const { Trait } = require("traits"); +const { EventEmitter } = require("events"); +const { validateOptions } = require("api-utils"); +const { Enqueued } = require("utils/function"); +const { EVENTS } = require("tabs/events"); +const { getThumbnailURIForWindow } = require("utils/thumbnail"); +const { getFaviconURIForLocation } = require("utils/data"); + + + +// Array of the inner instances of all the wrapped tabs. +const TABS = []; + +/** + * Trait used to create tab wrappers. + */ +const TabTrait = Trait.compose(EventEmitter, { + on: Trait.required, + _emit: Trait.required, + /** + * Tab DOM element that is being wrapped. + */ + _tab: null, + /** + * Window wrapper whose tab this object represents. + */ + window: null, + constructor: function Tab(options) { + this._onReady = this._onReady.bind(this); + this.on('error', this._onError = this._onError.bind(this)); + this._tab = options.tab; + let window = this.window = options.window; + // Setting event listener if was passed. + for each (let type in EVENTS) { + let listener = options[type.listener]; + if (listener) + this.on(type.name, options[type.listener]); + if ('ready' != type.name) // window spreads this event. + window.tabs.on(type.name, this._onEvent.bind(this, type.name)); + } + + this.on(EVENTS.close.name, this.destroy.bind(this)); + this._browser.addEventListener(EVENTS.ready.dom, this._onReady, true); + + if (options.isPinned) + this.pin(); + + // Since we will have to identify tabs by a DOM elements facade function + // is used as constructor that collects all the instances and makes sure + // that they more then one wrapper is not created per tab. + return this; + }, + _onError: function _onError(error) { + if (1 <= this._listeners('error').length) + console.exception(error); + }, + destroy: function destroy() { + for each (let type in EVENTS) + this._removeAllListeners(type.name); + this._browser.removeEventListener(EVENTS.ready.dom, this._onReady, + true); + }, + + /** + * Internal listener that emits public event 'ready' when the page of this + * tab is loaded. + */ + _onReady: function _onReady(event) { + // IFrames events will bubble so we need to ignore those. + if (event.target == this._contentDocument) + this._emit(EVENTS.ready.name, this._public); + }, + /** + * Internal tab event router. Window will emit tab related events for all it's + * tabs, this listener will propagate all the events for this tab to it's + * listeners. + */ + _onEvent: function _onEvent(type, tab) { + if (tab == this._public) + this._emit(type, tab); + }, + /** + * Browser DOM element where page of this tab is currently loaded. + */ + get _browser() this._window.gBrowser.getBrowserForTab(this._tab), + /** + * Window DOM element containing this tab. + */ + get _window() this._tab.ownerDocument.defaultView, + /** + * Document object of the page that is currently loaded in this tab. + */ + get _contentDocument() this._browser.contentDocument, + /** + * Window object of the page that is currently loaded in this tab. + */ + get _contentWindow() this._browser.contentWindow, + + /** + * The title of the page currently loaded in the tab. + * Changing this property changes an actual title. + * @type {String} + */ + get title() this._contentDocument.title, + set title(value) this._contentDocument.title = String(value), + /** + * Location of the page currently loaded in this tab. + * Changing this property will loads page under under the specified location. + * @type {String} + */ + get url() String(this._contentDocument.location), + set url(value) this._changeLocation(String(value)), + // "TabOpen" event is fired when it's still "about:blank" is loaded in the + // changing `location` property of the `contentDocument` has no effect since + // seems to be either ignored or overridden by internal listener, there for + // location change is enqueued for the next turn of event loop. + _changeLocation: Enqueued(function(url) this._contentDocument.location = url), + /** + * URI of the favicon for the page currently loaded in this tab. + * @type {String} + */ + get favicon() getFaviconURIForLocation(this.url), + /** + * The CSS style for the tab + */ + get style() null, // TODO + /** + * The index of the tab relative to other tabs in the application window. + * Changing this property will change order of the actual position of the tab. + * @type {Number} + */ + get index() + this._window.gBrowser.getBrowserIndexForDocument(this._contentDocument), + set index(value) this._window.gBrowser.moveTabTo(this._tab, value), + /** + * Thumbnail data URI of the page currently loaded in this tab. + * @type {String} + */ + getThumbnail: function getThumbnail() + getThumbnailURIForWindow(this._contentWindow), + /** + * Whether or not tab is pinned (Is an app-tab). + * @type {Boolean} + */ + get isPinned() this._tab.pinned, + pin: function pin() { + this._window.gBrowser.pinTab(this._tab); + }, + unpin: function unpin() { + this._window.gBrowser.unpinTab(this._tab); + }, + + /** + * Create a worker for this tab, first argument is options given to Worker. + * @type {Worker} + */ + attach: function attach(options) { + let { Worker } = require("content/worker"); + options.window = this._contentWindow.wrappedJSObject; + return Worker(options); + }, + + /** + * Make this tab active. + * Please note: That this function is called synchronous since in E10S that + * will be the case. Besides this function is called from a constructor where + * we would like to return instance before firing a 'TabActivated' event. + */ + activate: Enqueued(function activate() { + if (this._window) // Ignore if window is closed by the time this is invoked. + this._window.gBrowser.selectedTab = this._tab; + }), + /** + * Close the tab + */ + close: function close(callback) { + if (callback) + this.on(EVENTS.close.name, callback); + this._window.gBrowser.removeTab(this._tab); + } +}); + +function Tab(options) { + let chromeTab = options.tab; + for each (let tab in TABS) { + if (chromeTab == tab._tab) + return tab._public; + } + let tab = TabTrait(options); + TABS.push(tab); + return tab._public; +} +Tab.prototype = TabTrait.prototype; +exports.Tab = Tab; + +function Options(options) { + if ("string" === typeof options) + options = { url: options }; + + return validateOptions(options, { + url: { is: ["string"] }, + inBackground: { is: ["undefined", "boolean"] }, + isPinned: { is: ["undefined", "boolean"] }, + onOpen: { is: ["undefined", "function"] }, + onClose: { is: ["undefined", "function"] }, + onReady: { is: ["undefined", "function"] }, + onActivate: { is: ["undefined", "function"] }, + onDeactivate: { is: ["undefined", "function"] } + }); +} +exports.Options = Options; + + +exports.getTabForWindow = function (win) { + // Get browser window + let topWindow = win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShellTreeItem) + .rootTreeItem + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow); + if (!topWindow.gBrowser) return null; + + // Get top window object, in case we are in a content iframe + let topContentWindow; + try { + topContentWindow= win.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIWebNavigation) + .QueryInterface(Ci.nsIDocShellTreeItem) + .treeOwner + .QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindow); + } catch(e) { + // It may throw if win is not a valid content window + return null; + } + + function getWindowID(obj) { + return obj.QueryInterface(Ci.nsIInterfaceRequestor) + .getInterface(Ci.nsIDOMWindowUtils) + .currentInnerWindowID; + } + + // Search for related Tab + let topWindowId = getWindowID(topContentWindow); + for (let i = 0; i < topWindow.gBrowser.browsers.length; i++) { + let w = topWindow.gBrowser.browsers[i].contentWindow; + if (getWindowID(w) == topWindowId) { + return Tab({ + window: require("windows").BrowserWindow({window:topContentWindow}), + tab: topWindow.gBrowser.tabs[i] + }); + } + } + + // We were unable to find the related tab! + return null; +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test.js new file mode 100644 index 00000000..6e9d00c7 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test.js @@ -0,0 +1,126 @@ +/* vim:ts=2:sts=2:sw=2: + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +const BaseAssert = require("./test/assert").Assert; +const { isFunction, isObject } = require("type"); + +/** + * Function takes test `suite` object in CommonJS format and defines all of the + * tests from that suite and nested suites in a jetpack format on a given + * `target` object. Optionally third argument `prefix` can be passed to prefix + * all the test names. + */ +function defineTestSuite(target, suite, prefix) { + prefix = prefix || ""; + // If suite defines `Assert` that's what `assert` object have to be created + // from and passed to a test function (This allows custom assertion functions) + // See for details: http://wiki.commonjs.org/wiki/Unit_Testing/1.1 + let Assert = suite.Assert || BaseAssert; + // Going through each item in the test suite and wrapping it into a + // Jetpack test format. + Object.keys(suite).forEach(function(key) { + // If name starts with test then it's a test function or suite. + if (key.indexOf("test") === 0) { + let test = suite[key]; + + // For each test function so we create a wrapper test function in a + // jetpack format and copy that to a `target` exports. + if (isFunction(test)) { + + // Since names of the test may match across suites we use full object + // path as a name to avoid overriding same function. + target[prefix + key] = function(options) { + + // Creating `assert` functions for this test. + let assert = Assert(options); + + // If CommonJS test function expects more than one argument + // it means that test is async and second argument is a callback + // to notify that test is finished. + if (1 < test.length) { + + // Letting test runner know that test is executed async and + // creating a callback function that CommonJS tests will call + // once it's done. + options.waitUntilDone(); + test(assert, function() { + options.done(); + }); + } + + // Otherwise CommonJS test is synchronous so we call it only with + // one argument. + else { + test(assert); + } + } + } + + // If it's an object then it's a test suite containing test function + // and / or nested test suites. In that case we just extend prefix used + // and call this function to copy and wrap tests from nested suite. + else if (isObject(test)) { + test.Assert = test.Assert || Assert; + defineTestSuite(target, test, prefix + key + "."); + } + } + }); +} + +/** + * This function is a CommonJS test runner function, but since Jetpack test + * runner and test format is different from CommonJS this function shims given + * `exports` with all its tests into a Jetpack test format so that the built-in + * test runner will be able to run CommonJS test without manual changes. + */ +exports.run = function run(exports) { + + // We can't leave old properties on exports since those are test in a CommonJS + // format that why we move everything to a new `suite` object. + let suite = {}; + Object.keys(exports).forEach(function(key) { + suite[key] = exports[key]; + delete exports[key]; + }); + + // Now we wrap all the CommonJS tests to a Jetpack format and define + // those to a given `exports` object since that where jetpack test runner + // will look for them. + defineTestSuite(exports, suite); +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test/assert.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test/assert.js new file mode 100644 index 00000000..9c373827 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/test/assert.js @@ -0,0 +1,360 @@ +/* vim:ts=2:sts=2:sw=2: + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +const { isFunction, isNull, isObject, isString, isRegExp, isArray, + isUndefined, instanceOf, source } = require("type"); + +/** + * The `AssertionError` is defined in assert. + * @extends Error + * @example + * new assert.AssertionError({ + * message: message, + * actual: actual, + * expected: expected + * }) + */ +function AssertionError(options) { + let assertionError = Object.create(AssertionError.prototype); + + if (isString(options)) + options = { message: options }; + if ("actual" in options) + assertionError.actual = options.actual; + if ("expected" in options) + assertionError.expected = options.expected; + if ("operator" in options) + assertionError.operator = options.operator; + + assertionError.message = options.message; + assertionError.stack = new Error().stack; + return assertionError; +} +AssertionError.prototype = Object.create(Error.prototype, { + constructor: { value: AssertionError }, + name: { value: "AssertionError", enumerable: true }, + toString: { value: function toString() { + let value; + if (this.message) { + value = this.name + " : " + this.message; + } + else { + value = [ + this.name + " : ", + source(this.expected), + this.operator, + source(this.actual) + ].join(" "); + } + return value; + }} +}); +exports.AssertionError = AssertionError; + +function Assert(logger) { + return Object.create(Assert.prototype, { _log: { value: logger }}); +} +Assert.prototype = { + fail: function fail(e) { + this._log.fail(e.message); + }, + pass: function pass(message) { + this._log.pass(message); + }, + error: function error(e) { + this._log.exception(e); + }, + ok: function ok(value, message) { + if (!!!value) { + this.fail({ + actual: value, + expected: true, + message: message, + operator: "==" + }); + } + else { + this.pass(message); + } + }, + + /** + * The equality assertion tests shallow, coercive equality with `==`. + * @example + * assert.equal(1, 1, "one is one"); + */ + equal: function equal(actual, expected, message) { + if (actual == expected) { + this.pass(message); + } + else { + this.fail({ + actual: actual, + expected: expected, + message: message, + operator: "==" + }); + } + }, + + /** + * The non-equality assertion tests for whether two objects are not equal + * with `!=`. + * @example + * assert.notEqual(1, 2, "one is not two"); + */ + notEqual: function notEqual(actual, expected, message) { + if (actual != expected) { + this.pass(message); + } + else { + this.fail({ + actual: actual, + expected: expected, + message: message, + operator: "!=", + }); + } + }, + + /** + * The equivalence assertion tests a deep (with `===`) equality relation. + * @example + * assert.deepEqual({ a: "foo" }, { a: "foo" }, "equivalent objects") + */ + deepEqual: function deepEqual(actual, expected, message) { + if (isDeepEqual(actual, expected)) { + this.pass(message); + } + else { + this.fail({ + actual: actual, + expected: expected, + message: message, + operator: "deepEqual" + }); + } + }, + + /** + * The non-equivalence assertion tests for any deep (with `===`) inequality. + * @example + * assert.notDeepEqual({ a: "foo" }, Object.create({ a: "foo" }), + * "object's inherit from different prototypes"); + */ + notDeepEqual: function notDeepEqual(actual, expected, message) { + if (!isDeepEqual(actual, expected)) { + this.pass(message); + } + else { + this.fail({ + actual: actual, + expected: expected, + message: message, + operator: "notDeepEqual" + }); + } + }, + + /** + * The strict equality assertion tests strict equality, as determined by + * `===`. + * @example + * assert.strictEqual(null, null, "`null` is `null`") + */ + strictEqual: function strictEqual(actual, expected, message) { + if (actual === expected) { + this.pass(message); + } + else { + this.fail({ + actual: actual, + expected: expected, + message: message, + operator: "===" + }); + } + }, + + /** + * The strict non-equality assertion tests for strict inequality, as + * determined by `!==`. + * @example + * assert.notStrictEqual(null, undefined, "`null` is not `undefined`"); + */ + notStrictEqual: function notStrictEqual(actual, expected, message) { + if (actual !== expected) { + this.pass(message); + } + else { + this.fail({ + actual: actual, + expected: expected, + message: message, + operator: "!==" + }) + } + }, + + /** + * The assertion whether or not given `block` throws an exception. If optional + * `Error` argument is provided and it's type of function thrown error is + * asserted to be an instance of it, if type of `Error` is string then message + * of throw exception is asserted to contain it. + * @param {Function} block + * Function that is expected to throw. + * @param {Error|RegExp} [Error] + * Error constructor that is expected to be thrown or a string that + * must be contained by a message of the thrown exception, or a RegExp + * matching a message of the thrown exception. + * @param {String} message + * Description message + * + * @examples + * + * assert.throws(function block() { + * doSomething(4) + * }, "Object is expected", "Incorrect argument is passed"); + * + * assert.throws(function block() { + * Object.create(5) + * }, TypeError, "TypeError is thrown"); + */ + throws: function throws(block, Error, message) { + let threw = false; + let exception = null; + + // If third argument is not provided and second argument is a string it + // means that optional `Error` argument was not passed, so we shift + // arguments. + if (isString(Error) && isUndefined(message)) { + message = Error; + Error = undefined; + } + + // Executing given `block`. + try { + block(); + } + catch (e) { + threw = true; + exception = e; + } + + // If exception was thrown and `Error` argument was not passed assert is + // passed. + if (threw && (isUndefined(Error) || + // If passed `Error` is RegExp using it's test method to + // assert thrown exception message. + (isRegExp(Error) && Error.test(exception.message)) || + // If passed `Error` is a constructor function testing if + // thrown exception is an instance of it. + (isFunction(Error) && instanceOf(exception, Error)))) + { + this.pass(message); + } + + // Otherwise we report assertion failure. + else { + let failure = { + message: message, + operator: "throws" + }; + + if (exception) + failure = e.actual = exception; + + if (Error) + failure = e.expected = Error; + + this.fail(failure); + } + } +}; +exports.Assert = Assert; + +function isDeepEqual(actual, expected) { + + // 7.1. All identical values are equivalent, as determined by ===. + if (actual === expected) { + 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 (isDate(actual) && isDate(expected)) { + return actual.getTime() === expected.getTime(); + } + + // XXX specification bug: this should be specified + else if (isAtom(actual) || isAtom(actual)) { + return expected === actual; + } + + // 7.3. Other pairs that do not both pass typeof value == "object", + // equivalence is determined by ==. + else if (!isObject(actual) && !isObject(expected)) { + return actual == expected; + } + + // 7.4. 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 actual.prototype === expected.prototype && + isEquivalent(actual, expected); + } +} + +function isEquivalent(a, b, stack) { + return isEquivalentArray(Object.keys(a).sort(), + Object.keys(b).sort()) && + Object.keys(a).every(function(key) { + return isDeepEqual(a[key], b[key], stack) + }); +} + +function isArrayEquivalent(a, b, stack) { + return isArray(a) && isArray(b) && + a.every(function(value, index) { + return isDeepEqual(value, b[index]); + }); +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/text-streams.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/text-streams.js new file mode 100644 index 00000000..444600b3 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/text-streams.js @@ -0,0 +1,271 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- + * vim:set ts=2 sw=2 sts=2 et filetype=javascript + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Drew Willcoxon (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci,Cu,components} = require("chrome"); +var NetUtil = {}; +Cu.import("resource://gre/modules/NetUtil.jsm", NetUtil); +NetUtil = NetUtil.NetUtil; + +// NetUtil.asyncCopy() uses this buffer length, and since we call it, for best +// performance we use it, too. +const BUFFER_BYTE_LEN = 0x8000; +const PR_UINT32_MAX = 0xffffffff; +const DEFAULT_CHARSET = "UTF-8"; + +exports.TextReader = TextReader; +exports.TextWriter = TextWriter; + +/** + * An input stream that reads text from a backing stream using a given text + * encoding. + * + * @param inputStream + * The stream is backed by this nsIInputStream. It must already be + * opened. + * @param charset + * Text in inputStream is expected to be in this character encoding. If + * not given, "UTF-8" is assumed. See nsICharsetConverterManager.idl for + * documentation on how to determine other valid values for this. + */ +function TextReader(inputStream, charset) { + const self = this; + charset = checkCharset(charset); + + let stream = Cc["@mozilla.org/intl/converter-input-stream;1"]. + createInstance(Ci.nsIConverterInputStream); + stream.init(inputStream, charset, BUFFER_BYTE_LEN, + Ci.nsIConverterInputStream.DEFAULT_REPLACEMENT_CHARACTER); + + let manager = new StreamManager(this, stream); + + /** + * Reads a string from the stream. If the stream is closed, an exception is + * thrown. + * + * @param numChars + * The number of characters to read. If not given, the remainder of + * the stream is read. + * @return The string read. If the stream is already at EOS, returns the + * empty string. + */ + this.read = function TextReader_read(numChars) { + manager.ensureOpened(); + + let readAll = false; + if (typeof(numChars) === "number") + numChars = Math.max(numChars, 0); + else + readAll = true; + + let str = ""; + let totalRead = 0; + let chunkRead = 1; + + // Read in numChars or until EOS, whichever comes first. Note that the + // units here are characters, not bytes. + while (true) { + let chunk = {}; + let toRead = readAll ? + PR_UINT32_MAX : + Math.min(numChars - totalRead, PR_UINT32_MAX); + if (toRead <= 0 || chunkRead <= 0) + break; + + // The converter stream reads in at most BUFFER_BYTE_LEN bytes in a call + // to readString, enough to fill its byte buffer. chunkRead will be the + // number of characters encoded by the bytes in that buffer. + chunkRead = stream.readString(toRead, chunk); + str += chunk.value; + totalRead += chunkRead; + } + + return str; + }; +} + +/** + * A buffered output stream that writes text to a backing stream using a given + * text encoding. + * + * @param outputStream + * The stream is backed by this nsIOutputStream. It must already be + * opened. + * @param charset + * Text will be written to outputStream using this character encoding. + * If not given, "UTF-8" is assumed. See nsICharsetConverterManager.idl + * for documentation on how to determine other valid values for this. + */ +function TextWriter(outputStream, charset) { + const self = this; + charset = checkCharset(charset); + + let stream = outputStream; + + // Buffer outputStream if it's not already. + let ioUtils = Cc["@mozilla.org/io-util;1"].getService(Ci.nsIIOUtil); + if (!ioUtils.outputStreamIsBuffered(outputStream)) { + stream = Cc["@mozilla.org/network/buffered-output-stream;1"]. + createInstance(Ci.nsIBufferedOutputStream); + stream.init(outputStream, BUFFER_BYTE_LEN); + } + + // I'd like to use nsIConverterOutputStream. But NetUtil.asyncCopy(), which + // we use below in writeAsync(), naturally expects its sink to be an instance + // of nsIOutputStream, which nsIConverterOutputStream's only implementation is + // not. So we use uconv and manually convert all strings before writing to + // outputStream. + let uconv = Cc["@mozilla.org/intl/scriptableunicodeconverter"]. + createInstance(Ci.nsIScriptableUnicodeConverter); + uconv.charset = charset; + + let manager = new StreamManager(this, stream); + + /** + * Flushes the backing stream's buffer. + */ + this.flush = function TextWriter_flush() { + manager.ensureOpened(); + stream.flush(); + }; + + /** + * Writes a string to the stream. If the stream is closed, an exception is + * thrown. + * + * @param str + * The string to write. + */ + this.write = function TextWriter_write(str) { + manager.ensureOpened(); + let istream = uconv.convertToInputStream(str); + let len = istream.available(); + while (len > 0) { + stream.writeFrom(istream, len); + len = istream.available(); + } + istream.close(); + }; + + /** + * Writes a string on a background thread. After the write completes, the + * backing stream's buffer is flushed, and both the stream and the backing + * stream are closed, also on the background thread. If the stream is already + * closed, an exception is thrown immediately. + * + * @param str + * The string to write. + * @param callback + * An optional function. If given, it's called as callback(error) when + * the write completes. error is an Error object or undefined if there + * was no error. Inside callback, |this| is the stream object. + */ + this.writeAsync = function TextWriter_writeAsync(str, callback) { + manager.ensureOpened(); + let istream = uconv.convertToInputStream(str); + NetUtil.asyncCopy(istream, stream, function (result) { + let err = components.isSuccessCode(result) ? undefined : + new Error("An error occured while writing to the stream: " + result); + if (err) + console.error(err); + + // asyncCopy() closes its output (and input) stream. + manager.opened = false; + + if (typeof(callback) === "function") { + try { + callback.call(self, err); + } + catch (exc) { + console.exception(exc); + } + } + }); + }; +} + +// This manages the lifetime of stream, a TextReader or TextWriter. It defines +// closed and close() on stream and registers an unload listener that closes +// rawStream if it's still opened. It also provides ensureOpened(), which +// throws an exception if the stream is closed. +function StreamManager(stream, rawStream) { + const self = this; + this.rawStream = rawStream; + this.opened = true; + + /** + * True iff the stream is closed. + */ + stream.__defineGetter__("closed", function stream_closed() { + return !self.opened; + }); + + /** + * Closes both the stream and its backing stream. If the stream is already + * closed, an exception is thrown. For TextWriters, this first flushes the + * backing stream's buffer. + */ + stream.close = function stream_close() { + self.ensureOpened(); + self.unload(); + }; + + require("unload").ensure(this); +} + +StreamManager.prototype = { + ensureOpened: function StreamManager_ensureOpened() { + if (!this.opened) + throw new Error("The stream is closed and cannot be used."); + }, + unload: function StreamManager_unload() { + // TextWriter.writeAsync() causes rawStream to close and therefore sets + // opened to false, so check that we're still opened. + if (this.opened) { + // Calling close() on both an nsIUnicharInputStream and + // nsIBufferedOutputStream closes their backing streams. It also forces + // nsIOutputStreams to flush first. + this.rawStream.close(); + this.opened = false; + } + } +}; + +function checkCharset(charset) { + return typeof(charset) === "string" ? charset : DEFAULT_CHARSET; +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer-e10s-adapter.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer-e10s-adapter.js new file mode 100644 index 00000000..7bf953cf --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer-e10s-adapter.js @@ -0,0 +1,73 @@ +// This implementation is neither secure nor complete, +// because timer functionality should be implemented +// natively in-process by bug 568695. + +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +if (this.chrome) { + var callbacks = {}; + exports.setTimeout = function setTimeout(cb, ms) { + var id = chrome.call("setTimeout", ms); + callbacks[id] = cb; + return id; + }; + + exports.clearTimeout = function clearTimeout(id) { + delete callbacks[id]; + chrome.send("clearTimeout", id); + }; + + chrome.on("onTimeout", function(name, id) { + var cb = callbacks[id]; + delete callbacks[id]; + if (cb) + cb(); // yay race conditions + }); +} else { + exports.register = function(addon) { + var timer = require("timer"); + addon.registerCall("setTimeout", function(name, ms) { + var id = timer.setTimeout(function() { + addon.send("onTimeout", id); + }, ms); + return id; + }); + addon.on("clearTimeout", function(name, id) { + timer.clearTimeout(id); + }); + }; +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js new file mode 100644 index 00000000..86e10a18 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/timer.js @@ -0,0 +1,139 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * Drew Willcoxon + * Irakli Gozalishvili + * Erik Vold + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci} = require("chrome"); +var xpcom = require("xpcom"); + +var timerClass = Cc["@mozilla.org/timer;1"]; +var nextID = 1; +var timers = {}; + +function TimerCallback(timerID, callback, params) { + this._callback = callback; + this._params = params; +}; +TimerCallback.prototype = { + QueryInterface : xpcom.utils.generateQI([Ci.nsITimerCallback]) +}; + +function TimeoutCallback(timerID, callback, params) { + memory.track(this); + TimerCallback.apply(this, arguments) + this._timerID = timerID; +}; +TimeoutCallback.prototype = new TimerCallback(); +TimeoutCallback.prototype.notify = function notifyOnTimeout(timer) { + try { + delete timers[this._timerID]; + this._callback.apply(null, this._params); + } catch (e) { + console.exception(e); + } +}; + +function IntervalCallback(timerID, callback, params) { + memory.track(this); + TimerCallback.apply(this, arguments) +}; +IntervalCallback.prototype = new TimerCallback(); +IntervalCallback.prototype.notify = function notifyOnInterval() { + try { + this._callback.apply(null, this._params); + } catch (e) { + console.exception(e); + } +}; + + +var setTimeout = exports.setTimeout = function setTimeout(callback, delay) { + return makeTimer( + Ci.nsITimer.TYPE_ONE_SHOT, + callback, + TimeoutCallback, + delay, + Array.slice(arguments, 2)); +}; + +var clearTimeout = exports.clearTimeout = function clearTimeout(timerID) { + cancelTimer(timerID); +}; + +var setInterval = exports.setInterval = function setInterval(callback, delay) { + return makeTimer( + Ci.nsITimer.TYPE_REPEATING_SLACK, + callback, + IntervalCallback, + delay, + Array.slice(arguments, 2)); +}; + +var clearInterval = exports.clearInterval = function clearInterval(timerID) { + cancelTimer(timerID); +}; + +function makeTimer(type, callback, callbackType, delay, params) { + var timer = timerClass.createInstance(Ci.nsITimer); + + memory.track(timer, "nsITimer"); + + var timerID = nextID++; + timers[timerID] = timer; + + timer.initWithCallback( + new callbackType(timerID, callback, params), + delay || 0, + type + ); + return timerID; +} + +function cancelTimer(timerID) { + var timer = timers[timerID]; + if (timer) { + timer.cancel(); + delete timers[timerID]; + } +} + +require("unload").when( + function cancelAllPendingTimers() { + var timerIDs = [timerID for (timerID in timers)]; + timerIDs.forEach(function(timerID) { cancelTimer(timerID); }); + }); + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traceback.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traceback.js new file mode 100644 index 00000000..3828cbf8 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traceback.js @@ -0,0 +1,153 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci,components} = require("chrome"); + +// Undo the auto-parentification of URLs done in bug 418356. +function deParentifyURL(url) { + return url ? url.split(" -> ").slice(-1)[0] : url; +} + +// TODO: We might want to move this function to url or some similar +// module. +function getLocalFile(path) { + var ios = Cc['@mozilla.org/network/io-service;1'] + .getService(Ci.nsIIOService); + var channel = ios.newChannel(path, null, null); + var iStream = channel.open(); + var siStream = Cc['@mozilla.org/scriptableinputstream;1'] + .createInstance(Ci.nsIScriptableInputStream); + siStream.init(iStream); + var data = new String(); + data += siStream.read(-1); + siStream.close(); + iStream.close(); + return data; +} + +function safeGetFileLine(path, line) { + try { + var scheme = require("url").URL(path).scheme; + // TODO: There should be an easier, more accurate way to figure out + // what's the case here. + if (!(scheme == "http" || scheme == "https")) + return getLocalFile(path).split("\n")[line - 1]; + } catch (e) {} + return null; +} + +function errorStackToJSON(stack) { + var lines = stack.split("\n"); + + var frames = []; + lines.forEach( + function(line) { + if (!line) + return; + var atIndex = line.indexOf("@"); + var colonIndex = line.lastIndexOf(":"); + var filename = deParentifyURL(line.slice(atIndex + 1, colonIndex)); + var lineNo = parseInt(line.slice(colonIndex + 1)); + var funcSig = line.slice(0, atIndex); + var funcName = funcSig.slice(0, funcSig.indexOf("(")); + frames.unshift({filename: filename, + funcName: funcName, + lineNo: lineNo}); + }); + + return frames; +}; + +function nsIStackFramesToJSON(frame) { + var stack = []; + + while (frame) { + if (frame.filename) { + var filename = deParentifyURL(frame.filename); + stack.splice(0, 0, {filename: filename, + lineNo: frame.lineNumber, + funcName: frame.name}); + } + frame = frame.caller; + } + + return stack; +}; + +var fromException = exports.fromException = function fromException(e) { + if (e instanceof Ci.nsIException) + return nsIStackFramesToJSON(e.location); + if (e.stack && e.stack.length) + return errorStackToJSON(e.stack); + if (e.fileName && typeof(e.lineNumber == "number")) + return [{filename: deParentifyURL(e.fileName), + lineNo: e.lineNumber, + funcName: null}]; + return []; +}; + +var get = exports.get = function get() { + return nsIStackFramesToJSON(components.stack.caller); +}; + +var format = exports.format = function format(tbOrException) { + if (tbOrException === undefined) { + tbOrException = get(); + tbOrException.splice(-1, 1); + } + + var tb; + if (typeof(tbOrException) == "object" && + tbOrException.constructor.name == "Array") + tb = tbOrException; + else + tb = fromException(tbOrException); + + var lines = ["Traceback (most recent call last):"]; + + tb.forEach( + function(frame) { + if (!(frame.filename || frame.lineNo || frame.funcName)) + return; + lines.push(' File "' + frame.filename + '", line ' + + frame.lineNo + ', in ' + frame.funcName); + var sourceLine = safeGetFileLine(frame.filename, frame.lineNo); + if (sourceLine) + lines.push(' ' + sourceLine.trim()); + }); + + return lines.join("\n"); +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js new file mode 100644 index 00000000..07e764d0 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits.js @@ -0,0 +1,215 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +const { + compose: _compose, + override: _override, + resolve: _resolve, + trait: _trait, + //create: _create, + required, +} = require('traits/core'); + +const defineProperties = Object.defineProperties, + freeze = Object.freeze, + create = Object.create; + +/** + * Work around bug 608959 by defining the _create function here instead of + * importing it from traits/core. For docs on this function, see the create + * function in that module. + * + * FIXME: remove this workaround in favor of importing the function once that + * bug has been fixed. + */ +function _create(proto, trait) { + let properties = {}, + keys = Object.getOwnPropertyNames(trait); + for each(let key in keys) { + let descriptor = trait[key]; + if (descriptor.required && + !Object.prototype.hasOwnProperty.call(proto, key)) + throw new Error('Missing required property: ' + key); + else if (descriptor.conflict) + throw new Error('Remaining conflicting property: ' + key); + else + properties[key] = descriptor; + } + return Object.create(proto, properties); +} + +/** + * Placeholder for `Trait.prototype` + */ +let TraitProto = Object.prototype; + +function Get(key) this[key] +function Set(key, value) this[key] = value + +/** + * Creates anonymous trait descriptor from the passed argument, unless argument + * is a trait constructor. In later case trait's already existing properties + * descriptor is returned. + * This is module's internal function and is used as a gateway to a trait's + * internal properties descriptor. + * @param {Function} $ + * Composed trait's constructor. + * @returns {Object} + * Private trait property of the composition. + */ +function TraitDescriptor(object) + ( + 'function' == typeof object && + (object.prototype == TraitProto || object.prototype instanceof Trait) + ) ? object._trait(TraitDescriptor) : _trait(object) + +function Public(instance, trait) { + let result = {}, + keys = Object.getOwnPropertyNames(trait); + for each (let key in keys) { + if ('_' === key.charAt(0) && '__iterator__' !== key ) + continue; + let property = trait[key], + descriptor = { + configurable: property.configurable, + enumerable: property.enumerable + }; + if (property.get) + descriptor.get = property.get.bind(instance); + if (property.set) + descriptor.set = property.set.bind(instance); + if ('value' in property) { + let value = property.value; + if ('function' === typeof value) { + descriptor.value = property.value.bind(instance); + descriptor.writable = property.writable; + } else { + descriptor.get = Get.bind(instance, key); + descriptor.set = Set.bind(instance, key); + } + } + result[key] = descriptor; + } + return result; +} + +/** + * This is private function that composes new trait with privates. + */ +function Composition(trait) { + function Trait() { + let self = _create({}, trait); + self._public = create(Trait.prototype, Public(self, trait)); + delete self._public.constructor; + if (Object === self.constructor) + self.constructor = Trait; + else + return self.constructor.apply(self, arguments) || self._public; + return self._public; + } + defineProperties(Trait, { + prototype: { value: freeze(create(TraitProto, { + constructor: { value: constructor, writable: true } + }))}, // writable is `true` to avoid getters in custom ES5 + displayName: { value: (trait.constructor || constructor).name }, + compose: { value: compose, enumerable: true }, + override: { value: override, enumerable: true }, + resolve: { value: resolve, enumerable: true }, + required: { value: required, enumerable: true }, + _trait: { value: function _trait(caller) + caller === TraitDescriptor ? trait : undefined + } + }); + return freeze(Trait); +} + +/** + * Composes new trait out of itself and traits / property maps passed as an + * arguments. If two or more traits / property maps have properties with the + * same name, the new trait will contain a "conflict" property for that name. + * This is a commutative and associative operation, and the order of its + * arguments is not significant. + * @params {Object|Function} + * List of Traits or property maps to create traits from. + * @returns {Function} + * New trait containing the combined properties of all the traits. + */ +function compose() { + let traits = Array.slice(arguments, 0); + traits.push(this); + return Composition(_compose.apply(null, traits.map(TraitDescriptor))); +} + +/** + * Composes a new trait with all of the combined properties of `this` and the + * argument traits. In contrast to `compose`, `override` immediately resolves + * all conflicts resulting from this composition by overriding the properties of + * later traits. Trait priority is from left to right. I.e. the properties of + * the leftmost trait are never overridden. + * @params {Object} trait + * @returns {Object} + */ +function override() { + let traits = Array.slice(arguments, 0); + traits.push(this); + return Composition(_override.apply(null, traits.map(TraitDescriptor))); +} + +/** + * Composes new resolved trait, with all the same properties as this + * trait, except that all properties whose name is an own property of + * `resolutions` will be renamed to `resolutions[name]`. If it is + * `resolutions[name]` is `null` value is changed into a required property + * descriptor. + */ +function resolve(resolutions) + Composition(_resolve(resolutions, TraitDescriptor(this))) + +/** + * Base Trait, that all the traits are composed of. + */ +const Trait = Composition({ + /** + * Internal property holding public API of this instance. + */ + _public: { value: null, configurable: true, writable: true }, + toString: { value: function() '[object ' + this.constructor.name + ']' } +}); +TraitProto = Trait.prototype; +exports.Trait = Trait; + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits/core.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits/core.js new file mode 100644 index 00000000..a753c44a --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/traits/core.js @@ -0,0 +1,337 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; +// Design inspired by: http://www.traitsjs.org/ + +// shortcuts +const getOwnPropertyNames = Object.getOwnPropertyNames, + getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, + hasOwn = Object.prototype.hasOwnProperty, + _create = Object.create; +/** + * Compares two trait custom property descriptors if they are the same. If + * both are `conflict` or all the properties of descriptor are equal returned + * value will be `true`, otherwise it will be `false`. + * @param {Object} desc1 + * @param {Object} desc2 + */ +function areSame(desc1, desc2) { + return (desc1.conflict && desc2.conflict) || ( + desc1.get === desc2.get && + desc1.set === desc2.set && + desc1.value === desc2.value && + desc1.enumerable === desc2.enumerable && + desc1.required === desc2.required && + desc1.conflict === desc2.conflict + ); +} + +/** + * Converts array to an object whose own property names represent + * values of array. + * @param {String[]} names + * @returns {Object} + * @example + * Map(['foo', ...]) => { foo: true, ...} + */ +function Map(names) { + let map = {}; + for each (let name in names) + map[name] = true; + return map; +} + + +const ERR_CONFLICT = 'Remaining conflicting property: ', + ERR_REQUIRED = 'Missing required property: '; +/** + * Constant singleton, representing placeholder for required properties. + * @type {Object} + */ +const required = { toString: function()'' }; +exports.required = required; + +/** + * Generates custom **required** property descriptor. Descriptor contains + * non-standard property `required` that is equal to `true`. + * @param {String} name + * property name to generate descriptor for. + * @returns {Object} + * custom property descriptor + */ +function Required(name) { + function required() { throw new Error(ERR_REQUIRED + name) } + return { + get: required, + set: required, + required: true + }; +} + +/** + * Generates custom **conflicting** property descriptor. Descriptor contains + * non-standard property `conflict` that is equal to `true`. + * @param {String} name + * property name to generate descriptor for. + * @returns {Object} + * custom property descriptor + */ +function Conflict(name) { + function conflict() { throw new Error(ERR_CONFLICT + name) } + return { + get: conflict, + set: conflict, + conflict: true + }; +} + +/** + * Function generates custom properties descriptor of the `object`s own + * properties. All the inherited properties are going to be ignored. + * Properties with values matching `required` singleton will be marked as + * 'required' properties. + * @param {Object} object + * Set of properties to generate trait from. + * @returns {Object} + * Properties descriptor of all of the `object`'s own properties. + */ +function trait(properties) { + let result = {}, + keys = getOwnPropertyNames(properties); + for each (let key in keys) { + let descriptor = getOwnPropertyDescriptor(properties, key); + result[key] = (required === descriptor.value) ? Required(key) : descriptor; + } + return result; +} +exports.Trait = exports.trait = trait; + +/** + * Composes new trait. If two or more traits have own properties with the + * same name, the new trait will contain a 'conflict' property for that name. + * 'compose' is a commutative and associative operation, and the order of its + * arguments is not significant. + * + * @params {Object} trait + * Takes traits as an arguments + * @returns {Object} + * New trait containing the combined own properties of all the traits. + * @example + * var newTrait = compose(trait_1, trait_2, ..., trait_N); + */ +function compose(trait1, trait2) { + let traits = Array.slice(arguments, 0), + result = {}; + for each (let trait in traits) { + let keys = getOwnPropertyNames(trait); + for each (let key in keys) { + let descriptor = trait[key]; + // if property already exists and it's not a requirement + if (hasOwn.call(result, key) && !result[key].required) { + if (descriptor.required) + continue; + if (!areSame(descriptor, result[key])) + result[key] = Conflict(key); + } else { + result[key] = descriptor; + } + } + } + return result; +} +exports.compose = compose; + +/** + * Composes new trait with the same own properties as the original trait, + * except that all property names appearing in the first argument are replaced + * by 'required' property descriptors. + * @param {String[]} keys + * Array of strings property names. + * @param {Object} trait + * A trait some properties of which should be excluded. + * @returns {Object} + * @example + * var newTrait = exclude(['name', ...], trait) + */ +function exclude(keys, trait) { + let exclusions = Map(keys), + result = {}, + keys = getOwnPropertyNames(trait); + for each (let key in keys) { + if (!hasOwn.call(exclusions, key) || trait[key].required) + result[key] = trait[key]; + else + result[key] = Required(key); + } + return result; +} + +/** + * Composes a new trait with all of the combined properties of the argument + * traits. In contrast to `compose`, `override` immediately resolves all + * conflicts resulting from this composition by overriding the properties of + * later traits. Trait priority is from left to right. I.e. the properties of + * the leftmost trait are never overridden. + * @params {Object} trait + * @returns {Object} + * @examples + * // override is associative: + * override(t1,t2,t3) + * // is equivalent to + * override(t1, override(t2, t3)) + * // or + * to override(override(t1, t2), t3) + * + * // override is not commutative: + * override(t1,t2) + * // is not equivalent to + * override(t2,t1) + */ +function override() { + let traits = Array.slice(arguments, 0), + result = {}; + for each (let trait in traits) { + let keys = getOwnPropertyNames(trait); + for each(let key in keys) { + let descriptor = trait[key]; + if (!hasOwn.call(result, key) || result[key].required) + result[key] = descriptor; + } + } + return result; +} +exports.override = override; + +/** + * Composes a new trait with the same properties as the original trait, except + * that all properties whose name is an own property of map will be renamed to + * map[name], and a 'required' property for name will be added instead. + * @param {Object} map + * An object whose own properties serve as a mapping from old names to new + * names. + * @param {Object} trait + * A trait object + * @returns {Object} + * @example + * var newTrait = rename(map, trait); + */ +function rename(map, trait) { + let result = {}, + keys = getOwnPropertyNames(trait); + for each(let key in keys) { + // must be renamed & it's not requirement + if (hasOwn.call(map, key) && !trait[key].required) { + let alias = map[key]; + if (hasOwn.call(result, alias) && !result[alias].required) + result[alias] = Conflict(alias); + else + result[alias] = trait[key]; + if (!hasOwn.call(result, key)) + result[key] = Required(key); + } else { // must not be renamed or its a requirement + // property is not in result trait yet + if (!hasOwn.call(result, key)) + result[key] = trait[key]; + // property is already in resulted trait & it's not requirement + else if (!trait[key].required) + result[key] = Conflict(key); + } + } + return result; +} + +/** +* Composes new resolved trait, with all the same properties as the original +* trait, except that all properties whose name is an own property of +* resolutions will be renamed to `resolutions[name]`. If it is +* `resolutions[name]` is `null` value is changed into a required property +* descriptor. +* function can be implemented as `rename(map,exclude(exclusions, trait))` +* where map is the subset of mappings from oldName to newName and exclusions +* is an array of all the keys that map to `null`. +* Note: it's important to **first** `exclude`, **then** `rename`, since +* `exclude` and rename are not associative. +* @param {Object} resolutions +* An object whose own properties serve as a mapping from old names to new +* names, or to `null` if the property should be excluded. +* @param {Object} trait +* A trait object +* @returns {Object} +* Resolved trait with the same own properties as the original trait. +*/ +function resolve(resolutions, trait) { + let renames = {}, + exclusions = [], + keys = getOwnPropertyNames(resolutions); + for each (let key in keys) { // pre-process renamed and excluded properties + if (resolutions[key]) // old name -> new name + renames[key] = resolutions[key]; + else // name -> undefined + exclusions.push(key); + } + return rename(renames, exclude(exclusions, trait)); +} +exports.resolve = resolve; + +/** + * `create` is like `Object.create`, except that it ensures that: + * - an exception is thrown if 'trait' still contains required properties + * - an exception is thrown if 'trait' still contains conflicting + * properties + * @param {Object} + * prototype of the completed object + * @param {Object} trait + * trait object to be turned into a complete object + * @returns {Object} + * An object with all of the properties described by the trait. + */ +function create(proto, trait) { + let properties = {}, + keys = getOwnPropertyNames(trait); + for each(let key in keys) { + let descriptor = trait[key]; + if (descriptor.required && !hasOwn.call(proto, key)) + throw new Error(ERR_REQUIRED + key); + else if (descriptor.conflict) + throw new Error(ERR_CONFLICT + key); + else + properties[key] = descriptor; + } + return _create(proto, properties); +} +exports.create = create; + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/type.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/type.js new file mode 100644 index 00000000..b39374c4 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/type.js @@ -0,0 +1,372 @@ +/* vim:ts=2:sts=2:sw=2: + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +/** + * Returns `true` if `value` is `undefined`. + * @examples + * var foo; isUndefined(foo); // true + * isUndefined(0); // false + */ +function isUndefined(value) { + return value === undefined; +} +exports.isUndefined = isUndefined; + +/** + * Returns `true` if value is `null`. + * @examples + * isNull(null); // true + * isNull(undefined); // false + */ +function isNull(value) { + return value === null; +} +exports.isNull = isNull; + +/** + * Returns `true` if value is a string. + * @examples + * isString("moe"); // true + */ +function isString(value) { + return typeof value === "string"; +} +exports.isString = isString; + +/** + * Returns `true` if `value` is a number. + * @examples + * isNumber(8.4 * 5); // true + */ +function isNumber(value) { + return typeof value === "number"; +} +exports.isNumber = isNumber; + +/** + * Returns `true` if `value` is a `RegExp`. + * @examples + * isRegExp(/moe/); // true + */ +function isRegExp(value) { + return isObject(value) && instanceOf(value, RegExp); +} +exports.isRegExp = isRegExp; + +/** + * Returns true if `value` is a `Date`. + * @examples + * isDate(new Date()); // true + */ +function isDate(value) { + return isObject(value) && instanceOf(Date); +} +exports.isDate = isDate; + +/** + * Returns true if object is a Function. + * @examples + * isFunction(function foo(){}) // true + */ +function isFunction(value) { + return typeof value === "function"; +} +exports.isFunction = isFunction; + +/** + * Returns `true` if `value` is an object (please note that `null` is considered + * to be an atom and not an object). + * @examples + * isObject({}) // true + * isObject(null) // false + */ +function isObject(value) { + return typeof value === "object" && value !== null; +} +exports.isObject = isObject; + +/** + * Returns true if `value` is an Array. + * @examples + * isArray([1, 2, 3]) // true + * isArray({ 0: 'foo', length: 1 }) // false + */ +var isArray = Array.isArray || function isArray(value) { + Object.prototype.toString.call(value) === "[object Array]"; +} +exports.isArray = isArray; + +/** + * Returns `true` if `value` is an Arguments object. + * @examples + * (function(){ return isArguments(arguments); })(1, 2, 3); // true + * isArguments([1,2,3]); // false + */ +function isArguments(value) { + Object.prototype.toString.call(value) === "[object Arguments]"; +} +exports.isArguments = isArguments; + +/** + * Returns true if it is a primitive `value`. (null, undefined, number, + * boolean, string) + * @examples + * isPrimitive(3) // true + * isPrimitive('foo') // true + * isPrimitive({ bar: 3 }) // false + */ +function isPrimitive(value) { + return !isFunction(value) && !isObject(value); +} +exports.isPrimitive = isPrimitive; + +/** + * Returns `true` if given `object` is flat (it is direct decedent of + * `Object.prototype` or `null`). + * @examples + * isFlat({}) // true + * isFlat(new Type()) // false + */ +function isFlat(object) { + return isObject(object) && (isNull(Object.getPrototypeOf(object)) || + isNull(Object.getPrototypeOf( + Object.getPrototypeOf(object)))); +} +exports.isFlat = isFlat; + +/** + * Returns `true` if object contains no values. + */ +function isEmpty(object) { + if (isObject(object)) { + for (var key in object) + return false; + return true; + } + return false; +} +exports.isEmpty = isEmpty; + +/** + * Returns `true` if `value` is an array / flat object containing only atomic + * values and other flat objects. + */ +function isJSON(value, visited) { + // Adding value to array of visited values. + (visited || (visited = [])).push(value); + // If `value` is an atom return `true` cause it's valid JSON. + return isPrimitive(value) || + // If `value` is an array of JSON values that has not been visited + // yet. + (isArray(value) && value.every(function(element) { + return isJSON(element, visited); + })) || + // If `value` is a plain object containing properties with a JSON + // values it's a valid JSON. + (isFlat(value) && Object.keys(value).every(function(key) { + var $ = Object.getOwnPropertyDescriptor(value, key); + // Check every proprety of a plain object to verify that + // it's neither getter nor setter, but a JSON value, that + // has not been visited yet. + return ((!isObject($.value) || !~visited.indexOf($.value)) && + !('get' in $) && !('set' in $) && + isJSON($.value, visited)); + })); +} +exports.isJSON = function (value) { + return isJSON(value); +}; + +/** + * Returns if `value` is an instance of a given `Type`. This is exactly same as + * `value instanceof Type` with a difference that `Type` can be from a scope + * that has a different top level object. (Like in case where `Type` is a + * function from different iframe / jetpack module / sandbox). + */ +function instanceOf(value, Type) { + var isConstructorNameSame; + var isConstructorSourceSame; + + // If `instanceof` returned `true` we know result right away. + var isInstanceOf = value instanceof Type; + + // If `instanceof` returned `false` we do ducktype check since `Type` may be + // from a different sandbox. If a constructor of the `value` or a constructor + // of the value's prototype has same name and source we assume that it's an + // instance of the Type. + if (!isInstanceOf) { + isConstructorNameSame = value.constructor.name === Type.name; + isConstructorSourceSame = String(value.constructor) == String(Type); + isInstanceOf = (isConstructorNameSame && isConstructorSourceSame) || + instanceOf(Object.getPrototypeOf(value), Type); + } + return isInstanceOf; +} +exports.instanceOf = instanceOf; + +/** + * Function returns textual representation of a value passed to it. Function + * takes additional `indent` argument that is used for indentation. Also + * optional `limit` argument may be passed to limit amount of detail returned. + * @param {Object} value + * @param {String} [indent=" "] + * @param {Number} [limit] + */ +function source(value, indent, limit, offset, visited) { + var result; + var names; + var nestingIndex; + var isCompact = !isUndefined(limit); + + indent = indent || " "; + offset = (offset || ""); + result = ""; + visited = visited || []; + + if (isUndefined(value)) { + result += "undefined"; + } + else if (isNull(value)) { + result += "null"; + } + else if (isString(value)) { + result += '"' + value + '"'; + } + else if (isFunction(value)) { + value = String(value).split("\n"); + if (isCompact && value.length > 2) { + value = value.splice(0, 2); + value.push("...}"); + } + result += value.join("\n" + offset); + } + else if (isArray(value)) { + if ((nestingIndex = (visited.indexOf(value) + 1))) { + result = "#" + nestingIndex + "#"; + } + else { + visited.push(value); + + if (isCompact) + value = value.slice(0, limit); + + result += "[\n"; + result += value.map(function(value) { + return offset + indent + source(value, indent, limit, offset + indent, + visited); + }).join(",\n"); + result += isCompact && value.length > limit ? + ",\n" + offset + "...]" : "\n" + offset + "]"; + } + } + else if (isObject(value)) { + if ((nestingIndex = (visited.indexOf(value) + 1))) { + result = "#" + nestingIndex + "#" + } + else { + visited.push(value) + + names = Object.keys(value); + + result += "{ // " + value + "\n"; + result += (isCompact ? names.slice(0, limit) : names).map(function(name) { + var _limit = isCompact ? limit - 1 : limit; + var descriptor = Object.getOwnPropertyDescriptor(value, name); + var result = offset + indent + "// "; + var accessor; + if (0 <= name.indexOf(" ")) + name = '"' + name + '"'; + + if (descriptor.writable) + result += "writable "; + if (descriptor.configurable) + result += "configurable "; + if (descriptor.enumerable) + result += "enumerable "; + + result += "\n"; + if ("value" in descriptor) { + result += offset + indent + name + ": "; + result += source(descriptor.value, indent, _limit, indent + offset, + visited); + } + else { + + if (descriptor.get) { + result += offset + indent + "get " + name + " "; + accessor = source(descriptor.get, indent, _limit, indent + offset, + visited); + result += accessor.substr(accessor.indexOf("{")); + } + + if (descriptor.set) { + result += offset + indent + "set " + name + " "; + accessor = source(descriptor.set, indent, _limit, indent + offset, + visited); + result += accessor.substr(accessor.indexOf("{")); + } + } + return result; + }).join(",\n"); + + if (isCompact) { + if (names.length > limit && limit > 0) { + result += ",\n" + offset + indent + "//..."; + } + } + else { + if (names.length) + result += ","; + + result += "\n" + offset + indent + '"__proto__": '; + result += source(Object.getPrototypeOf(value), indent, 0, + offset + indent); + } + + result += "\n" + offset + "}"; + } + } + else { + result += String(value); + } + return result; +} +exports.source = function (value, indentation, limit) { + return source(value, indentation, limit); +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test-finder.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test-finder.js new file mode 100644 index 00000000..84f829c6 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test-finder.js @@ -0,0 +1,112 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +// We don't actually use chrome directly, but we do access the +// filesystem and scan it to dynamically import modules, so +// we put this here to tell the module loader to give us +// permission to require() whatever we want. +require("chrome"); + +var file = require("file"); + +var TestFinder = exports.TestFinder = function TestFinder(options) { + memory.track(this); + this.dirs = options.dirs || []; + this.filter = options.filter || function() { return true; }; + this.testInProcess = options.testInProcess === false ? false : true; + this.testOutOfProcess = options.testOutOfProcess === true ? true : false; +}; + +TestFinder.prototype = { + _makeTest: function _makeTest(suite, name, test) { + function runTest(runner) { + console.info("executing '" + suite + "." + name + "'"); + test(runner); + } + return runTest; + }, + + findTests: function findTests(cb) { + var self = this; + var tests = []; + var remoteSuites = []; + var filter; + + if (typeof(this.filter) == "string") { + var filterRegex = new RegExp(self.filter); + filter = function(name) { + return filterRegex.test(name); + }; + } else if (typeof(this.filter) == "function") + filter = this.filter; + + this.dirs.forEach( + function(dir) { + var suites = [name.slice(0, -3) + for each (name in file.list(dir)) + if (/^test-.*\.js$/.test(name) && filter(name))]; + + suites.forEach( + function(suite) { + var loader = require("parent-loader"); + var url = loader.fs.resolveModule(null, suite); + var moduleInfo = packaging.getModuleInfo(url); + var module = require(suite); + if (self.testInProcess) + for (name in module) + tests.push({ + testFunction: self._makeTest(suite, name, module[name]), + name: suite + "." + name + }); + if (!moduleInfo.needsChrome) + remoteSuites.push(suite); + }); + }); + + if (this.testOutOfProcess && remoteSuites.length > 0) { + var process = require("e10s").AddonProcess(); + var finderHandle = process.createHandle(); + finderHandle.onTestsFound = function(testsFound) { + cb(tests.concat(testsFound)); + }; + process.send("startMain", "find-tests", { + suites: remoteSuites, + finderHandle: finderHandle + }); + } else + cb(tests); + } +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test.js new file mode 100644 index 00000000..812cecf6 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unit-test.js @@ -0,0 +1,276 @@ +/* vim:st=2:sts=2:sw=2: + * ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +var timer = require("timer"); + +exports.findAndRunTests = function findAndRunTests(options) { + var TestFinder = require("unit-test-finder").TestFinder; + var finder = new TestFinder({ + dirs: options.dirs, + filter: options.filter, + testInProcess: options.testInProcess, + testOutOfProcess: options.testOutOfProcess + }); + var runner = new TestRunner({fs: options.fs}); + finder.findTests( + function (tests) { + runner.startMany({tests: tests, + onDone: options.onDone}); + }); +}; + +var TestRunner = exports.TestRunner = function TestRunner(options) { + if (options) { + this.fs = options.fs; + } + memory.track(this); + this.passed = 0; + this.failed = 0; + this.testRunSummary = []; +}; + +TestRunner.prototype = { + toString: function toString() "[object TestRunner]", + + DEFAULT_PAUSE_TIMEOUT: 10000, + + _logTestFailed: function _logTestFailed(why) { + this.test.errors[why]++; + if (!this.testFailureLogged) { + console.error("TEST FAILED: " + this.test.name + " (" + why + ")"); + this.testFailureLogged = true; + } + }, + + makeSandboxedLoader: function makeSandboxedLoader(options) { + if (!this.fs) + console.error("Hey, either you didn't pass .fs when building the" + + " TestRunner, or you used 'new' when calling" + + " test.makeSandboxedLoader. Don't do that."); + + if (!options) + options = {console: console}; + options.fs = this.fs; + + var Cuddlefish = require("cuddlefish"); + + if ("moduleOverrides" in options) { + var moduleOverrides = options.moduleOverrides; + delete options.moduleOverrides; + function getModuleExports(basePath, module) { + if (module in moduleOverrides) + return moduleOverrides[module]; + return null; + } + options.getModuleExports = getModuleExports; + } + + return new Cuddlefish.Loader(options); + }, + + pass: function pass(message) { + console.info("pass:", message); + this.passed++; + this.test.passed++; + }, + + fail: function fail(message) { + this._logTestFailed("failure"); + console.error("fail:", message); + console.trace(); + this.failed++; + this.test.failed++; + }, + + exception: function exception(e) { + this._logTestFailed("exception"); + console.exception(e); + this.failed++; + this.test.failed++; + }, + + assertMatches: function assertMatches(string, regexp, message) { + if (regexp.test(string)) { + if (!message) + message = uneval(string) + " matches " + uneval(regexp); + this.pass(message); + } else { + var no = uneval(string) + " doesn't match " + uneval(regexp); + if (!message) + message = no; + else + message = message + " (" + no + ")"; + this.fail(message); + } + }, + + assertRaises: function assertRaises(func, predicate, message) { + try { + func(); + if (message) + this.fail(message + " (no exception thrown)"); + else + this.fail("function failed to throw exception"); + } catch (e) { + var errorMessage; + if (typeof(e) == "string") + errorMessage = e; + else + errorMessage = e.message; + if (typeof(predicate) == "string") + this.assertEqual(errorMessage, predicate, message); + else + this.assertMatches(errorMessage, predicate, message); + } + }, + + assert: function assert(a, message) { + if (!a) { + if (!message) + message = "assertion failed, value is " + a; + this.fail(message); + } else + this.pass(message || "assertion successful"); + }, + + assertNotEqual: function assertNotEqual(a, b, message) { + if (a != b) { + if (!message) + message = "a != b != " + uneval(a); + this.pass(message); + } else { + var equality = uneval(a) + " == " + uneval(b); + if (!message) + message = equality; + else + message += " (" + equality + ")"; + this.fail(message); + } + }, + + assertEqual: function assertEqual(a, b, message) { + if (a == b) { + if (!message) + message = "a == b == " + uneval(a); + this.pass(message); + } else { + var inequality = uneval(a) + " != " + uneval(b); + if (!message) + message = inequality; + else + message += " (" + inequality + ")"; + this.fail(message); + } + }, + + done: function done() { + if (!this.isDone) { + this.isDone = true; + if (this.waitTimeout !== null) { + timer.clearTimeout(this.waitTimeout); + this.waitTimeout = null; + } + if (this.test.passed == 0 && this.test.failed == 0) { + this._logTestFailed("empty test"); + this.failed++; + this.test.failed++; + } + + this.testRunSummary.push({ + name: this.test.name, + passed: this.test.passed, + failed: this.test.failed, + errors: [error for (error in this.test.errors)].join(", ") + }); + + if (this.onDone !== null) { + var onDone = this.onDone; + var self = this; + this.onDone = null; + timer.setTimeout(function() { onDone(self); }, 0); + } + } + }, + + waitUntilDone: function waitUntilDone(ms) { + if (ms === undefined) + ms = this.DEFAULT_PAUSE_TIMEOUT; + + var self = this; + + function tiredOfWaiting() { + self._logTestFailed("timed out"); + self.failed++; + self.test.failed++; + self.done(); + } + + this.waitTimeout = timer.setTimeout(tiredOfWaiting, ms); + }, + + startMany: function startMany(options) { + function runNextTest(self) { + var test = options.tests.shift(); + if (test) + self.start({test: test, onDone: runNextTest}); + else + options.onDone(self); + } + runNextTest(this); + }, + + start: function start(options) { + this.test = options.test; + this.test.passed = 0; + this.test.failed = 0; + this.test.errors = {}; + + this.isDone = false; + this.onDone = options.onDone; + this.waitTimeout = null; + this.testFailureLogged = false; + + try { + this.test.testFunction(this); + } catch (e) { + this.exception(e); + } + if (this.waitTimeout === null) + this.done(); + } +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js new file mode 100644 index 00000000..7d690e86 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/unload.js @@ -0,0 +1,49 @@ +// Parts of this module were taken from narwhal: +// +// http://narwhaljs.org + +var observers = []; +var unloaders = []; + +var when = exports.when = function when(observer) { + observers.unshift(observer); +}; + +var send = exports.send = function send(reason) { + observers.forEach(function (observer) { + observer(reason); + }); +}; + +var addMethod = exports.addMethod = function addMethod(obj, unloader) { + var called = false; + + function unloadWrapper(reason) { + if (!called) { + called = true; + var index = unloaders.indexOf(unloadWrapper); + if (index == -1) + throw new Error("internal error: unloader not found"); + unloaders.splice(index, 1); + unloader.apply(obj, [reason]); + } + }; + + unloaders.push(unloadWrapper); + obj.unload = unloadWrapper; +}; + +var ensure = exports.ensure = function ensure(obj) { + if (!("unload" in obj)) + throw new Error("object has no 'unload' property"); + + addMethod(obj, obj.unload); +}; + +when( + function(reason) { + unloaders.slice().forEach( + function(unloadWrapper) { + unloadWrapper(reason); + }); + }); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url-e10s-adapter.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url-e10s-adapter.js new file mode 100644 index 00000000..50dec1d8 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url-e10s-adapter.js @@ -0,0 +1,91 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Add-on SDK. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili + * Myk Melez + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +if (this.chrome) { + exports.toFilename = function(spec) chrome.call("url:toFilename", spec); + exports.fromFilename = function(spec) chrome.call("url:fromFilename", spec); + + let URL = exports.URL = function URL(spec, base) { + // We have to force the `spec` and `base` arguments, if defined, to be + // strings before sending them across the process boundary, since the + // boundary will drop their custom toString() methods if they are URL + // objects, and the other side depends on being able to convert them to + // strings. + let result = chrome.call("url:URL", + typeof spec == "undefined" ? spec : "" + spec, + typeof base == "undefined" ? base : "" + base); + + let { scheme, userPass, host, port, path } = result.url; + + return Object.create(URL.prototype, { + scheme: { value: scheme, enumerable: true }, + userPass: { value: userPass, enumerable: true }, + host: { value: host, enumerable: true }, + port: { value: port, enumerable: true }, + path: { value: path, enumerable: true }, + toString: { value: function() chrome.call("url:toString", result.handle) } + }); + } +} +else { + const { URL, toFilename, fromFilename } = require("url"); + + exports.register = function register(addon) { + addon.registerCall("url:toFilename", function(name, spec) toFilename(spec)); + + addon.registerCall("url:fromFilename", + function(name, spec) fromFilename(spec)); + + addon.registerCall("url:URL", function(name, spec, base) { + let url = URL(spec, base); + + // We create a handle to give the addon process access to the toString() + // method, which cannot traverse the process boundary but also can't be + // duplicated in the addon process because it accesses private information + // (the spec of the URL). The handle doesn't need to be rooted, as it + // can be GCed as soon as all references to it are removed. + let handle = addon.createHandle(); + handle.isRooted = false; + handle.url = url; + + return { url: url, handle: handle }; + }); + + addon.registerCall("url:toString", + function(name, handle) handle.url.toString()); + } +} diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js new file mode 100644 index 00000000..9089352d --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/url.js @@ -0,0 +1,121 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci,Cr} = require("chrome"); + +var ios = Cc['@mozilla.org/network/io-service;1'] + .getService(Ci.nsIIOService); + +var resProt = ios.getProtocolHandler("resource") + .QueryInterface(Ci.nsIResProtocolHandler); + +function newURI(uriStr, base) { + try { + let baseURI = base ? ios.newURI(base, null, null) : null; + return ios.newURI(uriStr, null, baseURI); + } + catch (e if e.result == Cr.NS_ERROR_MALFORMED_URI) { + throw new Error("malformed URI: " + uriStr); + } + catch (e if (e.result == Cr.NS_ERROR_FAILURE || + e.result == Cr.NS_ERROR_ILLEGAL_VALUE)) { + throw new Error("invalid URI: " + uriStr); + } +} + +function resolveResourceURI(uri) { + var resolved; + try { + resolved = resProt.resolveURI(uri); + } catch (e if e.result == Cr.NS_ERROR_NOT_AVAILABLE) { + throw new Error("resource does not exist: " + uri.spec); + }; + return resolved; +} + +let fromFilename = exports.fromFilename = function fromFilename(path) { + var file = Cc['@mozilla.org/file/local;1'] + .createInstance(Ci.nsILocalFile); + file.initWithPath(path); + return ios.newFileURI(file).spec; +}; + +let toFilename = exports.toFilename = function toFilename(url) { + var uri = newURI(url); + if (uri.scheme == "resource") + uri = newURI(resolveResourceURI(uri)); + if (uri.scheme == "chrome") { + var channel = ios.newChannelFromURI(uri); + try { + channel = channel.QueryInterface(Ci.nsIFileChannel); + return channel.file.path; + } catch (e if e.result == Cr.NS_NOINTERFACE) { + throw new Error("chrome url isn't on filesystem: " + url); + } + } + if (uri.scheme == "file") { + var file = uri.QueryInterface(Ci.nsIFileURL).file; + return file.path; + } + throw new Error("cannot map to filename: " + url); +}; + +function URL(url, base) { + var uri = newURI(url, base); + + var userPass = null; + try { + userPass = uri.userPass ? uri.userPass : null; + } catch (e if e.result == Cr.NS_ERROR_FAILURE) {} + + var host = null; + try { + host = uri.host; + } catch (e if e.result == Cr.NS_ERROR_FAILURE) {} + + var port = null; + try { + port = uri.port == -1 ? null : uri.port; + } catch (e if e.result == Cr.NS_ERROR_FAILURE) {} + + this.__defineGetter__("scheme", function() uri.scheme); + this.__defineGetter__("userPass", function() userPass); + this.__defineGetter__("host", function() host); + this.__defineGetter__("port", function() port); + this.__defineGetter__("path", function() uri.path); + this.toString = function URL_toString() uri.spec; +}; +exports.URL = require("api-utils").publicConstructor(URL); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/data.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/data.js new file mode 100644 index 00000000..90a4c049 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/data.js @@ -0,0 +1,104 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +const { Cc, Ci, Cu } = require("chrome"); +const IOService = Cc["@mozilla.org/network/io-service;1"]. + getService(Ci.nsIIOService); +const AppShellService = Cc["@mozilla.org/appshell/appShellService;1"]. + getService(Ci.nsIAppShellService); + +Cu.import("resource://gre/modules/NetUtil.jsm", this); +const FaviconService = Cc["@mozilla.org/browser/favicon-service;1"]. + getService(Ci.nsIFaviconService); + +const PNG_B64 = "data:image/png;base64,"; +const DEF_FAVICON_URI = "chrome://mozapps/skin/places/defaultFavicon.png"; +let DEF_FAVICON = null; + +/** + * Takes URI of the page and returns associated favicon URI. + * If page under passed uri has no favicon then base64 encoded data URI of + * default faveicon is returned. + * @param {String} uri + * @returns {String} + */ +exports.getFaviconURIForLocation = function getFaviconURIForLocation(uri) { + let pageURI = NetUtil.newURI(uri); + try { + return FaviconService.getFaviconDataAsDataURL( + FaviconService.getFaviconForPage(pageURI)); + } + catch(e) { + if (!DEF_FAVICON) { + DEF_FAVICON = PNG_B64 + + base64Encode(getChromeURIContent(DEF_FAVICON_URI)); + } + return DEF_FAVICON; + } +} + +/** + * Takes chrome URI and returns content under that URI. + * @param {String} chromeURI + * @returns {String} + */ +function getChromeURIContent(chromeURI) { + let channel = IOService.newChannel(chromeURI, null, null); + let input = channel.open(); + let stream = Cc["@mozilla.org/binaryinputstream;1"]. + createInstance(Ci.nsIBinaryInputStream); + stream.setInputStream(input); + let content = stream.readBytes(input.available()); + stream.close(); + input.close(); + return content; +} +exports.getChromeURIContent = getChromeURIContent; + +/** + * Creates a base-64 encoded ASCII string from a string of binary data. + */ +function base64Encode(data) AppShellService.hiddenDOMWindow.btoa(String(data)); +exports.base64Encode = base64Encode; + +/** + * Decodes a string of data which has been encoded using base-64 encoding. + */ +function base64Decode(data) AppShellService.hiddenDOMWindow.atob(String(data)); +exports.base64Decode = base64Decode; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/function.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/function.js new file mode 100644 index 00000000..6576b4e3 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/function.js @@ -0,0 +1,64 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +var { setTimeout } = require("timer"); + +/** + * Takes a function and returns a wrapped one instead, calling which will call + * original function in the next turn of event loop. This is basically utility + * to do `setTimeout(function() { ... }, 0)`, with a difference that returned + * function is reused, instead of creating a new one each time. This also allows + * to use this functions as event listeners. + */ +function Enqueued(callee) { + return function enqueued() + setTimeout(invoke, 0, callee, arguments, this); +} +exports.Enqueued = Enqueued; + +/** + * Invokes `callee` by passing `params` as an arguments and `self` as `this` + * pseudo-variable. Returns value that is returned by a callee. + * @param {Function} callee + * Function to invoke. + * @param {Array} params + * Arguments to invoke function with. + * @param {Object} self + * Object to be passed as a `this` pseudo variable. + */ +function invoke(callee, params, self) callee.apply(self, params); +exports.invoke = invoke; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/registry.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/registry.js new file mode 100644 index 00000000..bdd1a95f --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/registry.js @@ -0,0 +1,90 @@ +/* -*- Mode: Java; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim:set ts=2 sw=2 sts=2 et: */ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +const { EventEmitter } = require('events'); +const unload = require("unload"); + +const Registry = EventEmitter.compose({ + _registry: null, + _constructor: null, + constructor: function Registry(constructor) { + this._registry = []; + this._constructor = constructor; + this.on('error', this._onError = this._onError.bind(this)); + unload.when(this._destructor.bind(this)); + }, + _destructor: function _destructor() { + let _registry = this._registry.slice(0); + for each (instance in _registry) + this._emit('remove', instance); + this._registry.splice(0); + }, + _onError: function _onError(e) { + if (!this._listeners('error').length) + console.error(e); + }, + has: function has(instance) { + let _registry = this._registry; + return ( + (0 <= _registry.indexOf(instance)) || + (instance && instance._public && 0 <= _registry.indexOf(instance._public)) + ); + }, + add: function add(instance) { + let { _constructor, _registry } = this; + if (!(instance instanceof _constructor)) + instance = new _constructor(instance); + if (0 > _registry.indexOf(instance)) { + _registry.push(instance); + this._emit('add', instance); + return instance; + } + }, + remove: function remove(instance) { + let _registry = this._registry; + let index = _registry.indexOf(instance) + if (0 <= index) { + this._emit('remove', instance); + _registry.splice(index, 1); + } + } +}); +exports.Registry = Registry; + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/thumbnail.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/thumbnail.js new file mode 100644 index 00000000..d9012e1b --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/utils/thumbnail.js @@ -0,0 +1,76 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +"use strict"; + +const { Cc, Ci, Cu } = require("chrome"); +const AppShellService = Cc["@mozilla.org/appshell/appShellService;1"]. + getService(Ci.nsIAppShellService); + +const NS = "http://www.w3.org/1999/xhtml"; +const COLOR = "rgb(255,255,255)"; + +/** + * Creates canvas element with a thumbnail of the passed window. + * @param {Window} window + * @returns {Element} + */ +function getThumbnailCanvasForWindow(window) { + let aspectRatio = 0.5625; // 16:9 + let thumbnail = AppShellService.hiddenDOMWindow.document + .createElementNS(NS, "canvas"); + thumbnail.mozOpaque = true; + thumbnail.width = Math.ceil(window.screen.availWidth / 5.75); + thumbnail.height = Math.round(thumbnail.width * aspectRatio); + let ctx = thumbnail.getContext("2d"); + let snippetWidth = window.innerWidth * .6; + let scale = thumbnail.width / snippetWidth; + ctx.scale(scale, scale); + ctx.drawWindow(window, window.scrollX, window.scrollY, snippetWidth, + snippetWidth * aspectRatio, COLOR); + return thumbnail; +} +exports.getThumbnailCanvasForWindow = getThumbnailCanvasForWindow; + +/** + * Creates Base64 encoded data URI of the thumbnail for the passed window. + * @param {Window} window + * @returns {String} + */ +exports.getThumbnailURIForWindow = function getThumbnailURIForWindow(window) { + return getThumbnailCanvasForWindow(window).toDataURL() +}; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/window-utils.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/window-utils.js new file mode 100644 index 00000000..6755012f --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/window-utils.js @@ -0,0 +1,176 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci} = require("chrome"); + +var errors = require("errors"); + +var gWindowWatcher = Cc["@mozilla.org/embedcomp/window-watcher;1"] + .getService(Ci.nsIWindowWatcher); + +const { EventEmitter } = require('events'), + { Trait } = require('traits'); + +/** + * An iterator for XUL windows currently in the application. + * + * @return A generator that yields XUL windows exposing the + * nsIDOMWindow interface. + */ +var windowIterator = exports.windowIterator = function windowIterator() { + let winEnum = gWindowWatcher.getWindowEnumerator(); + while (winEnum.hasMoreElements()) + yield winEnum.getNext().QueryInterface(Ci.nsIDOMWindow); +}; + +var WindowTracker = exports.WindowTracker = function WindowTracker(delegate) { + this.delegate = delegate; + this._loadingWindows = []; + for (window in windowIterator()) + this._regWindow(window); + gWindowWatcher.registerNotification(this); + require("unload").ensure(this); +}; + +WindowTracker.prototype = { + _regLoadingWindow: function _regLoadingWindow(window) { + this._loadingWindows.push(window); + window.addEventListener("load", this, true); + }, + + _unregLoadingWindow: function _unregLoadingWindow(window) { + var index = this._loadingWindows.indexOf(window); + + if (index != -1) { + this._loadingWindows.splice(index, 1); + window.removeEventListener("load", this, true); + } + }, + + _regWindow: function _regWindow(window) { + if (window.document.readyState == "complete") { + this._unregLoadingWindow(window); + this.delegate.onTrack(window); + } else + this._regLoadingWindow(window); + }, + + _unregWindow: function _unregWindow(window) { + if (window.document.readyState == "complete") + this.delegate.onUntrack(window); + else + this._unregLoadingWindow(window); + }, + + unload: function unload() { + gWindowWatcher.unregisterNotification(this); + for (window in windowIterator()) + this._unregWindow(window); + }, + + handleEvent: function handleEvent(event) { + if (event.type == "load" && event.target) { + var window = event.target.defaultView; + if (window) + this._regWindow(window); + } + }, + + observe: function observe(subject, topic, data) { + var window = subject.QueryInterface(Ci.nsIDOMWindow); + if (topic == "domwindowopened") + this._regWindow(window); + else + this._unregWindow(window); + } +}; + +errors.catchAndLogProps(WindowTracker.prototype, ["handleEvent", "observe"]); + +const WindowTrackerTrait = Trait.compose({ + _onTrack: Trait.required, + _onUntrack: Trait.required, + constructor: function WindowTrackerTrait() { + new WindowTracker({ + onTrack: this._onTrack.bind(this), + onUntrack: this._onUntrack.bind(this) + }); + } +}); +exports.WindowTrackerTrait = WindowTrackerTrait; + +var gDocsToClose = []; + +function onDocUnload(event) { + var index = gDocsToClose.indexOf(event.target); + if (index == -1) + throw new Error("internal error: unloading document not found"); + var document = gDocsToClose.splice(index, 1)[0]; + // Just in case, let's remove the event listener too. + document.defaultView.removeEventListener("unload", onDocUnload, false); +} + +onDocUnload = require("errors").catchAndLog(onDocUnload); + +exports.closeOnUnload = function closeOnUnload(window) { + window.addEventListener("unload", onDocUnload, false); + gDocsToClose.push(window.document); +}; + +exports.__defineGetter__("activeWindow", function() { + return Cc["@mozilla.org/appshell/window-mediator;1"] + .getService(Ci.nsIWindowMediator) + .getMostRecentWindow(null); +}); +exports.__defineSetter__("activeWindow", function(window) { + try { + window.focus(); + } + catch (e) { } +}); + +exports.__defineGetter__("activeBrowserWindow", function() { + return Cc["@mozilla.org/appshell/window-mediator;1"] + .getService(Ci.nsIWindowMediator) + .getMostRecentWindow("navigator:browser"); +}); + + +require("unload").when( + function() { + gDocsToClose.slice().forEach( + function(doc) { doc.defaultView.close(); }); + }); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/dom.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/dom.js new file mode 100644 index 00000000..bc132eae --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/dom.js @@ -0,0 +1,60 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +'use strict'; + +const { Trait } = require('traits'); + +const WindowDom = Trait.compose({ + _window: Trait.required, + get title() { + let window = this._window; + return window && window.document ? window.document.title : null + }, + close: function close() { + let window = this._window; + if (window) window.close(); + return this._public; + }, + activate: function activate() { + let window = this._window; + if (window) window.focus(); + return this._public; + } +}); +exports.WindowDom = WindowDom; + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/loader.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/loader.js new file mode 100644 index 00000000..41be2eaa --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/loader.js @@ -0,0 +1,151 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +const { Cc, Ci } = require('chrome'), + { setTimeout } = require("timer"), + { Trait } = require('traits'), + + WM = Cc['@mozilla.org/appshell/window-mediator;1']. + getService(Ci.nsIWindowMediator), + + URI_BROWSER = 'chrome://browser/content/browser.xul', + NAME = '_blank', + FEATURES = 'chrome,all,dialog=no', + PARAMS = [ URI_BROWSER, NAME, FEATURES ], + ON_LOAD = 'load', + ON_UNLOAD = 'unload', + STATE_LOADED = 'complete', + BROWSER = 'navigator:browser'; + +/** + * Trait provides private `_window` property and requires `_onLoad` property + * that will be called when `_window` is loaded. If `_window` property value + * is changed with already loaded window `_onLoad` still will be called. + */ +const WindowLoader = Trait.compose({ + /** + * Internal listener that is called when window is loaded. + * Please keep in mind that this trait will not handle exceptions that may + * be thrown by this method so method itself should take care of + * handling them. + * @param {nsIWindow} window + */ + _onLoad: Trait.required, + _tabOptions: Trait.required, + /** + * Internal listener that is called when `_window`'s DOM 'unload' event + * is dispatched. Please note that this trait will not handle exceptions that + * may be thrown by this method so method itself should take care of + * handling them. + */ + _onUnload: Trait.required, + _load: function _load() { + if (this.__window) return; + let params = PARAMS.slice() + params.push(this._tabOptions.map(function(options) options.url).join("|")) + let browser = WM.getMostRecentWindow(BROWSER); + this._window = browser.openDialog.apply(browser, params); + }, + /** + * Private window who's load event is being tracked. Once window is loaded + * `_onLoad` is called. + * @type {nsIWindow} + */ + get _window() this.__window, + set _window(window) { + let _window = this.__window; + if (!window) window = null; + if (window == _window) return; + if (_window) { + _window.removeEventListener(ON_UNLOAD, this.__unloadListener, false); + _window.removeEventListener(ON_LOAD, this.__loadListener, false); + } + if (!window) return; + window.addEventListener( + ON_UNLOAD, + this.__unloadListener || + (this.__unloadListener = this._unloadListener.bind(this)) + , + false + ); + this.__window = window; + // If window is not loaded yet setting up a listener. + if (STATE_LOADED != window.document.readyState) { + window.addEventListener( + ON_LOAD, + this.__loadListener || + (this.__loadListener = this._loadListener.bind(this)) + , + false + ); + } + else { // If window is loaded calling listener next turn of event loop. + this._onLoad(window) + } + return window; + }, + __window: null, + /** + * Internal method used for listening 'load' event on the `_window`. + * Method takes care of removing itself from 'load' event listeners once + * event is being handled. + */ + _loadListener: function _loadListener(event) { + let window = this._window; + if (!event.target || event.target.defaultView != window) return; + window.removeEventListener(ON_LOAD, this.__loadListener, false); + this._onLoad(window); + }, + __loadListener: null, + /** + * Internal method used for listening 'unload' event on the `_window`. + * Method takes care of removing itself from 'unload' event listeners once + * event is being handled. + */ + _unloadListener: function _unloadListener(event) { + let window = this._window; + if (!event.target + || event.target.defaultView != window + || STATE_LOADED != window.document.readyState + ) return; + window.removeEventListener(ON_UNLOAD, this.__unloadListener, false); + this._onUnload(window); + }, + __unloadListener: null +}); +exports.WindowLoader = WindowLoader; + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/tabs.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/tabs.js new file mode 100644 index 00000000..f0bc1e8a --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/windows/tabs.js @@ -0,0 +1,202 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is + * the Mozilla Foundation. + * Portions created by the Initial Developer are Copyright (C) 2010 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Irakli Gozalishvili (Original Author) + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ +"use strict"; + +const { Trait } = require("traits"); +const { List } = require("list"); +const { Tab, Options } = require("tabs/tab"); +const { EventEmitter } = require("events"); +const { EVENTS } = require("tabs/events"); + +const TAB_BROWSER = "tabbrowser"; + +/** + * This is a trait that is used in composition of window wrapper. Trait tracks + * tab related events of the wrapped window in order to keep truck of open + * tabs and maintain their wrappers. Every new tab is gets wrapped and jetpack + * type event is emitted. + */ +const WindowTabTracker = Trait.compose({ + /** + * Chrome window whose tabs are tracked. + */ + _window: Trait.required, + /** + * Function used to emit events. + */ + _emit: Trait.required, + _tabOptions: Trait.required, + /** + * Function to add event listeners. + */ + on: Trait.required, + /** + * Live array of the window tabContainers. + */ + get _tabContainers() + Array.slice(this._window.document.getElementsByTagName(TAB_BROWSER)) + .map(function(tabBrowser) tabBrowser.tabContainer), + /** + * Initializes tab tracker for a browser window. + */ + _initWindowTabTracker: function _initWindowTabTracker() { + this.tabs; + // Some XULRunner apps may have more than one tab browser. + for each (let tabContainer in this._tabContainers) { + let tabs = Array.slice(tabContainer.children); + // Emulating 'open' events for all open tabs. + for each (let tab in tabs) + this._onTabEvent(EVENTS.open, { target: tab }); + this._onTabEvent(EVENTS.activate, + { target: this._window.gBrowser.selectedTab }); + // Setting event listeners to track tab events. + for each (let type in EVENTS) { + if (!type.dom) continue; + tabContainer.addEventListener(type.dom, + this._onTabEvent.bind(this, type), + false); + } + } + }, + _destroyWindowTabTracker: function _destroyWindowTabTracker() { + for each (let tab in this.tabs) + this._emitEvent(EVENTS.close, tab); + this._tabs._clear(); + }, + /** + * Tab event router. Function is called on every tab related DOM event. + * For each event jetpack style event is emitted with a wrapped tab as + * an argument. + * @param {String} type + * Event type. + * @param {Event} event + */ + _onTabEvent: function _onTabEvent(type, event) { + let options = this._tabOptions.shift() || {}; + options.tab = event.target; + options.window = this._public; + var tab = Tab(options); + // Piping 'ready' events from open tabs to the window listeners. + if (type == EVENTS.open) + tab.on(EVENTS.ready.name, this._emitEvent.bind(this, EVENTS.ready)); + this._emitEvent(type, tab); + }, + _emitEvent: function _emitEvent(type, tab) { + // Notifies combined tab list that tab was added / removed. + tabs._emit(type.name, tab); + // Notifies contained tab list that window was added / removed. + this._tabs._emit(type.name, tab); + } +}); +exports.WindowTabTracker = WindowTabTracker; + +/** + * This trait is used to create live representation of open tab lists. Each + * window wrapper's tab list is represented by an object created from this + * trait. It is also used to represent list of all the open windows. Trait is + * composed out of `EventEmitter` in order to emit 'TabOpen', 'TabClose' events. + * **Please note** that objects created by this trait can't be exposed outside + * instead you should expose it's `_public` property, see comments in + * constructor for details. + */ +const TabList = List.resolve({ constructor: "_init" }).compose( + // This is ugly, but necessary. Will be removed by #596248 + EventEmitter.resolve({ toString: null }), + Trait.compose({ + on: Trait.required, + _emit: Trait.required, + constructor: function TabList(options) { + this._window = options.window; + this.on('error', this._onError = this._onError.bind(this)); + // Add new items to the list + this.on(EVENTS.open.name, this._add.bind(this)); + // Remove closed items from the list + this.on(EVENTS.close.name, this._remove.bind(this)); + // Emit events for closed items + this.on(EVENTS.activate.name, this._onActivate.bind(this)); + // Initialize list. + this._init(); + // This list is not going to emit any events, object holding this list + // will do it instead, to make that possible we return a private API. + return this; + }, + _onActivate: function _onActivate(value) { + this._emit(EVENTS.deactivate.name, this._activeTab); + this._activeTab = value; + }, + _onError: function _onError(error) { + if (1 <= this._listeners('error').length) + console.exception(error); + }, + get activeTab() this._activeTab, + _activeTab: null, + + open: function open(options) { + options = Options(options); + this._window._tabOptions.push(options); + let tab = this._window._window.gBrowser.addTab(options.url); + if (!options.inBackground) + this._window._window.gBrowser.selectedTab = tab; + } + // This is ugly, but necessary. Will be removed by #596248 + }).resolve({ toString: null }) +); + +/** + * Combined list of all open tabs on all the windows. + * type {TabList} + */ +var tabs = TabList({ window: null }); +exports.tabs = tabs._public; + +/** + * Trait is a part of composition that represents window wrapper. This trait is + * composed out of `WindowTabTracker` that allows it to keep track of open tabs + * on the window being wrapped. + */ +const WindowTabs = Trait.compose( + WindowTabTracker, + Trait.compose({ + _window: Trait.required, + /** + * List of tabs + */ + get tabs() (this._tabs || (this._tabs = TabList({ window: this })))._public, + _tabs: null, + }) +); +exports.WindowTabs = WindowTabs; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xhr.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xhr.js new file mode 100644 index 00000000..2af6c958 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xhr.js @@ -0,0 +1,179 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci} = require("chrome"); + +// ## Implementation Notes ## +// +// Making `XMLHttpRequest` objects available to Jetpack code involves a +// few key principles universal to all low-level module implementations: +// +// * **Unloadability**. A Jetpack-based extension using this module can be +// asked to unload itself at any time, e.g. because the user decides to +// uninstall or disable the extension. This means we need to keep track of +// all in-progress reqests and abort them on unload. +// +// * **Developer-Ergonomic Tracebacks**. Whenever an exception is raised +// by a Jetpack-based extension, we want it to be logged in a +// place that is specific to that extension--so that a developer +// can distinguish it from an error on a web page or in another +// extension, for instance. We also want it to be logged with a +// full stack traceback, which the Mozilla platform doesn't usually +// do. +// +// Because of this, we don't actually want to give the Mozilla +// platform's "real" XHR implementation to clients, but instead provide +// a simple wrapper that trivially delegates to the implementation in +// all cases except where callbacks are involved: whenever Mozilla +// platform code calls into the extension, such as during the XHR's +// `onreadystatechange` callback, we want to wrap the client's callback +// in a try-catch clause that traps any exceptions raised by the +// callback and logs them via console.exception() instead of allowing +// them to propagate back into Mozilla platform code. + +// This is a private list of all active requests, so we know what to +// abort if we're asked to unload. +var requests = []; + +// Events on XHRs that we should listen for, so we know when to remove +// a request from our private list. +const TERMINATE_EVENTS = ["load", "error", "abort"]; + +// Read-only properties of XMLHttpRequest objects that we want to +// directly delegate to. +const READ_ONLY_PROPS = ["readyState", "responseText", "responseXML", + "status", "statusText"]; + +// Methods of XMLHttpRequest that we want to directly delegate to. +const DELEGATED_METHODS = ["abort", "getAllResponseHeaders", + "getResponseHeader", "overrideMimeType", + "send", "sendAsBinary", "setRequestHeader", + "open"]; + +var getRequestCount = exports.getRequestCount = function getRequestCount() { + return requests.length; +}; + +var XMLHttpRequest = exports.XMLHttpRequest = function XMLHttpRequest() { + var req = Cc["@mozilla.org/xmlextras/xmlhttprequest;1"] + .createInstance(Ci.nsIXMLHttpRequest); + // For the sake of simplicity, don't tie this request to any UI. + req.mozBackgroundRequest = true; + + memory.track(req, "XMLHttpRequest"); + + this._req = req; + this._orsc = null; + + requests.push(this); + + var self = this; + + this._boundCleanup = function _boundCleanup() { + self._cleanup(); + }; + + TERMINATE_EVENTS.forEach( + function(name) { + self._req.addEventListener(name, self._boundCleanup, false); + }); +}; + +XMLHttpRequest.prototype = { + _cleanup: function _cleanup() { + this.onreadystatechange = null; + var index = requests.indexOf(this); + if (index != -1) { + var self = this; + TERMINATE_EVENTS.forEach( + function(name) { + self._req.removeEventListener(name, self._boundCleanup, false); + }); + requests.splice(index, 1); + } + }, + _unload: function _unload() { + this._req.abort(); + this._cleanup(); + }, + addEventListener: function addEventListener() { + throw new Error("not implemented"); + }, + removeEventListener: function removeEventListener() { + throw new Error("not implemented"); + }, + set upload(newValue) { + throw new Error("not implemented"); + }, + get onreadystatechange() { + return this._orsc; + }, + set onreadystatechange(cb) { + this._orsc = cb; + if (cb) { + var self = this; + this._req.onreadystatechange = function() { + try { + self._orsc.apply(self, arguments); + } catch (e) { + console.exception(e); + } + }; + } else + this._req.onreadystatechange = null; + } +}; + +READ_ONLY_PROPS.forEach( + function(name) { + XMLHttpRequest.prototype.__defineGetter__( + name, + function() { + return this._req[name]; + }); + }); + +DELEGATED_METHODS.forEach( + function(name) { + XMLHttpRequest.prototype[name] = function() { + return this._req[name].apply(this._req, arguments); + }; + }); + +require("unload").when( + function() { + requests.slice().forEach(function(request) { request._unload(); }); + }); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js new file mode 100644 index 00000000..8f05a54c --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xpcom.js @@ -0,0 +1,217 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * Drew Willcoxon + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc,Ci,Cm,Cr,Cu} = require("chrome"); + +var jsm = {}; +Cu.import("resource://gre/modules/XPCOMUtils.jsm", jsm); +var utils = exports.utils = jsm.XPCOMUtils; + +Cm.QueryInterface(Ci.nsIComponentRegistrar); + +var factories = []; + +function Factory(options) { + memory.track(this); + + this.wrappedJSObject = this; + this.create = options.create; + this.uuid = options.uuid; + this.name = options.name; + this.contractID = options.contractID; + + Cm.registerFactory(this.uuid, + this.name, + this.contractID, + this); + + var self = this; + + factories.push(this); +} + +Factory.prototype = { + createInstance: function(outer, iid) { + try { + if (outer) + throw Cr.NS_ERROR_NO_AGGREGATION; + return (new this.create()).QueryInterface(iid); + } catch (e) { + console.exception(e); + if (e instanceof Ci.nsIException) + throw e; + else + throw Cr.NS_ERROR_FAILURE; + } + }, + unregister: function() { + var index = factories.indexOf(this); + if (index == -1) + throw new Error("factory already unregistered"); + + var self = this; + + factories.splice(index, 1); + Cm.unregisterFactory(this.uuid, this); + }, + QueryInterface: utils.generateQI([Ci.nsIFactory]) +}; + +var makeUuid = exports.makeUuid = function makeUuid() { + var uuidGenerator = Cc["@mozilla.org/uuid-generator;1"] + .getService(Ci.nsIUUIDGenerator); + var uuid = uuidGenerator.generateUUID(); + return uuid; +}; + +var autoRegister = exports.autoRegister = function autoRegister(path) { + // TODO: This assumes that the url points to a directory + // that contains subdirectories corresponding to OS/ABI and then + // further subdirectories corresponding to Gecko platform version. + // we should probably either behave intelligently here or allow + // the caller to pass-in more options if e.g. there aren't + // Gecko-specific binaries for a component (which will be the case + // if only frozen interfaces are used). + + var appInfo = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULAppInfo); + var runtime = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULRuntime); + + var osDirName = runtime.OS + "_" + runtime.XPCOMABI; + var platformVersion = appInfo.platformVersion.substring(0, 5); + + var file = Cc['@mozilla.org/file/local;1'] + .createInstance(Ci.nsILocalFile); + file.initWithPath(path); + file.append(osDirName); + file.append(platformVersion); + + if (!(file.exists() && file.isDirectory())) + throw new Error("component not available for OS/ABI " + + osDirName + " and platform " + platformVersion); + + Cm.QueryInterface(Ci.nsIComponentRegistrar); + Cm.autoRegister(file); +}; + +var register = exports.register = function register(options) { + options = {__proto__: options}; + if (!options.uuid) + options.uuid = makeUuid(); + return new Factory(options); +}; + +var getClass = exports.getClass = function getClass(contractID, iid) { + if (!iid) + iid = Ci.nsISupports; + return Cm.getClassObjectByContractID(contractID, iid); +}; + +/** + * Returns an Error instance that is a more descriptive version of the raw XPCOM + * errOrResult. opts is used by some exceptions to include helpful info in + * their messages such as a filename, and as such its properties depend on the + * type of exception being thrown. opts need not be defined for errors that + * don't use it. See below for a list of supported options. + * + * If there is no friendly version of errOrResult, then if it's an nsIException, + * an Error whose message is errOrResult's message is returned; if it's a + * result, an Error with a simple numeric message is returned; and if it's an + * Error, it itself is returned. + * + * @param errOrResult + * An nsIException, Error, or one of the Components.results. + * @param opts + * An optional options object. The following properies are supported: + * @prop filename + * The name of the file being accessed when the exception was + * thrown, if any. + * @return An Error instance. + */ +var friendlyError = exports.friendlyError = + function friendlyError(errOrResult, opts) { + opts = opts || {}; + var result = errOrResult instanceof Ci.nsIException ? + errOrResult.result : + errOrResult; + + // Common options to be used below. + var filename = opts.filename || "(filename unknown)"; + + // If you add an error message, update testFriendlyError in test-xpcom.js. + // If the message includes options, also update this method's comment. + switch (result) { + case Cr.NS_BASE_STREAM_CLOSED: + return new Error("The stream is closed and cannot be read or written."); + case Cr.NS_ERROR_FILE_IS_DIRECTORY: + return new Error("The stream was opened on a directory, which cannot " + + "be read or written: " + filename); + case Cr.NS_ERROR_FILE_NOT_FOUND: + return new Error("path does not exist: " + filename); + } + + // errOrResult should be an nsIException, ... + if (errOrResult instanceof Ci.nsIException) + return new Error("XPCOM error: " + errOrResult.message); + + // ... one of Components.results, a number, ... + if (typeof(errOrResult) === "number") { + + // Look up the result's name to make the message a little nicer. + for (let [name, val] in Iterator(Cr)) { + if (val === errOrResult) { + return new Error("XPCOM error " + name + + " (0x" + errOrResult.toString(16) + ")"); + } + } + } + + // ... or an Error. + if (errOrResult.constructor.name === "Error") + return errOrResult; + + // We've been called wrong if we get here. + return new Error("Unknown error: " + errOrResult); + }; + +require("unload").when( + function() { + var copy = factories.slice(); + copy.reverse(); + copy.forEach(function(factory) { factory.unregister(); }); + }); diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js new file mode 100644 index 00000000..4259370d --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-api-utils-lib/xul-app.js @@ -0,0 +1,91 @@ +/* ***** BEGIN LICENSE BLOCK ***** + * Version: MPL 1.1/GPL 2.0/LGPL 2.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is Jetpack. + * + * The Initial Developer of the Original Code is Mozilla. + * Portions created by the Initial Developer are Copyright (C) 2007 + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * Atul Varma + * + * Alternatively, the contents of this file may be used under the terms of + * either the GNU General Public License Version 2 or later (the "GPL"), or + * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"), + * in which case the provisions of the GPL or the LGPL are applicable instead + * of those above. If you wish to allow use of your version of this file only + * under the terms of either the GPL or the LGPL, and not to allow others to + * use your version of this file under the terms of the MPL, indicate your + * decision by deleting the provisions above and replace them with the notice + * and other provisions required by the GPL or the LGPL. If you do not delete + * the provisions above, a recipient may use your version of this file under + * the terms of any one of the MPL, the GPL or the LGPL. + * + * ***** END LICENSE BLOCK ***** */ + +const {Cc, Ci} = require("chrome"); + +var appInfo = Cc["@mozilla.org/xre/app-info;1"] + .getService(Ci.nsIXULAppInfo); + +var ID = exports.ID = appInfo.ID; +var name = exports.name = appInfo.name; +var version = exports.version = appInfo.version; +var platformVersion = exports.platformVersion = appInfo.platformVersion; + +// The following mapping of application names to GUIDs was taken from: +// +// https://addons.mozilla.org/en-US/firefox/pages/appversions +// +// Using the GUID instead of the app's name is preferable because sometimes +// re-branded versions of a product have different names: for instance, +// Firefox, Minefield, Iceweasel, and Shiretoko all have the same +// GUID. + +var ids = exports.ids = { + Firefox: "{ec8030f7-c20a-464f-9b0e-13a3a9e97384}", + Mozilla: "{86c18b42-e466-45a9-ae7a-9b95ba6f5640}", + Sunbird: "{718e30fb-e89b-41dd-9da7-e25a45638b28}", + SeaMonkey: "{92650c4d-4b8e-4d2a-b7eb-24ecf4f6b63a}", + Fennec: "{a23983c0-fd0e-11dc-95ff-0800200c9a66}", + Thunderbird: "{3550f703-e582-4d05-9a08-453d09bdfdc6}" +}; + +var is = exports.is = function is(name) { + if (!(name in ids)) + throw new Error("Unkown Mozilla Application: " + name); + return ID == ids[name]; +}; + +var isOneOf = exports.isOneOf = function isOneOf(names) { + for (var i = 0; i < names.length; i++) + if (is(names[i])) + return true; + return false; +}; + +/** + * Use this to check whether the given version (e.g. xulApp.platformVersion) + * is in the given range. Versions must be in version comparator-compatible + * format. See MDC for details: + * https://developer.mozilla.org/en/XPCOM_Interface_Reference/nsIVersionComparator + */ +var versionInRange = exports.versionInRange = +function versionInRange(version, lowInclusive, highExclusive) { + var vc = Cc["@mozilla.org/xpcom/version-comparator;1"] + .getService(Ci.nsIVersionComparator); + return (vc.compare(version, lowInclusive) >= 0) && + (vc.compare(version, highExclusive) < 0); +} + diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/contentScripts/keworker.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/contentScripts/keworker.js new file mode 100644 index 00000000..a0d712c8 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/contentScripts/keworker.js @@ -0,0 +1,26 @@ +var text = ""; +var cleantext = ""; +var paragraphs = document.getElementsByTagName('p'); +var open = '<'; +var close = '>'; +for(var i=0; i + + \ No newline at end of file diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_Germany.svg b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_Germany.svg new file mode 100644 index 00000000..d466e44a --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_Germany.svg @@ -0,0 +1,8 @@ + + + + Flag of Germany + + + + \ No newline at end of file diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_Spain.svg b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_Spain.svg new file mode 100644 index 00000000..872f198b --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_Spain.svg @@ -0,0 +1,631 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_the_United_Kingdom.svg b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_the_United_Kingdom.svg new file mode 100644 index 00000000..63b1cb3d --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/Flag_of_the_United_Kingdom.svg @@ -0,0 +1,10 @@ + + + + + + + + + + \ No newline at end of file diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/de.png b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/de.png new file mode 100644 index 0000000000000000000000000000000000000000..75a3cf30fa0429d83911bc5750269270625b4fd2 GIT binary patch literal 760 zcmeAS@N?(olHy`uVBq!ia0y~yVAKJ!w{WllNj-bP_dtrJ*vT`50|;t3QaXTq&H|6f zVxX`(2s7UFmu&zFN|v}rlmzFem6RtIr81P4m+NKbWfvzW7NqLs7p2dBXCuYHz*Oq# z;uumf=j}B|-UbH&mV>Pi;-&a56h-W~zjU$|>*rTzOpUV{nBHAxW+>wno1hrs(3Zd` z*~FT{F|;_xKF^I~*l_YNlMxH|2>~4i=M4=!2ZtQzan$=Ymz5dHDu!w_KoifOn2BtH UDF$aA08=T0r>mdKI;Vst00~3U!2kdN literal 0 HcmV?d00001 diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/en.png b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/en.png new file mode 100644 index 0000000000000000000000000000000000000000..ef13c9f6d879f9e92d9d18b4bd8af4c80520c95e GIT binary patch literal 2467 zcmbVOd03L^7H8&Se#)TYnv}UvIwE4(wZ*VT)Xb$35fv31a>6F9BwVmiXGT#=ODp>_ zrzXoy4Y_RPMNERru++6CK0RRG zaLqM4-xW;xLwnj5=+BxJ6#rN0+wISr2`DLvy@IK8f~NE0^ts*|pAVY$>7HoH>|d_%@T|+TS zyyDV-AC9TZ7`hm0w<)9V#rWX){P?;Kb| z1m@!9w`jY{C-XEZzK~EBgT~CY;ECxD%)GmztwNbC8uPf=hapXoOP5{13T4~S7LECoN!$Q@Uu` zwn+Q^Vu=)9LIgTsbJ^njR?oWl!PiG^;) zD;F+dQN=|!NK-G(&8sP9q=f<_jmMpH6#Za!r-13S~bBw^a($G`3L9lky z*M0C*Fz#5Hpy8HL^bE4+#29!^%Wj&YbejSz&KfSRYTAsL%9K3&neD3L&;fIip~y2Z zKX?L*2*5z#Jp@;p6TMb4i?|iPU$cwZmhBMYwy`-tuBxawccN8aLTZmcF;wnS!U~a? zNSBfV6o(5&w0F|=H4PTKOSa>xCeNPw<>*NHP9ylRHPI^#gyh+)3Xs3>leDiB(Fukj zIPzaBSZLXPq52s}dIlm;Q&`OQDx_6-`-zhdL#-|Jgr1d4_C+VvxbCdh_ ztUlN>rYK&;Al4%Z95%60dJ5GoONmx{5bgB*Vm3~?b3X(ZZAARr*9@o1A$ZJ^*zb(s z@MidX1TQA`lmDCF*yl&Z@R4Ah+Lh^Y#d*iRyM*EocGUiL4E5iXksF6BbFsd7(66L6#MEExdD<;wTRxf2n29RcVJ=oG^~BFtjhFl z)@I4_Qd(snNJZ!S1XHa;)5injJ0_m?+{qCVjh=&mtA`sG71P9S4S?J0)NK&WN6r#( z#xozxNmRJ>BI#jOUjBR|8l%s2{D?x)tdw8=x#%-%^H~2-bX|wtPnbs4=OsVK^8fB_ z4nN7UJpi=~$yQ%CSpROMw8@0Gt)(=YiRyOvA8UH+K3(E#+g$JUKCWx4+tr#78_w`_ z4Lf!B!XQRJaQ(-!(TN4^fo_|}XOG?N>^&Kgn$m`Opqk6t<~7OJkH)O$k9zQiJI-Iu z91;^cGeGOy`JdLA)ufNOmYNyyo7+219jJNieeF^|#jB(7awsw#J>sCUidv&|Vl)$& zbGYi2$4#TGMX_DkKbab92DBxlYrB8@6#cR)?M+wSg!1fTq+FhQg#D8e{-aP9-v*A( z7OUw{7tD6`92?ga!jEtQc@bu9f6Fr==@B0)@55F1f$C`gAfmg19!4(XDUKUii#+G3 zV)|Fey=&#xnF5>#unB_2+&V14k$z$xgy4K`9R}djaT{(l&U~}CC+@l>5sr{QJ5*^@ zm$N_0dVp+BexT!7kf@x^SXjLZRJm=b4%`Nz`tTAWxDA#%&vPnpTR@j_V-&G%RUC@Y ztsYcx1YcsQ^ghU~IMr;mRes!5qrcf8nESFI7*{n9l^QrY7GJILhu~Go~&8}w_=)mqx;qQH){c@S0T5;Sp~WkXcj&Q21dM_ z!N>sD*_?>9H$|wO4(|<&W@3QRQ35OR3^&pQ7{yD)Fjnt)+$XBpfvH0#)2pmPZrcw! z{9=%%`hWSvZ0k81H!dzRAu$K-7GGH?y9JJ76BIQ=$98rplRO!N*3$3J`%0t)rhbb%ivTjK50HVc7P2#Zy>+o0L P4;3mX;9LJ{Dm(Yz5kj7!QBZE92VQf32wnXxIDU_@zPf zlv4p=y_7&K>(4J^Y&T^?Pb4Jt*#E4^&h|NXFO!sB3I<-fuC`vj79KW8zP`TP4la(K zRu*nH+^!yWS^p%dkdPRVRNl*iK4qV*+NGP$1)ZLsx|F6J1Sw`t*@KA6n6;xclFMB} zUrD%+YIw|4U;Zs&6X{qu*J!XB0D3$wy35;jLk=U^cuKJ@H3i#QSve3)LEr+#6X>&P=)Y)-~VJ7sfhMoD=THLOj_|D#JG_f-G-I{F4Ug?2{5`VMu~~Uj1W^hEkVYUaPMUCz7~R zBa(|bQacwF$hUqav2Na5t39L8EGTH3_$zIL6dHc$6v4Kx6{8H+mj{qQhGj$ zkEPW5lISdXXypqFdpH@;>gj**f5R>Lbm(F`c4!{lOSl>#AOAYPmCO=3Dz=;~m%^ks zX1DV*V@U57`R4~uY0Op>$%Z3;)@UFdfo|>lPs3UFB>)=Dr1Xe~u zXIL{>G5H?YdOE5K{pf!%UC>OUMkX6FITTpnbr}Cw2=+T z8@37|VkT^eZ7~Fm@?|u1`NJO)aWXNw-|en?asV1dzCZo)B9pu&J3d(M(hYOGMbs~h zuctA<&{@K~Q*+lFvhN06FmMe5cCIXTL^sHE7b6$_873y*2D9GWDxX{ujnmv7>b7a@ z1mUOhQ!D9~RjrJ{=ps}l1_%8qFxDXCZ}O~k#A*hWy@_U#ASpfGUuJjL3d(D5IQD5G zGrRCVh}DK4+5Pql?j&U7M#8RY_`%NcxQ(58#IXO?nVL$EV%eFudEMNj^9v|Xu}%E_ zW*dg$rD?qLxpn~Wdj!k>He+5iULMhR=OKX+f99UxQ#;{Q0$( z_3}{KUb~7Pd5M>+r-<@+4wx6kgiwwtV-ytja*x;aR`wkkxVRkluliNsx}gu5ENTk| zf*}l=Odpf5vQ9hl=4fu##iPYVCN94qKAl_0%w}8#TYrxXW=SgX${HGG0*?SjTi0Mv z=BNM&U+3ZH?tON&@Sn438ozmL$hIt#yTsK-?2Ze3>ti8EB>uS5{a)9!`xRE&N zaF+DTTlY49(%jn>LcLDl1bE27(GY#E`%t7TzSlTs&P2QO=pmR=&V*rkFF0Ys^f>N} zW8k*vd+%p=Tpd`aPVdzGwH{B0QXpv^IVyZ)?zk5Zx z>zF+Hlj9`QZ^qBsF0Y&#C_>&0J_P|1CQ<}yZ}c*KZzd}<%ZOq&TX08%=@*_XGVc_~ zR@!Jd1|C^JS@O=5AO*%2{xQ;TJODHnYXqrBx2jf0F2jP6`>jLA@E3z~##Qlp@nvDm5<*+nz_G9=rY(tnlKu@l3m9EQ~Z>nZ+8}|VA+#twUXXo;|Ale6z z^?|XOW5B*_u-We6;Zmdl_Jv-CF>*k~{I{kFdGK9yPXUnjLwpj!a-(!QOWpd5Sq)U| z4ibxR7gefSVwEX2XYms3RAaT=gmRPG0ICo9g^KezHnOHC<2cGgHGT{;N>o^OlFFH8 z_LKENmYUNVtl}v7mE2SUgh+I%H*C+}h=|E5f-ik~-ERwg#FN6*+ zeh#mD9SL^bs`Sv>67EJ4Rd6G15!6ycpTX!oO#*UQvyr-W(?=LYMSwxP>`{!(;VAYP z)|cFhM$A&xTSu2xJmWfR8@!d>n|G~jiGd+Jnogl#30w?4c6Ug(A zn-7oaJj>On?PbZ0-z3n;(Ee=FGCP>g3EyyfRn*^udta7EX?c@PV|LV;RJt0aP6Gbd zX`3B(#X&ZDz}BG8HciQr#Cui_&|h_$7IGJQn|6I(^h7E7k$Wd!yHBY`GE(Ny>IWf< zPTK257vi7It<}9YDk}#u;0~;9mBm#&p3~4FmNM?|3aavaf|N8o+_E~oC;-1tcV^7T zSEQfW@Z|30ytvhB&#nP?uCxQ9)^2;IWGDItr9tCd5}@2W|MZdof!T>_3?W5HXkN}L z#%;X3&7z{VY7^VSo8L4of}cTPH6HwDN^(|Dj?|Kds-i*bHnM?)Bx;Glr_*Qy52Zw7 zY2L?L$U)UQa_{!!9KCH~=b+1iA`eI79SDCJV@$}9Y&=|y%kD-B;NCGbOJja%n=tEW zVF?zOs8OEgov`ql-kChvra9JzT6j`Y$Inut&lld}yRKz+o9*(7i^kjFH#`x>!zCg) zQ^vn1T5&9*yQ!o1YP-b&q)BOLQDn)Ld}9^g@tHJ!R%10k2ersKUh+x@QGjFi6Ab4~ zPP4WBTK>&qNg6Ap&VkUHOwplF zsb-HPLD$0K0H80tuCDlNnwGh}Y#UMCw+rE19%cGD!e!}>xs4mcJ({_BVW5`u>z`KH z+roVe@b#o&>A6bQW-$v3O;C_b zB``u9Ia5*7^iV~5rLQ6tbY-M@ugD?>^3bsK(aHvGyRdl6pkLX~d#R@u3~;uubLwJHiHjsz){S@JyPpfQgHP^Vn#~;UMhq_r%s@Hf#5x z+t$+#)5*yLPSpRTVTo)XO8Nj6q5-!<+hzsrj?BG5sJO=`mIIeZnttQPWU{vLIX zGm+8h?-uFQEBAq}XD~wY5(D-oelIq%=YwRRX$~G$q`YV0qB?eAoDo5mDCes@J`6{nLDheh8 z7O8l)t63<9X^kr2NI*R=)g9RKfHR^2!j4ZHEuW;MV|kqGEL-}I%pRoW*ZnfuE6EDz zT!0l7a>bn>-IYALlBeBUdhZ5BBYYqP{Sv$}CG5L6>4^z(BaR2$tc^M|bJrvBHs^5~nUQ<4 z-mN|FQE~%FD>(97=pn+RWih5X#X(d+t0l_??{mxt&PSN@@hUW88PDo{knBw&eUH1T zN41K(1)iGg2fTOh_-dW0HByZTJM&+dL#>=qx}+5Yk$U)@-K$#VJ_MI>@T|JitZWta zi+Q8NyPBP8{DYa}cDZaeBcqAR^9M42lv5Nm{YtcE97#1o-#)YMxmy-j^zqUTvAK_8 zFCiq)7Q~*2pzM{6R@_MWXJ+B+ikhs;D~PgkgIMH6Fa#C3hs#SB-jqAaMb+_*W^45Q z7^#e+3#K~kg@(Kt0^p%XL1okpUFr7D2muoRdPP!y6Dp8w6@I0f7mRKXP`3$X2yjo*i&Q4V2moZAu>y3I3*O@~ucO z=t8Q-YAsU;ik_CEn$*`4jCFm+WSG%}vk0wDZYD~2TW;Q~xz^(XA^NA5?0}W~iHn6SRrgl-}q1(^oqMis%Mv=j1S$7HBFbPV@8D52tE!pscDFi%Pc#L zTIzvQ{939Rvs8am>%Gc}IqO_j`=hfzVU7L$$RwxS@_9`~@d)owZ(L%R<|yxc>aq_| zVQeybg8Xoall~h+XrzDWaf2vaKW%r8|Nd^9&98%r%;3Gt+?8 zK-+%+631*4x_-9qVb`s0zqg+&dPzSj|?NZ(ZmF0wRo0J%gys1%qAfO zBMPnf>*_P_me{z7J`zyD*dF$A>JbYib!?!sgZ(C9pe!`iNkrXoS4y|86u?1I9@u^Oi&rn*)I_CA@Mpe9$K;GDqJ_<1;GqN+a=|r;!2W9 z+{gmMj)f+VoFF;U@%=N#-m`Wj84J)ayNB+q#GyE}0-l1f8zKT=0WG+D*)H>#KkisC zZt;uMfLh26`LDaN5awiHXS?QlN6@b`_;Yw?M|RqD&ehx-#GZ(G8C7PXwz9^$?==v~ z)(p>L)_5_QN;IFHTQND7*sZP<6zB=Dw-H|QE@rjSXqCIgP4f-`clVS3-HhIvc3YB; z+)AL2GIuPW=%?eysu@bUb3l_Q=6Cu2t-`F^Kv$x-@3pA@J8vryTV(Z44QZ!jm9UTH zB%rjifFGB?N}0z%N{OG6HM$65q8TWD_MVF*Yb0#K)7l{M=_4)xT!OMjY7D$gU{i^< z%@PP7@74P6G-qm&!lrSS52j-c>j*ND?>si(=FHXt@%}-}rqnvm5g!v%i~e*~->P?w zlELa?aOp?g9$jpR003%;{Ya%d?b3fW_{dH996U}iEE&5LT3!o{ns(rV!RtAhx;8T1 zcnLLho`K>x)E{P4f*X$0Pqx1?#VQlMMrXDnd>eN`;ObIfkBJz24d-8mGhH`*MLI z#V_9q9B9T*FQoPHlYTS;nphV2+vH|F+kd~yw4%;(rG*qUhCD1f^K=YO-sGU&<-V4* z*Im#pzYr38a>if*IY5$BwK` zFjsOrJpE3$12QOLUl|%~++bdm2HKkakO<`~CK4v$FHz&q-R%X3poKOB;NZr5z6B?( z2%)e)ek2)7u9+zG`3l6mk1jpYGC-iH8boD+_tNvZAxm`tXz8I#fM)U-$8P(uBVDq;5;0dw;6PlO7ZG>4(P zO_W|p3RsxCzL|4c3!>O?53hhUi@;W5%r_IzZH03JDIfZ~8F1+&$UeT25j%X|QWq8G z;y#}8!XGyt``sOLPR(tcRGIE^X!th-vb%`X#Pue4UMfvfMnhgvp6n2^&@yzalrm3m3(i3pEbQ6aBujIJ9DJp;o`)C zcN$5z-3_DE5JZPX*Rk8*>RA%>Y=6rnSp1j{W|i`bDrQ^aaf<*RWy|jJG-}?*F36c+ zrFomnI@pZedeTy5LYyS4_1Uu2`Oh2d%2&i>In4mkf6B%s2+An(!uRAI4nLBNT89z_ z^ZQ3@Whk%~6Tf*sv`iM(rUMW5VR`rdT;SVV-hr!cSAB~aX1!tKu7#HM5-myM&N2aQ z5wI#r*DqWJ!=gxCgVElS*D;;m{X3QEd7CA@Rx0gnph7X!*LH;37TbHB?`9t9OM`EY ztr88roIm%C@!zPL_;cTPWdc1slB)BhqpoL4?SXWZI4L-Wf)i361EW40%lCk)5C7`V zUGb>IN&BVE-FHyMd^$>WZ%!zrkkh~+hKG$G;Cs?W_oQnk_Liri6+NOzUw(AN7eYC? z1ETuojBge9_WW+&(Z30i@Vul(#wxiSU77Ojw>fZ>p5C0F-Kcj^Ow`gO>_io+aW%J` zvBftHp&f(&3EG_?e6@x0^6xZUa3XQAb|p0{BCL}ueG^7Bls^=XS!$o<2^!nx%-c86 zKH<;L;AB@P&OT<*UjzPbOI|smFD>DmIIN?;G^!B%n=c0TFUb$FNvyA|XL#u(0$ko}y9*WJUZHLI3?#jGAr?Qxwy;y$|MF zeQA_O>3Ab)yq-f#DQcfDPwELc2g0s-D39+Azji%^Y$5je|AJG7DmkEg3qI3}pD=t! zfZB%G_oS>w9-RC9(0^Uq4-54&*2C2npLCd&6C++}n7{L!@cfhU&vwyOXZ_!XYeU(? zBX*!OYsGrENK2@;o%Z4h+s!wY&8%sJZ3anuyaOsuzF$f2K!;>E!BY_H;Str8lS5?S zVm;RBazeYKh^yrGSLoctTnj0d=K4=In1Z_@=KPDx;`(I#-A(f=!u@oq%RJz1|8f)O z@uIxd_RXtAU*sK5Hjy!?zyM-FPLj7ZWiw~p;wW76T=6*t7wE&6|1;m;o;gnvA&QKC zV^7vl68Iwz{>|@=I-&$uF-Ku5z&%{;(jF|lB!cqZRa5s^Sou-ZV|W4|eG}3?lJV=* z^Gf={6y<21s8Q9T3dx(9Lzh7RY;gwNc0JE_4l~Y9Uzu^uF3s6|2XJe6sVitVkaJM16lvS~V7! zkj2(Ky+z_@JXUunU|9dG7naNeUg=rbeTQrnt>U7K)E9cOp3c(1{oecoQK_5%8>6XN z<-WWJqR0CizPp}@p^gixgjitIK{6%m;}BshyG}8UtH@RHWV${ zH%D)`79*ot^@~RIVm7uh5iyg8zgm2OSWnt{|OJ*cGY=OQ;2@9xNEFwsw;}l=Wd;Y%-10n#RG7B&E;X9tBBp$k{~{-V|^?e$(~ zP6zf9=jDks(F~8hfjo+DyJBLubDtXv{P_jzKEATJ`M79BrC6l00g=3=4UPw3vK0|S z>qD1zdR6S%rODZ9@}tJN%>^}zcG?^r+V31LRxy_z9(lXtf%lx02i)9vFILT_;sP2_ z^w$@Cau!FV@E#FgISJMaZbTyabkH)KVcIy=Qfa@yl8!J$6RFA9UqXjbE(i#K*jXTL^>m08?GVONi9JLzOx+?VkSu;j)UpgT9JQV0C< ziq8>)+l>FohJbbdraiZ-j}fIMj)>RxSU`8+y1%ZjmbkR`JRrwn$t7EYT+sa(ofo0l zOtPQgm8Y;noU&MGkNN-Ltv8tPN>@q;O`v9YcO`RJ+Q2ZfY z8qp{Sdauh`U2NWHU?5Mmlpxzk6}Q#xX~yVvW0K{#Feq-YHSJ-zP`g%;W8>8RZ|O^~ zcxF#*laS;4fw8ygsNye*t9M18taP%ZSMz{72565s$5WCW?8&`^9rLw`R9 zTPc^6e!TEGKJEz?5&)G7d%}YEn$YNkq>(=h=DUTEfJCP5Wgz@13ywVFLt0TnpUgug zs_8Or1O$d$6ontYST&Qz2`8eKFJ3viV!PL=nA6S+;r4A|KxVEwzu2m&4XH0I>?|WQ zc>mYodM<^Kij1FU!{SKCDhY=&w9J$aQ57(&tOX%*d|&q}qNYBus+;!~)E_EJ`WA5i9XS z4?p|)ocXkvdPgHKKOD=|rF%u2bCz1Uv1oqeS=M#|D7otGRPxd)!oP|18I{$QfoL!8 zmM$Iyz$52>L{oWc1u8`|vU|5W3`9tE(0SlPhp%etI3?Q;{x0yq`j~_`^X+@L;0CB4 z-Q4a@I^pj!*Pre^cHh{^h#4T~e&Xy`3Wnn#0;NB6KI&P@_(5Ru?)5bou_1yAh&IkX zApKBjqEW1D)c&$ySf5|5`Ge!m-U-0tkpRw`Zd$TVyZXlr}b(isCIqhZr z2SAMs9QAOE@Pl+-ZqR*ttFKI7g!IJ<3PKz}(V$-FI8(-lS+vF^`R%orMrsdG#{TQN z5uj2f@5^$Np?Id|v9SQxJ{5nN2ThlPzA325Yqhz^T%uUj*AleXme^xRa7(xq2(3b` zwC~vpxs~GA%TCdt9PX_xmwB(rp=`>j_6!}bzY{zG<4Y)cb<`Heo0%a5^Ew|FJMxam zZPTG5>hNBhNagRsxwe)X(cz;HS9Vx^PA*yG+XL(V-&W|VY##?s3!kY8rbH!G50`ig zut{GZZrFmD=tuKYQ!<0gOPR~0(?&;%OARzB#jPqIAI@{`frzSs=EidgnP*&$FcP&S zbXHG54LlM{K~P<-*NsbWY_Pzxu2p8x>=*53drMGM)~?37`%6OG#}G4hyQ{{GmQ{O_ z5=i}5J;vBp-Z&^ynOzQUo*4E%?0vVTVchs{{abcV%bDDxT!Q%8>bAjN&FGA8qrdIU z#qf{!2|P#EAA}NUY1L1H!fB7-z1583nMF?29uD`1`imDoLrNd^czUyx^a#hC0r`qF z$3x7%f~NTm#i@rv$q(mJY|*6eU|5%(uGlkD**3hzx|CpqYbCC&Na}VQ;2u9g;5*97 zRI6v$c-0+4H2>ppv78C+e`oNZ2I|z(4`-^;I@}sI_@ow5V~_aj!D>58k5uh<$)G5W z%wZ6IeA|P0Ww-_04c>z~lUq|PJn?hE+HXJR+Gz#3%}`-#bkg6>ffKZFi9G$iZVr4v zZ`$1>@f2TR61{oO=Oy%BA!?++EAxGAlGdtD&lI~rjiE+;QI32p+IDJG?%1X$$)8^k zysMZ9+&Ngf5!K(P^|grvwE<0|wLQ4rr5(?xJmWwW2fGnB551e8byi-fuc5k)PUClp z$iOq(ni1bM5VZW3Ygc5@S>D}2>(9dYjW%E{?QNI-!ZWst@tzjH=6qxc6zJ%UC$z(O zbA#u}{>@ghhPUWXKHmpLE}n}aQq8>iTi| z)w5##+%2$KqM=_(fa8i^P%riDc-~mt5b_`O#HfvmJTV-W;34cJfB{lx@&{g1~wE>ToJ6igTs5`CL+SjI)*9D>d%o(j%??SDVh(((?_8rS*%$jfx zf9qIc0P_9{;u{sfw3})jk^`H|+JwF3XrBVbEZp1GSqTJQvKs!BH4*1NqDnpLvDYbO z4L**1HxnMFLN8DeSK9QPp=z5SAlhZ!L9AQeRro?!Y!tOq7-X#gy|e>v15=c2Wr+es z915mU0l>G}to&3KoeA!LYRad6Bvy-mS4zYyHIeQ1A!S0w=5lvcStYuuBYJl$8DW{~nF?Um!EYv!!OqW=SRC*$b8qNkswpzFN*a{67Gz`)20= literal 0 HcmV?d00001 diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/fr.png b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-data/flag/fr.png new file mode 100644 index 0000000000000000000000000000000000000000..7ea9c3bb7252664c2497327d9444473494fcdc67 GIT binary patch literal 835 zcmeAS@N?(olHy`uVBq!ia0y~yVAKJ!PjIjS$)NjpLV*-Zv6E*A2N2Y7q;vrJoCO|{ z#X#Y?Ak0`}lD!ZpC|TkfQ4*Y=R#Ki=l*&+EUaps!mtCBkSdglhUz9%kosAR&1JeOd z7srr_Id88R3NjfoFdY07y|9|oqso4VGqae}>`8ie&a7)%{Z69)y3C*6pZm(yH~fe> zf0t9|++9Y7{YE+phc`6v9A+}&;XYw7${7sN*gruUR6cP+~})HopJ>00DGTPE!Ct=GbNc0004EOGiWi zhy@);00009a7bBm000XU000XU0RWnu7ytkO2XskIMF-Xc4huUjL;Y1}0002RNkl4BL)55;;er6Twa#DM&p={N0Y ztb>Ud0@(S>%26F65`*k;rCK}E!aOTgP3AF(s?<}(LUlfGynhq07*qo IM6N<$f>G%q;{X5v literal 0 HcmV?d00001 diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/language.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/language.js new file mode 100644 index 00000000..7b68cd18 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/language.js @@ -0,0 +1,4 @@ +exports.german = 'de'; +exports.french = 'fr'; +exports.spanish = 'es'; +exports.english = 'en'; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/main.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/main.js new file mode 100644 index 00000000..be2e6e01 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/main.js @@ -0,0 +1,65 @@ +var widgets = require("widget"); +var pageMod = require("page-mod"); +var student = require("student"); +var data = require("self").data; + +var workers = new Array(); +var mod = null; + +exports.main = function(options, callback) { + mod = pageMod.PageMod( + { + include: "*", + contentScriptWhen:"ready", + contentScriptFile: data.url("./contentScripts/keworker.js"), + onAttach: function onAttach(worker) { + worker.on('message', handleMessage); + workers.push(worker); + } + } + ); + + var widget = widgets.Widget( + { + id: "ke", + label: "Knowledge Engineering", + contentURL: data.url("keicon.png") + } + ); + + function handleMessage(message) { + var lang = require("language"); + if(message.length > 0) { + //TODO: Iconswitch + var language = student.student(message); + console.log(language); + switch(language) { + case lang.german: + widget.contentURL = data.url("./flag/de.png"); + break; + case lang.spanish: + widget.contentURL = data.url("./flag/es.png"); + break; + case lang.english: + widget.contentURL = data.url("./flag/en.png"); + break; + case lang.french: + widget.contentURL = data.url("./flag/fr.png"); + break; + default: + widget.contentURL = data.url("./keicon.png"); + + } + //TODO: response + } + } + + console.log("The add-on is running."); +} + +exports.onUnload = function(reason) { + if(mod != null) {mod.destroy();} + for(var i=0; i=enWordCount && deWordCount >= frWordCount) { + return lang.german; + } + + if (enWordCount >= deWordCount && enWordCount >= frWordCount) { + return lang.english; + } + + if (frWordCount >= enWordCount && frWordCount >= deWordCount) { + return lang.french; + } + + return lang.german; +} + + +exports.student = student; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/utility.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/utility.js new file mode 100644 index 00000000..03e55465 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-lib/utility.js @@ -0,0 +1,13 @@ +/* +Tokenize a text at whitespace. +Some punctuations are removed +*/ +function tokenize(text) { + var lct = text.toLowerCase(); + lct = lct.replace(/(\.|,|!|\?|'|"|\\|\/|\|)/g,""); + var result = lct.split(/\W/g); + return result; +} + + +exports.tokenize = tokenize; diff --git a/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-tests/test-main.js b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-tests/test-main.js new file mode 100644 index 00000000..567f0d83 --- /dev/null +++ b/ss2013/1_Web Mining/Uebungen/1_Uebung/keaddon/resources/jid0-gn3ivo79cgfs9k4p3lxdo7tpfa4-keaddon-tests/test-main.js @@ -0,0 +1,83 @@ +const main = require("main"); +const lang = require("language"); +exports.test_test_run = function(test) { + test.pass("Unit test running!"); +}; + +exports.test_id = function(test) { + test.assert(require("self").id.length > 0); +}; + +exports.test_url = function(test) { + require("request").Request({ + url: "http://www.mozilla.org/", + onComplete: function(response) { + test.assertEqual(response.statusText, "OK"); + test.done(); + } + }).get(); + test.waitUntilDone(20000); +}; + +exports.test_open_tab = function(test) { + const tabs = require("tabs"); + tabs.open({ + url: "http://www.mozilla.org/", + onReady: function(tab) { + test.assertEqual(tab.url, "http://www.mozilla.org/"); + test.done(); + } + }); + test.waitUntilDone(20000); +}; + +var errormessage = ""; + +exports.test_util_countElements = function(test) { + const util = require("utility"); + test.assert(compareObjects(util.countElements(["du", "du", "hallo", "hallo", "du"]),{"hallo":2, "du":3}),errormessage); +}; + +exports.test_util_toCharArray = function(test) { + const util = require("utility"); + test.assert(compareArrays(util.toCharArray("test"), ["t","e","s","t"]), errormessage); +}; + +exports.test_util_toCharPairs = function(test) { + const util = require("utility"); + test.assert(compareArrays(util.toCharPairs("mainz"),["ma", "ai", "in", "nz"]), errormessage); +}; + +exports.test_util_tokenize = function(test) { + const util = require("utility"); + test.assert(compareArrays(util.tokenize("Dem Igel geht's gut."),["dem","igel","gehts","gut"]), errormessage); +}; + +exports.test_student_student = function(test) { + const student = require("student"); + var text = "blubber"; + test.assertEqual(student.student(text), lang.german, "Geht nicht weil."); +}; + +function compareObjects(a,b) { + for(var key in a) { + if( a[key] != b[key] ) { + return false; + } + } + return true; +}; + +function compareArrays(a,b) { + if (a.length != b.length) { + errormessage = "Arrays of unequal size"; + return false + } + for(var i=0; i