Course Policies
Attendance
If you are registered for 15-388 or 15-688 Section A, you are expected to attend each lecture in-person. Your attendance score depends on how many in-class polls you answered. These in-class polls will be posted on Diderot and will only be open for a few minutes during class.
If you are registered for 15-688 Section B (i.e. the no-meet/online section), you must watch each lecture video and answer a related quiz. The lecture video will be posted online shortly after the lecture and you have one week to watch it. A quiz will be posted soon after the lecture and you have one week from the time the quiz is opened to answer it.
If you are a 15-688 Section B student who wishes to attend any lecture, you can, subject to seat availability. If you complete the in-class poll you will get attendance credit for that lecture and you do not need to watch that lecture video or answer the related quiz.
 If you do not complete the in-class poll, you can get partial credit by watching the lecture video and answering the quiz.
Lecture videos
You can find the lecture videos here, uploaded soon after lectures. Note that the videos are posted twice: one link for public (i.e. non-CMU users) and one for CMU users that allows us to track your participation. To ensure that we record your participation, you must use this link or the links on the Lecture page.
Changing Sections
You may be able to do this over SIO; if you can do that, that is preferable.
If that does not work, fill out a copy of the CMU Course Late Add Form and bring it to a lecture to get the instructor’s signature. (You’ll need to additional signatures to complete and submit the form.)

- You must list your collaborations for each question or part in a comment in the corresponding answer cell. (For example,
# Jane explained to me what is asked in Question 3.4
)
Collaboration not in accordance with this policy will be handled severely, in accordance with the Carnegie Mellon University Policy on Academic Integrity.
Submission
These policies apply to all submitted work.

Assignments must be submitted by 11:59pm on the due date, according to the Diderot server timestamp (or Google’s email timestamp, if submitted by email). There is no grace period given for assignments submitted late, even by a few seconds.
Late Days
Each student is permitted 5 late days they may use over the course of the semester, using no more than 2 late days on each assignment. After the two late days on each assignment, or after you have used the five late days, you will receive zero credit for the assignment. Late days may only be used for the homework assignments, not for the tutorial or final project.
Server Error
If there is an error with the server, you may send your assignment to Gaurav Manek with the subject line pds-submit
. These emails are automatically processed; ensure the subject text matches exactly. We will compare the email and the server submission timestamps and grade the latest version before the assignment ending time.
Grading Errors
Our homeworks are graded automatically; if you suspect there is an error then please notify the course staff via Diderot (not email).
Special Circumstances
We understand that circumstances beyond your control may prevent you from being able to complete coursework. If this happens, please contact the Office of the Dean of Students, who are best suited to supporting you in a time of crisis.
With a note from the Dean’s office, we can adjust course deadlines to help you through your trying times. You must inform us (by email) of your intention to seek a Dean’s note as early as possible; you do not need to provide us with a reason.
Deadline adjustments are suitable when a few days is enough; if you need to take more time away, discuss your options with an academic dean.
Auditing
To audit the course, complete this form and bring it to a lecture for Prof. Kolter to sign. If you are not in the Pittsburgh campus, fill in your section, scan, and email it to<EMAIL_ADDRESS>.
To pass the class when auditing, you must receive a grade of at least 50% of the total points in at least 4 of the 5 homework assignments. Audits for the undergrad version may not be offered if we do not have sufficient room in the lectures. The tutorial, final project, and attendance do not count towards your grade, but you can feel free to submit the tutorial or project and attend class. For the final project, you cannot work with students who are taking the course for credit.


All about Backbone
Click Start to route to #routeTo/start
Running :
Stopped :
Destroyed :
Time Left :


B. Faso: 18 jihadists, police officer killed during attack
Eighteen jihadists and a police officer were killed during a response to an attack in Northern Burkina on Wednesday, a statement from the police headquarters said.
The attack was targeted at the police squadron based in Arbinda in the Soum Province, it said.
The statement added that a prompt response from the police led to the death of 18 terrorists and a police officer.
Seven of the officers were injured with two seriously injured receiving treatment in the capital, Ouagadougou .
Earlier this month, an attack on a convoy by Canadian mining firm, semafo killed 38 people.
Burkina Faso has been the scene of regular jihadist attacks since the first quarter of 2015.
AFP


Warehouse Chief Klump:
Hey, I thought you were checking your cards! Where did you go? Your cards are untouched!
Check all 5 of them and then show them to me.
|
Cell1
|
Cell2
|
Cell3
|
Cell4
|
Cell5
|
Put the first card face up.

Put the third card face up.
Put the fourth card face up.
Put the fifth card face up.


New status update on the "{{ title }}" report you subscribed to
This report was generated by rb status © 1997 - 2020 Raybeam, Inc. All Rights Reserved


|
Break Out Project, By Luis Bechara
POST MORTEM: Getting the game was a long process of figuring out c++ and SDL among other things such as understanding patterns. However I am satisfied of the initial result as a close-to-be MVP, it can be improved on futher by: 1- Encapsoluting all the game logic inside respective objects instead of the main fuction. 2- Create a SceneManager to load each instance as a child of a GameObject class. 3- Encasoluting all the Draw and SDL behaivior in a Renderer class that knows how the draw each object on screen to follow a more conventional MVC. also the game can be extended as follows. 1- writting more levels files. 2- enabling progression between levels and more clear game states. 3- enabling more localization files
|


"SOSTHENES "safe in strength, the chief ruler of the synagogue at Corinth, who was seized and beaten by the mob in the presence of Gallio, the Roman governor, when he refused to proceed against Paul at the instigation of the Jews (Acts 18:12-17). The motives of this assault against Sosthenes are not recorded, nor is it mentioned whether it was made by Greeks or Romans. Some identify him, but without sufficient grounds, with one whom Paul calls “Sosthenes our brother,” a convert to the faith (1 Corinthians 1:1).
"SOSTHENES "safe in strength, the chief ruler of the synagogue at Corinth, who was seized and beaten by the mob in the presence of Gallio, the Roman governor, when he refused to proceed against Paul at the instigation of the Jews (Acts 18:12-17). The motives of this assault against Sosthenes are not recorded, nor is it mentioned whether it was made by Greeks or Romans. Some identify him, but without sufficient grounds, with one whom Paul calls “Sosthenes our brother,” a convert to the faith (1 Corinthians 1:1).


Home
Gallery
Projects
Soil Moisture Control
API Fun
About
Resume
Contact
⚓
Washington State
1 / 5
2 / 5
3 / 5
4 / 5
5 / 5
❮
❯


Positive growth prospects in Singapore – UOB
by Pablo PiovanoBarnabas Gan, Economist at UOB Group, reviewed the growth outlook for Singapore.
Key Quotes
“Singapore’s third quarter economic growth expanded by a better-than-expected rate of 0.5% y/y (+2.1% q/q saar). With a positive q/q growth rate, Singapore has officially avoided a technical recession”.
“Growth is underpinned by a sustained expansion in the construction sector, while most services industries (except Wholesale & Retail and Transportation & Storage) grew when compared to the previous year. Manufacturing continued to drag on growth with a 1.7% y/y contraction, but much improved from the preliminary estimate of -3.5%, contributing most to the upward revision”.
“Our growth outlook is kept at 0.5% and 1.5% in 2019 and 2020, respectively. This is in line with official estimates whereby 2019’s growth rate has been revised higher to 0.5 – 1.0%, while MTI pencils 2020 growth at 0.5 – 2.5%”.
“We expect the Monetary Authority of Singapore to keep its monetary policy parameters unchanged at the next monetary MPS meeting in April 2020. This means keeping the slope (currently perceived at 0.5%), band width (perceived at 2.0%) and centering unchanged”.


--- layout: page title: 404 permalink: /404.html --- No content here, sorry. Would you like to go home?


Both players start with the same amount of time to think. Each player's timer runs until they play their turn. When a player's time runs out, they lose.
Feel free to use this clock with more complex rules.
Press Spacebar or click swap button after each play. While timer is stopped, click to modify time.
Designed by Antriksh Yadav@AntrikshyAntrikshy.com


--- layout: post title: Facebook Girl Users are being sold by an iPhone app unknowingly - you might be one of them! permalink: facebook-girl-users-are-being-sold-by-an-iphone-app-unknowingly-you-might-be-one-of-them/ date: 2012-04-03 15:27:41.000000000 +08:00 categories: - privacy - social networking tags: [] status: publish type: post published: true meta: _oembed_c5a97cb30f2cafb6534de0f647ce3d0d: '{{unknown}}' _yoast_wpseo_meta-robots-adv: none _yoast_wpseo_sitemap-include: '-' _yoast_wpseo_sitemap-prio: '-' _yoast_wpseo_canonical: '' _yoast_wpseo_redirect: '' _yoast_wpseo_meta-robots-nofollow: '0' _yoast_wpseo_focuskw: '' _yoast_wpseo_title: '' _yoast_wpseo_metadesc: '' _yoast_wpseo_meta-robots-noindex: '0' _edit_last: '2' OGP: "a:20:{s:5:\"title\";s:0:\"\";s:4:\"type\";s:0:\"\";s:5:\"image\";s:0:\"\";s:11:\"description\";s:273:\"This application collects data about "girls" in the Facebook, Twitter etc. including their location, pictures and other data that is publicly available whether it is from the post, tweets, profile and etc.\r\nBut, to clarify the act, what the app is doing is legal.\";s:9:\"fb:admins\";s:0:\"\";s:9:\"fb:app_id\";s:0:\"\";s:14:\"street-address\";s:0:\"\";s:4:\"city\";s:0:\"\";s:11:\"postal-code\";s:0:\"\";s:12:\"country-name\";s:0:\"\";s:5:\"email\";s:0:\"\";s:12:\"phone_number\";s:0:\"\";s:10:\"fax_number\";s:0:\"\";s:5:\"video\";s:0:\"\";s:10:\"videowidth\";s:0:\"\";s:11:\"videoheight\";s:0:\"\";s:9:\"videotype\";s:0:\"\";s:6:\"locale\";s:0:\"\";s:18:\"locale-alternative\";s:0:\"\";s:3:\"url\";s:0:\"\";}" _oembed_13483de6f66b84c45e6466851dfee086: '{{unknown}}' _yoast_wpseo_linkdex: '0' _oembed_b47f314d026bcd591fd62ffb9a558a71: '{{unknown}}' _oembed_3b5e3b1c99d1449e3de9850e30a57251: '{{unknown}}' _oembed_f95720413d38b3b32c41303e6c63ab58: '{{unknown}}' _oembed_8c3a843dcf226eda135ec6bcf3786f17: '{{unknown}}' dsq_thread_id: '3176303430' cleaned: true ---
There is a big issue exploded on the internet when online privacy advocates questioned the "purpose" of the iPhone app:
Girls Around Me
http://www.girlsaround.me/
This application collects data about "girls" in the Facebook, Twitter etc. including their location, pictures and other data that is publicly available whether it is from the post, tweets, profile and etc.
But, to clarify the act, what the app is doing is legal.
The problem is, most of the users, specially girls of social networking sites were unaware of the things they publish on the web. This includes the bikini pictures you have on your summer vacation, your personal pictures on your room etc.
As those pictures are being gathered by the www.girlsaround.me site, they are being sold as the primary feature of the app, so that anyone who has that app in their iPhone can trace which girl is the nearest to your location -- a perfect tool for 50 year old man who is on hunt for young girls.
As the legalities of the usage of the data is not really off-the-rule, Since only those publicly available data are being gathered, this scenario provokes each every person (specially girls) who uses social networking sites to be careful of what they are posting on the internet, specially the privacy settings involved with those posts.


{% extends "base.html" %} {% block title %}Run Pipeline{% endblock %} {% block head %} {{ super() }} {% endblock %} {% block content %}
| Cancel | Pipeline ID | Owner | Submission time | State | Start Time | End Time | Execution Time (min) | Execution Error Text | Query Start Time | Query End Time | Pts to Process | Email address for status updates |
|---|---|---|---|---|---|---|---|---|---|---|---|---|
| {% if pipeline.execution_status == "queued" or pipeline.execution_status == "running" %} {% elif pipeline.execution_status == "completed" %} {% else %} {% endif %} | {{ pipeline.id }} | {{ pipeline.researcher.username }} | {{ pipeline.pipeline_submission_timestamp }} | {{ pipeline.execution_status }} | {{ pipeline.execution_start_datetime }} | {{ pipeline.execution_end_datetime }} | {{ pipeline.execution_time_minutes }} | {{ pipeline.execution_error_text }} | {{ pipeline.query_start_datetime }} | {{ pipeline.query_end_datetime }} | {{ pipeline.participants }} | {{ pipeline.email_address_list }} |


// Second call has no "usagestr" defined workaround now is to check for existing key and not
// overwriting it.
if not self.usagestrings.has_key(name):
self.usagestrings[name] = usagestr
return tagfunction
// Second call has no "usagestr" defined workaround now is to check for existing key and not
// overwriting it.
if name not in self.usagestrings:
self.usagestrings[name] = usagestr
return tagfunction


Judges 13:10
And the woman made haste, and ran, and showed her husband, and said unto him, Behold, the man hath appeared unto me, that came unto me the other day.


Hi Guys!
First time learn Codding I can't understand anything like a kid for the first time attend in the class kindergarten, how funny. What I did? I just listening tutor explain something new for me, seeing friends project, how they works on computer, what they types, why they uses many formula, what the result and many more. Those made me amazed what incredible tecnology is.
Just using one Laptop and smartphone as modem to connecting Internet. We can write anything we wants such as recipes, articles, news about something occurs around you or maybe share your journey in live to other people in a website with your own style. That was my experience faced new thing in front of me, sometimes I got scared, keep arguing between brain and feeling and then I'm stuck in curious feeling!
Tips to Understand New Things
"I hear and I forget. I see and I remember. I do and I understand"
- Look
Keep your eyes focus on what are people doing.
- Listen
Keep your mouth in silent mode. Don't make any noise and distrub them.
- Read
What we look in the same time we also read. Push away bored feeling for read anything. As Abraham Linclon said "A capacity and taste for reading gives access to whatever has already been discovered by others."
- Try
After we look something new, listen people speak and read. what we have to do is Try! Try everything looks good for yourself. If I can do, why not?
- Ask
Accumulate learning by study, understand what you learn by questioning. Be Brave to ask anything what you don't know yet or what are made you confused.
- Try again
Don't give up easyly, we should keep in try and learning. Anthony J. D'Angelo said in The College Blue Book "Develop a passion for learning. If you do, you will never cease to grow"
That's all tips and trick from me. I wish what I share is helpfull and give you easy life. Thanks for coming to my blog. ^^


Vehicle Selection Page
ADD VEHICLES
Vehicle 1 ID:
Add Vehicle 1
Vehicle 2 ID:
Add Vehicle 2
Vehicle 3 ID:
Add Vehicle 3


SpaceX’s rockets
Space Exploration Technologies Corp., trading as SpaceX, is a private American aerospace manufacturer and space transportation services company headquartered in Hawthorne, California. It was founded in 2002 by Elon Musk with the goal of reducing space transportation costs to enable the colonization of Mars. SpaceX has developed several launch vehicles and the Dragon spacecraft.
Rockets
Roadster
Dragons


Email Alerts Security |
Top |
Users can apply administrative security rights on each email alerts. Security can be applied on a Role and/or User level. -Select an Alert option only to allow the user to see the alert type under Options section. User still has the option to subscribe to the alert: -Select both the Alert option and the Force option to allow the user to see the alert type under Options section. User will be forced to receive the alert and does not have the option to select/deselect alert option: -Seleting no Alert option and user will not see the alert option and will not be allowed to subscribe to the alert:
|


hello !! test_id is : {{id}}
{%if id.day is 1 %} first day and...{{none}} {%else%} today is not first day
and...today is {{id}} {%endif%}


§210-5 Rules and regulations. The rules and regulations shall:
(1) Prescribe the qualifications for eligibility of applicants for loans.
(2) Establish preferences and priorities in determining eligibility for loans.
(3) Establish the conditions, consistent with the purposes of this chapter, for the granting or for the continuance of a grant of a loan.
(4) Provide for inspection, at reasonable hours, of the plant, books, and records of an enterprise which has applied for or has been granted a loan, and to require the submission of progress and final reports. [L 1963, c 76, §6; Supp, §98R-6; HRS §210-5]


Welcome to TSBackup
Today's recycle date is
- Training Material
- Useful reference and other training materials for new tech support interns.
- Introduction to the Command Line (PDF)
- A Free manual published by flossmanuals.net. It is also available online, in HTML format at
http://flossmanuals.net/command-line
- upgrade-ubuntu.sh
- Use this to upgrade form 10.04 to 12.04.
N.B.
This script performs a backup, so you should not do one first as it will complain. You can force it to overwrite it with the -f option.
Steps to upgrade the script.
Note the following carefully:
- Run the script, carefully noting any instructions given
- When prompted to reboot. DO NOT REBOOT
- Press x, then type reboot on the command line.
- Rerun the script a second time to finish the process
- whoopise-disable.sh
- A small shell script that will disable the annoying crash reports on 12.04
- Tech Support Tools
- This is a tarball that uncompresses to a directory containing a bunch of usefull shell scripts for tech support purposes. The main ones of interest are
ts_network_backup
which automates the network backup process and ts_identify_backups
which is used in conjunction with it (given a ticket number it will identify the directory it was backed up to.
The latest version can always be found at:
http://tsbackup/tstools.tar.gz.
The current version is tstools.0.1.13.tar.gz.
Eventually it will be come a deb that be installed via apt-get form the freegeek archives. N.B. This is still beta quality, bugs may be present though it is definitely usable. Bug reports are welcome via email to<EMAIL_ADDRESS>(or the bugs queue in RT). Please include any output/error messages and the version you were using, thank you.
History
- tstools.0.1.13
- «Lucky Thirteen»
#34487 #32908 Hopefully fixed the bug which prevented backups when there was a space in the directory name (for reals this time).
Added a long list of temporary files that will be excluded from backups.
Fixed a bug with adding an addendum that left off the ticket number. (Also closing #33225)
Added a -R option for read only file systems e.g. dd images.
- tstools.0.1.12
- Bug Fixes:
Fixed #33225 which prevented the -t option from working correctly.
- tstools.0.1.11
- Bug Fixes:
32902 ts_network_backup failed w/ requesting -p option
32599 rm: cannot remove `=/home/gshadow': No such file or directory
32823 usermod: group ' ' does not existi
#32908: check_dir_read fails if there are spaces in path
- tstools.0.1.10
- Fixed bug in user restoration process.
- tstools.0.1.9
- Fixed bug preventing proper cleanup.
- tstools.0.1.8
- Added fix for issue where creating users with uid 1000 who were not oem failed.
- tstools.0.1.7
- Tidied up help for many tools. Added README. Bugfixes.
- tstools.0.1.6
- Initial Release
- Music...
- Access Ampache -- a web based music player and play music in Tech Support (assuming tsbackup is plugged into the speakers).
- Flash fix
- A small shell script that “fixes” issues with Adobe Flash and AMD CPU's. This isn't really a fix, more of an ugly workaround and will often break on updates. The issue is an upstream bug introduced by Adobe who apparently don't know how to use a compiler properly and show no sign of fixing it any time soon.
background image:
Royal Bluebells - Charlotte Pass, Peter Kent, Flickr. Some rights reserved.


workbox
This module is a single import that can be used to dynamically import additional Workbox modules with no effort.
Namespaces
backgroundSync
broadcastUpdate
cacheableResponse
core
expiration
googleAnalytics
precaching
rangeRequests
routing
strategies
Methods
clientsClaim
clientsClaim()
Claim any currently available clients once the service worker becomes active. This is normally used in conjunction with skipWaiting()
.
loadModule
loadModule(moduleName)
Load a Workbox module by passing in the appropriate module name.
This is not generally needed unless you know there are modules that are dynamically used and you want to safe guard use of the module while the user may be offline.
Parameter |
|
|---|---|
|
moduleName |
string |
setConfig
setConfig(options)
Updates the configuration options. You can specify whether to treat as a debug build and whether to use a CDN or a specific path when importing other workbox-modules
Parameter |
|||||||||
|---|---|---|---|---|---|---|---|---|---|
|
options |
Optional Object Values in
|
skipWaiting
skipWaiting()
Force a service worker to become active, instead of waiting. This is normally used in conjunction with clientsClaim()
.
Abstract type
ModulePathCallback
ModulePathCallback(moduleName, debug) returns string
A ModulePathCallback
function can be used to modify the modify the where Workbox modules are loaded.
Parameter |
|
|---|---|
|
moduleName |
string The name of the module to load (i.e. 'workbox-core', 'workbox-precaching' etc.). |
|
debug |
boolean When true, |
- Returns
-
string
This callback should return a path of module. This will be passed toimportScripts()
.


Home
(current)
Services
Office Cleaning
Post Construction
Tenant Turnover
Carpet Cleaning
Contact
N.G Building Cleaning
servicing Ottawa-Gatineau since 1989
Loading...


We're sorry but register_login doesn't work properly without JavaScript enabled. Please enable it to continue.


Just a miniature human who likes to code. Lover of the PNW.
Chronic snacker. Cat enthusiast. Longboarder. Frequent hiker. Wannabe Coder. Pluviophile.
Earned my Associates in Pre-nursing and said goodbye to that after I discovered the world of software engineering. Currently furthering my future with coding.


404 Page Not Found
We're sorry, but the page you are looking for does not exist.
Keep calm and return to the
homepage
.


This example was made with Scala.js, Scala.js-jQuery and jQueryUI after the jQueryUI Guide from Matt Doyle on Elated


About
September 19, 2015
Hi there, I’m Wahyu Langit
Wahyu Langit or Nur Wahyuono, SE. epotimizes integrity, energy, hard working, and creative service in every detail real estate transactions. He has a successful career in real estate for 13 years. He has worked every aspect of the industry representing sellers, buyers, investors and banks, in both of the residential and commercial market.
Wahyu Langit is family man with a devotion to God, his beautiful wife, and three children. He is an enthusiastic to the best buy real estate marketing, enjoys art painting, art design, web design and web development, reading, listen to music, travelling and showing clients to the best buy real estate has to offer.
The International Real Estate Agent Career’s
Beginning his career International Real Estate Agent in 2001, he then has been trained and inspired in real estate sale by ©ERA-The Real International Property Agent and ©Ray White–Real Estate Leader in Indonesia.
Wahyu Langit has a long record of successfully guiding local, national and multi-national clients with their commercial properties. He has built a solid foundation of corporate clients his tenant advisory services.
A 13-year’s commercial real estate industry veteran and has represented large users of office and industrial space in a wide array of real estate transaction. In addition to the sales of single-family home and condominium, he has also been real estate agent for numerous developers on of historic townhouse and buildings into both single family homes and condominium projects.
Clients choose to work with wahyu langit for his full service ability, ethics, experience and expertise. He has consistently shown the ability to satisfy clients in the buying and selling of their residential and commercial real estate. His strong base of loyal repeat customers is the reason Wahyu Langit has been successful for over 13 years in this incredibly competitive sales environment. Quite simply, he is trusted.
Wahyu Langit uses his experience and foresight to proactively address details before they become a problem. He inspects and maintains properties, initiate communication in every detail of the transaction, from the first phone call all the way to close transaction. Five words you can describe Wahyu Langit love, integrity, commitment, passion and fun.


Muscling up budding gyms to stretch new horizons
With GymClub, You can join forces with a network of like minded gyms that provide unlimited access to your users.
Learn More!Give us a call or send us an email and we will get back to you as soon as possible!
123-456-6789


| 2020 | Master of Data Science | Program coordinator |
| 2020 | Master of Machine Learning | Program coordinator |
| 2020 | Mining Big Data | Course code: COMPSCI 3306/7306, 1st Semester |
| 2020 | Master of Data Science Research Project Part A | Course code: COMPSCI 7097A, 1st Semester |
| 2020 | Introduction to Statistical Machine Learning | Course code: COMPSCI 3314/7314, 2nd Semester |
| 2020 | Master of Data Science Research Project Part B | Course code: COMPSCI 7097B, 2nd Semesters |
| 2020 | Big Data Analysis and Project | Course code: COMPSCI 7209, 2nd Semester |
| 2019 | Master of Data Science | Program coordinator |
| 2019 | Mining Big Data | Course code: COMPSCI 3306/7306, 1st Semester |
| 2019 | Master of Data Science Research Project Part A | Course code: COMPSCI 7097A, 1st and 2nd Semesters |
| 2019 | Introduction to Statistical Machine Learning | Course code: COMPSCI 3314/7314, 2nd Semester |
| 2019 | Master of Data Science Research Project Part B | Course code: COMPSCI 7097B, 2nd Semester |
| 2018 | Introduction to Statistical Machine Learning | Course code: COMPSCI 4401/7401, 2nd Semester |
| 2018 | Big Data Analysis and Project | Course code: COMPSCI 7209, 2nd Semester |
| 2018 | Advanced Topics in Computer Science | Course code: COMPSCI 3020, 1st Semester |
| 2018 | Algorithm and Data Structure Analysis (Small-Group Discovery Experience) | Course code: COMPSCI 2201, 1st Semester |
| 2017 | Introduction to Statistical Machine Learning | Course code: COMPSCI 4401/7401, 2nd Semester |
| 2017 | Introduction to Geometric Algorithms | Course code: COMP SCI 4802/7402, 2nd Semester |
| 2016 | Mining Big Data | Course code: COMPSCI 4403, 2nd Semester |
| 2016 | Introduction to Statistical Machine Learning | Course code: COMPSCI 4401/7401, 2nd Semester |
| 2015 | Algorithm and Data Structure Analysis (Small-Group Discovery Experience) | Course code: COMPSCI 2201, 2nd Semester |
| 2015 | Operating Systems | Course code: COMPSCI 3004NA/7064NA, 3rd Trimester |
| 2015 | Computer Graphics | Course code: COMPSCI 3014NA, 2nd Trimester |
| 2015 | Introduction to Statistical Machine Learning | Course code: COMPSCI 4401/7401, 2nd Semester |
| 2015 | Scientific Computing (Small-Group Discovery Experience) | Course code: COMPSCI 1012, 1st Semester |
| 2014 | Introduction to Statistical Machine Learning | Course code: COMPSCI 7012, 2nd Semester |
| 2014 | Scientific Computing (Small-Group Discovery Experience) | Course code: COMPSCI 1012, 1st Semester |
| 2013 | Introduction to Statistical Machine Learning | Course code: COMPSCI 7012, 2nd Semester |
| 2012 | Introduction to Statistical Machine Learning | Course code: COMPSCI 7012, 2nd Semester |
| 2012 | Master of Computing and Innovation Project | Course code: COMPSCI 7098, 1st Semester |
| 2012 | Foundations of Computer Science | Course code: COMPSCI 2202, 1st Semester |
| 2011 | Computer Vision | Course code: COMPSCI 4022/7022, 2nd Semester; Guest lecturer
|


This is the PMD programming mistake detector. In order to use it, create a new instance of {@link net.sourceforge.pmd.PMD} and use its {@link net.sourceforge.pmd.PMD#processFiles} method.


The English letter allows you to write in Farsi all you have to do is to know the sound of the letters and you've got the equivalent letters in Farsi before your eyes.
If you know the familiar English keyboard, you can write skillfully in Farsi, too. The letter ‘s’ shows ‘sin’ and ‘k’ shows ‘kaaf’, so to write 'motoshakker, you type, ‘m’+t+‘S’+‘k’+‘r’.
To get:
The Farsiman keyboard for touch devices has multiple layers: Default (lowercase), Shift (uppercase) numerals, and combinations. Invest less than 60 seconds and master them all. Here we go:
Press and hold on the key with a little dot on the top right to reveal more characters.
© 2019 Yuichi Yoshimoto


--- title: Contact layout: default --- {% include contactCSS.html %} Want to get in touch? Just fill out this form, and I'll get back to you as soon as possible. Would you like to get involved? Get the latest news Knock on doors Make phone calls Get a lawn sign Host a house party Submit
Vipond for CongressP.O. Box 1852Brookfield, WI 53008-1852


 If the user does not exist they will be emailed instructions to set up their account then automatically added to your project." %}
{% include 'management/project_users/_role_help.html' %}


About Us
Our Department
We are the Journalism, Information and Communications Department within Manchester Metropolitan University. Our courses consist of different routes within the Department; they are the following Information and Communications, Multimedia Journalism, Web Development and Digital Media and Communications. The Geoffrey Manton (GM) building is the heart of our Department. We have fascinating facilities in our Department which is called The Multimedia Resources Library (MRL). In the Multimedia Resources Library (MRL), we have IT suites which contain PC’s and Apple Macs, with the latest software and hardware for our students to use to do their projects.
The Facilities
In our Department we have fully equipped video cameras and DSLR cameras for our student to loan and use for their creative assements. Apart from the MRL, we have other facilities across the campus like a 24/7 Library where students can loan books for their assignments. As well as in the Library we have three level floors of IT suites, quiet zones and group zones where students can study in regards to their preferences. On the other hand we have various Café Atrium across the campus where students could purchase hot and cold food, hot and cold drinks and sandwiches.
Teaching Staff
Our department senior lecturers have been teaching Web Development for 15 years and have great links within the industry. We also have events throughout the Department where specialised people from the industry talk to our students. Manchester is really big in the digital industry, so it gives amazing opportunities for our students when they are graduated. Manchester Metropolitan University is the number 1 greenest institution.
Finally, we think creativity all the time and we make our students into creative individuals as our strong programme helps our students get the required skills. As we follow industry standards.


|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |
Object org.apache.spark.mllib.feature.IDF.DocumentFrequencyAggregator
public static class IDF.DocumentFrequencyAggregator
Document frequency aggregator.
| Constructor Summary | |
|---|---|
IDF.DocumentFrequencyAggregator()
|
|
IDF.DocumentFrequencyAggregator(int minDocFreq)
|
| Method Summary | |
|---|---|
IDF.DocumentFrequencyAggregator |
add(Vector doc)
Adds a new document. |
Vector |
idf()
Returns the current IDF vector. |
IDF.DocumentFrequencyAggregator |
merge(IDF.DocumentFrequencyAggregator other)
Merges another. |
int |
minDocFreq()
|
| Methods inherited from class Object |
|---|
equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait |
| Constructor Detail |
|---|
public IDF.DocumentFrequencyAggregator(int minDocFreq)
public IDF.DocumentFrequencyAggregator()
| Method Detail |
|---|
public int minDocFreq()
public IDF.DocumentFrequencyAggregator add(Vector doc)
public IDF.DocumentFrequencyAggregator merge(IDF.DocumentFrequencyAggregator other)
public Vector idf()
|
|||||||||
| PREV CLASS NEXT CLASS | FRAMES NO FRAMES | ||||||||
| SUMMARY: NESTED | FIELD | CONSTR | METHOD | DETAIL: FIELD | CONSTR | METHOD |


SimpleParallax is a small, simple, easy to use scrolling parallax library. It uses CSS3 transformations along with requestAnimationFrame to create buttery smooth animations, with zero dependencies. Get up and running in seconds.
This box can be created like this:
var parallax = new SimpleParallax({ element: document.getElementById('center-screen'), speed: 2 });
Various options are supported:
var parallax = new SimpleParallax({ element: document.getElementById('element'), speed: 0.5, offset: function() { return 20; } });
Created by Chris Anselmo. View on Github.
Background by Ignasi Àvila Padró


Robust, reliable and flexible paths to files below a project root. The 'root' of a project is defined as a directory that matches a certain criterion, e.g., it contains a certain regular file.
| Version: | 1.3-2 |
| Depends: | R (≥ 3.0.0) |
| Imports: | backports |
| Suggests: | testthat, mockr, knitr, withr, rmarkdown |
| Published: | 2018-01-03 |
| Author: | Kirill Müller [aut, cre] |
| Maintainer: | Kirill Müller <krlmlr+r at mailbox.org> |
| BugReports: | https://github.com/krlmlr/rprojroot/issues |
| License: | GPL-3 |
| URL: | https://github.com/krlmlr/rprojroot, https://krlmlr.github.io/rprojroot |
| NeedsCompilation: | no |
| Materials: | NEWS |
| CRAN checks: | rprojroot results |
| Reference manual: | rprojroot.pdf |
| Vignettes: |
Finding files in project subdirectories |
| Package source: | rprojroot_1.3-2.tar.gz |
| Windows binaries: | r-devel: rprojroot_1.3-2.zip, r-release: rprojroot_1.3-2.zip, r-oldrel: rprojroot_1.3-2.zip |
| OS X binaries: | r-release: rprojroot_1.3-2.tgz, r-oldrel: rprojroot_1.3-2.tgz |
| Old sources: | rprojroot archive |
| Reverse imports: | cloudml, DataPackageR, debugr, desc, exampletestr, excerptr, here, learnr, pkgbuild, pkgload, prodigenr, radix, rcmdcheck, secret, sparklyr, styler, teachingApps, usethis, workflowr |
| Reverse suggests: | clusteredinterference, DBI, deckgl, document, docxtools, fakemake, googledrive, googlesheets, Rdpack, readxl, reprex, repurrrsive, RMariaDB, surveydata, tatoo, testthis, webdriver |
Please use the canonical form https://CRAN.R-project.org/package=rprojroot to link to this page.


MYSTERY MEN Reviewed by Jamie Peck
Rating: *** (out of ****) Universal / 1:58 / 1999 / PG-13 (language, comic violence, crude humor) Cast: Ben Stiller; William H. Macy; Hank Azaria; Janeane Garofalo; Geoffrey Rush; Wes Studi; Paul Ruebens; Kel Mitchell; Greg Kinnear; Claire Forlani; Eddie Izzard; Tom Waits; Lena Olin Director: Kinka Usher Screenplay: Neil Cuthbert
If you've been pining to see William H. Macy removed from his element, then "Mystery Men" is going to be your kind of movie. The "Fargo" Oscar-nominee and critically-acclaimed character actor here plays a blue-collar (and blue-jeans) crime-fighter known as The Shoveler, and seeing him dispatch disco-vamping enemies with a swift whack of his namesake weapon provides many a pinch-me-so-I-know-I'm-not-dreaming moment. Be thankful you're wide awake: Chief among the perverse pleasures of "Mystery" is witnessing him and more unexpected talents deadpan their way through a story that's all punchlines and sensory explosion.
A single member of a trio of hero-wannabes in the Gotham-like metropolis Champion City, Shoveler's team also includes Mr. Furious (Ben Stiller, radiating manic cool in stubble, spiky hair and black leather), prone to attention-getting tantrums, and The Blue Raja (Hank Azaria), a fork-flinger sporting an effete British accent and a wardrobe that looks stitched together from an elderly lady's housecoat. (It probably was.) They genuinely want to help rid their hometown of bad guys, yet always seem to fall into the shadow of the amazing Captain Amazing (Greg Kinnear, perfectly utilized), Champion City's bonafide defender against evil.
With this set-up, "Mystery Men" sounds like any number of comics brought to large, lush life on the big screen - and, as every colorfully askew frame makes evident, it's source is just that (specifically, a Dark Horse publication called "Flaming Carrot"). But that the protagonists are second-rate saviors hints at vast opportunities for a wicked sense of humor, an edge that the performers, screenwriter Neil Cuthbert and debut director Kinka Usher take to the hilt. And what a hilt: A particularly amusing running gag involves Kinnear's promotional sponsorship, his NASCAR-esque jumpsuit displaying logos for Reebok, Rayovac and Pepsi.
Actually, Captain Amazing loses the latter endorsement after one too many ho-hum rescues. This puts him in a glum mood, so he demands that his publicist work to free old arch-nemesis Casanova Frankenstein (hammy Geoffrey Rush) from the local asylum to spark some deadly new conflict - only the plan backfires when he gets kidnaped by Casanova, allowing Shoveler, Mr. Furious and Blue Raja to prove their worth. First order of business: A backyard barbeque to hold auditions for new partners, where such funny rejects as Waffle Man (special power: "truth syrup") and PMS Avenger expire their moment in the spotlight.
Enter the real deals ... well, sort of: Paul "Pee-Wee Herman" Rueben's flatulent Spleen, Wes Studi's uber-enigmatic Sphinx, Kel Mitchell's affable Invisible Boy and "Mystery" MVP Janeane Garofalo as The Bowler, whose ball - containing both her dead father's skull and spirit - throws like a destructive boomerang. Once these cads come together following a shaky beginning, "Mystery Men" stands tall and proud on terra firma. Usher piles his freak show high in trappings so garish and silly that they occasionally topple under the weight, especially the messy action sequence that inaugurates the movie. But when they fly, they soar.
"Mystery Men" similarly finishes on a sloppy note, as each individual good guy gets his or her chance to shine in the run-of-the-mill climactic battle; the film dangerously courts becoming what it so far has poked a generous amount of fun at. But even with Usher's inexperience creating cluttered bookends, the long, strong midsection's mirthful mayhem and summer-flick satirizing are as irresistible as the priceless cast. Given the delightfully demented accomplishment here, a sequel that reunites these super friends and their behind-the-scenes counterparts - in some cases older, in others wiser - isn't out of the question.
© 1999 Jamie Peck E-mail<EMAIL_ADDRESS>Visit The Reel Deal Online: http://www.gl.umbc.edu/~jpeck1/ "Upon hearing word of this outrage, ‘Star Wars' creator George Lucas (in the throes of developing scripts for the two remaining "Star Wars" films) quickly removed all references to an upcoming character allegedly named Stingy MacHaggis, a kilt-wearing alien who was to spend a good portion of ‘Episode II' drinking, picking fights and playing an alien musical instrument that strongly resembled a set of bagpipes. He is to be replaced by another alien character - a formless, colorless and mute creature who in no way resembles any culture or individual that ever existed or ever will exist. -AAlgar on "The Phantom Menace"'s race-stereotyping controversy
The review above was posted to the
rec.arts.movies.reviews newsgroup (de.rec.film.kritiken for German reviews).
The Internet Movie Database accepts no responsibility for the contents of the
review and has no editorial control. Unless stated otherwise, the copyright
belongs to the author.
Please direct comments/criticisms of the review to relevant newsgroups.
Broken URLs inthe reviews are the responsibility of the author.
The formatting of the review is likely to differ from the original due
to ASCII to HTML conversion.
Related links: index of all rec.arts.movies.reviews reviews


Introduction to the Web Script Framework
Jeff Potts
October, 2007
- License
- Introduction
- What is the Web Script Framework?
- Examples
- SomeCo Whitepaper User-contributed Ratings Examples
- Conclusion
- Where to find more information
- Footnotes
License
This work is licensed under the Creative Commons Attribution-ShareAlike 3.0 Unported License. To view a copy of this license, visit http://creativecommons.org/licenses/by-sa/3.0/ or send a letter to Creative Commons, 444 Castro Street, Suite 900, Mountain View, California, 94041, USA.
Introduction
This article is an introduction to the Alfresco Web Script Framework that became available with release 2.1 of the product.
We'll continue to extend the “SomeCo Whitepapers” example started in previous articles. As a quick refresher, in those articles, we extended the out-of-the-box content model so that SomeCo could store custom metadata about one of their document types, whitepapers. We created a custom aspect called rateable that could be attached to any object that was user-rateable. Then, in the custom behavior article we wrote business logic associated with the rateable aspect that knew how to calculate the average user rating for a given piece of content. The calculation was triggered every time a rating was created or deleted. We used server-side JavaScript to create rating objects to test out our behavior but there wasn't an interface available that end users could use to rate whitepapers.
SomeCo is now ready to move to the next step: Exposing the rating functionality to the front-end. In their infinite wisdom, the team at SomeCo realizes that Alfresco's Web Scripts provide a nice way to expose a lightweight, RESTful API for working with whitepapers and ratings. So in this article, we'll roll our own REST API for retrieving a list of whitepapers, retrieving the average rating for a given whitepaper, retrieving a specific rating, posting a new rating for a whitepaper, and deleting all ratings for a given whitepaper. We'll use JavaScript for most of our controller logic but we'll see how to use Java as well. The view will be implemented using FreeMarker templates that return HTML and JSON.
The complete source code that accompanies this article is available at ecmarchitect.com. See the “More Information” section at the end of this article for the link. In addition to the code for this article, the zip includes the code created in the first two “SomeCo” articles so if you don't have to dig around for the code we build upon in this article.
Sound decent? Okay, let's get started.
What is the Web Script Framework?
Content-centric applications, whether they are inside or outside the firewall, are becoming more and more componentized. I think of this as turning traditional content management approaches inside-out. Rather than having a single, monolithic system responsible for all aspects of a content-centric web application, loosely-coupled sub-systems are being integrated to create more agile solutions.
This approach requires that your content management system have a flexible and lightweight interface. You don't want to be locked in to a presentation approach based on the content repository you are working with. In fact, in some cases, you might have very little control over the tools that will be used to talk to your CMS.
Consider the exploding rate of Next Generation Internet (NGI) solutions, the growing adoption of wikis and blogs within an Enterprise (“Enterprise 2.0”), and the increasing popularity of mash-ups both inside and outside the Enterprise. These trends are driving implementations where the CMS is seen as a black-box component with the front-end (or perhaps many different front-ends) interacting with the CMS and other components via REST.
Among open source content management systems, Alfresco is one of the few that really lends itself to this approach because it has many options for interacting with the repository. These options have evolved over time. The following summarizes ways in which your front-end could work with the Alfresco repository prior to release 2.1:
Embed the repository. Alfresco's repository can be embedded in a custom application. Using this approach you have the full power of the Alfresco foundation API. Of course, the downside is that you've just tightly coupled the repository with your application. Didn't we just talk about how important an open, loosely-coupled architecture is? Moving on...
Web Services. Alfresco has had a SOAP-based Web Services API available for quite some time, but SOAP-based Web Services have heavier client-side requirements than their RESTful cousins. Some clients found that the out-of-the-box services were too chatty and had too much processing overhead to scale well so they ended up writing their own services and exposing them through the embedded Apache Axis server. So Web Services may not be the right fit in all cases.
JCR. The JCR API is a standard way of working with content in a repository and can be leveraged remotely through RMI. This has the benefit of using a standards-based approach for interacting with the repository which theoretically reduces switching costs and makes the application easier to support. One challenge with this approach is that the JCR API may not do everything you need to do so you end up using the JCR in combination with one of the above approaches which reduces the “switching costs” benefit. Another potential issue is that it is Java-only.
URL Addressability. Objects in the Alfresco repository are URL-addressable. And, FreeMarker templates and server-side JavaScript can be applied to any node in the repository. So, for example, you can write a FreeMarker template that returns XML or JSON. A front-end app can then post an XMLHttpRequest to Alfresco that specifies a node reference and a reference to the FreeMarker template. Alfresco will process the FreeMarker template in the context of the node specified and return the results. This is the closest you can get to the functionality of the Web Script Framework prior to 2.1.
These options are all still available and may make sense depending on exactly what you are trying to do. But with 2.1 there's a potentially better way for interacting with the repository—the Web Script Framework.
The Web Script Framework essentially improves on the basic idea that started with URL addressability. Think of a web script as a chunk of code that is mapped to a human-readable (and search-engine readable) URL. So, for example, a URL that returns expense reports pending approval might look like:
/alfresco/service/expenses/pending
while a URL that returns expenses pending approval for a specific user might look like:
/alfresco/service/expenses/pending/jpotts
In the URL above, you could read the “jpotts” component of the URL as an implied argument. A more explicit way to provide an argument would be like:
/alfresco/service/expenses/pending?user=jpotts
Or maybe “pending” is an argument as well which tells the web script what status of expense reports to return. The point is that the structure of the URL and how (and if) your URL includes arguments is completely up to you.
The response the URL returns is also up to you. Your response might return HTML, XML, JSON, or even a JSR-168 Portlet.
The Web Script Framework makes it easy to follow the Model-View-Controller (MVC) pattern, although it isn't required. The Controller is server-side JavaScript, a Java Bean, or both. The Controller handles the request, performs any business logic that is needed, populates the Model with data, and then forwards the request to the View. The View is a FreeMarker template responsible for constructing a response in the appropriate format. The Model is essentially a data structure passed between the Controller and the View.
The mapping of URL to controller is done through an XML descriptor which is responsible for declaring the URL pattern, whether the script requires a transaction or not, and the authentication requirements for the script. The descriptor optionally describes arguments that can be passed to the script as well as the response formats that are available.
The response formats are mapped to FreeMarker templates through naming convention. So, for example, the FreeMarker template that returns expenses as HTML would be named with an extension of “html” while the one that returns XML would be named with an extension of “xml”.
The descriptor, the JavaScript file, and the FreeMarker templates can reside either in the repository or on the file system. If a Web Script uses a Java Bean, the class must reside somewhere on the classpath.
With these building blocks in mind you may already be thinking of different ways you could leverage Web Scripts. If not, let me help. You can use Web Scripts to expose the Alfresco content repository through a RESTful API to:
- Enable a front-end web application written in any language that can talk HTTP to retrieve repository data in XML, JSON, or any other format or to persist data to the repository;
- Populate JSR-168 portlets;
- Capture user-contributed content/data;
- Interact with a business process (e.g., a JBPM workflow) through non-web client interfaces such as email;
- Create ATOM or RSS feeds for repository content or business process data; and
- Decompose the existing web client into smaller components which could potentially lend itself to being re-born in new and exciting ways!
Okay, you probably shouldn't tackle that last one but rest assured that Alfresco is already working on it.
The last thing to mention is that Web Scripts are executed in a “Web Script Runtime”. In 2.1, there are three runtimes available out-of-the-box. The servlet runtime executes all web scripts requested via HTTP. The JSF runtime that allows JSF components to execute scripts. A JSR-168 runtime allows portlets to invoke web scripts directly.
You can write your own runtime if these don't meet your needs. Alfresco may add more in the future. At some point, you could see web script execution separated entirely from the Alfresco web application into its own process which would lend itself to load-balancing, scalability, etc.
In this article, we'll focus on the servlet runtime for HTTP.
Web Scripts Directory
The web client comes with a tool for listing and reloading web script definitions. To get to the tool, go to http://localhost:8080/alfresco/service/index. You'll see links that let you browse the list of deployed web scripts and a button labeled “Refresh list of Web Scripts”. Although making changes to web scripts that reside in the repository does not require a restart, you may have to refresh the index with this button after a change.
Click through the links to see what is available out of the box. You'll notice that the tool itself is built using web scripts.
Examples
Let's walk through some examples. We're going to start with a very simple Hello World web script. After that, we'll get progressively more complex until, at the end, we have a REST-based interface for creating, reading, and deleting SomeCo whitepaper ratings.
Hello World Example
Let's implement the most basic web script possible: A Hello World script that echoes back an argument. We'll need one descriptor and one FreeMarker template. Do the following:
- Log in to Alfresco.
- Navigate to /Company Home/Data Dictionary/Web Scripts Extensions.
Create a file called helloworld.get.desc.xml with the following content:
<webscript> <shortname>Hello World</shortname> <description>Hello world web script</description> <url>/helloworld?name={nameArgument}</url> </webscript>
Create a file called helloworld.get.html.ftl with the following content:

Hello, ${args.name}!

- Go to http://localhost:8080/alfresco/service/index and press the Refresh button. If you then click the “List Web Scripts” link you should be able to find the web script you just defined.
Now go to http://localhost:8080/alfresco/service/helloworld?name=Jeff. You should see:
Hello, Jeff!
A few things to note. First, notice the file names include “get”. That's the HTTP method used to call the URL. In later examples we'll see how to use POST and DELETE. By differentiating on the HTTP method, you can have multiple controllers for the same “service” depending on how the service is called (GET vs. POST, etc.). Second, in this case we only had one argument but we could add as many as we need. Watch out, though! Descriptors must be valid XML which means ampersands must be escaped. So the proper way to define a URL with multiple arguments is:
<url>/helloworld?name={nameArgument}&secondArg={anotherArg}</url>
Third, notice we didn't include a JavaScript file in this example but the script still ran because controllers are optional.
Most scripts are going to use a controller, though, so let's go ahead and add one.
Create a file called helloworld.get.js with the following content:
model.foo = "bar";
Update your helloworld.get.html.ftl file with the following content:

Hello, ${args.name}!

Foo: ${foo}

- Go to http://localhost:8080/alfresco/service/index and press the Refresh button. This is required because you added a controller that the web script run-time didn't know about.
Now go to your web browser and enter the same URL from the first example which was http://localhost:8080/alfresco/service/helloworld?name=Jeff. You should see:
Hello, Jeff! Foo: bar
What's going on here is that the controller is getting executed before the FreeMarker template. In the controller we can do anything the Alfresco JavaScript API can do. In this case, we didn't leverage the JavaScript API at all—we just put some data into the “model” object which was then read by the FreeMarker template. In subsequent examples the controller will have more work to do and in one case, we'll use Java instead of JavaScript for the controller.
SomeCo Whitepaper User-contributed Ratings Examples
We want to create a REST API that front-end developers can use to find whitepapers and ratings as well as post new ratings. Before we dive in, it probably makes sense to rough out the API.
| URL | Method | Description | Response Formats |
|---|---|---|---|
| /someco/whitepapers | GET | Returns a list of whitepapers. | HTML, JSON |
| /someco/rating?id={id} | GET | Gets the average rating for a given whitepaper by passing in the whitepaper's noderef. | HTML, JSON |
| /someco/rating?id={id}&rating={rating}&user={user} | POST | Creates a new rating for the specified whitepaper by passing in a rating value and the user who posted the rating. | HTML, JSON |
| /someco/rating?id={id} | DELETE | Deletes all ratings for a specified whitepaper. | HTML |
When this API is in place, front-end developers can incorporate whitepapers and user-contributed ratings into the SomeCo web site. The following screenshots show pages that use the API we're going to build to query for whitepaper and ratings data. It looks like the folks at SomeCo have shamelessly ripped off the Optaros publications section. They didn't even bother to change the logo.
You can't tell from the screenshots, but the ratings widget is clickable. When clicked it sends an asynchronous post to the /someco/rating URL described in the table above. When the “Get the White Paper” link is clicked, the page in Illustration 2 is displayed. I reused the description from the index page for the Executive Summary. In the real world this would probably be a more lengthy description separate from the introduction on the index page. The “Download this white paper” link uses the standard “Download URL” to give the user direct access to the content.
Listing all Whitepapers
As a quick review, recall that SomeCo writes whitepapers and manages those papers with Alfresco. Some whitepapers are published to the web site. A custom aspect called “webable” has a flag called isActive. Whitepapers with the isActive flag set to true should be shown on the web site. For this article, we're going to ignore the webable aspect and the isActive flag. We'll just assume any sub-type of sc:whitepaper found in the /Someco/Whitepapers folder is fair game. (If this bugs you, see the sidebar).
Let's write a web script that returns all whitepapers. We want the list in two formats HTML and JSON. HTML will allow us to easily test the service and JSON will make it easy for code on the front-end to process the list. This will require four files: one descriptor, one JavaScript controller, and two FreeMarker templates—one for each format.
Sidebar: Enabling a subset of whitepapers for web display
The real-world solution this example is based on uses UI actions to enable and disable the “sc:isActive” flag. An Evaluator class hides or shows the “Enable Web” or “Disable Web” UI action link based on the value of the flag and the group membership of the user. If you want to do something similar on your own, the sc:webable aspect is in the model included with the source code for this article. And, I've included two scripts (enableWeb.js and disableWeb.js) that you can use to attach the webable aspect and set the isActive flag appropriately. If you want the whitepaper service to filter the list based on the isActive flag, the Lucene query in the whitepaper.get.js file needs to be appended with “@sc\\:isActive:true” to show only active whitepapers. I left this functionality out of the example because it isn't core to the topic.
Organizing your code
Before we start coding, let's talk a bit about organization. First, packages. The Web Script Framework allows us to organize script assets into a hierarchical folder or package structure. Just as it is with Java it is probably a good idea to do this for all web scripts. Following a reverse domain name pattern is probably a good convention. So we'll be using “com/someco” for our package which means our files will reside under /Company Home/Data Dictionary/Web Scripts Extensions/com/someco.[^1^](#sdfootnote1sym)
Next, URLs can follow any pattern we want, but they will always start with <alfresco webapp>/service where “<alfresco webapp>” is the name of the Alfresco web application context (usually “alfresco”). Because the URL pattern must be unique, it is probably a good idea to incorporate the package name in the URL. In this article we'll prefix all URLs with “someco”.
Alfresco reserves certain package names and URLs for their own use (see the Alfresco wiki) but by following the conventions proposed here, you'll steer clear of those.
Finally, you've seen that web script assets can reside in the repository, but they can also reside in the file system. The only requirement is that they be on the classpath, but I suggest that they reside in the “alfresco/extension” directory just like your other extensions. Following the package structure suggested earlier, if we were to store our scripts on the file system, rather than the repository, we'd put them in alfresco/extension/templates/webscripts/com/ someco.
The advantage of using the file system is that the web scripts that make up your solution can be deployed alongside your other extensions without requiring anyone to upload them to the repository. The disadvantage is that changes require a restart.
In the source code I've provided with this article, the web scripts are set up to deploy to the file system with the other extensions. If, instead of deploying the sample code, you want to follow along and you want to avoid restarts, move my scripts out of the alfresco extension directory before you deploy, then upload your scripts to the repository like we did for the Hello World example.
If scripts are defined in the repository as well as the classpath, the files in the repository take precedence over the files on the classpath. The Alfresco wiki documents the search order for web scripts (See “Where to find more information” at the end of this article for a list of references).
Step 1: The descriptor
With that, we should be good to go. The first step is to create the descriptor file. It should be named whitepapers.get.desc.xml and should look like this:
<webscript>
<shortname>Get all whitepapers</shortname>
<description>Returns a list of active whitepapers</description>
<url>/someco/whitepapers</url>
<url>/someco/whitepapers.json</url>
<url>/someco/whitepapers.html</url>
<format default="json">extension</format>
<authentication>guest</authentication>
<transaction>none</transaction>
</webscript>
There are a few elements in this descriptor we didn't see in the Hello World example. First, notice that there are multiple URL elements. There is one URL for each format plus a URL without a format. This shows how to request a different output format from the same base URL. Because the URLs differ only in format, it isn't strictly required that they be listed in the descriptor, but it is a good practice.
In this case, we're using the “extension” syntax—the extension on the URL specifies the format. An alternative syntax is to use the “argument” syntax like this:
<url>/someco/whitepapers?format=json</url>
<url>/someco/whitepapers?format=html</url>
My current thinking is that the extension syntax is preferred because it is friendlier to search engines but there may be reasons to use the argument syntax.
The format element declares the type of syntax we're using and defines a default output format. If you want to accept either syntax, you can use “any” as the format. In our case, using this descriptor if someone uses the argument syntax, they'll get an Error 500. If someone uses the URL without specifying a format, they'll get JSON.
The authentication element declares the lowest level of authentication required for this script. If your script touches the repository you will want this to be Guest or higher. Other options are “none”, “user”, and “admin”.
The transaction element specifies the level of transaction required by the script. Listing whitepapers doesn't need a transaction so we've got it set to “none”. Other possible values are “required” and “requiresnew”.
Step 2: The Controller
Next, we need a controller. Create a file called whitepapers.get.js with the following content:
<import resource="classpath:alfresco/extension/scripts/rating.js">
var whitepapers = search.luceneSearch("PATH:\\"/{http://www.alfresco.org/model/application/1.0}company\_home/{http://www.alfresco.org/model/content/1.0}Someco\\" +TYPE:\\"{[http://www.someco.com/model/content/1.0](http://www.someco.com/model/content/1.0)}whitepaper\\"");
if (whitepapers == null || whitepapers.length == 0) {
logger.log("No whitepapers found");
status.code = 404;
status.message = "No whitepapers found";
status.redirect = true;
} else {
var whitepaperInfo = new Array();
for (i = 0; i \< whitepapers.length; i++) {
var whitepaper = new whitepaperEntry(whitepapers[i],
getRating(whitepapers[i]));
whitepaperInfo[i] = whitepaper;
}
model.whitepapers = whitepaperInfo;
}
function whitepaperEntry(whitepaper, rating) {
this.whitepaper = whitepaper;
this.rating = rating;
}
The first thing to notice about the script is that we're importing another script. The rating.js script was created as part of the last article to contain logic used to calculate the average rating. The idea here is that retrieving a rating is also business logic related to a rating, so it should reside in the rating.js file as well. This makes it easy for us to reuse that logic in other scripts. We'll see the updated version of the rating.js script momentarily. (The ability to import a script from another script was added with release 2.1. The import tag is not native to the Rhino JavaScript implementation).
The next thing to notice is that the script queries the repository using Lucene to get a list of whitepapers. Look at what happens if there are no whitepapers found. The response code gets set to 404 which is the standard HTTP response code for “File not found”. Alfresco has a standard response template for error codes but you can override it with your own by creating FreeMarker templates that follow a specific naming convention. For example, we could have a custom 404 response template for whitepapers by creating a file called whitepapers.get.html.404.ftl. See the Alfresco wiki for more information.
The last thing that happens is that we build a new Array for our results. I could just set model.whitepapers equal to the whitepapers variable that contains the query results but I want to add some data to the result set, so I'm building a new Array and setting that to the model. (I know the average rating is a property of a whitepaper, so it may not yet be obvious why I have a separate function for retrieving the rating or why I would store the rating in the model separate from the whitepaper. Trust that it will make sense later).
Remember that our controller imports a script called rating.js. This script resides in our classpath but the import tag also supports including scripts that reside in the repository. If you still have rating.js around from the custom behaviors article, the difference between it and this one is a new function called getRating as shown below:
function getRating(curNode) {
var rating = {};
rating.average = curNode.properties["{http://www.someco.com/model/content/1.0}averageRating"];
rating.count = curNode.properties["{http://www.someco.com/model/content/1.0}ratingCount"];
return rating;
}
The function simply retrieves the averageRating and ratingCount properties from the specified node and returns them in a rating object. The full source for rating.js is in the accompanying source code.
Step 3: The view
Assuming there are items in the search results, we'll need FreeMarker templates to process them. Let's create the HTML response template first. Create a new file called whitepapers.get.html.ftl with the following content:
<#assign datetimeformat="EEE, dd MMM yyyy HH:mm:ss zzz">

Whitepapers

<#list whitepapers as child>

Name
${child.whitepaper.properties.name}

Title
${child.whitepaper.properties["cm:title"]}

Link
${url.context}${child.whitepaper.url}

Type
${child.whitepaper.mimetype}

Size
${child.whitepaper.size}

Id
${child.whitepaper.id}

Description

<#if child.whitepaper.properties["cm:description"]?exists
&& child.whitepaper.properties["cm:description"] !=
"">${child.whitepaper.properties["cm:description"]}</#if>

Pub Date
${child.whitepaper.properties["cm:modified"]?string(datetimeformat)}

Rating

Average
${child.rating.average}

Count
${child.rating.count}

<#if !(child.whitepaper == whitepapers?last.whitepaper)>

</#if>
</#list>

This template iterates through the query results passed in by the controller, and builds an HTML table with properties of each whitepaper. (Yes, the table is ugly. Yes, you could use CSS to spruce it up tremendously or even remove the table entirely. But for SomeCo, this response template is really for debugging purposes only and I didn't want to fool with the CSS so a table it is).
The last thing we have to do before we test the web script is create the JSON response template. Create a file called whitepapers.get.json.ftl with the following content:
<#assign datetimeformat="EEE, dd MMM yyyy HH:mm:ss zzz">
{"whitepapers" : [
<#list whitepapers as child>
{
"name" : "${child.whitepaper.properties.name}",
"title" : "${child.whitepaper.properties["cm:title"]}",
"link" : "${url.context}${child.whitepaper.url}",
"type" : "${child.whitepaper.mimetype}",
"size" : "${child.whitepaper.size}",
"id" : "${child.whitepaper.id}",
"description" : "<#if child.whitepaper.properties["cm:description"]?exists && child.whitepaper.properties["cm:description"] != "">${child.whitepaper.properties["cm:description"]}</#if>",
"pubDate" : "${child.whitepaper.properties["cm:modified"]?string(datetimeformat)}",
"rating" : {
"average" : "${child.rating.average}",
"count" : "${child.rating.count}",
}
}
<#if !(child.whitepaper == whitepapers?last.whitepaper)>,</#if>
</#list>
]
}
Again, just like the HTML response template, the script iterates through the result set but this one outputs JSON. The JSON structure is completely arbitrary.
Assuming you have some test data in your repository (Someco Whitepaper objects in your Someco/Whitepapers folder) you should be able to refresh the web script list and run the web script. Because we told Alfresco that this script requires Guest access or higher, you'll need to either log in to Alfresco before running the script, authenticate with a valid user and password when the basic authentication dialog is presented, or append “&guest=true” to the URL like this: http://localhost:8080/alfresco/service/someco/whitepapers.html&guest=true. If you forget the “.html” you'll get a JSON response because we set that to the default.
If all goes well you should see something similar to the figure below:
Debugging
Did it work? If not, it's time to debug. The first thing you're going to want to do is to go into log4j.properties and set log4j.logger.org.alfresco.repo.jscript to DEBUG. This will cause any logger.log statements in your controller to write to catalina.out.
Another tool you'll want to leverage is the web script list. You can use it to see (1) if Alfresco knows about your script and (2) the version of the scripts the run-time knows about. For example, you can go to http://localhost:8080/alfresco/service/script/com/someco/whitepapers/whitepapers.get and Alfresco will dump the descriptor and all of the response templates.
The Node Browser can be helpful to debug problems as well. In this case, for example, we're running a Lucene query in our JavaScript. If the controller isn't finding any whitepapers even though you've created test data, try executing the query in the Node Browser. If it doesn't return results, there's something wrong with your test data.
Retrieving the Rating for a Whitepaper
Getting a specific rating is roughly the same as getting a whitepaper but it is a bit easier because of our existing getRating function in rating.js. All the controller has to do is grab the ID argument, locate the node, then call getRating as shown below:
<import resource="classpath:alfresco/extension/scripts/rating.js"\>
if (args.id == null || args.id.length == 0) {
logger.log("ID arg not set");
status.code = 400;
status.message = "Node ID has not been provided";
status.redirect = true;
} else {
logger.log("Getting current node");
var curNode = search.findNode("workspace://SpacesStore/" + args.id);
if (curNode == null) {
logger.log("Node not found");
status.code = 404;
status.message = "No node found for id:" + args.id;
status.redirect = true;
} else {
model.rating = getRating(curNode, args.user);
}
}
The descriptor and response templates are very similar to the whitepaper example so I won't include them here. After we get the post in place, we'll revisit the HTML response template by making some updates that help us test.
For now, here's what a successful JSON call to the rating service returns:
{"rating" :
{
"average" : "1.923",
"count" : "13",
}
}
Posting a Rating with a Java-backed Web Script
Before we talk about the POST web script we should talk about authentication. All of our /someco scripts require Guest access or higher. That means we either have to have an active session already established, we have to append “&guest=true” to the URL, or we have to login when the browser presents us with a basic authentication dialog. (Another option is to get a ticket from a web service call, but that's not in the scope of this article).
SomeCo doesn't want to open up write access to the /Someco/Whitepapers folder to Guest users who might try to access the repository via the web client so that means we need a real user account in order to write new rating objects. We could use “user” authentication for the POST but SomeCo doesn't want to set up user accounts for every user that might rate content.
The solution is to let Guest call the POST URL but leverage the Alfresco Java API to “run as” a different user. (In our case we'll use admin but a user account dedicated to the purpose of creating ratings is probably a better idea). The post logic will reside in a Java Bean rather than a server-side JavaScript file.
The descriptor and the response templates look like the examples we've seen so far so I won't repeat them here. Take a look at the accompanying source code if you are curious.
The piece that is new is the use of Java as the controller so let's spend some time on that. We'll implement this Java-backed web script in three steps. The first step is to write the business logic for creating the rating. Just like when we put the business logic in the rating.js file to promote reuse, we're going to use the Rating bean we created in the previous article for the new create() method. The second step is to write the Java bean that functions as our controller. The third step is to configure the controller bean via Spring so that Alfresco knows to invoke it when the web script is called.
Step 1: Business logic
Add the following method to the com.someco.behavior.Rating class we created in the previous article.
public void create(NodeRef nodeRef, int rating, String user) {
boolean switchUser = false;
String currentUser = AuthenticationUtil.getCurrentUserName();
if (!currentUser.equals("admin")) {
logger.debug("Current user is not admin so switching to admin");
AuthenticationUtil.setCurrentUser("admin");
switchUser = true;
}
UserTransaction txn = transactionService.getUserTransaction();
try {
txn.begin();
// add the aspect to this document if it needs it
if (nodeService.hasAspect(nodeRef,
Qname.createQName(SomeCoModel.NAMESPACE_SOMECO_CONTENT_MODEL,
SomeCoModel.ASPECT_SC_RATEABLE))) {
logger.debug("Document already has aspect");
} else {
logger.debug("Adding rateable aspect");
nodeService.addAspect(nodeRef,
Qname.createQName(SomeCoModel.NAMESPACE_SOMECO_CONTENT_MODEL,
SomeCoModel.ASPECT_SC_RATEABLE), null);
}
Map<QName, Serializable> props = new HashMap<QName,
Serializable>();
props.put(QName.createQName(SomeCoModel.NAMESPACE_SOMECO_CONTENT_MODEL,
"rating"), rating);
props.put(QName.createQName(SomeCoModel.NAMESPACE_SOMECO_CONTENT_MODEL,
"rater"), user);
nodeService.createNode(nodeRef,
Qname.createQName(SomeCoModel.NAMESPACE_SOMECO_CONTENT_MODEL,
SomeCoModel.ASSN_SC_RATINGS),
Qname.createQName(SomeCoModel.NAMESPACE_SOMECO_CONTENT_MODEL,
"rating" + new Date().getTime()),
Qname.createQName(SomeCoModel.NAMESPACE_SOMECO_CONTENT_MODEL,
SomeCoModel.TYPE_SC_RATING), props);
txn.commit();
} catch(Throwable e) {
try {
if (txn.getStatus() == Status.STATUS_ACTIVE) txn.rollback();
} catch (Throwable ee) {
e.printStackTrace();
}
}
if (switchUser) AuthenticationUtil.setCurrentUser(currentUser);
}
This is a bit painful to look at but basically what's going on is:
- If the current user is not admin, the current user is set to admin
- A new transaction is started
- If the node doesn't yet have the rateable aspect, it is added
- The rating and rater properties are set
- The transaction is committed
- If the current user was switched to admin, the current user is switched back to whomever it was before the switch to admin
Step 2: Web script controller bean
With the create() method in place, all we have to do is write a Java class that grabs the id, rating, and rater arguments and calls the method. To do that, create a new class called com.someco.scripts.PostRating. The class name isn't significant but it seems like following some sort of descriptive convention could be helpful here if there are a large number of Java-backed scripts. The class needs to extend org.alfresco.webscripts.DeclarativeWebScript. Our logic goes in executeImpl as shown below.
public class PostRating extends
org.alfresco.web.scripts.DeclarativeWebScript {
Logger logger = Logger.getLogger(PostRating.class);
private Rating ratingBean;
@Override
protected Map<String, Object> executeImpl(WebScriptRequest req,
WebScriptStatus status) {
String id = req.getParameter("id");
String rating = req.getParameter("rating");
String user = req.getParameter("user");
if (id == null || rating == null || rating.equals("0") ||
user == null) {
logger.debug("ID, rating, or user not set");
status.jsSet_code(400);
status.jsSet_message("Required data has not been provided");
status.jsSet_redirect(true);
} else {
NodeRef curNode = new NodeRef("workspace://SpacesStore/" + id);
if (curNode == null) {
logger.debug("Node not found");
status.jsSet_code(404);
status.jsSet_message("No node found for id:" + id);
status.jsSet_redirect(true);
} else {
ratingBean.create(curNode, Integer.parseInt(rating), user);
}
}
Map<String, Object> model = new HashMap<String, Object>();
model.put("node", id);
model.put("rating", rating);
model.put("user", user);
return model;
}
public Rating getRatingBean() {
return ratingBean;
}
public void setRatingBean(Rating ratingBean) {
this.ratingBean = ratingBean;
}
}
This code should look strikingly similar to a JavaScript controller and in fact it does the same thing. It checks the arguments, sets an error code if the arguments are missing, and then writes some data to the model.
The controller gets the Rating class through Spring dependency injection. We'll configure that in our Spring config, which is the next step.
Step 3: Spring config for the Web script controller bean
The following shows the contents of someco-scripts-context.xml. The name of the file isn't important, but it must end with *context.xml.
<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC '-//SPRING//DTD BEAN//EN' 'http://www.springframework.org/dtd/spring-beans.dtd'>
<beans>
<bean id="webscript.com.someco.ratings.rating.post" class="com.someco.scripts.PostRating" parent="webscript">
<property name="ratingBean">
<ref bean="ratingBehavior" />
</property>
</bean>
</beans>
This should look like any other Spring bean config file you've seen. The web script magic is in the id and parent attributes. The id follows a naming convention. The convention is:
webscript.package.service-id.method
Pay close attention to the use of the singular “webscript” here versus the plural “webscripts” in the Data Dictionary folders. That's a potential multi-hour debugging session ending in a forehead slap with a “Doh!” if you aren't careful.
It is probably worth mentioning that a decision to use a Java-backed web script doesn't exclude the use of JavaScript for that web script. If you have both a Java class and a JavaScript file, the Java class gets executed first followed by the JavaScript. The script has access to everything the Java class put in the model and can update the model before passing it along to the response template.
Revisiting the rating.get.html.ftl template
Now we have everything we need in place but we don't have a great way to test the rating POST. So, what we'll do is add a little rating widget[^0^](#sdfootnote2sym) to the rating.get.html.ftl template. A simple link would do but I wanted to test out the widget before incorporating it into a real page.
First, let's see what it looks like when we call /someco/rating.html/id=someid. The figure below shows a call when the whitepaper node has 13 ratings and an average of 1.923.
The purpose of the rating widget is two-fold. First, it graphically displays the average rating for a whitepaper. Second, each star in the widget is hot. So when you click one of the rating stars, an asynchronous post is made to /someco/rating which causes a new rating object to get created. The rating posted depends on the star clicked. The person submitting the rating would normally be passed in based on some sort of credential, maybe from a portal session or a cookie. In our little test, the rater gets pulled from the field.
Let's look at HTML first, then some of the JavaScript:

Back
to the list of whitepapers

Node: ${args.id}

Average: ${rating.average}

# of Ratings: ${rating.count}

<form name="login">
Rater:<input name="userId"></input>
</form>
Rating:
${rating.average}

This is all basic HTML/FreeMarker stuff you've seen before. The last line sets up a div for the ratings widget. The id of the div uses the node ref of the whitepaper. This allows multiple ratings widgets to be on the same page and makes it easy for the JavaScript to pass the node ref on to the /someco/rating URL.
The second piece is the JavaScript. I'm going to omit some of the less interesting functions and just show the functions related to posting ratings. The accompanying source code has the full source.
function submitRating(evt) {
var tmp = Event.element(evt).getAttribute('id').substr(5);
var widgetId = tmp.substr(0, tmp.indexOf('\_'));
var starNbr = tmp.substr(tmp.indexOf('\_')+1);
alert("Post to URL:" + widgetId + "," + starNbr);
if (document.login.userId.value != undefined &&
document.login.userId.value != "") {
curUser = document.login.userId.value;
} else {
curUser = "jpotts";
}
postRating(widgetId, starNbr, curUser);
}
function postRating(id, rating, user) {
if (receiveReq.readyState == 4 || receiveReq.readyState == 0) {
receiveReq.open("POST", "/alfresco/service/someco/rating?id=" + id +
"&rating=" + rating + "&guest=true&user=" + user, true);
receiveReq.onreadystatechange = handleRatingPosted;
receiveReq.send(null);
}
}
function handleRatingPosted() {
if (receiveReq.readyState == 4) {
alert("Post successful");
}
}
Those of you familiar with AJAX techniques may be wondering why I didn't use Prototype to make the post since I was already using it with the rating widget. I had trouble getting Prototype to play nicely with the Web Script Framework. For some reason the arguments weren't getting recognized. So I punted and used the lower-level XMLHttpRequest. You'll also notice that I don't dynamically update the rating or re-init the widget after the successful post. My only excuse for that one is laziness.
Deleting ratings
Setting up a web script for delete is similar to the GET for ratings. The descriptor is named rating.delete.desc.xml. I set mine to require “admin” authentication. It seems rare that you would want to delete all ratings for a given node but highly likely that if you are going to expose it, it should be for admins only.
As in previous examples, the controller JavaScript reads and checks the arguments then calls a function. In this case it is the deleteRatings function that has been added to rating.js. The body of the function is:
function deleteRatings(curNode) {
// check the parent to make sure it has the right aspect
if (curNode.hasAspect("{http://www.someco.com/model/content/1.0}rateable")) {
// continue, this is what we want
} else {
logger.log("Node did not have rateable aspect.");
return;
}
// get the node's children
var children = curNode.children;
if (children != null && children.length \> 0) {
logger.log("Found children...iterating");
for (i in children) {
var child = children[i];
logger.log("Removing child: " + child.id);
child.remove();
}
}
}
The script bails if the node doesn't have the rateable aspects (because there wouldn't be any ratings). Otherwise, it grabs the children and deletes them. Note the important assumption that the only children that exist are ratings. If there's a possibility of other child associations, you'd obviously want to be more discriminating.
Example summary
We've implemented two GET scripts (one for whitepapers and one for rating), a POST script for creating new ratings, and a DELETE for clearing out ratings. At this point SomeCo has everything they need for building a front-end that talks to the Alfresco repository via REST. One piece of functionality I didn't show, but I've included in the source, is the ability for an optional “user” argument to be passed in to the two GET scripts. When present, the script will return the last rating for the specified user. I'll leave it to you to follow the source to figure out how that works.
Dealing with the cross-domain scripting limitation
You may have noticed that in all of my URL examples, I'm using localhost. In fact, the static HTML pages (whitepaper index and whitepaper detail) that make AJAX calls are also on localhost. I did this to simplify the example but in real life, it is highly likely that the code making an AJAX call to your web script will reside on a different host than the one where Alfresco lives. This creates a problem called the “cross-domain scripting limitation”. The issue is that for security reasons browsers don't let you open an XMLHttpRequest to a different host than the one serving the page. There are a few ways you can handle this depending on your situation.
- Use script tags. One way to work around the problem is to use a script tag in which the src attribute points to a location on a different host. The browser thinks it is loading a JavaScript file but what it is really doing is calling your web script which returns JSON. The script tags can be output dynamically through document.write.
- Use a proxy. Servers aren't subject to the browser's security constraints. You can easily write your own Java servlet that acts as a reverse proxy. AJAX calls go against the proxy and pass in the “real” URL as an argument. The servlet then invokes the URL and returns the results.
 Alfresco claims to have a callback mechanism built in to the web script run-time. The way it is supposed to work is that you pass in a function name as an argument to the web script like “&alf_callback=someFunction”. The function is supposed to get called when the page is loaded. I couldn't get it working and ended up filing a Jira ticket.
- Deploy everything to the same server. This is the least likely scenario to work in a production implementation but it's the one I chose for this article so we wouldn't have to spend a lot of time on the issue. The scripts and images the ratings widget depends on reside in someco/javascript and someco/images, respectively, under the Alfresco web root. The whitepaper index and whitepaper details pages I used for the screenshots at the beginning of the article are enhanced copies of the files used for the Optaros web site deployed to the ROOT web application folder.
Deploying and Testing
To run the sample as-is, all you have to do is:
- Import the web-script-article-project.zip file into Eclipse.
- Change build.properties to match your environment.
- Run the default Ant task.
The default Ant task will compile all necessary code, JAR it up, zip up the JAR and the extensions into the appropriate folder structure, and then unzip on top of the Alfresco web root which deploys the custom model, Spring config files, web client customizations, scripts, web scripts, and the images and JavaScript for the rating.get.html page to the appropriate directories.
After an error-free start up, create Someco/Whitepapers in your Company Home and upload a couple of test whitepapers. Upload and execute the addTestRating.js script in the context of each test whitepaper to create test rating objects.
You should then be able to run any of the web scripts identified in this article without any problems.
In case you are curious, my environment is:
- Ubuntu Dapper Drake
- MySQL 4.1 (with version 5.0.3 of the JDBC driver)
- Java 1.5.0_12
- Tomcat 5.5.x
- Alfresco 2.1.0 Enterprise, WAR-only distribution
Obviously, other operating systems, databases, and application servers will work as well. Web Scripts, however, only work starting with Alfresco 2.1.
Conclusion
This article has given you an introduction to the Alfresco Web Script Framework. We began with a very simple Hello World script and then gradually moved to more complex examples which culminated in a REST API for retrieving whitepapers, getting the average rating for a specific whitepaper, posting new ratings for a given whitepaper, and deleting all ratings for a specific whitepaper. We used both JavaScript and Java to implement controller logic. We used FreeMarker to output HTML as well as JSON. We saw some options for working around the cross-domain scripting limitation.
There are still topics left to explore. One example is using Web Scripts to integrate a portal like Liferay or JBoss Portal with Alfresco. Another is Microsoft Office-Alfresco integration which is based on Web Scripts. And what about using Web Scripts to customize the Web Client user interface? Hopefully, you've been inspired enough to take a look at those topics on your own. Maybe you'll even blog about your experience. If so, or if you have any other feedback, please let me know. I'd love to hear from you.
Where to find more information
- The complete source code that accompanies this article is available here from ecmarchitect.com.
- You may also enjoy previous articles in the Alfresco Developer series at ecmarchitect.com:
- “Implementing custom behaviors”, September, 2007.
- “Working with Custom Content Types”, June, 2007.
- “Developing custom actions”, January, 2007.
- Alfresco wiki pages related to this topic:
- Alfresco Web Scripts wiki page
- Alfresco Web Script Runtimes wiki page
- Alfresco JavaScript API wiki page
- Alfresco Template Guide (FreeMarker info) wiki page
- For deployment help, see the Client Configuration Guide and Packaging and Deploying Extensions in the Alfresco wiki.
- For general development help, see the Developer Guide.
- For help customizing the data dictionary, see the Data Dictionary wiki page.
- Luis Sala's presentation on Web Scripts at the West Coast Alfresco+Liferay Meetup along with a podcast of the audio portion of the presentation is available at Luis' Fresh Talk blog.
- Learn more about JSON at json.org and FreeMarker at freemarker.sourceforge.net.
- The jMaki Project is a framework for building Ajax-enabled, Java web applications. Included as part of it is a proxy you can use to work around the cross-domain scripting limitation if you don't want to write your own.
- The JSR-168 Portlet Specification is available on the Java Community Process site.
Footnotes
1It isn't required that you use the “Web Scripts Extensions” folder in the repository. I did it because it seemed consistent with how web client customizations are deployed (using the alfresco/extension folder). Web scripts placed in the “Web Scripts Extensions” folder that have the same file names as those in the “Web Scripts” folder will override the scripts stored in “Web Scripts”. For this reason, if you want others to be able to override your scripts, use the “Web Scripts” folder rather than “Web Scripts Extensions”. See the Alfresco wiki for more on web script folder search order.
2I used the code at http://www.progressive-coding.com/tutorial.php?id=6 as the starting point for the rating widget. Most of it is unchanged with the exception of changing the ratings from being 0-indexed to being 1-indexed and following the author's instructions to hook the widget into the page using Prototype which I already happened to have lying around.


Main Page
|
Namespace List
|
Class Hierarchy
|
Class List
|
File List
|
Namespace Members
|
Class Members
|
File Members
|
Related Pages
mr::basis Namespace Reference
Enumerations
enum
type
{
kLinear
= 0,
kHermite
,
kCatmullRom
,
kBezier
,
kBSpline
,
kBspline
= kBSpline,
kPower
,
kUnknown
}
Types of spline basis that can be used.
More...
Enumeration Type Documentation
enum
mr::basis::type
Types of spline basis that can be used.
Enumeration values:
kLinear
kHermite
kCatmullRom
kBezier
kBSpline
kBspline
kPower
kUnknown
Generated on Sun Feb 22 18:29:29 2004 for mrClasses by
1.3.5


Equivalent to clicking the Subtotal command on the Data menu, and then clicking the Remove All button in the Subtotal dialog box. Removes all previously existing subtotals and grand totals in a list. Any page breaks and outlines will also be removed.
Syntax
SUBTOTAL.REMOVE()
Related Function
SUBTOTAL.CREATE Generates a subtotal in a list or database
Return to index


Set payment priority order
The training provider listed first will be paid first from your available funds.
- 1.
- 2.
- 3.
- 4.
- 5.
- Provider Orange
- Provider Purple
- Provider Red
- Provider Green
- Provider Yellow
Help with reset
Reset will return your list to a default order.


Arrays returned from paginating finds are, in fact, instances of this little class. You may think of WillPaginate::Collection as an ordinary array with some extra properties. Those properties are used by view helpers to generate correct page links.
WillPaginate::Collection also assists in rolling out your own pagination solutions: see create.
If you are writing a library that provides a collection which you would like to conform to this API, you don’t have to copy these methods over; simply make your plugin/gem dependant on this library and do:
require 'will_paginate/collection' # WillPaginate::Collection is now available for use
Just like new, but yields the object after instantiation and returns it afterwards. This is very useful for manual pagination:
@entries = WillPaginate::Collection.create(1, 10) do |pager| result = Post.find(:all, :limit => pager.per_page, :offset => pager.offset) # inject the result array into the paginated collection: pager.replace(result) unless pager.total_entries # the pager didn't manage to guess the total count, do it manually pager.total_entries = Post.count end end
The possibilities with this are endless. For another example, here is how WillPaginate used to define pagination for Array instances:
Array.class_eval do def paginate(page = 1, per_page = 15) WillPaginate::Collection.create(page, per_page, size) do |pager| pager.replace self[pager.offset, pager.per_page].to_a end end end
The Array#paginate API has since then changed, but this still serves as a fine example of WillPaginate::Collection usage.
# File lib/will_paginate/collection.rb, line 83 def self.create(page, per_page, total = nil) pager = new(page, per_page, total) yield pager pager end
Arguments to the constructor are the current page number, per-page limit and the total number of entries. The last argument is optional because it is best to do lazy counting; in other words, count conditionally after populating the collection using the replace method.
# File lib/will_paginate/collection.rb, line 47 def initialize(page, per_page, total = nil) @current_page = page.to_i raise InvalidPage.new(page, @current_page) if @current_page < 1 @per_page = per_page.to_i raise ArgumentError, "`per_page` setting cannot be less than 1 (#{@per_page} given)" if @per_page < 1 self.total_entries = total if total end
current_page + 1 or nil if there is no next page
# File lib/will_paginate/collection.rb, line 110 def next_page current_page < total_pages ? (current_page + 1) : nil end
Current offset of the paginated collection. If we’re on the first page, it is always 0. If we’re on the 2nd page and there are 30 entries per page, the offset is 30. This property is useful if you want to render ordinals side by side with records in the view: simply start with offset + 1.
# File lib/will_paginate/collection.rb, line 100 def offset (current_page - 1) * per_page end
Helper method that is true when someone tries to fetch a page with a larger number than the last page. Can be used in combination with flashes and redirecting.
# File lib/will_paginate/collection.rb, line 92 def out_of_bounds? current_page > total_pages end
current_page - 1 or nil if there is no previous page
# File lib/will_paginate/collection.rb, line 105 def previous_page current_page > 1 ? (current_page - 1) : nil end
This is a magic wrapper for the original Array#replace method. It serves for populating the paginated collection after initialization.
Why magic? Because it tries to guess the total number of entries judging by the size of given array. If it is shorter than per_page limit, then we know we’re on the last page. This trick is very useful for avoiding unnecessary hits to the database to do the counting after we fetched the data for the current page.
However, after using replace you should always test the value of total_entries and set it to a proper value if it’s nil. See the example in create.
# File lib/will_paginate/collection.rb, line 132 def replace(array) result = super # The collection is shorter then page limit? Rejoice, because # then we know that we are on the last page! if total_entries.nil? and length < per_page and (current_page == 1 or length > 0) self.total_entries = offset + length end result end
sets the total_entries property and calculates total_pages
# File lib/will_paginate/collection.rb, line 115 def total_entries=(number) @total_entries = number.to_i @total_pages = (@total_entries / per_page.to_f).ceil end
Generated with the Darkfish Rdoc Generator 2.


 It is likely you will see someone you know. Do you agree to keep their identity secret?
The women on this site are not at all interested in a "relationship" and are only looking to fuck. Are you OK with this request?

Are you 24 years of age or older? The women on this site are not interested in men younger than that due to rude and immature behavior in the past.
Congratulations!
You have qualified to enter our site. Please click Continue to
complete the registration process.
VERY IMPORTANT! Remember you must keep the identities of
women you see on here a secret.


| Rows | |
| Columns | |
| Geometry | |
| Rows | |
| Columns | |
| Geometry | |
This webpage provides a sandbox to play with sandpiles. Sandpiles were the 90th activity in Annie Perkins' Math Art Challenge.
In a sandpile, each cell has a certain number of grains of sand in it. A cell is unstable if it has more than three grains (more generally, at least as many grains as neighbours). An unstable cell can topple, whereupon it gives one grain to each of its neighbours.
This implementation is slightly different to how sandpiles work in the literature as I slightly misunderstood the instructions. In the literature, a "turn" consists of a single cell toppling. Although on a given turn there is a choice, in the long run then the order of choices doesn't matter.
In my version, however, on a given turn then every cell that is currently unstable topples. This can lead to a different type of long term behaviour. In particular, it makes sense to consider periodic long term behaviour.
With pretty much anything mathematical on a grid I find myself asking "What does this look like on a torus?", shortly followed by a Klein bottle and a projective plane. This determines what happens when cells on the edge topple. The options are: