Canonical Voices

Nicholas Skaggs

Virtual Hugs of appreciation!

Because I was asleep at the wheel (err, keyboard) yesterday I failed to express my appreciation for some folks. It's a day for hugging! And I missed it!

I gave everyone a shoutout on social media, but since planet looks best overrun with thank you posts, I shall blog it as well!

Thank you to:

David Planella for being the rock that has anchored the team.
Leo Arias for being super awesome and making testing what it is today on all the core apps.
Carla Sella for working tirelessly on many many different things in the years I've known her. She never gives up (even when I've tried too!), and has many successes to her name for that reason.
Nekhelesh Ramananthan for always being willing to let clock app be the guinea pig
Elfy, for rocking the manual tests project. Seriously awesome work. Everytime you use the tracker, just know elfy has been a part of making that testcase happen.
Jean-Baptiste Lallement and Martin Pitt for making some of my many wishes come true over the years with quality community efforts. Autopkgtest is but one of these.

And many more. Plus some I've forgotten. I can't give hugs to everyone, but I'm willing to try!

To everyone in the ubuntu community, thanks for making ubuntu the wonderful community it is!

Read more
David Henningsson

PulseAudio buffers and protocol

This is a technical post about PulseAudio internals and the upcoming protocol improvements in the upcoming PulseAudio 6.0 release.

PulseAudio memory copies and buffering

PulseAudio is said to have a “zero-copy” architecture. So let’s look at what copies and buffers are involved in a typical playback scenario.

Client side

When PulseAudio server and client runs as the same user, PulseAudio enables shared memory (SHM) for audio data. (In other cases, SHM is disabled for security reasons.) Applications can use pa_stream_begin_write to get a pointer directly into the SHM buffer. When using pa_stream_write or through the ALSA plugin, there will be one memory copy into the SHM.

Server resampling and remapping

On the server side, the server might need to convert the stream into a format that fits the hardware (and potential other streams that might be running simultaneously). This step is skipped if deemed unnecessary.

First, the samples are converted to either signed 16 bit or float 32 bit (mainly depending on resampler requirements).
In case resampling is necessary, we make use of external resampler libraries for this, the default being speex.
Second, if remapping is necessary, e g if the input is mono and the output is stereo, that is performed as well. Finally, the samples are converted to a format that the hardware supports.

So, in worst case, there might be up to four different buffers involved here (first: after converting to “work format”, second: after resampling, third: after remapping, fourth: after converting to hardware supported format), and in best case, this step is entirely skipped.

Mixing and hardware output

PulseAudio’s built in mixer multiplies each channel of each stream with a volume factor and writes the result to the hardware. In case the hardware supports mmap (memory mapping), we write the mix result directly into the DMA buffers.

Summary

The best we can do is one copy in total, from the SHM buffer directly into the DMA hardware buffer. I hope this clears up any confusion about what PulseAudio’s advertised “zero copy” capabilities means in practice.

However, memory copies is not the only thing you want to avoid to get good performance, which brings us to the next point:

Protocol improvements in 6.0

PulseAudio does pretty well CPU wise for high latency loads (e g music playback), but a bit worse for low latency loads (e g VOIP, gaming). Or to put it another way, PulseAudio has a low per sample cost, but there is still some optimisation that can be done per packet.

For every playback packet, there are three messages sent: from server to client saying “I need more data”, from client to server saying “here’s some data, I put it in SHM, at this address”, and then a third from server to client saying “thanks, I have no more use for this SHM data, please reclaim the memory”. The third message is not sent until the audio has actually been played back.
For every message, it means syscalls to write, read, and poll a unix socket. This overhead turned out to be significant enough to try to improve.

So instead of putting just the audio data into SHM, as of 6.0 we also put the messages into two SHM ringbuffers, one in each direction. For signalling we use eventfds. (There is also an optimisation layer on top of the eventfd that tries to avoid writing to the eventfd in case no one is currently waiting.) This is not so much for saving memory copies but to save syscalls.

From my own unscientific benchmarks (i e, running “top”), this saves us ~10% – 25% of CPU power in low latency use cases, half of that being on the client side.

Read more
Michael Hall

When things are moving fast and there’s still a lot of work to do, it’s sometimes easy to forget to stop and take the time to say “thank you” to the people that are helping you and the rest of the community. So every November 20th we in Ubuntu have a Community Appreciation Day, to remind us all of the importance of those two little words. We should of course all be saying it every day, but having a reminder like this helps when things get busy.

Like so many who have already posted their appreciation have said, it would be impossible for me to thank everybody I want to thank. Even if I spent all day on this post, I wouldn’t be able to mention even half of them.  So instead I’m going to highlight two people specifically.

First I want to thank Scarlett Clark from the Kubuntu community. In the lead up to this last Ubuntu Online Summit we didn’t have enough track leads on the Users track, which is one that I really wanted to see more active this time around. The track leads from the previous UOS couldn’t do it because of personal or work schedules, and as time was getting scarce I was really in a bind to find someone. I put out a general call for help in one of the Kubuntu IRC channels, and Scarlett was quick to volunteer. I really appreciated her enthusiasm then, and even more the work that she put in as a first-time track lead to help make the Users track a success. So thank you Scarlett.

Next, I really really want to say thank you to Svetlana Belkin, who seems to be contributing in almost every part of Ubuntu these days (including ones I barely know about, like Ubuntu Scientists). She was also a repeat track lead last UOS for the Community track, and has been contributing a lot of great feedback and ideas on ways to make our amazing community even better. Most importantly, in my opinion, is that she’s trying to re-start the Ubuntu Leadership team, which I think is needed now more than ever, and which I really want to become more active in once I get through with some deadline-bound work. I would encourage anybody else who is a leader in the community, or who wants to be one, to join her in that. And thank you, Svetlana, for everything that you do.

It is both a joy and a privilege to be able to work with people like Scarlett and Svetlana, and everybody else in the Ubuntu community. Today more than ever I am reminded about how lucky I am to be a part of it.

Read more
Daniel Holbach

Appreciation for Michael Hall

Today marks another Ubuntu Community Appreciation Day, one of Ubuntu’s beautiful traditions, where you publicly thank people for their work. It’s always hard to pick just one person or a group of people, but you know what – better appreciate somebody’s work than nobody’s work at all.

One person I’d like to thanks for their work is Michael Hall. He is always around, always working on a number of projects, always involved in discussions on social media and never shy to add yet another work item to his TODO list. Even with big projects on his plate, he is still writing apps, blog entries, charms and hacks on a number of websites and is still on top of things like mailing list discussions.

I don’t know how he does it, but I’m astounded how he gets things done and still stays friendly. I’m glad he’s part of our team and tirelessly working on making Ubuntu a better place.

I also like this picture of him.

cat5000

Mike: keep up the good work! :-)

Read more
UbuntuTouch

[原]Ubuntu OS应用Runtime Enviroment

在这篇文章中,我们将介绍Ubuntu OS的Runtime Environment。在文章“App confinement: Security policy for click packages”中,我们看见它里面有介绍一个应用的runtime环境。这里,我们通过一个例子来显示一个应用的runtime环境到底是怎样的。


在这里我们可以参阅我以前的文章“在Ubuntu上的C++及QML混合编程”,我们下载文章中的例程:


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


在一个Terminal中打入上述的句子,就可以下载例程中的软件。同时,我们对我们的主程序文件“ReadEnv.qml”做如下的修改:


import QtQuick 2.0
import Ubuntu.Components 0.1
import Ubuntu.Components.ListItems 0.1 as ListItem
import ReadEnv 1.0
import "ui"

/*!
    \brief MainView with Tabs element.
           First Tab has a single Label and
           second Tab has a single ToolbarAction.
*/

MainView {
    id: root

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

    anchorToKeyboard: true

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

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

    property string app_pkgname

    ReadEnv {
        id: readEnv
    }

    Flickable {
        id: scrollWidget
        anchors.fill: parent
        contentHeight: contentItem.childrenRect.height
        boundsBehavior: (contentHeight > root.height) ? Flickable.DragAndOvershootBounds : Flickable.StopAtBounds
        /* Set the direction to workaround https://bugreports.qt-project.org/browse/QTBUG-31905
           otherwise the UI might end up in a situation where scrolling doesn't work */
        flickableDirection: Flickable.VerticalFlick

        Column {
            anchors.left: parent.left
            anchors.right: parent.right

            ListItem.Base {
                height: ubuntuLabel.height + runtime.height + units.gu(6)

                Column {
                    anchors.left: parent.left
                    anchors.right: parent.right
                    anchors.centerIn: parent
                    spacing: units.gu(2)
                    Label {
                        id: ubuntuLabel
                        anchors.horizontalCenter: parent.horizontalCenter
                        text: ""
                        fontSize: "x-large"
                    }
                    Label {
                        id: runtime
                        anchors.horizontalCenter: parent.horizontalCenter
                        text: "Runtime Environment"
                    }
                }
            }

            ListItem.Subtitled {
                text: i18n.tr("UBUNTU_APPLICATION_ISOLATION")
                subText: readEnv.getenv("UBUNTU_APPLICATION_ISOLATION")
            }

            ListItem.Subtitled {
                text: i18n.tr("APP_ID")
                subText: readEnv.getenv("APP_ID")
            }

            ListItem.Subtitled {
                text: i18n.tr("XDG_CACHE_HOME")
                subText: readEnv.getenv("XDG_CACHE_HOME")
            }

            ListItem.Subtitled {
                text: i18n.tr("XDG_CONFIG_HOME")
                subText: readEnv.getenv("XDG_CONFIG_HOME")
            }

            ListItem.Subtitled {
                text: i18n.tr("XDG_DATA_HOME")
                subText: readEnv.getenv("XDG_DATA_HOME")
            }

            ListItem.Subtitled {
                text: i18n.tr("XDG_RUNTIME_DIR")
                subText: readEnv.getenv("XDG_RUNTIME_DIR")
            }

            ListItem.Subtitled {
                text: i18n.tr("TMPDIR")
                subText: readEnv.getenv("TMPDIR")
            }

            ListItem.Subtitled {
                text: i18n.tr("PWD")
                subText: readEnv.getenv("PWD")
            }

            ListItem.Subtitled {
                text: i18n.tr("APP_PKGNAME")
                subText: app_pkgname
            }

            ListItem.Subtitled {
                text: i18n.tr("PATH")
                subText: readEnv.getenv("PATH")
            }

            ListItem.Subtitled {
                text: i18n.tr("LD_LIBRARY_PATH")
                subText: readEnv.getenv("LD_LIBRARY_PATH")
            }

            ListItem.Subtitled {
                text: i18n.tr("QML2_IMPORT_PATH")
                subText: readEnv.getenv("QML2_IMPORT_PATH")
            }
        }
    }

    Component.onCompleted: {
        var APP_ID = readEnv.getenv("APP_ID");

        console.log("APP_ID: " + APP_ID );
        app_pkgname = APP_ID.split('_')[0]
        console.log("APP_PKGNAME: " + app_pkgname);
    }
}

我们可以通过我们设计的ReadEnv库来读取该应用的环境变量。运行我们的程序,显示如下:


 


在文章中,它提到如下的目录,该应具有读和写的权限:


  • XDG_CACHE_HOME/<APP_PKGNAME>
  • XDG_CONFIG_HOME/<APP_PKGNAME>
  • XDG_DATA_HOME/<APP_PKGNAME>
  • XDG_RUNTIME_DIR/<APP_PKGNAME>
  • XDG_RUNTIME_DIR/confined/<APP_PKGNAME> (for TMPDIR)
针对我们的应用来说,也即如下的目录具有读写的权限:

  • /home/phablet/.cache/com.ubuntu.developer.liu-xiao-guo.readenv
  • /home/phablet/.config/com.ubuntu.developer.liu-xiao-guo.readenv
  • /home/phablet/.local/share/com.ubuntu.developer.liu-xiao-guo.readenv
  • /run/user/32011/confined/com.ubuntu.developer.liu-xiao-guo.readenv

整个程序的源码在如下的地址可以找到:


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




作者:UbuntuTouch 发表于2014-11-19 14:52:03 原文链接
阅读:189 评论:0 查看评论

Read more
Joseph Salisbury

Meeting Minutes

IRC Log of the meeting.

Meeting minutes.

Agenda

20141118 Meeting Agenda


Release Metrics and Incoming Bugs

Release metrics and incoming bug data can be reviewed at the following link:

  • http://people.canonical.com/~kernel/reports/kt-meeting.txt


Status: Vivid Development Kernel

The master-next branch of our Vivid kernel has been rebased to the
v3.18-rc5 upstream kernel. We have still withheld uploading to
the archive until we’ve progressed to a later -rc candidate.
—–
Important upcoming dates:
Thurs Dec 18 – Vivid Alpha 1 (~4 weeks away)
Thurs Jan 22 – Vivid Alpha 2 (~9 weeks away)


Status: CVE’s

The current CVE status can be reviewed at the following link:

http://people.canonical.com/~kernel/cve/pkg/ALL-linux.html


Status: Stable, Security, and Bugfix Kernel Updates – Utopic/Trusty/Precise/Lucid

Status for the main kernels, until today (18-Nov):

  • Lucid – Verification & Testing
  • Precise – Verification & Testing
  • Trusty – Verification & Testing
  • Utopic – Verification & Testing

    Current opened tracking bugs details:

  • http://kernel.ubuntu.com/sru/kernel-sru-workflow.html

    For SRUs, SRU report is a good source of information:

  • http://kernel.ubuntu.com/sru/sru-report.html

    Schedule:

    cycle: 31-Oct through 22-Nov
    ====================================================================
    31-Oct Last day for kernel commits for this cycle
    02-Nov – 08-Nov Kernel prep week.
    09-Nov – 15-Nov Bug verification & Regression testing.
    16-Nov – 22-Nov Regression testing & Release to -updates.


Open Discussion or Questions? Raise your hand to be recognized

No open discussions.

Read more
facundo

PyCon 2014 en Rafaela


Acaba de pasar la sexta PyCon Argentina. Como dice el título, se hizo en Rafaela, provincia de Santa Fe.

Fuimos con Nico Demarchi en auto, salimos el miércoles a la tarde y llegamos una y monedas de la mañana, volvimos el domingo durante el día, arrancando a media mañana. Creo que es el límite de lo que haría en auto... más distancia ya iría en micro o avión.

Yo tenía que llegar el miércoles a la noche porque el jueves abría el día de talleres con Introducción a Python (modo charla extendida, ya que tenía dos horas). El jueves dí dos charlas más: Cómo debuguear en Python, y Cómo los logs me salvaron el alma.Y para cerrar (justo antes de los sorteos y foto grupal), le conté a la gente un poco cómo íbamos con el proyecto de armar la Asociación Civil de PyAr.

Mis charlas salieron bien, aunque la de debugging no me gustó del todo como la había dado (pero luego recibí buen feedback). Para el taller de Intro a Python usé por primera vez a Pysenteishon, un software muy copado y piola para ir pasando los slides desde el teléfono (¡gracias Emiliano por hacerlo!). Y para las charlas del jueves estuve por primera vez descalzo dando la presentación (era algo que quería probar desde hace rato, y aproveché que el escenario del auditorio tenía piso de madera).

Dando la charla en patas

También fuí a muchas charlas, había muchas cosas copadas para ver, y creo que me salté uno o dos timeslots nada más en toda la conferencia. Las keynotes estuvieron bien, pero no me entusiasmaron particularmente. Y todo lo fue lugar y organización estuvo genial, la verdad que se pasaron. Lo mismo con la gente con la que me (re)encontré: es un placer ser parte de una comunidad así.

Yo llevé la cámara... pero la verdad es que colgué sacando fotos. Pero la grosa de Yami sacó un montón, están todas acá. Y una de las últimas que sacó es justamente la grupal, esta que muestro acá:

Foto grupal

Y como siempre que uno no viaja durmiendo o solo, está el efecto de "PyCon extendida". Es que uno viene charlando de mil cosas, de lo más variado, pero también de proyectos, ideas, etc. Con Nico nos venía rondando en la cabeza una idea para facilitar el uso de dependencias en programas Python, estuvimos charlando con gente en la conferencia, nos dieron feedback, la idea fue mutando... y en el viaje de vuelta se nos terminó de ocurrir algo piola, que no debería ser demasiado loco de implementar; ya les traeré la novedad.

¡Pero no sólo un proyecto me traje! (como si tuviera pocos y/o mucho tiempo libre, ¿no?). Tengo ganas de hacer una "maquinita de timelapse" con una Raspi (una cajita que uno puede colgar en cualquier lado y dejarla ahí algunas horas o un par de días y arme un video de esos donde se ve todo rápido, por ejemplo este). El otro proyecto es armar una valija o caja robusta con todo lo necesario en un PyCamp (router, computadora para caché de repositorios, energía, y varios etcéteras), de manera de tener todo listo y de fácil armado, onda llegás y enchufás. Ya veremos cómo se van desarrollando ambos proyectos...

Read more
Michael Hall

Last week was our second ever Ubuntu Online Summit, and it couldn’t have gone better. Not only was it a great chance for us in Canonical to talk about what we’re working on and get community members involved in the ongoing work, it was also an opportunity for the community to show us what they have been working on and give us an opportunity to get involved with them.

Community Track leads

This was also the second time we’ve recruited track leads from among the community. Traditionally leading a track was a responsibility given to one of the engineering managers within Canonical, and it was up to them to decide what sessions to put on the UDS schedule. We kept the same basic approach when we went to online vUDS. But starting with UOS 14.06, we asked leaders in the community to help us with that, and they’ve done a phenomenal job. This time we had Nekhelesh RamananthanJosé Antonio ReySvetlana BelkinRohan GargElfy, and Scarlett Clark take up that call, and they were instrumental in getting even more of the community involved

Community Session Hosts

uos_creatorsMore than a third of those who created sessions for this UOS were from the community, not Canonical. For comparison, in the last in-person UDS, less than a quarter of session creators were non-Canonical. The shift online has been disruptive, and we’ve tried many variations to try and find what works, but this metric shows that those efforts are starting to pay off. Community involvement, indeed community direction, is higher in these Online Summits than it was in UDS. This is becoming a true community event: community focused, community organized, and community run.

Community Initiatives

The Ubuntu Online Summit wasn’t just about the projects driven by Canonical, such as the Ubuntu desktop and phone, there were many sessions about projects started and driven by members of the community. Last week we were shown the latest development on Ubuntu MATE and KDE Plasma 5 from non-Canonical lead flavors. We saw a whole set of planning sessions for community developed Core Apps and an exciting new Component Store for app developers to share bits of code with each other. For outreach there were sessions for providing localized ISOs for loco teams and expanding the scope of the community-lead Start Ubuntu project. Finally we had someone from the community kick off a serious discussion about getting Ubuntu running on cars. Cars! All of these exciting sessions were thought up by, proposed by, and run by members of the community.

Community Improvements

This was a great Ubuntu Online Summit, and I was certainly happy with the increased level of community involvement in it, but we still have room to make it better. And we are going to make it better with help from the community. We will be sending out a survey to everyone who registered as attending for this UOS to gather feedback and ideas, please take the time to fill it out when you get the link. If you attended but didn’t register there’s still time, go to the link above, log in and save your attendance record. Finally, it’s never too early to start thinking about the next UOS and what sessions you might want to lead for it, so that you’re prepared when those track leads come knocking at your door.

Read more
niemeyer

Last night I did a trivial yet surprisingly satisfying hardware hack, of the kind that can only be accomplished when the brain is in holiday mode. Our son has that very simple airplane toy, which turned out to become one of his most loved ones, enough to have deserved wheel repairs before. He’s also reportedly a fan of all kinds of light-emitting or reflecting objects (including the sun, and specially the moon). So the idea sparkled: how easily can that airplane get a blinking led?

With an attiny85, a CR2032 battery, a LED, and half an hour of soldering work, this was the result:

The code loaded in the chip is small enough to be listed here, and it gets away with blinking without waking up the main CPU clock:

    ; Set inverse OC1B pin as output for the led.
    sbi _SFR_IO_ADDR(DDRB), 3

    ; Enable timer TC1 with PCK/16k prescaling (attiny85 p.89)
    ldi r18, (1<<CS10)|(1<<CS11)|(1<<CS12)|(1<<CS13)
    out _SFR_IO_ADDR(TCCR1), r18

    ; Set OC1B on compare match (250), clear on 0x00 (attiny85 p.86,90)
    ldi r18, (1<<PWM1B) | (1<<COM1B0)
    out _SFR_IO_ADDR(GTCCR), r18
    ldi r18, 250
    out _SFR_IO_ADDR(OCR1B), r18

    ; Set the sleep mode to idle (attiny85 p.39).
    ldi r18, (1<<SE)
    out _SFR_IO_ADDR(MCUCR), r18

    ; Shutdown unnecessary MCU modules (attiny85 p.38)
    ldi r18, (1<<PRTIM0)|(1<<PRUSI)|(1<<PRADC)
    out _SFR_IO_ADDR(PRR), r18

    sleep
    rjmp .-4

The power consumption in the idle mode plus the blinks should keep the coin battery running for a couple of weeks, at least. A vibration sensor would improve that significantly, by enabling the MCU to go into powerdown mode and be awaken externally, but I don’t have a sensor at hand that is small enough.

This is the assembly, and the final result:

Toy Airplane Hack

He’s enjoying it. :-)

Read more
mitechie

A couple of people have reached out to me via LinkedIn and reminded me that my three year work anniversary happened last Friday. Three years since I left my job at a local place to go work for the Canonical where I got the chance to be paid to work on open source software and better my Python skills with the team working on Launchpad. My wife wasn’t quite sure. “You’ve only been at your job a year and a half, and your last one was only two years. What makes this different?”

What’s amazing, looking back, is just how *right* the decision turned out to be. I was nervous at the time. I really wasn’t Launchpad’s biggest fan. However, the team I interviewed with held this promise of making me a better developer. They were doing code reviews of every branch that went up to land. They had automated testing, and they firmly believed in unit and functional tests of the code. It was a case of the product didn’t excite me, but the environment, working with smart developers from across the globe, was exactly what I felt like I needed to move forward with my career, my craft.

2013-09-02 18.17.47

I joined my team on Launchpad in a squad of four other developers. It was funny. When I joined I felt so lost. Launchpad is an amazing and huge bit of software, and I knew I was in over my head. I talked with my manager at the time, Deryck, and he told me “Don’t worry, it’ll take you about a year to get really productive working on Launchpad.” A year! Surely you jest, and if you’re not jesting…wtf did I just get myself into?

It was a long road and over time I learned how to take a code review (a really hard skill for many of us), how to do one, and how to talk with other smart and opinionated developers. I learned the value of the daily standup, how to manage work across a kanban board. I learned to really learn from others. Up until this point I’d always been the big fish in a small pond and suddenly I was the minnow hiding in the shallows. Forget books on how to code, just look at the diff in the code review you’re reading right now. Learn!

My boss was right, it was nearly ten months before I really felt like I could be asked to do most things in Launchpad and get them done in an efficient way. Soon our team was moved on from Launchpad to other projects. It was actually pretty great. On the one hand, “Hey! I just got the hang of this thing” but, on the other hand, we were moving on to new things. Development life here has never been one of sitting still. We sit down and work on the Ubuntu cycle of six month plans, and it’s funny because even that is such a long time. Do you really know what you’ll be doing six months from now?

P1100197.jpg

Since that time in Launchpad I’ve gotten work on several different projects and I ended up switching teams to work on the Juju Gui. I didn’t really know a lot about this Juju thing, but the Gui was a fascinating project. It’s a really large scale JavaScript application. This is no “toss some jQuery on a web page” thing here.

I also moved to work under a new manager Gary. As my second manager since starting at Canonical and I was amazed at my luck. Here I’ve had two great mentors that made huge strides in teaching me how to work with other developers, how to do the fun stuff, the mundane, and how to take pride in the accomplishments of the team. I sit down at my computer every day and I’ve got the brain power of amazing people at my disposal over irc, Google Hangouts, email, and more. It’s amazing to think that at these sprints we do, I’m pretty much never the smartest person in the room. However, that’s what’s so great. It’s never boring and when there’s a problem the key is that we put our joint brilliant minds to the problem. In every hard problem we’ve faced I’ve never found that a single person had the one true solution. What we come up with together is always better than what any of us had apart.

When Gary left and there was a void for team lead and it was something I was interested in. I really can’t say enough awesome things about the team of folks I work with. I wanted to keep us all together and I felt like it would be great for us to try to keep things going. It was kind of a “well I’ll just try not to $#@$@# it up” situation. That was more than nine months ago now. Gary and Deryck taught me so much, and I still have to bite my tongue and ask myself “What would Gary do” at times. I’ve kept some things the same, but I’ve also brought my own flavor into the team a bit, at least I like to think so. These days my Github profile doesn’t show me landing a branch a day, but I take great pride in the progress of the team as a whole each and every week.

The team I run now is as awesome a group of people, the best I could hope to work for. I do mean that, I work for my team. It’s never the other way around and that’s one lesson I definitely picked up from my previous leads. The projects we’re working on are exciting and new and are really important to Canonical. I get to sit in and have discussions and planning meetings with Canonical super genius veterans like Kapil, Gustavo, and occasionally Mark Shuttleworth himself.

Looking back I’ve spent the last three years becoming a better developer, getting an on the job training course on leading a team of brilliant people, and crash course on thinking about the project, not just as the bugs or features for the week, but for the project as it needs to exist in three to six months. I’ve spent three years bouncing between “what have I gotten myself into, this is beyond my abilities” to “I’ve got this. You can’t find someone else to do this better”. I always tell people that if you’re not swimming as hard as you can to keep up, find another job. I feel like three years ago I did that and I’ve been swimming ever since.

P1040511.jpg

Three years is a long time in a career these days. It’s been a wild ride and I can’t thank the folks that let me in the door, taught me, and have given me the power to do great things with my work enough. I’ve worked by butt off in Budapest, Copenhagen, Cape Town, Brussels, North Carolina, London, Vegas, and the bay area a few times. Will I be here three years from now? Who knows, but I know I’ve got an awesome team to work with on Monday and we’ll be building an awesome product to keep building. I’m going to really enjoy doing work that’s challenging and fulfilling every step of the way.

DSC00329


Read more

Tracking Usage

One of the long standing goals of Unity has been to provide an application focused presentation of the desktop. Under X11 this proves tricky as anyone can connect into X and doesn't necessarily have to give information on what applications they're associated with. So we wrote BAMF, which does a pretty good job of matching windows to applications, but it could never be perfect because there simply wasn't enough information available. When we started to rethink the world assuming a non-X11 display server we knew there was one thing we really wanted, to never ever have something like BAMF again.

This meant designing, from startup to shutdown, a complete tracking of an application before it started creating windows in the display server. We then were able to use the same mechanisms to create a consistent and secure environment for the applications. This is both good for developers and users as their applications start in a predictable way each and every time it's started. And we also setup the per-application AppArmor confinement that the application lives in.

Enough backstory, what's really important to this blog post is that we also get an event when an application starts and stops which is a reliable event. So I wrote a little tool that takes those events out of the log and presents them as usage data. It is cleverly called:

$ ubuntu-app-usage

And it presents a list of all the applications that you've used on the system along with how long you've used them. How long do you spend messing around on the web? Now you know. You're welcome.

It's not perfect in that it uses all the time that you've used the device, it'd be nice to query the last week or the last year to see that data as well. Perhaps even a percentage of time. I might add those little things in the future, if you're interested you can beat me too it.

Read more
Prakash

.NET goes open source

With other languages such as Java and Python getting large user base, this is a good move to gain some users.

Microsoft is open sourcing .NET, this should reduce the compatibility challenges with cross-platform applications developed using Microsoft Tools.

http://news.microsoft.com/2014/11/12/microsoft-takes-net-open-source-and-cross-platform-adds-new-development-capabilities-with-visual-studio-2015-net-2015-and-visual-studio-online/

Read more
UbuntuTouch

在前面的文章中,我们已经创建了很多点评的Scope。在这个篇文章中,我们将使用现有的SDK来重新开发点评Scope。我们将有意识地使得我们的数据和Scope的框架进行分离,从而展示一个更好的开发框架。更多关于Scope的介绍可以在网址http://developer.ubuntu.com/scopes/找到。我们最终的显示图片如下:

   

     


1)创建一个最基本的Scope

我们打开我们的SDK。我们选择菜单“File”==>“New File or Project”。然后我们选择“Unity Scope”。输入“dianping”作为我们项目的名字。

  

我们选择适合自己的“Qt Scope using HTTP+JSON API”模版,并输入我们的Scope名字。

  

同时要记得输入像我上面一样的“Maintainer”格式的信息。否则编译会会有一些问题。紧接着,我们选择我们需要支持的kits。这里我们选择同时支持Desktop,armhf(手机)及i386(模拟器)。这样,我们就基本上完成了我们的模版Scope。我们可以在manifest.json.in中修改我们所需要的。



我们可以修改我们Scope的描述及选择正确的Framework。在上面我们选择了“ubuntu-sdk-14.10-dev2”。这个是在手机或在emulator里被支持的Framework。我们可以通过如下的方式来得到手机或emulator所支持的Framework。



我们可以运行一下我们刚创建的Scope。运行的情况如下。如果我们有问题的话,我们可能需要参照文章“Ubuntu SDK 安装Qt SDK安装”。

\

我们可以使用热键“Ctrl + R”来在Desktop下运行我们的Scope。也可以点击SDK中做下角的绿色的按钮就可以直接运行我们的Scope了。如果在“Application Output”显示的是“scope-unit-tests”,我们必须按照如下的方法进行修改以使得它能够在我们的Desktop下面能够正常运行:



我们也可以通过如下的方式选择emulator进行运行:





等我们选择完emulator后,我们就可以按上面的方法Ctrl+R或绿色的按钮来在emulator中运行我们的Scope了。我们可以参考文章“怎么安装Ubuntu应用到Device中

这个模版的Scope是一个完整的Scope,我们可以在“Search Query”中输入“Beijing”看看有什么变化。

2)点评接口

我们可以在dianping的网站申请自己的开发者账号,并可以试一下它的接口的功能。点评的接口文档可以在点评地址找到。等你注册完好后,我们可以在地址进行测试。我已经注册好了。大家可以在自己的浏览器地址栏中输入如下的内容,我们可以看到JSON格式的输出:

http://api.dianping.com/v1/business/find_businesses?appkey=3562917596&sign=1EAF11F443AE46F87D7D4F2F55903A1D8719455F&category=美食&city=北京&limit=20&platform=2&sort=2



我们可以看到正确的JSON输出。

3)设计Client数据接口

在整个template的设计中,Client的作用是用来向Web Service申请数据,并把数据存入内存中以便在Query的类中调用,并用Scope UI toolkit进行展示。最初的设计和我们的是不一样的。为了方便我们的设计,我们把Client类的接口进行修改,如下:


#ifndef API_CLIENT_H_
#define API_CLIENT_H_

#include <api/config.h>

#include <atomic>
#include <deque>
#include <map>
#include <string>
#include <core/net/http/request.h>
#include <core/net/uri.h>

#include <QJsonDocument>

namespace api {

/**
 * Provide a nice way to access the HTTP API.
 *
 * We don't want our scope's code to be mixed together with HTTP and JSON handling.
 */
class Client {
public:

    /**
     * Data structure for the quried data
     */
    struct Data {
        std::string name;
        std::string business_url;
        std::string s_photo_url;
        std::string photo_url;
        std::string rating_s_img_url;
        std::string address;
        std::string telephone;
    };

    /**
     * A list of weather information
     */
    typedef std::deque<Data> DataList;


    Client(Config::Ptr config);

    virtual ~Client() = default;

    /**
     * Get the query data
     */
    virtual DataList getData(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(QString uri, QJsonDocument &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);

private:
    QString getQueryString(QString query);
    QString removeTestInfo(QString name);

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

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

}

#endif // API_CLIENT_H_

在这里我们简化了以前的设计。我们设计了一个Data数据结构来装我们所得到的数据,我们使用如下的方法来获取我们query所需要的数据:

    virtual DataList getData(const std::string &query);

这个函数返回一个数组。这个数组将被我们的Query类所利用,并显示所获得的数据。Client类的实现如下:

#include <api/client.h>

#include <core/net/error.h>
#include <core/net/http/client.h>
#include <core/net/http/content_type.h>
#include <core/net/http/response.h>
#include <QVariantMap>

#include <QString>
#include <QCryptographicHash>
#include <QDebug>
#include <QTextCodec>
#include <QUrl>

#include <iostream>

namespace http = core::net::http;
namespace net = core::net;

using namespace api;
using namespace std;
using namespace std;

const QString appkey = "3562917596";
const QString secret = "091bf584e9d24edbbf48971d65307be3";
const QString BASE_URI = "http://api.dianping.com/v1/business/find_businesses?";

Client::Client(Config::Ptr config) :
    config_(config), cancelled_(false) {
}

void Client::get( QString uri, QJsonDocument &root) {
    // Create a new HTTP client
    auto client = http::make_client();

    // Start building the request configuration
    http::Request::Configuration configuration;

    // Build the URI from its components
    configuration.uri = uri.toStdString();

    // Give out a user agent string
    configuration.header.add("User-Agent", config_->user_agent);

    // Build a HTTP request object from our configuration
    auto request = client->head(configuration);

    try {
        // Synchronously make the HTTP request
        // We bind the cancellable callback to #progress_report
        auto response = request->execute(
                    bind(&Client::progress_report, this, placeholders::_1));

        // Check that we got a sensible HTTP status code
        if (response.status != http::Status::ok) {
            throw domain_error(response.body);
        }
        // Parse the JSON from the response
        root = QJsonDocument::fromJson(response.body.c_str());

        // qDebug() << "response: " << response.body.c_str();
    } catch (net::Error &) {
    }
}

Client::DataList Client::getData(const string& query) {
    QJsonDocument root;

    QString temp = QString::fromStdString(query);
    QByteArray bytearray = query.c_str();
    QString query_string = QString::fromUtf8(bytearray.data(), bytearray.size());

    qDebug() << "query_string: " << query_string;

    QString uri = getQueryString(query_string);
    qDebug() << "uri: "  << uri;
    get(uri, root);

    DataList result;

    QVariantMap variant = root.toVariant().toMap();

    // Iterate through the weather data
    for (const QVariant &i : variant["businesses"].toList()) {
        QVariantMap item = i.toMap();

        QString name = removeTestInfo(item["name"].toString());
        qDebug() << "name: " << name;

        QString business_url = item["business_url"].toString();
        qDebug() << "business_url: " << business_url;

        QString s_photo_url = item["s_photo_url"].toString();
        qDebug() << "s_photo_url: " << s_photo_url;

        QString photo_url = item["photo_url"].toString();
        qDebug() << "photo_url: " << photo_url;

        QString rating_s_img_url = item["rating_s_img_url"].toString();
        qDebug() << "rating_s_img_url: " << rating_s_img_url;

        QString address = item["address"].toString();
        qDebug() << "address: " << address;

        QString telephone = item["telephone"].toString();
        qDebug() << "telephone: " << telephone;

        // Add a result to the weather list
        result.emplace_back(
            Data { name.toStdString(), business_url.toStdString(), s_photo_url.toStdString(),
                   photo_url.toStdString(), rating_s_img_url.toStdString(),
                   address.toStdString(), telephone.toStdString() });
    }

    return result;
}

http::Request::Progress::Next Client::progress_report(
        const http::Request::Progress&) {

    return cancelled_ ?
                http::Request::Progress::Next::abort_operation :
                http::Request::Progress::Next::continue_operation;
}

void Client::cancel() {
    cancelled_ = true;
}

Config::Ptr Client::config() {
    return config_;
}

QString Client::getQueryString(QString query) {
    QMap<QString, QString> map;

    map["category"] = "美食";
    map["city"] = query;
    map["sort"] = "2";
    map["limit"] = "20";
    map["platform"] = "2";

    QCryptographicHash generator(QCryptographicHash::Sha1);

    QString temp;
    temp.append(appkey);
    QMapIterator<QString, QString> i(map);
    while (i.hasNext()) {
        i.next();
        qDebug() << i.key() << ": " << i.value();
        temp.append(i.key()).append(i.value());
    }

    temp.append(secret);

    qDebug() << temp;

    qDebug() << "UTF-8: " << temp.toUtf8();

    generator.addData(temp.toUtf8());
    QString sign = generator.result().toHex().toUpper();

//    qDebug() << sign;

    QString url;
    url.append(BASE_URI);
    url.append("appkey=");
    url.append(appkey);

    url.append("&");
    url.append("sign=");
    url.append(sign);

    i.toFront();
    while (i.hasNext()) {
        i.next();
        qDebug() << i.key() << ": " << i.value();
        url.append("&").append(i.key()).append("=").append(i.value());
    }

    qDebug() << "Final url: " << url;

    QUrl url1(url);

    qDebug() << url1.url();
    QByteArray bytearray = url1.toEncoded();
    QString string = QString::fromUtf8(bytearray.data(), bytearray.size());
    qDebug() << "url new: " << string;

    return string;
}

// The following method is used to remove the
// "这是一条测试商户数据,仅用于测试开发,开发完成后请申请正式数据..." string
const QString TEST_STRING = "(这是一条测试商户数据,仅用于测试开发,开发完成后请申请正式数据...)";
QString Client::removeTestInfo(QString name)
{
    if ( name.contains(TEST_STRING) ) {
        int index = name.indexOf(TEST_STRING);
        QString newName = name.left(index);
        // qDebug() << "newName: " << newName;
        return newName;
    } else {
        qDebug() << "it does not contain the string";
        return name;
    }
}

首先,我们可以看一下这里的helper方法“getQueryString”。这个方法的作用是用来得到我们的申请的url的。我们可以参考“点评开发入门示例”是怎么生成申请的url的。“removeTestInfo”是用来删除我们得到的数据的部分内容以更好地呈现。如果我们需要正式的数据,需要和dianping进行注册。我们通过使用能够net-cpp的API来进行HTTP请求,并使用Qt API QJsonDocument来进行JSON的解析。我们可以通过qDebug来打印并输出我们想要看到的内容。

为了能对我们修改的Client类进行测试,我们对Query.cpp中的“run”进行了如下的修改:

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

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

        Client::DataList datalist;
        if (query_string.empty()) {
            queryString = QString("北京");
            datalist = client_.getData("北京");
        } else {
            // otherwise, get the forecast for the search string
            datalist = client_.getData(query_string);
        }
    } catch (domain_error &e) {
        // Handle exceptions being thrown by the client API
        cerr << e.what() << endl;
        reply->error(current_exception());
    }
}

这样做的目的是为了产生一个对Client类的getData方法调用以便我们调试我们的Client类。重新编译并运行我们的Scope。目前应该什么也看不到,但是我们可以看到许多的输出:


这样我们的Client类的实现基本已经完成。它可以帮我们向点评的web service发送请求,并得到我们想要的数据。这个数据被放在一个叫做Client::DataList的数组中。我们在下面的章节中具体描述怎么利用这个数据进行显示。通过Client类的实现,我们完成了数据(Client)和展示(Query)之间的分离。这也是一个比较推荐的设计。

整个部分的源代码可以在地址下载:

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

4)代码讲解


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"和carousel布局。用的是小的card-size。components项可以用来让我们选择预先定义好的field来显示我们所需要的结果。这里我们添加了"title"及“art"。同时我们可以显示一个title及一个图片(art)。更多详细的介绍可以参阅文章“Customization & branding”。

//Create a JSON string to be used tro create a category renderer - uses grid layout
std::string CR_GRID = R"(
{
        "schema-version" : 1,
        "template" : {
        "category-layout" : "grid",
        "card-size": "small"
        },
        "components" : {
        "title" : "title",
        "art" : {
        "field": "art",
        "aspect-ratio": 1.6,
        "fill-mode": "fit"
        }
        }
        }
        )";

//Create a JSON string to be used tro create a category renderer - uses carousel layout
std::string CR_CAROUSEL = R"(
{
        "schema-version" : 1,
        "template" : {
        "category-layout" : "carousel",
        "card-size": "small",
        "overlay" : true
        },
        "components" : {
        "title" : "title",
        "art" : {
        "field": "art",
        "aspect-ratio": 1.6,
        "fill-mode": "fit"
        }
        }
        }
        )";

我们把上述的定义加到我们Query.cpp文件的开始部分。同时我们也可以删除由template已经创建好的“WEATHER_TEMPLATE”及“CITY_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());
        QString queryString = QString::fromStdString(query.query_string());

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

        Client::DataList datalist;
        if (query_string.empty()) {
            queryString = QString("北京");
            datalist = client_.getData("北京");
        } else {
            // otherwise, get the forecast for the search string
            datalist = client_.getData(query_string);
        }

        CategoryRenderer rdrGrid(CR_GRID);
        CategoryRenderer rdrCarousel(CR_CAROUSEL);

        QString title = queryString + "美味";

        // Register two categories
        auto carousel = reply->register_category("dianpingcarousel", title.toStdString(), "", rdrCarousel);
        auto grid = reply->register_category("dianpinggrid", "", "", rdrGrid);

        bool isgrid = false;

        // For each of the entry in the datalist
        for (const Client::Data &data : datalist) {

            // for each result
            const std::shared_ptr<const Category> * category;

            if ( isgrid ) {
                category = &grid;
                isgrid = false;
            } else {
                isgrid = true;
                category = &carousel;
            }

            //create our categorized result using our pointer, which is either to out
            //grid or our carousel Category
            CategorisedResult catres((*category));

            // We must have a URI
            catres.set_uri(data.business_url);
            catres.set_dnd_uri(data.business_url);
            catres.set_title(data.name);
            catres.set_art(data.photo_url);

            catres["address"] = Variant(data.address);
            catres["telephone"] = Variant(data.telephone);

            // Push the result
            if (!reply->push(catres)) {
                // 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());
    }
}

为了能够使得上面的代码能够被成功编译,我们必须在Query.cpp的开始部分加入如下的句子:

using namespace unity::scopes;

我们从我们的Client API中的Client::getData来获取我们所需要的web service的数据,把数据填入到相应的CategorisedResult中。重新编译我们的Scope,我们可以看到如下的画面:


我们可以在“Search Query”中输入“上海”,我们可以看到不同的结果。我们也可以尝试点击我们的画面,在另外一个画面中可以看到一个图片。
到这里,我们基本上已经看到了Scope工作的了。我们下面来更进一步来在Preview中显示更多的内容。这样我们基本上完成了Query.cpp的代码。整个源码可以在如下的地址找到:

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

src/scope/preview.cpp


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

  • 定义在preview时所需要的widget
  • 让widget和搜索到的数据field一一对应起来
  • 定义不同数量的layout列(由屏幕的尺寸来定)
  • 把不同的widget分配到layout中的不同列中
  • 把reply实例显示到layout的widget中
更多关于这个类的介绍可以在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"。
    PreviewWidget w_header("headerId", "header");

最终的程序如下:

void Preview::run(sc::PreviewReplyProxy const& reply) {
    // Support three different column layouts
    // 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
    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", "infoId", "telId", "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", "telId", "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");

    // Standard subtitle field here gets our 'artist' key value
    // w_header.add_attribute_mapping("subtitle", "artist");

    PreviewWidget w_art("artId", "image");
    w_art.add_attribute_mapping("source", "art");

    PreviewWidget w_info("infoId", "text");
    w_info.add_attribute_mapping("text", "address");

    PreviewWidget w_tel("telId", "text");
    w_tel.add_attribute_mapping("text", "telephone");

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

    // 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(urlString.toStdString())} // 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_tel, w_actions});
    // And push them to the PreviewReplyProxy as needed for use in the preview
    reply->push(widgets);
}

为了能够编译我们的代码,我们必须在Preview.cpp文件的开始部分加入如下的代码:

using namespace unity::scopes;
#include <QDebug>

重新编译我们的Scope。并运行它,我们可以看到如下的画面:

 

在手机的上的运行情况。选择手机为当前的kit(armhf):



我们使用热键Ctrl + R或按下绿色的按钮:

   

这样我们基本上初步完成了我们的Scope。同样,我们可以在搜索的框中输入其它任何一个城市的名字,这样我们就可以搜到不同的结果。整个Scope的源代码可以在如下的地址找到:

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

我们将在以下的章节中对我们的Scope做进一步的定制。

5)定制Scope


定制Scope图标


我们虽然可以在我们的手机上或者是在emulator上运行我们的Scope,但是它的icon不是我们需要的。我们可以打开data文件夹,并修改里面的“icon.png”及“logo.png”。这样我们就可以得到我们定制的应用图标了。



定制Scope颜色

打开我们Scope在data目录下的文件“com.ubuntu.developer.liu-xiao-guo.dianping_dianping.ini”。并做如下的修改:

[ScopeConfig]
DisplayName = Dianping Scope
Description = This is a Dianping scope
Art = screenshot.png
Author = Firstname Lastname
Icon = icon.png

[Appearance]
PageHeader.Logo = logo.png
PageHeader.Background = color:///#FFFFFF
PageHeader.ForegroundColor = #F8500F
PageHeader.DividerColor = #F8500F
BackgroundColor = #FFFFFF
PreviewButtonColor = #F8500F

这里我们对PageHeader的颜色做了些改变。我们会看到在手机上的不同的颜色的变化。

   

更多关于个性化的设置,可以参阅文章“Customization & branding”。到目前位置的所有源代码在如下的地址可以下载:

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

定制Category template


我们到目前下面显示的是一个grid的布局,我们想显示更多的信息。先前的template是:

//Create a JSON string to be used tro create a category renderer - uses grid layout
std::string CR_GRID = R"(
{
        "schema-version" : 1,
        "template" : {
        "category-layout" : "grid",
        "card-size": "small"
        },
        "components" : {
        "title" : "title",
        "art" : {
        "field": "art",
        "aspect-ratio": 1.6,
        "fill-mode": "fit"
        }
        }
        }
        )";

由于默认的是水平方向的,我们希望是垂直布局的,这样我们把template修改为:

std::string CR_GRID = R"(
{
        "schema-version" : 1,
        "template" : {
            "category-layout" : "vertical-journal",
            "card-layout": "horizontal",
            "card-size": "small",
            "collapsed-rows": 0
        },
        "components" : {
            "title" : "title",
            "subtitle":"subtitle",
            "summary":"summary",
            "art":{
                "field": "art2",
                "aspect-ratio": 1
            }
        }
})";

同时,为了显示更多的信息,我们加入了“subtitle”及“summary”的项目到“Components”中。我们可以参考文章“Customization & branding”进行对比:

  

为了得到我们所需要的“summary”数据,我们修改我们的Data数据结构为:

    struct Data {
        std::string name;
        std::string business_url;
        std::string s_photo_url;
        std::string photo_url;
        std::string rating_s_img_url;
        std::string address;
        std::string telephone;
        std::string summary; //added
    };

这里,我们新增加一个“summary”的数据,同时我们修改Client.cpp中getData的方法,并增加如下的代码:

        QVariantList deals = item["deals"].toList();

        QString summary;
        if ( deals.count() > 0 ) {
            QVariantMap temp = deals.first().toMap();
            summary = temp["description"].toString();
        }

        qDebug() << "summary: " << summary;

在Query.cpp中,我们也新加入如下的代码来显示我们的“summary”数据:

            catres["subtitle"] = data.address;
            catres["summary"] = data.summary;
            catres["fulldesc"] = data.summary;
            catres["art2"] = data.s_photo_url;

重新运行我们的Scope,我们可以看到如下的显示:

  

显然通过上面的改变,我们已经达到了修改我们的Scope的目的。虽然是同样的数据,我们可以通过修改我们的template来得到不同的显示。所有的源代码在如下的地址可以找到:

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

加入设置


我们在这里想对dianping Scope做一个设置。比如我想有更多的搜寻的结果,而不是每次只有最多20个。我们可以通过文章“如何在Ubuntu Scope中定义设置变量并读取”来多我们的limit进行设置。首先,在Query类中加入函数。我们也需要在query.h文件中加入相应的定义:

query.h

private:
    void initScope();

// The followoing function is used to retrieve the settings for the scope
void Query::initScope()
{
    unity::scopes::VariantMap config = settings();  // The settings method is provided by the base class
//    if (config.empty())
//        qDebug() << "CONFIG EMPTY!";

    int limit = config["limit"].get_double();
    cerr << "limit: " << limit << endl;

    client_.setLimit(limit);
}

我们在Client.cpp中定义一个方法:

void Client::setLimit(int limit)
{
    m_limit = limit;
}

这里“m_limit”是一个成员变量。我们同时修改:

QString Client::getQueryString(QString query) {
    QMap<QString, QString> map;

    map["category"] = "美食";
    map["city"] = query;
    map["sort"] = "2";
    map["limit"] = QString::number(m_limit);  // 修改这个
    map["platform"] = "2";
 ...
}


并在“run”的开始部分调用它:

void Query::run(sc::SearchReplyProxy const& reply) {

    // Initialize the scopes
    initScope();

 ....
}

同时不要忘记在“data”目录下生产相应的.ini文件(/dianping/data/com.ubuntu.developer.liu-xiao-guo.dianping_dianping-settings.ini)。注意这里的格式必须是“包名”-settings.ini。其内容如下:

[limit]
type = number
defaultValue = 20
displayName = 搜寻条数

我们也同时需要对“data”目录下的CMakeLists.txt文件进行修改。添加如下的部分到其中:

configure_file(
  "com.ubuntu.developer.liu-xiao-guo.dianping_dianping-settings.ini"
  "${CMAKE_BINARY_DIR}/src/com.ubuntu.developer.liu-xiao-guo.dianping_dianping-settings.ini"
)

INSTALL(
  FILES "${CMAKE_BINARY_DIR}/src/com.ubuntu.developer.liu-xiao-guo.dianping_dianping-settings.ini"
  DESTINATION "${SCOPE_INSTALL_DIR}"
)

这个部分的改动是为了能够把设置文件也安装到手机的文件系统中去。我们可以在项目中点击右键,并选择运行“Run CMake”,这样,我们在Project中可以看到新添加的.ini文件。重新运行我们的Scope,并在Scope的右上角的设置图标(像有锯齿的 )去尝试改变limit的值,看看效果是什么样的。

  

这样通过改变搜寻的数目,我们可以看到搜寻的结果的条数的变化。整个源码在如下的地址可以找到:

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

6)利用Scope位置信息搜索附近位置的信息


目前我们的点评Scope已经能够完成绝大部分的工作了。我们可以通过它来搜索不同城市的美食佳肴。比如我们可以输入“北京",“上海”,“广州”等城市的美食。美中不足的是我们大多数情况下是希望能够搜索到我们附近的美食等。许多外地的美食可能对我们来讲并不感兴趣。为了能够多位置进行搜索,我们可以利用Scope架构中所提供的位置信息进行对位置进行搜索。我们可以重新对点评API来进行研究,我们发现点评的API中有如下的描述:



在这里我们可以看到,在点评的API中,可以对地理位置经纬度进行搜索。如果我们可以利用当前的经纬度进行搜索,我们就可以找到当前位置的有兴趣的东西了。如果这样,我们搜索的关键词又会是什么呢?我们可以发现API这里有一个关键词category。我想我们可以对category进行搜索。也即对分类进行搜索。通过我们对category的分析,目前category的分类有如下:

美食,休闲娱乐,购物,丽人, 结婚,亲子,运动健身,酒店, 汽车服务,生活服务

在我们的Scope中,我们可以通过输入上面的关键词,这样就可以找到当前位置我们喜欢的美食,酒店等信息。这个信息对于我们来说是非常有用的。
为了实现这个功能,我们在我们的Query类中加入位置信息成员变量:

class Query: public unity::scopes::SearchQueryBase {
public:
    Query(const unity::scopes::CannedQuery &query,
          const unity::scopes::SearchMetadata &metadata, api::Config::Ptr config);
    ~Query() = default;
    void cancelled() override;
    void run(const unity::scopes::SearchReplyProxy &reply) override;

private:
    void initScope();

private:
    api::Client client_;

    QString m_longitude;    // added
    QString m_latitude;  // added
};

同时在query.cpp的开始部分,我们加入两个经纬度常量。这样当我们没有获得位置时,我们将使用这个常量的位置信息来显示当前位置的信息:

const QString DEFAULT_LATITUDE = "39.9698";
const QString DEFAULT_LONGITUDE = "116.446";

在Query::run的方法中加入如下的代码:

void Query::run(sc::SearchReplyProxy const& reply) {
    try {
        initScope();

        // Get the current location of the search
        auto metadata = search_metadata();
        if ( metadata.has_location() ) {
            qDebug() << "Location is supported!";
            auto location = metadata.location();

            if ( location.has_altitude()) {
                cerr << "altitude: " << location.altitude() << endl;
                cerr << "longitude: " << location.longitude() << endl;
                cerr << "latitude: " << location.latitude() << endl;
                auto latitude = std::to_string(location.latitude());
                auto longitude = std::to_string(location.longitude());
                m_longitude = QString::fromStdString(longitude);
                m_latitude = QString::fromStdString(latitude);
            }

            if ( m_longitude.isEmpty() ) {
                m_longitude = DEFAULT_LONGITUDE;
            }
            if ( m_latitude.isEmpty() ) {
                m_latitude = DEFAULT_LATITUDE;
            }

            qDebug() << "m_longitude1: " << m_longitude;
            qDebug() << "m_latitude1: " << m_latitude;
        } else {
            qDebug() << "Location is not supported!";
            m_longitude = DEFAULT_LONGITUDE;
            m_latitude = DEFAULT_LATITUDE;
        }

        client_.setCoordinate(m_longitude, m_latitude);

        // Start by getting information about the query
        const sc::CannedQuery &query(sc::SearchQueryBase::query());
        QString queryString = QString::fromStdString(query.query_string());

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

        Client::DataList datalist;
        if (query_string.empty()) {
            queryString = QString("美食");  // changed
            datalist = client_.getData(queryString.toStdString());
        } else {
            // otherwise, get the forecast for the search string
            datalist = client_.getData(query_string);
        }

 ...
}

注意这里,我们加入了代码对位置信息的获取,并同时修改了对搜索的关键词的改动。我们默认的是“美食”而不是先前的“北京”城市。

为了能够进行编译,在Query.cpp的开始部分加入如下的头文件:

#include <unity/scopes/SearchMetadata.h>
#include <QDebug>

我们必须同时在Client类中加入成员变量:

    QString m_longitude;
    QString m_latitude;

同时加入如下的方法:

void Client::setCoordinate(QString longitude, QString latitude)
{
    m_longitude = longitude;
    m_latitude = latitude;
}

当然,最后,我们也不要忘记修改我们的API请求的部分,把经纬度的信息加入进去:

QString Client::getQueryString(QString query) {
    QMap<QString, QString> map;

    map["category"] = query; //This is the new search item
    // map["city"] = query;
    map["sort"] = "2";
    map["limit"] = QString::number(m_limit);
    map["platform"] = "2";

    map["latitude"] = m_latitude;
    map["longitude"] = m_longitude;
   
    ...
}

这里我们对“category”进行搜索而不是上面的对“城市”进行搜索。经过这样的改造,我们基本上完成了我们对位置的搜索的Scope了。由于在Desktop上显示对位置不支持,所要对这个对位置的搜索进行测试,我们必须在真实的手机上进行测试。重新编译我们的Scope,并部署到一个真实的手机上。当我们重新运行我们的Scope在手机上时,在“Application Output”窗口显示的是如下的信息“



它显示我们并没有对位置进行支持虽然我们的GPS已经被打开了,这是什么原因呢?这是由于Ubuntu平台的安全性所造成的。我们必须修改我们的相关设置。我们可以参照文章“怎么在Ubuntu Scope中获取location地址信息”对我们的Scope进行配置。打开我们Scope的“com.ubuntu.developer.liu-xiao-guo.dianping_dianping.ini”,并加入如下的句子:

[ScopeConfig]
DisplayName = Dianping Scope
Description = This is a Dianping scope
Art = screenshot.png
Author = Firstname Lastname
Icon = icon.png

LocationDataNeeded=true // added

[Appearance]
PageHeader.Logo = logo.png
PageHeader.Background = color:///#FFFFFF
PageHeader.ForegroundColor = #F8500F
PageHeader.DividerColor = #F8500F
BackgroundColor = #FFFFFF
PreviewButtonColor = #F8500F

重新运行我们的Scope:

   


注意通过这样的改变,我们可以只能对如下的关键词进行搜索:

美食休闲娱乐购物丽人结婚亲子运动健身酒店汽车服务生活服务

一个更为完整的department的Scope可以在“在Ubuntu OS上创建一个department 点评Scope (Qt XML)”找到。到目前位置的所有的源码在如下的地址找到:

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

7)生成click包及部署到手机中


如果开发者想生成自己的click包或把Scope安装到自己的手机中,我们可以按如下所示的步骤操作:

选择手机target并成功编译





选择“Publish”生成click安装包或直接安装到手机中




如果是生产click安装包的话,文件可以在和项目名称(dianping)处于同一级的下面的一个目录中可以找到,比如对我们的情况:



最终的安装名称是一个以“click”为扩展名的文件。对于我们的情况是“com.ubuntu.developer.liu-xiao-guo.dianping_0.1_armhf.click。”如果我们得到click安装包的话,我们就可以在其它的任何一个手机上进行安装了。我们可以按照文章“怎么安装Ubuntu应用到Device”把我们的click文件安装到手机中了。

对于安装到手机的中Scope,我们可以通过如下的方式打开我们的Scope:








作者:UbuntuTouch 发表于2014-11-14 13:15:58 原文链接
阅读:127 评论:0 查看评论

Read more
Steph Wilson

Community members at the Sprint

Victor and Andrew are two inspiring Community developers that have devoted their spare time to contribute to the Ubuntu Touch Music App team. I sat down with them during the Washington Device Sprint in October where they told us how they drew inspiration from the Design Team, and what drives them to contribute to Ubuntu.

You can read more about Victor and Andrew through their blogs, where they post interesting articles on their work and personal projects.

From left to right: Riccardo, Andrew, Filippo and Victor

From left to right: Riccardo, Andrew, Filippo and Victor

Hey guys, so when did you first get involved with Ubuntu?

Victor: “I started to contribute to the Ubuntu platform in March/April 2013 where I noticed there was no music app, so I started putting one together. It was pretty sketchy to start with, but it worked. I didn’t have a device to test it on so I mostly tested it using the platform on my desktop – so things were a bit hit and miss.

There was also another developer doing a music app, and at the time there was no core capability of playing music through an application for the proposed devices. Michael Hall (Open Source Software Developer) and Alan Pope (Engineering Manager) pulled Daniel Holm and I together, where we merged our core bases and started the music core app.

We didn’t have as much time as other applications, so we more or less sprinted like we are now to get things done. It was very spec driven and specific, which was helpful but sometimes it was hard to put together a full vision of what the designers wanted. So now we are redoing it from the feedback we have gathered, and it’s going pretty well. A little more agile than it was previously as to do thing faster, but it’s been fun the whole time. It’s nice to work on an application that people need and gets visibility, never get sick of hacking at it.”

Andrew: “I’m from North London, where I’m currently studying Software Engineering at Oxford Brookes University. I was working on my own music app where I just taught myself how to do things using my own framework, then I saw that these guys at Ubuntu had a similar problem to me, and so I thought I’d provide a patch. This then built up from there, and now here I am!”

Steph: “It’s amazing that someone can be in their bedroom writing codes and then suddenly your app is on a phone!”

Victor: “The other great thing about it is the Community Managers make it easy and apparent that you can contribute to different projects.”

Andrew: “Yeah someone just got in contact with me and asked me if I wanted to join the team and told me how open source projects work.”

What inspired you to contribute?

Victor: “A lot of my original inspiration was from what the Design Team had previously done. The previous iteration design spec was very large for the music app and it wasn’t as future driven, more just visually pleasing.”

Do you find it hard to implement some designs?

Victor: “We try to make it as close to the designs as we can, but obviously there’s compromises. There was some very flow driven things such as: sized cover arts that were hard to implement, but we can implement them now. It’s nice because they use the same pattern from other applications.”

Andrew: “Usually we just tell the designer that this is just not possible.”

What is it about open source that you like?

Victor: “I have been a user since 2006, but I have never been a large open source developer myself. It is hard to get involved with when you don’t know what you want to contribute to.”

Andrew: “Most applications are so developed already, so you would have to learn the existing code base and develop on it, whereas if you start a new you know everything from the get-go. Seeing your application on the device and knowing it can be on other devices too, is pretty exciting!”

How does it fit into your lifestyles?

Victor: “I’m a software engineer as well, so I write a lot of code. I haven’t really done QML or QT until I started doing these applications with the Ubuntu platform, so it has been a learning experience. I am learning something new from experienced people.”

Have you made any other applications for Ubuntu?

Victor: I’ve made a few games like Piano Tiles, and another that’s kind of like a clone of that but in QML – It’s a simple app but a good time waster haha.”

How much time does it take you to develop an app?

Victor: “It took me like a day. Andrew made a game last night! In 2 hours…”

Andrew: “Yeah we did! Loads of us at the sprint just got together in a room and made a few games.”

So you’re used to working remotely, does that put a barrier against things?

Andrew: “It sometimes delay things. However, you start to build this image of a person, so when you actually get to meet them you start to understand how they are and what makes them tick.

Victor: “Depends on how personal it really needs to be. If you are collaborating together and it’s mostly writing code and coming up with ideas, it doesn’t necessarily need to be face-to-face. It is obviously nicer, but you also get the benefit if the other person is a night owl in a different country where sometimes our hours overlap, two different chunks of time we’re working in.

Andrew: “There’s usually someone on IRC to speak to, it’s like a 24 hour operation haha.”

What’s the vibe like in the Community at the moment?

Victor: “It’s a pretty small Community at the moment, with close ties. Everyone is receptive to feedback, so if it was larger Community I don’t think it would be as receptive.”

Steph: “Thanks for your time guys!”

Here’s a sneaky preview of the music app, more will be revealed soon:

Album detail

Landing page

Read more
David Planella

.tg {border-collapse:collapse;border-spacing:0;border-color:#ccc;margin:20px auto;width:680px !important;} .tg td{font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:#ccc;color:#333;background-color:#fff;} .tg th{font-size:14px;font-weight:normal;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;border-color:#ccc;color:#333;background-color:#f0f0f0;} .tg .tg-4eph{background-color:#f9f9f9}

image-phone-naturallyneat-medium

This is a week full of exciting events in the Ubuntu world! Following on the series of Ubuntu Scopes Workshops for the Ubuntu Scopes Showdown, we’re thrilled to announce more Scopes Workshops sessions as part of the Ubuntu Online Summit.

Scopes workshops: learn more and ask your questions

In order to support participants of the Scope Showdown, we’re organizing a series of workshops around different topics on writing scopes. These will be 1 hour hands-on sessions where the presenter will be demonstrating the topic live on video, with real code and using the Ubuntu SDK.

These are also meant to be interactive, so during and after the session the presenter will be answering the questions posted in real time by developers on the chat widget on each session page. Here’s the schedule for the workshops:

Workshop Time Presenter
Online Accounts for Scopes Developers Thursday, 13th Nov at 14:00UTC Alberto Mardegan
Scope Development How-Tos Thursday, 13th Nov at 15:00UTC Thomas Strehl & the Unity API Team

In a nutshell:

  • WHAT: Scopes workshops at the Ubuntu Online Summit
  • WHEN: Thursday, 13th November, starting at 14:00 UTC
  • WHERE: At the Ubuntu Online Summit

Looking forward to seeing you there!

Read more
David Callé

Departments are a way for the user to navigate the data source exposed by a scope. A music scope can use them to allow browsing by genre, a Youtube scope could list channels and playlists, a news scope could use them for listing topics, etc. Departments can also display a full hierarchy of sub-departments.

In this tutorial, you are going to learn how to create and add them to your scope.

Read…

scope_dep8 scope_dep9

Read more
facundo

Como loco con las películas


Gran cantidad de películas vistas, principalmente porque tuve un par de viajes en el medio (y en uno en particular, tanto en la ida como en el regreso, tenía enchufe en el asiento, así que pude ver varias pelis sin preocuparme de la duración de la batería de la laptop).

Y también porque vi varias en casa. Como contrapartida, vengo atrasado con las series... pero bueno :)

  • A Good Day to Die Hard: -0. Algunos momentos de humor. No mucho más, demasiado repetido todo.
  • Branded: -0. Demasiado volada. Tiene una idea interesante, y una historia, pero no se llevan bien del todo.
  • Dark Shadows: -0. Una gran colección de actores para una historia que ni fú ni fá.
  • Emergo: -0. Tiene algunas cosas muy interesantes, pero todo ese tipo de películas donde tenés una imagen quieta durante un minuto y de repente se mueve o pasa algo, me aburren profundamente.
  • Extraterrestre: -0. Algunos momentos tiene, y la historia de la película no está mal, es una mirada nueva. Pero en general me aburrió :/
  • Hit and Run: -0. Una comedia romanticona más, principalmente de persecuciones y disparos. Berreta, pero con sus momentos de humor.
  • Into the Mind: +0. La historia no vale demasiado... pero la fotografía es absolutamente genial.
  • Intruders: +0. No es la gran cosa a nivel de terror, pero tiene giros interesantes, y me mantuvo atrapado hasta el final.
  • Iron Man 3: +0. Un poco más de lo mismo, pero dentro de eso, la película está bien, y es un correcto cierre a la historia.
  • Meeting Evil: -1. Dos escenas. O tres. Nada más.
  • Metegol: +1. La historia está buena, y la animación es inmejorable, muy buena peli.
  • Muppets Most Wanted: +0. Es *obviamente* para chicos... pero es linda.
  • Oblivion: +0. Una buena película de ciencia ficción y acción. Podría ser mejor con alguna que otra mejor actuación, si fuese menos previsible, y sin un par de errores conceptuales en la historia. Pero zafa, cumple.
  • One for the Money: +0. Comedia romántica con algo de acción... muy muy liviana, pero divertida.
  • Savages: +0. La historia no es la gran cosa, pero muy bien contada! Buenas actuaciones, buena fotografía, buena dirección.
  • Side Effects: -0. Un poco lenta, algo predecible, y con un final bleh. Tiene sus momentos interesantes y algunos giros, pero no alcanza.
  • Side by Side: +1. Muy buena película que muestra la evolución en la tecnología del cine. Muy bien armada la película, maravillosamente contada.
  • Skyfall: +0. Es una buena película de James Bond (con floja participación de chicas Bond, sin embargo). Si te gusta, bien, sino a otra cosa.
  • The Adjustment Bureau: +1. Muy buena historia, muy bien explicado lo que tiene sentido explicar (dejando afuera lo que no tiene sentido, claro), muy interesante todo el concepto.
  • The Amazing Spider-Man: +0. La peli está buena, pero está muy pegada al original, con lo cual es como ver un remake de la película de hace sólo ~10 años, y eso le resta muchísimo.
  • The Bourne Legacy: -0. Una peli de persecuciones. No vale la pena. Sí, tiene algo alrededor, pero nada nuevo contra las Bournes anteriores. En resumen... te entretiene, pero no vale la pena.
  • The Call: +0. La peli no está mal, las actuaciones muy buenas y la historia.... bien hasta el final. O sea, hasta cuatro minutos antes del final :/
  • The Debt: -0. La historia tiene un trasfondo interesante... pero me aburrió demasiado.
  • The Last Stand: -0. "Hagamos una con Arnold, que está viejo, repitiendo clichés; pongamos a una parejita linda como ayudantes, y algunos actores buenos para que le den estructura". La peli es de esas que los malos, los buenos y los buenos están todo el tiempo disparando para ver quien la tiene más larga.
  • The Paperboy: -0. La historia está buena... demasiado sórdida, quizás, sin mucho sentido; es como una pequeña imagen de algo que no llegó a crecer, se nota que le falta profundidad en muchos aspectos (al final te enterás que es basada en una novela, eso lo explica).
  • Total Recall: -0. No me gustó... por lo fantasioso. O sea, si va a ser una película de ciencia ficción, todo bien, pero que sea más o menos en serio. Si van a agarrar un libro de Philip K. Dick y lo van a llevar a la pantalla estilo Underworld, no da...


De este lado, también un montonazo de películas nuevas! Parece que se pusieron las pilas con temas interesantes. Ojo, también hay algunas que son viejas y me las recomendaron hace poco.

Una novedad es que empecé a incluir de qué va la peli (argumento, fecha, género, actores, director), lo que puede servirle a alguien para a priori descartarla o decidir de buscar más info. Obviamente, no los escribo yo, sino que los estoy sacando de IMDB; sí, ya sé, está en inglés... pero es mejor que nada.

  • 7 cajas (2012; Action, Thriller) It's Friday night in Asunción, Paraguay and the temperature is sweltering. Víctor, a 17-year-old wheelbarrow delivery boy, dreams of becoming famous and covets a fancy cellular phone in the infamous Mercado 4. He's offered a chance to deliver seven boxes with unknown contents in exchange for a quick US$100. But what sounds like an easy job soon gets complicated. Something in the boxes is highly coveted and Víctor and his pursuers quickly find themselves caught up in a crime they know nothing about. [D: Juan Carlos Maneglia, Tana Schembori; A: Celso Franco, Víctor Sosa, Lali Gonzalez]
  • All Is Lost (2013; Action, Adventure, Drama) Deep into a solo voyage in the Indian Ocean, an unnamed man (Redford) wakes to find his 39-foot yacht taking on water after a collision with a shipping container left floating on the high seas. With his navigation equipment and radio disabled, the man sails unknowingly into the path of a violent storm. Despite his success in patching the breached hull, his mariner's intuition and a strength that belies his age, the man barely survives the tempest. Using only a sextant and nautical maps to chart his progress, he is forced to rely on ocean currents to carry him into a shipping lane in hopes of hailing a passing vessel. But with the sun unrelenting, sharks circling and his meager supplies dwindling, the ever-resourceful sailor soon finds himself staring his mortality in the face. [D: J.C. Chandor; A: Robert Redford]
  • Autómata (2014; Sci-Fi, Thriller) Jacq Vaucan is an insurance agent of ROC robotics corporation who investigates cases of robots violating their primary protocols against harming humans. What he discovers will have profound consequences for the future of humanity. [D: Gabe Ibáñez; A: Antonio Banderas, Birgitte Hjort Sørensen, Melanie Griffith]
  • Camp X-Ray (2014; Drama) A young soldier escapes her suffocating small town by joining the military, only to find that she isn't going for a tour of duty in Iraq as she hoped. Instead, she's sent to Guantanamo. Met with hatred and abuse from the men in her charge, she forges an odd friendship with a young man who has been imprisoned at Gitmo for eight years. [D: Peter Sattler; A: Nawal Bengholam, Peyman Moaadi, Lane Garrison]
  • El Ardor (2014; Drama, Western) A mysterious man emerges from the Argentinean rainforest to rescue the kidnapped daughter of a poor farmer after mercenaries murder her father and take over his property. [D: Pablo Fendrik; A: Gael García Bernal, Alice Braga, Claudio Tolcachir]
  • Focus (2015; Comedy, Crime, Drama, Romance) A veteran grifter takes a young, attractive woman under his wing, but things get complicated when they become romantically involved. [D: Glenn Ficarra, John Requa; A: Margot Robbie, Will Smith, Rodrigo Santoro]
  • Interstellar (2014; Adventure, Sci-Fi) In the near future Earth has been devastated by drought and famine, causing a scarcity in food and extreme changes in climate. When humanity is facing extinction, a mysterious rip in the space-time continuum is discovered, giving mankind the opportunity to widen their lifespan. A group of explorers must travel beyond our solar system in search of a planet that can sustain life. The crew of the Endurance are required to think bigger and go further than any human in history as they embark on an interstellar voyage, into the unknown. Coop, the pilot of the Endurance, must decide between seeing his children again and the future of the human race. [D: Christopher Nolan; A: Ellen Burstyn, Matthew McConaughey, Mackenzie Foy]
  • The Hunger Games (2012; Sci-Fi) In a dystopian future, the totalitarian nation of Panem is divided between 12 districts and the Capitol. Each year two young representatives from each district are selected by lottery to participate in The Hunger Games. Part entertainment, part brutal retribution for a past rebellion, the televised games are broadcast throughout Panem. The 24 participants are forced to eliminate their competitors while the citizens of Panem are required to watch. When 16-year-old Katniss's young sister, Prim, is selected as District 12's female representative, Katniss volunteers to take her place. She and her male counterpart, Peeta, are pitted against bigger, stronger representatives, some of whom have trained for this their whole lives. [D: Gary Ross; A: Stanley Tucci, Wes Bentley, Jennifer Lawrence]
  • La Vénus à la fourrure (2013; Drama) An actress attempts to convince a director how she's perfect for a role in his upcoming production. [D: Roman Polanski; A: Emmanuelle Seigner, Mathieu Amalric]
  • Laggies (2014; Comedy, Romance) In the throes of a quarter-life crisis, Megan panics when her boyfriend proposes, then, taking an opportunity to escape for a week, hides out in the home of her new friend, 16-year-old Annika, who lives with her world-weary single dad. [D: Lynn Shelton; A: Keira Knightley, Chloë Grace Moretz, Sam Rockwell]
  • Mad Max: Fury Road (2015; Action, Adventure, Thriller) An apocalyptic story set in the furthest reaches of our planet, in a stark desert landscape where humanity is broken, and almost everyone is crazed fighting for the necessities of life. Within this world exist two rebels on the run who just might be able to restore order. There's Max, a man of action and a man of few words, who seeks peace of mind following the loss of his wife and child in the aftermath of the chaos. And Furiosa, a woman of action and a woman who believes her path to survival may be achieved if she can make it across the desert back to her childhood homeland. [D: George Miller; A: Tom Hardy, Charlize Theron, Nicholas Hoult]
  • Mortdecai (2015; Action, Comedy) Juggling some angry Russians, the British Mi5, his impossibly leggy wife and an international terrorist, debonair art dealer and part time rogue Charlie Mortdecai must traverse the globe armed only with his good looks and special charm in a race to recover a stolen painting rumored to contain the code to a lost bank account filled with Nazi gold. [D: David Koepp; A: Johnny Depp, Olivia Munn, Aubrey Plaza]
  • Primer (2004; Drama, Thriller, Sci-Fi) At night and on weekends, four men in a suburban garage have built a cottage industry of error-checking devices. But, they know that there is something more. There is some idea, some mechanism, some accidental side effect that is standing between them and a pure leap of innovation. And so, through trial and error they are building the device that is missing most. However, two of these men find the device and immediately realize that it is too valuable to market. The limit of their trust in each other is strained when they are faced with the question, If you always want what you can't have, what do you want when you can have anything? [D: Shane Carruth; A: Shane Carruth, David Sullivan, Casey Gooden]
  • Relatos salvajes (2014; Comedy, Drama, Thriller) A story about love deception, the return of the past, a tragedy, or even the violence contained in an everyday detail, appear themselves to push them towards the abyss, into the undeniable pleasure of losing control. [D: Damián Szifrón; A: Liliana Ackerman, Luis Manuel Altamirano García, Alejandro Angelini]
  • Stealing Beauty (1996; Drama, Romance) After her mother commits suicide, nineteen year old Lucy Harmon travels to Italy to have her picture painted. However, she has other reasons for wanting to go. She wants to renew her acquaintance with Nicolo Donati, a young boy with whom she fell in love on her last visit four years ago. She also is trying tosolve the riddle left in a diary written by her dead mother, Sara. [D: Bernardo Bertolucci; A: Carlo Cecchi, Sinéad Cusack, Joseph Fiennes]
  • The Hobbit: The Battle of the Five Armies (2014; Adventure, Fantasy) Bilbo and Company are forced to be embraced in a war against an armed flock of combatants and the terrifying Smaug from acquiring a kingdom of treasure and obliterating all of Middle-Earth. [D: Peter Jackson; A: Benedict Cumberbatch, Luke Evans, Evangeline Lilly]
  • The Imitation Game (2014; Biography, Drama, Thriller, War) Based on the real life story of legendary cryptanalyst Alan Turing, the film portrays the nail-biting race against time by Turing and his brilliant team of code-breakers at Britain's top-secret Government Code and Cypher School at Bletchley Park, during the darkest days of World War II. [D: Morten Tyldum; A: Benedict Cumberbatch, Keira Knightley, Matthew Goode]
  • The Maze Runner (2014; Action, Mystery, Sci-Fi, Thriller) Thomas wakes up in an elevator, remembering nothing but his own name. He emerges into a world of about 60 teen boys who have learned to survive in a completely enclosed environment, subsisting on their own agriculture and supplies. A new boy arrives every 30 days. The original group has been in "The Glade" for two years, trying to find a way to escape through the Maze that surrounds their living space. They have begun to give up hope. Then a comatose girl arrives with a strange note, and their world begins to change. There are some great, fast-paced action scenes, particularly those involving the nightmarish Grievers who plague the boys. [D: Wes Ball; A: Dylan O'Brien, Aml Ameen, Ki Hong Lee]
  • The Scribbler (2014; Thriller) THE SCRIBBLER follows Suki (Katie Cassidy), a young woman confronting her destructive mental illness using "The Siamese Burn," an experimental machine designed to eliminate multiple personalities. The closer Suki comes to being "cured," she's haunted by a thought - what if the last unwanted identity turns out to be her? [D: John Suits; A: Katie Cassidy, Garret Dillahunt, Michelle Trachtenberg]
  • The Book of Life (2014; Animation, Adventure, Comedy, Family, Fantasy, Romance) From producer Guillermo del Toro and director Jorge Gutierrez comes an animated comedy with a unique visual style. THE BOOK OF LIFE is the journey of Manolo, a young man who is torn between fulfilling the expectations of his family and following his heart. Before choosing which path to follow, he embarks on an incredible adventure that spans three fantastical worlds where he must face his greatest fears. Rich with a fresh take on pop music favorites, THE BOOK OF LIFE encourages us to celebrate the past while looking forward to the future. [D: Jorge R. Gutierrez; A: Diego Luna, Zoe Saldana, Channing Tatum]
  • The Judge (2014; Drama) Hank Palmer is a successful defense attorney in Chicago, who is getting a divorce. When His brother calls with the news that their mother has died, Hank returns to his childhood home to attend the funeral. Despite the brittle bond between Hank and the Judge, Hank must come to his fathers aid and defend him in court. Here, Hank discovers the truth behind the case, which binds together the dysfunctional family and reveals the struggles and secrecy of the family. [D: David Dobkin; A: Robert Downey Jr., Robert Duvall, Vera Farmiga]
  • The November Man (2014; Action, Crime, Thriller) Peter Devereaux is a former CIA agent who is asked by the man he worked for that their person who in Russia who is presently close to a man running for President, who is believed to have committed crimes during the Chechen war, can give them the name of someone who can prove it. His friend says that she will only come to him. So he goes and she gets the info and tries to get out but the man finds out and tries to get her. Peter arrives and gets her but as they are getting away they're shot at. She is killed but tells Peter the name before she dies. Peter kills the men who attacked them but when he sees the leader, Mason, a man he trained, he realizes the CIA is involved. He tries to find the person and the only person who might know where she is, is Alice Fournier, the social worker who helped her when she came to the West. A CIA bigwig comes and orders that Devereaux be taken out and wants Mason to take care of it. An assassin whom the Presidential candidate sent to make sure no one wrecks his chances of becoming President. Devereaux finds Alice and tries to protect while trying to find the girl. [D: Roger Donaldson; A: Pierce Brosnan, Luke Bracey, Olga Kurylenko]
  • Tomorrowland (2015; Mystery, Sci-Fi) Bound by a shared destiny, a bright, optimistic teen bursting with scientific curiosity and a former boy-genius inventor jaded by disillusionment embark on a danger-filled mission to unearth the secrets of an enigmatic place somewhere in time and space that exists in their collective memory as "Tomorrowland." [D: Brad Bird; A: Britt Robertson, George Clooney, Judy Greer]
  • Under the Skin (2013; Drama, Sci-Fi, Thriller) A female drives a van through the roads and streets of Scotland seducing lonely men. [D: Jonathan Glazer; A: Scarlett Johansson, Jeremy McWilliams, Lynsey Taylor Mackay]


Finalmente, el conteo de pendientes por fecha:

(Ene-2009)    1   1
(May-2009)    5
(Oct-2009)   14
(Mar-2010)   18  16   4
(Sep-2010)   18  18  18   9   2   1
(Dic-2010)   13  12  12  12   5   1
(Abr-2011)   23  23  23  23  22  17   4
(Ago-2011)   12  11  11  11  11  11  11   4
(Ene-2012)   21  21  18  17  17  17  17  11   3
(Jul-2012)       15  15  15  15  15  15  14  11
(Nov-2012)           12  12  11  11  11  11  11   6
(Feb-2013)               19  19  16  15  14  14   9
(Jun-2013)                   19  18  16  15  15  15
(Sep-2013)                       18  18  18  18  17
(Dic-2013)                           14  14  12  12
(Abr-2014)                                9   9   8
(Jul-2014)                                   10  10
(Nov-2014)                                       24
Total:      125 117 113 118 121 125 121 110 103 101

Read more
David Planella

Over a week ago, we announced the Ubuntu Scope Showdown: a competition to write a scope for Ubuntu on phones in 5 weeks and win exciting prizes.

Scopes are Ubuntu’s innovative take at revolutionizing the content and services experience. For users, they provide quick and intuitive access to content without the need of loading an app. For developers and operators, scopes provide an easy path to surface their content and customize the UX in a way that is very flexible and integrated.

After the initial contest kickoff, we’ve already had a number of participants blogging, sharing updates and teasers about their work. Here’s a peek at some of their progress.

A variety of scopes

In the words of Robert Schroll, of Beru fame, e-mail apps are just passé. So much that he decided to explore an interesting concept: reading your e-mail with a scope. With a nice extra touch: Ubuntu Online accounts integration.

 Because e-mail apps are so 90s - the Gmail scope


Because e-mail apps are so 90s – the Gmail scope

After listening to one of Daniel Holbach’s mixes, Bogdan Cuza thought they alone deserve a scope, and so the Mixcloud scope was born. The rest, as they say, is history.

Can't get enough of those Balkan Beats - the Mixcloud scope

Can’t get enough of those Balkan Beats – the Mixcloud scope

You don’t know where to eat tonight? No worries, Sam Segers has you covered. Check out his Google places scope to easily find somewhere new to go.

Your cooking skills not up to your date's expectations? The Google places scope comes to the rescue

Your cooking skills not up to your date’s expectations? The Google places scope comes to the rescue

Developer Dan has a treat for all of us movie lovers: the Cinema scope. Features categories and departments, with settings, TV series and genres coming up soon! Check out the details on his blog.

Helping Ubuntu users see what stuff dreams are made of since 2014 - the Cinema scope

Helping Ubuntu users watch stuff dreams are made of since 2014 – the Cinema scope

Riccardo Padovani is bringing the dark horse -or well, duck?- of search engines into Ubuntu. Armed with the DuckDuckGo scope, get results like a pro with “real privacy, smarter search and less clutter”.

Duck is the new black - the DuckDuckGo scope

Duck is the new black – the DuckDuckGo scope

A wishlist of scopes

As Alan Pope and Michael Hall, I do have my wishlist of scopes for content that I’d like to have accessible at a flick of the finger on my phone. Maybe someone of you can make our day?

  • 8tracks scope: I love music, and I love mixes. 8tracks is a music streaming service to listen to the mixes their community members create and to get creative submitting mixes. As an avid mixer and listener, I’d be using this all of the time, especially if it came with Online Accounts integration that showed me content relevant to my interests.
  • Ask Ubuntu scope: the biggest Ubuntu Q&A site. I regularly check the ‘application-development‘ tag there to see any new questions and if I can help a fellow Ubuntu developer (and you should too). It’d be absolutely awesome to get those updates easily on my phone screen, with settings to filter on tags and the ability to upvote/downvote questions and answers.

Not sure what to write a scope for yet? Well, check out the ideas over at the Showdown reddit, or let your imagination run wild with a comprehensive list of APIs to get more inspiration!

A prize for your scopes

It’s not too late to enter the Showdown, you too can write a scope and win prizes! Here are some tips to get started:

Looking forward to seeing the next batch of scopes participants come up with!

The post The Ubuntu Scope Showdown – progress showcase appeared first on David Planella.

Read more
David Planella

More content coming up for app and scope developers targeting Ubuntu on devices: this time around Online Accounts!

Learn the concepts on how to write account providers for online services using the Ubuntu Online Accounts API (UOA), and let the API take care of all the complexity and security for you, so that you can concentrate on your code.

Go to the Online Accounts Developer Guide >

Read more
Daniel Holbach

Ubuntu Online Summit: 12-14 November

Yet another Ubuntu Online Summit (UOS) is ahead of us. It’s going to happen from 12-14 November. Participation is open to everyone, so to attend simply:

If you still need to get a session on the schedule to discuss a topic related to your field, create the session soon!

What I love about the Ubuntu Online Summit is that people get together, invite some fresh sets of eyes and brains and figure out together where Ubuntu is going. The sessions are also not too long (1h), so you are forced to come conclusions (and work items!) quickly.

Sessions I’m particularly looking forward to are:

  • 12 Nov
    • 15 UTC – Community Roundtable
    • 15 UTC – Testing Unity 8 Desktop
    • 16 UTC – App/Scope development training events
    • 18 UTC – Community events in Vivid cycle
    • 19 UTC – More appdev/scope code examples
  • 13 Nov
    • 16 UTC – Community Council Feedback
    • 16 UTC – Porting Apps To Ubuntu
    • 18 UTC – Ubuntu Women Vivid Goals
    • 19 UTC – Ubuntu Community Q&A
  • 14 Nov
    • 14 UTC – Transparency and participation
    • 15 UTC – Promoting the Ubuntu phone in LoCos
    • 16 UTC – LoCo Team Activity Review
    • 18 UTC – Ubuntu Touch Component Store

Please note: session times might still be changed, so keep an eye on the schedule. (Also: there’s lots more good stuff!)

Looking forward to seeing you all there! :-D

Read more