Canonical Voices

David Planella

image-phone-naturallyneat-medium

The 5 weeks after the Ubuntu Scopes Showdown announcement are coming to an end, it’s time to start putting the pencils down and submitting your scopes for the judges to do their reviews.

While you’ve still got two days to fix some bugs and do some final polish, the 3rd of December is the last day for submissions to be accepted for the Showdown. Remember that to qualify, you’ll need to:

  • Register your scope for the contest
  • Submit your scope to the Ubuntu Software Store

Registering your scope

To register your scope for the judges’ review, you’ll simply need a couple of minutes to fill in the registration form. It might be worth filling it in advance, even if you are planning to upload your app at the last minute.

You can submit the form now and still upload new revisions of your app until the 3rd of December.

Register your scope for participation

Submitting your scope

Submitting your scope to the store should also be quick and easy. The upload workflow is exactly the same as for apps, and with automated reviews it takes just a few minutes from upload to your scope being available for everyone on the Ubuntu Software Store.

To ensure your scope is discoverable and looks good, you might want to check out the scope upload tips ›

And when you’re ready to start the upload, you can follow the 5-step process to get it published ›

Need help?

If you need help with any of the above, feel free to reach out in any of the channels below:

Looking forward to seeing your scopes in the store!

Read more
Daniel Holbach

Despite being an “old” technology and having its problems, we still use mailing lists… a lot.  Some of the lists have been cleaned up by the Community Council some time ago, especially if they were created and then forgotten some time later.

We do have a number of mailing lists though which are still active, but have the problem of not having enough (or enough active) moderators on board. What then happens is this:

List moderation

… which sucks.

It’s not very nice if you have lots and lots of good discussion not happening just because you had no time to tend to the moderation queue.

Some mailing lists receive quite a bit of spam, others get a lot of mails from folks who are not subscribed yet, but this really shouldn’t be a problem. If you run a popular mailing list and moderation gets too much of a hassle, please consider adding more moderators – if you ask nicely a bunch of folks will be happy to help out.

So my advice:

  1. If you every registered a mailing list, please have a look at its moderation queue and see if you need help.
  2. If yes, please add more moderators.
  3. If you don’t do it yet, use listadmin – it’s the best thing since sliced bread and keeping up with moderation in the future will be no problem at all.

Read more
UbuntuTouch

[原]Ubuntu SDK 安装

在这篇文章里,你将学到如何安装Ubuntu SDK到你的系统中,并生成一个简单的应用以测试你的安装是否成功。对英文好的学习者,可以参考Ubuntu 网站中的英文地址来进行安装。如果开发者想对Ubuntu SDK的使用有更深的认识,可以参阅文章“如何使用Ubuntu SDK”。


操作系统选择

Ubuntu for phone的开发是基于Ubuntu 14.10 (Utopic)上的。为了能够使得Scope应用的开发编译成功,Ubuntu SDK应该安装在Utopic (14.10)的Ubuntu OS之中。如果你使用的操作系统不是这个版本的,你可以安装一个VM(比如VirtualBoxVMWare),在VM中再安装Ubuntu OS 14.10。关于如何安装VirtualBox,请参阅文章”怎么在Virtualbox下安装Ubuntu OS“。如果你想在你的电脑里从一个分区里安装Ubunut系统,你也可以参考文章“How to use manual partitioning during installation”。

对于一些开发者来说,我们提供了一个比较快捷的安装包。这个安装包把Ubuntu OS及SDK打到一个文件里,该文件可以一次性下载,并安装到VirtualBox中。详细的安装步骤在“在不同的系统中的virtualbox中安装Ubuntu SDK”找到。

添加Phablet Tools PPA

Phablet Tools PPA 提供了一些额外的工具来对device进行安装。这个工具是安装在从Ubuntu OS 12.04以后的版本中的。

你可以在Ubunt 14.04 Trusty 以后的版本中并不需要添加,因为它已经在Ubuntu通用的发布中。你可以通过如下的方式进行添加:

$ sudo add-apt-repository ppa:phablet-team/tools

添加Ubuntu SDK 发布 PPA中

按照一下方式添加Ubuntu SDK 发布 PPA (https://launchpad.net/~ubuntu-sdk-team/+archive/ppa)。注意使用Utopic(14.10)也要加入此PPA
键入如下命令,并输入你的Linux管理员密码来完成。

$ sudo add-apt-repository ppa:ubuntu-sdk-team/ppa

安装 Ubuntu SDK

按一下方式安装SDK。在需要的时候输入Linux管理员密码

$ sudo apt-get update && sudo apt-get install ubuntu-sdk

提示:对一些人,特别是对那些安装Ubuntu 14.10 ( Utopic)的开发者来说,必须确保所有的安装的包更新到最新的版本。这个可以通过如下的命令实现:

$ sudo apt-get update && sudo apt-get dist-upgrade

启动Ubuntu SDK IDE

  • 在Ubuntu "Unity Dash Applications lens"中寻找 "Ubuntu SDK
  • 点击找到的”Ubuntu SDK" 图标


你也可以在shell中启动Ubuntu SDK:

$ ubuntu-sdk 

提示:对一些开发者来说,他们可能很想让Ubuntu SDK IDE的图标出现在Ubuntu Unity 的启动面板中,这样可以每次很方便地启动。只要先启动SDK,然后在Ubuntu桌面的左侧的启动面板中,找到SDK的图标,并按下右键,然后选定"Lock to Launcher"。这样,SDK 就可以固定在启动的面板中了。



当我们第一次启动Ubuntu SDK时,可以看到如下的界面:



我们可以在SDK的第一次启动过程中来安装armhf chroot (为手机架构)及i386 chroot (为emulator架构)。依赖于网络的速度,这个安装的过程比较漫长,所以请大家耐心等待!

     


如果我们在SDK启动时,选择不再显示安装wizard,并且我们选择不安装armhf及i386架构,我们也可以在下面的步骤中来安装它们。具体的步骤也可以参阅“如何使用Ubuntu SDK”。

安装Ubuntu SDK armhf chroot

这个步骤是为了交叉编译我们所开发的应用(armhf格式)并部署到手机上。我们可以通过如下的步骤进行安装:

  • 启动Ubuntu SDK
  • 选中IDE菜单中的"Tools",然后在选中"Options",然后再选中”Ubuntu"。就会看到如下的画面
  • 点击"Create Click Target",然后可以看到如图所示的对话框。选择"armhf/Framework-14.10"即可。之后你可以看到安装开始。依赖于你的网络的情况,安装需要一段时间。需要耐心等待!


在上图中,我们可以看到已经安装好的"utopic ubuntu-sdk ... armhf",这里我们可以点击"update"来更新我们所安装的包,同时,我们也可以看到"Maintain"这个按钮。这个是用来对我们的chroot来进行维护的。比如说我们所开发的应用中,可能需要一个库,但它不是标准的库,没有安装。这时我们想测试时,就可以点击这个按钮,并在shell中进行安装或删除某个包。当然我们必须也要记得在手机中进行安装这个库以使编译好的应用能够运行。

等安装完后,我们可以在shell中看到如下的信息:

~$ schroot -l
chroot:click-ubuntu-sdk-14.10-armhf
chroot:trusty-amd64-armhf
chroot:trusty-armhf
chroot:utopic-amd64-armhf
source:click-ubuntu-sdk-14.10-armhf
source:trusty-amd64-armhf
source:trusty-armhf
source:utopic-amd64-armhf

这里 "chroot:click-ubuntu-sdk-14.10-armhf"就是我们在这个步骤中安装的chroot。有了这个我们就可以为手机target生成目标安装文件进行部署了

安装Ubuntu SDK i386 chroot

这个安装是为了使得以后我们含有C++代码(比如说C++ plugins)的应用能够顺利编译并使得应用在模拟器中运行。我们可以一并安装,在以后需要的时候我们可以生下这个步骤。这个安装过程同样需要很长的时间。需要耐心等待。这个安装步骤和上面几乎是一样的,只是我们需要选择"i386"架构。



安装完后,我们可以在shell中通过如下的命令查看已经安装好的chroot:

~$ schroot -l
chroot:click-ubuntu-sdk-14.10-armhf
chroot:click-ubuntu-sdk-14.10-i386
chroot:trusty-amd64-armhf
chroot:trusty-armhf
chroot:utopic-amd64-armhf
source:click-ubuntu-sdk-14.10-armhf
source:click-ubuntu-sdk-14.10-i386
source:trusty-amd64-armhf
source:trusty-armhf
source:utopic-amd64-armhf

安装模拟器

这个步骤是为了安装一个在手机一个模拟器以仿真一个手机,这样开发者可以在电脑上进行开发及测试。等调试好了以后,就可以部署到我们的真手机中以进行下一步的测试。具体的安装步骤如下:

  • Ubuntu 启动SDK
  • 选择IDE左侧的"Devices",然后在所在的界面中点击图中的"+"。这样就可以看到如下的画面
  • 在所显示的对话框中,输入所需要的模拟器的名字。选择"i386",然后点击"Create"即可。整个过程可能会花很长的时间完成。请耐心等待。这个安装虽然也可以选择"armhf"来进行模拟,但目前建议的还是"i386"架构。


注意当我们安装摸拟器时,我们可以选择“devel”或“stable”  channel(stable是最新Ubuntu的官方发行版,devel是最新经过验证的daily build)。“devel-proposed”是包含最新变化的发行版。这个版本还需要被验证,并且可能有bug。在我们的安装过程中,我们推荐使用“rtm-14.09” (release-to-manufacturer)。

 

在安装模拟器过程中,如果出现问题,可以按照上面右图所示的方式我们的安装的log信息。
有了这个模拟器,我们就可以在模拟器中运行我们开发的应用了。我们可以选择刚才生成的模拟器(myinstance),并运行它:



注意,当我们运行模拟器时,如果被提问需要密码时,这个默认的密码是“0000实际运行的效果图如下,



开发者也可以参阅https://wiki.ubuntu.com/Touch/Emulator文章来安装自己的模拟器。开发者可以在shell中使用如下的命令来运行模拟器:

$ubuntu-emulator run myinstance --scale=0.8

这里myinstance是我们已经创建好的Ubuntu emulator的名称。

如果由于一些原因,开发者看见模拟器是一个黑色的屏幕(看不见任何的内容)或者运行的速度比较慢。这有可能是我们在我们的电脑的BIOS里没有启动硬件虚拟化功能而造成的。开发者需要到自己的电脑的BIOS里的设置启动VT-X/AMD-V。开发者可以在Shell中通过如下的命令来检查自己的电脑是否支持virtualization:

 # check if the hardware support virtualzation
 $ grep -e svm -e vmx /proc/cpuinfo
 
# check if it's enabled from BIOS
 $ sudo apt-get install cpu-checker && kvm-ok

安装搜狗中文输入法


我们知道对中文应用开发者来说,中文的支持很重要。开发者可以参考我的文章“怎么在Ubuntu OS上面安装搜狗输入法及对Qt Creator的支持"来进行安装。

Qt SDK 安装

这个安装步骤是不必须的。对于有些开发者来说,想更多地学习Qt,并且在硬盘存贮允许的情况下可以在http://qt-project.org/downloads下载并安装最新的Qt SDK。Qt SDK里有丰富的例程,是我们学习Qt的一个很好的资源。


总结

至此,我们的开发安装环境基本上已经好了。在下一个章节中,我们来试着创建一个应用来检测一下我们的环境是否已经成功了。我们可以转到"开发第一个Ubuntu Touch应用"来检查我们的安装环境是否正确。

作者:UbuntuTouch 发表于2014-8-6 8:53:28 原文链接
阅读:402 评论:0 查看评论

Read more
UbuntuTouch

在这篇文章里,我们将使用Ubuntu SDK从零开始来创建一个“中国天气”的Scope应用。通过这个过程,让开发者了解Scope在Ubuntu上的开发流程,以及对Scope有更深的认识。该应用完全使用std C++来完成的。更多关于Scope的知识,可以在网址:http://developer.ubuntu.com/scopes/。我们开发应用的最终显示图为:


        


1)启动Ubuntu SDK来创建一个基本的Scope应用


首先,我们来打开我们的Ubuntu SDK来创建一个最基本的应用。我们选择菜单“New file or Project”或使用热键“Ctrl + N”。我们选择“Unity Scope”模版。



我们给我们的应用一个名字“ChinaWeather”。我们同事也选择template的类型为“Scope using HTTP+JSON API”

   

接下来,我们也同时选择不同的Kit,这样我们都可以在他们上面编译并部署我们的应用。




我们直接在电脑的Desktop上运行我们的应用。为了确保我们能够在desktop上运行我们的scope并看到界面,我们可以点击“Projects”,并在Desktop中的“Run Configuration”中进行设置。确保选中“chinaweather”。




我们可以在“Unity Scope tool”中输入北京,我们就可以看到北京的天气的情况:



如果你能运行到这里,说明你的安装环境是没有问题的。如果有问题的话,请参阅我的Ubuntu SDK安装文章。这个最基本的应用其实没有什么内容。在下面的章节中我们来向这里添加一些东西以实现我们所需要的一些东西。

如果大家有手机的话,也可以直接在手机上运行看一下运行的效果。




2)完成我们的Client API代码


我们可以看到在项目的“src”目录下有两个目录:apiscope。api目录下的代码主要是为了来访问我们的web service来得到一个json或是xml的数据。这个数据可以在我们的Scope中进行利用并得到显示。下面我们来完成我们的工作。

首先我们需要在百度的开发者网站来申请我们的开发者账号。大家可以放问网站来申请账号。我们首先来做一个测试以确保我们的账号是可以工作的。按照文中所提到的,我们可以在浏览器中输入如下的地址:http://api.map.baidu.com/telematics/v3/weather?location=%E5%8C%97%E4%BA%AC&output=json&ak=5slgyqGDENN7Sy7pw29IUvrZ。我们可以得到如下的内容:

{"error":0,"status":"success","date":"2014-09-29","results":[{"currentCity":"北京","pm25":"42","index":[{"title":"穿衣","zs":"较冷","tipt":"穿衣指数","des":"建议着大衣、呢外套加毛衣、卫衣等服装。体弱者宜着厚外套、厚毛衣。因昼夜温差较大,注意增减衣服。"},{"title":"洗车","zs":"较不宜","tipt":"洗车指数","des":"较不宜洗车,未来一天无雨,风力较大,如果执意擦洗汽车,要做好蒙上污垢的心理准备。"},{"title":"旅游","zs":"适宜","tipt":"旅游指数","des":"天气较好,温度适宜,但风稍微有点大。这样的天气适宜旅游,您可以尽情地享受大自然的无限风光。"},{"title":"感冒","zs":"易发","tipt":"感冒指数","des":"昼夜温差大,风力较强,易发生感冒,请注意适当增减衣服,加强自我防护避免感冒。"},{"title":"运动","zs":"较适宜","tipt":"运动指数","des":"天气较好,但风力较大,推荐您进行室内运动,若在户外运动请注意避风保暖。"},{"title":"紫外线强度","zs":"弱","tipt":"紫外线强度指数","des":"紫外线强度较弱,建议出门前涂擦SPF在12-15之间、PA+的防晒护肤品。"}],"weather_data":[{"date":"周一 09月29日 (实时:23℃)","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/qing.png","weather":"多云转晴","wind":"北风4-5级","temperature":"23 ~ 10℃"},{"date":"周二","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/yin.png","weather":"多云转阴","wind":"微风","temperature":"18 ~ 12℃"},{"date":"周三","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/zhenyu.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/zhenyu.png","weather":"阵雨","wind":"微风","temperature":"15 ~ 12℃"},{"date":"周四","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/duoyun.png","weather":"多云","wind":"微风","temperature":"23 ~ 13℃"}]}]}

首先,我们可以看到API是工作的。没有任何问题。显示的架构是json格式的。我们下面来修改架构中的“Client”类来完成对所得到的json格式的内容进行解析。首先,我们删除整个“Client::Current Client::weather(const string& query)”函数,因为这个是我们不需要的。为了能够编译,我们也删除或注释掉在query.cpp文件run函数中的部分内容,这样我们可以集中精力来完成这个Client API的设计。我们只留下最基本的部分以帮助我们来完成如下的设计。

void Query::run(sc::SearchReplyProxy const& reply) {
    try {
        // Start by getting information about the query
        const sc::CannedQuery &query(sc::SearchQueryBase::query());

        // Trim the query string of whitespace
        string query_string = alg::trim_copy(query.query_string());

        Client::Forecast forecast;
        if (query_string.empty()) {
            // If there is no search string, get the forecast for London
            forecast = client_.forecast_daily("北京");
        } else {
            // otherwise, get the forecast for the search string
            forecast = client_.forecast_daily(query_string);
        }

        // Register a category for the forecast
        auto forecast_cat = reply->register_category("forecast",
                                                     "7 day forecast", "", sc::CategoryRenderer(WEATHER_TEMPLATE));

        // For each of the forecast days
        for (const auto &weather : forecast.weather) {
            // Create a result
            sc::CategorisedResult res(forecast_cat);
        }

    } catch (domain_error &e) {
        // Handle exceptions being thrown by the client API
        cerr << e.what() << endl;
        reply->error(current_exception());
    }
}


为了能够正确地使用API,我们还必须在项目的设置文件中做一些设置。打开IDE项目中的api文件夹,并打开config.h文件。把它的内容修改为:

#ifndef API_CONFIG_H_
#define API_CONFIG_H_

#include <memory>
#include <string>

namespace api {

struct Config {
    typedef std::shared_ptr<Config> Ptr;

    /*
     * The root of all API request URLs
     */
    std::string apiroot { "http://api.map.baidu.com" };

    /*
     * The custom HTTP user agent string for this library
     */
    std::string user_agent { "chineweather 0.1; (foo)" };
};

}

#endif /* API_CONFIG_H_ */


为了适应我们的情况,我们把forecast_daily API修改为:

    virtual Forecast forecast_daily(const std::string &query);

这是因为我们的百度API中不需要天数。为了能够使得我们的数据结构和我们上面百度天气API接口返回的数据相匹配,我们对“client.h”做了修改:

class Client {
public:
    /**
     * Information about a City
     */
    struct City {
        unsigned int id;
        std::string name;
        std::string country;
    };

    /**
     * Weather information for a day.
     */
    struct Weather {
        std::string date;
        std::string dayPictureUrl;
        std::string nightPictureUrl;
        std::string weather;
        std::string wind;
        std::string temperature;
        std::string uri;
    };

    /**
     * A list of weather information
     */
    typedef std::deque<Weather> WeatherList;

    /**
     * Forecast information about a city
     */
    struct Forecast {
        City city;
        std::string pmIndex;
        WeatherList weather;
    };

    Client(Config::Ptr config);

    virtual ~Client() = default;

    /**
     * Get the weather forecast for the specified location and duration
     */
    virtual Forecast forecast_daily(const std::string &query);

    /**
     * Cancel any pending queries (this method can be called from a different thread)
     */
    virtual void cancel();

    virtual Config::Ptr config();

protected:
    void get(const core::net::Uri::Path &path,
             const core::net::Uri::QueryParameters ¶meters,
             Json::Value &root);

    /**
     * Progress callback that allows the query to cancel pending HTTP requests.
     */
    core::net::http::Request::Progress::Next progress_report(
            const core::net::http::Request::Progress& progress);

    /**
     * Hang onto the configuration information
     */
    Config::Ptr config_;

    /**
     * Thread-safe cancelled flag
     */
    std::atomic<bool> cancelled_;
};

}

特别值得注意的是,我们修改了weather的数据结构。这个和我们从百度API中返回的数据结构是一样的:

{"date":"周一 09月29日 (实时:23℃)","dayPictureUrl":"http://api.map.baidu.com/images/weather/day/duoyun.png","nightPictureUrl":"http://api.map.baidu.com/images/weather/night/qing.png","weather":"多云转晴","wind":"北风4-5级","temperature":"23 ~ 10℃"}

下面我们来看一看在client.cpp文件中的“get"函数。这是一个标准的函数接口。它是通过http来访问所需要访问输入参数所提供的地址,并得到相应的内容。这个内容可以是json或xml形式的。这个函数,我们不需要做任何的改变。

void Client::get(const net::Uri::Path &path, const net::Uri::QueryParameters &parameters, json::Value &root)

我们来修改forecast_daily函数,如下:

Client::Forecast Client::forecast_daily(const string& query) {
    json::Value root;

    // Build a URI and get the contents
    // The fist parameter forms the path part of the URI.
    // The second parameter forms the CGI parameters.
    get( { "telematics", "v3", "weather" },
    { { "location", query },
      { "output", "json" }, { "ak", "DdzwVcsGMoYpeg5xQlAFrXQt" } }, root);
    // e.g. http://api.map.baidu.com/telematics/v3/weather?location=%1&output=json&ak=DdzwVcsGMoYpeg5xQlAFrXQt

    Forecast result;

    //    // Iterate through the weather data
    string date = root["date"].asString();
    cerr << "date: "  << date << endl;

    int indexofYear = date.find_first_of("-", 0);
    cerr << "indexofYear: " << indexofYear << endl;

    string year = date.substr(0, indexofYear);
    cerr << "year: " << year << endl;

    int indexofMonth = date.find("-", indexofYear+1);
    cerr << "indexofMonth: " << indexofMonth << endl;

    string month = date.substr(indexofYear + 1, indexofMonth-indexofYear-1);
    cerr << "month: " << month << endl;

    string day = date.substr(indexofMonth +1, date.length()-indexofMonth);
    cerr << "day: " << day << endl;

    std::locale::global(std::locale(""));

    // current date/time based on current system
    time_t now = time(0);

    tm *localtm = localtime(&now);

    localtm->tm_year = stoi( year ) - 1900;
    localtm->tm_mon = stoi( month );
    localtm->tm_mday = stoi( day );

    json::Value results = root["results"];
    for (json::ArrayIndex index = 0; index < results.size(); ++index) {
        json::Value item = results.get(index, json::Value());

        // Extract the first weather item
        result.city.name = item["currentCity"].asString();

        cerr << "city name: " << result.city.name << endl;

        result.pmIndex = item["pm25"].asString();
        cerr << "PM index: " << result.pmIndex  << endl;

        json::Value weathers = item["weather_data"];

        for ( json::ArrayIndex i = 0; i < weathers.size(); i ++ ) {
            json::Value weather = weathers.get(i, json::Value());

            localtm->tm_mday++;

            time_t newtime = mktime(localtm);
            tm *newlocaltm = localtime(&newtime);
            char buffer[256];
            strftime(buffer, sizeof(buffer), "%a %Y年%b%d ", newlocaltm);

            string date = buffer;
            cerr << "date: " << date << endl;

            string dayPictureUrl = weather["dayPictureUrl"].asString();
            cerr << "dayPictureUrl: " << dayPictureUrl << endl;

            string nightPictureUrl = weather["nightPictureUrl"].asString();
            cerr << "nightPictureUrl: " << nightPictureUrl << endl;

            string weather1 = weather["weather"].asString();
            cerr << "weather: " << weather1 << endl;

            string temperature = weather["temperature"].asString();
            cerr << "temperature: " << temperature << endl;

            string wind = weather["wind"].asString();
            cerr << "wind: " << wind << endl;

            cerr << "====================================" << endl;

            result.weather.emplace_back(
                        Weather { date,
                                  dayPictureUrl,
                                  nightPictureUrl,
                                  weather1,
                                  wind,
                                  temperature,
                                  URI
                        }
                        );

        }
    }

    return result;
}

同时我们在client.h中定义如下的宏:

#define URI "http://www.weather.com.cn/html/weather/101010100.shtml"

重新编译项目,如果遇到任何的问题,我们必须停下来解决以使得整个项目能够被正确地编译。在Ubuntu Desktop下运行我们的应用。我们可以在Application Output窗口看见许多的输出。


3)代码讲解


src/scope/scope.cpp


这个文件定义了一个unity::scopes::ScopeBase的类。它提供了客户端用来和Scope交互的起始接口。

  • 这个类定义了“start", "stop"及"run"来运行scope。绝大多数开发者并不需要修改这个类的大部分实现。在我们的例程中,我们将不做任何的修改
  • 它也同时实现了另外的两个方法:search 和 preview。我们一般来说不需要修改这俩个方法的实现。但是他们所调用的函数在具体的文件中必须实现

注意:我们可以通过研究Scope API的头文件来对API有更多的认识。更多的详细描述,开发者可以在http://developer.ubuntu.com/api/scopes/sdk-14.10/查看。

src/scope/query.cpp


这个文件定义了一个unity::scopes::SearchQueryBase类。

这个类用来产生由用户提供的查询字符串而生产的查询结果。这个结果可能是基于json或是xml的。这个类可以用来进行对返回的结果处理并显示。

  • 得到由用户输入的查询字符串
  • 向web services发送请求
  • 生成搜索的结果(根据每个不同而不同)
  • 创建搜索结果category(比如不同的layout-- grid/carousel)
  • 根据不同的搜寻结果来绑定不同的category以显示我们所需要的UI
  • 推送不同的category来显示给最终用户

创建并注册CategoryRenderers

在本例中,我们创建了两个JSON objects. 它们是最原始的字符串,如下所示,它有两个field:template及components。template是用来定义是用什么layout来显示我们所搜索到的结果。这里我们选择的是”grid"及小的card-size。components项可以用来让我们选择预先定义好的field来显示我们所需要的结果。这里我们添加了"title"及“art"。


std::string CR_GRID = R"(
    {
        "schema-version" : 1,
        "template" : {
            "category-layout" : "grid",
            "card-size": "medium"
        },
        "components" : {
            "title" : "title",
            "art" : {
                "field": "art",
                "aspect-ratio": 1.6,
                "fill-mode": "fit"
            }
        }
    }

这是一个grid的layout,同时我们可以显示一个title及一个图片(art)。我们在文件的开始部分加入如上的的template的定义。

更多关于 CategoryRenderer 类的介绍可以在 docs找到。

我们为每个JSON Object创建了一个CategoryRenderer,并同时向reply object注册。我们修改我们的run方法来实现显示:


void Query::run(sc::SearchReplyProxy const& reply) {
    try {
        // Start by getting information about the query
        const sc::CannedQuery &query(sc::SearchQueryBase::query());

        // Trim the query string of whitespace
        string query_string = alg::trim_copy(query.query_string());

        Client::Forecast forecast;

        cerr << "query_string: " << query_string;

        if (query_string.empty()) {
            // If there is no search string, get the forecast for London
            forecast = client_.forecast_daily("北京");
        } else {
            // otherwise, get the forecast for the search string
            forecast = client_.forecast_daily(query_string);
        }

        // Register a category for the forecast
        auto forecast_cat = reply->register_category("Chineweather",
                                                     forecast.city.name,
                                                     "", sc::CategoryRenderer(CR_GRID));

        // For each of the forecast days
        for (const auto &weather : forecast.weather) {

            // Create a result
            sc::CategorisedResult res(forecast_cat);

            // Set the rest of the attributes
            res.set_art(weather.dayPictureUrl);
            stringstream ss(stringstream::in | stringstream::out);
            ss << "白天: " << weather.date;


            res.set_title(ss.str());

            // We must have a URI
            res.set_uri(weather.uri);
            res.set_dnd_uri(weather.uri);

            // Add some extra data, and they will be shown in the preview
            res["weather"] = sc::Variant(weather.weather);
            res["temperature"] = sc::Variant(weather.temperature);
            res["wind"] = sc::Variant(weather.wind);

            // Push the result
            if (!reply->push(res)) {
                // If we fail to push, it means the query has been cancelled.
                // So don't continue;
                return;
            }

            res.set_art(weather.nightPictureUrl);
            ss.str(std::string());
            ss << "夜晚: " << weather.date;
            res.set_title(ss.str());

            // We must have a URI
            res.set_uri(weather.uri);
            res.set_dnd_uri(weather.uri);

            // Push the result
            if (!reply->push(res)) {
                // If we fail to push, it means the query has been cancelled.
                // So don't continue;
                return;
            }

        }

    } catch (domain_error &e) {
        // Handle exceptions being thrown by the client API
        cerr << e.what() << endl;
        reply->error(current_exception());
    }
}

我们从我们的Client API中的Client::Forecast来获取我们所需要的web service的数据,把数据填入到相应的CategorisedResult中。

我们运行我们的程序,我们可以在屏幕上看到如下的画面:

    

我们也可以尝试点击我们的画面,在另外一个画面中可以看到一个图片。到这里,我们基本上已经看到了Scope工作的了。我们下面来更进一步来在Preview中显示更多的内容。

src/scope/preview.cpp

这个文件定义了一个unity::scopes::PreviewQueryBase类。

这个类定义了一个widget及一个layout来展示我们搜索到的结果。这是一个preview结i果,就像它的名字所描述的那样。

  • 定义在preview时所需要的widget
  • 让widget和搜索到的数据field一一对应起来
  • 定义不同数量的layout列(由屏幕的尺寸来定)
  • 把不同的widget分配到layout中的不同列中
  • 把reply实例显示到layout的widget中

大多数的代码在“run&quot;中实现。跟多关于这个类的介绍可以在http://developer.ubuntu.com/api/scopes/sdk-14.10/previewwidgets/找到。

Preview

Preview需要来生成widget并连接它们的field到CategorisedResult所定义的数据项中。它同时也用来为不同的显示环境(比如屏幕尺寸)生成不同的layout。根据不同的显示环境来生成不同数量的column。

Preview Widgets

这是一组预先定义好的widgets。每个都有一个类型。更据这个类型我们可以生成它们。你可以在这里找到Preview Widget列表及它们提供的的field类型。

这个例子使用了如下的widgets

  • header:它有title及subtitle field
  • image:它有source field有来显示从哪里得到这个art
  • text:它有text field
  • action:用来展示一个有"Open"的按钮。当用户点击时,所包含的URI将被打开

如下是一个例子,它定义了一个叫做“headerId"的PreviewWidget。第二个参数是它的类型"header"。

  1. PreviewWidget w_header("headerId""header");  

最终的程序如下:

#include <scope/preview.h>

#include <unity/scopes/ColumnLayout.h>
#include <unity/scopes/PreviewWidget.h>
#include <unity/scopes/PreviewReply.h>
#include <unity/scopes/Result.h>
#include <unity/scopes/VariantBuilder.h>

#include <iostream>

namespace sc = unity::scopes;

using namespace std;
using namespace scope;
using namespace unity::scopes;

Preview::Preview(const sc::Result &result, const sc::ActionMetadata &metadata) :
    sc::PreviewQueryBase(result, metadata) {
}

void Preview::cancelled() {
}

void Preview::run(sc::PreviewReplyProxy const& reply) {
    //
    // This preview handler just reuses values of the original result via
    // add_attribute_mapping() calls, but it could also do another network
    // request for more details if needed.
    //

    // Client can display Previews differently depending on the context
    // By creates two layouts (one with one column, one with two) and then
    // adding widgets to them differently, Unity can pick the layout the
    // scope developer thinks is best for the mode
    sc::ColumnLayout layout1col(1), layout2col(2);

    // add columns and widgets (by id) to layouts.
    // The single column layout gets one column and all widets
    layout1col.add_column({"headerId", "artId", "tempId", "windId", "actionsId"});

    // The two column layout gets two columns.
    // The first column gets the art and header widgets (by id)
    layout2col.add_column({"artId", "headerId"});
    // The second column gets the info and actions widgets
    layout2col.add_column({"infoId", "windId", "actionsId"});

    // Push the layouts into the PreviewReplyProxy intance, thus making them
    // available for use in Preview diplay
    reply->register_layout({layout1col, layout2col});

    //Create some widgets
    // header type first. note 'headerId' used in layouts
    // second field ('header) is a standard preview widget type
    PreviewWidget w_header("headerId", "header");
    // This maps the title field of the header widget (first param)  to the
    // title field in the result to be displayed in this preview, thus providing
    // the result-specific data to the preview for display
    w_header.add_attribute_mapping("title", "title"); // attribute, result field name
    // Standard subtitle field here gets our 'artist' key value
    w_header.add_attribute_mapping("subtitle", "weather");

    PreviewWidget w_art("artId", "image");
    w_art.add_attribute_mapping("source", "art"); // // key, result field name

    PreviewWidget w_info("tempId", "text");
    w_info.add_attribute_mapping("text", "temperature");

    PreviewWidget w_wind("windId", "text");
    w_wind.add_attribute_mapping("text", "wind");

    Result result = PreviewQueryBase::result();
//    QString urlString(result["uri"].get_string().c_str());
    cerr << "[Details] GET " << result["uri"].get_string() << endl;

    // Create an Open button and provide the URI to open for this preview result
    PreviewWidget w_actions("actionsId", "actions");
    VariantBuilder builder;
    builder.add_tuple({
            {"id", Variant("open")},
            {"label", Variant("Open")},
            {"uri", Variant(result["uri"].get_string())} // uri set, this action will be handled by the Dash
        });
    w_actions.add_attribute_value("actions", builder.end());

    // Bundle out widgets as required into a PreviewWidgetList
    PreviewWidgetList widgets({w_header, w_art, w_info, w_wind, w_actions});
    // And push them to the PreviewReplyProxy as needed for use in the preview
    reply->push(widgets);
}


我们再重新运行程序,我们可以看到如下的画面:

      


在手机上的运行情况如下:

   

最后,我们可以找到data文件夹,并换上我们喜欢的应用图标。这样,我们就基本完成了我们所要完成的应用了。

所有的程序代码可以在如下的网址找到:

bzr branch lp:~liu-xiao-guo/debiantrial/chinaweathernew

该应用的另外一个用Qt进行开发的范例可以在如下的网址找到:

bzr branch lp:~liu-xiao-guo/debiantrial/chinaweatherfinal

4)调试应用

当我们在开发应用时,我们可以通过上面的“cerr”在“Application Output”输出结果来查看结果。当在手机运行时,我们也可以通过查看如下的文件来看Scope的运行情况:



我们可以通过查看在手机中的文件“~/.cache/upstart/scope-registry.log”来看最新的Scope的运行情况。




作者:UbuntuTouch 发表于2014-9-29 11:20:38 原文链接
阅读:365 评论:0 查看评论

Read more
UbuntuTouch

[原]如何在Ubuntu OS上开发Scope (视频)

在这个俩个视频里,我来介绍如何利用Ubuntu SDK从零开始在Ubuntu OS上开发一个点评Scope。如果大家想看文章的话,请参阅文章“在Ubuntu OS上创建一个dianping Scope (Qt JSON)”。更多关于Ubuntu Scope的介绍可以在网站http://developer.ubuntu.com/scopes/找到。


Scope开发视频第一部分

视频的地址在:http://v.youku.com/v_show/id_XODM5ODIxMDgw.html

视频的源码在:bzr branch lp:~liu-xiao-guo/debiantrial/dianpingvideo

Scope开发视频第二部分

视频的地址在:http://v.youku.com/v_show/id_XODQxOTA1OTk2.html

视频源码在:bzr branch lp:~liu-xiao-guo/debiantrial/dianpingvideo2


如果大家有什么意见或不清楚的,欢迎大家进行评论!

作者:UbuntuTouch 发表于2014-12-2 15:26:31 原文链接
阅读:324 评论:0 查看评论

Read more
UbuntuTouch

[原]Ubuntu手机应用QML开发 (视频)

在这个视频里,我们从零开始来展示如何使用Ubuntu SDK来开发一个Flickr应用,并部署到手机和模拟器中。本视频可以在地址:http://v.youku.com/v_show/id_XODQxMjUwMzMy.html看到。


教程的博客地址:使用Ubuntu SDK开发Flickr应用教程


视频的源码在地址:bzr branch lp:~liu-xiao-guo/debiantrial/flickrvideo

作者:UbuntuTouch 发表于2014-12-4 13:57:13 原文链接
阅读:294 评论:0 查看评论

Read more
Prakash

This Thanksgiving, Amazon Fire Phone is available at a special price of $199. For that price it looks like a great phone.

  • Unlocked
  • 2.2GHz quad-core processor
  • 2GB RAM
  • Bright 4.7″ HD display
  • 13 MP camera with optical image stabilization, HDR, and LED flash
  • 4 G LTE
  • NFC support
  • Free Headphones
  • Free Amazon Prime for 1 year.

The only reasons why I wouldn’t buy this is..

  • Tied to Amazon app store, no Google Play,
  • 4.7″ Screen, if you are in the market for a bigger display
  • No expandable memory slot
  • GSM Only


Read more
UbuntuTouch

在这篇文章中,我们来介绍怎么在Ubuntu OS上本地化一个应用。本地化对很多的应用很重要。我们重点介绍怎么把应用本地化为中文。


1)创建一个最基本的应用


首先打开我们的Ubuntu SDK,并选择“App with Simple UI and localization”的模版。




然后接下来:

   



我们完成后我们的项目后,我们发现在项目的“LocalizeQml/po”目录中有生产一个文件“CMakeLists.txt”。当我们第一次运行我们的应用(无论在任何的architecture下),SDK会帮我们生产另外一个文件“com.ubuntu.developer.liu-xiao-guo.localizeqml.pot”。这个文件就是我们需要本地化的文件。我们在当前的文件目录下,复制这个文件,并重新命名为“zh_CN.po”。注意这里“zh_CN”是为中国地区简体中文的国际语言代码。我们打开该文件,并同时翻译该文件:

# 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: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-11-20 12:05+0800\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=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: ../app/ui/HelloTab.qml:6
msgid "Hello.."
msgstr "您好"

#: ../app/ui/HelloTab.qml:18
msgid "Hello World"
msgstr "您好,世界"

#: ../app/ui/HelloTab.qml:26
msgid "You can change the Tab from Page title above."
msgstr "您可以从页面的标题上改变标签"

#: ../app/ui/WorldTab.qml:6
msgid "..World!"
msgstr "..世界!"

#: ../app/ui/WorldTab.qml:18
msgid "WorldTab"
msgstr "世界标签"

#: /home/liuxg/release/build-localizedqml-Desktop-Default/po/localizedqml.desktop.in.h:1
msgid "LocalizeQml"
msgstr "本地化QML"

这里必须注意的是,必须设置charset为UTF-8才可以正常显示中文。我们可以在手机或模拟器中输入一下的命令来查看当前的手机的语言:



我们再重新运行我们的应用。在手机上看到的界面如下:



我们看见我们的UI现在都是显示的是中文。我们现在来回顾一下我的QML文件的内容:

Tab {
    title: i18n.tr("Hello..")

    page: Page {
        Column {
            spacing: units.gu(2)
            anchors.centerIn: parent

            HelloComponent {
                objectName: "helloTab_HelloComponent"

                anchors.horizontalCenter: parent.horizontalCenter

                text: i18n.tr("Hello World")
            }

            Label {
                objectName: "helloTab_label"

                anchors.horizontalCenter: parent.horizontalCenter

                text: i18n.tr("You can change the Tab from Page title above.")
            }
        }
    }
}

我们可以看到所有的字符串是以“i18n.tr”来输出的。它可以帮我们进行本地化。当然我们可以把我们的应用本地化到任何一个其它的语言。

为了说明问题,我们把我们的应用改为:

Tab {
    title: i18n.tr("Hello..")

    page: Page {
        Column {
            spacing: units.gu(2)
            anchors.centerIn: parent

            HelloComponent {
                objectName: "helloTab_HelloComponent"

                anchors.horizontalCenter: parent.horizontalCenter

                text: i18n.tr("Hello World")
            }

            Label {
                objectName: "helloTab_label"

                anchors.horizontalCenter: parent.horizontalCenter

                text: i18n.tr("You can change the Tab from Page title above.")
            }

            Button {
                text: i18n.tr("Press me")
            }
        }
    }
}

重新运行我们的应用,我们看到的是英文的界面。我们也同时查看一下我们在“po”目录下的“com.ubuntu.developer.liu-xiao-guo.localizeqml.pot”,我们看见我们新添加的“Press me”在这个文件中。我们需要重新把它添加到我们的“zh_CN.po”文件中去。

# 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: \n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2014-11-20 12:05+0800\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=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"

#: ../app/ui/HelloTab.qml:6
msgid "Hello.."
msgstr "您好"

#: ../app/ui/HelloTab.qml:18
msgid "Hello World"
msgstr "您好,世界"

#: ../app/ui/HelloTab.qml:26
msgid "You can change the Tab from Page title above."
msgstr "您可以从页面的标题上改变标签"

#: ../app/ui/WorldTab.qml:6
msgid "..World!"
msgstr "..世界!"

#: ../app/ui/WorldTab.qml:18
msgid "WorldTab"
msgstr "世界标签"

#: /home/liuxg/release/build-localizedqml-Desktop-Default/po/localizedqml.desktop.in.h:1
msgid "LocalizeQml"
msgstr "本地化QML"

#: ../app/ui/HelloTab.qml:30
msgid "Press me"
msgstr "按一下我"

重新运行我们的应用:



我们看到新的字符串已经被翻译了。我们可以在我们的shell中输入如下的命名:



我们可以看见一个.mo的本地化文件被打入包中,并存于“zh_CN”下的文件目录中。整个应用的源码在如下的地址找到:

bzr branch lp:~liu-xiao-guo/debiantrial/localizeqml


作者:UbuntuTouch 发表于2014-11-28 15:05:01 原文链接
阅读:179 评论:0 查看评论

Read more
Daniel Holbach

I’m very happy that the ubuntu-community-team mailing list is seeing lots of discussion right now. It shows how many people deeply care about the direction of Ubuntu’s community and have ideas for how to improve things.

Looking back through the discussion of the last weeks, I can’t help but notice a few issues we are running into – issues all to common on open source project mailing lists. Maybe you all have some ideas on how we could improve the discussion?

  • Bikeshedding
    The term bikeshedding has a negative connotation, but it’s a very natural phenomenon. Rouven, a good friend of mine, recently pointed out that the recent proposal to change the statutes of the association behind our coworking space (which took a long time to put together) received no comments on the internal mailing list, whereas a change of the coffee brand seemed to invite comments from everyone.
    It is quite natural for this to happen. In a bigger proposal it’s natural for us to comment on anything that is tangible. Discussions in our community of more technical people you will often see discussions about which technology to use, rather than an answer which tries to comment on all aspects.
  • Idea overload
    Being a creative community can sometimes be a bit of a curse. You end up with different proposals plus additional ideas and nobody or few to actually implement them.
  • Huge proposals
    Sometimes you see a mail on a list which lists a huge load of different things. Without somebody who tracks where the discussion is going, summing things up, making lists of work items, etc. it will be very hard to convert a discussion into an actual project.
  • Derailing the conversation
    You’ve all seen this happen: you start the conversation with a specific problem or proposal and end up discussing something entirely different.

All of the above are nothing new, but in a part of our project where discussions tend to be quite general and where we have contributors from many different parts of the community some of the above are even more true.

Personally I feel that all of the above are fine problems to have. We are creative and we have ideas on how to improve things – that’s great. In my mind I always treated the ubuntu-community-team mailing list as a place to kick around ideas, to chat and to hang out and see what others are doing.

As I care a lot about our community and I’d still like to figure out how we can avoid the risk of some of the better ideas falling through the cracks. What do you think would help?

Maybe a meeting, maybe every two weeks to pick up some of the recent discussion and see together as a group if we can convert some of the discussion into something which actually flies?

Read more
UbuntuTouch

[原]Ubuntu OS Scope开发视频(英文)

在这篇文章中,我们来介绍一下我们录制的Scope开发的视频。这些视频是我们公司的社区team帮录制的。它们的内容是英文的。希望对大家的开发有帮助。


1)Scope开发介绍


2)为Scope添加Location支持


3)设置Scope开发环境


4)Scope开发How-tos



5)如何在装置中运行应用

http://v.youku.com/v_show/id_XODM5MjM4Njg0.html

作者:UbuntuTouch 发表于2014-11-27 19:13:50 原文链接
阅读:367 评论:0 查看评论

Read more
Sergio Schvezov

Travis and ruby gems setup on Ubuntu

Quick install

Most of the instalation instructions that dangle the web just make you sudo gem install, I don’t like that, so here’s the quick reference for when I need to do this next time:

sudo apt install ruby-dev
export GEM_HOME=$HOME/gems
gem install travis -v 1.7.4 --no-rdoc --no-ri

And this goes into ~/.bashrc:

export GEM_HOME=$HOME/gems
export PATH=$PATH:$GEM_HOME/bin

Read more
David Callé

Now that your scope is in a working state, it’s time to get it ready for publication. In this tutorial you will learn how to make your scope look good when the user is browsing the store or the list of scopes installed on the phone.

In the next steps, we are going to prepare a few graphics, edit the <scope>.ini file located in the data directory of your project and package the scope for the store.

Read…

scope_prev_all

Read more
facundo

Decime quien sos vos


El título de este post es robado a un maravilloso programa de Eduardo Aliverti.

Es un programa de radio que sale desde hace años por Radio Nacional los domingos a las 10hs. Se basa en una entrevista de Aliverti a alguna personalidad, armando un diálogo tranquilo, profundo, inteligente.

La dinámica es bastante minimalista: sólo Aliverti charlando con el entrevistado. Nada más. La producción es de Roxana Russo, de extensísima carrera, y directora de la carrera de Periodismo en ETER (escuela donde terminé el curso de Locución y Técnicas Vocales hace un par de meses, :) ).

En palabras de ellos mismos:

        "Decime quién sos vos" es un programa de entrevistas tan distendidas como agudas e intimistas donde convergen personalidades emblemáticas del pensamiento, la cultura, el arte, el espectáculo, el deporte.

¿Por qué les cuento esto? En parte porque el programa se merece ampliamente una recomendación: es uno de los (casi ningún) programas de radio y televisión que escucho religiosamente.

Pero también porque van a poder bajarlo de forma fácil usando Encuentro, a partir de la versión 2.1 que acabo de liberar.

Meter "Decime quien sos vos" en Encuentro me llevó *muchísimo* trabajo (incluso tuve que hacer una biblioteca para parsear SWFs en Python), pero la posibilidad de buscar fácilmente entrevistados para poder bajar el programa lo valía.

Entonces, ahora es muy fácil escuchar entrevistas de calidad a (entre otros) Pepe Soriano, Hector Larrea, Teresa Parodi, Carlos Ulanosvsky, Horacio Fontova, Lalo Mir, Horacio Verbitsky, Lito Vitale, Adrián Paenza, Walter Malosetti, Luis Salinas, Roberto Perfumo, Abelardo Castillo, Gonzalo Bonadeo, Luis María Pescetti, Alejandro Dolina, Lito Cruz, etcétera, etcétera, y recontra etcétera.

Bajen/instalen el nuevo Encuentro, refresquen la metadata, y además de todo lo que pueden encontrar ahí, filtren u ordenen por este nuevo programa, y van a ver que el contenido es invaluable.

Que lo disfruten, :)

Read more
Michael Hall

The Ubuntu Core Apps project has proven that the Ubuntu community is not only capable of building fantastic software, but they’re capable of the meeting the same standards, deadlines and requirements that are expected from projects developed by employees. One of the things that I think made Core Apps so successful was the project management support that they all received from Alan Pope.

Project management is common, even expected, for software developed commercially, but it’s just as often missing from community projects. It’s time to change that. I’m kicking off a new personal[1] project, I’m calling it the Ubuntu Incubator.

get_excited_banner_banner_smallThe purpose of the Incubator is to help community projects bootstrap themselves, obtain the resources they need to run their project, and put together a solid plan that will set them on a successful, sustainable path.

To that end I’m going to devote one month to a single project at a time. I will meet with the project members regularly (weekly or every-other week), help define a scope for their project, create a spec, define work items and assign them to milestones. I will help them get resources from other parts of the community and Canonical when they need them, promote their work and assist in recruiting contributors. All of the important things that a project needs, other than direct contributions to the final product.

I’m intentionally keeping the scope of my involvement very focused and brief. I don’t want to take over anybody’s project or be a co-founder. I will take on only one project at a time, so that project gets all of my attention during their incubation period. The incubation period itself is very short, just one month, so that I will focus on getting them setup, not on running them.  Once I finish with one project, I will move on to the next[2].

How will I choose which project to incubate? Since it’s my time, it’ll be my choice, but the most important factor will be whether or not a project is ready to be incubated. “Ready” means they are more than just an idea: they are both possible to accomplish and feasible to accomplish with the person or people already involved, the implementation details have been mostly figured out, and they just need help getting the ball rolling. “Ready” also means it’s not an existing project looking for a boost, while we need to support those projects too, that’s not what the Incubator is for.

So, if you have a project that’s ready to go, but you need a little help taking that first step, you can let me know by adding your project’s information to this etherpad doc[3]. I’ll review each one and let you know if I think it’s ready, needs to be defined a little bit more, or not a good candidate. Then each month I’ll pick one and reach out to them to get started.

Now, this part is important: don’t wait for me! I want to speed up community innovation, not slow it down, so even if I add your project to the “Ready” queue, keep on doing what you would do otherwise, because I have no idea when (or if) I will be able to get to yours. Also, if there are any other community leaders with project management experience who have the time and desire to help incubate one of these project, go ahead and claim it and reach out to that team.

[1] While this compliments my regular job, it’s not something I’ve been asked to do by Canonical, and to be honest I have enough Canonical-defined tasks to consume my working hours. This is me with just my community hat on, and I’m inclined to keep it that way.

[2] I’m not going to forget about projects after their month is up, but you get 100% of the time I spend on incubation during your month, after that my time will be devoted to somebody else.

[3] I’m using Etherpad to keep the process as lightweight as possible, if we need something better in the future we’ll adopt it then.

Read more
Diogo Matsubara

Agenda

  • Review ACTION points from previous meeting
    • None
  • V Development
  • Server & Cloud Bugs (caribou)
  • Weekly Updates & Questions for the QA Team (psivaa)
  • Weekly Updates & Questions for the Kernel Team (smb, sforshee, arges)
  • Ubuntu Server Team Events
  • Open Discussion
  • Announce next meeting date, time and chair

Minutes

Meeting Actions
  • matsubara to chase someone that can update release bugs report: http://reqorts.qa.ubuntu.com/reports/rls-mgr/rls-v-tracking-bug-tasks.html#ubuntu-server
Weekly Updates & Questions for the Kernel Team (smb, sforshee, arges)
  • smb reports: “I did a few stable uploads for Xen in Utopic and Trusty. Though zul, you may want to hold back doing cloud-archive versions. There is more to come. ;) Also from some email report on xen-devel there are a few things missing to make openstack and xen a better experience (bug #1396068 and bug #1394327 at least). I am working on getting things applied and SRUed.”
Agree on next meeting date and time

Next meeting will be on Tuesday, Dec 2nd at 16:00 UTC in #ubuntu-meeting. kickinz1 will chair.

IRC Log
http://ubottu.com/meetingology/logs/ubuntu-meeting/2014/ubuntu-meeting.2014-11-25-16.01.html

Read more
Dustin Kirkland

Try These 7 Tips in Your Next Blog Post


In a presentation to my colleagues last week, I shared a few tips I've learned over the past 8 years, maintaining a reasonably active and read blog.  I'm delighted to share these with you now!

1. Keep it short and sweet


Too often, we spend hours or days working on a blog post, trying to create an epic tome.  I have dozens of draft posts I'll never finish, as they're just too ambitious, and I should really break them down into shorter, more manageable articles.

Above, you can see Abraham Lincoln's Gettysburg Address, from November 19, 1863.  It's merely 3 paragraphs, 10 sentences, and less than 300 words.  And yet it's one of the most powerful messages ever delivered in American history.  Lincoln wrote it himself on the train to Gettysburg, and delivered it as a speech in less than 2 minutes.

2. Use memorable imagery


Particularly, you need one striking image at the top of your post.  This is what most automatic syndicates or social media platforms will pick up and share, and will make the first impression on phones and tablets.

3. Pen a catchy, pithy title


More people will see or read your title than the post itself.  It's sort of like the chorus to that song you know, but you don't know the rest of the lyrics.  A good title attracts readers and invites re-shares.

4. Publish midweek


This is probably more applicable for professional, rather than hobbyist, topics, but the data I have on my blog (1.7 million unique page views over 8 years), is that the majority of traffic lands on Tuesday, Wednesday, and Thursday.  While I'm writing this very post on a rainy Saturday morning over a cup of coffee, I've scheduled it to publish at 8:17am (US Central time) on the following Tuesday morning.

5. Share to your social media circles


My posts are generally professional in nature, so I tend to share them on G+, Twitter, and LinkedIn.  Facebook is really more of a family-only thing for me, but you might choose to share your posts there too.  With the lamentable death of the Google Reader a few years ago, it's more important than ever to share links to posts on your social media platforms.

6. Hope for syndication, but never expect it

So this is the one "tip" that's really out of your control.  If you ever wake up one morning to an overflowing inbox, congratulations -- your post just went "viral".  Unfortunately, this either "happens", or it "doesn't".  In fact, it almost always "doesn't" for most of us.

7. Engage with comments only when it makes sense


If you choose to use a blog platform that allows comments (and I do recommend you do), then be a little careful about when and how to engage in the comments.  You can easily find yourself overwhelmed with vitriol and controversy.  You might get a pat on the back or two.  More likely, though, you'll end up under a bridge getting pounded by a troll.  Rather than waste your time fighting a silly battle with someone who'll never admit defeat, start writing your next post.  I ignore trolls entirely.

A Case Study

As a case study, I'll take as an example the most successful post I've written: Fingerprints are Usernames, Not Passwords, with nearly a million unique page views.

  1. The entire post is short and sweet, weighing in at under 500 words and about 20 sentences
  2. One iconic, remarkable image at the top
  3. A succinct, expressive title
  4. Published on Tuesday, October 1, 2013
  5. 1561 +1's on G+, 168 retweets on Twitter
  6. Shared on Reddit and HackerNews (twice)
  7. 434 comments, some not so nice
Cheers!
Dustin


Read more
UbuntuTouch

[原]如何使用Ubuntu SDK (视频)

在这个视频里,我们介绍了如何使用我们的Ubuntu SDK来开发我们的应用。视频的地址可以在youku.com的如下的地址可以找到:http://v.youku.com/v_show/id_XODM0NDg0Njk2.html




作者:UbuntuTouch 发表于2014-11-25 12:13:10 原文链接
阅读:390 评论:0 查看评论

Read more
UbuntuTouch

由于一些平台安全性的原因,Ubuntu手机目前暂时没有提供供第三方开发者发送短信及拨打电话的接口,但是在实际的应用中,我们也许会需要用到发送短信息或拨打电话。这个时候我们怎么办呢?我们在前面的文章“使用URL dispatcher的范例”中已经介绍了如何使用url dispatcher来调用第三方应用的方法。这里我们用该方法来展示如何在我们的应用中发送短信息及拨打电话。


首先,我们创建一个最简单的“App with Simple UI”模版应用,并修改我们的“main.qml”文件如下:


import QtQuick 2.0
import Ubuntu.Components 1.1
import Ubuntu.Components.ListItems 0.1 as ListItem

/*!
    \brief MainView with a Label and Button elements.
*/

MainView {
    // objectName for functional testing purposes (autopilot-qt5)
    objectName: "mainView"

    // Note! applicationName needs to match the "name" field of the click manifest
    applicationName: "com.ubuntu.developer.liu-xiao-guo.phone"

    /*
     This property enables the application to change orientation
     when the device is rotated. The default is false.
    */
    //automaticOrientation: true

    // Removes the old toolbar and enables new features of the new header.
    useDeprecatedToolbar: false

    width: units.gu(50)
    height: units.gu(75)

    Page {
        title: i18n.tr("Phone")

        function call(phonenumber) {
            Qt.openUrlExternally("tel:///" + encodeURIComponent(phonenumber))
        }

        function sendMessage(phonenumber, text) {
            Qt.openUrlExternally("message:///" + encodeURIComponent(phonenumber))
        }


        Column {
            spacing: units.gu(1)
            anchors {
                margins: units.gu(2)
                fill: parent
            }

            Row {
                anchors.horizontalCenter: parent.horizontalCenter

                Label {
                    anchors.verticalCenter: parent.verticalCenter
                    text: i18n.tr("Number: ")
                }

                TextField {
                    id: inputnumber
                    placeholderText: "please type your phone number"
                    text: "1111111111"
                }
            }

            Button {
                width: parent.width
                text: i18n.tr("Call")

                onClicked: {
                    call(inputnumber.text)
                }
            }

            ListItem.Divider {}

            Row {
                anchors.horizontalCenter: parent.horizontalCenter

                Label {
                    anchors.verticalCenter: parent.verticalCenter
                    text: i18n.tr("Number: ")
                }

                TextField {
                    id: inputnumber1
                    placeholderText: "please type your phone number"
                    text: "22222222222"
                }
            }

            TextEdit {
                id: messageText
            }

            Button {
                width: parent.width
                text: i18n.tr("Send Message")

                onClicked: {
                    sendMessage(inputnumber1.text)
                }
            }
        }
    }
}

这个应用的设计非常简单。我们的UI如下:




我们在上面的号码输入框中输入自己想要拨打或发送短信的号码,按下“Call”或“Send Message”按钮,就可以拨打电话或发送短信了。只不过短信或电话的应用被调用起来来完成这个动作。从安全的角度来说,这个需要用户的交互才可以完成。对手机是非常安全的。我们使用了如下的代码来完成url dispatcher的工作:

      function call(phonenumber) {
            Qt.openUrlExternally("tel:///" + encodeURIComponent(phonenumber))
        }

        function sendMessage(phonenumber, text) {
            Qt.openUrlExternally("message:///" + encodeURIComponent(phonenumber))
        }


整个应用的完整代码在如下的地址可以找到:

bzr branch lp:~liu-xiao-guo/debiantrial/phone



作者:UbuntuTouch 发表于2014-11-25 11:51:26 原文链接
阅读:335 评论:0 查看评论

Read more
Colin Ian King

Recently I was playing around with CPU loading and was trying to estimate the number of compute operations being executed on my machine.  In particular, I was interested to see how many instructions per cycle and stall cycles I was hitting on the more demanding instructions.   Fortunately, perf stat allows one to get detailed processor statistics to measure this.

In my first test, I wanted to see how the Intel rdrand instruction performed with 2 CPUs loaded (each with a hyper-thread):


$ perf stat stress-ng --rdrand 4 -t 60 --times
stress-ng: info: [7762] dispatching hogs: 4 rdrand
stress-ng: info: [7762] successful run completed in 60.00s
stress-ng: info: [7762] for a 60.00s run time:
stress-ng: info: [7762] 240.01s available CPU time
stress-ng: info: [7762] 231.05s user time ( 96.27%)
stress-ng: info: [7762] 0.11s system time ( 0.05%)
stress-ng: info: [7762] 231.16s total time ( 96.31%)

Performance counter stats for 'stress-ng --rdrand 4 -t 60 --times':

231161.945062 task-clock (msec) # 3.852 CPUs utilized
18,450 context-switches # 0.080 K/sec
92 cpu-migrations # 0.000 K/sec
821 page-faults # 0.004 K/sec
667,745,260,420 cycles # 2.889 GHz
646,960,295,083 stalled-cycles-frontend # 96.89% frontend cycles idle
stalled-cycles-backend
13,702,533,103 instructions # 0.02 insns per cycle
# 47.21 stalled cycles per insn
6,549,840,185 branches # 28.334 M/sec
2,352,175 branch-misses # 0.04% of all branches

60.006455711 seconds time elapsed

stress-ng's rdrand test just performs a 64 bit rdrand read and loops on this until the data is ready, and performs this 32 times in an unrolled loop.  Perf stat shows that each rdrand + loop sequence on average consumes about 47 stall cycles showing that rdrand is probably just waiting for the PRNG block to produce random data.

My next experiment was to run the stress-ng ackermann stressor; this performs a lot of recursion, hence one should see a predominantly large amount of branching.

$ perf stat stress-ng --cpu 4 --cpu-method ackermann -t 60 --times
stress-ng: info: [7796] dispatching hogs: 4 cpu
stress-ng: info: [7796] successful run completed in 60.03s
stress-ng: info: [7796] for a 60.03s run time:
stress-ng: info: [7796] 240.12s available CPU time
stress-ng: info: [7796] 226.69s user time ( 94.41%)
stress-ng: info: [7796] 0.26s system time ( 0.11%)
stress-ng: info: [7796] 226.95s total time ( 94.52%)

Performance counter stats for 'stress-ng --cpu 4 --cpu-method ackermann -t 60 --times':

226928.278602 task-clock (msec) # 3.780 CPUs utilized
21,752 context-switches # 0.096 K/sec
127 cpu-migrations # 0.001 K/sec
927 page-faults # 0.004 K/sec
594,117,596,619 cycles # 2.618 GHz
298,809,437,018 stalled-cycles-frontend # 50.29% frontend cycles idle
stalled-cycles-backend
845,746,011,976 instructions # 1.42 insns per cycle
# 0.35 stalled cycles per insn
298,414,546,095 branches # 1315.017 M/sec
95,739,331 branch-misses # 0.03% of all branches

60.032115099 seconds time elapsed

..so about 35% of the time is used in branching and we're getting  about 1.42 instructions per cycle and no many stall cycles, so the code is most probably executing inside the instruction cache, which isn't surprising because the test is rather small.

My final experiment was to measure the stall cycles when performing complex long double floating point math operations, again with stress-ng.

$ perf stat stress-ng --cpu 4 --cpu-method clongdouble -t 60 --times
stress-ng: info: [7854] dispatching hogs: 4 cpu
stress-ng: info: [7854] successful run completed in 60.00s
stress-ng: info: [7854] for a 60.00s run time:
stress-ng: info: [7854] 240.00s available CPU time
stress-ng: info: [7854] 225.15s user time ( 93.81%)
stress-ng: info: [7854] 0.44s system time ( 0.18%)
stress-ng: info: [7854] 225.59s total time ( 93.99%)

Performance counter stats for 'stress-ng --cpu 4 --cpu-method clongdouble -t 60 --times':

225578.329426 task-clock (msec) # 3.757 CPUs utilized
38,443 context-switches # 0.170 K/sec
96 cpu-migrations # 0.000 K/sec
845 page-faults # 0.004 K/sec
651,620,307,394 cycles # 2.889 GHz
521,346,311,902 stalled-cycles-frontend # 80.01% frontend cycles idle
stalled-cycles-backend
17,079,721,567 instructions # 0.03 insns per cycle
# 30.52 stalled cycles per insn
2,903,757,437 branches # 12.873 M/sec
52,844,177 branch-misses # 1.82% of all branches

60.048819970 seconds time elapsed

The complex math operations take some time to complete, stalling on average over 35 cycles per op.  Instead of using 4 concurrent processes, I re-ran this using just the two CPUs and eliminating 2 of the hyperthreads.  This resulted in 25.4 stall cycles per instruction showing that hyperthreaded processes are stalling because of contention on the floating point units.

Perf stat is an incredibly useful tool for examining performance issues at a very low level.   It is simple to use and yet provides excellent stats to allow one to identify issues and fine tune performance critical code.  Well worth using.

Read more
Daniel Holbach

I Am Who I Am Because Of Who We All Are

I read the “We Are Not Loco” post  a few days ago. I could understand that Randall wanted to further liberate his team in terms of creativity and everything else, but to me it looks feels the wrong approach.

The post makes a simple promise: do away with bureaucracy, rename the team to use a less ambiguous name, JFDI! and things are going to be a lot better. This sounds compelling. We all like simplicity; in a faster and more complicated world we all would like things to be simpler again.

What I can also agree with is the general sense of empowerment. If you’re member of a team somewhere or want to become part of one: go ahead and do awesome things – your team will appreciate your hard work and your ideas.

So what was it in the post that made me sad? It took me a while to find out what specifically it was. The feeling set in when I realised somebody turned their back on a world-wide community and said “all right, we’re doing our own thing – what we used to do together to us is just old baggage”.

Sure, it’s always easier not having to discuss things in a big team. Especially if you want to agree on something like a name or any other small detail this might take ages. On the other hand: the world-wide LoCo community has achieved a lot of fantastic things together: there are lots of coordinated events around the world, there’s the LoCo team portal, and most importantly, there’s a common understanding of what teams can do and we all draw inspiration from each other’s teams. By making this a global initiative we created numerous avenues where new contributors find like-minded individuals (who all live in different places on the globe, but share the same love for Ubuntu and organising local events and activities). Here we can learn from each other, experiment and find out together what the best practices for local community awesomeness are.

Going away and equating the global LoCo community with bureaucracy to me is desolidarisation – it’s quite the opposite of “I Am Who I Am Because Of Who We All Are”.

Personally I would have preferred a set of targeted discussions which try to fix processes, improve communication channels and inspire a new round leaders of Ubuntu LoCo teams. Not everything you do in a LoCo team has to be approved by the entire set of other teams, actual reality in the LoCo world is quite different from that.

If you have ideas to discuss or suggestions, feel free to join our loco-contacts mailing list and bring it up there! It’s your chance to hang out with a lot of fun people from around the globe. :-)

Read more