FileSystem
FileSystem Pharo Moose
Free Software
Moose
Pharo
Pike
REST
RosettaCode
VR
Zinc-REST
angular.js
beijinglug
code-in
collaboration
community-calendar
email
ember.js
fish
interview
life-after-death
n-reduce
open hardware
open-party
shell
smalltalk
vim

The idea has been brought up a few times, that we would upload our minds into a computer and in this way would be able to live forever.

How would that look like?

At it's base, every uploaded mind would represent a program with access to data storage and computing resources. These programs can interact with each other not unlike programs on the internet today. For example like in a virtual reality game world. (Second Life, etc)

In uploaded form we would manipulate our environment through other programs, that we create ourselves or that others create for us. There might be a market to trade these programs and its products.

Now, anything that is programmable will have bugs and is exploitable, therefore it will be necessary to protect against such attacks. Much like we use encryption today to keep things private, encryption and self protection will play a large role in such a cyberworld.

Unlike today where we can rely on physical protection, healtcare, etc to support us, in cyberspace, all protection comes in form of programs, and that means instead of relying on others to act in our behalf in order to pretect us, every one of us will be able to get a copy of a protection program that we then will be able to control by ourselves. It's all bits and bytes, so there is no reason to assume that we would not be able to have full control over our environment.

We could build cyberspace without these protections, but it is inconceivable that anyone would accept a world where their own well being is not ensured. Either from the outside, or from the inside. But if everyone is uploaded, then there is no more outside, and therefore all protection must come from the inside, through programs. And since even now, most people are not skilled programmers, and that is unlikely to change much in the future, it is hard to imagine that people would willingly enter a world where their life depends on their programming skills. No, people must be able to trust that no harm will come to them in this new world where they otherwise would not have the skill to protect themselves.

The reason we feel safe in this world is because we agreed to a set of laws which we enforce, and for the most part, crimes are visible and can be persecuted. People who live in places where this is not the case don't feel safe, and noone would willingly leave their save home to move to such an area.

In a cyberworld, such safety can only be achieved by making crime impossible to begin with, because given enough resources, a computer program can do damage without leaving a trace.

This has a few severe implications.

If real crime is impossible and we further have full control over our own protection, controlling what data we receive that could possibly offend us, then effectively we can no longer be hurt. There is no physical pain anyways, and any virtual pain we could just switch off.

If we can not be hurt, the corollary is that we can not really hurt anyone. We can not do anything that has any negative consequences on anyone else.

We can not even steal someones computing resources, or rather we probably could but there would be no point because even if computing resources are unevenly distributed, it would not matter.

There is no sense of time, since any sense of time is simulated and can be controlled. So if we were trying to build something that takes lots of time, we could adjust our sense of time so that we would not have to feel the wait for the computation to complete. With that in mind, stealing resources to make computation faster would become meaningless.

And if we could take all resources from someone, then that would effectively kill them as their program could no longer run. It would be frozen in storage. Allowing this could start a war of attrition that would end with one person controlling everyone else and everyone fearing for their life. It just doesn't make sense to allow that.

In other words we no longer have freedom to do evil. Or more drastically, we no longer have complete free will. Free will implies the ability to chose evil. Without that choice free will is limited.

In summary life in cyberspace has the following attributes:

  • We will all live there eternally (well, as long as the computer keeps running).
  • There is no sense of time.
  • We will keep our sense of identity.
  • We will be able to interact with every human ever uploaded.
  • We will continue to advance and develop.
  • There is no power to do evil.
  • We will be able to affect the physical world, and the physical world will affect us.

Here is how cyberspace looks like from the outside:

  • When a person is uploaded, its physical body ceases to function and decays.
  • Everyone can be uploaded, there is no specific requirements or conditions that would prevent anyone from being uploaded.
  • We are assuming that we will be able to communicate with those in cyberspace, but imagine how it would look like if we could not communicate with an uploaded person. We would then actually not be able to tell if they successfully uploaded or not. We would in fact not even be able to tell whether cyberspace exists at all, and we would have to take a leap of faith that it is real.

Conclusion:

While discussing this article, a lot of arguments were made about the details of how cyberspace would look like. In particular it was questioned that there would be no pain. Most commenters could not imagine that we'd want a painfree life.

That is fine. These particular details are not important. There are many ways we can imagine how cyberspace could look like. What is important is this:

These attributes of cyberspace as described here, are all attributes of life after death as described at least by the Baha'i Faith, and possibly other religions.

This is significant not because of the attributes themselves, but because this means that given todays grasp of technology, at least this version of cyberspace looks indistinguishable from life after death.

Now, if we are unable to distinguish cyberspace from life after death, then how would we know which one we are dealing with? If it is possible that cyberspace looks like life after death, isn't it equally possible that life after death looks like cyberspace? Is it possible that they are one and the same?

Why do we want to upload into cyberspace? Because we want eternal life free from bodily limitations? Isn't this something that religions have promised us for millenia?

If that is the case, wouldn't we be trying to reinvent something that maybe already exists?

So maybe, cyberspace already exists, and death is just the upload process? Maybe we are simply not yet advanced enough to perceive or understand our life beyond the point of upload from the outside?

Maybe we just need to evolve further before we are able to communicate with those who are uploaded?

Author :mbaehr   |   size :7449Bytes   |   Publish Date :May/6/17/15:25   |   to Top

Once in a while i have someone reject to work with me because they don't know Pike. What they are really saying is, that they are not willing to learn something new.

If you are a decent programmer, then learning a new programming language is not hard. Technology changes all the time, and every year you'll learn new frameworks and tools. That's part of your work. So why shy away from learning a new language?

If you can't bring yourself to learn a new language then i suspect you'll also have a hard time learning anything else. So actually i should thank you by refusing the job because of that.

You say: learning a new language is hard.

If you believe that, you haven't tried enough. Sure, if you pick some of the more unusual languages like Haskell, it may be hard (but i don't know, i have not tried learning Haskell yet) and in general, learning your second language is probably the hardest (because the first language you learn, everything is new and you expect it to be hard, but with the second language maybe you fear it is as dificult as the first one, and you don't want to go through that again), also learning a new syntax may take some getting used to.

But all of these hurdles are measured in days.

Pike in particular has a syntax very close to C and Java. (that is, operations that are the same in C, Java and Pike also use the same syntax, with very few exceptions). This makes the syntax also similar to Javascript, PHP, and the many other languages with a C-inspired syntax. Picking that up should not be hard.

The rest is learning the Pike libraries and figuring out what makes Pike tick. You should have that down within a few weeks.

This is the same for pretty much any other language you might start to learn.

I am talking from experience here. I'll give you a few examples:

At my first fulltime job i was hired for my Pike experience. As a junior programmer who hadn't finished univeristy yet, i didn't really have any work history. But i did have a number of Pike modules for the Roxen webapplicationserver that i could show off.

At the same time a university graduate was hired, who had not even seen Pike before joining the team. Within a few weeks she was as productive as the rest of us, and having finished her studies she arguably knew more about programming and could explain more about Pike than i could.

At another job a few years later one of my managers who had just recently joined the company fell in love with Pike, and when he left he built his own company using Pike as the main development language. This guy was not even a programmer.

When i came to china, my first job was for a python programmer. I had learned python by then, but i had no practical experiece whatsoever. I was allowed to do the programming tests in Pike (they had an automated testsuite, which of course could not handle Pike, so in my case the answers were reviewed manually. They had no problems reviewing their tests in a language they had never seen before. That's how good they were). One of the tests i did in python, and i passed and got the job. I was productive from the start.

A few years ago i hired 3 chinese students to work for me. Since this was the first time i hired anyone, i was not sure how learning a new language would go down, on the first day, possibly their first experiene working with a foreigner too. So the first project i gave them was in Java. It was a Java client for the sTeam server. Two of the students left after the summer holidays were over, but one stayed on, and his next project was in Pike. Also for the sTeam server, so he could reuse his knowledge of the APIs that he learned during the Java project, but he did have to learn the language itself. He was productive within a few days.

Last year i was hired to help with a PHP project, using the Laravel framework. I had never really written PHP code before, but the framework was not so different from others (eg Django) so that i was productive immideately. And i ended up fixing other peoples code too.

This summer, i was working with 3 students for Google Summer Of Code. One student worked on the sTeam server, and had to learn Pike for that. He did it during the get-to-know period and started churning out code from the first day of the coding-period.

Another student picked a smalltalk project. She learned smalltalk as soon as she picked the project, joined the pharo-smalltalk community and became a recognized contributor to the pharo 4.0 release. All before her proposal for the GSOC project was even accepted.

Convinced yet?

You say: Noone else uses Pike. It won't help me get a job.

That is probably true. But it is becoming less true as time goes by.

One of the problems with hiring is that, just as you believe learning a new language is hard, so do the hiring managers, and thus they search only for programmers that already know the language that they will need to use.

In the Pike community too. I was the only Pike programmer available who liked moving countries, and so i had my pick for jobs in the USA, in Germany, in New Zealand, in Latvia. Thanks to Pike i got around. Try that with a popular language.

Fortunately, this is changing. Like my first China job, more companies recognizing the ability to learn as more important than a particular language. For them it won't matter which programming languages you learned, as long as you can demonstrate your learning skill. In fact, learning an unknown language will let you stand out as someone serious about learning programming languages.

Learning new languages will also increase your confidence in your ability. For that PHP job i was never asked how much PHP experience i had. I did make clear that i had no experience with Laravel, which is something they could not expect from everyone, even if they had plenty of PHP experiece. But i had experience with similar frameworks, and i was confident that i could pick up what i needed quickly. And i proved it.

When i am hiring programmers myself, i definetly don't care which languages they know. All i care is that they know at least two languages. These people have at least gotten over the second language hump, and learning a third language will be a breeze. Whether it's Pike or any other language.

Stop telling me that you can't learn a new programming language. You can! Because if you couldn't, you would not qualify as a programmer to begin with. At least, i would not hire you.

Author :mbaehr   |   size :6930Bytes   |   Publish Date :Aug/24/15/17:47   |   to Top

In this session we are going to build a simple RESTful API using the Zinc-REST package.

The base image is again Moose, now the latest build of Moose 5.1

You may watch part one, part two and part three of this series if you are interested to find out what lead to this point. They are however not needed to be able to follow this session.

Author :mbaehr   |   size :702Bytes   |   Publish Date :Feb/28/15/17:23   |   to Top

For part three of our workshop series we start from scratch, and build a small website that hosts nothing but static files from a memory FileSystem.

We are also going to explore the new development tools that are built in the Moose project

You may watch the first and second parts of this series, or you may jump right in here.

In the next session we are going to build the RESTful API to make this application functional

Author :mbaehr   |   size :851Bytes   |   Publish Date :Feb/28/15/17:20   |   to Top

In the second part of this series we transform our website to serve all content as files from a FileSystem object.

If you haven't yet, take a look at part 1

In the next session we will serve an actual web-application

Author :mbaehr   |   size :523Bytes   |   Publish Date :Feb/13/15/08:41   |   to Top

For the community-calendar project in total, 11 tasks were proposed, of which 7 got completed:

Not so much work got done on the code itself, but we now have some documentation of the API as well as the start of a testing framework to help keep the API stable.

As a sideproject, these tasks were designed to explore the ember.js framework. the calendar-widget, going to be embedded into different websites was a good target because we now can offer both versions for embedding.

For ember.js the student, samarjeet wrote about the work in his weblog. An initial comparison: Comparing the community-calendar
Creating Ember Components turned out to be more dificult, and we had to enlist outside help to solve it.
Finally, a deeper comparison of Angular.js vs. Ember.js

This leaves us with 4 tasks that were not worked on

Author :mbaehr   |   size :3345Bytes   |   Publish Date :Jan/31/15/09:19   |   to Top

I have been interviewed by CSDN. The interview has been published today in chinese.

The original english answers as i sent them are below:

1. Could you introduce yourself to us first?

I am using and developing Free Software and Open Source for more than 20 years. I am a contributor to the Pike programming language, the Foresight Linux distribution and several other Free Software Projects. I co-edited a book on Pike and organized developer conferences. I am also a mentor at FOSSASIA. Throughout my career I focused on developing and advocating Free Software. I have lived and worked in several countries around our planet Earth. I came to china in 2008. I am currently the CTO at eKita, a startup in Bangkok, and the General Manager at Realsoftservice, a Linux service firm in Beijing where i offer software development, training and internships. I live in Beijing with my family.

2. Compared with your own country, what attracts you most in China or Beijing?

China (and Asia in general) has a different culture from western countries. Learning chinese culture allows me to look at situations from a different perspective.

I believe that all the world should be united into one country. And in order to do that we need to understand the different parts of the world, what everyone can contribute to this world, and what unifies us.

China is a large part of this world, and also not much is known about china outside of it. The only way to learn about china is to be here.

China is also huge. I like to travel, and china allows me to travel long distances to places that are very different from each other without having to cross any borders.

3. What is your role in BLUG? Could you describe the important development milestones of BLUG?

I am acting as the secretary. That means i help to arrange meetings and events for the group.

I joined the BLUG in 2008 and i am not familiar with the history before. One important event before i joined was the 2007 Software Freedom Day which was chosen as the best SFD event for that year.

At the time, when i joined, the BLUG had monthly meetings, frequent quan'r dinners and BLUG Tuesday events. We also had a group aiming to build a quadcopter and a library. Active members were both foreigners and chinese.

In summer 2008 an intern at Exoweb where i worked at the time, together with me initiated a hackaton event called "Coding For Fun". I then continued hosting the event by myself as part of the BLUG. When i left Beijing other BLUG members continued hosting the event.

When I came back to Beijing some active members had left. I took over the management of the group in 2013, when most active members had left. At that time active participation was very low. I continued running the monthly meetings and Coding For Fun events. In Autumn we re-started BLUG Tuesday and used it to test new meeting locations. That way we found our current meeting place.

We slowly regained new active members, most of them chinese.

4. What kind of difficulties have BLUG encountered in the process of development, and how to solve them?

The main difficulty we have is finding good locations for the meeting and Coding For Fun events. It is still an unsolved problem. We don't have sponsors to pay for using locations, so we rely on offers for places we can use for free.

5. What are the daily activities in BLUG? Do you (or BLUG) have any interactions with other communities?

I am trying to visit and keep relations with every group that i can find in Beijing. I am regularly participating at events from the Beijing Open Party, Ruby, Python, Angular.js meetups. Barcamp and more.

Most of these groups have Linux users, but as i am a programmer, many groups are interesting to me personally too.

We also work with other groups to organize events, for example the Software Freedom Day. or we support conferences like GNOME.asia and FUDcon or the OpenSUSE summit, all of which had volunteers who are BLUG members.

We also participated at Google Code-In with FOSSASIA.

6. Have you ever attended open source activities in other countries or regions?

What are the differences between other countries and China in Open-source activities?

Every place and every country i have lived in, i participate in the local activities. These vary in size and regularity. In some cases my visit was the motivation for a group to have more meetings. In most groups the meeting involved some form of topic presentation and discussion. But sometimes it was just going out for dinner. Really not much different from china.

7. From your personal point of view, could you share with us some tips on how to manage one open source community successfully?

Well, there are different kinds of communities, for example those that revolve around a particular software project where all members in some form contribute to that software project. The contributions to such projects are often motivated by the contributors own needs. The main goal for community managers is to get active contributors to the project.

Other communities are more loose where people just share a common ideal, but actually may contribute to different projects.

The BLUG is of the latter kind. People contribute to the BLUG more out of a desire to serve the community than out of a personal need. And many do not contribute to the BLUG directly.

The goal of the BLUG is to provide a venue for Free Software contributors and users to share and meet like-minded people. Most Free Software Communities are spread all over the world, whereas groups like the BLUG are very local.

To manage a local group, i believe persistence would be the most important aspect. If the group has meetings, they should be regular, so that new people can easily find out when and where the meetings happen. Then it takes a while for the word to spread, and attendance to grow. Keep holding the meetings, even if only two or three people join. Then keep advertising the group and invite new people. Eventually more will join and come back regularly.

8. Could you introduce us some active and outstanding members in BLUG?

It is difficult to praise the contributions of some people without unjustly leaving out others. Moreover i don't even know all the contributions of every member. Some members don't come to the meeting often but they are very active elsewhere in the Free Software and Open Source Community. This is one of the things that tends to be miss-understood about the Free Software community.

Some people worry if they release their work with a Free Software license, then others can take advantage of it without giving anything back. But we don't know if those users are not active somewhere else making contributions to our society in other ways.

This is after all what i believe is the purpose of our life. All Men have been created to carry forward an ever-advancing civilization. (人人生来是为了推动文明不断进步的)

9. GNU project founder Richard Stallman came to China in May, 2014, did you have a meet with him?

And what do you think about the Free Software campaign leaded by Richard Stallman since 1980th?

I have met richard stallman a few times before, but never had much direct interaction with him. This year he joined us for a BLUG Dinner. As for his campaign, i fully support the idea of Free Software. I believe that all knowledge should be shared, and everyone should have the opportunity to use all of the worlds knowledge in their work. To fulfill the purpose of life we should all use our work to contribute to society. And allowing others to use and modify our software is a great and very easy way of doing that.

10. The last one, could you reveal to us the BLUG's future development plan, and what kind of activity will be organized in the future days?

Future plans of the BLUG depend on its members. For now my goal is to get more active members, people who help to host events, give talks, or help contribute to our website. The BLUG website is very old and in dire need of an upgrade. but it is difficult to do if we want to keep all the data.

I am also trying to work on a community calendar where we can share all events

Author :mbaehr   |   size :9220Bytes   |   Publish Date :Jan/29/15/08:13   |   to Top

I am learning how to build a website with a RESTful API in Pharo Smalltalk. This project started during Google Code-In as a set of tasks for students to work on. A handful of students were interested and picked up tasks to learn Pharo.

Now that Google Code-In is over, the students are interested to continue learning and so i am running workshops with them, where we explore the tools needed to build this server.

The first workshop was held last week on sunday the 25th, and the next one will be on saturday the 31st of Jnauary. from 2pm to 6pm chinese time, that is 7am to 11am CET or 6am to 10am UTC. We will meet on freenode irc in the channels #fossasia and #pharo.

A part of website consists of static files. To simplify development and deployment, we want to serve those files from the smalltalk image. One way to hold several documents inside an image is using a memory FileSystem. The FileSystem class is described in the book "Deep into Pharo" in chapter 3.

In the first workshop we try to use the FileSystem class in a sample application. We use the tutorial "Building and deploying your first web app with Pharo" as a starting point, and adapt the code to store images in a FileSystem object.

If you want to follow along, please first complete the tutorial and then watch the screencast below to continue:

In the next session we will convert the rest of the website to using our FileSystem object.

Author :mbaehr   |   size :1976Bytes   |   Publish Date :Feb/3/15/05:41   |   to Top

For years i have been meaning to learn smalltalk. my first exploration started about 10 years ago while teaching two children to make a game with squeak. Then i worked through a tutorial about making a simple game. Unfortunately it didn't capture my interest. So the my attempts to learn smalltalk were stalled as i searched for a project that i could do with it.

Why do i want to learn smalltalk? Because it is the first object-oriented language. Many of the OO concepts were invented in smalltalk. There is also the concept of working in an image that not only contains my code but also a full IDE which is used to update my code at runtime. Updating code at runtime is a concept that has been with me for more than 20 years now, ever since i started programming MUDs in LPC and writing modules for the Spinner/Roxen webserver in Pike. Pike allows recompiling classes at runtime. Any new instances will be made from the new class, while old instances remain as is. If the compilation fails, the class is not replaced and the old class continues to work. This way it is possible to make changes on a live server without restarting and disrupting ongoing requests. A decade later i discovered sTeam, the platform that also drives this very website. It takes this process even further: sTeam persists code and objects in a database. While in Roxen objects live as long as it takes to process a request, in sTeam objects are permanent, much like in a smalltalk image. sTeam then adds the capability to update live objects with new class implementations. The image concept of smalltalk is therefore already very familiar, and the major difference is smalltalk's GUI.

Recently a friend asked me what it would take to build a text search application for the Baha'i writings in chinese. There is one for english and other western languages, but not for chinese, and it does not run on mobile devices. It is also not Free Software, so i can't use it as a base to improve. But i didn't really want to take on a new project either so i just filed the idea for the time being.

One of my customers is managing access to several internal resources through htaccess and htpasswd. Because they have many interns who need to have access to some of these, and because they are now spread over multiple servers, it is becoming more and more cumbersome to manage them manually via these files. It also does not help that a salt module which we could use to help depends on apache helpers, which we can not install because apache conflicts with nginx which we are using. So i started exploring alternatives. One such alternative is a different way for nginx to verify access. It can make a request to an external service which then grants or rejects access depending on the resource and credentials. This could be implemented as a webservice with a webinterface to manage the users. I looked for some existing applications that would get me part of the way but i found nothing suitable.

Enter Google Code-In: FOSSASIA invited the BLUG to join them as mentors.

At first i put up tasks for the community-calendar project, but then i realized that this was an opportunity to explore new ideas. Figuring that teaching is the best way to learn i put up those project ideas as tasks for the students. I could ask students to learn and explore, and finally work on those projects. I would pick the technology and guide the students through a sequence of tasks to acquire the skills needed to implement the actual applications. This was my chance to get back into smalltalk. Since code-In targets middle and highschool students, it is quite unlikely that any of them already know smalltalk, or have even heared about it. so in a way this will introduce a few students to smalltalk. I picked pharo because i feel it is going in the right direction trying to improve itself and also adding things like commandline support.

The desktop application was straight-forward: find out how to embed text-documents in the image and make them searchable.

The web application took more exploration. I wanted to do it with a RESTful api and a javascript frontend. Again, the frontend was easy to define: create a user management interface. For the backend, the question was which webframework to use? AIDA/web has builtin user management and REST style url support by default. Seaside includes a REST module, but both are strong on generating html which i am not interested in. Then there is iliad, which appears more lightweight. Eventually i figured i could just let the students explore each, and i created a task for each tutorial that i could find:

(some of these i repeated because the student who did the them first time didn't pick up the follow-up tasks.)

Finally i discovered that Zinc, the HTTP server used by most frameworks is powerful enough to build a RESTful API without all the templating extras that the above frameworks provide. I also discovered teapot, a microframework that might be useful.

Once the students are familiar with the smalltalk environment, they can move on to the next steps:

Of course there are also tasks for the front-end

Related is also this task about a file editor, which i believe should make it easier to edit static assets like html and css pages from within the image:

Author :mbaehr   |   size :8501Bytes   |   Publish Date :Jan/1/15/15:18   |   to Top

FOSSASIA is a mentor organization at Google Code-In, and the Beijing GNU/Linux User Group has been invited to join them as mentors.

Two of us joined and created tasks for our projects.

At first i created tasks for our community-calendar project, but then i took the opportunity to get students to work on new projects that i had been hoping to do. For a long time i wanted to learn smalltalk, but i lacked good project ideas. This changed recently, as a friend asked me about a text search application, and one of my customers needed a better solution than htpasswd to manage users for nginx. I decided that both could be done in smalltalk.

So i created tasks for three new projects: A text search application to run on the desktop, and one on mobile, and a user-management web-application. For the desktop and the web-application i stipulated pharo smalltalk as the implementation platform. For good measure i also threw in my idealist for sup, a reimplementation of the frontend for this weblog in angular.js, a t-shirt design for the BLUG, packaging pike, and exploration of the meetup.com api. I also proposed a new structure of the files for the fossasia api, and helped mentor a few tasks relating to getting chinese communities added to the api.

  • community-calendar (7 tasks)
  • desktop text search application (2 tasks)
  • mobile text search application (2 tasks)
  • user-management web-application (12 tasks)
  • sup ideas (more than 50 ideas, create tasks as needed)
  • fossasia (1 task)
  • sTeam weblog ui (1 task)
  • blug t-shirt (1 task)
  • amber (2 tasks)
  • file-editor (1 task)
  • packaging pike (1 task)
  • meetup.com api (3 tasks)
new tasks will be added as needed, when i get another idea for improvements on one of the projects, or if i feel a task needs to be redone.

Author :mbaehr   |   size :1935Bytes   |   Publish Date :Dec/31/14/03:53   |   to Top

The following command is used to watch the progress of files being updated in a directory.

watch 'du -h *| tail -20 | cut -c -$(($COLUMNS-5))'

cut is used so we don't get linewraps in the output. And we need to subtract 5 from the width because there is a tabstop in there which cut counts as 1 instead of the width of the tabstop (which is 8 minus the width of the size column)

This command works fine as long as files are updated in alphabetical order, but when this is not the case we need to sort files by time.

We need to do something like this instead:

watch 'du -h $(ls -tr)| tail -20 | cut -c -$(($COLUMNS-5))'

Unfortunately this only works if the filenames don't contain spaces.

fish handles spaces in filenames just fine:

du -h (ls -tr)| tail -20 | cut -c -(math $COLUMNS - 5)

So instead of trying to find a solution for dealing with spaces in bash, lets just use a better shell, shall we?

However, watch insists on executing the command with sh -c, so we need to devise our own watch loop for fish instead. That's not really hard:

while true
  clear
  du -h (ls -tr) | tail -20 | cut -c -(math $COLUMNS - 5)
  sleep 2
end

Unfortunately using clear causes an annoying flicker, especially if the du command takes a bit longer.

ANSI escape-sequences help:


clear
while true
  echo \e\[H
  du -h (ls -tr) | tail -20 | cut -c -(math $COLUMNS - 5)
  sleep 2
end

This causes the cursor to be moved into the top-left corner without clearing the screen. Now we are almost there. Two problems still:
The tab character used to align the columns does not overwrite anything in its space. Likewise at the end of the line, if the newly written line is shorter then the remaining part of the old line is not cleared.

We can fix this with some sed trickery to clear the path:


clear
while true
    echo \e\[H
    du -h (ls -tr) | tail -20 | sed -e 's/^/\x1b\[K/' | cut -c -(math $COLUMNS - 2)
    sleep 2
end

The ANSI escape sequence ESC[K clears the line just before it is rewritten. This has almost the same effect as clearing the screen, but without the flicker because we only start clearing after du has done its work.
And because the escape sequence adds 3 characters to the output we need to adjust the width accordingly.

At the end we can also add a command to clear the rest of the screen.

Leaves one last issue: $COLUMNS doesn't get updated if the terminal is resized. Granted, it's a nit-pick really, because how often does one resize the terminal. But to make this command generally usable, let's fix this too:


clear
while true
    echo \e\[H
    du -h (ls -tr) | tail -20 | sed -e 's/^/\x1b\[K/' | cut -c -(math (tput cols) - 2)
    echo \e\[0J
    sleep 2
end

This is now pretty usable, so we'll leave it at that. There is still some room for improvement though. For example we could make the line-count flexible based on the terminal height. Also currently we are estimating that the size column is at least 2 characters wide so the tabstop adds at most 5 characters worth of space which cut does not count. Should it be less then we would get a linewrap again and if it is more then we get empty space at the end of the line. cut likely also has problems with multibyte unicode characters. This can probably be solved by switching the terminal in a no-wrap mode while the command is running, or finding a replacement for cut that handles these issues.

Update:

For those who prefer to stick with sh, i found a way how do deal with spaces:

watch 'ls -tr | while IFS= read -r i; do du -h "$i"; done | tail -20 | cut -c -$(($COLUMNS-5))'
Author :mbaehr   |   size :4458Bytes   |   Publish Date :Sep/20/13/03:36   |   to Top

I needed to quickly serve some files, and i didn't want to install a full webserver, knowing that this was only temporary. So instead here is a simple http file-server in Pike. I call it a file-server because it serves static files, and nothing else.

Based on this example for a simple web-server, it just takes a few additions to turn this into a file-server:

#!/usr/local/bin/pike

constant default_port = 8080;
constant my_version = "0.0";

Protocols.HTTP.Server.Port port;

string basedir = "/srv/www";

int main(int argc, array(string) argv)
{
  int my_port = default_port;
  if(argc>1) my_port=(int)argv[1];

  write("SocServe starting on port %d\n", my_port);

  port = Protocols.HTTP.Server.Port(handle_request, my_port);
  return -1;
}

void handle_request(Protocols.HTTP.Server.Request request)
{
  write(sprintf("got request: %O\n", request));

  mapping response = ([]);

  response->server="SocServe " + my_version;

  string target = Stdio.append_path(basedir, request->not_query);
  mixed tstat = file_stat(target);
  write("target: %O\n", tstat);

  if (tstat && tstat->isdir)
  {
    response->type = "text/html";
    response->error = 200;
    response->data = dirlist(target);
  } 
  else if (tstat && tstat->isreg)
  {
    response->type = MIME.ext_to_media_type((target/".")[-1]) || "octet/stream";
    response->error = 200;
    response->file = Stdio.File(target);
  }
  else
  {
    response->type = "text/html";
    response->error = 200;
    response->request = sprintf("%O", mkmapping(indices(request), values(request)));
    response->data = "<h1>SocServe " + my_version + "</h1>n<pre>"
    + response->request + "</pre>n";
  }

  request->response_and_finish(response);
}

string dirlist(string path)
{ 
  array dir = get_dir(path);
  return sprintf("%{<a href=\"%s\">%s</a><br>\n%}", ({ dir[*], dir[*] })); 
}

These are the changes: first combine the request path with our basedir which will reduce any embedded /../ to not go beyond that base. Then we check if it's a directory or a file. For a directory we make a simple listing, and for a file we find the mime-type and then just open the file and pass it to the request. This will cause the file to be served with non-blocking I/O, allowing you to handle multiple requests in parallel without blocking the server while a file is being downloaded.

That's all there is to it. Start it up, and it's ready to serve files.

Author :mbaehr   |   size :2640Bytes   |   Publish Date :Jul/7/13/17:51   |   to Top

To solve this problem i found this useful solution, but discovered that it didn't cover all cases i had.

s/\v(\U)([^\.]*\.)/\u\1\L\2/g

To start with, \U does not mean every not-uppercase letter, but every character from the whole set that is not uppercase. So it includes spaces and everything else. This causes the expression to match " hello world!" if the sentence doesn't start at the beginning of the line, which is not quite what we want. To get every non-uppercase (that is lowercase) letter use \l. But even that does not really work, because it means that now it matches "Hello world." as "ello world.", and we get a transformation as "HEllo world!". Again, not what we are looking for. Unfortunately, until someone can suggest a method to skip already capitalized sentences we have to stick to \w.

Next, the expression only excludes periods, but not question-marks, exclamations or other sentence ending characters. We can extend this by simply including the respective characters: [^\.?!:;]. We also do not need to enforce the terminating character, we can simply drop that. What we really want to match is the beginning of the sentence, we don't care about the end.

Also, unless the text is in all uppercase, lower-casing the second group could be counter productive as it would affect upper-cased acronyms etc. that are already there.

Lastly, we want to capture sentences spanning multiple lines, lest every line gets matched as a separate sentence. This is achieved using \_.

(And inside a character set the . doesn't need to be escaped.)

Putting it all together we get s/\v(\w)(\_[^.?!:;]*)/\u\1\2/g

Instead of matching a whole sentence we can also try searching for the end of the previous sentence: s/\v(%^|[.?!:;]\_s+)(\a)/\1\u\2/g

Author :mbaehr   |   size :2163Bytes   |   Publish Date :Mar/8/13/15:52   |   to Top

Since i already found last week that creating views with jquery is not easy i decided to explore alternatives first. Already from early check-ins i received recommendations for angular.js, knockout.js and backbone.js.

Taking this frame work comparison as a guide i excluded backbone.js, and because a friend from the singapore hackerspace had also recommended angular.js i started with that.

Implementation was straight forward. What i really liked was that i didn't have to redo my datastructure that i had made up beforehand, but angular.js allowed me to access and traverse the data in the form that it was available. After some trials i even managed to build that 3 levels deep nested loop. (Iterate over columns, then projects and then task-types)

Then i briefly tried knockout.js but dropped it quickly because it would have caused me to put ko.observable() all over the place. angular.js handles this way better in my opinion. It simply observes the whole dataset and checks for updates.

Other contenders from the above comparison table were ember.js and batman.js. I had a brief look at ember.js and found that similar to knockout it would force me to write a new object-based datastructure, so i dropped the idea. batman.js is written in coffeescript, which is interesting but i want to stick to pure javascript for now, so i'll explore that later.

Author :mbaehr   |   size :2186Bytes   |   Publish Date :Aug/22/12/15:06   |   to Top

This weeks goal was to learn how to work with PhoneGap/Cordova. Because of that i figured i could just link a Phonegap tutorial for this weeks goal. The report video is worth watching though. It covers the PhoneGap installation with eclipse, which went smoothly following the instructions on the website. Another Highlight this week was that we received 6 "awesome" votes, which is enough to get us over the minimum of 10 needed to access mentors.

Only two details are worth noting about the installation: The instructions call for installation of the android SDK, but it turned out that when installing the eclipse android plugin, the SDK was downloaded and installed right along with it. So you can skip the SDK step. The other point to note was that if you want to use the emulator you need to use the SDK manager to download a system image and then create a virtual device using the device manager. After that you are ready to roll.

Since the install was smooth and painless i moved on to the next step and quickly implemented the mockup in static html/css. i also tried to build the html from a function using jquery, but had no luck with that.

Why PhoneGap?

I have looked briefly at whats out there and somehow PhoneGap came to my attention. I watched some introductions and found that made a good case being all Free Software and supporting many platforms.

One great feature is that you can mix native and html views

Now they see it as allowing a transition from a native app to an html app, but i see also the reverse as ultimately we wanted to build native apps. This will allow us to do so without having to start from scratch. Instead we can focus on adding native code where it matters, where for example html is to limited to achieve a certain effect that we need or to slow. (It may turn out that we never need that, but it is good to have that option)

Also their stance of believing in the vision that all future mobile apps should be based on html and css and that they really want to make themselves irrelevant by expecting that eventually the browsers will pick up that functionality (so that all you need to deploy is html, css and js) is quite interesting. I am not necessarily agreeing with their idea of the future, but i certainly like their approach to it.

The phonegap guys even claim that they don't have competition.

Author :mbaehr   |   size :2963Bytes   |   Publish Date :Aug/22/12/15:05   |   to Top

Today's Open Party had a low turnout due to strong rain. Nonetheless it still had 11 talks in 4 tracks. Topics were Firefox OS, Geek Park, backbone.js conference report among others.

My presentation about nReduce gathered about half a dozend people. Given 3 competing talks and not more than 20-30 visitors overall this is actually quite a high turnout. They were also quite engaged and asked many questions. Maybe we'll get some more beijing teams when nReduce opens a new batch. One person was also interested in the email-task-manager.

nReduce is an online incubator. That is, the key benefits of joining an incubator: meeting other teams and sharing your experience, as well as talking to mentors, are brought online. Every team makes weekly goals and reports with short (less than 1 minute) videos. Teams group with other teams to work with and then discuss each others weekly progress. Our experience with nReduce was great from the start. Every week we received valuable feedback. A few times our check-in had the most discussion activity from all the teams we grouped with. Our progress is slow because we work on this only part-time for now, but we managed to come up with suitable goals that invited discussion.

We have now reached the halfway point and also reached a significant milestone for the email-task-manager. Until last week we were not clear whether we should start with a webinterface or focus on mobile clients first. The opinions were divided with me siding for the web. But one short comment by Hugh Mason clarified what we should do:

the folk who started with mobile first were forced to focus on the ONE really important feature of their product because of the small screen and the demand for instant gratification that mobile users show. That was really valuable. I'd always generally going for mobile first now if you plan on it being mobile ever
After reading that the goal was as clear as day. We absolutely have to start with mobile. There is no doubt about it now. We need to focus on the features that we can fit onto a mobile screen first, before expanding onto larger devices where we can use the space to add more features. It is also interesting to note that while we found related and competing products, none of those seem to focus on mobile.

Author :mbaehr   |   size :2446Bytes   |   Publish Date :Jul/21/12/09:46   |   to Top

Phoronix declares the death of the open-source graphics card, but i disagree. Now, i am not really following the projects mentioned in the article (though i pay attention when i come across the topic), but i believe that open-source graphics is far from dead and it will come back. I am certain. We just need some patience.

In the long term, since the first computers, more and more sophisticated devices are being created by hobbyists. It is all a matter of the cost of components and the availability of affordable tools. For example, just recently oshpark.com was launched. A site that will print custom circuit boards at an affordable price. This site may not be the first of its kind, but it certainly is not the last. And just like the 3d printers, circuitboard printing is becoming accessible to more people, and it will be followed eventually by the ability to create small batches of affordable ICs, opening up room for more development and creation of open hardware.

Incidently, just today i attended a meeting here in beijing of openbrd. A group of young enthusiastic developers intent on making a completely open version of a miniature form factor arm based computer. (Like the raspberry pi or the beagleboard, but all specs, drivers, etc completely open and designed to allow anyone to build the device for themselves). So they are not designing the chips themselves, but another group like them, in a few years, may. They are meeting weekly in a restaurant in the northwest of beijing. About half a dozen people sat around a table, watching an unscripted presentation and discussing the topic. Today's topic wasn't about open hardware but introduced wget and curl and then by a second speaker, emacs. This group formed less than a year ago, but it is not the first group about open hardware in beijing. Before it, the beijing linux user group was leading an effort to create an open hardware quadcopter. But like the open-source graphics projects, that project eventually ceased (because some key members left beijing). Worldwide, there are many more groups like it. And one day, one of these groups will produce that open source graphics card.

As i said, i am not closely following the open-source graphics card efforts, and it may be a long time before these efforts gains some traction again, as well as the focus may shift to other components in a digital device. But the failure of existing projects to produce a result is a setback, it's not the end. just wait!

This topic is also discussed on LXer. In particular, khamul makes some compelling counter arguments regarding the prospects of accessible IC production.

Update:

A short while after this posting the developer behind Project VGA has written a lengthy email explaining why the open-source graphics card is no more. It appears to be that part of the problem was lack of openness from a company supporting the project. And then, just a few days later a university group announces that they are developing an open source graphics accelerator as part of their master thesis.

Author :mbaehr   |   size :3632Bytes   |   Publish Date :Jun/25/12/07:40   |   to Top

Because i usually find potential clients through the internet i am occasionally confronted with the question on dealing with remote work. In this post i will try to relay my experience and hopefully answer some questions.

I will write about four types of collaboration:
Effective local collaboration and effective remote collaboration as well as complete lack of local collaboration and ineffective remote collaboration.
I have experienced all four.

The key to each one is communication. if communication does not happen, it will fail. Let me detail all the types above and explain what i learned from them. Starting with the complete lack of local collaboration.

The situation here was that i was hired to work on a specific project by myself. There was no team, just a manager who was unfortunately very busy. I was seated in a different room and left alone to do my work. The result was a complete desaster. I didn't have enough guidance, there was no oversight, no progress checking, nothing. This was probably as much my fault as the managers. As i said he was busy, and i should have been more upfront to ask.

I believe that if i had done this project from home, it would have been more effective for that situation. When you are in an office it is easy to assume that you are disciplined and working, and making progress. When you work at home your manager will be more concerned to find out if you are really working, and at least check in once in a while. Also working from home makes it more obvious that actual working time needs to be documented as opposed to mentally ticking a clock when you enter and leave the office.

Later, when i started to work from home my first client asked for hourly time sheets. At first i thought that it would be a drag, but then i realized that it was quite liberating because i could take a break whenever i wanted without feeling guilty and simply subtracted that time from the time sheet. It helped with the discipline :-)

The next type is ineffective remote collaboration. The situation here was that i joined a team that was working on a Free Software project at a university. I was the only outsider in that team. I was welcomed with open arms. The personal relationship with the other developers was great. When i visited them we had parties together, and when i joined them in the office we were working together.

But that office became the problem in the long run. As everyone else was there, most communication happened accross the desk face to face, so not only was i not involved in the communication or decisions, i often didn't even find out about plans, goals, opportunities etc...

Not enough effort was made to keep me in the loop and as a result i didn't really see much opportunity to contribute. Opportunity sure was there, and if i had just done what i wanted i could have ignored the communication problem and just send in code. But i like to work with a team, and not despite it.

Now let us look at the types where collaboration worked.

There are actually two types of local collaboration. One is the usual with regular meetings, everyone does their thing, if you have a question you go and ask, you help each other, everything as you'd expect.

The second is more interesting. What was unusual here was that we were 50 people in the company working on a large project with a client on the other side of the planet. All communication was done through a project internal irc server that we shared with the client. Once a day we had a project wide irc meeting where everyone, yes, all 50 odd people, would report on what they were working on. Within 5 minutes there was a flodd of issue tracker numbers and short comments, so everyone got to see what everyone else was doing. The meeting was in two parts: first a plain status report, and then a problem report. A bot was there to track that everyone had made their status report before problem reports were allowed.

The rest of the day, work was done in small teams. Each team had their own daily 5 minute stand up meeting, which was done face-to-face and extra meetings if they needed it.

The office was a large open space, and because of that talking was usually not convenient and if you had a question you'd ping your colleague on irc even if she was sitting right behind you.

Using irc in this manner had another sideeffect. It was simply less disruptive. If you were diving deep into a coding problem you could simply ignore the irc window and you wouldn't be disturbed. On the other hand if i didn't get a response even though i can see my collegue if i turn around i would know that he was busy and so i'd either work on something else else or find another person for my question.

(Here are some articles on why interruptions are bad: http://37signals.com/svn/archives2/the_science_of_interruptions.php http://www.paulgraham.com/makersschedule.html http://www.futurepundit.com/archives/004149.html)

This setup had another sideeffect. It didn't actually matter if you were in the office. If the situation called for it, you could work from home without affecting productivity. Also occasionally some of the senior developers were sent to the clients location, but they'd continue to work with their team from remote.

Because all communication was written, it could be logged, and so you could for example review the irc meeting even if you missed it.

Which brings us to the last type: fully working from remote. Above all else, consider the vast amount of Free Software developed by volunteers all across the world. You can pretty much guess that most of them work from remote. And successfully so. Myself, i am involved in several international Free Software projects and i have worked with clients in new zealand, singapore, germany and austria all from remote.

the most recent project for example was managed using trac with work shared among half a dozend people in almost as many locations in two timezones (6h difference).

we used trac, email, irc, jabber and voip to communicate.

working from remote forces you to write down more, which in turn gives more opportunity to think before expressing something, or to correct it.

There is an interesting paper on this topic called: "Can Absence Make a Team Grow Stronger?" (A. Majchrzak, A. Malhotra, J. Stamps and J. Lipnack), Harvard Business Review, May 2004, pp. 137-144 ( (there are more papers on this topic at http://public.kenan-flagler.unc.edu/faculty/malhotra/))

So it all comes down to the willingness of team-members to use suitable communication tools and make sure that remote team members are kept in the loop. positive sideeffects include better documentation or more doccumentation of informal decisions, a quieter office and more flexibility for the team members without negatively affecting the teams productivity.

This article in itself demonstrates one of the advantages of remote work.

It was written as a direct response to one potential client. now, imagine someone asking me this question in a personal meeting. I'd give them an answer, but it would be much shorter and not contain as much details or even reference links.

So not only did i answer the clients question, but i produced a general document that will answer this question for everyone else.

I wrote documentation.

Author :mbaehr   |   size :8210Bytes   |   Publish Date :May/14/12/18:00   |   to Top

LXer today posted an article that compares email to MPI.

What i find interesting about this article is not the realization that MPI is like email, but the reverse, that human collaboration using messages is like MPI. The suggestion to use SMTP as a transport for things much more complex than emails is something worth looking at. It relates to my belief that the instant messaging difference does not come from the new protocols like XMPP for jabber, but from the new client interface that facilitates short messages in a conversational style. SMTP is equally (if not more) capable of transporting these messages. Sure, SMTP is not designed for "instant" messaging. but todays use of SMTP where my local SMTP server talks directly to your SMTP server, makes email is just as instant.

We don't need another protocol, at best we need improved SMTP servers that handle multicast messaging. But the sender/recipient envelope is as simple and timeless as it gets. Any additional data can be added in headers, and here is where there is plenty of room for change.

We can make email messages more sophisticated, with additional headers indicating for example whether a message requires an action, or a response or whether it is merely informational. A reply message could then contain headers to show if the message is a response, or a followup question, or just an acknowledgement of the original message.

All we need for this is to add these features into email clients to allow more sophisticated messages to be sent and received.

Author :mbaehr   |   size :1798Bytes   |   Publish Date :Mar/28/12/10:29   |   to Top

Stack Overflow is a great site. Every time when a search on a problem takes me there i look forward to the helpful and insightful answers. In ways, posting a question on Stack Overflow is similar to creating a task on RosettaCode.

On Stack Overflow a problem gets posted in form of a question, and people attempt to solve the problem by answering it. Question and answers can be discussed and updated. Once the poster of the question is satisfied, an answer may be chosen as being accepted.

On RosettaCode a problem gets posted in form of a Draft Task and people attempt to solve the problem by creating an implementation in their favorite language. Task and implementations may be discussed and revised until a consensus is found. Once discussion stabilizes and people focus on implementing, the task may be promoted from Draft Task to Task status

The key difference is that the questions and answers on Stack Overflow can be of various qualities. There are lots of duplicates, and not always are the answers useful. On RosettaCode on the other hand the poster is motivated to solve the Task her or himself. Also the goal of all Tasks is to produce a usable implementation, and the discussion does not end when an answer is accepted by the poster but it continues until a consensus for an acceptable task definition is found. And then after that the Task stays active as long as new solutions in different languages get added. Also RosettaCode gets referenced frequently in Stack Overflow discussions

On RosettaCode people are not motivated to answer by getting points but because the answer helps shape the Task and thus ultimately the quality of the whole site. They take ownership of the task by providing their implementation. They don't want to help a fellow with a question but produce something of lasting benefit for all future visitors of the site.

As Stack Overflow grows, it will be harder and harder to sift through all the questions to find the right answer, whereas the growth of RosettaCode will lead to a library of problems and solutions where one can find practical code examples that have a clear relationship to the question (the Task) with several complete implementations that allow for analysis and comparison.

When i have a problem to solve i try to see if it is generic and interesting enough for RosettaCode. Then i formulate a Task, and make an attempt at solving it myself. The discussion often helps me to identify problems that i had not foreseen, edge cases, and different approaches. Every new task includes a lot of learning and goes beyond just solving the immediate problem.

I don't know if the creator of RosettaCode had this kind of use in mind, but i hope he can see the value of this approach. And it is not only new Tasks that get created this way, but also solutions to existing Tasks too. Just in the past week i found three Tasks that were directly applicable to problems i am currently solving. And one of the Tasks motivated me to produce a generic solution to a problem that i had solved in an adhoc manner before.

By using RosettaCode i am not just solving problems for myself, but i help generate solutions that are useful for other people too.

Author :mbaehr   |   size :3388Bytes   |   Publish Date :Jan/9/12/17:58   |   to Top

cal is a commandline tool to display a monthly or yearly calendar. It's convenient to use for lookup when there is no gui at hand.

It has a few limitations and irritations however. The most annoying one is that whenever i want to display a different month i have to enter a year as well. If you enter cal 2 it will display the year number 2, and not the month that i'd expect.

This pike version of cal fixes that. If you enter a number small enough to be a month then it will display the corresponding month of the current year.

The pike version has other features too. Thanks to pikes extensive calendar support, cal.pike can handle calendars other than the gregorian calendar. You can see a list of supported calendars in the pike module reference. To use a different calendar, just enter the name of the calendar as a first argument. The only calender from that list that doesn't work is Stardate because that doesn't have any months.

Further, motivated by this calendar task on rosettacode.org i have added support for varying terminal sizes. The program will check the calendar in an optimal with for the terminal. For a calendar with 12 months this means it will either fit as 2x6, 3x4, 4x3 or 6x2 rows and columns. The pike version for that task is btw only the year display. Support for showing a month and other stuff has been removed.

Other features: pikes calendar system supports events to mark holidays. Days that fall on an event are displayed in green. It is possible to choose events by region.

cal.pike is available under the GNU GPL v3. You can download it here

Author :mbaehr   |   size :2107Bytes   |   Publish Date :Jan/5/12/16:35   |   to Top

A few months ago i discovered rosettacode.org, a website where various programming tasks are implemented in many different languages.

rosettacode is not only useful to compare languages, but also to learn new ones. You can see how a problem solved in a language that you know, looks like in the language you are learning. Or you can try to implement it in that new language, using the existing implementations as a reference.

For me to learn a new language, i need to be able to do something useful with it. Simply taking a book and doing exercises that are thrown away is not very motivational.

But doing the same kind of exercises on rosettacode is quite different, because the result is useful to those who want to use the solution for comparisons.

Solving tasks on rosettacode of course only works with tasks that are not already solved in your target language. But that is not usually a problem because no single language on rosettacode has all tasks solved. And there are new tasks every week.

For pike there are still a few hundreds of tasks unsolved, ranging from trivial to very hard. So there is something for every level. And don't fear of making a mistake. Your solutions will be reviewed by others, and corrected or discussed if necessary.

If solving existing tasks does not satisfy you, you can also make up new tasks.

Writing tasks can be fun and challenging. But again, no fear. Others will add appropriate questions and point out where your task is unclear or could be improved. That alone is a great learning experience. Then providing your implementation and comparing it with the solutions others come up with is educational. Some people may come up with an approach that you have not thought of, giving you further insight into the problem, and may even cause you to adapt your own solution.

In summary, whether you are completely new to pike or an experienced developer, rosettacode is a place where you can improve your skills, contribute to others learning experience, and show off pikes unique features. I hope you will join me in increasing pikes presence on the site.

Author :mbaehr   |   size :2468Bytes   |   Publish Date :Dec/25/11/15:02   |   to Top