=== modified file '.bzrignore'
--- .bzrignore	2014-01-20 13:10:02 +0000
+++ .bzrignore	2014-05-02 16:27:07 +0000
@@ -25,7 +25,6 @@
 *.la
 *.lo
 *.o
-*.pot
 *.service
 *.tar.*
 *.typelib

=== modified file 'autopilot/unityclickscope/test_click_scope.py'
--- autopilot/unityclickscope/test_click_scope.py	2014-02-03 15:42:51 +0000
+++ autopilot/unityclickscope/test_click_scope.py	2014-05-02 16:27:07 +0000
@@ -22,13 +22,11 @@
 import fixtures
 from autopilot.introspection import dbus as autopilot_dbus
 from autopilot.matchers import Eventually
-from testtools.matchers import Equals
-from ubuntuuitoolkit import emulators as toolkit_emulators
+from testtools.matchers import Equals, MatchesAny
 from unity8 import process_helpers
-from unity8.shell import (
-    emulators as unity_emulators,
-    tests as unity_tests
-)
+from unity8.shell import tests as unity_tests
+from unity8.shell.emulators import dash
+
 
 from unityclickscope import credentials, fake_services, fixture_setup
 
@@ -36,6 +34,10 @@
 logger = logging.getLogger(__name__)
 
 
+class ClickScopeException(Exception):
+    """Exception raised when there's a problem with the scope."""
+
+
 class BaseClickScopeTestCase(dbusmock.DBusTestCase, unity_tests.UnityTestCase):
 
     scenarios = [
@@ -57,7 +59,7 @@
         unity_proxy = self.launch_unity()
         process_helpers.unlock_unity(unity_proxy)
         self.dash = self.main_window.get_dash()
-        self.scope = self.dash.get_scope('applications')
+        self.scope = self.dash.get_scope('clickscope')
 
     def _use_fake_server(self):
         fake_search_server = fixture_setup.FakeSearchServerRunning()
@@ -103,64 +105,76 @@
 
     def _restart_scope(self):
         logging.info('Restarting click scope.')
-        os.system('pkill click-scope')
+        os.system('pkill -f -9 clickscope.ini')
+        lib_path = '/usr/lib/$DEB_HOST_MULTIARCH/'
+        scoperunner_path = os.path.join(lib_path, 'scoperunner/scoperunner')
+        clickscope_config_ini_path = os.path.join(
+            lib_path, 'unity-scopes/clickscope/clickscope.ini')
         os.system(
             "dpkg-architecture -c "
-            "'/usr/lib/$DEB_HOST_MULTIARCH//unity-scope-click/click-scope' &")
+            "'{scoperunner} \"\" {clickscope}' &".format(
+                scoperunner=scoperunner_path,
+                clickscope=clickscope_config_ini_path))
 
     def _unlock_screen(self):
         self.main_window.get_greeter().swipe()
 
     def open_scope(self):
-        self.dash.open_scope('applications')
-        self.scope.isCurrent.wait_for(True)
-
-    def open_app_preview(self, name):
-        self.search(name)
-        icon = self.scope.wait_select_single('Tile', text=name)
-        pointing_device = toolkit_emulators.get_pointing_device()
-        pointing_device.click_object(icon)
-        preview = self.dash.wait_select_single(AppPreview)
-        preview.showProcessingAction.wait_for(False)
-        return preview
+        scope = self.dash.open_scope('clickscope')
+        scope.isCurrent.wait_for(True)
+        return scope
 
     def search(self, query):
         # TODO move this to the unity8 main view emulator.
         # --elopio - 2013-12-27
-        search_box = self._proxy.select_single("SearchIndicator")
-        self.touch.tap_object(search_box)
+        search_indicator = self._proxy.select_single(
+            'SearchIndicator', objectName='search')
+        self.touch.tap_object(search_indicator)
+        page_header = self._proxy.select_single(
+            'PageHeader', objectName='pageHeader')
+        search_container = page_header.select_single(
+                'QQuickItem', objectName='searchContainer')
+        search_container.state.wait_for(
+            MatchesAny(Equals('narrowActive'), Equals('active')))
         self.keyboard.type(query)
 
+    def open_app_preview(self, category, name):
+        self.search(name)
+        preview = self.scope.open_preview(category, name)
+        preview.get_parent().ready.wait_for(True)
+        return preview
+
 
 class TestCaseWithHomeScopeOpen(BaseClickScopeTestCase):
 
     def test_open_scope_scrolling(self):
-        self.assertFalse(self.scope.isCurrent)
-        self.dash.open_scope('applications')
-        self.assertThat(self.scope.isCurrent, Eventually(Equals(True)))
+        scope = self.dash.open_scope('clickscope')
+        self.assertThat(scope.isCurrent, Equals(True))
 
 
 class TestCaseWithClickScopeOpen(BaseClickScopeTestCase):
 
     def setUp(self):
         super(TestCaseWithClickScopeOpen, self).setUp()
-        self.open_scope()
+        self.scope = self.open_scope()
 
     def test_search_available_app(self):
         self.search('Shorts')
-        self.scope.wait_select_single('Tile', text='Shorts')
+        applications = self.scope.get_applications('appstore')
+        self.assertThat(applications[0].title, Equals('Shorts'))
 
     def test_open_app_preview(self):
         expected_details = dict(
-            title='Shorts', publisher='Ubuntu Click Loader')
-        preview = self.open_app_preview('Shorts')
+            title='Shorts', subtitle='Shorts is an rssreader application')
+        preview = self.open_app_preview('appstore', 'Shorts')
         details = preview.get_details()
         self.assertEqual(details, expected_details)
 
     def test_install_without_credentials(self):
-        preview = self.open_app_preview('Shorts')
+        preview = self.open_app_preview('appstore', 'Shorts')
         preview.install()
-        error = self.dash.wait_select_single(DashPreview)
+        error = self.dash.wait_select_single(Preview)
+
         details = error.get_details()
         self.assertEqual('Login Error', details.get('title'))
 
@@ -168,12 +182,14 @@
 class ClickScopeTestCaseWithCredentials(BaseClickScopeTestCase):
 
     def setUp(self):
+        self.skipTest('segfaults. TODO in following branches.')
         self.add_u1_credentials()
         super(ClickScopeTestCaseWithCredentials, self).setUp()
-        self.open_scope()
-        self.preview = self.open_app_preview('Shorts')
+        self.scope = self.open_scope()
+        self.preview = self.open_app_preview('appstore', 'Shorts')
 
     def add_u1_credentials(self):
+        import pdb; pdb.set_trace()
         account_manager = credentials.AccountManager()
         account = account_manager.add_u1_credentials(
             'dummy@example.com', 'dummy')
@@ -187,43 +203,26 @@
             self.preview.is_progress_bar_visible, Eventually(Equals(True)))
 
 
-class Preview(object):
-
-    def get_details(self):
-        """Return the details of the open preview."""
-        title = self.select_single('Label', objectName='titleLabel').text
-        subtitle = self.select_single(
-            'Label', objectName='subtitleLabel').text
-        # The description label doesn't have an object name. Reported as bug
-        # http://pad.lv/1269114 -- elopio - 2014-1-14
-        # description = self.select_single(
-        #    'Label', objectName='descriptionLabel').text
-        # TODO check screenshots, icon, rating and reviews.
-        return dict(title=title, subtitle=subtitle)
-
-
-# TODO move this to unity. --elopio - 2014-1-22
-class DashPreview(unity_emulators.UnityEmulatorBase, Preview):
-    """Autopilot emulator for the generic preview."""
-
-
-# TODO move this to unity. --elopio - 2014-1-14
-class AppPreview(unity_emulators.UnityEmulatorBase, Preview):
+class DashApps(dash.DashApps):
+    """Autopilot emulator for the applicatios scope."""
+
+
+class Preview(dash.Preview):
     """Autopilot emulator for the application preview."""
 
     def get_details(self):
         """Return the details of the application whose preview is open."""
-        details = super(AppPreview, self).get_details()
+        card_header = self.select_single('CardHeader', objectName='cardHeader')
         return dict(
-            title=details.get('title'), publisher=details.get('subtitle'))
+            title=card_header.title, subtitle=card_header.subtitle)
 
     def install(self):
-        install_button = self.select_single('Button', objectName='button0')
-        if install_button.text != 'Install':
-            raise unity_emulators.UnityEmulatorException(
-                'Install button not found.')
+        parent = self.get_parent()
+        install_button = self.select_single(
+            'PreviewActionButton', objectName='buttoninstall_click')
         self.pointing_device.click_object(install_button)
         self.implicitHeight.wait_for(0)
+        parent.ready.wait_for(True)
 
     def is_progress_bar_visible(self):
         try:

=== modified file 'data/CMakeLists.txt'
--- data/CMakeLists.txt	2014-03-06 15:38:35 +0000
+++ data/CMakeLists.txt	2014-05-02 16:27:07 +0000
@@ -1,12 +1,21 @@
+find_program(INTLTOOL_MERGE intltool-merge)
+set(SCOPE_INI_TARGET clickscope.ini)
+
 configure_file(
-  clickscope.ini.in
-  clickscope.ini
-)
+  ${SCOPE_INI_TARGET}.in.in
+  ${SCOPE_INI_TARGET}.in
+)
+
+add_custom_target(${SCOPE_INI_TARGET} ALL
+  COMMENT "Merging translations into ${SCOPE_INI_TARGET}"
+  COMMAND LC_ALL=C ${INTLTOOL_MERGE} -d -u ${CMAKE_SOURCE_DIR}/po ${SCOPE_INI_TARGET}.in ${SCOPE_INI_TARGET} >/dev/null
+)
+
 install(
   FILES clickscope-screenshot.jpg apps-scope.svg
   DESTINATION "${SCOPE_DATA_DIR}"
 )
 install(
-  FILES "${CMAKE_CURRENT_BINARY_DIR}/clickscope.ini"
+  FILES "${CMAKE_CURRENT_BINARY_DIR}/${SCOPE_INI_TARGET}"
   DESTINATION "${SCOPE_LIB_DIR}"
 )

=== renamed file 'data/clickscope.ini.in' => 'data/clickscope.ini.in.in'
--- data/clickscope.ini.in	2014-02-24 13:36:22 +0000
+++ data/clickscope.ini.in.in	2014-05-02 16:27:07 +0000
@@ -1,8 +1,8 @@
 [ScopeConfig]
-DisplayName = Apps
-Description = Scope for searching the click app store
-Author = Canonical Ltd.
-Art = @SCOPE_DATA_DIR@/clickscope-screenshot.jpg
-Icon = @SCOPE_DATA_DIR@/apps-scope.svg
-SearchHint = clickscope.SearchHint
-HotKey = clickscope.HotKey
+_DisplayName=Apps
+_Description=Scope for searching the click app store
+Author=Canonical Ltd.
+Art=@SCOPE_DATA_DIR@/clickscope-screenshot.jpg
+Icon=@SCOPE_DATA_DIR@/apps-scope.svg
+SearchHint=clickscope.SearchHint
+HotKey=clickscope.HotKey

=== modified file 'debian/control'
--- debian/control	2014-04-10 18:19:33 +0000
+++ debian/control	2014-05-02 16:27:07 +0000
@@ -8,11 +8,10 @@
                intltool,
                libglib2.0-dev (>= 2.32),
                libjsoncpp-dev,
-               libubuntu-download-manager-client-dev,
-               libubuntu-download-manager-common-dev,
+               libubuntu-download-manager-client-dev (>= 0.3+14.10.20140430-0ubuntu1),
+               libubuntu-download-manager-common-dev (>= 0.3+14.10.20140430-0ubuntu1),
                libubuntuoneauth-2.0-dev,
                libunity-scopes-dev (>= 0.4.0),
-               liburl-dispatcher1-dev,
                pkg-config,
 Maintainer: Ubuntu Developers <ubuntu-devel-discuss@lists.ubuntu.com>
 Standards-Version: 3.9.5

=== modified file 'po/CMakeLists.txt'
--- po/CMakeLists.txt	2014-04-03 16:06:05 +0000
+++ po/CMakeLists.txt	2014-05-02 16:27:07 +0000
@@ -17,9 +17,10 @@
 )
 
 # Creates the .pot file containing the translations template
-add_custom_target(${POT_FILE} ALL
+add_custom_target(${POT_FILE}
     COMMENT "Generating translation template"
     COMMAND XGETTEXT="${GETTEXT_XGETTEXT_EXECUTABLE}" srcdir="${CMAKE_CURRENT_SOURCE_DIR}" ${INTLTOOL_UPDATE} --gettext-package ${GETTEXT_PACKAGE} --pot
+    COMMAND cp -f ${POT_FILE} ${CMAKE_CURRENT_SOURCE_DIR}/
     DEPENDS POTFILES
 )
 

=== modified file 'po/POTFILES.in'
--- po/POTFILES.in	2014-04-03 16:06:05 +0000
+++ po/POTFILES.in	2014-05-02 16:27:07 +0000
@@ -1,1 +1,3 @@
+[type: gettext/ini] data/clickscope.ini.in.in
 scope/click/preview.cpp
+scope/click/query.cpp

=== added file 'po/ar.po'
--- po/ar.po	1970-01-01 00:00:00 +0000
+++ po/ar.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,92 @@
+# Arabic translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-05-01 19:32+0000\n"
+"Last-Translator: Ibrahim Saed <ibraheem5000@gmail.com>\n"
+"Language-Team: Arabic <ar@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-02 07:39+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "التطبيقات"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "خطأ في التنزيل"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr "فشل في التنزيل أو التثبيت. يرجى المحاولة مجددًا."
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "إغلاق"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "خطأ في الولوج"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr "يرجى الولوج إلى حساب أوبونتو ون خاصتك."
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr "انتقل إلى الحسابات"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "فتح"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "إزالة التثبيت"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "التأكيد"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+"إزالة تثبيت هذا التطبيق ستؤدي لحذف جميع المعلومات المتعلقة به. هل أنت متأكد "
+"من رغبتك بإزالة التثبيت؟"
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr "ليس بعد الآن"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr "نعم أزِل التثبيت"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "تثبيت"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr "تطبيقاتي"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "متوفر"

=== added file 'po/ca.po'
--- po/ca.po	1970-01-01 00:00:00 +0000
+++ po/ca.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,90 @@
+# Catalan translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-04-29 21:24+0000\n"
+"Last-Translator: David Planella <david.planella@ubuntu.com>\n"
+"Language-Team: Catalan <ca@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-04-30 07:36+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "Aplicacions"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr ""
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Tanca"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr ""

=== added file 'po/de.po'
--- po/de.po	1970-01-01 00:00:00 +0000
+++ po/de.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,90 @@
+# German translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-04-29 21:45+0000\n"
+"Last-Translator: Phillip Sz <Unknown>\n"
+"Language-Team: German <de@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-04-30 07:36+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "Anwendungen"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "Fehler beim Herunterladen"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr ""
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Schließen"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "Anmeldefehler"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "Öffnen"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "Entfernen"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "Bestätigung"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "Installieren"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr "Meine Anwendungen"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "Verfügbar"

=== added file 'po/es.po'
--- po/es.po	1970-01-01 00:00:00 +0000
+++ po/es.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,92 @@
+# Spanish translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-05-01 06:54+0000\n"
+"Last-Translator: Paco Molinero <paco@byasl.com>\n"
+"Language-Team: Spanish <es@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-02 07:39+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "Aplicaciones"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr "Scope para buscar en la tienda de aplicaciones"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "Error en la descarga"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr "La descarga o la instalación han fallado. Inténtelo nuevamente."
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Cerrar"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "Error de autenticación"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr "Acceda a su cuenta de Ubuntu One."
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr "Ir a Cuentas"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "Abrir"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "Desinstalar"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "Confirmación"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+"Desinstalar esta aplicación borrará toda la información asociada. ¿Quiere "
+"desinstalar?"
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr "Cancelar"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr "Desinstalar"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "Instalar"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr "Mis aplicaciones"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "Disponibles"

=== added file 'po/eu.po'
--- po/eu.po	1970-01-01 00:00:00 +0000
+++ po/eu.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,92 @@
+# Basque translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-04-29 21:40+0000\n"
+"Last-Translator: Ibai Oihanguren Sala <Unknown>\n"
+"Language-Team: Basque <eu@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-04-30 07:36+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "Aplikazioak"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "Deskarga-errorea"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr "Deskarga edo instalazioak huts egin du. Saiatu berriro."
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Itxi"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "Errorea saioa hastean"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr "Hasi saioa zure Ubuntu One kontuan."
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr "Joan Kontuak-era"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "Ireki"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "Desinstalatu"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "Berrespena"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+"Aplikazio hau desinstalatuz erlazionatutako informazio guztia ezabatuko da. "
+"Ziur desinstalatu nahi duzula?"
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr "Bai, desinstalatu"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "Instalatu"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr "Nire aplikazioak"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "Eskuragarri"

=== added file 'po/fi.po'
--- po/fi.po	1970-01-01 00:00:00 +0000
+++ po/fi.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,92 @@
+# Finnish translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-04-30 08:18+0000\n"
+"Last-Translator: Jiri Grönroos <Unknown>\n"
+"Language-Team: Finnish <fi@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-01 07:02+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "Sovellukset"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr "Näkymä Click-sovelluskaupasta etsintää varten"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "Latausvirhe"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr "Lataus tai asennus epäonnistui. Yritä uudelleen."
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Sulje"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "Kirjautumisvirhe"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr "Kirjaudu Ubuntu One -tilillesi."
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr "Siirry tileihin"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "Avaa"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "Poista"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "Vahvistus"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+"Tämän sovelluksen poistaminen poistaa kaikki siihen liittyvät tiedot. "
+"Haluatko varmasti poistaa sovelluksen?"
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr "Ei enää"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr "Kyllä, poista"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "Asenna"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr "Omat sovellukset"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "Saatavilla"

=== added file 'po/gd.po'
--- po/gd.po	1970-01-01 00:00:00 +0000
+++ po/gd.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,94 @@
+# Gaelic; Scottish translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-05-01 13:41+0000\n"
+"Last-Translator: GunChleoc <Unknown>\n"
+"Language-Team: Gaelic; Scottish <gd@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-02 07:39+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "Aplacaidean"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr "Sgòp airson lorg sa bhùth click app"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "Mearachd leis an luchdadh a-nuas"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr ""
+"Dh'fhàillig leis an luchdadh a-nuas no an stàladh. Am feuch thu ris a-"
+"rithist?"
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Dùin"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "Mearachd leis an logadh a-steach"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr "Logh a-steach dhan chunntas Ubuntu One agad."
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr "Rach dha na cunntasan"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "Fosgail"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "Dì-stàlaich"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "Dearbhadh"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+"Ma dhì-stàlaicheas tu an aplacaid seo, thèid a h-uile fiosrachadh ceangailte "
+"rithe a sguabadh às. A bheil thu cinnteach gu bheil thu airson a dì-stàladh?"
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr "Chan eil tuilleadh"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr "Tha, dì-stàlaich i"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "Stàlaich"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr "Na h-aplacaidean agam"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "Ri fhaighinn"

=== added file 'po/gl.po'
--- po/gl.po	1970-01-01 00:00:00 +0000
+++ po/gl.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,90 @@
+# Galician translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-04-30 09:08+0000\n"
+"Last-Translator: Marcos Lans <Unknown>\n"
+"Language-Team: Galician <gl@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-01 07:02+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "Aplicativos"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "Erro de descarga"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr ""
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Pechar"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "Erro de acceso"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "Abrir"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "Desinstalar"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "Confirmación"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "Instalar"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "Dispoñíbel"

=== added file 'po/he.po'
--- po/he.po	1970-01-01 00:00:00 +0000
+++ po/he.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,90 @@
+# Hebrew translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-05-01 14:52+0000\n"
+"Last-Translator: Yaron <sh.yaron@gmail.com>\n"
+"Language-Team: Hebrew <he@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-02 07:39+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "יישומים"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr "מתחם לחיפוש בחנות היישומים בלחיצה"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "שגיאת הורדה"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr "ההורדה או ההתקנה נכשלו. נא לנסות שוב."
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "סגירה"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "שגיאת כניסה"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr "נא להיכנס לחשבונך ב־Ubuntu One"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr "מעבר לחשבונות"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "פתיחה"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "הסרה"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr ""

=== added file 'po/id.po'
--- po/id.po	1970-01-01 00:00:00 +0000
+++ po/id.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,90 @@
+# Indonesian translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-04-30 02:36+0000\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: Indonesian <id@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-01 07:02+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr ""
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr ""
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr ""

=== added file 'po/it.po'
--- po/it.po	1970-01-01 00:00:00 +0000
+++ po/it.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,92 @@
+# Italian translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-04-30 12:04+0000\n"
+"Last-Translator: Claudio Arseni <claudio.arseni@gmail.com>\n"
+"Language-Team: Italian <it@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-01 07:02+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "App"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr "Scope per la ricerca nel «click app store»"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "Errore nello scaricamento"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr "Scaricamento o installazione non riusciti. Riprovare."
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Chiudi"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "Errore di accesso"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr "Accedere al proprio account Ubuntu One."
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr "Vai agli account"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "Apri"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "Rimuovi"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "Conferma"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+"Rimuovendo questa applicazione verranno eliminate anche tutte le relative "
+"informazioni. Rimuovere veramente?"
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr "Non ora"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr "Sì, rimuovi"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "Installa"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr "Le mia app"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "Disponibile"

=== added file 'po/lv.po'
--- po/lv.po	1970-01-01 00:00:00 +0000
+++ po/lv.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,90 @@
+# Latvian translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-04-30 06:16+0000\n"
+"Last-Translator: Jānis-Marks Gailis <jeanmarc.gailis@gmail.com>\n"
+"Language-Team: Latvian <lv@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-01 07:02+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "Lietotnes"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "Lejupielādes kļūda"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr ""
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Aizvērt"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "Pieteikšanās kļūda"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "Atvērt"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "Noņemt"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "Apstiprināt"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "Instalēt"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "Pieejams"

=== added file 'po/nb.po'
--- po/nb.po	1970-01-01 00:00:00 +0000
+++ po/nb.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,92 @@
+# Norwegian Bokmal translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-05-01 11:24+0000\n"
+"Last-Translator: Åka Sikrom <Unknown>\n"
+"Language-Team: Norwegian Bokmal <nb@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-02 07:39+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "Programmer"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr "Ramme som søker gjennom klikk-programvarebutikken"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "Feil ved nedlastning"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr "Feil ved nedlastning eller installasjon. Prøv igjen."
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Lukk"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "Påloggingsfeil"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr "Logg på Ubuntu One-kontoen din."
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr "Gå til Kontoer"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "Åpne"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "Avinstaller"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "Bekreftelse"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+"All relatert informasjon blir slettet hvis du avinstallerer dette "
+"programmet. Er du sikker på at du vil avinstallere?"
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr "Ikke nå lenger"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr "Ja, avinstaller"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "Installer"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr "Mine programmer"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "Tilgjengelig"

=== added file 'po/ru.po'
--- po/ru.po	1970-01-01 00:00:00 +0000
+++ po/ru.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,90 @@
+# Russian translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-05-01 05:40+0000\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: Russian <ru@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-02 07:39+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr ""
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr ""
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr ""

=== added file 'po/sl.po'
--- po/sl.po	1970-01-01 00:00:00 +0000
+++ po/sl.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,90 @@
+# Slovenian translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-04-30 15:46+0000\n"
+"Last-Translator: Damir Jerovšek <Unknown>\n"
+"Language-Team: Slovenian <sl@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-01 07:03+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "Programi"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "Napaka med prenosom"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr "Prejem ali namestitev je spodletela. Poskusite znova."
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Zapri"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "Napaka med prijavo"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "Odpri"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "Odstrani"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "Potrditev"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr "Da, odstrani"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "Namesti"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr "Moji programi"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "Na voljo"

=== added file 'po/uk.po'
--- po/uk.po	1970-01-01 00:00:00 +0000
+++ po/uk.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,94 @@
+# Ukrainian translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-04-30 04:14+0000\n"
+"Last-Translator: Yuri Chornoivan <yurchor@gmail.com>\n"
+"Language-Team: Ukrainian <uk@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-01 07:03+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "Програми"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr "Область для пошуку у збірці програм click"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "Помилка під час отримання даних"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr ""
+"Спроба отримання даних або встановлення пакунка зазнала невдачі. Будь ласка, "
+"повторіть її."
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "Закрити"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "Помилка входу"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr "Будь ласка, увійдіть до вашого облікового запису Ubuntu One."
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr "Перейти до облікових записів"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "Відкрити"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "Вилучити"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "Підтвердждення"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+"Вилучення цієї програми призведе до вилучення усіх пов’язаних з нею даних. "
+"Ви справді хочете вилучити програму?"
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr "Ні"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr "Так, вилучити"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "Встановити"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr "Мої програми"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "Доступно"

=== added file 'po/unity-scope-click.pot'
--- po/unity-scope-click.pot	1970-01-01 00:00:00 +0000
+++ po/unity-scope-click.pot	2014-05-02 16:27:07 +0000
@@ -0,0 +1,90 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: \n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"Language: \n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr ""
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr ""
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr ""
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr ""

=== added file 'po/zh_CN.po'
--- po/zh_CN.po	1970-01-01 00:00:00 +0000
+++ po/zh_CN.po	2014-05-02 16:27:07 +0000
@@ -0,0 +1,90 @@
+# Chinese (Simplified) translation for unity-scope-click
+# Copyright (c) 2014 Rosetta Contributors and Canonical Ltd 2014
+# This file is distributed under the same license as the unity-scope-click package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, 2014.
+#
+msgid ""
+msgstr ""
+"Project-Id-Version: unity-scope-click\n"
+"Report-Msgid-Bugs-To: FULL NAME <EMAIL@ADDRESS>\n"
+"POT-Creation-Date: 2014-04-29 15:20-0400\n"
+"PO-Revision-Date: 2014-04-30 07:29+0000\n"
+"Last-Translator: Aron Xu <Unknown>\n"
+"Language-Team: Chinese (Simplified) <zh_CN@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=UTF-8\n"
+"Content-Transfer-Encoding: 8bit\n"
+"X-Launchpad-Export-Date: 2014-05-01 07:03+0000\n"
+"X-Generator: Launchpad (build 16985)\n"
+
+#: ../data/clickscope.ini.in.in.h:1
+msgid "Apps"
+msgstr "应用"
+
+#: ../data/clickscope.ini.in.in.h:2
+msgid "Scope for searching the click app store"
+msgstr "用以搜索 Click 应用商店的 Scope"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:199
+msgid "Download Error"
+msgstr "下载出错"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:200
+msgid "Download or install failed. Please try again."
+msgstr "下载或安装失败。请再试一次。"
+
+#. TODO see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:202
+msgid "Close"
+msgstr "关闭"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:207
+msgid "Login Error"
+msgstr "登录出错"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:208
+msgid "Please log in to your Ubuntu One account."
+msgstr "请用您的 Ubuntu One 账号登录"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:210
+msgid "Go to Accounts"
+msgstr "跳转到帐号"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:391
+msgid "Open"
+msgstr "打开"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:399
+msgid "Uninstall"
+msgstr "卸载"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:484
+msgid "Confirmation"
+msgstr "确认"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:486
+msgid ""
+"Uninstalling this app will delete all the related information. Are you sure "
+"you want to uninstall?"
+msgstr "卸载这个应用将删除所有相关信息。您确定要卸载吗？"
+
+#. TODO: see bug LP: #1289434
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:493
+msgid "Not anymore"
+msgstr ""
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:497
+msgid "Yes Uninstall"
+msgstr "卸载"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/preview.cpp:545
+msgid "Install"
+msgstr "安装"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:95
+msgid "My apps"
+msgstr "我的应用"
+
+#: /home/dobey/Projects/canonical/unity-scope-click/no-auto-pot/po/../scope/click/query.cpp:184
+msgid "Available"
+msgstr "可用"

=== modified file 'scope/click/CMakeLists.txt'
--- scope/click/CMakeLists.txt	2014-04-10 18:19:33 +0000
+++ scope/click/CMakeLists.txt	2014-05-02 16:27:07 +0000
@@ -2,7 +2,6 @@
 SET (CMAKE_AUTOMOC ON)
 find_package (Qt5Core REQUIRED)
 pkg_check_modules(JSON_CPP REQUIRED jsoncpp)
-pkg_check_modules(LIBURL_DISPATCHER REQUIRED url-dispatcher-1)
 
 add_definitions(
   -DGETTEXT_PACKAGE=\"${PROJECT_NAME}\"
@@ -10,6 +9,7 @@
 )
 
 add_library(${SCOPE_LIB_UNVERSIONED} SHARED
+  configuration.cpp
   download-manager.cpp
   index.cpp
   interface.cpp
@@ -18,7 +18,9 @@
   query.cpp
   reviews.cpp
   scope.cpp
+  scope_activation.cpp
   smartconnect.cpp
+  package.cpp
   preview.cpp
   ubuntuone_credentials.cpp
   webclient.cpp

=== added file 'scope/click/configuration.cpp'
--- scope/click/configuration.cpp	1970-01-01 00:00:00 +0000
+++ scope/click/configuration.cpp	2014-05-02 16:27:07 +0000
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include <string>
+#include <vector>
+
+#include <QDir>
+#include <QProcess>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/replace.hpp>
+
+#include "configuration.h"
+
+namespace click {
+
+std::vector<std::string> Configuration::list_folder(const std::string& folder, const std::string& pattern)
+{
+    std::vector<std::string> result;
+
+    QDir dir(QString::fromStdString(folder), QString::fromStdString(pattern),
+             QDir::Unsorted, QDir::Readable | QDir::Files);
+    QStringList entries = dir.entryList();
+    for (int i = 0; i < entries.size(); ++i) {
+        QString filename = entries.at(i);
+        result.push_back(filename.toStdString());
+    }
+
+    return result;
+}
+
+std::vector<std::string> Configuration::get_available_frameworks()
+{
+    std::vector<std::string> result;
+    for (auto f: list_folder(FRAMEWORKS_FOLDER, FRAMEWORKS_PATTERN)) {
+        result.push_back(f.substr(0, f.size()-FRAMEWORKS_EXTENSION_LENGTH));
+    }
+    return result;
+}
+
+std::string Configuration::architectureFromDpkg()
+{
+    QString program("dpkg");
+    QStringList arguments;
+    arguments << "--print-architecture";
+    QProcess archDetector;
+    archDetector.start(program, arguments);
+    if(!archDetector.waitForFinished()) {
+        throw std::runtime_error("Architecture detection failed.");
+    }
+    auto output = archDetector.readAllStandardOutput();
+    auto ostr = QString::fromUtf8(output);
+    ostr.remove('\n');
+
+    return ostr.toStdString();
+}
+
+std::string Configuration::get_architecture()
+{
+    static const std::string arch{architectureFromDpkg()};
+    return arch;
+}
+
+std::string Configuration::get_language_base()
+{
+    std::string language = get_language();
+    std::vector<std::string> lang_parts;
+    boost::split(lang_parts, language, boost::is_any_of("_"));
+    return lang_parts[0];
+}
+
+std::string Configuration::get_language()
+{
+    const char* language = getenv(LANGUAGE_ENVVAR);
+    if (language == NULL) {
+        language = "C";
+    }
+    std::vector<std::string> lang_parts;
+    boost::split(lang_parts, language, boost::is_any_of("."));
+    return lang_parts[0];
+}
+
+std::string Configuration::get_accept_languages()
+{
+    std::string language = get_language();
+    std::vector<std::string> lang_parts;
+    boost::split(lang_parts, language, boost::is_any_of("_"));
+    std::string result;
+    if (lang_parts.size() > 1) {
+        boost::replace_first(language, "_", "-");
+        result = language + ", " + get_language_base();
+    } else {
+        result = language;
+    }
+    return result;
+}
+
+} // namespace click

=== added file 'scope/click/configuration.h'
--- scope/click/configuration.h	1970-01-01 00:00:00 +0000
+++ scope/click/configuration.h	2014-05-02 16:27:07 +0000
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef CONFIGURATION_H
+#define CONFIGURATION_H
+
+#include <string>
+#include <vector>
+
+namespace click
+{
+
+class Configuration
+{
+public:
+    constexpr static const char* FRAMEWORKS_FOLDER {"/usr/share/click/frameworks/"};
+    constexpr static const char* FRAMEWORKS_PATTERN {"*.framework"};
+    constexpr static const int FRAMEWORKS_EXTENSION_LENGTH = 10; // strlen(".framework")
+    constexpr static const char* LANGUAGE_ENVVAR {"LANGUAGE"};
+
+    virtual std::vector<std::string> get_available_frameworks();
+    virtual std::string get_architecture();
+
+    virtual std::string get_language_base();
+    virtual std::string get_language();
+    virtual std::string get_accept_languages();
+
+    virtual ~Configuration() {}
+protected:
+    virtual std::vector<std::string> list_folder(const std::string &folder, const std::string &pattern);
+    virtual std::string architectureFromDpkg();
+};
+
+} // namespace click
+
+#endif // CONFIGURATION_H

=== modified file 'scope/click/download-manager.cpp'
--- scope/click/download-manager.cpp	2014-03-22 00:08:31 +0000
+++ scope/click/download-manager.cpp	2014-05-02 16:27:07 +0000
@@ -335,7 +335,7 @@
 void click::Downloader::startDownload(std::string url, std::string package_name,
                                       const std::function<void (std::pair<std::string, click::InstallError >)>& callback)
 {
-    qt::core::world::enter_with_task([this, callback, url, package_name] (qt::core::world::Environment& /*env*/)
+    qt::core::world::enter_with_task([this, callback, url, package_name] ()
     {
         auto& dm = downloadManagerInstance(networkAccessManager);
 

=== modified file 'scope/click/index.cpp'
--- scope/click/index.cpp	2014-04-04 10:11:11 +0000
+++ scope/click/index.cpp	2014-05-02 16:27:07 +0000
@@ -31,57 +31,20 @@
 #include <QObject>
 #include <QProcess>
 
-#include <json/json.h>
+#include <cstdlib>
 #include <sstream>
 
 #include "download-manager.h"
 #include "index.h"
+#include "interface.h"
 #include "application.h"
+#include "smartconnect.h"
 
 namespace json = Json;
 
 namespace click
 {
 
-bool operator==(const Package& lhs, const Package& rhs) {
-    return lhs.name == rhs.name &&
-            lhs.title == rhs.title &&
-            lhs.price == rhs.price &&
-            lhs.icon_url == rhs.icon_url;
-}
-
-bool operator==(const PackageDetails& lhs, const PackageDetails& rhs) {
-    return lhs.package == rhs.package &&
-            lhs.description == rhs.description &&
-            lhs.download_url == rhs.download_url &&
-            lhs.rating == rhs.rating &&
-            // TODO: keywords should be a list of strings
-            lhs.keywords == rhs.keywords &&
-            lhs.terms_of_service == rhs.terms_of_service &&
-            lhs.license == rhs.license &&
-            lhs.publisher == rhs.publisher &&
-            lhs.main_screenshot_url == rhs.main_screenshot_url &&
-            // TODO: more_screenshots_urls should be a list of strings
-            lhs.more_screenshots_urls == rhs.more_screenshots_urls &&
-            // TODO: binary_filesize should be a int/long
-            lhs.binary_filesize == rhs.binary_filesize &&
-            lhs.version == rhs.version &&
-            lhs.framework == rhs.framework;
-}
-
-QDebug operator<< (QDebug d, const std::string &s) {
-    d << QString::fromStdString(s);
-    return d;
-}
-
-bool operator==(const Application& lhs, const Application& rhs) {
-    return lhs.name == rhs.name &&
-            lhs.title == rhs.title &&
-            lhs.description == rhs.description &&
-            lhs.main_screenshot == rhs.main_screenshot &&
-            lhs.icon_url == rhs.icon_url;
-}
-
 void PackageManager::uninstall(const Package& package,
                                std::function<void(int, std::string)> callback)
 {
@@ -117,186 +80,45 @@
     process.data()->start(command.c_str());
 }
 
-PackageList package_list_from_json(const std::string& json)
-{
-    std::istringstream is(json);
-
-    PackageList pl;
-
-    json::Reader reader;
-    json::Value root;
-
-    if (!reader.parse(json, root)) {
-        throw std::runtime_error(reader.getFormattedErrorMessages());
-    }
-
-    for (uint i = 0; i < root.size(); i++)
-    {
-        Package p;
-        json::Value item = root[i];
-        p.name = item[Package::JsonKeys::name].asString();
-        p.title = item[Package::JsonKeys::title].asString();
-        p.price = item[Package::JsonKeys::price].asDouble();
-        p.icon_url = item[Package::JsonKeys::icon_url].asString();
-        p.url = item[Package::JsonKeys::resource_url].asString();
-        pl.push_back(p);
-    }
-    return pl;
-}
-
-PackageDetails PackageDetails::from_json(const std::string &json)
-{
-    PackageDetails details;
-    try
-    {
-        json::Reader reader;
-        json::Value root;
-
-        if (!reader.parse(json, root))
-            throw std::runtime_error(reader.getFormattedErrorMessages());
-
-        // Mandatory details go here. That is, asString() will throw as we
-        // do not provide a default value if a value with the given key does not exist.
-        details.package.name = root[Package::JsonKeys::name].asString();
-        details.package.title = root[Package::JsonKeys::title].asString();
-        details.package.icon_url = root[Package::JsonKeys::icon_url].asString();
-        details.package.price = root[Package::JsonKeys::price].asDouble();
-        details.description = root[JsonKeys::description].asString();
-        details.download_url = root[JsonKeys::download_url].asString();
-        details.license = root[JsonKeys::license].asString();
-
-        // Optional details go here.
-        if (root[JsonKeys::version].isString())
-            details.version = root[JsonKeys::version].asString();
-
-        if (root[JsonKeys::rating].isNumeric())
-            details.rating = root[JsonKeys::rating].asDouble();
-
-        if (root[JsonKeys::keywords].isString())
-            details.keywords = root[JsonKeys::keywords].asString();
-
-        if (root[JsonKeys::terms_of_service].isString())
-            details.terms_of_service = root[JsonKeys::terms_of_service].asString();
-
-        if (root[JsonKeys::publisher].isString())
-            details.publisher = root[JsonKeys::publisher].asString();
-
-        if (root[JsonKeys::main_screenshot_url].isString())
-            details.main_screenshot_url = root[JsonKeys::main_screenshot_url].asString();
-
-        auto screenshots = root[JsonKeys::more_screenshot_urls];
-
-        for (uint i = 0; i < screenshots.size(); i++)
-        {
-            auto scr = screenshots[i].asString();
-            // more_screenshot_urls may contain main_screenshot_url, if so, skip it
-            if (scr != details.main_screenshot_url)
-            {
-                details.more_screenshots_urls.push_back(scr);
-            }
-        }
-
-        if (root[JsonKeys::binary_filesize].isIntegral())
-            details.binary_filesize = root[JsonKeys::binary_filesize].asUInt64();
-
-        if (root[JsonKeys::framework].isString())
-            details.framework = root[JsonKeys::framework].asString();
-
-    } catch(const std::exception& e)
-    {
-        std::cerr << "PackageDetails::loadJson: Exception thrown while decoding JSON: " << e.what() << std::endl;
-    } catch(...)
-    {
-        std::cerr << "PackageDetails::loadJson: Exception thrown while decoding JSON." << std::endl;
-    }
-
-    return details;
-}
-
-std::string print_string_if_not_empty(const std::string& s)
-{
-
-    return s.empty() ? "n/a" : s;
-}
-
-std::string print_list_if_not_empty(const std::list<std::string>& li)
-{
-    std::stringstream s;
-    s << "[";
-    if (!li.empty())
-    {
-        auto it = li.begin();
-        s << print_string_if_not_empty(*it);
-        ++it;
-        while (it != li.end())
-        {
-            s << ", " << print_string_if_not_empty(*it);
-            ++it;
-        }
-    }
-    s << "]";
-    return s.str();
-}
-
-std::ostream& operator<<(std::ostream& out, const click::PackageDetails& details)
-{
-    out << "("
-        << print_string_if_not_empty(details.package.name) << ", "
-        << print_string_if_not_empty(details.package.title) << ", "
-        << print_string_if_not_empty(details.package.icon_url) << ", "
-        << print_string_if_not_empty(details.description) << ", "
-        << print_string_if_not_empty(details.download_url) << ", "
-        << details.rating << ", "
-        << print_string_if_not_empty(details.keywords) << ", "
-        << print_string_if_not_empty(details.terms_of_service) << ", "
-        << print_string_if_not_empty(details.license) << ", "
-        << print_string_if_not_empty(details.publisher) << ", "
-        << print_string_if_not_empty(details.main_screenshot_url) << ", "
-        << print_list_if_not_empty(details.more_screenshots_urls) << ", "
-        << details.binary_filesize << ", "
-        << print_string_if_not_empty(details.version) << ", "
-        << print_string_if_not_empty(details.framework)
-        << ")";
-
-    return out;
-}
-
-std::ostream& operator<<(std::ostream& out, const click::Application& app)
-{
-    out << "("
-        << print_string_if_not_empty(app.name) << ", "
-        << print_string_if_not_empty(app.title) << ", "
-        << app.price << ", "
-        << print_string_if_not_empty(app.icon_url) << ", "
-        << print_string_if_not_empty(app.url) << ", "
-        << print_string_if_not_empty(app.version) << ", "
-        << print_string_if_not_empty(app.description) << ", "
-        << print_string_if_not_empty(app.main_screenshot)
-        << ")";
-
-    return out;
-}
-
-Index::Index(const QSharedPointer<click::web::Client>& client) : client(client)
-{
-
+Index::Index(const QSharedPointer<click::web::Client>& client,
+             const QSharedPointer<Configuration> configuration) :
+    client(client), configuration(configuration)
+{
+
+}
+
+std::string Index::build_index_query(std::string query)
+{
+    std::stringstream result;
+
+    result << query;
+    for (auto f: configuration->get_available_frameworks()) {
+        result << ",framework:" << f;
+    }
+    result << ",architecture:" << configuration->get_architecture();
+
+    return result.str();
 }
 
 click::web::Cancellable Index::search (const std::string& query, std::function<void(click::PackageList)> callback)
 {
     click::web::CallParams params;
-    params.add(click::QUERY_ARGNAME, query.c_str());
+    std::string built_query(build_index_query(query));
+    params.add(click::QUERY_ARGNAME, built_query.c_str());
     QSharedPointer<click::web::Response> response(client->call(
-        click::SEARCH_BASE_URL + click::SEARCH_PATH, params));
+        get_base_url() + click::SEARCH_PATH, params));
 
     QObject::connect(response.data(), &click::web::Response::finished, [=](QString reply) {
         click::PackageList pl = click::package_list_from_json(reply.toUtf8().constData());
+        qDebug() << "found packages:" << pl.size();
         callback(pl);
     });
     QObject::connect(response.data(), &click::web::Response::error, [=](QString /*description*/) {
         qDebug() << "No packages found due to network error";
         click::PackageList pl;
+        qDebug() << "calling callback";
         callback(pl);
+        qDebug() << "                ...Done!";
     });
     return click::web::Cancellable(response);
 }
@@ -304,7 +126,7 @@
 click::web::Cancellable Index::get_details (const std::string& package_name, std::function<void(PackageDetails, click::Index::Error)> callback)
 {
     QSharedPointer<click::web::Response> response = client->call
-        (click::SEARCH_BASE_URL + click::DETAILS_PATH + package_name);
+        (get_base_url() + click::DETAILS_PATH + package_name);
     qDebug() << "getting details for" << package_name.c_str();
 
     QObject::connect(response.data(), &click::web::Response::finished, [=](const QByteArray reply) {
@@ -321,6 +143,15 @@
     return click::web::Cancellable(response);
 }
 
+std::string Index::get_base_url ()
+{
+    const char *env_url = getenv(SEARCH_BASE_URL_ENVVAR.c_str());
+    if (env_url != NULL) {
+        return env_url;
+    }
+    return click::SEARCH_BASE_URL;
+}
+
 Index::~Index()
 {
 }

=== modified file 'scope/click/index.h'
--- scope/click/index.h	2014-04-01 17:28:41 +0000
+++ scope/click/index.h	2014-05-02 16:27:07 +0000
@@ -32,18 +32,18 @@
 
 
 #include <string>
-#include <list>
-#include <iosfwd>
 #include <functional>
 
-#include <json/json.h>
-
+#include "configuration.h"
+#include "package.h"
 #include "webclient.h"
 
-namespace json = Json;
 
 namespace click {
 
+class Configuration;
+
+const std::string SEARCH_BASE_URL_ENVVAR = "U1_SEARCH_BASE_URL";
 const std::string SEARCH_BASE_URL = "https://search.apps.ubuntu.com/";
 const std::string SEARCH_PATH = "api/v1/search";
 const std::string SUPPORTED_FRAMEWORKS = "framework:ubuntu-sdk-13.10";
@@ -51,48 +51,6 @@
 const std::string ARCHITECTURE = "architecture:";
 const std::string DETAILS_PATH = "api/v1/package/";
 
-struct Package
-{
-    struct JsonKeys
-    {
-        JsonKeys() = delete;
-
-        constexpr static const char* name{"name"};
-        constexpr static const char* title{"title"};
-        constexpr static const char* price{"price"};
-        constexpr static const char* icon_url{"icon_url"};
-        constexpr static const char* resource_url{"resource_url"};
-    };
-
-    Package() = default;
-    Package(std::string name, std::string title, double price, std::string icon_url, std::string url) :
-        name(name),
-        title(title),
-        price(price),
-        icon_url(icon_url),
-        url(url)
-    {
-    }
-    Package(std::string name, std::string title, double price, std::string icon_url, std::string url, std::string version) :
-        name(name),
-        title(title),
-        price(price),
-        icon_url(icon_url),
-        url(url),
-        version(version)
-    {
-    }
-    virtual ~Package() = default;
-
-    std::string name; // formerly app_id
-    std::string title;
-    double price;
-    std::string icon_url;
-    std::string url;
-    std::string version;
-    void matches (std::string query, std::function<bool> callback);
-};
-
 class PackageManager
 {
 public:
@@ -100,68 +58,23 @@
     virtual void execute_uninstall_command (const std::string& command, std::function<void(int, std::string)>);
 };
 
-typedef std::list<Package> PackageList;
-
-PackageList package_list_from_json(const std::string& json);
-
-struct PackageDetails
-{
-    struct JsonKeys
-    {
-        JsonKeys() = delete;
-
-        constexpr static const char* name{"name"};
-        constexpr static const char* title{"title"};
-        constexpr static const char* icon_url{"icon_url"};
-        constexpr static const char* description{"description"};
-        constexpr static const char* download_url{"download_url"};
-        constexpr static const char* rating{"rating"};
-        constexpr static const char* keywords{"keywords"};
-        constexpr static const char* terms_of_service{"terms_of_service"};
-        constexpr static const char* license{"license"};
-        constexpr static const char* publisher{"publisher"};
-        constexpr static const char* main_screenshot_url{"screenshot_url"};
-        constexpr static const char* more_screenshot_urls{"screenshot_urls"};
-        constexpr static const char* binary_filesize{"binary_filesize"};
-        constexpr static const char* version{"version"};
-        constexpr static const char* framework{"framework"};
-    };
-
-    static PackageDetails from_json(const std::string &json);
-
-    Package package;
-
-    std::string description;
-    std::string download_url;
-    double rating;
-    std::string keywords;
-    std::string terms_of_service;
-    std::string license;
-    std::string publisher;
-    std::string main_screenshot_url;
-    std::list<std::string> more_screenshots_urls;
-    json::Value::UInt64 binary_filesize;
-    std::string version;
-    std::string framework;
-};
-
-std::ostream& operator<<(std::ostream& out, const PackageDetails& details);
-
 class Index
 {
 protected:
     QSharedPointer<web::Client> client;
+    QSharedPointer<Configuration> configuration;
+    virtual std::string build_index_query(std::string query);
 public:
     enum class Error {NoError, CredentialsError, NetworkError};
-    Index(const QSharedPointer<click::web::Client>& client);
-    click::web::Cancellable search (const std::string& query, std::function<void(PackageList)> callback);
-    click::web::Cancellable get_details(const std::string& package_name, std::function<void(PackageDetails, Error)> callback);
-    ~Index();
+    Index(const QSharedPointer<click::web::Client>& client,
+          const QSharedPointer<Configuration> configuration=QSharedPointer<Configuration>(new Configuration()));
+    virtual click::web::Cancellable search (const std::string& query, std::function<void(PackageList)> callback);
+    virtual click::web::Cancellable get_details(const std::string& package_name, std::function<void(PackageDetails, Error)> callback);
+    virtual ~Index();
+
+    static std::string get_base_url ();
 };
 
-bool operator==(const Package& lhs, const Package& rhs);
-bool operator==(const PackageDetails& lhs, const PackageDetails& rhs);
-
 } // namespace click
 
 #endif // CLICKINDEX_H

=== modified file 'scope/click/interface.cpp'
--- scope/click/interface.cpp	2014-04-10 17:29:49 +0000
+++ scope/click/interface.cpp	2014-05-02 16:27:07 +0000
@@ -136,6 +136,10 @@
     auto enumerator = [&result, &installTimes, this, search_query, include_desktop_results]
             (const unity::util::IniParser& keyFile, const std::string& filename)
     {
+        if (keyFile.has_group(DESKTOP_FILE_GROUP) == false) {
+            qWarning() << "Broken desktop file:" << QString::fromStdString(filename);
+            return;
+        }
         if (is_visible_app(keyFile) == false) {
             return; // from the enumerator lambda
         }
@@ -226,30 +230,6 @@
     return icon_id;
 }
 
-std::vector<std::string> FrameworkLocator::list_folder(const std::string& folder, const std::string& pattern)
-{
-    std::vector<std::string> result;
-
-    QDir dir(QString::fromStdString(folder), QString::fromStdString(pattern),
-             QDir::Unsorted, QDir::Readable | QDir::Files);
-    QStringList entries = dir.entryList();
-    for (int i = 0; i < entries.size(); ++i) {
-        QString filename = entries.at(i);
-        result.push_back(filename.toStdString());
-    }
-
-    return result;
-}
-
-std::vector<std::string> FrameworkLocator::get_available_frameworks()
-{
-    std::vector<std::string> result;
-    for (auto f: list_folder(FRAMEWORKS_FOLDER, FRAMEWORKS_PATTERN)) {
-        result.push_back(f.substr(0, f.size()-FRAMEWORKS_EXTENSION_LENGTH));
-    }
-    return result;
-}
-
 ManifestList manifest_list_from_json(const std::string& json)
 {
     using namespace boost::property_tree;
@@ -265,20 +245,22 @@
     {
         assert(v.first.empty()); // array elements have no names
         auto node = v.second;
-        std::string name = node.get<std::string>("name");
-        std::string version = node.get<std::string>("version");
-        std::string first_app_name;
+        Manifest manifest;
+
+        manifest.name = node.get<std::string>("name");
+        manifest.version = node.get<std::string>("version");
+        manifest.removable = node.get<bool>("_removable");
 
         BOOST_FOREACH(ptree::value_type &sv, node.get_child("hooks"))
         {
             // FIXME: "primary app" for a package is not defined, we just
             // use first one here:
-            first_app_name = sv.first;
+            manifest.first_app_name = sv.first;
             break;
         }
-        qDebug() << "adding manifest: " << name.c_str() << version.c_str() << first_app_name.c_str();
+        qDebug() << "adding manifest: " << manifest.name.c_str() << manifest.version.c_str() << manifest.first_app_name.c_str();
 
-        manifests.push_back(Manifest(name, version, first_app_name));
+        manifests.push_back(manifest);
     }
 
     return manifests;
@@ -293,87 +275,59 @@
     ptree pt;
     read_json(is, pt);
 
-    std::string name = pt.get<std::string>("name");
-    std::string version = pt.get<std::string>("version");
-    std::string first_app_name;
+    Manifest manifest;
+
+    manifest.name = pt.get<std::string>("name");
+    manifest.version = pt.get<std::string>("version");
+    manifest.removable = pt.get<bool>("_removable");
 
     BOOST_FOREACH(ptree::value_type &sv, pt.get_child("hooks"))
     {
         // FIXME: "primary app" for a package is not defined, we just
         // use first one here:
-        first_app_name = sv.first;
+        manifest.first_app_name = sv.first;
         break;
     }
-    qDebug() << "adding manifest: " << name.c_str() << version.c_str() << first_app_name.c_str();
-
-    Manifest manifest(name, version, first_app_name);
+    qDebug() << "adding manifest: " << manifest.name.c_str() << manifest.version.c_str() << manifest.first_app_name.c_str();
 
     return manifest;
 }
 
 void Interface::get_manifests(std::function<void(ManifestList, ManifestError)> callback)
 {
-    QSharedPointer<QProcess> process(new QProcess());
-    typedef void(QProcess::*QProcessFinished)(int, QProcess::ExitStatus);
-    typedef void(QProcess::*QProcessError)(QProcess::ProcessError);
-    QObject::connect(process.data(),
-                     static_cast<QProcessFinished>(&QProcess::finished),
-                     [callback, process](int code, QProcess::ExitStatus /*status*/) {
-                         qDebug() << "manifest command finished with exit code:" << code;
-                         try {
-                             auto data = process.data()->readAllStandardOutput().data();
-                             ManifestList manifests = manifest_list_from_json(data);
-                             qDebug() << "calling back ";
-                             callback(manifests, ManifestError::NoError);
-                         }
-                         catch ( ... ) {
-                             callback(ManifestList(), ManifestError::ParseError);
-                         }
-                     } );
-
-    QObject::connect(process.data(),
-                     static_cast<QProcessError>(&QProcess::error),
-                     [callback, process](QProcess::ProcessError error) {
-                         qCritical() << "error running command:" << error;
-                         callback(ManifestList(), ManifestError::CallError);
-                     } );
-
     std::string command = "click list --manifest";
     qDebug() << "Running command:" << command.c_str();
-    process->start(command.c_str());
+    run_process(command, [callback](int code, const std::string& stdout_data, const std::string&) {
+        if (code == 0) {
+            try {
+                ManifestList manifests = manifest_list_from_json(stdout_data);
+                callback(manifests, ManifestError::NoError);
+            } catch (...) {
+                callback(ManifestList(), ManifestError::ParseError);
+            }
+        } else {
+            callback(ManifestList(), ManifestError::CallError);
+        }
+    });
 }
 
 void Interface::get_manifest_for_app(const std::string &app_id,
                                      std::function<void(Manifest, ManifestError)> callback)
 {
-    QSharedPointer<QProcess> process(new QProcess());
-    typedef void(QProcess::*QProcessFinished)(int, QProcess::ExitStatus);
-    typedef void(QProcess::*QProcessError)(QProcess::ProcessError);
-    QObject::connect(process.data(),
-                     static_cast<QProcessFinished>(&QProcess::finished),
-                     [callback, process](int code, QProcess::ExitStatus /*status*/) {
-                         qDebug() << "manifest command finished with exit code:" << code;
-                         try {
-                             auto data = process.data()->readAllStandardOutput().data();
-                             Manifest manifest = manifest_from_json(data);
-                             qDebug() << "calling back ";
-                             callback(manifest, ManifestError::NoError);
-                         }
-                         catch ( ... ) {
-                             callback(Manifest(), ManifestError::ParseError);
-                         }
-                     } );
-
-    QObject::connect(process.data(),
-                     static_cast<QProcessError>(&QProcess::error),
-                     [callback, process](QProcess::ProcessError error) {
-                         qCritical() << "error running command:" << error;
-                         callback(Manifest(), ManifestError::CallError);
-                     } );
-
     std::string command = "click info " + app_id;
     qDebug() << "Running command:" << command.c_str();
-    process->start(command.c_str());
+    run_process(command, [callback](int code, const std::string& stdout_data, const std::string&) {
+        if (code == 0) {
+            try {
+                Manifest manifest = manifest_from_json(stdout_data);
+                callback(manifest, ManifestError::NoError);
+            } catch (...) {
+                callback(Manifest(), ManifestError::ParseError);
+            }
+        } else {
+            callback(Manifest(), ManifestError::CallError);
+        }
+    });
 }
 
 void Interface::get_dotdesktop_filename(const std::string &app_id,
@@ -398,4 +352,33 @@
     });
 }
 
+void Interface::run_process(const std::string& command,
+                            std::function<void(int code,
+                                               const std::string& stdout_data,
+                                               const std::string& stderr_data)> callback)
+{
+    QSharedPointer<QProcess> process(new QProcess());
+    typedef void(QProcess::*QProcessFinished)(int, QProcess::ExitStatus);
+    typedef void(QProcess::*QProcessError)(QProcess::ProcessError);
+    QObject::connect(process.data(),
+                     static_cast<QProcessFinished>(&QProcess::finished),
+                     [callback, process](int code, QProcess::ExitStatus /*status*/) {
+                         qDebug() << "command finished with exit code:" << code;
+                         auto data = process.data()->readAllStandardOutput().data();
+                         auto errors = process.data()->readAllStandardError().data();
+                         callback(code, data, errors);
+                     } );
+
+    QObject::connect(process.data(),
+                     static_cast<QProcessError>(&QProcess::error),
+                     [callback, process](QProcess::ProcessError error) {
+                         qCritical() << "error running command:" << error;
+                         auto data = process.data()->readAllStandardOutput().data();
+                         auto errors = process.data()->readAllStandardError().data();
+                         callback(process.data()->exitCode(), data, errors);
+                     } );
+
+    process->start(command.c_str());
+}
+
 } // namespace click

=== modified file 'scope/click/interface.h'
--- scope/click/interface.h	2014-04-08 20:04:45 +0000
+++ scope/click/interface.h	2014-05-02 16:27:07 +0000
@@ -59,6 +59,7 @@
     std::string name;
     std::string version;
     std::string first_app_name;
+    bool removable = false;
 };
 
 enum class ManifestError {NoError, CallError, ParseError};
@@ -71,6 +72,7 @@
 {
 public:
     Interface(const QSharedPointer<KeyFileLocator>& keyFileLocator);
+    Interface() = default;
     virtual ~Interface();
 
     virtual std::vector<Application> find_installed_apps(const QString& search_query);
@@ -79,29 +81,22 @@
 
     static bool is_icon_identifier(const std::string &icon_id);
     static std::string add_theme_scheme(const std::string &filename);
-    static void get_manifests(std::function<void(ManifestList, ManifestError)> callback);
-    static void get_manifest_for_app(const std::string &app_id, std::function<void(Manifest, ManifestError)> callback);
-    static void get_dotdesktop_filename(const std::string &app_id,
+    virtual void get_manifests(std::function<void(ManifestList, ManifestError)> callback);
+    virtual void get_manifest_for_app(const std::string &app_id, std::function<void(Manifest, ManifestError)> callback);
+    virtual void get_dotdesktop_filename(const std::string &app_id,
                                         std::function<void(std::string filename, ManifestError)> callback);
     constexpr static const char* ENV_SHOW_DESKTOP_APPS {"CLICK_SCOPE_SHOW_DESKTOP_APPS"};
     virtual bool is_visible_app(const unity::util::IniParser& keyFile);
     virtual bool show_desktop_apps();
+
+    virtual void run_process(const std::string& command,
+                             std::function<void(int code,
+                                                const std::string& stdout_data,
+                                                const std::string& stderr_data)> callback);
 private:
     QSharedPointer<KeyFileLocator> keyFileLocator;
 };
 
-class FrameworkLocator
-{
-public:
-    constexpr static const char* FRAMEWORKS_FOLDER {"/usr/share/click/frameworks/"};
-    constexpr static const char* FRAMEWORKS_PATTERN {"*.framework"};
-    constexpr static const int FRAMEWORKS_EXTENSION_LENGTH = 10; // strlen(".framework")
-
-    virtual std::vector<std::string> get_available_frameworks();
-protected:
-    virtual std::vector<std::string> list_folder(const std::string &folder, const std::string &pattern);
-};
-
 } // namespace click
 
 #endif // CLICK_INTERFACE_H

=== added file 'scope/click/package.cpp'
--- scope/click/package.cpp	1970-01-01 00:00:00 +0000
+++ scope/click/package.cpp	2014-05-02 16:27:07 +0000
@@ -0,0 +1,237 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include <sstream>
+
+#include "application.h"
+#include "package.h"
+
+namespace click
+{
+
+QDebug operator<< (QDebug d, const std::string &s) {
+    d << QString::fromStdString(s);
+    return d;
+}
+
+bool operator==(const Package& lhs, const Package& rhs) {
+    return lhs.name == rhs.name &&
+            lhs.title == rhs.title &&
+            lhs.price == rhs.price &&
+            lhs.icon_url == rhs.icon_url;
+}
+
+bool operator==(const PackageDetails& lhs, const PackageDetails& rhs) {
+    return lhs.package == rhs.package &&
+            lhs.description == rhs.description &&
+            lhs.download_url == rhs.download_url &&
+            lhs.rating == rhs.rating &&
+            // TODO: keywords should be a list of strings
+            lhs.keywords == rhs.keywords &&
+            lhs.terms_of_service == rhs.terms_of_service &&
+            lhs.license == rhs.license &&
+            lhs.publisher == rhs.publisher &&
+            lhs.main_screenshot_url == rhs.main_screenshot_url &&
+            // TODO: more_screenshots_urls should be a list of strings
+            lhs.more_screenshots_urls == rhs.more_screenshots_urls &&
+            // TODO: binary_filesize should be a int/long
+            lhs.binary_filesize == rhs.binary_filesize &&
+            lhs.version == rhs.version &&
+            lhs.framework == rhs.framework;
+}
+
+PackageList package_list_from_json(const std::string& json)
+{
+    std::istringstream is(json);
+
+    PackageList pl;
+
+    json::Reader reader;
+    json::Value root;
+
+    if (!reader.parse(json, root)) {
+        throw std::runtime_error(reader.getFormattedErrorMessages());
+    }
+
+    for (uint i = 0; i < root.size(); i++)
+    {
+        Package p;
+        json::Value item = root[i];
+        p.name = item[Package::JsonKeys::name].asString();
+        p.title = item[Package::JsonKeys::title].asString();
+        p.price = item[Package::JsonKeys::price].asDouble();
+        p.icon_url = item[Package::JsonKeys::icon_url].asString();
+        p.url = item[Package::JsonKeys::resource_url].asString();
+        pl.push_back(p);
+    }
+    return pl;
+}
+
+PackageDetails PackageDetails::from_json(const std::string &json)
+{
+    PackageDetails details;
+    try
+    {
+        json::Reader reader;
+        json::Value root;
+
+        if (!reader.parse(json, root))
+            throw std::runtime_error(reader.getFormattedErrorMessages());
+
+        // Mandatory details go here. That is, asString() will throw as we
+        // do not provide a default value if a value with the given key does not exist.
+        details.package.name = root[Package::JsonKeys::name].asString();
+        details.package.title = root[Package::JsonKeys::title].asString();
+        details.package.icon_url = root[Package::JsonKeys::icon_url].asString();
+        details.package.price = root[Package::JsonKeys::price].asDouble();
+        details.description = root[JsonKeys::description].asString();
+        details.download_url = root[JsonKeys::download_url].asString();
+        details.license = root[JsonKeys::license].asString();
+
+        // Optional details go here.
+        if (root[JsonKeys::version].isString())
+            details.version = root[JsonKeys::version].asString();
+
+        if (root[JsonKeys::rating].isNumeric())
+            details.rating = root[JsonKeys::rating].asDouble();
+
+        if (root[JsonKeys::keywords].isString())
+            details.keywords = root[JsonKeys::keywords].asString();
+
+        if (root[JsonKeys::terms_of_service].isString())
+            details.terms_of_service = root[JsonKeys::terms_of_service].asString();
+
+        if (root[JsonKeys::publisher].isString())
+            details.publisher = root[JsonKeys::publisher].asString();
+
+        if (root[JsonKeys::main_screenshot_url].isString())
+            details.main_screenshot_url = root[JsonKeys::main_screenshot_url].asString();
+
+        auto screenshots = root[JsonKeys::more_screenshot_urls];
+
+        for (uint i = 0; i < screenshots.size(); i++)
+        {
+            auto scr = screenshots[i].asString();
+            // more_screenshot_urls may contain main_screenshot_url, if so, skip it
+            if (scr != details.main_screenshot_url)
+            {
+                details.more_screenshots_urls.push_back(scr);
+            }
+        }
+
+        if (root[JsonKeys::binary_filesize].isIntegral())
+            details.binary_filesize = root[JsonKeys::binary_filesize].asUInt64();
+
+        if (root[JsonKeys::framework].isString())
+            details.framework = root[JsonKeys::framework].asString();
+
+    } catch(const std::exception& e)
+    {
+        std::cerr << "PackageDetails::loadJson: Exception thrown while decoding JSON: " << e.what() << std::endl;
+    } catch(...)
+    {
+        std::cerr << "PackageDetails::loadJson: Exception thrown while decoding JSON." << std::endl;
+    }
+
+    return details;
+}
+
+std::string print_string_if_not_empty(const std::string& s)
+{
+
+    return s.empty() ? "n/a" : s;
+}
+
+std::string print_list_if_not_empty(const std::list<std::string>& li)
+{
+    std::stringstream s;
+    s << "[";
+    if (!li.empty())
+    {
+        auto it = li.begin();
+        s << print_string_if_not_empty(*it);
+        ++it;
+        while (it != li.end())
+        {
+            s << ", " << print_string_if_not_empty(*it);
+            ++it;
+        }
+    }
+    s << "]";
+    return s.str();
+}
+
+std::ostream& operator<<(std::ostream& out, const click::PackageDetails& details)
+{
+    out << "("
+        << print_string_if_not_empty(details.package.name) << ", "
+        << print_string_if_not_empty(details.package.title) << ", "
+        << print_string_if_not_empty(details.package.icon_url) << ", "
+        << print_string_if_not_empty(details.description) << ", "
+        << print_string_if_not_empty(details.download_url) << ", "
+        << details.rating << ", "
+        << print_string_if_not_empty(details.keywords) << ", "
+        << print_string_if_not_empty(details.terms_of_service) << ", "
+        << print_string_if_not_empty(details.license) << ", "
+        << print_string_if_not_empty(details.publisher) << ", "
+        << print_string_if_not_empty(details.main_screenshot_url) << ", "
+        << print_list_if_not_empty(details.more_screenshots_urls) << ", "
+        << details.binary_filesize << ", "
+        << print_string_if_not_empty(details.version) << ", "
+        << print_string_if_not_empty(details.framework)
+        << ")";
+
+    return out;
+}
+
+bool operator==(const Application& lhs, const Application& rhs) {
+    return lhs.name == rhs.name &&
+            lhs.title == rhs.title &&
+            lhs.description == rhs.description &&
+            lhs.main_screenshot == rhs.main_screenshot &&
+            lhs.icon_url == rhs.icon_url;
+}
+
+std::ostream& operator<<(std::ostream& out, const click::Application& app)
+{
+    out << "("
+        << print_string_if_not_empty(app.name) << ", "
+        << print_string_if_not_empty(app.title) << ", "
+        << app.price << ", "
+        << print_string_if_not_empty(app.icon_url) << ", "
+        << print_string_if_not_empty(app.url) << ", "
+        << print_string_if_not_empty(app.version) << ", "
+        << print_string_if_not_empty(app.description) << ", "
+        << print_string_if_not_empty(app.main_screenshot)
+        << ")";
+
+    return out;
+}
+
+} // namespace click

=== added file 'scope/click/package.h'
--- scope/click/package.h	1970-01-01 00:00:00 +0000
+++ scope/click/package.h	2014-05-02 16:27:07 +0000
@@ -0,0 +1,137 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef CLICK_PACKAGE_H
+#define CLICK_PACKAGE_H
+
+#include <string>
+#include <list>
+
+#include <json/json.h>
+
+
+namespace json = Json;
+
+namespace click {
+
+struct Package
+{
+    struct JsonKeys
+    {
+        JsonKeys() = delete;
+
+        constexpr static const char* name{"name"};
+        constexpr static const char* title{"title"};
+        constexpr static const char* price{"price"};
+        constexpr static const char* icon_url{"icon_url"};
+        constexpr static const char* resource_url{"resource_url"};
+    };
+
+    Package() = default;
+    Package(std::string name, std::string title, double price, std::string icon_url, std::string url) :
+        name(name),
+        title(title),
+        price(price),
+        icon_url(icon_url),
+        url(url)
+    {
+    }
+    Package(std::string name, std::string title, double price, std::string icon_url, std::string url, std::string version) :
+        name(name),
+        title(title),
+        price(price),
+        icon_url(icon_url),
+        url(url),
+        version(version)
+    {
+    }
+    virtual ~Package() = default;
+
+    std::string name; // formerly app_id
+    std::string title;
+    double price;
+    std::string icon_url;
+    std::string url;
+    std::string version;
+    void matches (std::string query, std::function<bool> callback);
+};
+
+typedef std::list<Package> PackageList;
+
+PackageList package_list_from_json(const std::string& json);
+
+struct PackageDetails
+{
+    struct JsonKeys
+    {
+        JsonKeys() = delete;
+
+        constexpr static const char* name{"name"};
+        constexpr static const char* title{"title"};
+        constexpr static const char* icon_url{"icon_url"};
+        constexpr static const char* description{"description"};
+        constexpr static const char* download_url{"download_url"};
+        constexpr static const char* rating{"rating"};
+        constexpr static const char* keywords{"keywords"};
+        constexpr static const char* terms_of_service{"terms_of_service"};
+        constexpr static const char* license{"license"};
+        constexpr static const char* publisher{"publisher"};
+        constexpr static const char* main_screenshot_url{"screenshot_url"};
+        constexpr static const char* more_screenshot_urls{"screenshot_urls"};
+        constexpr static const char* binary_filesize{"binary_filesize"};
+        constexpr static const char* version{"version"};
+        constexpr static const char* framework{"framework"};
+    };
+
+    static PackageDetails from_json(const std::string &json);
+
+    Package package;
+
+    std::string description;
+    std::string download_url;
+    double rating;
+    std::string keywords;
+    std::string terms_of_service;
+    std::string license;
+    std::string publisher;
+    std::string main_screenshot_url;
+    std::list<std::string> more_screenshots_urls;
+    json::Value::UInt64 binary_filesize;
+    std::string version;
+    std::string framework;
+};
+
+std::ostream& operator<<(std::ostream& out, const PackageDetails& details);
+
+bool operator==(const Package& lhs, const Package& rhs);
+bool operator==(const PackageDetails& lhs, const PackageDetails& rhs);
+
+} // namespace click
+
+#endif // CLICK_PACKAGE_H

=== modified file 'scope/click/preview.cpp'
--- scope/click/preview.cpp	2014-04-10 18:19:33 +0000
+++ scope/click/preview.cpp	2014-05-02 16:27:07 +0000
@@ -27,6 +27,8 @@
  * files in the program, then also delete it here.
  */
 
+#include "application.h"
+#include "interface.h"
 #include "preview.h"
 #include "qtbridge.h"
 #include "download-manager.h"
@@ -42,40 +44,110 @@
 #include <iostream>
 #include <sstream>
 
+#include "interface.h"
 #include "click-i18n.h"
 
 namespace click {
 
 // Preview base class
 
-Preview::Preview(const unity::scopes::Result& result)
+Preview::Preview(const unity::scopes::Result& result,
+                 const unity::scopes::ActionMetadata& metadata,
+                 const QSharedPointer<click::web::Client>& client,
+                 const QSharedPointer<click::network::AccessManager>& nam)
+{
+    strategy.reset(choose_strategy(result, metadata, client, nam));
+}
+
+PreviewStrategy* Preview::choose_strategy(const unity::scopes::Result &result,
+                                          const unity::scopes::ActionMetadata &metadata,
+                                          const QSharedPointer<web::Client> &client,
+                                          const QSharedPointer<click::network::AccessManager>& nam)
+{
+    if (metadata.scope_data().which() != scopes::Variant::Type::Null) {
+        auto metadict = metadata.scope_data().get_dict();
+
+        if (metadict.count(click::Preview::Actions::DOWNLOAD_FAILED) != 0) {
+            return new DownloadErrorPreview(result);
+        } else if (metadict.count(click::Preview::Actions::DOWNLOAD_COMPLETED) != 0  ||
+                   metadict.count(click::Preview::Actions::CLOSE_PREVIEW) != 0) {
+            qDebug() << "in Scope::preview(), metadata has download_completed="
+                     << metadict.count(click::Preview::Actions::DOWNLOAD_COMPLETED)
+                     << " and close_preview="
+                     << metadict.count(click::Preview::Actions::CLOSE_PREVIEW);
+
+            return new InstalledPreview(result, metadata, client);
+        } else if (metadict.count("action_id") != 0  && metadict.count("download_url") != 0) {
+            std::string action_id = metadict["action_id"].get_string();
+            std::string download_url = metadict["download_url"].get_string();
+            if (action_id == click::Preview::Actions::INSTALL_CLICK) {
+                return new InstallingPreview(download_url, result, client, nam);
+            } else {
+                qWarning() << "unexpected action id " << QString::fromStdString(action_id)
+                           << " given with download_url" << QString::fromStdString(download_url);
+                return new UninstalledPreview(result, client);
+            }
+        } else if (metadict.count(click::Preview::Actions::UNINSTALL_CLICK) != 0) {
+            return new UninstallConfirmationPreview(result);
+        } else if (metadict.count(click::Preview::Actions::CONFIRM_UNINSTALL) != 0) {
+            return new UninstallingPreview(result, client);
+        } else if (metadict.count(click::Preview::Actions::RATED) != 0) {
+            return new InstalledPreview(result, metadata, client);
+        } else {
+            qWarning() << "preview() called with unexpected metadata. returning uninstalled preview";
+            return new UninstalledPreview(result, client);
+        }
+    } else {
+        // metadata.scope_data() is Null, so we return an appropriate "default" preview:
+        if (result["installed"].get_bool() == true) {
+            return new InstalledPreview(result, metadata, client);
+        } else {
+            return new UninstalledPreview(result, client);
+        }
+    }
+
+}
+
+void Preview::cancelled()
+{
+    strategy->cancelled();
+}
+
+void Preview::run(const unity::scopes::PreviewReplyProxy &reply)
+{
+    strategy->run(reply);
+}
+
+PreviewStrategy::PreviewStrategy(const unity::scopes::Result& result)
     : result(result)
 {
 }
 
-Preview::Preview(const unity::scopes::Result& result,
+PreviewStrategy::PreviewStrategy(const unity::scopes::Result& result,
                  const QSharedPointer<click::web::Client>& client) :
     result(result),
+    client(client),
     index(new click::Index(client)),
     reviews(new click::Reviews(client))
 {
 }
 
-Preview::~Preview()
+PreviewStrategy::~PreviewStrategy()
 {
 }
 
-void Preview::cancelled()
+void PreviewStrategy::cancelled()
 {
     index_operation.cancel();
     reviews_operation.cancel();
+    submit_operation.cancel();
 }
 
 
 // TODO: error handling - once get_details provides errors, we can
 // return them from populateDetails and check them in the calling code
 // to decide whether to show error widgets. see bug LP: #1289541
-void Preview::populateDetails(std::function<void(const click::PackageDetails& details)> details_callback,
+void PreviewStrategy::populateDetails(std::function<void(const click::PackageDetails& details)> details_callback,
                               std::function<void(const click::ReviewList&,
                                                     click::Reviews::Error)> reviews_callback)
 {
@@ -96,7 +168,7 @@
         // I think this should not be required when we switch the click::Index over
         // to using the Qt bridge. With that, the qt dependency becomes an implementation detail
         // and code using it does not need to worry about threading/event loop topics.
-        qt::core::world::enter_with_task([this, details_callback, reviews_callback, app_name](qt::core::world::Environment&)
+        qt::core::world::enter_with_task([this, details_callback, reviews_callback, app_name]()
             {
                 index_operation = index->get_details(app_name, [this, app_name, details_callback, reviews_callback](PackageDetails details, click::Index::Error error){
                     if(error == click::Index::Error::NoError) {
@@ -104,7 +176,12 @@
                         details_callback(details);
                     } else {
                         qDebug() << "Error getting details for:" << app_name.c_str();
-                        // TODO: handle error getting details
+                        click::PackageDetails details;
+                        details.package.title = result.title();
+                        details.package.icon_url = result.art();
+                        details.description = result["description"].get_string();
+                        details.main_screenshot_url = result["main_screenshot"].get_string();
+                        details_callback(details);
                     }
                     reviews_operation = reviews->fetch_reviews(app_name,
                                                                reviews_callback);
@@ -113,7 +190,7 @@
     }
 }
 
-scopes::PreviewWidgetList Preview::headerWidgets(const click::PackageDetails& details)
+scopes::PreviewWidgetList PreviewStrategy::headerWidgets(const click::PackageDetails& details)
 {
     scopes::PreviewWidgetList widgets;
 
@@ -140,12 +217,9 @@
 
     scopes::PreviewWidget header("hdr", "header");
     header.add_attribute_value("title", scopes::Variant(details.package.title));
-    if (!details.description.empty())
+    if (!details.publisher.empty())
     {
-        std::stringstream ss(details.description);
-        std::string first_line;
-        if (std::getline(ss, first_line))
-            header.add_attribute_value("subtitle", scopes::Variant(first_line));
+        header.add_attribute_value("subtitle", scopes::Variant(details.publisher));
     }
     if (!details.package.icon_url.empty())
         header.add_attribute_value("mascot", scopes::Variant(details.package.icon_url));
@@ -154,7 +228,7 @@
     return widgets;
 }
 
-scopes::PreviewWidgetList Preview::descriptionWidgets(const click::PackageDetails& details)
+scopes::PreviewWidgetList PreviewStrategy::descriptionWidgets(const click::PackageDetails& details)
 {
     scopes::PreviewWidgetList widgets;
     if (details.description.empty())
@@ -169,7 +243,7 @@
     return widgets;
 }
 
-scopes::PreviewWidgetList Preview::reviewsWidgets(const click::ReviewList& reviewlist)
+scopes::PreviewWidgetList PreviewStrategy::reviewsWidgets(const click::ReviewList& reviewlist)
 {
     scopes::PreviewWidgetList widgets;
 
@@ -191,7 +265,7 @@
     return widgets;
 }
 
-scopes::PreviewWidgetList Preview::downloadErrorWidgets()
+scopes::PreviewWidgetList PreviewStrategy::downloadErrorWidgets()
 {
     return errorWidgets(scopes::Variant(_("Download Error")),
                         scopes::Variant(_("Download or install failed. Please try again.")),
@@ -199,18 +273,20 @@
                         scopes::Variant(_("Close")));
 }
 
-scopes::PreviewWidgetList Preview::loginErrorWidgets()
+scopes::PreviewWidgetList PreviewStrategy::loginErrorWidgets()
 {
     return errorWidgets(scopes::Variant(_("Login Error")),
                         scopes::Variant(_("Please log in to your Ubuntu One account.")),
                         scopes::Variant(click::Preview::Actions::OPEN_ACCOUNTS),
-                        scopes::Variant(_("Go to Accounts")));
+                        scopes::Variant(_("Go to Accounts")),
+                        scopes::Variant("settings:///system/online-accounts"));
 }
 
-scopes::PreviewWidgetList Preview::errorWidgets(const scopes::Variant& title,
+scopes::PreviewWidgetList PreviewStrategy::errorWidgets(const scopes::Variant& title,
                                                 const scopes::Variant& subtitle,
                                                 const scopes::Variant& action_id,
-                                                const scopes::Variant& action_label)
+                                                const scopes::Variant& action_label,
+                                                const scopes::Variant& uri)
 {
     scopes::PreviewWidgetList widgets;
 
@@ -221,7 +297,14 @@
 
     scopes::PreviewWidget buttons("buttons", "actions");
     scopes::VariantBuilder builder;
-    builder.add_tuple({ {"id", action_id}, {"label", action_label} });
+    if (uri.is_null())
+    {
+        builder.add_tuple({ {"id", action_id}, {"label", action_label} });
+    }
+    else
+    {
+        builder.add_tuple({ {"id", action_id}, {"label", action_label}, {"uri", uri} });
+    }
     buttons.add_attribute_value("actions", builder.end());
     widgets.push_back(buttons);
 
@@ -232,7 +315,7 @@
 // class DownloadErrorPreview
 
 DownloadErrorPreview::DownloadErrorPreview(const unity::scopes::Result &result)
-    : Preview(result)
+    : PreviewStrategy(result)
 {
 }
 
@@ -255,7 +338,7 @@
                                      const unity::scopes::Result &result,
                                      const QSharedPointer<click::web::Client>& client,
                                      const QSharedPointer<click::network::AccessManager> &nam)
-    : Preview(result, client), download_url(download_url),
+    : PreviewStrategy(result, client), download_url(download_url),
       downloader(new click::Downloader(nam))
 {
 }
@@ -317,8 +400,10 @@
 // class InstalledPreview
 
 InstalledPreview::InstalledPreview(const unity::scopes::Result& result,
+                                   const unity::scopes::ActionMetadata& metadata,
                                    const QSharedPointer<click::web::Client>& client)
-    : Preview(result, client)
+    : PreviewStrategy(result, client),
+      metadata(metadata)
 {
 }
 
@@ -328,50 +413,146 @@
 
 void InstalledPreview::run(unity::scopes::PreviewReplyProxy const& reply)
 {
-    populateDetails([this, reply](const PackageDetails &details){
-            reply->push(headerWidgets(details));
-            reply->push(installedActionButtonWidgets());
-            reply->push(descriptionWidgets(details));
-        },
-        [this, reply](const ReviewList& reviewlist,
-                      click::Reviews::Error error) {
-            if (error == click::Reviews::Error::NoError) {
-                reply->push(reviewsWidgets(reviewlist));
-            } else {
-                qDebug() << "There was an error getting reviews for:" << result["name"].get_string().c_str();
-            }
-            reply->finished();
-        });
+    // Check if the user is submitting a rating, so we can submit it.
+    Review review;
+    review.rating = 0;
+    // We use a try/catch here, as scope_data() can be a dict, but not have
+    // the values we need, which will result in an exception thrown. 
+    try {
+        auto metadict = metadata.scope_data().get_dict();
+        review.rating = metadict["rating"].get_int();
+        review.review_text = metadict["review"].get_string();
+    } catch(...) {
+        // Do nothing as we are not submitting a review.
+    }
+
+    // Get the removable flag from the click manifest.
+    bool removable = false;
+    std::promise<bool> manifest_promise;
+    std::future<bool> manifest_future = manifest_promise.get_future();
+    std::string app_name = result["name"].get_string();
+    if (!app_name.empty()) {
+        qt::core::world::enter_with_task([&]() {
+            click::Interface().get_manifest_for_app(app_name,
+                [&](Manifest manifest, ManifestError error) {
+                    qDebug() << "Got manifest for:" << app_name.c_str();
+                    removable = manifest.removable;
+
+                    // Fill in required data about the package being reviewed.
+                    review.package_name = manifest.name;
+                    review.package_version = manifest.version;
+
+                    if (error != click::ManifestError::NoError) {
+                        qDebug() << "There was an error getting the manifest for:" << app_name.c_str();
+                    }
+                    manifest_promise.set_value(true);
+            });
+        });
+        manifest_future.get();
+        if (review.rating > 0) {
+            std::promise<bool> submit_promise;
+            std::future<bool> submit_future = submit_promise.get_future();
+            qt::core::world::enter_with_task([this, review, &submit_promise]() {
+                    QSharedPointer<click::CredentialsService> sso(new click::CredentialsService());
+                    client->setCredentialsService(sso);
+                    submit_operation = reviews->submit_review(review,
+                                                              [&submit_promise](click::Reviews::Error){
+                                                                  // TODO: Need to handle errors properly.
+                                                                  submit_promise.set_value(true);
+                                                              });
+                });
+            submit_future.get();
+        }
+    }
+    getApplicationUri([this, reply, removable, app_name, &review](const std::string& uri) {
+            populateDetails([this, reply, uri, removable, app_name, &review](const PackageDetails &details){
+                reply->push(headerWidgets(details));
+                reply->push(createButtons(uri, removable));
+                reply->push(descriptionWidgets(details));
+
+                // Hide the rating widget until #1314117 is fixed.
+                if (false && review.rating == 0 && removable) {
+                    scopes::PreviewWidgetList review_input;
+                    scopes::PreviewWidget rating("rating", "rating-input");
+                    rating.add_attribute_value("required", scopes::Variant("rating"));
+                    review_input.push_back(rating);
+                    reply->push(review_input);
+                }
+            },
+            [this, reply](const ReviewList& reviewlist,
+                          click::Reviews::Error error) {
+                if (error == click::Reviews::Error::NoError) {
+                    reply->push(reviewsWidgets(reviewlist));
+                } else {
+                    qDebug() << "There was an error getting reviews for:" << result["name"].get_string().c_str();
+                }
+                reply->finished();
+        });
+    });
 }
 
-scopes::PreviewWidgetList InstalledPreview::installedActionButtonWidgets()
+scopes::PreviewWidgetList InstalledPreview::createButtons(const std::string& uri,
+                                                          bool removable)
 {
     scopes::PreviewWidgetList widgets;
-
     scopes::PreviewWidget buttons("buttons", "actions");
     scopes::VariantBuilder builder;
-    builder.add_tuple(
+    if (!uri.empty())
+    {
+        builder.add_tuple(
         {
             {"id", scopes::Variant(click::Preview::Actions::OPEN_CLICK)},
-            {"label", scopes::Variant(_("Open"))}
+            {"label", scopes::Variant(_("Open"))},
+            {"uri", scopes::Variant(uri)}
         });
-    builder.add_tuple(
-        {
+    }
+    if (removable)
+    {
+        builder.add_tuple({
             {"id", scopes::Variant(click::Preview::Actions::UNINSTALL_CLICK)},
             {"label", scopes::Variant(_("Uninstall"))}
         });
-    buttons.add_attribute_value("actions", builder.end());
-    widgets.push_back(buttons);
-
+    }
+    if (!uri.empty() || removable) {
+        buttons.add_attribute_value("actions", builder.end());
+        widgets.push_back(buttons);
+    }
     return widgets;
 }
 
+void InstalledPreview::getApplicationUri(std::function<void(const std::string&)> callback)
+{
+    std::string uri;
+    QString app_url = QString::fromStdString(result.uri());
+
+    // asynchronously get application uri based on app name, if the uri is not application://.
+    // this can happen if the app was just installed and we have its http uri from the Result.
+    if (!app_url.startsWith("application:///")) {
+        const std::string name = result["name"].get_string();
+        auto ft = qt::core::world::enter_with_task([this, name, callback] ()
+        {
+            click::Interface().get_dotdesktop_filename(name,
+                                          [callback] (std::string val, click::ManifestError error) {
+                                          std::string uri;
+                                          if (error == click::ManifestError::NoError) {
+                                              uri = "application:///" + val;
+                                          }
+                                          callback(uri);
+                                 }
+                );
+        });
+    } else {
+        uri = app_url.toStdString();
+        callback(uri);
+    }
+}
+
 
 // class PurchasingPreview
 
 PurchasingPreview::PurchasingPreview(const unity::scopes::Result& result,
                                      const QSharedPointer<click::web::Client>& client)
-    : Preview(result, client)
+    : PreviewStrategy(result, client)
 {
 }
 
@@ -400,7 +581,7 @@
 // class UninstallConfirmationPreview
 
 UninstallConfirmationPreview::UninstallConfirmationPreview(const unity::scopes::Result& result)
-    : Preview(result)
+    : PreviewStrategy(result)
 {
 }
 
@@ -439,7 +620,7 @@
 
 UninstalledPreview::UninstalledPreview(const unity::scopes::Result& result,
                                        const QSharedPointer<click::web::Client>& client)
-    : Preview(result, client)
+    : PreviewStrategy(result, client)
 {
 }
 
@@ -510,7 +691,7 @@
     package.title = result.title();
     package.name = result["name"].get_string();
     package.version = result["version"].get_string();
-    qt::core::world::enter_with_task([this, package] (qt::core::world::Environment& /*env*/)
+    qt::core::world::enter_with_task([this, package] ()
     {
         click::PackageManager manager;
         manager.uninstall(package, [&](int code, std::string stderr_content) {

=== modified file 'scope/click/preview.h'
--- scope/click/preview.h	2014-04-02 09:29:38 +0000
+++ scope/click/preview.h	2014-05-02 16:27:07 +0000
@@ -36,16 +36,26 @@
 #include "qtbridge.h"
 #include "reviews.h"
 
+#include <unity/scopes/ActionMetadata.h>
 #include <unity/scopes/PreviewQueryBase.h>
 #include <unity/scopes/PreviewWidget.h>
 #include <unity/scopes/Result.h>
+#include <unity/scopes/ScopeBase.h>
 
 namespace scopes = unity::scopes;
 
 namespace click {
 
+class PreviewStrategy;
+
 class Preview : public unity::scopes::PreviewQueryBase
 {
+protected:
+    std::unique_ptr<PreviewStrategy> strategy;
+    PreviewStrategy* choose_strategy(const unity::scopes::Result& result,
+                                     const unity::scopes::ActionMetadata& metadata,
+                                     const QSharedPointer<web::Client> &client,
+                                     const QSharedPointer<click::network::AccessManager>& nam);
 public:
     struct Actions
     {
@@ -63,17 +73,31 @@
         constexpr static const char* CONFIRM_UNINSTALL{"confirm_uninstall"};
         constexpr static const char* CLOSE_PREVIEW{"close_preview"};
         constexpr static const char* OPEN_ACCOUNTS{"open_accounts"};
+        constexpr static const char* RATED{"rated"};
     };
 
     Preview(const unity::scopes::Result& result);
     Preview(const unity::scopes::Result& result,
-            const QSharedPointer<click::web::Client>& client);
-
-    virtual ~Preview();
-
+            const unity::scopes::ActionMetadata& metadata,
+            const QSharedPointer<click::web::Client>& client,
+            const QSharedPointer<click::network::AccessManager>& nam);
     // From unity::scopes::PreviewQuery
     void cancelled() override;
-    virtual void run(unity::scopes::PreviewReplyProxy const& reply) override = 0;
+    virtual void run(unity::scopes::PreviewReplyProxy const& reply) override;
+};
+
+class PreviewStrategy
+{
+public:
+
+    PreviewStrategy(const unity::scopes::Result& result);
+    PreviewStrategy(const unity::scopes::Result& result,
+            const QSharedPointer<click::web::Client>& client);
+
+    virtual ~PreviewStrategy();
+
+    virtual void cancelled();
+    virtual void run(unity::scopes::PreviewReplyProxy const& reply) = 0;
 
 protected:
     virtual void populateDetails(std::function<void(const PackageDetails &)> details_callback,
@@ -87,15 +111,18 @@
     virtual scopes::PreviewWidgetList errorWidgets(const scopes::Variant& title,
                                                    const scopes::Variant& subtitle,
                                                    const scopes::Variant& action_id,
-                                                   const scopes::Variant& action_label);
+                                                   const scopes::Variant& action_label,
+                                                   const scopes::Variant& action_uri = scopes::Variant::null());
     scopes::Result result;
+    QSharedPointer<click::web::Client> client;
     QSharedPointer<click::Index> index;
     click::web::Cancellable index_operation;
     QSharedPointer<click::Reviews> reviews;
     click::web::Cancellable reviews_operation;
+    click::web::Cancellable submit_operation;
 };
 
-class DownloadErrorPreview : public Preview
+class DownloadErrorPreview : public PreviewStrategy
 {
 public:
     DownloadErrorPreview(const unity::scopes::Result& result);
@@ -105,7 +132,7 @@
     void run(unity::scopes::PreviewReplyProxy const& reply) override;
 };
 
-class InstallingPreview : public Preview
+class InstallingPreview : public PreviewStrategy
 {
 public:
     InstallingPreview(std::string const& download_url,
@@ -124,20 +151,27 @@
 
 };
 
-class InstalledPreview : public Preview
+class InstalledPreview : public PreviewStrategy
 {
 public:
     InstalledPreview(const unity::scopes::Result& result,
+                     const unity::scopes::ActionMetadata& metadata,
                      const QSharedPointer<click::web::Client>& client);
 
     virtual ~InstalledPreview();
 
     void run(unity::scopes::PreviewReplyProxy const& reply) override;
+
 protected:
-    virtual scopes::PreviewWidgetList installedActionButtonWidgets();
+    void getApplicationUri(std::function<void(const std::string&)> callback);
+
+private:
+    static scopes::PreviewWidgetList createButtons(const std::string& uri,
+                                                   bool removable);
+    scopes::ActionMetadata metadata;
 };
 
-class PurchasingPreview : public Preview
+class PurchasingPreview : public PreviewStrategy
 {
 public:
     PurchasingPreview(const unity::scopes::Result& result,
@@ -150,7 +184,7 @@
     virtual scopes::PreviewWidgetList purchasingWidgets(const PackageDetails &);
 };
 
-class UninstallConfirmationPreview : public Preview
+class UninstallConfirmationPreview : public PreviewStrategy
 {
 public:
     UninstallConfirmationPreview(const unity::scopes::Result& result);
@@ -161,7 +195,7 @@
 
 };
 
-class UninstalledPreview : public Preview
+class UninstalledPreview : public PreviewStrategy
 {
 public:
     UninstalledPreview(const unity::scopes::Result& result,

=== modified file 'scope/click/qtbridge.cpp'
--- scope/click/qtbridge.cpp	2014-02-07 11:14:48 +0000
+++ scope/click/qtbridge.cpp	2014-05-02 16:27:07 +0000
@@ -39,10 +39,6 @@
 {
 namespace world
 {
-Environment::Environment(QObject *parent) : QObject(parent)
-{
-}
-
 namespace detail
 {
 QEvent::Type qt_core_world_task_event_type()
@@ -51,28 +47,20 @@
     return event_type;
 }
 
-class Environment : public qt::core::world::Environment
-{
-public:
-    Environment(QObject* parent) : qt::core::world::Environment(parent)
-    {
-    }
-};
-
 class TaskEvent : public QEvent
 {
 public:
-    TaskEvent(const std::function<void(qt::core::world::Environment&)>& task)
+    TaskEvent(const std::function<void()>& task)
         : QEvent(qt_core_world_task_event_type()),
           task(task)
     {
     }
 
-    void run(qt::core::world::Environment& env)
+    void run()
     {
         try
         {
-            task(env);
+            task();
             promise.set_value();
         } catch(...)
         {
@@ -86,7 +74,7 @@
     }
 
 private:
-    std::function<void(qt::core::world::Environment&)> task;
+    std::function<void()> task;
     std::promise<void> promise;
 };
 
@@ -125,12 +113,6 @@
     return instance;
 }
 
-qt::core::world::Environment* environment()
-{
-    static detail::Environment* env = new detail::Environment(coreApplicationInstance());
-    return env;
-}
-
 bool TaskHandler::event(QEvent *e)
 {
     if (e->type() != qt_core_world_task_event_type())
@@ -139,7 +121,7 @@
     auto te = dynamic_cast<TaskEvent*>(e);
     if (te)
     {
-        te->run(*environment());
+        te->run();
         return true;
     }
 
@@ -160,9 +142,6 @@
     detail::task_handler()->moveToThread(
                 detail::coreApplicationInstance()->thread());
 
-    detail::environment()->moveToThread(
-                detail::coreApplicationInstance()->thread());
-
     // Signal to other worlds that we are good to go.
     ready();
 
@@ -174,14 +153,14 @@
 
 void destroy()
 {
-    enter_with_task([](qt::core::world::Environment&)
+    enter_with_task([]()
     {
         // We make sure that all tasks have completed before quitting the app.
         QEventLoopLocker locker;
     }).wait_for(std::chrono::seconds{1});
 }
 
-std::future<void> enter_with_task(const std::function<void(qt::core::world::Environment&)>& task)
+std::future<void> enter_with_task(const std::function<void()>& task)
 {
     QCoreApplication* instance = QCoreApplication::instance();
 

=== modified file 'scope/click/qtbridge.h'
--- scope/click/qtbridge.h	2014-04-17 13:03:18 +0000
+++ scope/click/qtbridge.h	2014-05-02 16:27:07 +0000
@@ -32,134 +32,6 @@
 {
 namespace world
 {
-// Forward declaration to allow for friend declaration in HeapAllocatedObject.
-class Environment;
-}
-}
-
-/**
- * @brief Models an object allocated on the heap in qt world, but pulled over
- * to this world to be passed on to tasks. Please note that compilation will
- * abort if QObject is not a base of T.
- *
- * One other important thing to note: The destrucotor will throw a std::runtime_error
- * if a HeapAllocatedObject has not been free'd in Qt world and does _not_ have a parent
- * assigned. In that case, the object would be leaked.
- *
- */
-template<typename T>
-class HeapAllocatedObject
-{
-public:
-    static_assert(
-            std::is_base_of<QObject, T>::value,
-            "HeapAllocatedObject<T> is only required to transport QObject"
-            " subclasses over the world boundary.");
-
-    /** Constructs an empty, invalid instance. */
-    HeapAllocatedObject() = default;
-
-    /** HeapAllocatedObjects, i.e., their shared state, can be copied. */
-    HeapAllocatedObject(const HeapAllocatedObject<T>& rhs) = default;
-
-    /** HeapAllocatedObjects, i.e., their shared state can be assigned. */
-    HeapAllocatedObject& operator=(const HeapAllocatedObject<T>& rhs) = default;
-
-    /** HeapAllocatedObjects, i.e., their shared state can be compared for equality. */
-    inline bool operator==(const HeapAllocatedObject<T>& rhs) const
-    {
-        return state == rhs.state || state->instance == rhs.state->instance;
-    }
-
-    /** Check if this object contains a valid instance. */
-    inline operator bool() const
-    {
-        return state && (state->instance != nullptr);
-    }
-
-private:
-    friend class qt::core::world::Environment;
-
-    struct Private
-    {
-        Private(T* instance) : instance(instance)
-        {
-        }
-
-        ~Private()
-        {
-            if (instance != nullptr && instance->parent() == nullptr)
-            {
-                std::cerr << "MEMORY LEAK: HeapAllocatedObject::Private::~Private: "
-                             "Giving up ownership on a QObject instance without a parent: "
-                          << std::string(qPrintable(instance->metaObject()->className()))
-                          << std::endl;
-                // We allow leaking a bit of memory here instead of crashing the scope
-            }
-        }
-
-        T* instance{nullptr};
-    };
-
-    HeapAllocatedObject(T* instance) : state(std::make_shared<Private>(instance))
-    {
-    }
-
-    std::shared_ptr<Private> state;
-};
-
-namespace core
-{
-namespace world
-{
-/**
- * @brief The Environment class models the environment in the Qt world
- * that tasks operate under.
- */
-class Environment : public QObject
-{
-    Q_OBJECT
-
-public:
-    /**
-     * @brief Allocates subclasses of a QObject in the Qt world to make sure
-     * thread assumptions are satisfied.
-     *
-     * @tparam Args Construction argument types to be passed to the class's c'tor.
-     * @param args Construction arguments to be passed to the class's c'tor.
-     */
-    template<typename T, typename... Args>
-    qt::HeapAllocatedObject<T> allocate(Args... args)
-    {
-        return qt::HeapAllocatedObject<T>{new T(args...)};
-    }
-
-    /**
-     * @brief Frees a previously allocated object in the Qt world.
-     * @param object The object to be freed.
-     */
-    template<typename T>
-    void free(const qt::HeapAllocatedObject<T>& object)
-    {
-        delete object.state->instance;
-        object.state->instance = nullptr;
-    }
-
-    /**
-     * @brief Provides access to the instance contained in the object handle.
-     * @param object The object containing the instance to be accessed.
-     * @return A pointer to an instance of T, or nullptr.
-     */
-    template<typename T>
-    T* resolve(const HeapAllocatedObject<T>& object)
-    {
-        return object.state->instance;
-    }
-
-protected:
-    Environment(QObject* parent);
-};
-
 /**
  * @brief Sets up the Qt core world and executes its event loop. Blocks until destroy() is called.
  * @param argc Number of arguments in argv.
@@ -179,7 +51,7 @@
  * @param task The task to be executed in the Qt core world.
  * @return A std::future that can be waited for to synchronize to the world's internal event loop.
  */
-std::future<void> enter_with_task(const std::function<void(Environment&)>& task);
+std::future<void> enter_with_task(const std::function<void()>& task);
 
 
 /**
@@ -188,16 +60,16 @@
  * @return A std::future that can be waited for to get hold of the result of the task.
  */
 template<typename T>
-inline std::future<T> enter_with_task_and_expect_result(const std::function<T(Environment&)>& task)
+inline std::future<T> enter_with_task_and_expect_result(const std::function<T()>& task)
 {
     std::shared_ptr<std::promise<T>> promise = std::make_shared<std::promise<T>>();
     std::future<T> future = promise->get_future();
 
-    auto t = [promise, task](Environment& env)
+    auto t = [promise, task]()
     {
         try
         {
-            promise->set_value(task(env));
+            promise->set_value(task());
         } catch(...)
         {
             promise->set_exception(std::current_exception());

=== modified file 'scope/click/query.cpp'
--- scope/click/query.cpp	2014-04-10 18:19:33 +0000
+++ scope/click/query.cpp	2014-05-02 16:27:07 +0000
@@ -27,6 +27,7 @@
  * files in the program, then also delete it here.
  */
 
+#include "application.h"
 #include "query.h"
 #include "qtbridge.h"
 #include "key_file_locator.h"
@@ -39,14 +40,6 @@
 #include <unity/scopes/SearchReply.h>
 #include <unity/scopes/SearchMetadata.h>
 
-#include<QJsonDocument>
-#include<QJsonArray>
-#include<QJsonObject>
-#include<QNetworkReply>
-#include<QNetworkRequest>
-#include<QProcess>
-#include<QStringList>
-#include<QUrl>
 #include<vector>
 #include<set>
 #include<sstream>
@@ -56,8 +49,6 @@
 namespace
 {
 
-
-
 std::string CATEGORY_APPS_DISPLAY = R"(
     {
         "schema-version" : 1,
@@ -94,159 +85,11 @@
     }
 )";
 
-QNetworkAccessManager* getNetworkAccessManager(qt::core::world::Environment& env)
-{
-    static qt::HeapAllocatedObject<QNetworkAccessManager> nam = env.allocate<QNetworkAccessManager>(&env);
-    return env.resolve(nam);
-}
-
-QString architectureFromDpkg()
-{
-    QString program("dpkg");
-    QStringList arguments;
-    arguments << "--print-architecture";
-    QProcess archDetector;
-    archDetector.start(program, arguments);
-    if(!archDetector.waitForFinished()) {
-        throw std::runtime_error("Architecture detection failed.");
-    }
-    auto output = archDetector.readAllStandardOutput();
-    auto ostr = QString::fromUtf8(output);
-    ostr.remove('\n');
-
-    return ostr;
-}
-
-const QString& architecture()
-{
-    static const QString arch{architectureFromDpkg()};
-    return arch;
-}
-
-class ReplyWrapper : public QObject
-{
-    Q_OBJECT
-
-public:
-    ReplyWrapper(QNetworkReply* reply,
-                 const scopes::SearchReplyProxy& replyProxy,
-                 const std::set<std::string>& installedApplications,
-                 const std::string& categoryTemplate,
-                 const QString& queryUri,
-                 QObject* parent)
-        : QObject(parent),
-          reply(reply),
-          replyProxy(replyProxy),
-          installedApplications(installedApplications),
-          renderer(categoryTemplate),
-          category(replyProxy->register_category("appstore", _("Available"), "", renderer)),
-          queryUrl(queryUri) {
-    }
-
-    void cancel()
-    {
-        reply->abort();
-    }
-
-public slots:
-    void downloadFinished(QNetworkReply *reply) {
-        // If the user types a search term, multiple queries are kicked off
-        // and we have to make sure that we only consider results from the query
-        // that this reply corresponds to.
-        if (reply->url() != queryUrl)
-            return;
-
-        // category might be null if the query got cancelled before the ReplyWrapper got created
-        // unlikely, but still possible.
-        if (!category)
-            return;
-
-        struct Scope
-        {
-            Scope(QNetworkReply* reply, ReplyWrapper* wrapper)
-                : reply(reply),
-                  wrapper(wrapper)
-            {
-            }
-
-            ~Scope()
-            {
-                reply->deleteLater();
-                wrapper->deleteLater();
-            }
-
-            QNetworkReply* reply;
-            ReplyWrapper* wrapper;
-        } scope(reply, this);
-
-        if (reply->error() != QNetworkReply::NoError)
-        {
-            std::cerr << __PRETTY_FUNCTION__ << ": Received network reply with error: "
-                      << reply->errorString().toStdString() << std::endl;
-            return;
-        }
-
-        try
-        {
-            QByteArray msg = reply->readAll();
-            QJsonParseError jsonParseError;
-            QJsonDocument doc = QJsonDocument::fromJson(msg, &jsonParseError);
-
-            if (jsonParseError.error != QJsonParseError::NoError)
-                throw std::runtime_error(
-                            "ReplyWrapper::onDownloadFinished: Cannot parse JSON from server response with " +
-                            jsonParseError.errorString().toStdString());
-
-            QJsonArray results = doc.array();
-
-            for(const auto &entry : results) {
-                if(not entry.isObject()) {
-                    // FIXME: write message about invalid JSON here.
-                    continue;
-                }
-                scopes::CategorisedResult res(category);
-                QJsonObject obj = entry.toObject();
-                std::string resourceUrl = obj[click::Query::JsonKeys::RESOURCE_URL].toString().toUtf8().data();
-                std::string title = obj[click::Query::JsonKeys::TITLE].toString().toUtf8().data();
-                std::string iconUrl = obj[click::Query::JsonKeys::ICON_URL].toString().toUtf8().data();
-                std::string name = obj[click::Query::JsonKeys::NAME].toString().toUtf8().data();
-
-                if (installedApplications.count(name) > 0)
-                    continue;
-
-                res.set_uri(queryUrl.toString().toUtf8().data());
-                res.set_title(title);
-                res.set_art(iconUrl);
-                res.set_dnd_uri(queryUrl.toString().toUtf8().data());
-                res[click::Query::ResultKeys::NAME] = name;
-                res[click::Query::ResultKeys::INSTALLED] = false;
-                res[click::Query::ResultKeys::DOWNLOAD_URL] = resourceUrl;
-                // FIXME at this point we should go through the rest of the fields
-                // and convert them.
-                replyProxy->push(res);
-            }
-        } catch(const std::exception& e)
-        {
-            std::cerr << __PRETTY_FUNCTION__ << ": Caught std::exception with: " << e.what() << std::endl;
-        } catch(...)
-        {
-            std::cerr << __PRETTY_FUNCTION__ << ": Caught exception" << std::endl;
-        }
-    }
-
-private:
-    QNetworkReply* reply;
-    scopes::SearchReplyProxy replyProxy;
-    std::set<std::string> installedApplications;
-    scopes::CategoryRenderer renderer;
-    scopes::Category::SCPtr category;
-    QUrl queryUrl;
-};
-}
-
-static void push_local_results(scopes::SearchReplyProxy const &replyProxy,
-                               std::vector<click::Application> const &apps,
-                               std::string categoryTemplate)
+}
+
+void click::Query::push_local_results(scopes::SearchReplyProxy const &replyProxy,
+                                      std::vector<click::Application> const &apps,
+                                      std::string &categoryTemplate)
 {
     scopes::CategoryRenderer rdr(categoryTemplate);
     auto cat = replyProxy->register_category("local", _("My apps"), "", rdr);
@@ -272,32 +115,32 @@
 
 struct click::Query::Private
 {
-    Private(const std::string& query, const scopes::SearchMetadata& metadata)
+    Private(const std::string& query, click::Index& index, const scopes::SearchMetadata& metadata)
         : query(query),
+          index(index),
           meta(metadata)
     {
     }
     std::string query;
+    click::Index& index;
     scopes::SearchMetadata meta;
-    qt::HeapAllocatedObject<ReplyWrapper> replyWrapper;
+    click::web::Cancellable search_operation;
 };
 
-click::Query::Query(std::string const& query, scopes::SearchMetadata const& metadata)
-    : impl(new Private(query, metadata))
+click::Query::Query(std::string const& query, click::Index& index, scopes::SearchMetadata const& metadata)
+    : impl(new Private(query, index, metadata))
 {
 }
 
 click::Query::~Query()
 {
+    qDebug() << "destroying search";
 }
 
 void click::Query::cancelled()
 {
-    qt::core::world::enter_with_task([=](qt::core::world::Environment& env)
-    {
-        if (impl->replyWrapper)
-            env.resolve(impl->replyWrapper)->cancel();
-    });
+    qDebug() << "cancelling search of" << QString::fromStdString(impl->query);
+    impl->search_operation.cancel();
 }
 
 namespace
@@ -310,16 +153,81 @@
     return iface;
 }
 
-QString frameworks_arg()
-{
-    std::stringstream frameworks;
-    for (auto f: click::FrameworkLocator().get_available_frameworks()) {
-        frameworks << ",framework:" << f;
+}
+
+bool click::Query::push_result(scopes::SearchReplyProxy const& searchReply, const scopes::CategorisedResult &res)
+{
+    return searchReply->push(res);
+}
+
+void click::Query::finished(const scopes::SearchReplyProxy &searchReply)
+{
+    searchReply->finished();
+}
+
+scopes::Category::SCPtr click::Query::register_category(const scopes::SearchReplyProxy &searchReply,
+                                                        const std::string &id,
+                                                        const std::string &title,
+                                                        const std::string &icon,
+                                                        const scopes::CategoryRenderer &renderer_template)
+{
+    return searchReply->register_category(id, title, icon, renderer_template);
+}
+
+void click::Query::run_under_qt(const std::function<void ()> &task)
+{
+    qt::core::world::enter_with_task([task]() {
+        task();
+    });
+}
+
+void click::Query::add_available_apps(scopes::SearchReplyProxy const& searchReply,
+                                      const std::set<std::string>& locallyInstalledApps,
+                                      const std::string& categoryTemplate)
+{
+    scopes::CategoryRenderer categoryRenderer(categoryTemplate);
+    auto category = register_category(searchReply, "appstore", _("Available"), "", categoryRenderer);
+    if (!category) {
+        // category might be null when the underlying query got cancelled.
+        qDebug() << "category is null";
+        return;
     }
-    return QString::fromStdString(frameworks.str());
-}
-
-}
+
+    run_under_qt([=]()
+    {
+        qDebug() << "starting search of" << QString::fromStdString(impl->query);
+
+        impl->search_operation = impl->index.search(impl->query, [=](PackageList packages){
+            qDebug("callback here");
+            foreach (auto p, packages) {
+                qDebug() << "pushing result" << QString::fromStdString(p.name);
+                try {
+                    scopes::CategorisedResult res(category);
+                    if (locallyInstalledApps.count(p.name) > 0) {
+                        qDebug() << "already installed" << QString::fromStdString(p.name);
+                        continue;
+                    }
+                    res.set_title(p.title);
+                    res.set_art(p.icon_url);
+                    res.set_uri(p.url);
+                    res[click::Query::ResultKeys::NAME] = p.name;
+                    res[click::Query::ResultKeys::INSTALLED] = false;
+
+                    this->push_result(searchReply, res);
+                } catch(const std::exception& e){
+                    qDebug() << "PackageDetails::loadJson: Exception thrown while decoding JSON: " << e.what() ;
+                } catch(...){
+                    qDebug() << "no reason to catch";
+                }
+            }
+            qDebug() << "search completed";
+            this->finished(searchReply);
+        });
+
+    });
+
+}
+
 void click::Query::run(scopes::SearchReplyProxy const& searchReply)
 {
     QString query = QString::fromStdString(impl->query);
@@ -336,8 +244,9 @@
         categoryTemplate);
 
     std::set<std::string> locallyInstalledApps;
-    for(const auto& app : localResults)
+    for(const auto& app : localResults) {
         locallyInstalledApps.insert(app.name);
+    }
 
     static const std::string no_net_hint("no-internet");
     if (impl->meta.contains_hint(no_net_hint))
@@ -347,27 +256,10 @@
         {
             return;
         }
+
     }
-    
-    qt::core::world::enter_with_task([=](qt::core::world::Environment& env)
-    {
-        static const QString queryPattern(
-                    "https://search.apps.ubuntu.com/api/v1/search?q=%1"
-                    "%2,architecture:%3");
-
-        QString queryUri = queryPattern.arg(QString::fromUtf8(impl->query.c_str()))
-                .arg(frameworks_arg()).arg(architecture());
-
-        auto nam = getNetworkAccessManager(env);
-        auto networkReply = nam->get(QNetworkRequest(QUrl(queryUri)));
-
-        impl->replyWrapper = env.allocate<ReplyWrapper>(networkReply, searchReply, locallyInstalledApps, categoryTemplate, queryUri, &env);
-        auto rw = env.resolve(impl->replyWrapper);
-
-        QObject::connect(
-                    nam, &QNetworkAccessManager::finished,
-                    rw, &ReplyWrapper::downloadFinished);
-    });
+
+    add_available_apps(searchReply, locallyInstalledApps, categoryTemplate);
 }
 
 #include "query.moc"

=== modified file 'scope/click/query.h'
--- scope/click/query.h	2014-04-07 16:41:36 +0000
+++ scope/click/query.h	2014-05-02 16:27:07 +0000
@@ -36,9 +36,14 @@
 namespace scopes = unity::scopes;
 
 #include <QSharedPointer>
+#include <set>
 
 namespace click
 {
+
+class Application;
+class Index;
+
 class Query : public scopes::SearchQueryBase
 {
 public:
@@ -64,13 +69,27 @@
         constexpr static const char* VERSION{"version"};
     };
 
-    Query(std::string const& query, scopes::SearchMetadata const& metadata);
-    ~Query();
+    Query(std::string const& query, click::Index& index, scopes::SearchMetadata const& metadata);
+    virtual ~Query();
 
     virtual void cancelled() override;
 
     virtual void run(scopes::SearchReplyProxy const& reply) override;
 
+protected:
+    virtual void add_available_apps(const scopes::SearchReplyProxy &searchReply, const std::set<std::string> &locallyInstalledApps, const std::string &category);
+    virtual bool push_result(const scopes::SearchReplyProxy &searchReply, scopes::CategorisedResult const& res);
+    virtual void finished(const scopes::SearchReplyProxy &searchReply);
+    virtual void push_local_results(scopes::SearchReplyProxy const &replyProxy,
+                                    std::vector<click::Application> const &apps,
+                                    std::string& categoryTemplate);
+    virtual scopes::Category::SCPtr register_category(scopes::SearchReplyProxy const& searchReply,
+                                               std::string const& id,
+                                               std::string const& title,
+                                               std::string const& icon,
+                                               scopes::CategoryRenderer const& renderer_template);
+    virtual void run_under_qt(const std::function<void()> &task);
+
 private:
     struct Private;
     QSharedPointer<Private> impl;

=== modified file 'scope/click/reviews.cpp'
--- scope/click/reviews.cpp	2014-04-04 09:05:24 +0000
+++ scope/click/reviews.cpp	2014-05-02 16:27:07 +0000
@@ -27,12 +27,15 @@
  * files in the program, then also delete it here.
  */
 
-#include <stdlib.h>
+#include <cstdlib>
 
 #include <boost/property_tree/ptree.hpp>
 #include <boost/property_tree/json_parser.hpp>
 #include <boost/foreach.hpp>
 
+#include <json/value.h>
+#include <json/writer.h>
+
 #include "reviews.h"
 
 namespace click
@@ -123,11 +126,50 @@
     return click::web::Cancellable(response);
 }
 
+click::web::Cancellable Reviews::submit_review (const Review& review,
+                                                std::function<void(Error)> callback)
+{
+    std::map<std::string, std::string> headers({
+            {click::web::CONTENT_TYPE_HEADER, click::web::CONTENT_TYPE_JSON},
+                });
+    Json::Value root(Json::ValueType::objectValue);
+    root["package_name"] = review.package_name;
+    root["version"] = review.package_version;
+    root["rating"] = review.rating;
+    root["review_text"] = review.review_text;
+
+    root["arch_tag"] = click::Configuration().get_architecture();
+    // NOTE: We only use the base language code for reviews.
+    root["language"] = click::Configuration().get_language_base();
+
+    // NOTE: "summary" is a required field, but we don't have one. Use "".
+    root["summary"] = "";
+    
+    qDebug() << "Rating" << review.package_name.c_str() << review.rating;
+
+    QSharedPointer<click::web::Response> response = client->call
+        (get_base_url() + click::REVIEWS_API_PATH, "POST", true,
+         headers, Json::FastWriter().write(root), click::web::CallParams());
+
+    QObject::connect(response.data(), &click::web::Response::finished,
+                [=](QString) {
+                   qDebug() << "Review submitted for:" << review.package_name.c_str();
+                   callback(Error::NoError);
+                });
+    QObject::connect(response.data(), &click::web::Response::error,
+                [=](QString) {
+                    qCritical() << "Network error submitting a reviews for:" << review.package_name.c_str();
+                    callback(Error::NetworkError);
+                });
+
+    return click::web::Cancellable(response);
+}
+
 std::string Reviews::get_base_url ()
 {
     const char *env_url = getenv(REVIEWS_BASE_URL_ENVVAR.c_str());
     if (env_url != NULL) {
-        return env_url;;
+        return env_url;
     }
     return click::REVIEWS_BASE_URL;
 }

=== modified file 'scope/click/reviews.h'
--- scope/click/reviews.h	2014-03-27 15:03:56 +0000
+++ scope/click/reviews.h	2014-05-02 16:27:07 +0000
@@ -40,7 +40,7 @@
 namespace click
 {
 
-const std::string REVIEWS_BASE_URL_ENVVAR = "CLICK_REVIEWS_BASE_URL";
+const std::string REVIEWS_BASE_URL_ENVVAR = "U1_REVIEWS_BASE_URL";
 const std::string REVIEWS_BASE_URL = "https://reviews.ubuntu.com";
 const std::string REVIEWS_API_PATH = "/click/api/1.0/reviews/";
 const std::string REVIEWS_QUERY_ARGNAME = "package_name";
@@ -78,6 +78,8 @@
 
     click::web::Cancellable fetch_reviews (const std::string& package_name,
                                            std::function<void(ReviewList, Error)> callback);
+    click::web::Cancellable submit_review (const Review& review,
+                                           std::function<void(Error)> callback);
 
     static std::string get_base_url ();
 };

=== modified file 'scope/click/scope.cpp'
--- scope/click/scope.cpp	2014-04-10 18:19:33 +0000
+++ scope/click/scope.cpp	2014-05-02 16:27:07 +0000
@@ -34,9 +34,9 @@
 #include "network_access_manager.h"
 #include "key_file_locator.h"
 #include "interface.h"
+#include "scope_activation.h"
 
 #include <QSharedPointer>
-#include <url-dispatcher.h>
 
 #include "click-i18n.h"
 
@@ -45,34 +45,16 @@
 click::Interface& clickInterfaceInstance()
 {
     static QSharedPointer<click::KeyFileLocator> keyFileLocator(new click::KeyFileLocator());
-    static click::Interface iface(keyFileLocator);
-
+    static click::Interface iface(keyFileLocator);  
     return iface;
 }
 }
 
-class ScopeActivation : public unity::scopes::ActivationQueryBase
-{
-    unity::scopes::ActivationResponse activate() override
-    {
-        auto response = unity::scopes::ActivationResponse(status_);
-        response.set_scope_data(unity::scopes::Variant(hints_));
-        return response;
-    }
-
-public:
-    void setStatus(unity::scopes::ActivationResponse::Status status) { status_ = status; }
-    void setHint(std::string key, unity::scopes::Variant value) { hints_[key] = value; }
-private:
-    unity::scopes::ActivationResponse::Status status_ = unity::scopes::ActivationResponse::Status::ShowPreview;
-    unity::scopes::VariantMap hints_;
-};
-
 click::Scope::Scope()
 {
-    nam = QSharedPointer<click::network::AccessManager>(new click::network::AccessManager());
-    sso = QSharedPointer<click::CredentialsService>(new click::CredentialsService());
-    client = QSharedPointer<click::web::Client>(new click::web::Client(nam, sso));
+    nam.reset(new click::network::AccessManager());
+    client.reset(new click::web::Client(nam));
+    index.reset(new click::Index(client));
 }
 
 click::Scope::~Scope()
@@ -106,89 +88,29 @@
 
 scopes::SearchQueryBase::UPtr click::Scope::search(unity::scopes::CannedQuery const& q, scopes::SearchMetadata const& metadata)
 {
-    return scopes::SearchQueryBase::UPtr(new click::Query(q.query_string(), metadata));
+    return scopes::SearchQueryBase::UPtr(new click::Query(q.query_string(), *index, metadata));
 }
 
 
 unity::scopes::PreviewQueryBase::UPtr click::Scope::preview(const unity::scopes::Result& result,
         const unity::scopes::ActionMetadata& metadata) {
     qDebug() << "Scope::preview() called.";
-    std::string action_id = "";
-    std::string download_url = "";
-
-    if (metadata.scope_data().which() != scopes::Variant::Type::Null) {
-        auto metadict = metadata.scope_data().get_dict();
-
-        if (metadict.count(click::Preview::Actions::DOWNLOAD_FAILED) != 0) {
-            return scopes::PreviewQueryBase::UPtr{new DownloadErrorPreview(result)};
-        } else if (metadict.count(click::Preview::Actions::DOWNLOAD_COMPLETED) != 0  ||
-                   metadict.count(click::Preview::Actions::CLOSE_PREVIEW) != 0) {
-            qDebug() << "in Scope::preview(), metadata has download_completed=" 
-                     << metadict.count(click::Preview::Actions::DOWNLOAD_COMPLETED)
-                     << " and close_preview=" 
-                     << metadict.count(click::Preview::Actions::CLOSE_PREVIEW);
-
-            return scopes::PreviewQueryBase::UPtr{new InstalledPreview(result, client)};
-        } else if (metadict.count("action_id") != 0  &&
-            metadict.count("download_url") != 0) {
-            action_id = metadict["action_id"].get_string();
-            download_url = metadict["download_url"].get_string();
-            if (action_id == click::Preview::Actions::INSTALL_CLICK) {
-                return scopes::PreviewQueryBase::UPtr{new InstallingPreview(download_url, result, client, nam)};
-            } else {
-                qWarning() << "unexpected action id " << QString::fromStdString(action_id)
-                           << " given with download_url" << QString::fromStdString(download_url);
-                return scopes::PreviewQueryBase::UPtr{new UninstalledPreview(result, client)};
-            }
-        } else if (metadict.count(click::Preview::Actions::UNINSTALL_CLICK) != 0) {
-            return scopes::PreviewQueryBase::UPtr{ new UninstallConfirmationPreview(result)};
-        } else if (metadict.count(click::Preview::Actions::CONFIRM_UNINSTALL) != 0) {
-            return scopes::PreviewQueryBase::UPtr{new UninstallingPreview(result, client)};
-        } else {
-            qWarning() << "preview() called with unexpected metadata. returning uninstalled preview";
-            return scopes::PreviewQueryBase::UPtr{new UninstalledPreview(result, client)};            
-        }
-    } else {
-        // metadata.scope_data() is Null, so we return an appropriate "default" preview:
-        if (result["installed"].get_bool() == true) {
-            return scopes::PreviewQueryBase::UPtr{new InstalledPreview(result, client)};
-        } else {
-            return scopes::PreviewQueryBase::UPtr{new UninstalledPreview(result, client)};
-        }
-    }
+    return scopes::PreviewQueryBase::UPtr{new click::Preview(result, metadata, client, nam)};
 }
 
-unity::scopes::ActivationQueryBase::UPtr click::Scope::perform_action(unity::scopes::Result const& result, unity::scopes::ActionMetadata const& metadata, std::string const& /* widget_id */, std::string const& action_id)
+unity::scopes::ActivationQueryBase::UPtr click::Scope::perform_action(unity::scopes::Result const& /* result */, unity::scopes::ActionMetadata const& metadata, std::string const& /* widget_id */, std::string const& action_id)
 {
     auto activation = new ScopeActivation();
     qDebug() << "perform_action called with action_id" << QString().fromStdString(action_id);
 
-    if (action_id == click::Preview::Actions::OPEN_CLICK) {
-        QString app_url = QString::fromStdString(result.uri());
-        if (!app_url.startsWith("application:///")) {
-            qt::core::world::enter_with_task([this, result] (qt::core::world::Environment& /*env*/)
-            {
-                clickInterfaceInstance().get_dotdesktop_filename(result["name"].get_string(),
-                     [] (std::string val, click::ManifestError error){
-                         if (error == click::ManifestError::NoError) {
-                             std::string uri = "application:///" + val;
-                             url_dispatch_send(uri.c_str() , NULL, NULL);
-                         }
-                     }
-                );
-            });
-            activation->setStatus(unity::scopes::ActivationResponse::Status::HideDash);
-        } else {
-            activation->setStatus(unity::scopes::ActivationResponse::Status::NotHandled);
-        }
-    } else if (action_id == click::Preview::Actions::INSTALL_CLICK) {
+    // note: OPEN_CLICK and OPEN_ACCOUNTS actions are handled directly by the Dash
+    if (action_id == click::Preview::Actions::INSTALL_CLICK) {
         std::string download_url = metadata.scope_data().get_dict()["download_url"].get_string();
         qDebug() << "the download url is: " << QString::fromStdString(download_url);
         activation->setHint("download_url", unity::scopes::Variant(download_url));
         activation->setHint("action_id", unity::scopes::Variant(action_id));
         qDebug() << "returning ShowPreview";
         activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
-
     } else if (action_id == click::Preview::Actions::DOWNLOAD_FAILED) {
         activation->setHint(click::Preview::Actions::DOWNLOAD_FAILED, unity::scopes::Variant(true));
         activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
@@ -204,9 +126,20 @@
     } else if (action_id == click::Preview::Actions::CONFIRM_UNINSTALL) {
         activation->setHint(click::Preview::Actions::CONFIRM_UNINSTALL, unity::scopes::Variant(true));
         activation->setStatus(unity::scopes::ActivationResponse::Status::ShowPreview);
-    } else if (action_id == click::Preview::Actions::OPEN_ACCOUNTS) {
-        std::string uri = "settings:///system/online-accounts";
-        url_dispatch_send(uri.c_str() , NULL, NULL);
+    } else if (action_id == click::Preview::Actions::RATED) {
+        scopes::VariantMap rating_info = metadata.scope_data().get_dict();
+        // Cast to int because widget gives us double, which is wrong.
+        int rating = ((int)rating_info["rating"].get_double());
+        std::string review_text = rating_info["review"].get_string();
+
+        // We have to get the values and then set them as hints here, to be
+        // able to pass them on to the Preview, which actually makes the
+        // call to submit.
+        activation->setHint("rating", scopes::Variant(rating));
+        activation->setHint("review", scopes::Variant(review_text));
+        activation->setHint(click::Preview::Actions::RATED,
+                            scopes::Variant(true));
+        activation->setStatus(scopes::ActivationResponse::Status::ShowPreview);
     }
     return scopes::ActivationQueryBase::UPtr(activation);
 }

=== modified file 'scope/click/scope.h'
--- scope/click/scope.h	2014-03-26 20:20:40 +0000
+++ scope/click/scope.h	2014-05-02 16:27:07 +0000
@@ -34,8 +34,8 @@
 #include <unity/scopes/QueryBase.h>
 #include <unity/scopes/ActivationQueryBase.h>
 
+#include "index.h"
 #include "network_access_manager.h"
-#include "ubuntuone_credentials.h"
 #include "webclient.h"
 
 namespace scopes = unity::scopes;
@@ -61,8 +61,8 @@
 
 private:
     QSharedPointer<click::network::AccessManager> nam;
-    QSharedPointer<click::CredentialsService> sso;
     QSharedPointer<click::web::Client> client;
+    QSharedPointer<click::Index> index;
 
     std::string installApplication(unity::scopes::Result const& result);
 };

=== added file 'scope/click/scope_activation.cpp'
--- scope/click/scope_activation.cpp	1970-01-01 00:00:00 +0000
+++ scope/click/scope_activation.cpp	2014-05-02 16:27:07 +0000
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include "scope_activation.h"
+#include <unity/scopes/ActivationResponse.h>
+
+unity::scopes::ActivationResponse click::ScopeActivation::activate()
+{
+    auto response = unity::scopes::ActivationResponse(status_);
+    response.set_scope_data(unity::scopes::Variant(hints_));
+    return response;
+}
+
+void click::ScopeActivation::setStatus(unity::scopes::ActivationResponse::Status status)
+{
+    status_ = status;
+}
+
+void click::ScopeActivation::setHint(std::string key, unity::scopes::Variant value)
+{
+    hints_[key] = value;
+}

=== added file 'scope/click/scope_activation.h'
--- scope/click/scope_activation.h	1970-01-01 00:00:00 +0000
+++ scope/click/scope_activation.h	2014-05-02 16:27:07 +0000
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#ifndef CLICK_SCOPE_ACTIVATION_H
+#define CLICK_SCOPE_ACTIVATION_H
+
+#include <unity/scopes/ActivationQueryBase.h>
+
+namespace click
+{
+
+class ScopeActivation : public unity::scopes::ActivationQueryBase
+{
+    unity::scopes::ActivationResponse activate() override;
+
+public:
+    void setStatus(unity::scopes::ActivationResponse::Status status);
+    void setHint(std::string key, unity::scopes::Variant value);
+
+private:
+    unity::scopes::ActivationResponse::Status status_ = unity::scopes::ActivationResponse::Status::ShowPreview;
+    unity::scopes::VariantMap hints_;
+};
+
+}
+
+#endif

=== modified file 'scope/click/webclient.cpp'
--- scope/click/webclient.cpp	2014-04-01 13:27:09 +0000
+++ scope/click/webclient.cpp	2014-05-02 16:27:07 +0000
@@ -28,9 +28,9 @@
  */
 
 #include <QBuffer>
-#include <QCoreApplication>
 #include <QDebug>
 
+#include "configuration.h"
 #include "webclient.h"
 #include "smartconnect.h"
 
@@ -49,22 +49,22 @@
 
 struct click::web::Client::Private
 {
-    Private(const QSharedPointer<click::network::AccessManager> nam,
-            const QSharedPointer<click::CredentialsService> sso)
-        : network_access_manager(nam),
-          sso(sso)
+    Private(const QSharedPointer<click::network::AccessManager> nam)
+        : network_access_manager(nam)
     {
     }
 
     QSharedPointer<click::network::AccessManager> network_access_manager;
     QSharedPointer<click::CredentialsService> sso;
+
+    void setCredentialsService(const QSharedPointer<click::CredentialsService>& sso)
+    {
+        this->sso = sso;
+    }
 };
 
-click::web::Client::Client(
-    const  QSharedPointer<click::network::AccessManager>& network_access_manager,
-    const QSharedPointer<click::CredentialsService>& sso
-)
-    : impl(new Private{network_access_manager, sso})
+click::web::Client::Client(const  QSharedPointer<click::network::AccessManager>& network_access_manager)
+    : impl(new Private{network_access_manager})
 {
 }
 
@@ -90,39 +90,45 @@
 {
     QUrl url(iri.c_str());
     url.setQuery(params.query);
-    QNetworkRequest request(url);
+    QSharedPointer<QNetworkRequest> request(new QNetworkRequest(url));
     QSharedPointer<QBuffer> buffer(new QBuffer());
     buffer->setData(data.c_str(), data.length());
 
+    // Set the Accept-Language header for all requests.
+    request->setRawHeader(ACCEPT_LANGUAGE_HEADER.c_str(),
+                          Configuration().get_accept_languages().c_str());
+
     for (const auto& kv : headers) {
         QByteArray header_name(kv.first.c_str(), kv.first.length());
         QByteArray header_value(kv.second.c_str(), kv.second.length());
-        request.setRawHeader(header_name, header_value);
+        request->setRawHeader(header_name, header_value);
     }
 
-    QSharedPointer<click::web::Response> responsePtr = QSharedPointer<click::web::Response>(new click::web::Response(buffer));
+    QSharedPointer<click::web::Response> responsePtr = QSharedPointer<click::web::Response>(new click::web::Response(request, buffer));
 
-    auto doConnect = [=, &request]() {
+    auto doConnect = [=]() {
         QByteArray verb(method.c_str(), method.length());
-        auto reply = impl->network_access_manager->sendCustomRequest(request,
+        auto reply = impl->network_access_manager->sendCustomRequest(*request,
                                                                 verb,
                                                                 buffer.data());
         responsePtr->setReply(reply);
     };
 
-    if (sign) {
+    if (sign && !impl->sso.isNull()) {
         click::utils::SmartConnect sc(responsePtr.data());
-
         sc.connect(impl->sso.data(), &click::CredentialsService::credentialsFound,
-                   [=, &request](const UbuntuOne::Token& token) {
-            QString auth_header = token.signUrl(url.toString(),
-                                                       method.c_str());
-            request.setRawHeader(AUTHORIZATION.c_str(), auth_header.toUtf8());
-            doConnect();
-        });
+                   [=](const UbuntuOne::Token& token) {
+                       QString auth_header = token.signUrl(url.toString(),
+                                                           method.c_str());
+                       qDebug() << "Signed URL:" << request->url().toString();
+                       request->setRawHeader(AUTHORIZATION_HEADER.c_str(), auth_header.toUtf8());
+                       impl->sso.clear();
+                       doConnect();
+                   });
         sc.connect(impl->sso.data(), &click::CredentialsService::credentialsNotFound,
-                   []() {
+                   [this]() {
                        // TODO: Need to handle and propagate error conditons.
+                       impl->sso.clear();
                    });
         // TODO: Need to handle error signal once in CredentialsService.
         impl->sso->getCredentials();
@@ -134,8 +140,16 @@
     return responsePtr;
 }
 
-click::web::Response::Response(const QSharedPointer<QBuffer>& buffer, QObject* parent)
+void click::web::Client::setCredentialsService(const QSharedPointer<click::CredentialsService>& sso)
+{
+    impl->setCredentialsService(sso);
+}
+
+click::web::Response::Response(const QSharedPointer<QNetworkRequest>& request,
+                               const QSharedPointer<QBuffer>& buffer,
+                               QObject* parent)
     : QObject(parent),
+      request(request),
       buffer(buffer)
 {
 }

=== modified file 'scope/click/webclient.h'
--- scope/click/webclient.h	2014-04-01 13:27:09 +0000
+++ scope/click/webclient.h	2014-05-02 16:27:07 +0000
@@ -49,7 +49,11 @@
 namespace web
 {
 
-const std::string AUTHORIZATION = "Authorization";
+const std::string ACCEPT_LANGUAGE_HEADER ="Accept-Language";
+const std::string AUTHORIZATION_HEADER = "Authorization";
+const std::string CONTENT_TYPE_HEADER = "Content-Type";
+
+const std::string CONTENT_TYPE_JSON = "application/json";
 
 class Client;
 
@@ -67,7 +71,8 @@
     Q_OBJECT
 
 public:
-    Response(const QSharedPointer<QBuffer>& buffer,
+    Response(const QSharedPointer<QNetworkRequest>& request,
+             const QSharedPointer<QBuffer>& buffer,
              QObject* parent=0);
     void setReply(QSharedPointer<click::network::Reply> reply);
     virtual void abort();
@@ -83,6 +88,7 @@
 
 private:
     QSharedPointer<click::network::Reply> reply;
+    QSharedPointer<QNetworkRequest> request;
     QSharedPointer<QBuffer> buffer;
 };
 
@@ -100,8 +106,7 @@
 class Client
 {
 public:
-    Client(const QSharedPointer<click::network::AccessManager>& networkAccessManager,
-           const QSharedPointer<click::CredentialsService>& sso);
+    Client(const QSharedPointer<click::network::AccessManager>& networkAccessManager);
     virtual ~Client();
 
     virtual QSharedPointer<Response> call(
@@ -114,6 +119,7 @@
         const std::map<std::string, std::string>& headers = std::map<std::string, std::string>(),
         const std::string& data = "",
         const CallParams& params = CallParams());
+    void setCredentialsService(const QSharedPointer<click::CredentialsService>& sso);
 private:
     struct Private;
     QScopedPointer<Private> impl;

=== modified file 'scope/tests/CMakeLists.txt'
--- scope/tests/CMakeLists.txt	2014-04-02 12:01:34 +0000
+++ scope/tests/CMakeLists.txt	2014-05-02 16:27:07 +0000
@@ -26,9 +26,11 @@
 add_executable (${CLICKSCOPE_TESTS_TARGET}
   mock_network_access_manager.h
   mock_webclient.h
+  test_configuration.cpp
   test_download_manager.cpp
   test_index.cpp
   test_interface.cpp
+  test_query.cpp
   test_reviews.cpp
   test_smartconnect.cpp
   test_webclient.cpp

=== added file 'scope/tests/applications/user/broken.desktop'
Binary files scope/tests/applications/user/broken.desktop	1970-01-01 00:00:00 +0000 and scope/tests/applications/user/broken.desktop	2014-05-02 16:27:07 +0000 differ
=== added file 'scope/tests/applications/user/semi-broken.desktop'
--- scope/tests/applications/user/semi-broken.desktop	1970-01-01 00:00:00 +0000
+++ scope/tests/applications/user/semi-broken.desktop	2014-05-02 16:27:07 +0000
@@ -0,0 +1,1 @@
+semi broken file

=== modified file 'scope/tests/fake_json.h'
--- scope/tests/fake_json.h	2014-04-02 14:44:39 +0000
+++ scope/tests/fake_json.h	2014-05-02 16:27:07 +0000
@@ -30,6 +30,9 @@
 #ifndef FAKE_JSON_H
 #define FAKE_JSON_H
 
+#include <string>
+
+
 const std::string FAKE_JSON_REVIEWS_RESULT_ONE = R"foo(
         [
           {
@@ -125,4 +128,30 @@
     }
 )foo";
 
+const std::string FAKE_JSON_MANIFEST_REMOVABLE = R"foo(
+    {
+        "_removable": 1,
+        "name": "com.example.fake",
+        "version": "0.1",
+        "hooks": {
+            "fake-app": {
+                "desktop": "fake-app.desktop"
+            }
+        }
+    }
+)foo";
+
+const std::string FAKE_JSON_MANIFEST_NONREMOVABLE = R"foo(
+    {
+        "_removable": 0,
+        "name": "com.example.fake",
+        "version": "0.1",
+        "hooks": {
+            "fake-app": {
+                "desktop": "fake-app.desktop"
+            }
+        }
+    }
+)foo";
+
 #endif // FAKE_JSON_H

=== modified file 'scope/tests/integration/webclient_integration.cpp'
--- scope/tests/integration/webclient_integration.cpp	2014-04-01 13:27:09 +0000
+++ scope/tests/integration/webclient_integration.cpp	2014-05-02 16:27:07 +0000
@@ -28,7 +28,6 @@
  */
 
 #include <click/network_access_manager.h>
-#include <click/ubuntuone_credentials.h>
 #include <click/webclient.h>
 #include <click/index.h>
 
@@ -77,9 +76,7 @@
 TEST_F(IntegrationTest, queryForArmhfPackagesReturnsCorrectResults)
 {
     click::web::Client ws(QSharedPointer<click::network::AccessManager>(
-                               new click::network::AccessManager()),
-                           QSharedPointer<click::CredentialsService>(
-                               new click::CredentialsService()));
+                              new click::network::AccessManager()));
 
     click::web::CallParams params;
     params.add("q", "qr,architecture:armhf");
@@ -101,10 +98,8 @@
 {
     QSharedPointer<click::network::AccessManager> namPtr(
                 new click::network::AccessManager());
-    QSharedPointer<click::CredentialsService> ssoPtr(
-                new click::CredentialsService());
     QSharedPointer<click::web::Client> clientPtr(
-                new click::web::Client(namPtr, ssoPtr));
+                new click::web::Client(namPtr));
     click::Index index(clientPtr);
     click::PackageList packages;
     index.search("qr,architecture:armhf", [&, this](click::PackageList found_packages){
@@ -120,10 +115,8 @@
     const std::string sample_name("com.ubuntu.developer.alecu.qr-code");
     QSharedPointer<click::network::AccessManager> namPtr(
                 new click::network::AccessManager());
-    QSharedPointer<click::CredentialsService> ssoPtr(
-                new click::CredentialsService());
     QSharedPointer<click::web::Client> clientPtr(
-                new click::web::Client(namPtr, ssoPtr));
+                new click::web::Client(namPtr));
     click::Index index(clientPtr);
     index.get_details(sample_name, [&](click::PackageDetails details, click::Index::Error){
         EXPECT_EQ(details.package.name, sample_name);

=== modified file 'scope/tests/mock_webclient.h'
--- scope/tests/mock_webclient.h	2014-03-14 14:34:53 +0000
+++ scope/tests/mock_webclient.h	2014-05-02 16:27:07 +0000
@@ -30,8 +30,9 @@
 #ifndef MOCK_WEBCLIENT_H
 #define MOCK_WEBCLIENT_H
 
+#include "test_data.h"
+
 #include <click/webclient.h>
-#include <click/ubuntuone_credentials.h>
 
 #include <gtest/gtest.h>
 
@@ -40,11 +41,6 @@
 namespace
 {
 
-const std::string FAKE_SERVER = "http://fake-server/";
-const std::string FAKE_PATH = "fake/api/path";
-const std::string FAKE_QUERY = "FAKE_QUERY";
-const std::string FAKE_PACKAGENAME = "com.example.fakepackage";
-
 template<typename Interface, typename Mock>
 struct LifetimeHelper
 {
@@ -67,7 +63,7 @@
 
 QSharedPointer<click::web::Response> responseForReply(const QSharedPointer<click::network::Reply>& reply)
 {
-    auto response = QSharedPointer<click::web::Response>(new click::web::Response(QSharedPointer<QBuffer>(new QBuffer())));
+    auto response = QSharedPointer<click::web::Response>(new click::web::Response(QSharedPointer<QNetworkRequest>(new QNetworkRequest()), QSharedPointer<QBuffer>(new QBuffer())));
     response->setReply(reply);
     return response;
 }
@@ -75,9 +71,8 @@
 class MockClient : public click::web::Client
 {
 public:
-    MockClient(const QSharedPointer<click::network::AccessManager>& networkAccessManager,
-                const QSharedPointer<click::CredentialsService>& sso)
-        : Client(networkAccessManager, sso)
+    MockClient(const QSharedPointer<click::network::AccessManager>& networkAccessManager)
+        : Client(networkAccessManager)
     {
     }
 

=== added file 'scope/tests/test_configuration.cpp'
--- scope/tests/test_configuration.cpp	1970-01-01 00:00:00 +0000
+++ scope/tests/test_configuration.cpp	2014-05-02 16:27:07 +0000
@@ -0,0 +1,174 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <click/configuration.h>
+
+using namespace click;
+
+namespace
+{
+
+class FakeConfiguration : public click::Configuration
+{
+public:
+    MOCK_METHOD2(list_folder, std::vector<std::string>(
+                     const std::string& folder, const std::string& pattern));
+};
+
+}
+
+
+TEST(Configuration, getAvailableFrameworksUsesRightFolder)
+{
+    using namespace ::testing;
+    FakeConfiguration locator;
+    EXPECT_CALL(locator, list_folder(Configuration::FRAMEWORKS_FOLDER, _))
+            .Times(1).WillOnce(Return(std::vector<std::string>()));
+    locator.get_available_frameworks();
+}
+
+TEST(Configuration, getAvailableFrameworksUsesRightPattern)
+{
+    using namespace ::testing;
+    FakeConfiguration locator;
+    EXPECT_CALL(locator, list_folder(_, Configuration::FRAMEWORKS_PATTERN))
+            .Times(1).WillOnce(Return(std::vector<std::string>()));
+    locator.get_available_frameworks();
+}
+
+TEST(Configuration, getAvailableFrameworksTwoResults)
+{
+    using namespace ::testing;
+
+    FakeConfiguration locator;
+    std::vector<std::string> response = {"abc.framework", "def.framework"};
+    EXPECT_CALL(locator, list_folder(_, _))
+            .Times(1)
+            .WillOnce(Return(response));
+    auto frameworks = locator.get_available_frameworks();
+    std::vector<std::string> expected = {"abc", "def"};
+    EXPECT_EQ(expected, frameworks);
+}
+
+TEST(Configuration, getAvailableFrameworksNoResults)
+{
+    using namespace ::testing;
+
+    FakeConfiguration locator;
+    std::vector<std::string> response = {};
+    EXPECT_CALL(locator, list_folder(_, _))
+            .Times(1)
+            .WillOnce(Return(response));
+    auto frameworks = locator.get_available_frameworks();
+    EXPECT_EQ(0, frameworks.size());
+}
+
+TEST(Configuration, getLanguageCorrect)
+{
+    ASSERT_EQ(setenv(Configuration::LANGUAGE_ENVVAR, "en_US.UTF-8", 1), 0);
+    EXPECT_EQ(Configuration().get_language(), "en_US");
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+}
+
+TEST(Configuration, getLanguageUnsetFallback)
+{
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+    ASSERT_EQ(Configuration().get_language(), "C");
+}
+
+TEST(Configuration, getLanguageNoCharsetCorrect)
+{
+    ASSERT_EQ(setenv(Configuration::LANGUAGE_ENVVAR, "en_US", 1), 0);
+    EXPECT_EQ(Configuration().get_language(), "en_US");
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+}
+
+TEST(Configuration, getLanguageNoRegionOrCharsetCorrect)
+{
+    ASSERT_EQ(setenv(Configuration::LANGUAGE_ENVVAR, "en", 1), 0);
+    EXPECT_EQ(Configuration().get_language(), "en");
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+}
+
+TEST(Configuration, getLanguageBaseCorrect)
+{
+    ASSERT_EQ(setenv(Configuration::LANGUAGE_ENVVAR, "en_US.UTF-8", 1), 0);
+    EXPECT_EQ(Configuration().get_language_base(), "en");
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+}
+
+TEST(Configuration, getLanguageBaseUnsetFallback)
+{
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+    ASSERT_EQ(Configuration().get_language_base(), "C");
+}
+
+TEST(Configuration, getLanguageBaseNoCharseteCorrect)
+{
+    ASSERT_EQ(setenv(Configuration::LANGUAGE_ENVVAR, "en_US", 1), 0);
+    EXPECT_EQ(Configuration().get_language_base(), "en");
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+}
+
+TEST(Configuration, getLanguageBaseNoRegionOrCharseteCorrect)
+{
+    ASSERT_EQ(setenv(Configuration::LANGUAGE_ENVVAR, "en", 1), 0);
+    EXPECT_EQ(Configuration().get_language_base(), "en");
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+}
+
+TEST(Configuration, getAcceptLanguagesCorrect)
+{
+    ASSERT_EQ(setenv(Configuration::LANGUAGE_ENVVAR, "en_US.UTF-8", 1), 0);
+    EXPECT_EQ(Configuration().get_accept_languages(), "en-US, en");
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+}
+
+TEST(Configuration, getAcceptLanguagesUnsetFallback)
+{
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+    ASSERT_EQ(Configuration().get_accept_languages(), "C");
+}
+
+TEST(Configuration, getAcceptLanguagesNoCharseteCorrect)
+{
+    ASSERT_EQ(setenv(Configuration::LANGUAGE_ENVVAR, "en_US", 1), 0);
+    EXPECT_EQ(Configuration().get_accept_languages(), "en-US, en");
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+}
+
+TEST(Configuration, getAcceptLanguagesNoRegionOrCharseteCorrect)
+{
+    ASSERT_EQ(setenv(Configuration::LANGUAGE_ENVVAR, "en", 1), 0);
+    EXPECT_EQ(Configuration().get_accept_languages(), "en");
+    ASSERT_EQ(unsetenv(Configuration::LANGUAGE_ENVVAR), 0);
+}

=== modified file 'scope/tests/test_data.h'
--- scope/tests/test_data.h	2014-02-10 12:12:09 +0000
+++ scope/tests/test_data.h	2014-05-02 16:27:07 +0000
@@ -34,6 +34,11 @@
 
 namespace testing
 {
+const std::string FAKE_SERVER = "http://fake-server/";
+const std::string FAKE_PATH = "fake/api/path";
+const std::string FAKE_QUERY = "FAKE_QUERY";
+const std::string FAKE_PACKAGENAME = "com.example.fakepackage";
+
 const std::string& systemApplicationsDirectoryForTesting();
 const std::string& userApplicationsDirectoryForTesting();
 }

=== modified file 'scope/tests/test_index.cpp'
--- scope/tests/test_index.cpp	2014-04-02 14:44:39 +0000
+++ scope/tests/test_index.cpp	2014-05-02 16:27:07 +0000
@@ -43,20 +43,37 @@
 namespace
 {
 
+class MockableIndex : public click::Index {
+public:
+    using click::Index::build_index_query;
+    MockableIndex(const QSharedPointer<click::web::Client>& client,
+                  const QSharedPointer<click::Configuration> configuration) :
+        click::Index(client, configuration)
+    {
+    }
+    MOCK_METHOD1(build_index_query, std::string(std::string));
+};
+
+class MockConfiguration : public click::Configuration {
+public:
+    MOCK_METHOD0(get_architecture, std::string());
+    MOCK_METHOD0(get_available_frameworks, std::vector<std::string>());
+};
+
+
 class IndexTest : public ::testing::Test {
 protected:
     QSharedPointer<MockClient> clientPtr;
     QSharedPointer<MockNetworkAccessManager> namPtr;
-    QSharedPointer<MockCredentialsService> ssoPtr;
-    std::shared_ptr<click::Index> indexPtr;
+    QSharedPointer<MockConfiguration> configPtr;
+    std::shared_ptr<MockableIndex> indexPtr;
 
     virtual void SetUp() {
         namPtr.reset(new MockNetworkAccessManager());
-        ssoPtr.reset(new MockCredentialsService());
-        clientPtr.reset(new NiceMock<MockClient>(namPtr, ssoPtr));
-        indexPtr.reset(new click::Index(clientPtr));
+        clientPtr.reset(new NiceMock<MockClient>(namPtr));
+        configPtr.reset(new MockConfiguration());
+        indexPtr.reset(new MockableIndex(clientPtr, configPtr));
     }
-
 public:
     MOCK_METHOD1(search_callback, void(click::PackageList));
     MOCK_METHOD2(details_callback, void(click::PackageDetails, click::Index::Error));
@@ -82,17 +99,23 @@
     indexPtr->search("", [](click::PackageList) {});
 }
 
-TEST_F(IndexTest, testSearchSendsQueryAsParam)
+TEST_F(IndexTest, testSearchSendsBuiltQueryAsParam)
 {
+    const std::string FAKE_BUILT_QUERY = "FAKE_QUERY,frameworks:fake-14.04,architecture:fake-arch";
+
     LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
     auto response = responseForReply(reply.asSharedPtr());
 
     click::web::CallParams params;
-    params.add(click::QUERY_ARGNAME, FAKE_QUERY);
+    params.add(click::QUERY_ARGNAME, FAKE_BUILT_QUERY);
     EXPECT_CALL(*clientPtr, callImpl(_, _, _, _, _, params))
             .Times(1)
             .WillOnce(Return(response));
 
+    EXPECT_CALL(*indexPtr, build_index_query(FAKE_QUERY))
+            .Times(1)
+            .WillOnce(Return(FAKE_BUILT_QUERY));
+
     indexPtr->search(FAKE_QUERY, [](click::PackageList) {});
 }
 
@@ -396,6 +419,24 @@
     get_details_operation.cancel();
 }
 
+TEST_F(IndexTest, testGetBaseUrl)
+{
+    const char *value = getenv(click::SEARCH_BASE_URL_ENVVAR.c_str());
+    if (value != NULL) {
+        ASSERT_TRUE(unsetenv(click::SEARCH_BASE_URL_ENVVAR.c_str()) == 0);
+    }
+    ASSERT_TRUE(click::Index::get_base_url() == click::SEARCH_BASE_URL);
+    
+}
+
+TEST_F(IndexTest, testGetBaseUrlFromEnv)
+{
+    ASSERT_TRUE(setenv(click::SEARCH_BASE_URL_ENVVAR.c_str(),
+                       FAKE_SERVER.c_str(), 1) == 0);
+    ASSERT_TRUE(click::Index::get_base_url() == FAKE_SERVER);
+    ASSERT_TRUE(unsetenv(click::SEARCH_BASE_URL_ENVVAR.c_str()) == 0);
+}
+
 TEST_F(MockPackageManager, testUninstallCommandCorrect)
 {
     click::Package package = {
@@ -407,3 +448,51 @@
     EXPECT_CALL(*this, execute_uninstall_command(expected, _)).Times(1);
     uninstall(package, [](int, std::string) {});
 }
+
+class ExhibitionistIndex : public click::Index {
+public:
+    using click::Index::build_index_query;
+    ExhibitionistIndex(const QSharedPointer<click::web::Client>& client,
+                       const QSharedPointer<click::Configuration> configuration) :
+        click::Index(client, configuration)
+    {
+    }
+};
+
+class QueryStringTest : public ::testing::Test {
+protected:
+    const std::string fake_arch{"fake_arch"};
+    const std::string fake_fwk_1{"fake_fwk_1"};
+    const std::string fake_fwk_2{"fake_fwk_2"};
+    std::vector<std::string> fake_frameworks{fake_fwk_1, fake_fwk_2};
+
+    QSharedPointer<MockClient> clientPtr;
+    QSharedPointer<MockNetworkAccessManager> namPtr;
+    QSharedPointer<MockConfiguration> configPtr;
+    std::shared_ptr<ExhibitionistIndex> indexPtr;
+
+    virtual void SetUp() {
+        namPtr.reset(new MockNetworkAccessManager());
+        clientPtr.reset(new NiceMock<MockClient>(namPtr));
+        configPtr.reset(new MockConfiguration());
+        indexPtr.reset(new ExhibitionistIndex(clientPtr, configPtr));
+    }
+};
+
+
+TEST_F(QueryStringTest, testBuildQueryAddsArchitecture)
+{
+    EXPECT_CALL(*configPtr, get_architecture()).Times(1).WillOnce(Return(fake_arch));
+    EXPECT_CALL(*configPtr, get_available_frameworks()).Times(1).WillOnce(Return(fake_frameworks));
+    auto index_query = indexPtr->build_index_query("fake");
+    EXPECT_NE(std::string::npos, index_query.find("architecture:" + fake_arch));
+}
+
+TEST_F(QueryStringTest, testBuildQueryAddsFramework)
+{
+    EXPECT_CALL(*configPtr, get_architecture()).Times(1).WillOnce(Return(fake_arch));
+    EXPECT_CALL(*configPtr, get_available_frameworks()).Times(1).WillOnce(Return(fake_frameworks));
+    auto index_query = indexPtr->build_index_query("fake");
+    EXPECT_NE(std::string::npos, index_query.find("framework:" + fake_fwk_1));
+    EXPECT_NE(std::string::npos, index_query.find("framework:" + fake_fwk_2));
+}

=== modified file 'scope/tests/test_interface.cpp'
--- scope/tests/test_interface.cpp	2014-04-10 17:29:49 +0000
+++ scope/tests/test_interface.cpp	2014-05-02 16:27:07 +0000
@@ -27,6 +27,7 @@
  * files in the program, then also delete it here.
  */
 
+#include "fake_json.h"
 #include "test_data.h"
 
 #include <QCoreApplication>
@@ -43,6 +44,7 @@
 #include <click/key_file_locator.h>
 
 using namespace click;
+using namespace ::testing;
 
 namespace
 {
@@ -113,12 +115,22 @@
         Super::enumerateKeyFilesForInstalledApplications(enumerator);
     }
 };
+
+class ClickInterfaceTest : public ::testing::Test {
+public:
+    MOCK_METHOD2(manifest_callback, void(Manifest, ManifestError));
+    MOCK_METHOD2(manifests_callback, void(ManifestList, ManifestError));
+};
+
 }
 
 class FakeClickInterface : public click::Interface {
 public:
     FakeClickInterface(const QSharedPointer<KeyFileLocator>& keyFileLocator) : Interface(keyFileLocator) {}
+    FakeClickInterface() {}
+
     MOCK_METHOD0(show_desktop_apps, bool());
+    MOCK_METHOD2(run_process, void(const std::string&, std::function<void(int, const std::string&, const std::string&)>));
 };
 
 TEST(ClickInterface, testIsNonClickAppFalse)
@@ -293,55 +305,140 @@
     EXPECT_FALSE(iface.show_desktop_apps());
 }
 
-
-class FakeFrameworkLocator : public click::FrameworkLocator
-{
-public:
-    MOCK_METHOD2(list_folder, std::vector<std::string>(
-                     const std::string& folder, const std::string& pattern));
-};
-
-TEST(FrameworkLocator, getAvailableFrameworksUsesRightFolder)
-{
-    using namespace ::testing;
-    FakeFrameworkLocator locator;
-    EXPECT_CALL(locator, list_folder(FrameworkLocator::FRAMEWORKS_FOLDER, _))
-            .Times(1).WillOnce(Return(std::vector<std::string>()));
-    locator.get_available_frameworks();
-}
-
-TEST(FrameworkLocator, getAvailableFrameworksUsesRightPattern)
-{
-    using namespace ::testing;
-    FakeFrameworkLocator locator;
-    EXPECT_CALL(locator, list_folder(_, FrameworkLocator::FRAMEWORKS_PATTERN))
-            .Times(1).WillOnce(Return(std::vector<std::string>()));
-    locator.get_available_frameworks();
-}
-
-TEST(FrameworkLocator, getAvailableFrameworksTwoResults)
-{
-    using namespace ::testing;
-
-    FakeFrameworkLocator locator;
-    std::vector<std::string> response = {"abc.framework", "def.framework"};
-    EXPECT_CALL(locator, list_folder(_, _))
-            .Times(1)
-            .WillOnce(Return(response));
-    auto frameworks = locator.get_available_frameworks();
-    std::vector<std::string> expected = {"abc", "def"};
-    EXPECT_EQ(expected, frameworks);
-}
-
-TEST(FrameworkLocator, getAvailableFrameworksNoResults)
-{
-    using namespace ::testing;
-
-    FakeFrameworkLocator locator;
-    std::vector<std::string> response = {};
-    EXPECT_CALL(locator, list_folder(_, _))
-            .Times(1)
-            .WillOnce(Return(response));
-    auto frameworks = locator.get_available_frameworks();
-    EXPECT_EQ(0, frameworks.size());
+TEST(ClickInterface, testGetManifestForAppCorrectCommand)
+{
+    FakeClickInterface iface;
+    std::string command = "click info " + FAKE_PACKAGENAME;
+    EXPECT_CALL(iface, run_process(command, _)).
+        Times(1);
+    iface.get_manifest_for_app(FAKE_PACKAGENAME, [](Manifest, ManifestError){});
+}
+
+TEST_F(ClickInterfaceTest, testGetManifestForAppParseError)
+{
+    FakeClickInterface iface;
+    EXPECT_CALL(iface, run_process(_, _)).
+        Times(1).
+        WillOnce(Invoke([&](const std::string&,
+                            std::function<void(int, const std::string&,
+                                               const std::string&)> callback){
+                            callback(0, "INVALID JSON", "");
+                        }));
+    EXPECT_CALL(*this, manifest_callback(_, ManifestError::ParseError));
+    iface.get_manifest_for_app(FAKE_PACKAGENAME, [this](Manifest manifest,
+                                                        ManifestError error){
+                                   manifest_callback(manifest, error);
+                               });
+}
+
+TEST_F(ClickInterfaceTest, testGetManifestForAppCommandFailed)
+{
+    FakeClickInterface iface;
+    EXPECT_CALL(iface, run_process(_, _)).
+        Times(1).
+        WillOnce(Invoke([&](const std::string&,
+                            std::function<void(int, const std::string&,
+                                               const std::string&)> callback){
+                            callback(-1, "", "CRITICAL: FAIL");
+                        }));
+    EXPECT_CALL(*this, manifest_callback(_, ManifestError::CallError));
+    iface.get_manifest_for_app(FAKE_PACKAGENAME, [this](Manifest manifest,
+                                                        ManifestError error){
+                                   manifest_callback(manifest, error);
+                               });
+}
+
+TEST_F(ClickInterfaceTest, testGetManifestForAppIsRemovable)
+{
+    FakeClickInterface iface;
+    EXPECT_CALL(iface, run_process(_, _)).
+        Times(1).
+        WillOnce(Invoke([&](const std::string&,
+                            std::function<void(int, const std::string&,
+                                               const std::string&)> callback){
+                            callback(0, FAKE_JSON_MANIFEST_REMOVABLE, "");
+                        }));
+    iface.get_manifest_for_app(FAKE_PACKAGENAME, [](Manifest manifest,
+                                                    ManifestError error){
+                                   ASSERT_TRUE(error == ManifestError::NoError);
+                                   ASSERT_TRUE(manifest.removable);
+                               });
+}
+
+TEST_F(ClickInterfaceTest, testGetManifestForAppIsNotRemovable)
+{
+    FakeClickInterface iface;
+    EXPECT_CALL(iface, run_process(_, _)).
+        Times(1).
+        WillOnce(Invoke([&](const std::string&,
+                            std::function<void(int, const std::string&,
+                                               const std::string&)> callback){
+                            callback(0, FAKE_JSON_MANIFEST_NONREMOVABLE, "");
+                        }));
+    iface.get_manifest_for_app(FAKE_PACKAGENAME, [](Manifest manifest,
+                                                    ManifestError error){
+                                   ASSERT_TRUE(error == ManifestError::NoError);
+                                   ASSERT_FALSE(manifest.removable);
+                               });
+}
+
+TEST(ClickInterface, testGetManifestsCorrectCommand)
+{
+    FakeClickInterface iface;
+    std::string command = "click list --manifest";
+    EXPECT_CALL(iface, run_process(command, _)).
+        Times(1);
+    iface.get_manifests([](ManifestList, ManifestError){});
+}
+
+TEST_F(ClickInterfaceTest, testGetManifestsParseError)
+{
+    FakeClickInterface iface;
+    EXPECT_CALL(iface, run_process(_, _)).
+        Times(1).
+        WillOnce(Invoke([&](const std::string&,
+                            std::function<void(int, const std::string&,
+                                               const std::string&)> callback){
+                            callback(0, "INVALID JSON", "");
+                        }));
+    EXPECT_CALL(*this, manifests_callback(_, ManifestError::ParseError));
+    iface.get_manifests([this](ManifestList manifests, ManifestError error){
+            manifests_callback(manifests, error);
+        });
+}
+
+TEST_F(ClickInterfaceTest, testGetManifestsCommandFailed)
+{
+    FakeClickInterface iface;
+    EXPECT_CALL(iface, run_process(_, _)).
+        Times(1).
+        WillOnce(Invoke([&](const std::string&,
+                            std::function<void(int, const std::string&,
+                                               const std::string&)> callback){
+                            callback(-1, "", "CRITICAL: FAIL");
+                        }));
+    EXPECT_CALL(*this, manifests_callback(_, ManifestError::CallError));
+    iface.get_manifests([this](ManifestList manifests, ManifestError error){
+            manifests_callback(manifests, error);
+        });
+}
+
+TEST_F(ClickInterfaceTest, testGetManifestsParsed)
+{
+    FakeClickInterface iface;
+    std::string expected_str = "[" + FAKE_JSON_MANIFEST_NONREMOVABLE + "," +
+        FAKE_JSON_MANIFEST_REMOVABLE + "]";
+    ManifestList expected = manifest_list_from_json(expected_str);
+
+    EXPECT_CALL(iface, run_process(_, _)).
+        Times(1).
+        WillOnce(Invoke([&](const std::string&,
+                            std::function<void(int, const std::string&,
+                                               const std::string&)> callback){
+                            callback(0, expected_str, "");
+                        }));
+    iface.get_manifests([expected](ManifestList manifests, ManifestError error){
+            ASSERT_TRUE(error == ManifestError::NoError);
+            ASSERT_TRUE(manifests.size() == expected.size());
+        });
 }

=== added file 'scope/tests/test_query.cpp'
--- scope/tests/test_query.cpp	1970-01-01 00:00:00 +0000
+++ scope/tests/test_query.cpp	2014-05-02 16:27:07 +0000
@@ -0,0 +1,257 @@
+/*
+ * Copyright (C) 2014 Canonical Ltd.
+ *
+ * This program is free software: you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 3, as published
+ * by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranties of
+ * MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
+ * PURPOSE.  See the GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * In addition, as a special exception, the copyright holders give
+ * permission to link the code of portions of this program with the
+ * OpenSSL library under certain conditions as described in each
+ * individual source file, and distribute linked combinations
+ * including the two.
+ * You must obey the GNU General Public License in all respects
+ * for all of the code used other than OpenSSL.  If you modify
+ * file(s) with this exception, you may extend this exception to your
+ * version of the file(s), but you are not obligated to do so.  If you
+ * do not wish to do so, delete this exception statement from your
+ * version.  If you delete this exception statement from all source
+ * files in the program, then also delete it here.
+ */
+
+#include <string>
+#include <memory>
+
+#include <gtest/gtest.h>
+#include <gmock/gmock.h>
+
+#include "click/qtbridge.h"
+#include "click/query.h"
+#include "click/index.h"
+#include "click/application.h"
+
+#include "mock_network_access_manager.h"
+
+#include <unity/scopes/CategoryRenderer.h>
+#include <unity/scopes/CategorisedResult.h>
+#include <unity/scopes/CannedQuery.h>
+#include <unity/scopes/ScopeBase.h>
+#include <unity/scopes/SearchReply.h>
+
+using namespace ::testing;
+
+namespace
+{
+static const std::string FAKE_QUERY {"FAKE_QUERY"};
+static const std::string FAKE_CATEGORY_TEMPLATE {"{}"};
+
+
+class MockIndex : public click::Index {
+    click::PackageList packages;
+public:
+    MockIndex(click::PackageList packages = click::PackageList())
+        : Index(QSharedPointer<click::web::Client>()),
+          packages(packages)
+    {
+
+    }
+
+    click::web::Cancellable search(const std::string &query, std::function<void (click::PackageList)> callback) override
+    {
+        do_search(query, callback);
+        callback(packages);
+        return click::web::Cancellable();
+    }
+
+    MOCK_METHOD2(do_search,
+                 void(const std::string&,
+                      std::function<void(click::PackageList)>));
+};
+
+class MockQueryBase : public click::Query {
+public:
+    MockQueryBase(const std::string query, click::Index& index,
+                  scopes::SearchMetadata const& metadata) : click::Query(query, index, metadata)
+    {
+
+    }
+
+    void run_under_qt(const std::function<void()> &task) {
+        // when testing, do not actually run under qt
+        task();
+    }
+};
+
+class MockQuery : public MockQueryBase {
+public:
+    MockQuery(const std::string query, click::Index& index,
+              scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, metadata)
+    {
+
+    }
+    void wrap_add_available_apps(const scopes::SearchReplyProxy &searchReply,
+                                 const std::set<std::string> &locallyInstalledApps,
+                                 const std::string& categoryTemplate)
+    {
+        add_available_apps(searchReply, locallyInstalledApps, categoryTemplate);
+    }
+    MOCK_METHOD2(push_result, bool(scopes::SearchReplyProxy const&, scopes::CategorisedResult const&));
+    MOCK_METHOD1(finished, void(scopes::SearchReplyProxy const&));
+    MOCK_METHOD5(register_category, scopes::Category::SCPtr(const scopes::SearchReplyProxy &searchReply,
+                                                            const std::string &id,
+                                                            const std::string &title,
+                                                            const std::string &icon,
+                                                            const scopes::CategoryRenderer &renderer_template));
+};
+
+class MockQueryRun : public MockQueryBase {
+public:
+    MockQueryRun(const std::string query, click::Index& index,
+                 scopes::SearchMetadata const& metadata) : MockQueryBase(query, index, metadata)
+    {
+
+    }
+    MOCK_METHOD3(add_available_apps,
+                 void(scopes::SearchReplyProxy const&searchReply,
+                      const std::set<std::string> &locallyInstalledApps,
+                      const std::string& categoryTemplate));
+    MOCK_METHOD3(push_local_results, void(scopes::SearchReplyProxy const &replyProxy,
+                                          std::vector<click::Application> const &apps,
+                                          std::string& categoryTemplate));
+};
+
+class FakeCategory : public scopes::Category
+{
+public:
+    FakeCategory(std::string const& id, std::string const& title,
+                 std::string const& icon, scopes::CategoryRenderer const& renderer) :
+       scopes::Category(id, title, icon, renderer)
+    {
+    }
+
+};
+} // namespace
+
+TEST(QueryTest, testAddAvailableAppsCallsClickIndex)
+{
+    MockIndex mock_index;
+    scopes::SearchMetadata metadata("en_EN", "phone");
+    std::set<std::string> no_installed_packages;
+    MockQuery q(FAKE_QUERY, mock_index, metadata);
+    EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)).Times(1);
+    scopes::SearchReplyProxy reply;
+
+    scopes::CategoryRenderer renderer("{}");
+    auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer);
+    EXPECT_CALL(q, register_category(_, _, _, _, _)).WillOnce(Return(ptrCat));
+    q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
+}
+
+TEST(QueryTest, testAddAvailableAppsPushesResults)
+{
+    click::PackageList packages {
+        {"name", "title", 0.0, "", ""}
+    };
+    MockIndex mock_index(packages);
+    scopes::SearchMetadata metadata("en_EN", "phone");
+    std::set<std::string> no_installed_packages;
+    MockQuery q(FAKE_QUERY, mock_index, metadata);
+    EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _));
+
+    scopes::CategoryRenderer renderer("{}");
+    auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer);
+    EXPECT_CALL(q, register_category(_, _, _, _, _)).WillOnce(Return(ptrCat));
+
+    scopes::SearchReplyProxy reply;
+    auto expected_title = packages.front().title;
+    EXPECT_CALL(q, push_result(_, Property(&scopes::CategorisedResult::title, expected_title)));
+    q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
+}
+
+TEST(QueryTest, testAddAvailableAppsCallsFinished)
+{
+    click::PackageList packages {
+        {"name", "title", 0.0, "", ""}
+    };
+    MockIndex mock_index(packages);
+    scopes::SearchMetadata metadata("en_EN", "phone");
+    std::set<std::string> no_installed_packages;
+    MockQuery q(FAKE_QUERY, mock_index, metadata);
+    EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _));
+
+    scopes::CategoryRenderer renderer("{}");
+    auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer);
+    EXPECT_CALL(q, register_category(_, _, _, _, _)).WillOnce(Return(ptrCat));
+
+    scopes::SearchReplyProxy reply;
+    EXPECT_CALL(q, finished(_));
+    q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
+}
+
+TEST(QueryTest, testAddAvailableAppsWithNullCategory)
+{
+    click::PackageList packages {
+        {"name", "title", 0.0, "", ""}
+    };
+    MockIndex mock_index(packages);
+    scopes::SearchMetadata metadata("en_EN", "phone");
+    std::set<std::string> no_installed_packages;
+    MockQuery q(FAKE_QUERY, mock_index, metadata);
+    EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _)).Times(0);
+
+    EXPECT_CALL(q, register_category(_, _, _, _, _)).WillOnce(Return(nullptr));
+
+    scopes::SearchReplyProxy reply;
+    EXPECT_CALL(q, push_result(_, _)).Times(0);
+    q.wrap_add_available_apps(reply, no_installed_packages, FAKE_CATEGORY_TEMPLATE);
+}
+
+TEST(QueryTest, testQueryRunCallsAddAvailableApps)
+{
+    click::PackageList packages {
+        {"name", "title", 0.0, "", ""}
+    };
+    MockIndex mock_index(packages);
+    scopes::SearchMetadata metadata("en_EN", "phone");
+    std::set<std::string> no_installed_packages;
+    MockQueryRun q(FAKE_QUERY, mock_index, metadata);
+    auto reply = scopes::SearchReplyProxy();
+    EXPECT_CALL(q, push_local_results(_, _, _));
+    EXPECT_CALL(q, add_available_apps(reply, no_installed_packages, _));
+
+    q.run(reply);
+}
+
+MATCHER_P(HasPackageName, n, "") { return arg[click::Query::ResultKeys::NAME].get_string() == n; }
+
+TEST(QueryTest, testDuplicatesFilteredOnPackageName)
+{
+    click::PackageList packages {
+        {"org.example.app1", "app title1", 0.0, "", ""},
+        {"org.example.app2", "app title2", 0.0, "", ""}
+    };
+    MockIndex mock_index(packages);
+    scopes::SearchMetadata metadata("en_EN", "phone");
+    std::set<std::string> one_installed_package {
+        "org.example.app2"
+    };
+    MockQuery q(FAKE_QUERY, mock_index, metadata);
+    EXPECT_CALL(mock_index, do_search(FAKE_QUERY, _));
+
+    scopes::CategoryRenderer renderer("{}");
+    auto ptrCat = std::make_shared<FakeCategory>("id", "", "", renderer);
+    EXPECT_CALL(q, register_category(_, _, _, _, _)).WillOnce(Return(ptrCat));
+
+    scopes::SearchReplyProxy reply;
+    auto expected_name = packages.front().name;
+    EXPECT_CALL(q, push_result(_, HasPackageName(expected_name)));
+    q.wrap_add_available_apps(reply, one_installed_package, FAKE_CATEGORY_TEMPLATE);
+}

=== modified file 'scope/tests/test_reviews.cpp'
--- scope/tests/test_reviews.cpp	2014-03-25 18:49:16 +0000
+++ scope/tests/test_reviews.cpp	2014-05-02 16:27:07 +0000
@@ -48,13 +48,11 @@
 protected:
     QSharedPointer<MockClient> clientPtr;
     QSharedPointer<MockNetworkAccessManager> namPtr;
-    QSharedPointer<MockCredentialsService> ssoPtr;
     std::shared_ptr<click::Reviews> reviewsPtr;
 
     virtual void SetUp() {
         namPtr.reset(new MockNetworkAccessManager());
-        ssoPtr.reset(new MockCredentialsService());
-        clientPtr.reset(new NiceMock<MockClient>(namPtr, ssoPtr));
+        clientPtr.reset(new NiceMock<MockClient>(namPtr));
         reviewsPtr.reset(new click::Reviews(clientPtr));
     }
 
@@ -219,6 +217,75 @@
     fetch_reviews_op.cancel();
 }
 
+TEST_F(ReviewsTest, testSubmitReviewIsCancellable)
+{
+    LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
+    auto response = responseForReply(reply.asSharedPtr());
+
+    click::Review review;
+    review.rating = 3;
+    review.review_text = "A review";
+    review.package_name = "com.example.test";
+    review.package_version = "0.1";
+
+    EXPECT_CALL(*clientPtr, callImpl(_, "POST", true, _, _, _))
+            .Times(1)
+            .WillOnce(Return(response));
+
+    auto submit_op = reviewsPtr->submit_review(review,
+                                               [](click::Reviews::Error){});
+    EXPECT_CALL(reply.instance, abort()).Times(1);
+    submit_op.cancel();
+}
+
+TEST_F(ReviewsTest, testSubmitReviewUtf8)
+{
+    LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
+    auto response = responseForReply(reply.asSharedPtr());
+
+    click::Review review;
+    review.rating = 3;
+    review.review_text = "'\"小海嚴選";
+    review.package_name = "com.example.test";
+    review.package_version = "0.1";
+
+    // NOTE: gmock replaces the \" above as \\\" for HasSubstr(), so we have
+    // to manually copy the string into the expected result.
+    std::string expected_review_text = "\"review_text\":\"'\\\"小海嚴選\"";
+
+    EXPECT_CALL(*clientPtr, callImpl(_, "POST", true, _,
+                                     HasSubstr(expected_review_text), _))
+            .Times(1)
+            .WillOnce(Return(response));
+
+    auto submit_op = reviewsPtr->submit_review(review,
+                                               [](click::Reviews::Error){});
+}
+
+TEST_F(ReviewsTest, testSubmitReviewLanguageCorrect)
+{
+    LifetimeHelper<click::network::Reply, MockNetworkReply> reply;
+    auto response = responseForReply(reply.asSharedPtr());
+
+    click::Review review;
+    review.rating = 3;
+    review.review_text = "A review.";
+    review.package_name = "com.example.test";
+    review.package_version = "0.1";
+
+    ASSERT_EQ(setenv(click::Configuration::LANGUAGE_ENVVAR,
+                     "zh_TW.UTF-8", 1), 0);
+    std::string expected_language = "\"language\":\"zh\"";
+    EXPECT_CALL(*clientPtr, callImpl(_, "POST", true, _,
+                                     HasSubstr(expected_language), _))
+            .Times(1)
+            .WillOnce(Return(response));
+
+    auto submit_op = reviewsPtr->submit_review(review,
+                                               [](click::Reviews::Error){});
+    ASSERT_EQ(unsetenv(click::Configuration::LANGUAGE_ENVVAR), 0);
+}
+
 TEST_F(ReviewsTest, testGetBaseUrl)
 {
     const char *value = getenv(click::REVIEWS_BASE_URL_ENVVAR.c_str());

=== modified file 'scope/tests/test_webclient.cpp'
--- scope/tests/test_webclient.cpp	2014-04-01 13:27:09 +0000
+++ scope/tests/test_webclient.cpp	2014-05-02 16:27:07 +0000
@@ -28,6 +28,7 @@
  */
 #include <QDebug>
 
+#include "click/configuration.h"
 #include "click/webclient.h"
 
 #include "mock_network_access_manager.h"
@@ -46,10 +47,16 @@
 
 MATCHER_P(IsValidOAuthHeader, refOAuth, "")
 {
-    return arg.hasRawHeader("Authorization") && arg.rawHeader(click::web::AUTHORIZATION.c_str())
+    return arg.hasRawHeader(click::web::AUTHORIZATION_HEADER.c_str()) && arg.rawHeader(click::web::AUTHORIZATION_HEADER.c_str())
         .startsWith("OAuth ");
 }
 
+MATCHER_P(IsCorrectAcceptLanguageHeader, refAcceptLanguages, "")
+{
+    return arg.hasRawHeader(click::web::ACCEPT_LANGUAGE_HEADER.c_str()) &&
+        arg.rawHeader(click::web::ACCEPT_LANGUAGE_HEADER.c_str()) == refAcceptLanguages;
+}
+
 MATCHER_P(IsCorrectCookieHeader, refCookie, "")
 {
     return arg.hasRawHeader("Cookie") && arg.rawHeader("Cookie") == refCookie;
@@ -86,7 +93,7 @@
     ON_CALL(*reply, readAll()).WillByDefault(Return("HOLA"));
     QSharedPointer<click::network::Reply> replyPtr(reply);
 
-    click::web::Client wc(namPtr, ssoPtr);
+    click::web::Client wc(namPtr);
 
     EXPECT_CALL(nam, sendCustomRequest(IsCorrectUrl(QString("http://fake-server/fake/api/path")), _, _))
             .Times(1)
@@ -103,7 +110,7 @@
     ON_CALL(*reply, readAll()).WillByDefault(Return("HOLA"));
     QSharedPointer<click::network::Reply> replyPtr(reply);
 
-    click::web::Client wc(namPtr, ssoPtr);
+    click::web::Client wc(namPtr);
 
     click::web::CallParams params;
     params.add("a", "1");
@@ -154,7 +161,7 @@
     ON_CALL(*reply, readAll()).WillByDefault(Return("HOLA"));
     QSharedPointer<click::network::Reply> replyPtr(reply);
 
-    click::web::Client wc(namPtr, ssoPtr);
+    click::web::Client wc(namPtr);
 
     EXPECT_CALL(nam, sendCustomRequest(IsCorrectCookieHeader("CookieCookieCookie"), _, _))
             .Times(1)
@@ -173,7 +180,7 @@
     ON_CALL(*reply, readAll()).WillByDefault(Return("HOLA"));
     QSharedPointer<click::network::Reply> replyPtr(reply);
 
-    click::web::Client wc(namPtr, ssoPtr);
+    click::web::Client wc(namPtr);
 
     QByteArray verb("POST", 4);
     EXPECT_CALL(nam, sendCustomRequest(_, verb, _))
@@ -192,7 +199,7 @@
     ON_CALL(*reply, readAll()).WillByDefault(Return("HOLA \u5c0f\u6d77"));
     QSharedPointer<click::network::Reply> replyPtr(reply);
 
-    click::web::Client wc(namPtr, ssoPtr);
+    click::web::Client wc(namPtr);
 
     EXPECT_CALL(nam, sendCustomRequest(_, _, IsCorrectBufferData("HOLA \u5c0f\u6d77")))
             .Times(1)
@@ -211,7 +218,8 @@
     ON_CALL(*reply, readAll()).WillByDefault(Return("HOLA"));
     QSharedPointer<click::network::Reply> replyPtr(reply);
 
-    click::web::Client wc(namPtr, ssoPtr);
+    click::web::Client wc(namPtr);
+    wc.setCredentialsService(ssoPtr);
 
     EXPECT_CALL(sso, getCredentials()).WillOnce(Invoke([&](){
                 UbuntuOne::Token token("token_key", "token_secret",
@@ -226,15 +234,38 @@
                       "HEAD", true);
 }
 
+TEST_F(WebClientTest, testSignedCredentialsServiceUnset)
+{
+    using namespace ::testing;
+
+    auto reply = new NiceMock<MockNetworkReply>();
+    ON_CALL(*reply, readAll()).WillByDefault(Return("HOLA"));
+    QSharedPointer<click::network::Reply> replyPtr(reply);
+
+    click::web::Client wc(namPtr);
+
+    EXPECT_CALL(nam, sendCustomRequest(_, _, _))
+            .Times(1)
+            .WillOnce(Return(replyPtr));
+    EXPECT_CALL(*reply, errorString()).Times(1).WillOnce(Return("auth failed"));
+
+    auto response = wc.call(FAKE_SERVER + FAKE_PATH,
+                            "HEAD", true);
+    QObject::connect(response.data(), &click::web::Response::error,
+                     [this](QString desc){
+                         errorHandler(desc);
+                     });
+
+    EXPECT_CALL(*this, errorHandler(_));
+    emit reply->error(QNetworkReply::AuthenticationRequiredError);
+}
+
 TEST_F(WebClientTest, testSignTokenNotFound)
 {
     using namespace ::testing;
 
-    auto reply = new NiceMock<MockNetworkReply>();
-    ON_CALL(*reply, readAll()).WillByDefault(Return("HOLA"));
-    QSharedPointer<click::network::Reply> replyPtr(reply);
-
-    click::web::Client wc(namPtr, ssoPtr);
+    click::web::Client wc(namPtr);
+    wc.setCredentialsService(ssoPtr);
 
     EXPECT_CALL(sso, getCredentials()).WillOnce(Invoke([&]() {
                 sso.credentialsNotFound();
@@ -245,6 +276,7 @@
                       "HEAD", true);
 }
 
+
 TEST_F(WebClientTest, testResponseFinished)
 {
     using namespace ::testing;
@@ -253,7 +285,7 @@
     ON_CALL(*reply, readAll()).WillByDefault(Return("HOLA"));
     QSharedPointer<click::network::Reply> replyPtr(reply);
 
-    click::web::Client wc(namPtr, ssoPtr);
+    click::web::Client wc(namPtr);
 
     EXPECT_CALL(nam, sendCustomRequest(_, _, _))
             .Times(1)
@@ -272,7 +304,7 @@
     auto reply = new NiceMock<MockNetworkReply>();
     QSharedPointer<click::network::Reply> replyPtr(reply);
 
-    click::web::Client wc(namPtr, ssoPtr);
+    click::web::Client wc(namPtr);
 
     EXPECT_CALL(nam, sendCustomRequest(_, _, _))
             .Times(1)
@@ -297,7 +329,7 @@
     auto reply = new NiceMock<MockNetworkReply>();
     QSharedPointer<click::network::Reply> replyPtr(reply);
 
-    click::web::Client wc(namPtr, ssoPtr);
+    click::web::Client wc(namPtr);
 
     EXPECT_CALL(nam, sendCustomRequest(_, _, _))
             .Times(1)
@@ -308,3 +340,23 @@
     EXPECT_CALL(*reply, abort()).Times(1);
     response->abort();
 }
+
+TEST_F(WebClientTest, testAcceptLanguageSetCorrectly)
+{
+    using namespace ::testing;
+
+    auto reply = new NiceMock<MockNetworkReply>();
+    ON_CALL(*reply, readAll()).WillByDefault(Return("HOLA"));
+    QSharedPointer<click::network::Reply> replyPtr(reply);
+
+    click::web::Client wc(namPtr);
+
+    ASSERT_EQ(setenv(click::Configuration::LANGUAGE_ENVVAR,
+                     "en_US.UTF-8", 1), 0);
+    EXPECT_CALL(nam, sendCustomRequest(IsCorrectAcceptLanguageHeader("en-US, en"), _, _))
+            .Times(1)
+            .WillOnce(Return(replyPtr));
+
+    auto wr = wc.call(FAKE_SERVER + FAKE_PATH);
+    ASSERT_EQ(unsetenv(click::Configuration::LANGUAGE_ENVVAR), 0);
+}

