Project 1: Hello, NodeBB!¶
Learning Goals¶
- Familiarize yourself with an existing software project
- Download, install and run an existing software project
- Onboard on development tools and technologies
- Learn Git Flow and GitHub to support future collaborative development
- Run local analysis tools and use the output to evaluate a codebase
Project Context¶
Welcome to the 17-313 development team! To get started, you will be going through our onboarding process to familiarize yourself with both the course and the project you will be working on. Eventually, you will be tasked with designing and developing new features, but the first step is to download, run, explore, and evaluate the existing software product.
This semester, we will be building upon NodeBB, an open-source community forum software project that was started in 2014. You can learn more about this project from the original development team's website.
For your own development, you will be forking your own repository off of a class-specific fork of NodeBB, which you can find at https://github.com/CMU-313/NodeBB.
Our fork contains some tweaks to make the project easier to modify and debug. This will also allow you to create issues and pull requests that are visible to the instructors, which will be the primary way of submitting code deliverables for this project.
Deliverables and Deadlines¶
This is an individual assignment. There are four (4) deliverables and one (1) deadline for this homework.
Onboarding – 100 points – due Thursday, January 26th, 11:59pm
- Build Checkpoint (5 pts)
- GitHub Issue (20 pts)
- GitHub Pull Request (35 pts)
- Gradescope Written Assignment (40 pts)
Prerequisites¶
Onboarding Materials¶
Before jumping into the codebase, please review the course syllabus and be sure you have access to each of the following:
- Course Slack - check your email for an invite link
- Canvas
- Gradescope
If you run into any trouble accessing the above or have any questions, reach out to the instructors.
Git & GitHub¶
In this project and throughout the rest of this course, you will be expected to work extensively with Git and GitHub. Specifically for this project, you should be familiar with:
- Forking/cloning GitHub repositories
- Understanding general Git flow - pulling, branching, adding, committing, pushing, merging
- Creating GitHub Issues and using related features (labels, assignees, milestones)
- Creating GitHub Pull Requests and using related features (linking to issues)
- Creating GitHub Project Boards
If you are not familiar with any of these steps, you are highly recommended to first complete a short Github Exercise, as it will cover the standards we are expecting in this class (which you will be graded upon). Refer to the Resources & Documentation section if needed.
Getting Started¶
Repository Setup¶
Fork the class-specific repository into your personal GitHub account.
Warning
Even though this project is based off of an active open source project, we have made significant changes to ensure its suitability for our class. As such, be sure you are forking off of CMU-313/NodeBB and direct any questions to course staff. Do not contact the maintainers of NodeBB for assistance with your homework questions.
Ensure that GitHub Actions are enabled (click the green button under the "Actions" tab), then follow the below installation instructions based on your computer's operating system:
Once you have run NodeBB successfully, you should be able to navigate to http://localhost:4567 and see the main forum page. By default, NodeBB will be deployed to port 4567
on your machine. You may change this port number (e.g. to avoid conflict with another process running on your machine).
Warning
In this class, we do expect students to first try debugging errors on their own; this includes following stack traces, searching up error strings and unfamiliar outputs, etc. If you do get stuck, or if the process of installing and running NodeBB is taking you more than a few hours, stop and ask for help on Slack!
Take some time to click through the pages and explore the different features that NodeBB has to offer.
Analysis Tools¶
When working on an existing codebase, especially in a collaborative setting, we want to ensure that none of our changes introduce unexpected bugs or issues for other developers. To fulfill these goals, we often use different tools to help us evaluate our code. Luckily, NodeBB is already packaged with a number of neat tools!
Follow the Development Tools section in the repository README to run both the linter and testing tools provided by NodeBB on your computer. Without any changes to the repository, both tools should pass.
After the test suite finishes running, NodeBB will also generate a code coverage report. This report gives you measurements with regards to what percentage of the codebase is covered by the test suite. Open the index.html
file in the coverage
folder to see the full report.
Coverage Report (added 1/19/23)
As this is an existing codebase with a decently-sized test suite, you should expect to see a relatively high percentage of coverage, i.e. the majority of the bars/cells displayed should be green.
If you are seeing a lot of red bars, it may mean that the test suite was not run properly. Double-check that all of the tests passed and that there were no failures.
More on Analysis Tools
A linter is a tool that directly analyzes your source code for common errors. A test suite is a set of test cases that you write for a software program to show that it has some specified set of behaviors; our testing tool provides a framework to structure our test cases, runs the test suite, and generates a report of which tests pass/fail.
We will do a more in-depth exploration of analysis tools later in the course. For now, just know that these tools exist for you to use in evaluating your code.
Build Checkpoint (5 pts)¶
Upon completing the above steps, take screenshots of
- the home page of NodeBB, and
- the coverage report generated by the coverage tool
opened in your browser. Be sure the URL is clearly visible in both screenshots (i.e. localhost:4567
and the file path to your coverage file), so we can confirm that you have everything running locally.
Submit the two screenshots to Gradescope.
Onboarding¶
Now that you have explored the repository, the development team would like to give you an onboarding assignment.
Types types types! Driven by their programming language enthusiast, the team is currently undertaking a major code overhaul and converting the repository from JavaScript to TypeScript. This language is a superset of JavaScript and comes with many advantages, including better support for code editors, compile time error-checking and, of course, types!
As part of the efforts to integrate this new language into the repository, all future code will be written using TypeScript and the old files are translated as necessary. To prepare you for TypeScript development, the team would like you to contribute towards rewriting the codebase.
GitHub Issue (20 pts)¶
First, choose a single JavaScript file to translate and open a GitHub Issue in the class repository to declare which file you will be translating.
There are some restrictions on the .js
file that you can pick. Specifically, the file must:
- Be in the
src/
folder - Contain at least 50 lines of non-import statement code before you start translating it. Files like
src/api/index.js
andsrc/controllers/admin.js
are not allowed - Not be a file that someone else has already picked. We expect you to look through existing issues, if any, to avoid such duplication (thus, there is an incentive for you to start early!)
Title the task appropriately, such as Converting <file name> from JS to TS
, and mention the file name in the description. To prevent ambiguities between similarly-named files, be sure to use the full file path (src/../xx.js
) in the title and description.
Issue Guidelines
Issues titles should provide a high-level overview of what the problem is (e.g. "Navbar button UI bugs", "Unexpected registration validation errors"). Sometimes, issues are used to propose new features (e.g. "Add CSV export feature").
Issue descriptions should then elaborate on the title. For feature-level bugs, this may include providing information about how to reproduce the bug; for codebase-level changes, you can name specific files.
Then, assign yourself to the Issue by leaving a comment that says "I would like to work on this please!"
You should soon see another comment by the github-actions
bot informing you that you have been successfully assigned to this issue.
Why Bot Assignment?
You might be curious as to why we are using a GitHub bot instead of directly assigning yourself to the issue. As you aren’t officially recognized as a collaborator of CMU-313/NodeBB, GitHub adds some restrictions to your permissions for security purposes, including not being able to assign yourself to an issue. Hence, we are using a bot to work around these restrictions. This is similar to how you would request issues on an Open Source project!
For future projects, you will have full control over these GitHub features such as managing assignees, adding labels, creating milestones, and more.
GitHub Pull Request (35 pts)¶
Back in your own fork, create a feature branch and implement the change. You should start with the following steps:
- Install TypeScript
- If you chose a file named
xx.js
, create a new file calledxx.ts
in the same directory - Copy over the contents of the original file into this new file
- Make changes to
xx.ts
file as needed to translate the file into TypeScript - Run
npx tsc
to generate a compiled JavaScript file from your changes
Your changes must still pass both the linter and the test suite, so be sure to test your changes locally!
Dependencies on Untranslated Files
There will be some instances where your file may reference functions or variables from modules in other files that have not been translated yet. This may cause the linter to throw errors as these values will be of type any
. In those situations, and only in those situations, you may add the following comments to suppress the linter warnings:
// The next line calls a function in a module that has not been updated to TS yet
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
We will check your files to make sure you are only suppressing these warnings when absolutely necessary. For examples and more details, see the Additional TypeScript Background section under "Resources and Documentation" below.
As you work, be sure to periodically commit your changes. Your commit message(s) must clearly describe what is changing. If you’d like, you can also make use of branching and pull requests in your own repository to practice working with GitHub.
Branch and Commit Guidelines
Branch names should be short and provide a description of what you will be doing on that branch (e.g. "fix-header-sizing-issue", "fix-multiple-dialog-bug", "add-sorting-feature"). When working with others, you can also append your username to signal which branches are yours (e.g. "313ta/add-sorting-feature").
Commits should start with a verb and provide a description of what they are doing to the codebase (e.g. "Remove faulty condition from getCustomerDetails", "Fix failing CompositeTestCase", "Fix issue #21" ).
Once you are satisfied, open a pull request from your personal branch back to the class repository. Similar to the Issue, your PR title should mention the full path of the file you’ve changed. The PR body should summarize the changes you made and use one of the linking keywords to link the issue that you previously opened (e.g. adding resolves #313
will signal to GitHub that this PR resolves issue number 313).
Pull Request Guidelines
Pull request titles should describe what high-level changes were made to the codebase.
Pull request descriptions should describe what changes have been made in more detail and how the changes have been tested.
There will be automated checks that run on your pull request to ensure you meet the requirements of this assignment. Some of them take a while to run, so be sure to check on your pull request periodically to ensure that all these actions pass and everything is working properly!
Test Suite Failures
If the tests are failing on GitHub but work locally, it may be caused by server overload. Re-running the failing GitHub Action 1-2 times will resolve this.
If all of the actions have passed, you will see a green checkmark next to your pull request. This signals that you have completed the implementation aspect of this assignment! ✅
Written Assignment (40 pts)¶
After you have completed all of the above tasks, we will ask you some questions relevant to the NodeBB project and the course syllabus. Fill out and submit the HW1 Written Assignment available on Gradescope.
Grading¶
To receive full credit for this project, we expect:
- The correct usage of tools and technology, including Git, GitHub, and the repository-based tools
- A Gradescope submission of two screenshots showing a local running build of NodeBB and the coverage report within a browser
- A GitHub Issue with:
- A selected JavaScript file that follows our requirements above
- A meaningful title and description that includes the full path of the file
- A successful self-assignment as an assignee
- A GitHub Pull Request with:
- A meaningful title that includes the full path of the file
- A description body that describes the changes made and links the pull request to the issue
- Meaningful commit messages
- Appropriate usage of the eslint-ignore comment
- A green checkmark signaling that all checks have passed
- Answers to the Gradescope Written Assignment that demonstrate successful completion of the project and understanding of the benefits and limitations of software metrics in the context of NodeBB
Resources & Documentation¶
Below are some common resources to assist you with your completion of this project. If you get stuck, start by consulting the following materials; if you have any additional questions, the course staff will be available to answer questions via Slack and Office Hours.
Git & GitHub Documentation¶
Documentation for working with Git and GitHub:
We also have a simple Git-based exercise that you are highly recommeneded to complete before proceeding with this project.
TypeScript Documentation¶
The repository README contains links to different documentation material that you may find helpful in your development process. Particularly, you will want to focus on the documentation relating to JavaScript/TypeScript:
- TypeScript for New Programmers
- TypeScript for JavaScript Programmers
- JavaScript to TypeScript Translation
You will also find some sample translated TypeScript files within the repository. You can use these as guidance for your translation process:
Additional TypeScript Background¶
This section provides more context on how TypeScript is used for this project and when it is appropriate to suppress ESLint warnings in your translated TypeScript files.
As native JavaScript does not have any typing, by default, all functions/values/classes/modules that are not typed will be automatically given the any
type by TypeScript. Under default settings, this allows any valid JavaScript code to be run as TypeScript.
Using the any
type, however, will defeat the purpose of the various type-checking features TypeScript provides. As such, we’ve set our linter to check for strict typing and disallow the use of the any
type. For the most part, this should check that you explicitly type everything within your files and ensure that you are able to make the most out of TypeScript.
A limitation of this strictness is that there will be errors thrown when using non-translated JavaScript imports, which TypeScript will assume to have type any
. As an example from one of our sample translated files src/social.ts
:
// A module import from a non-translated JavaScript file database/index.js
import db from './database';
…
const activated = await db.getSetMembers('social:posts.activated');
Running the linter will give the following errors:
error Unsafe member access .getSetMembers on an `any` value
@typescript-eslint/no-unsafe-member-access
error Unsafe call of an `any` typed value
@typescript-eslint/no-unsafe-call
error Unsafe assignment of an `any` value
@typescript-eslint/no-unsafe-assignment
Let’s take a look at each error:
@typescript-eslint/no-unsafe-member-access
- we don’t know the typing of our imported moduledb
, so it is treated asany
. However, we don’t know if something of typeany
has a function calledgetSetMembers
, hence this is an unsafe member access@typescript-eslint/no-unsafe-call
- we don’t know the typing of the functiondb.getSetMembers
, and so it is treated asany
. We can not call a function of typeany
, sodb.getSetMembers('social:posts.activated')
is an unsafe call@typescript-eslint/no-unsafe-assignment
- we don’t know the return type ofdb.getSetMembers
, and so it is treated asany
. We can not assign something of typeany
to our variableactivated
The first two errors are dependent on us knowing the typing of db
and db.getSetMembers
. However, because we haven’t translated the database/index.js
file yet, we don’t have access to their typing information. In this case, it is okay to suppress the ESLint errors as they only arise from a lack of translation. We can do this by adding the following comments:
// The next line calls a function in a module that has not been updated to TS yet
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
const activated = await db.getSetMembers('social:posts.activated');
For the last error, even though we don’t have typing information provided by the db
module, we still want to make sure future uses of the activated
variable get properly typechecked. Checking the rest of the file reveals that activated
should be a string[]
type; we can also manually cross-reference the db.getSetMembers
function to check that this is the correct typing. Hence, it’s okay to cast the return value of this function call to string[]
, and our full solution looks like this:
// The next line calls a function in a module that has not been updated to TS yet
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-unsafe-call
const activated: string[] = await db.getSetMembers('social:posts.activated') as string[];
Installing Typing Packages¶
In some cases, if your file imports an npm
package (such as lodash
, nconf
, etc), you will need to install the typings for the package. To do this, run:
% npm install @types/[packagename] --save-dev
You should then see the @types/[packagename]
added to your package.json
file.
GitHub Actions Packages
To make sure your GitHub Actions also install the correct packages, you should copy the package.json
file to install/package.json
.


iOS 13.2.2 arrives to fix iPhone background process bug
Another update for the iPhone and iPad looks to fix a bug that made multitasking incredibly frustrating
by Henry BurrellApple has pushed iOS 13.2.2 to all compatible iPhones, continuing the string of point updates to iOS 13 since its launch on 19 September. We previously reported the iOS 13.3 developer beta could have included a fix for a bug that killed apps in the background, but it appears to have been addressed by Apple in this public 13.2.2 release.
It means iPhones will skip from iOS 13.2 to 13.2.2 – 13.2.1 was an exclusive software release for HomePod.
Many iPhone and iPad owners have been complaining that they found iOS 13.2 to be aggressively killing app processes in the background, seeing things like videos playing form the beginning when you return to the app. We noticed media controls defaulting back to the Music app after pausing a podcast, switching apps, and then trying to resume audio.
Here is the full change log for iOS 13.2.2:
We hope it goes some way to settling what has been an unusually rocky iOS launch for Apple with several bugs at each juncture.


Dealing with users gone bad…
We have all been there when someone that gets paid more than you do runs in and says “We need to remove User X from the network and lock them out of their PC to preserve evidence!!!”. If not, you will be.
So…aside from any 3rd party endpoint software you might have in that environment…what do you do? I have a list of steps, native Windows functions, that I have found helps eliminate avenues for User X’s continued use of ComputerX.
1. Disable User X’s Active Directory Account
This can be done in a number of ways but this post has a PowerShell tag so I recommend downloading Remote Server Administration Tools for your flavor of Windows if you don’t have it already. Then it is a simple matter of …
2. Delete All Cached Credentials
This will set the number of cached creds Windows is storing to 0 and erase the previous creds.
3. Change their BitLocker Key Remotely
This is a fun one. This will delete the user’s BitLocker key and save a new one that the user doesn’t know so they can’t unlock the drive after a reboot.
4. Shut down the remote system using any number of methods.
This is not meant to be an exhaustive list but rather a collection of practical considerations. Lemme know if this helps or you have other suggestions.


FROM DR. JUSTUS LEE THE MANAGER FOREIGN REMITTANCE DEPARTMENT, AFRICA DEVELOPMENT BANK(ADB) BURKINA FASO. DEAR PARTNER, (TOP SECRET) I AM DR. JUSTUS LEE, THE MANAGER IN CHARGE OF AUDITING AND ACCOUNTING SECTION OF AFRICA DEVELOPMENT BANK.AFRICA DEVELOPMENT BANK(ADB) OUAGADOUGOU BURKINA-FASO WEST AFRICA ,WITH DUE RESPECT AND REGARD. I HAVE DECIDED TO CONTACT YOU ON A BUSINESS TRANSACTION THAT WILL BE VERY BENEFICIAL TO BOTH OF US AT THE END OF THE TRANSACTION . DURING OUR INVESTIGATION AND AUDITING IN THIS BANK, MY DEPARTMENT CAME ACROSS A VERY HUGE SUM OF MONEY BELONGING TO A DECEASED PERSON MR.ANDREAS SCHRANNER WHO WHO DIED WITH HIS WIFE AND THEIR ONLY DAUGHTER ON JULY 2000 IN A PLANE CRASH AND THE FUND HAS BEEN DORMANT IN HIS ACCOUNT WITH THIS BANK WITHOUT ANY CLAIM OF THE FUND IN OUR CUSTODY EITHER FROM HIS FAMILY OR RELATION BEFORE OUR DISCOVERY TO THIS DEVELOPMENT. THE SAID AMOUNT WAS U.S $10.150M ((TEN MILLION ONE HUNDRED AND FIFTYTHOUSAND US DOLLOARS)). AS IT MAY INTEREST YOU TO KNOW, I GOT YOUR IMPRESSIVE INFORMATION THROUGH INTERNATION SEARCH IN BURKINA-FASO HERE IN OUAGADOUGOU BURKINA-FASO.   THIS IS THE ACTUAL REASON WHY IT WILL REQUIRE A SECOND PARTY OR FELLOW WHO WILL FORWARD CLAIMS AS THE NEXT OF KIN WITH AFFIDAVIT OF TRUST OF OATH TO THE BANK AND ALSO PRESENT A FOREIGN ACCOUNT WHERE HE WILL NEED THE MONEY TO BE RE-TRANSFERRED INTO ON HIS REQUEST AS IT MAY BE AFTER DUE VERIFICATION AND CLARIFICATION BY THE CORRESPONDENT BRANCH OF THE BANK WHERE THE WHOLE MONEY WILL BE REMITTED FROM TO YOUR OWN DESIGNATION BANK ACCOUNT.  ON SMOOTH CONCLUSION OF THIS TRANSACTION, YOU WILL BE ENTITLED TO 40% OF THE TOTAL SUM AS GRATIFICATION, WHILE 60% WILL BE FOR ME.    TRUSTING TO HEAR FROM YOU. YOU CAN CONTACT ME THROUGH THIS NUMBER(226 76440063).  ¡Miles de amigos con tus mismas aficiones! http://www.latinchat.com


Title
ID:
100500
Title:
Title
Description:
Description
Authors:
Author 1
Author 2
Author 3
Genres:
Genre 1
Genre 2
Genre 3
Comments
Add
user name
date
text comment bla bla bla


When you have a web app owned by several teams - very soon you will need to handle issues like: quality, ownership and autonomy. Using the "micro services architecture" hammer is not that trivia when your nail is a monolithic web application. How do you handle: session management, security, cross apps links and user experience ? In this talk i will describe how we did manage to solve most of the issues, and ended up with smaller web apps (aks microApps) running a modern technology, with full ownership and autonomy. Technical debt Why did you build it that way? For historical reasons. There is a lot of code that was written that could be replaced by a plugin or a configuration option. How to get from the mess to a nice MicroApplication system? Salami or Scrambled egg? Implementing a proxy in front of all the MicroApps that handles the authentication, logging, monitoring, etc. "Infrastructure as a service"


Here are defined all feed sources that will be used when generating feed digest for the credential. The list consists of personal blogs of all course participants. Also, you can add arbitary sources to be included in feed digest.
Are you sure you want to remove this feed source?
Note: This action CANNOT be undone!


Your don't love any city! Back to
home page.
World's best cities
Methodology
Your favorites
Contact
About me
The farther I travel, the closer I am to myself.


New culture - New Language - New life style.
I started with nothing in this country
As a college student, I started to have friends, met up people and began to work
Most of my time spent in Lab and Library. My friends and I worked, ate and played together through these years.
Working at PlayMotion which is a start up company as game designer
School: University of California, San Diego
Major: Electrical Engineering
Software: C, Java, Swift, Assembly, Verilog.
Hardware: Fundamental Circuit Design.
Fundamental Filters.


|
QuantumLibrary
|
Parallel execution engine used to run coroutines or IO tasks asynchronously. This class is the main entry point into the library. More...
#include <quantum_dispatcher.h>
Public Types | |
| using | ContextTag = ThreadContextTag |
Public Member Functions | |
| DEPRECATED | Dispatcher (int numCoroutineThreads=-1, int numIoThreads=5, bool pinCoroutineThreadsToCores=false) |
| Constructor. More... | |
| Dispatcher (const Configuration &config) | |
| Constructor. @oaram[in] config The configuration for the Quantum dispatcher. More... | |
| ~Dispatcher () | |
| Destructor. More... | |
| template<class RET = int, class FUNC , class ... ARGS> | |
| ThreadContextPtr< RET > | post (FUNC &&func, ARGS &&... args) |
| Post a coroutine to run asynchronously. More... | |
| template<class RET = int, class FUNC , class ... ARGS> | |
| ThreadContextPtr< RET > | post (int queueId, bool isHighPriority, FUNC &&func, ARGS &&... args) |
| Post a coroutine to run asynchronously on a specific queue (thread). More... | |
| template<class RET = int, class FUNC , class ... ARGS> | |
| ThreadContextPtr< RET > | postFirst (FUNC &&func, ARGS &&... args) |
| Post the first coroutine in a continuation chain to run asynchronously. More... | |
| template<class RET = int, class FUNC , class ... ARGS> | |
| ThreadContextPtr< RET > | postFirst (int queueId, bool isHighPriority, FUNC &&func, ARGS &&... args) |
| Post the first coroutine in a continuation chain to run asynchronously on a specific queue (thread). More... | |
| template<class RET = int, class FUNC , class ... ARGS> | |
| ThreadFuturePtr< RET > | postAsyncIo (FUNC &&func, ARGS &&... args) |
| Post a blocking IO (or long running) task to run asynchronously on the IO thread pool. More... | |
| template<class RET = int, class FUNC , class ... ARGS> | |
| ThreadFuturePtr< RET > | postAsyncIo (int queueId, bool isHighPriority, FUNC &&func, ARGS &&... args) |
| Post a blocking IO (or long running) task to run asynchronously on a specific thread in the IO thread pool. More... | |
| template<class RET = int, class INPUT_IT , class = Traits::IsInputIterator<INPUT_IT>> | |
| ThreadContextPtr< std::vector< RET > > | forEach (INPUT_IT first, INPUT_IT last, Functions::ForEachFunc< RET, INPUT_IT > func) |
| Applies the given unary function to all the elements in the range [first,last). This function runs in parallel. More... | |
| template<class RET = int, class INPUT_IT > | |
| ThreadContextPtr< std::vector< RET > > | forEach (INPUT_IT first, size_t num, Functions::ForEachFunc< RET, INPUT_IT > func) |
| Same as forEach() but takes a length as second argument in case INPUT_IT is not a random access iterator. More... | |
| template<class RET = int, class INPUT_IT , class = Traits::IsInputIterator<INPUT_IT>> | |
| ThreadContextPtr< std::vector< std::vector< RET > > > | forEachBatch (INPUT_IT first, INPUT_IT last, Functions::ForEachFunc< RET, INPUT_IT > func) |
| The batched version of forEach(). This function applies the given unary function to all the elements in the range [first,last). This function runs serially with respect to other functions in the same batch. More... | |
| template<class RET = int, class INPUT_IT > | |
| ThreadContextPtr< std::vector< std::vector< RET > > > | forEachBatch (INPUT_IT first, size_t num, Functions::ForEachFunc< RET, INPUT_IT > func) |
| Same as forEachBatch() but takes a length as second argument in case INPUT_IT is not a random access iterator. More... | |
| template<class KEY , class MAPPED_TYPE , class REDUCED_TYPE , class INPUT_IT , class = Traits::IsInputIterator<INPUT_IT>> | |
| ThreadContextPtr< std::map< KEY, REDUCED_TYPE > > | mapReduce (INPUT_IT first, INPUT_IT last, Functions::MapFunc< KEY, MAPPED_TYPE, INPUT_IT > mapper, Functions::ReduceFunc< KEY, MAPPED_TYPE, REDUCED_TYPE > reducer) |
| Implementation of map-reduce functionality. More... | |
| template<class KEY , class MAPPED_TYPE , class REDUCED_TYPE , class INPUT_IT > | |
| ThreadContextPtr< std::map< KEY, REDUCED_TYPE > > | mapReduce (INPUT_IT first, size_t num, Functions::MapFunc< KEY, MAPPED_TYPE, INPUT_IT > mapper, Functions::ReduceFunc< KEY, MAPPED_TYPE, REDUCED_TYPE > reducer) |
| Same as mapReduce() but takes a length as second argument in case INPUT_IT is not a random access iterator. More... | |
| template<class KEY , class MAPPED_TYPE , class REDUCED_TYPE , class INPUT_IT , class = Traits::IsInputIterator<INPUT_IT>> | |
| ThreadContextPtr< std::map< KEY, REDUCED_TYPE > > | mapReduceBatch (INPUT_IT first, INPUT_IT last, Functions::MapFunc< KEY, MAPPED_TYPE, INPUT_IT > mapper, Functions::ReduceFunc< KEY, MAPPED_TYPE, REDUCED_TYPE > reducer) |
| This version of mapReduce() runs both the mapper and the reducer functions in batches for improved performance. This should be used in the case where the functions are more CPU intensive with little or no IO. More... | |
| template<class KEY , class MAPPED_TYPE , class REDUCED_TYPE , class INPUT_IT > | |
| ThreadContextPtr< std::map< KEY, REDUCED_TYPE > > | mapReduceBatch (INPUT_IT first, size_t num, Functions::MapFunc< KEY, MAPPED_TYPE, INPUT_IT > mapper, Functions::ReduceFunc< KEY, MAPPED_TYPE, REDUCED_TYPE > reducer) |
| Same as mapReduceBatch() but takes a length as second argument in case INPUT_IT is not a random access iterator. More... | |
| void | terminate () final |
| Signal all threads to immediately terminate and exit. All other pending coroutines and IO tasks will not complete. Call this function for a fast shutdown of the dispatcher. More... | |
| size_t | size (IQueue::QueueType type=IQueue::QueueType::All, int queueId=(int) IQueue::QueueId::All) const |
| Returns the total number of queued tasks for the specified type and queue id. More... | |
| bool | empty (IQueue::QueueType type=IQueue::QueueType::All, int queueId=(int) IQueue::QueueId::All) const |
| Check if the specified type and queue id is empty (i.e. there are no running tasks) More... | |
| void | drain (std::chrono::milliseconds timeout=std::chrono::milliseconds::zero()) |
| Drains all queues on this dispatcher object. More... | |
| int | getNumCoroutineThreads () const |
| Returns the number of underlying coroutine threads as specified in the constructor. If -1 was passed than this number essentially indicates the number of cores. More... | |
| int | getNumIoThreads () const |
| Returns the number of underlying IO threads as specified in the constructor. More... | |
| const std::pair< int, int > & | getCoroQueueIdRangeForAny () const |
| Gets the range [minQueueId, maxQueueId] of coroutine queueIds covered by IQueue::QueueId::Any when using Dispatcher::post. More... | |
| QueueStatistics | stats (IQueue::QueueType type=IQueue::QueueType::All, int queueId=(int) IQueue::QueueId::All) |
| Returns a statistics object for the specified type and queue id. More... | |
| void | resetStats () |
| Resets all coroutine and IO queue counters. More... | |
| Public Member Functions inherited from Bloomberg::quantum::ITerminate | |
| virtual | ~ITerminate ()=default |
| Virtual destructor. This function is explicitly left empty. More... | |
Parallel execution engine used to run coroutines or IO tasks asynchronously. This class is the main entry point into the library.
|
inline |
Constructor.
This will build two thread pools, one used for running parallel coroutines and another used for running blocking IO tasks.
| [in] | numCoroutineThreads | Number of parallel threads running coroutines. -1 indicates one per core. |
| [in] | numIoThreads | Number of parallel threads running blocking IO calls. |
| [in] | pinCoroutineThreadsToCores | If set to true, it will pin all coroutine threads unto physical cores. provided numCoroutineThreads <= cores. |
|
explicit |
Constructor. @oaram[in] config The configuration for the Quantum dispatcher.
| Bloomberg::quantum::Dispatcher::~Dispatcher | ( | ) |
Destructor.
Destroys the task dispatcher object. This will wait until all coroutines complete, signal all worker threads (coroutine and IO) to exit and join them.
|
inline |
Drains all queues on this dispatcher object.
| [in] | timeout | Maximum time for this function to wait. Set to 0 to wait indefinitely until all queues drain. |
|
inline |
Check if the specified type and queue id is empty (i.e. there are no running tasks)
| [in] | type | The type of queue. |
| [in] | queueId | The queue number to query. Valid range is [0, numCoroutineThreads) for IQueue::QueueType::Coro, [0, numIoThreads) for IQueue::QueueType::IO and IQueue::QueueId::All for either. |
| ThreadContextPtr< std::vector< RET > > Bloomberg::quantum::Dispatcher::forEach | ( | INPUT_IT | first, |
| INPUT_IT | last, | ||
| Functions::ForEachFunc< RET, INPUT_IT > | func | ||
| ) |
Applies the given unary function to all the elements in the range [first,last). This function runs in parallel.
| RET | The return value of the unary function. |
| UNARY_FUNC | A unary function of type 'RET(*INPUT_IT)'. |
| InputIt | The type of iterator. @oaram[in] first The first element in the range. @oaram[in] last The last element in the range (exclusive). @oaram[in] func The unary function. |
| ThreadContextPtr< std::vector< RET > > Bloomberg::quantum::Dispatcher::forEach | ( | INPUT_IT | first, |
| size_t | num, | ||
| Functions::ForEachFunc< RET, INPUT_IT > | func | ||
| ) |
Same as forEach() but takes a length as second argument in case INPUT_IT is not a random access iterator.
| ThreadContextPtr< std::vector< std::vector< RET > > > Bloomberg::quantum::Dispatcher::forEachBatch | ( | INPUT_IT | first, |
| INPUT_IT | last, | ||
| Functions::ForEachFunc< RET, INPUT_IT > | func | ||
| ) |
The batched version of forEach(). This function applies the given unary function to all the elements in the range [first,last). This function runs serially with respect to other functions in the same batch.
| ThreadContextPtr< std::vector< std::vector< RET > > > Bloomberg::quantum::Dispatcher::forEachBatch | ( | INPUT_IT | first, |
| size_t | num, | ||
| Functions::ForEachFunc< RET, INPUT_IT > | func | ||
| ) |
Same as forEachBatch() but takes a length as second argument in case INPUT_IT is not a random access iterator.
|
inline |
Gets the range [minQueueId, maxQueueId] of coroutine queueIds covered by IQueue::QueueId::Any when using Dispatcher::post.
|
inline |
Returns the number of underlying coroutine threads as specified in the constructor. If -1 was passed than this number essentially indicates the number of cores.
|
inline |
Returns the number of underlying IO threads as specified in the constructor.
| ThreadContextPtr< std::map< KEY, REDUCED_TYPE > > Bloomberg::quantum::Dispatcher::mapReduce | ( | INPUT_IT | first, |
| INPUT_IT | last, | ||
| Functions::MapFunc< KEY, MAPPED_TYPE, INPUT_IT > | mapper, | ||
| Functions::ReduceFunc< KEY, MAPPED_TYPE, REDUCED_TYPE > | reducer | ||
| ) |
Implementation of map-reduce functionality.
| KEY | The KEY type used for mapping and reducing. |
| MAPPED_TYPE | The output type after a map operation. |
| REDUCED_TYPE | The output type after a reduce operation. |
| MAPPER_FUNC | The mapper function having the signature 'std::vector<std::pair<KEY,MAPPED_TYPE>>(*INPUT_IT)' |
| REDUCER_FUNC | The reducer function having the signature 'std::pair<KEY,REDUCED_TYPE>(std::pair<KEY, std::vector<MAPPED_TYPE>>&&)' |
| INPUT_IT | The iterator type. @oaram[in] first The start iterator to a list of items to be processed in the range [first,last). @oaram[in] last The end iterator to a list of items (not inclusive). @oaram[in] mapper The mapper function. @oaram[in] reducer The reducer function. |
| ThreadContextPtr< std::map< KEY, REDUCED_TYPE > > Bloomberg::quantum::Dispatcher::mapReduce | ( | INPUT_IT | first, |
| size_t | num, | ||
| Functions::MapFunc< KEY, MAPPED_TYPE, INPUT_IT > | mapper, | ||
| Functions::ReduceFunc< KEY, MAPPED_TYPE, REDUCED_TYPE > | reducer | ||
| ) |
Same as mapReduce() but takes a length as second argument in case INPUT_IT is not a random access iterator.
| ThreadContextPtr< std::map< KEY, REDUCED_TYPE > > Bloomberg::quantum::Dispatcher::mapReduceBatch | ( | INPUT_IT | first, |
| INPUT_IT | last, | ||
| Functions::MapFunc< KEY, MAPPED_TYPE, INPUT_IT > | mapper, | ||
| Functions::ReduceFunc< KEY, MAPPED_TYPE, REDUCED_TYPE > | reducer | ||
| ) |
This version of mapReduce() runs both the mapper and the reducer functions in batches for improved performance. This should be used in the case where the functions are more CPU intensive with little or no IO.
| ThreadContextPtr< std::map< KEY, REDUCED_TYPE > > Bloomberg::quantum::Dispatcher::mapReduceBatch | ( | INPUT_IT | first, |
| size_t | num, | ||
| Functions::MapFunc< KEY, MAPPED_TYPE, INPUT_IT > | mapper, | ||
| Functions::ReduceFunc< KEY, MAPPED_TYPE, REDUCED_TYPE > | reducer | ||
| ) |
Same as mapReduceBatch() but takes a length as second argument in case INPUT_IT is not a random access iterator.
| ThreadContextPtr< RET > Bloomberg::quantum::Dispatcher::post | ( | FUNC && | func, |
| ARGS &&... | args | ||
| ) |
Post a coroutine to run asynchronously.
This method will post the coroutine on any thread available. Typically it will pick one which has the smallest number of concurrent coroutines executing at the time of the post.
| RET | Type of future returned by this coroutine. |
| FUNC | Callable object type which will be wrapped in a coroutine. Can be a standalone function, a method, an std::function, a functor generated via std::bind or a lambda. The signature of the callable object must strictly be 'int f(CoroContext<RET>::Ptr, ...)'. |
| ARGS | Argument types passed to FUNC. |
| [in] | func | Callable object. |
| [in] | args | Variable list of arguments passed to the callable object. |
| ThreadContextPtr< RET > Bloomberg::quantum::Dispatcher::post | ( | int | queueId, |
| bool | isHighPriority, | ||
| FUNC && | func, | ||
| ARGS &&... | args | ||
| ) |
Post a coroutine to run asynchronously on a specific queue (thread).
| RET | Type of future returned by this coroutine. |
| FUNC | Callable object type which will be wrapped in a coroutine. Can be a standalone function, a method, an std::function, a functor generated via std::bind or a lambda. The signature of the callable object must strictly be 'int f(CoroContext<RET>::Ptr, ...)'. |
| ARGS | Argument types passed to FUNC. |
| [in] | queueId | Id of the queue where this coroutine should run. Note that the user can specify IQueue::QueueId::Any as a value, which is equivalent to running the simpler version of post() above. Valid range is [0, numCoroutineThreads) or IQueue::QueueId::Any. |
| [in] | isHighPriority | If set to true, the coroutine will be scheduled to run immediately after the currently executing coroutine on 'queueId' has completed or has yielded. |
| [in] | func | Callable object. |
| [in] | args | Variable list of arguments passed to the callable object. |
| ThreadFuturePtr< RET > Bloomberg::quantum::Dispatcher::postAsyncIo | ( | FUNC && | func, |
| ARGS &&... | args | ||
| ) |
Post a blocking IO (or long running) task to run asynchronously on the IO thread pool.
| RET | Type of future returned by this task. |
| FUNC | Callable object type. Can be a standalone function, a method, an std::function, a functor generated via std::bind or a lambda. The signature of the callable object must strictly be 'int f(ThreadPromise<RET>::Ptr, ...)'. |
| ARGS | Argument types passed to FUNC. |
| [in] | func | Callable object. |
| [in] | args | Variable list of arguments passed to the callable object. |
| ThreadFuturePtr< RET > Bloomberg::quantum::Dispatcher::postAsyncIo | ( | int | queueId, |
| bool | isHighPriority, | ||
| FUNC && | func, | ||
| ARGS &&... | args | ||
| ) |
Post a blocking IO (or long running) task to run asynchronously on a specific thread in the IO thread pool.
| RET | Type of future returned by this task. |
| FUNC | Callable object type. Can be a standalone function, a method, an std::function, a functor generated via std::bind or a lambda. The signature of the callable object must strictly be 'int f(ThreadPromise<RET>::Ptr, ...)'. |
| ARGS | Argument types passed to FUNC. |
| [in] | queueId | Id of the queue where this task should run. Note that the user can specify IQueue::QueueId::Any as a value, which is equivalent to running the simpler version of postAsyncIo() above. Valid range is [0, numCoroutineThreads) or IQueue::QueueId::Any. |
| [in] | isHighPriority | If set to true, the task will be scheduled to run immediately. |
| [in] | func | Callable object. |
| [in] | args | Variable list of arguments passed to the callable object. |
| ThreadContextPtr< RET > Bloomberg::quantum::Dispatcher::postFirst | ( | FUNC && | func, |
| ARGS &&... | args | ||
| ) |
Post the first coroutine in a continuation chain to run asynchronously.
| RET | Type of future returned by this coroutine. |
| FUNC | Callable object type which will be wrapped in a coroutine. Can be a standalone function, a method, an std::function, a functor generated via std::bind or a lambda. The signature of the callable object must strictly be 'int f(CoroContext<RET>::Ptr, ...)'. |
| ARGS | Argument types passed to FUNC. |
| [in] | func | Callable object. |
| [in] | args | Variable list of arguments passed to the callable object. |
| ThreadContextPtr< RET > Bloomberg::quantum::Dispatcher::postFirst | ( | int | queueId, |
| bool | isHighPriority, | ||
| FUNC && | func, | ||
| ARGS &&... | args | ||
| ) |
Post the first coroutine in a continuation chain to run asynchronously on a specific queue (thread).
| RET | Type of future returned by this coroutine. |
| FUNC | Callable object type which will be wrapped in a coroutine. Can be a standalone function, a method, an std::function, a functor generated via std::bind or a lambda. The signature of the callable object must strictly be 'int f(CoroContext<RET>::Ptr, ...)'. |
| ARGS | Argument types passed to FUNC. |
| [in] | queueId | Id of the queue where this coroutine should run. Note that the user can specify IQueue::QueueId::Any as a value, which is equivalent to running the simpler version of post() above. Valid range is [0, numCoroutineThreads) or IQueue::QueueId::Any. |
| [in] | isHighPriority | If set to true, the coroutine will be scheduled to run immediately after the currently executing coroutine on 'queueId' has completed or has yielded. |
| [in] | func | Callable object. |
| [in] | args | Variable list of arguments passed to the callable object. |
|
inline |
Resets all coroutine and IO queue counters.
|
inline |
Returns the total number of queued tasks for the specified type and queue id.
| [in] | type | The type of queue. |
| [in] | queueId | The queue number to query. Valid range is [0, numCoroutineThreads) for IQueue::QueueType::Coro, [0, numIoThreads) for IQueue::QueueType::IO and IQueue::QueueId::All for either. |
|
inline |
Returns a statistics object for the specified type and queue id.
| [in] | type | The type of queue. |
| [in] | queueId | The queue number to query. Valid range is [0, numCoroutineThreads) for IQueue::QueueType::Coro, [0, numIoThreads) for IQueue::QueueType::IO and IQueue::QueueId::All for either. |
|
inlinefinalvirtual |
Signal all threads to immediately terminate and exit. All other pending coroutines and IO tasks will not complete. Call this function for a fast shutdown of the dispatcher.
Implements Bloomberg::quantum::ITerminate.


Plugin Information |
|---|
View CloudBees Docker Build and Publish on the plugin site for more information. |
This plugin provides the ability to build projects with a Dockerfile, and publish the resultant tagged image (repo) to the docker registry. Docs are here.
If you want to build and push your Docker based project to the docker registry (including private repos), then you are in luck!
This is an early version - build @michaelneale of @cloudbees - ask me if you have questions.
Features:
- Only a Dockerfile needed to build your project
- Publish to docker index/registry - INCLUDING PRIVATE REPOS/IMAGES
- nocache option (for rebuild of all Dockerfile steps)
- publish option
- manage registry credentials for private and public repos
- tag the image built - use any Jenkins env. variables.
Dockerfile as buildfile
A Dockerfile is a convenient way to express build instructions. This plugin will use the Dockerfile in the workspace (possibly previously checked out from git) and will invoke docker build to create the Docker image. The result can be automatically uploaded to the Docker Registry or a private registry.
As the Beatles song, all you need is Dockerfile, and love. If you have a Dockerfile in the root of your project, then no further configuration is needed.
How to use
Warning: the instructions below seem to cover the 0.x version of the plugin. Current documentation is here.
Firstly, ensure you have docker running (if you are running with a slave, ensure the slave can run docker) - and that Jenkins can run docker commands.
Setup a build of any type - with a CloudBees Docker Build and Publish build step. You can use the example under src/test/example to build a very simple busybox based image, and push it to jenkinsci/docker-build-and-publish-example.
The usual Docker build caching mechanism applies - and you can choose to publish, or not, the resultant image, configured under Advanced options.
Builds will be decorated with the repository name (and tag) of the build images:
You can supply multiple tags for an image separated by commas. The latest tag is automatically applied to image - if you do not want this check the Do not tag this build as latest checkbox.
Why use a Dockerfile
Defining your build as a Dockerfile means that it will run in a consistent linux environment, no matter where the build is run. You also end up with an image (in a repository, possibly pushed to a registry) that can then be deployed - the exact same image you built.
Dockerfiles can also help speed up builds. If there has been no change relative to a build instruction in the Dockerfile - then a cached version of that portion of the build can be used (this is a fundamental feature of docker)
More info
See more on the GitHub readme:
Attachments:
build-config.png (image/png)
build-label.png (image/png)
Screen Shot 2015-09-17 at 9.26.47 AM.png (image/png)


Node.js Simple Router
Yet another minimalistic router for node.js
Install
From Node Package Manager:
npm install node-simple-router
or from source:
git clone git://github.com/sandy98/node-simple-router.git
Purpose
Designed to provide routes to barebones node http server, Sinatra style (or Express.js router, for that matter) staying out of your way for the rest.
Main target: restful APIs for single page applications.
Source main file - router.coffee - and testing utility - test_router.coffee - are coffeescript source files. Should you prefer to work with javascript, just simply compile them (i.e. coffee -c router.coffee) provided you have installed coffee-script, which is as simple as
sudo npm install coffee-script -g
Basic Usage
# CoffeeScript version
# Assumes usual installation through npm.
Router = require 'node-simple-router'
# Alternative: assumes router.js - or router.coffee - is located at the current working directory.
#Router = require('./router')
var http = require('http')
router = Router()
router.get '/', (request, response) ->
response.end 'Home page'
router.get '/hello/:who', (request, response) ->
response.end "Hello, #{request.params.who}"
server = http.createServer router
server.listen 3000
or, for the unlikely case you didn't yet discover/fall in love with coffeescript, the javascript version:
// Javascript version
// Assumes usual installation through npm.
var Router = require('node-simple-router')
// Alternative: assumes router.js is located at the current working directory.
//var Router = require('./router')
var http = require('http')
var router = Router();
router.get('/', function (request, response) {
response.end('Home page');})
router.get('/hello/:who', function(request, response) {
response.end("Hello, " + request.params.who);})
server = http.createServer(router)
server.listen(3000)
Changelog
< 0.2.4 All the basic stuff
2012-09-07: v0.2.4 Added CGI support
Currently the cgi dispatcher relies - as it's supposed to be - on the cgi process to provide the correct headers. Also, post and get - summed up in 'body' - must be readed by the cgi process via std input and converted to json object by whatever means the cgi implementation provides. For instance, a python example could be implemented along the lines:
import json, sys
body = json.loads(sys.stdin.readline())
for key in body:
print "%s = %s" % (key, body[key])
2013-03-25: v0.2.5 Added mimetypes xml and svg to the list of recognized types
2013-04-01: v0.2.6 Added compile to js tool 'compile.sh'
2013-04-02: v0.2.7 Added mk-server to the bin directory.
This is a tiny tool that will create a brand new node-simple-router powered server to the working directory. It can be invoked with no params, producing an executable server.coffee file. Should you prefer getting a javascript version of the server, you must invoke it like so: mk-server js. This will produce server.js.
It's worth noting that in order for this to be useful, you should install node-simple-router globally sudo npm install -g node-simple-router
2013-04-03: v0.3.0 node-simple-router becomes able to handle form uploads.
Or, to be precise, node-simple-router aka nsr has earned the ability to handle multipart/form-data
This can be seen as an important update, hence the minor version leap (0.2 to 0.3)
There is an example of the way to use it to handle uploads that may be found in test/uploader/server.coffee (or server.js, for that matter), following the route "/upload". A simplified version follows:
router.post "/upload", (req, res) ->
res.writeHead(200, {'Content-type': 'text/html'})
if req.post['multipart-data']
for part in req.post['multipart-data']
for key, val of part
res.write "#{key} = #{val}
" unless ((key is 'fileData') and part.fileName)
if part.fileName
fullname = "#{__dirname}/public/uploads/#{part.fileName}"
if part.contentType.indexOf('text') >= 0
fs.writeFileSync fullname, part.fileData
else
fs.writeFileSync fullname, part.fileData, 'binary'
res.write '
'
if part.contentType.indexOf('image') >= 0
res.write ""
else
res.write "
#{part.fileData}
"
res.write '
'
res.write "
"
res.end ""
Essentially, what you get is an array labeled 'multipart-data' added to the body of the request. Each of its members will have some, or all of the following properties (some may lack "filename")
-
contentDisposition
Just for reference. This will always be "form-data"
-
fieldName
The name of the input element that originated the current member of the array.
-
fileName
This will only exist if the originating field is <input type="file">
-
fileData
This and the following may be somewhat misleading names, because as has been noted the object may not be a file. Regardless, it contains whatever was in the originating field. If this was a text input type, it will be the contents input by the user. If it was a file, it will be its contents. Its worth noting that in order for this to work accurately, the request input has been previously determined as binary by the router, like so:
req.setEncoding('binary')
-
fileLen
Length of fileData
-
contentType
Mimetype of fileData, as sent by the browser. Things like 'text/plain', 'image/jpeg', etc
2013-07-27: v0.3.5 Correction for paths which have escaped characters.
2013-08-02: v0.3.6 Added default favicon. Fixed cgi-bin.
2013-08-03: v0.4.1 Improved cgi-bin. Looks like it's now really usable. Now FCGI to come.
2013-08-04: v0.4.5 Further improvement for cgi-bin, mainly PHP related. Some issues remain as regards to PHP, though.
2013-08-12: v0.4.7 CGI works smoothly now. SCGI support - router.scgi_pass - added and working fine.
2013-12-28: v0.4.9-2 Fixes nil error when request method is not known/handled.
2013-12-29: v0.4.9-3 As a result of the former, now NSR handles router.any, for example:
router.any("/doit", function (request, response) {});
will handle any incoming request to "/doit" uri, regardless the request method.
2014-01-10: v0.4.9-4 Improved server generated by mk-server utility.
Complementary topics
I) Default options
-
logging: true
Turns off logging if defined false
-
log: console.log
Defines console.log as default logging output.
-
serve_static: true
Allows serving static content.
-
static_route: "#{__dirname}/public"
Defines root directory for static contents
-
list_dir: true
Allows/disallows directory listings
Example:
//Disallows logging and directory listing, uses '/static' for static contents,
//defaults remaining options
var router = Router({logging: false, list_dir: false, static_route: __dirname + '/static'})
II) Retrieving get/post data
Request get data may be retrieved from request.get, an object in JSON format
Request post data is included, also in JSON format, in request.post, although in this case, if data came in an unrecognized format, it will be retrieved as raw data, without any conversion.
Finally, request.get and request.post are joined in request.body, so if you don't care how the data got to the server, you can use that.
III) Getting parameters from urls
Uses a similar convention as Express.js: url segment preceded by a colon is treated as a parameter, as shown below
router.get('/users/:id', function(request, response) {
response.end("User: " + getUserById(request.params.id).fullName);})
IV) Todo list
- Making directory listing actually work
- Preparing a nice template for directory listing.
- Managing file uploads.
Final note
Was this necessary?
Probably not.
But then again, there are a couple of reasons that I think make it worth, and perhaps, useful to someone who shares these.
For one thing, reinventing the wheel is not only fun, it's frequently highly educative.
Second, there are quite a bunch of routing solutions for node.js, but I found the ones that come bundled with node frameworks, although in most cases high quality and performant, also in many cases just a bit too much stuffed with features that either I didn't need or was unable to manage/tweak to my projects needs, hence the decision to roll my own, mainly aimed to serve as a lightweight component for a restful API.
Last but not least, I wanted to share the fun.
Last minute note: Guaycuru web server, initially included as a test of the static resource serving capabilities of this router, is no longer present in current distribution. Instead, you can get it here or install it by means of npm
License
(The MIT License)
Copyright (c) 2012 Ernesto Savoretti<EMAIL_ADDRESS>Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.


Please provide a name to identify the user
Continue >Select the users you would like to delete.
| Delete? | Name | ID |
| {{r.name}} | {{r.id}} |
The user has been saved and may now be searched.
Continue >Selected user(s) have been deleted.
Continue >Best match: {{bestMatchName}}
| ID | Name | % Match | % Confidence | Distance |
| {{r.id}} | {{r.name}} | {{Math.round(100*r.propMatch)}} | {{Math.round(100*r.confidence)}} | {{r.dist}} |


{% extends "trix_student/base.django.html" %} {% load i18n %} {% block title %}{% trans "Frontpage" %}{% endblock title %} {% block content %}
{% trans "Trix is a teaching platform to help you work more systematic towards your goal, resulting in a better learning outcome." %}
{% blocktrans %}Trix acts as an assignments wiki, where educational authors provide you with a selection of assignments. Here you can study and track your progress as you advance through your learning goals.{% endblocktrans %}
{% blocktrans %}Trix follows a simple tag structure where assignments are marked with informative tags. This along with filtering capabilities ensures a tailored selection of assignments perfectly suited to your personal level. Trix is a day to day learning tool as well as a preparatory tool for focused learning.{% endblocktrans %}
{% trans "For more information" %}, {% trans "read the getting started guide" %}.
{{ course.description }}


{{template "header" .}}
The MCC combined with the MNC code are used in mobile networks (2G/3G/4G etc.) to indentify a mobile network and the operator of that network.
ITU - The International Telecommunication Union is administering and allocating the MCC∕MNC codes. The MCC/MNC mappings to mobile network operators on this site is extracted from the ITU service publications and updates
This site is not affilated with ITU or any other organizations.


--- layout: default title: Insert title here meta_description: Insert Description here current: home ---
I am a web designer based in Glasgow. I came to this career from a what felt like a lifetime working as a chef in high profile establishments. I learned to work with reliability, creativity and attention to detail. I'm well travelled, but, now back living here in Glasgow and loving every minute of being a freelance web developer & designer!
I offer a range of services that can help your business succeed online.
From our first meeting over a cup of coffee, to getting your site on the internet, I provide professional and effective web development. Fancy a chat about an update for your website? Get in contact to start planning.
 I can work a bit of magic on Photoshop to create the best ideas for your business. If you have your own designs, I can create a story board to show you how your finished product might look.
Search engine optimisation and social media branding; these are just a couple of ways that I can help your business take off. Whether starting from scratch or just looking for a wee update, linking your pages to social media and Google can be profitable for any business.
From our first meeting over a cup of coffee, to getting your site on the internet, I provide professional and effective web development. Fancy a chat about an update for your website? Get in contact to start planning.


Now you know how to let the animation move left, right, top and down as well as diagonally. How about you try to let the move in a rectangle clockwise. So this is what you need to achieve:
Move right 400px
Move down 200px
Move left 400px
Then move back up 200px
Each move will take 2 seconds to run.
You may have to change the timing to {startDelay: 2, duration: 2} from '2' at certain places. Note that startDelay starts counting from the start of the animation.
new Animation(document.querySelector("#a"), {left: "400px"}, 2);
new Animation(document.querySelector("#a"), {top: "200px"},
{startDelay: 2, duration: 2});
new Animation(document.querySelector("#a"), {left: "0px"},
{startDelay: 4, duration: 2});
new Animation(document.querySelector("#a"), {top: "0px"},
{startDelay: 6, duration: 2});


@Beta var variationMode: VariationMode
the VariationMode indicating how to display variations
variationMode - the VariationMode indicating how to display variations
variationMode