<?xml version="1.0"?>
<News hasArchived="true" page="8889" pageCount="10801" pageSize="10" timestamp="Wed, 09 Sep 2026 16:42:16 -0400" url="https://my3.my.umbc.edu/posts.xml?mode=activity&amp;page=8889&amp;range=30">
<NewsItem contentIssues="false" id="123343" important="false" status="posted" url="https://my3.my.umbc.edu/posts/123343">
<Title>Thomas Schaller, Political Science, in Governing Magazine</Title>
<Body>
<![CDATA[
    <div class="html-content">
    <p><a href="/wp-content/uploads/2012/08/tom-schaller-11.jpg" rel="nofollow external" class="bo"><img alt="Tom Schaller" src="/wp-content/uploads/2012/08/tom-schaller-11.jpg?w=300" width="178" height="119" style="max-width: 100%; height: auto;"></a>Thomas F. Schaller, professor of political science at UMBC, offers his expertise on Maryland politics in a new <em>Governing Magazine</em> article that asks <a href="http://www.governing.com/blogs/politics/gov-states-deepening-nations-red-blue-divide.html" rel="nofollow external" class="bo">“Are the States Deepening the Nation’s Red-Blue Divide?”</a></p>
    <p>The article explores how the expansion of unified party control and legislative supermajorities at the state level are impacting policymaking, examining what policies are being approved in strongly Republican and strongly Democratic states.</p>
    <p>The article identifies Maryland as a Democratic state that has taken a turn to the left with recent legislation on assault weapons, education, same-sex marriage and the death penalty. “Maryland is getting bluer in election results,” says Schaller; conveying that Maryland’s GOP has become increasingly marginalized.</p>
    </div>
]]>
</Body>
<Summary>Thomas F. Schaller, professor of political science at UMBC, offers his expertise on Maryland politics in a new Governing Magazine article that asks “Are the States Deepening the Nation’s Red-Blue...</Summary>
<Website>https://umbc.edu/stories/thomas-schaller-political-science-in-governing-magazine/</Website>
<TrackingUrl>https://my3.my.umbc.edu/api/v0/pixel/news/123343/guest@my.umbc.edu/f5e667d7af0e5292334807fc52669062/api/pixel</TrackingUrl>
<Tag>cahss</Tag>
<Tag>policy-and-society</Tag>
<Tag>politicalscience</Tag>
<Group token="umbc-news-magazine">UMBC News &amp;amp; Magazine</Group>
<GroupUrl>https://my3.my.umbc.edu/groups/umbc-news-magazine</GroupUrl>
<AvatarUrl>https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xsmall.png?1748556657</AvatarUrl>
<AvatarUrl size="original">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/original.png?1748556657</AvatarUrl>
<AvatarUrl size="xxlarge">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xxlarge.png?1748556657</AvatarUrl>
<AvatarUrl size="xlarge">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xlarge.png?1748556657</AvatarUrl>
<AvatarUrl size="large">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/large.png?1748556657</AvatarUrl>
<AvatarUrl size="medium">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/medium.png?1748556657</AvatarUrl>
<AvatarUrl size="small">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/small.png?1748556657</AvatarUrl>
<AvatarUrl size="xsmall">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xsmall.png?1748556657</AvatarUrl>
<AvatarUrl size="xxsmall">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xxsmall.png?1748556657</AvatarUrl>
<Sponsor>UMBC News &amp; Magazine</Sponsor>
<PawCount>0</PawCount>
<CommentCount>0</CommentCount>
<CommentsAllowed>false</CommentsAllowed>
<PostedAt>Thu, 25 Apr 2013 19:00:25 -0400</PostedAt>
</NewsItem>

<NewsItem contentIssues="false" id="123344" important="false" status="posted" url="https://my3.my.umbc.edu/posts/123344">
<Title>Donald Norris, Public Policy, in the Washington Post</Title>
<Body>
<![CDATA[
    <div class="html-content">
    <p>Yesterday’s allegations that state prison guards helped a gang operate a contraband smuggling scheme from behind bars at the Baltimore City Detention Center are prompting strong responses from Maryland lawmakers. While Sen. Brian E. Frosh said the O’Malley administration deserves credit for its role in a “very bold, aggressive and appropriate” prosecution, Del. Curtis S. Anderson called the indictments “just horrific” and asked for further explanation from the governor.</p>
    <p><a href="/wp-content/uploads/2012/09/donald-norris-umbc.jpg" rel="nofollow external" class="bo"><img alt="Donald Norris UMBC" src="/wp-content/uploads/2012/09/donald-norris-umbc.jpg" width="140" height="126" style="max-width: 100%; height: auto;"></a>Donald F. Norris, professor and chair of public policy at UMBC, <a href="http://www.washingtonpost.com/local/md-politics/maryland-prison-indictments-prompt-anger-some-understanding-from-lawmakers/2013/04/24/a0644f86-acee-11e2-a198-99893f10d6dd_story.html" rel="nofollow external" class="bo">told the <em>Washington Post</em></a> that any political fallout from the episode for O’Malley, who is considering a 2016 presidential bid, will likely be determined by “how he handles this, whether he gets out in front of it.” Norris notes, “If the state were riddled with incompetence and corruption, that’d be one thing, but it’s not. … This kind of thing happens in all prison systems, though maybe not this flagrant.”</p>
    </div>
]]>
</Body>
<Summary>Yesterday’s allegations that state prison guards helped a gang operate a contraband smuggling scheme from behind bars at the Baltimore City Detention Center are prompting strong responses from...</Summary>
<Website>https://umbc.edu/stories/donald-norris-public-policy-in-the-washington-post-3/</Website>
<TrackingUrl>https://my3.my.umbc.edu/api/v0/pixel/news/123344/guest@my.umbc.edu/86d8ede40138c5abb11bd011e3675a4c/api/pixel</TrackingUrl>
<Tag>cahss</Tag>
<Tag>policy-and-society</Tag>
<Tag>publicpolicy</Tag>
<Group token="umbc-news-magazine">UMBC News &amp;amp; Magazine</Group>
<GroupUrl>https://my3.my.umbc.edu/groups/umbc-news-magazine</GroupUrl>
<AvatarUrl>https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xsmall.png?1748556657</AvatarUrl>
<AvatarUrl size="original">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/original.png?1748556657</AvatarUrl>
<AvatarUrl size="xxlarge">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xxlarge.png?1748556657</AvatarUrl>
<AvatarUrl size="xlarge">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xlarge.png?1748556657</AvatarUrl>
<AvatarUrl size="large">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/large.png?1748556657</AvatarUrl>
<AvatarUrl size="medium">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/medium.png?1748556657</AvatarUrl>
<AvatarUrl size="small">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/small.png?1748556657</AvatarUrl>
<AvatarUrl size="xsmall">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xsmall.png?1748556657</AvatarUrl>
<AvatarUrl size="xxsmall">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xxsmall.png?1748556657</AvatarUrl>
<Sponsor>UMBC News &amp; Magazine</Sponsor>
<PawCount>0</PawCount>
<CommentCount>0</CommentCount>
<CommentsAllowed>false</CommentsAllowed>
<PostedAt>Thu, 25 Apr 2013 18:38:42 -0400</PostedAt>
</NewsItem>

<NewsItem contentIssues="false" id="123345" important="false" status="posted" url="https://my3.my.umbc.edu/posts/123345">
<Title>For All the World to Hear to Present at AAM Meeting</Title>
<Body>
<![CDATA[
    <div class="html-content">
    <p><a href="/wp-content/uploads/2013/03/fatwth-in-afro-american-28-feb-2013.jpg" rel="nofollow external" class="bo"><img alt="FATWTH in Afro-American 28 Feb 2013" src="/wp-content/uploads/2013/03/fatwth-in-afro-american-28-feb-2013.jpg?w=150" width="150" height="144" style="max-width: 100%; height: auto;"></a><em>For All The World to Hear: Stories from the Struggle for Civil Rights</em>, an oral history, outreach project of the CADVC, will present the session “Storytelling from Page to Stage: An Oral History Community Project” at the American Alliance of Museums’ (AAM) annual Meeting and Museum Expo.</p>
    <p>The session, scheduled for Monday, May 20 from 1:45-3:00 p.m. in the Baltimore Convention Center, will tell the tale of the creation and production of <em>For All the World to Hear.</em> Harriet Lynn, director of the project, Sandra Abbott, CADVC, producer of <em>For All the World to Hear</em>, and Carrie Rennolds, graduate student, will present alongside participants in the project, who will share stories of their experience before and during the American civil rights movement.</p>
    <p>Learn more about the session at the AAM article, <a href="http://www.aam-us.org/events/annual-meeting/annual-meeting-theme" rel="nofollow external" class="bo">“2013 AAM Annual Meeting Theme: The Power of Stor</a><a href="http://www.aam-us.org/events/annual-meeting/annual-meeting-theme" rel="nofollow external" class="bo">y,”</a> or visit <a href="http://foralltheworldtohear.org" rel="nofollow external" class="bo">foralltheworldtohear.org</a>.</p>
    </div>
]]>
</Body>
<Summary>For All The World to Hear: Stories from the Struggle for Civil Rights, an oral history, outreach project of the CADVC, will present the session “Storytelling from Page to Stage: An Oral History...</Summary>
<Website>https://umbc.edu/stories/for-all-the-world-to-hear-to-present-at-aam-meeting/</Website>
<TrackingUrl>https://my3.my.umbc.edu/api/v0/pixel/news/123345/guest@my.umbc.edu/66a099b012a27fc7d4e7a69866240eac/api/pixel</TrackingUrl>
<Tag>cadvc</Tag>
<Tag>cahss</Tag>
<Tag>policy-and-society</Tag>
<Tag>visualarts</Tag>
<Group token="umbc-news-magazine">UMBC News &amp;amp; Magazine</Group>
<GroupUrl>https://my3.my.umbc.edu/groups/umbc-news-magazine</GroupUrl>
<AvatarUrl>https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xsmall.png?1748556657</AvatarUrl>
<AvatarUrl size="original">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/original.png?1748556657</AvatarUrl>
<AvatarUrl size="xxlarge">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xxlarge.png?1748556657</AvatarUrl>
<AvatarUrl size="xlarge">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xlarge.png?1748556657</AvatarUrl>
<AvatarUrl size="large">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/large.png?1748556657</AvatarUrl>
<AvatarUrl size="medium">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/medium.png?1748556657</AvatarUrl>
<AvatarUrl size="small">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/small.png?1748556657</AvatarUrl>
<AvatarUrl size="xsmall">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xsmall.png?1748556657</AvatarUrl>
<AvatarUrl size="xxsmall">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/001/943/24435aa6207c452e7bc15cc74b42c7bb/xxsmall.png?1748556657</AvatarUrl>
<Sponsor>UMBC News &amp; Magazine</Sponsor>
<PawCount>0</PawCount>
<CommentCount>0</CommentCount>
<CommentsAllowed>false</CommentsAllowed>
<PostedAt>Thu, 25 Apr 2013 17:55:19 -0400</PostedAt>
</NewsItem>

<NewsItem contentIssues="true" id="28273" important="false" status="posted" url="https://my3.my.umbc.edu/posts/28273">
<Title>Promise-Based Validation</Title>
<Body>
<![CDATA[
    <div class="html-content">
    <a href="http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31473&amp;c=1382487731" rel="nofollow external" class="bo"><img src="http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31473&amp;c=1382487731" alt="" style="max-width: 100%; height: auto;"></a><p>The concept of “Promises” has changed the way we write asynchronous JavaScript. Over the past year, many frameworks have incorporated some form of the Promise pattern to make asynchronous code easier to write, read and maintain. For example, jQuery added <a href="http://api.jquery.com/category/deferred-object/" rel="nofollow external" class="bo">$.Deferred()</a>, and NodeJS has the <a href="http://documentup.com/kriskowal/q/" rel="nofollow external" class="bo">Q</a> and <a href="https://github.com/dfilatov/jspromise" rel="nofollow external" class="bo">jspromise</a> modules that work on both client and server. Client-side MVC frameworks, such as <a href="http://emberjs.com" rel="nofollow external" class="bo">EmberJS</a> and <a href="http://angularjs.org/" rel="nofollow external" class="bo">AngularJS</a>, also implement their own versions of Promises.</p>
    <p></p>
    <p>But it doesn’t have to stop there: we can rethink older solutions and apply Promises to them. In this article, we’ll do just that: validate a form using the Promise pattern to expose a super simple API.</p>
    <hr>
    <h2>What is a Promise?</h2>
    <blockquote><p> Promises notify the result of an operation.</p></blockquote>
    <p>Simply put, Promises notify the result of an operation. The result can be a success or a failure, and the operation, itself, can be anything that abides by a simple contract. I chose to use the word <em>contract</em> because you can design this contract in several different ways. Thankfully, the development community reached a consensus and created a specification called <a href="http://promises-aplus.github.io/promises-spec/" rel="nofollow external" class="bo">Promises/A+</a>.</p>
    <p>Only the operation truly knows when it has completed; as such, it is responsibile for notifying its result using the Promises/A+ contract. In other words, it <em>promises</em> to tell you the final result on completion.</p>
    <p>The operation returns a <code>promise</code> object, and you can attach your callbacks to it by using the <code>done()</code> or <code>fail()</code> methods. The operation can notify its outcome by calling <code>promise.resolve()</code> or <code>promise.reject()</code>, respectively. This is depicted in the following figure:</p> <img src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/04/promise-validation-promise.png" alt="Figure for Promises" style="max-width: 100%; height: auto;"><hr>
    <h2>Using Promises for Form Validation</h2>
    <p>Let me paint a plausible scenario.</p>
    <blockquote><p>We can rethink older solutions and apply Promises to them.</p></blockquote>
    <p>Client-side form validation always begins with the simplest of intentions. You may have a sign-up form with <em>Name</em> and <em>Email</em> fields, and you need to ensure that the user provides valid input for both fields. That seems fairly straightforward, and you start implementing your solution.</p>
    <p>You are then told that email addresses must be unique, and you decide to validate the email address on the server. So, the user clicks the submit button, the server checks the email’s uniqueness and the page refreshes to display any errors. That seems like the right approach, right? Nope. Your client wants a slick user experience; visitors should see any error messages without refreshing the page.</p>
    <p>Your form has the <em>Name</em> field that doesn’t require any server-side support, but then you have the <em>Email</em> field that requires you to make a request to the server. Server requests means <code>$.ajax()</code> calls, so you will have to perform email validation in your callback function. If your form has multiple fields that require server-side support, your code will be a nested mess of <code>$.ajax()</code> calls in callbacks. Callbacks inside callbacks: “Welcome to callback hell! We hope you have a miserable stay!”.</p>
    <p>So, how do we handle callback hell?</p>
    <h3>The Solution I Promised</h3>
    <p>Take a step back and think about this problem. We have a set of operations that can either succeed or fail. Either of these results can be captured as a <code>Promise</code>, and the operations can be anything from simple client-side checks to complex server-side validations. Promises also give you the added benefit of consistency, as well as letting you avoid conditionally checking on the type of validation. Lets see how we can do this.</p>
    <blockquote><p>As I noted earlier, there are several promise implementations in the wild, but I will focus on jQuery’s <a href="http://api.jquery.com/deferred" rel="nofollow external" class="bo">$.Deferred()</a> Promise implementation.</p></blockquote>
    <p>We will build a simple validation framework where every check immediately returns either a result or a Promise. As a user of this framework, you only have to remember one thing: <em>“it always returns a Promise”</em>. Lets get started.</p>
    <h3>Validator Framework using Promises</h3>
    <p>I think it’s easier to appreciate the simplicity of Promises from the consumer’s point of view. Lets say I have a form with three fields: Name, Email and Address:</p>
    <pre>&lt;form&gt;&#x000A;      &lt;div class="row"&gt;&#x000A;        &lt;div class="large-4 columns"&gt;&#x000A;          &lt;label&gt;Name&lt;/label&gt;&#x000A;          &lt;input type="text" class="name"/&gt;&#x000A;        &lt;/div&gt;&#x000A;      &lt;/div&gt;&#x000A;    &#x000A;      &lt;div class="row"&gt;&#x000A;        &lt;div class="large-4 columns"&gt;&#x000A;          &lt;label&gt;Email&lt;/label&gt;&#x000A;          &lt;input type="text" class="email"/&gt;&#x000A;        &lt;/div&gt;&#x000A;      &lt;/div&gt;&#x000A;    &#x000A;      &lt;div class="row"&gt;&#x000A;        &lt;div class="large-4 columns"&gt;&#x000A;          &lt;label&gt;Address&lt;/label&gt;&#x000A;          &lt;input type="text" class="address"/&gt;&#x000A;        &lt;/div&gt;&#x000A;      &lt;/div&gt;&#x000A;    &#x000A;    &lt;/form&gt;&#x000A;    </pre>
    <p>I will first configure the validation criteria with the following object. This also serves as our framework’s API:</p>
    <pre>var validationConfig = {&#x000A;      '.name': {&#x000A;        checks: 'required',&#x000A;        field: 'Name'&#x000A;      },&#x000A;      '.email': {&#x000A;        checks: ['required'],&#x000A;        field: 'Email'&#x000A;      },&#x000A;      '.address': {&#x000A;        checks: ['random', 'required'],&#x000A;        field: 'Address'&#x000A;      }&#x000A;    };&#x000A;    </pre>
    <p>The keys of this config object are jQuery selectors; their values are objects with the following two properties:</p>
    <ul>
    <li>
    <code>checks</code>: a string or array of validations.</li>
    <li>
    <code>field</code>: the human-readable field name, which will be used for reporting errors for that field</li>
    </ul>
    <p>We can call our validator, exposed as the global variable <code>V</code>, like this:</p>
    <pre>V.validate(validationConfig)&#x000A;      .done(function () {&#x000A;          // Success&#x000A;      })&#x000A;      .fail(function (errors) {&#x000A;          // Validations failed. errors has the details&#x000A;      });&#x000A;    </pre>
    <p>Note the use of the <code>done()</code> and <code>fail()</code> callbacks; these are the default callbacks for handing a Promise’s result. If we happen to add more form fields, you could simply augment the <code>validationConfig</code> object without disturbing the rest of the setup (the <a href="http://en.wikipedia.org/wiki/Open/closed_principle" rel="nofollow external" class="bo">Open-Closed Principle</a> in action). In fact, we can add other validations, like the uniqueness constraint for email addresses, by extending the validator framework (which we will see later).</p>
    <p>So that’s the consumer-facing API for the validator framework. Now, let’s dive in and see how it works under the hood.</p>
    <h3>Validator, Under the Hood</h3>
    <p>The validator is exposed as an object with two properties:</p>
    <ul>
    <li>
    <code>type</code>: contains the different kinds of validations, and it is also serves as the extension point for adding more.</li>
    <li>
    <code>validate</code>: the core method that performs the validations based upon the provided config object.</li>
    </ul>
    <p>The overall structure can be summarized as:</p>
    <pre>var V = (function ($) {&#x000A;    &#x000A;    var validator = {&#x000A;    &#x000A;      /*&#x000A;      * Extension point - just add to this hash&#x000A;      * &#x000A;      * V.type['my-validator'] = {&#x000A;      *   ok: function(value){ return true; },&#x000A;      *   message: 'Failure message for my-validator'&#x000A;      *   }&#x000A;      */&#x000A;      type: {&#x000A;        'required': {&#x000A;          ok: function (value) {&#x000A;              // is valid ?&#x000A;          },&#x000A;          message: 'This field is required'&#x000A;        },&#x000A;    &#x000A;        ...&#x000A;      },&#x000A;    &#x000A;      /**&#x000A;       *&#x000A;       * @param config&#x000A;       * {&#x000A;       *   '&lt;jquery-selector&gt;': string | object | [ string ]&#x000A;       * }&#x000A;       */&#x000A;      validate: function (config) {&#x000A;    &#x000A;        // 1. Normalize the configuration object  &#x000A;    &#x000A;        // 2. Convert each validation to a promise  &#x000A;    &#x000A;        // 3. Wrap into a master promise&#x000A;    &#x000A;        // 4. Return the master promise&#x000A;      }&#x000A;    };&#x000A;    &#x000A;    })(jQuery);&#x000A;    </pre>
    <p>The <code>validate</code> method provides the underpinnings of this framework. As seen in the comments above, there are four steps that happen here:</p>
    <p><strong>1. Normalize the configuration object.</strong></p>
    <p>This is where we go through our config object and convert it into an internal representation. This is mostly to capture all the information we need to carry out the validation and report errors if necessary:</p>
    <pre>function normalizeConfig(config) {&#x000A;      config = config || {};&#x000A;    &#x000A;      var validations = [];&#x000A;    &#x000A;      $.each(config, function (selector, obj) {&#x000A;    &#x000A;        // make an array for simplified checking&#x000A;        var checks = $.isArray(obj.checks) ? obj.checks : [obj.checks];&#x000A;    &#x000A;        $.each(checks, function (idx, check) {&#x000A;          validations.push({&#x000A;            control: $(selector),&#x000A;            check: getValidator(check),&#x000A;            checkName: check,&#x000A;            field: obj.field&#x000A;          });&#x000A;        });&#x000A;    &#x000A;      });&#x000A;      return validations;&#x000A;    }&#x000A;    &#x000A;    function getValidator(type) {&#x000A;      if ($.type(type) === 'string' &amp;&amp; validator.type[type]) return validator.type[type];&#x000A;    &#x000A;      return validator.noCheck;&#x000A;    }&#x000A;    &#x000A;    </pre>
    <p>This code loops over the keys in the config object and creates an internal representation of the validation. We will use this representation in the <code>validate</code> method.</p>
    <p>The <code>getValidator()</code> helper fetches the validator object from the <code>type</code> hash. If we don’t find one, we return the <code>noCheck</code> validator which always returns true.</p>
    <p><strong>2. Convert each validation to a Promise.</strong></p>
    <p>Here, we ensure every validation is a Promise by checking the return value of <code>validation.ok()</code>. If it contains the <code>then()</code> method, we know it’s a Promise (this is as per the Promises/A+ spec). If not, we create an ad-hoc Promise that resolves or rejects depending on the return value.</p>
    <pre>    &#x000A;    validate: function (config) {&#x000A;      // 1. Normalize the configuration object&#x000A;      config = normalizeConfig(config);&#x000A;      var promises = [],&#x000A;        checks = [];&#x000A;    &#x000A;      // 2. Convert each validation to a promise&#x000A;      $.each(config, function (idx, v) {&#x000A;        var value = v.control.val();&#x000A;        var retVal = v.check.ok(value);&#x000A;    &#x000A;        // Make a promise, check is based on Promises/A+ spec&#x000A;        if (retVal.then) {&#x000A;          promises.push(retVal);&#x000A;        }&#x000A;        else {&#x000A;          var p = $.Deferred();&#x000A;    &#x000A;          if (retVal) p.resolve();&#x000A;          else p.reject();&#x000A;    &#x000A;          promises.push(p.promise());&#x000A;        }&#x000A;        checks.push(v);&#x000A;      });&#x000A;      // 3. Wrap into a master promise&#x000A;    &#x000A;      // 4. Return the master promise&#x000A;    }&#x000A;    </pre>
    <p><strong>3. Wrap into a master Promise.</strong></p>
    <p>We created an array of Promises in the previous step. When they all succeed, we want to either resolve once or fail with detailed error information. We can do this by wrapping all of the Promises into a single Promise and propagate the result. If everything goes well, we just resolve on the master promise.</p>
    <p>For errors, we can read from our internal validation representation and use it for reporting. Since there can be multiple validation failures, we loop over the <code>promises</code> array and read the <code>state()</code> result. We collect all of the rejected promises into the <code>failed</code> array and call <code>reject()</code> on the master promise:</p>
    <pre>// 3. Wrap into a master promise&#x000A;    var masterPromise = $.Deferred();&#x000A;    $.when.apply(null, promises)&#x000A;      .done(function () {&#x000A;        masterPromise.resolve();&#x000A;      })&#x000A;      .fail(function () {&#x000A;        var failed = [];&#x000A;        $.each(promises, function (idx, x) {&#x000A;          if (x.state() === 'rejected') {&#x000A;            var failedCheck = checks[idx];&#x000A;            var error = {&#x000A;              check: failedCheck.checkName,&#x000A;              error: failedCheck.check.message,&#x000A;              field: failedCheck.field,&#x000A;              control: failedCheck.control&#x000A;            };&#x000A;            failed.push(error);&#x000A;          }&#x000A;        });&#x000A;        masterPromise.reject(failed);&#x000A;      });&#x000A;    &#x000A;    // 4. Return the master promise&#x000A;    return masterPromise.promise();&#x000A;    </pre>
    <p><strong>4. Return the master promise.</strong></p>
    <p>Finally we return the master promise from the <code>validate()</code> method. This is the Promise on which the client code sets up the <code>done()</code> and <code>fail()</code> callbacks.</p>
    <p>Steps two and three are the crux of this framework. By normalizing the validations into a Promise, we can handle them consistently. We have more control with a master Promise object, and we can attach additional contextual information that may be useful to the end user.</p>
    <hr>
    <h2>Using the Validator</h2>
    <p>See the demo file for a full use of the validator framework. We use the <code>done()</code> callback to report success and <code>fail()</code> to show a list of errors against each of the fields. The screenshots below show the success and failure states:</p> <img src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/04/promise-validation-demo-success.png" alt="Demo showing Success" style="max-width: 100%; height: auto;"> <img src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/04/promise-validation-demo-failure.png" alt="Demo showing failures" style="max-width: 100%; height: auto;"><p>The demo uses the same HTML and validation configuration mentioned earlier in this article. The only addition is the code that displays the alerts. Note the use of the <code>done()</code> and <code>fail()</code> callbacks to handle the validation results.</p>
    <pre>function showAlerts(errors) {&#x000A;      var alertContainer = $('.alert');&#x000A;      $('.error').remove();&#x000A;    &#x000A;      if (!errors) {&#x000A;        alertContainer.html('&lt;small class="label success"&gt;All Passed&lt;/small&gt;');&#x000A;      } else {&#x000A;        $.each(errors, function (idx, err) {&#x000A;          var msg = $('&lt;small&gt;&lt;/small&gt;')&#x000A;              .addClass('error')&#x000A;              .text(err.error);&#x000A;    &#x000A;          err.control.parent().append(msg);&#x000A;        });&#x000A;      }&#x000A;    }&#x000A;    &#x000A;    $('.validate').click(function () {&#x000A;    &#x000A;      $('.indicator').show();&#x000A;      $('.alert').empty();&#x000A;    &#x000A;      V.validate(validationConfig)&#x000A;          .done(function () {&#x000A;            $('.indicator').hide();&#x000A;            showAlerts();&#x000A;          })&#x000A;          .fail(function (errors) {&#x000A;            $('.indicator').hide();&#x000A;            showAlerts(errors);&#x000A;          });&#x000A;    &#x000A;    });&#x000A;    </pre>
    <h3>Extending the Validator</h3>
    <p>I mentioned earlier that we can add more validation operations to the framework by extending the validator’s <code>type</code> hash. Consider the <code>random</code> validator as an example. This validator randomly succeeds or fails. I know its not a useful validator, but it’s worth noting some of its concepts:</p>
    <ul>
    <li>Use <code>setTimeout()</code> to make the validation async. You can also think of this as simulating network latency.</li>
    <li>Return a Promise from the <code>ok()</code> method.</li>
    </ul>
    <pre>  &#x000A;    // Extend with a random validator&#x000A;    V.type['random'] = {&#x000A;      ok: function (value) {&#x000A;        var deferred = $.Deferred();&#x000A;    &#x000A;        setTimeout(function () {&#x000A;          var result = Math.random() &lt; 0.5;&#x000A;          if (result) deferred.resolve();&#x000A;          else deferred.reject();&#x000A;    &#x000A;        }, 1000);&#x000A;    &#x000A;        return deferred.promise();&#x000A;      },&#x000A;      message: 'Failed randomly. No hard feelings.'&#x000A;    };&#x000A;    </pre>
    <p>In the demo, I used this validation on the <em>Address</em> field like so:</p>
    <pre>var validationConfig = {&#x000A;      /* cilpped for brevity */&#x000A;    &#x000A;      '.address': {&#x000A;        checks: ['random', 'required'],&#x000A;        field: 'Address'&#x000A;      }&#x000A;    };&#x000A;    </pre>
    <hr>
    <h2>Summary</h2>
    <p>I hope that this article has given you a good idea of how you can apply Promises to old problems and build your own framework around them. The Promise-based approach is a fantastic solution to abstract operations that may or may not run synchronously. You can also chain callbacks and even compose higher-order Promises from a set of other Promises.</p>
    <p>The Promise pattern is applicable in a variety of scenarios, and you’ll hopefully encounter some of them and see an immediate match!</p>
    <hr>
    <h2>References</h2>
    <ul>
    <li><a href="http://promises-aplus.github.io/promises-spec/" rel="nofollow external" class="bo">Promises/A+ spec</a></li>
    <li><a href="http://api.jquery.com/category/deferred-object/" rel="nofollow external" class="bo">jQuery.Deferred()</a></li>
    <li><a href="http://documentup.com/kriskowal/q/" rel="nofollow external" class="bo">Q</a></li>
    <li><a href="https://github.com/dfilatov/jspromise" rel="nofollow external" class="bo">jspromise</a></li>
    </ul>
    </div>
]]>
</Body>
<Summary>The concept of “Promises” has changed the way we write asynchronous JavaScript. Over the past year, many frameworks have incorporated some form of the Promise pattern to make asynchronous code...</Summary>
<Website>http://feedproxy.google.com/~r/nettuts/~3/g_CrQeWOv6w/</Website>
<TrackingUrl>https://my3.my.umbc.edu/api/v0/pixel/news/28273/guest@my.umbc.edu/1ce26acb6467255e2843650610089e47/api/pixel</TrackingUrl>
<Tag>css</Tag>
<Tag>development</Tag>
<Tag>html</Tag>
<Tag>javascript</Tag>
<Tag>javascript-and-ajax</Tag>
<Tag>mysql</Tag>
<Tag>php</Tag>
<Tag>promises</Tag>
<Tag>sql</Tag>
<Tag>tutorials</Tag>
<Tag>wed</Tag>
<Group token="retired-583">Web Developer - Build Group</Group>
<GroupUrl>https://my3.my.umbc.edu/groups/retired-583</GroupUrl>
<AvatarUrl>https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xsmall.png?1363101197</AvatarUrl>
<AvatarUrl size="original">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/original.jpg?1363101197</AvatarUrl>
<AvatarUrl size="xxlarge">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xxlarge.png?1363101197</AvatarUrl>
<AvatarUrl size="xlarge">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xlarge.png?1363101197</AvatarUrl>
<AvatarUrl size="large">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/large.png?1363101197</AvatarUrl>
<AvatarUrl size="medium">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/medium.png?1363101197</AvatarUrl>
<AvatarUrl size="small">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/small.png?1363101197</AvatarUrl>
<AvatarUrl size="xsmall">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xsmall.png?1363101197</AvatarUrl>
<AvatarUrl size="xxsmall">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xxsmall.png?1363101197</AvatarUrl>
<Sponsor>Web Developer - Build Group</Sponsor>
<PawCount>0</PawCount>
<CommentCount>0</CommentCount>
<CommentsAllowed>true</CommentsAllowed>
<PostedAt>Thu, 25 Apr 2013 17:46:03 -0400</PostedAt>
<EditAt>Thu, 25 Apr 2013 17:46:03 -0400</EditAt>
</NewsItem>

<NewsItem contentIssues="true" id="28272" important="false" status="posted" url="https://my3.my.umbc.edu/posts/28272">
<Title>Promised-Based Validation</Title>
<Body>
<![CDATA[
    <div class="html-content">
    <a href="http://rss.buysellads.com/click.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31473&amp;c=348866813" rel="nofollow external" class="bo"><img src="http://rss.buysellads.com/img.php?z=1260013&amp;k=d754f1e9ba63a736ba8ff5ece958f7dd&amp;a=31473&amp;c=348866813" alt="" style="max-width: 100%; height: auto;"></a><p>The concept of “Promises” has changed the way we write asynchronous JavaScript. Over the past year, many frameworks have incorporated some form of the Promise pattern to make asynchronous code easier to write, read and maintain. For example, jQuery added <a href="http://api.jquery.com/category/deferred-object/" rel="nofollow external" class="bo">$.Deferred()</a>, and NodeJS has the <a href="http://documentup.com/kriskowal/q/" rel="nofollow external" class="bo">Q</a> and <a href="https://github.com/dfilatov/jspromise" rel="nofollow external" class="bo">jspromise</a> modules that work on both client and server. Client-side MVC frameworks, such as <a href="http://emberjs.com" rel="nofollow external" class="bo">EmberJS</a> and <a href="http://angularjs.org/" rel="nofollow external" class="bo">AngularJS</a>, also implement their own versions of Promises.</p>
    <p></p>
    <p>But it doesn’t have to stop there: we can rethink older solutions and apply Promises to them. In this article, we’ll do just that: validate a form using the Promise pattern to expose a super simple API.</p>
    <hr>
    <h2>What is a Promise?</h2>
    <blockquote><p> Promises notify the result of an operation.</p></blockquote>
    <p>Simply put, Promises notify the result of an operation. The result can be a success or a failure, and the operation, itself, can be anything that abides by a simple contract. I chose to use the word <em>contract</em> because you can design this contract in several different ways. Thankfully, the development community reached a consensus and created a specification called <a href="http://promises-aplus.github.io/promises-spec/" rel="nofollow external" class="bo">Promises/A+</a>.</p>
    <p>Only the operation truly knows when it has completed; as such, it is responsibile for notifying its result using the Promises/A+ contract. In other words, it <em>promises</em> to tell you the final result on completion.</p>
    <p>The operation returns a <code>promise</code> object, and you can attach your callbacks to it by using the <code>done()</code> or <code>fail()</code> methods. The operation can notify its outcome by calling <code>promise.resolve()</code> or <code>promise.reject()</code>, respectively. This is depicted in the following figure:</p> <img src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/04/promise-validation-promise.png" alt="Figure for Promises" style="max-width: 100%; height: auto;"><hr>
    <h2>Using Promises for Form Validation</h2>
    <p>Let me paint a plausible scenario.</p>
    <blockquote><p>We can rethink older solutions and apply Promises to them.</p></blockquote>
    <p>Client-side form validation always begins with the simplest of intentions. You may have a sign-up form with <em>Name</em> and <em>Email</em> fields, and you need to ensure that the user provides valid input for both fields. That seems fairly straightforward, and you start implementing your solution.</p>
    <p>You are then told that email addresses must be unique, and you decide to validate the email address on the server. So, the user clicks the submit button, the server checks the email’s uniqueness and the page refreshes to display any errors. That seems like the right approach, right? Nope. Your client wants a slick user experience; visitors should see any error messages without refreshing the page.</p>
    <p>Your form has the <em>Name</em> field that doesn’t require any server-side support, but then you have the <em>Email</em> field that requires you to make a request to the server. Server requests means <code>$.ajax()</code> calls, so you will have to perform email validation in your callback function. If your form has multiple fields that require server-side support, your code will be a nested mess of <code>$.ajax()</code> calls in callbacks. Callbacks inside callbacks: “Welcome to callback hell! We hope you have a miserable stay!”.</p>
    <p>So, how do we handle callback hell?</p>
    <h3>The Solution I Promised</h3>
    <p>Take a step back and think about this problem. We have a set of operations that can either succeed or fail. Either of these results can be captured as a <code>Promise</code>, and the operations can be anything from simple client-side checks to complex server-side validations. Promises also give you the added benefit of consistency, as well as letting you avoid conditionally checking on the type of validation. Lets see how we can do this.</p>
    <blockquote><p>As I noted earlier, there are several promise implementations in the wild, but I will focus on jQuery’s <a href="http://api.jquery.com/deferred" rel="nofollow external" class="bo">$.Deferred()</a> Promise implementation.</p></blockquote>
    <p>We will build a simple validation framework where every check immediately returns either a result or a Promise. As a user of this framework, you only have to remember one thing: <em>“it always returns a Promise”</em>. Lets get started.</p>
    <h3>Validator Framework using Promises</h3>
    <p>I think it’s easier to appreciate the simplicity of Promises from the consumer’s point of view. Lets say I have a form with three fields: Name, Email and Address:</p>
    <pre>&lt;form&gt;&#x000A;      &lt;div class="row"&gt;&#x000A;        &lt;div class="large-4 columns"&gt;&#x000A;          &lt;label&gt;Name&lt;/label&gt;&#x000A;          &lt;input type="text" class="name"/&gt;&#x000A;        &lt;/div&gt;&#x000A;      &lt;/div&gt;&#x000A;    &#x000A;      &lt;div class="row"&gt;&#x000A;        &lt;div class="large-4 columns"&gt;&#x000A;          &lt;label&gt;Email&lt;/label&gt;&#x000A;          &lt;input type="text" class="email"/&gt;&#x000A;        &lt;/div&gt;&#x000A;      &lt;/div&gt;&#x000A;    &#x000A;      &lt;div class="row"&gt;&#x000A;        &lt;div class="large-4 columns"&gt;&#x000A;          &lt;label&gt;Address&lt;/label&gt;&#x000A;          &lt;input type="text" class="address"/&gt;&#x000A;        &lt;/div&gt;&#x000A;      &lt;/div&gt;&#x000A;    &#x000A;    &lt;/form&gt;&#x000A;    </pre>
    <p>I will first configure the validation criteria with the following object. This also serves as our framework’s API:</p>
    <pre>var validationConfig = {&#x000A;      '.name': {&#x000A;        checks: 'required',&#x000A;        field: 'Name'&#x000A;      },&#x000A;      '.email': {&#x000A;        checks: ['required'],&#x000A;        field: 'Email'&#x000A;      },&#x000A;      '.address': {&#x000A;        checks: ['random', 'required'],&#x000A;        field: 'Address'&#x000A;      }&#x000A;    };&#x000A;    </pre>
    <p>The keys of this config object are jQuery selectors; their values are objects with the following two properties:</p>
    <ul>
    <li>
    <code>checks</code>: a string or array of validations.</li>
    <li>
    <code>field</code>: the human-readable field name, which will be used for reporting errors for that field</li>
    </ul>
    <p>We can call our validator, exposed as the global variable <code>V</code>, like this:</p>
    <pre>V.validate(validationConfig)&#x000A;      .done(function () {&#x000A;          // Success&#x000A;      })&#x000A;      .fail(function (errors) {&#x000A;          // Validations failed. errors has the details&#x000A;      });&#x000A;    </pre>
    <p>Note the use of the <code>done()</code> and <code>fail()</code> callbacks; these are the default callbacks for handing a Promise’s result. If we happen to add more form fields, you could simply augment the <code>validationConfig</code> object without disturbing the rest of the setup (the <a href="http://en.wikipedia.org/wiki/Open/closed_principle" rel="nofollow external" class="bo">Open-Closed Principle</a> in action). In fact, we can add other validations, like the uniqueness constraint for email addresses, by extending the validator framework (which we will see later).</p>
    <p>So that’s the consumer-facing API for the validator framework. Now, let’s dive in and see how it works under the hood.</p>
    <h3>Validator, Under the Hood</h3>
    <p>The validator is exposed as an object with two properties:</p>
    <ul>
    <li>
    <code>type</code>: contains the different kinds of validations, and it is also serves as the extension point for adding more.</li>
    <li>
    <code>validate</code>: the core method that performs the validations based upon the provided config object.</li>
    </ul>
    <p>The overall structure can be summarized as:</p>
    <pre>var V = (function ($) {&#x000A;    &#x000A;    var validator = {&#x000A;    &#x000A;      /*&#x000A;      * Extension point - just add to this hash&#x000A;      * &#x000A;      * V.type['my-validator'] = {&#x000A;      *   ok: function(value){ return true; },&#x000A;      *   message: 'Failure message for my-validator'&#x000A;      *   }&#x000A;      */&#x000A;      type: {&#x000A;        'required': {&#x000A;          ok: function (value) {&#x000A;              // is valid ?&#x000A;          },&#x000A;          message: 'This field is required'&#x000A;        },&#x000A;    &#x000A;        ...&#x000A;      },&#x000A;    &#x000A;      /**&#x000A;       *&#x000A;       * @param config&#x000A;       * {&#x000A;       *   '&lt;jquery-selector&gt;': string | object | [ string ]&#x000A;       * }&#x000A;       */&#x000A;      validate: function (config) {&#x000A;    &#x000A;        // 1. Normalize the configuration object  &#x000A;    &#x000A;        // 2. Convert each validation to a promise  &#x000A;    &#x000A;        // 3. Wrap into a master promise&#x000A;    &#x000A;        // 4. Return the master promise&#x000A;      }&#x000A;    };&#x000A;    &#x000A;    })(jQuery);&#x000A;    </pre>
    <p>The <code>validate</code> method provides the underpinnings of this framework. As seen in the comments above, there are four steps that happen here:</p>
    <p><strong>1. Normalize the configuration object.</strong></p>
    <p>This is where we go through our config object and convert it into an internal representation. This is mostly to capture all the information we need to carry out the validation and report errors if necessary:</p>
    <pre>function normalizeConfig(config) {&#x000A;      config = config || config;&#x000A;    &#x000A;      var validations = [];&#x000A;    &#x000A;      $.each(config, function (selector, obj) {&#x000A;    &#x000A;        // make an array for simplified checking&#x000A;        var checks = $.isArray(obj.checks) ? obj.checks : [obj.checks];&#x000A;    &#x000A;        $.each(checks, function (idx, check) {&#x000A;          validations.push({&#x000A;            control: $(selector),&#x000A;            check: getValidator(check),&#x000A;            checkName: check,&#x000A;            field: obj.field&#x000A;          });&#x000A;        });&#x000A;    &#x000A;      });&#x000A;      return validations;&#x000A;    }&#x000A;    &#x000A;    function getValidator(type) {&#x000A;      if ($.type(type) === 'string' &amp;&amp; validator.type[type]) return validator.type[type];&#x000A;    &#x000A;      return validator.noCheck;&#x000A;    }&#x000A;    &#x000A;    </pre>
    <p>This code loops over the keys in the config object and creates an internal representation of the validation. We will use this representation in the <code>validate</code> method.</p>
    <p>The <code>getValidator()</code> helper fetches the validator object from the <code>type</code> hash. If we don’t find one, we return the <code>noCheck</code> validator which always returns true.</p>
    <p><strong>2. Convert each validation to a Promise.</strong></p>
    <p>Here, we ensure every validation is a Promise by checking the return value of <code>validation.ok()</code>. If it contains the <code>then()</code> method, we know it’s a Promise (this is as per the Promises/A+ spec). If not, we create an ad-hoc Promise that resolves or rejects depending on the return value.</p>
    <pre>    &#x000A;    validate: function (config) {&#x000A;      // 1. Normalize the configuration object&#x000A;      config = normalizeConfig(config);&#x000A;      var promises = [],&#x000A;        checks = [];&#x000A;    &#x000A;      // 2. Convert each validation to a promise&#x000A;      $.each(config, function (idx, v) {&#x000A;        var value = v.control.val();&#x000A;        var retVal = v.check.ok(value);&#x000A;    &#x000A;        // Make a promise, check is based on Promises/A+ spec&#x000A;        if (retVal.then) {&#x000A;          promises.push(retVal);&#x000A;        }&#x000A;        else {&#x000A;          var p = $.Deferred();&#x000A;    &#x000A;          if (retVal) p.resolve();&#x000A;          else p.reject();&#x000A;    &#x000A;          promises.push(p.promise());&#x000A;        }&#x000A;        checks.push(v);&#x000A;      });&#x000A;      // 3. Wrap into a master promise&#x000A;    &#x000A;      // 4. Return the master promise&#x000A;    }&#x000A;    </pre>
    <p><strong>3. Wrap into a master Promise.</strong></p>
    <p>We created an array of Promises in the previous step. When they all succeed, we want to either resolve once or fail with detailed error information. We can do this by wrapping all of the Promises into a single Promise and propagate the result. If everything goes well, we just resolve on the master promise.</p>
    <p>For errors, we can read from our internal validation representation and use it for reporting. Since there can be multiple validation failures, we loop over the <code>promises</code> array and read the <code>state()</code> result. We collect all of the rejected promises into the <code>failed</code> array and call <code>reject()</code> on the master promise:</p>
    <pre>// 3. Wrap into a master promise&#x000A;    var masterPromise = $.Deferred();&#x000A;    $.when.apply(null, promises)&#x000A;      .done(function () {&#x000A;        masterPromise.resolve();&#x000A;      })&#x000A;      .fail(function () {&#x000A;        var failed = [];&#x000A;        $.each(promises, function (idx, x) {&#x000A;          if (x.state() === 'rejected') {&#x000A;            var failedCheck = checks[idx];&#x000A;            var error = {&#x000A;              check: failedCheck.checkName,&#x000A;              error: failedCheck.check.message,&#x000A;              field: failedCheck.field,&#x000A;              control: failedCheck.control&#x000A;            };&#x000A;            failed.push(error);&#x000A;          }&#x000A;        });&#x000A;        masterPromise.reject(failed);&#x000A;      });&#x000A;    &#x000A;    // 4. Return the master promise&#x000A;    return masterPromise.promise();&#x000A;    </pre>
    <p><strong>4. Return the master promise.</strong></p>
    <p>Finally we return the master promise from the <code>validate()</code> method. This is the Promise on which the client code sets up the <code>done()</code> and <code>fail()</code> callbacks.</p>
    <p>Steps two and three are the crux of this framework. By normalizing the validations into a Promise, we can handle them consistently. We have more control with a master Promise object, and we can attach additional contextual information that may be useful to the end user.</p>
    <hr>
    <h2>Using the Validator</h2>
    <p>See the demo file for a full use of the validator framework. We use the <code>done()</code> callback to report success and <code>fail()</code> to show a list of errors against each of the fields. The screenshots below show the success and failure states:</p> <img src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/04/promise-validation-demo-success.png" alt="Demo showing Success" style="max-width: 100%; height: auto;"> <img src="http://cdn.tutsplus.com/net.tutsplus.com/uploads/2013/04/promise-validation-demo-failure.png" alt="Demo showing failures" style="max-width: 100%; height: auto;"><p>The demo uses the same HTML and validation configuration mentioned earlier in this article. The only addition is the code that displays the alerts. Note the use of the <code>done()</code> and <code>fail()</code> callbacks to handle the validation results.</p>
    <pre>function showAlerts(errors) {&#x000A;      var alertContainer = $('.alert');&#x000A;      $('.error').remove();&#x000A;    &#x000A;      if (!errors) {&#x000A;        alertContainer.html('&lt;small class="label success"&gt;All Passed&lt;/small&gt;');&#x000A;      } else {&#x000A;        $.each(errors, function (idx, err) {&#x000A;          var msg = $('&lt;small&gt;&lt;/small&gt;')&#x000A;              .addClass('error')&#x000A;              .text(err.error);&#x000A;    &#x000A;          err.control.parent().append(msg);&#x000A;        });&#x000A;      }&#x000A;    }&#x000A;    &#x000A;    $('.validate').click(function () {&#x000A;    &#x000A;      $('.indicator').show();&#x000A;      $('.alert').empty();&#x000A;    &#x000A;      V.validate(validationConfig)&#x000A;          .done(function () {&#x000A;            $('.indicator').hide();&#x000A;            showAlerts();&#x000A;          })&#x000A;          .fail(function (errors) {&#x000A;            $('.indicator').hide();&#x000A;            showAlerts(errors);&#x000A;          });&#x000A;    &#x000A;    });&#x000A;    </pre>
    <h3>Extending the Validator</h3>
    <p>I mentioned earlier that we can add more validation operations to the framework by extending the validator’s <code>type</code> hash. Consider the <code>random</code> validator as an example. This validator randomly succeeds or fails. I know its not a useful validator, but it’s worth noting some of its concepts:</p>
    <ul>
    <li>Use <code>setTimeout()</code> to make the validation async. You can also think of this as simulating network latency.</li>
    <li>Return a Promise from the <code>ok()</code> method.</li>
    </ul>
    <pre>  &#x000A;    // Extend with a random validator&#x000A;    V.type['random'] = {&#x000A;      ok: function (value) {&#x000A;        var deferred = $.Deferred();&#x000A;    &#x000A;        setTimeout(function () {&#x000A;          var result = Math.random() &lt; 0.5;&#x000A;          if (result) deferred.resolve();&#x000A;          else deferred.reject();&#x000A;    &#x000A;        }, 1000);&#x000A;    &#x000A;        return deferred.promise();&#x000A;      },&#x000A;      message: 'Failed randomly. No hard feelings.'&#x000A;    };&#x000A;    </pre>
    <p>In the demo, I used this validation on the <em>Address</em> field like so:</p>
    <pre>var validationConfig = {&#x000A;      /* cilpped for brevity */&#x000A;    &#x000A;      '.address': {&#x000A;        checks: ['random', 'required'],&#x000A;        field: 'Address'&#x000A;      }&#x000A;    };&#x000A;    </pre>
    <hr>
    <h2>Summary</h2>
    <p>I hope that this article has given you a good idea of how you can apply Promises to old problems and build your own framework around them. The Promise-based approach is a fantastic solution to abstract operations that may or may not run synchronously. You can also chain callbacks and even compose higher-order Promises from a set of other Promises.</p>
    <p>The Promise pattern is applicable in a variety of scenarios, and you’ll hopefully encounter some of them and see an immediate match!</p>
    <hr>
    <h2>References</h2>
    <ul>
    <li><a href="http://promises-aplus.github.io/promises-spec/" rel="nofollow external" class="bo">Promises/A+ spec</a></li>
    <li><a href="http://api.jquery.com/category/deferred-object/" rel="nofollow external" class="bo">jQuery.Deferred()</a></li>
    <li><a href="http://documentup.com/kriskowal/q/" rel="nofollow external" class="bo">Q</a></li>
    <li><a href="https://github.com/dfilatov/jspromise" rel="nofollow external" class="bo">jspromise</a></li>
    </ul>
    </div>
]]>
</Body>
<Summary>The concept of “Promises” has changed the way we write asynchronous JavaScript. Over the past year, many frameworks have incorporated some form of the Promise pattern to make asynchronous code...</Summary>
<Website>http://feedproxy.google.com/~r/nettuts/~3/00Nqws5_38U/</Website>
<TrackingUrl>https://my3.my.umbc.edu/api/v0/pixel/news/28272/guest@my.umbc.edu/e7dc9ece7f33f8a911a8594db78e5ea2/api/pixel</TrackingUrl>
<Tag>css</Tag>
<Tag>development</Tag>
<Tag>html</Tag>
<Tag>javascript</Tag>
<Tag>javascript-and-ajax</Tag>
<Tag>mysql</Tag>
<Tag>php</Tag>
<Tag>promises</Tag>
<Tag>sql</Tag>
<Tag>tutorials</Tag>
<Tag>wed</Tag>
<Group token="retired-583">Web Developer - Build Group</Group>
<GroupUrl>https://my3.my.umbc.edu/groups/retired-583</GroupUrl>
<AvatarUrl>https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xsmall.png?1363101197</AvatarUrl>
<AvatarUrl size="original">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/original.jpg?1363101197</AvatarUrl>
<AvatarUrl size="xxlarge">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xxlarge.png?1363101197</AvatarUrl>
<AvatarUrl size="xlarge">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xlarge.png?1363101197</AvatarUrl>
<AvatarUrl size="large">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/large.png?1363101197</AvatarUrl>
<AvatarUrl size="medium">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/medium.png?1363101197</AvatarUrl>
<AvatarUrl size="small">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/small.png?1363101197</AvatarUrl>
<AvatarUrl size="xsmall">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xsmall.png?1363101197</AvatarUrl>
<AvatarUrl size="xxsmall">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xxsmall.png?1363101197</AvatarUrl>
<Sponsor>Web Developer - Build Group</Sponsor>
<PawCount>0</PawCount>
<CommentCount>0</CommentCount>
<CommentsAllowed>true</CommentsAllowed>
<PostedAt>Thu, 25 Apr 2013 17:46:03 -0400</PostedAt>
</NewsItem>

<NewsItem contentIssues="true" id="28269" important="false" status="posted" url="https://my3.my.umbc.edu/posts/28269">
<Title>Intern of the week: Molissa Udevitz for Natural Resources</Title>
<Tagline>Learn about Molissa's experience in Alaska!</Tagline>
<Body>
<![CDATA[
    <div class="html-content">
    <p><span><strong>Name: </strong> Molissa Udevitz</span></p>
    <p><span><strong>Internship, Co-op or Research Site:</strong>  Alaska Department of Natural Resources Division of Forestry</span></p>
    <p><span><strong>Location of the Organization (City, State): </strong> Palmer, Alaska</span></p>
    <p><span><strong>Title of Your Position:</strong>  Squad Leader Intern II</span></p>
    <p><span><strong>Major(s)/Minor(s): </strong> Double Major - Environmental Studies and Dance</span></p>
    <span><strong>Expected Graduation Date (Month &amp; Year):</strong>  May 2015</span><br><br><em><strong><br>1. </strong></em><span><em><strong>Briefly describe your internship, co-op, research or service-learning 
    position/assignment, including your day-to-day tasks and 
    responsibilities.<br></strong></em></span><br><span><span>I work with a crew of nine other interns on various natural resource 
    management projects.  We spend each day out in the field working on 
    projects such as invasive plant surveys and removal, stream bank 
    restoration, and fuels reduction.  As one of two Squad Bosses, I help 
    supervise other crew members and projects as well as assist with 
    communication between our intern supervisor and the crew.</span><em><strong><span><br><br><em><strong>2. </strong></em></span></strong></em></span><span><em><strong><span><em><strong><span>What have you enjoyed the most about your position or organization/company and what have you found most challenging?<br></span></strong></em></span></strong></em></span><br><span><span><span><span>The best part of my internship is that I get to work on a variety of 
    projects and meet different professionals while completing these 
    projects.  I have had the opportunity to meet, work with, and ask 
    questions of professionals who work for both nonprofits and the public 
    sector in natural resource management related jobs.</span></span></span><em><strong><span><em><strong><span></span></strong></em></span></strong></em></span><span><em><strong><span><em><strong><span><span><br><br></span></span></strong></em></span></strong></em><span><span><span>The most challenging part of my internship is identifying with my fellow crew members.  As the only college student on the crew, I have different priorities and goals than the other interns.  However, spending time with people unfamiliar to the college environment has exposed me to a new perspective.</span></span></span><em><strong><span><em><strong><span><span><br><br></span></span></strong></em></span></strong><strong><span><span><span>3. </span></span></span></strong></em></span><span><span><span><span><em><strong><span>What have you gained from your experience that you could not have gained from another summer activity?<br></span></strong></em></span></span></span></span><br><span><span><span><span><span><span>I am fortunate my internship is designed to be educational for interns, 
    and I don’t think another summer opportunity would have provided me with
     the same variety of experiences as this internship has.  Where else 
    could I have given a presentation on invasive plants to youth, learned 
    about forestry inventory and timber sales, attended a community 
    weed-pull event, become wildland fire-fighter certified, and gained 
    leadership experience as a Squad Boss?!</span></span><em><strong><span><span><br><br></span></span></strong><strong><span><span>4. </span></span></strong></em></span></span></span></span><span><span><span><span><span><span><em><strong><span>How do you see your summer work as meaningful? Has it given you a chance to
     work on issues or with communities that matter to you?<br></span></strong></em></span></span></span></span></span></span><br><span><span><span><span><span><span><span><span>My summer work has been meaningful because the projects our crew completed
     will have a lasting positive impact on the environment.  For example, 
    by restoring stream banks, we improved salmon access to spawning 
    grounds.  Some of our other projects, such as making a trail from a 
    campground to a river handicap accessible, will allow people to further 
    enjoy nature for years to come.</span></span><em><strong><span><span><br><br></span></span></strong><strong><span><span>5. </span></span></strong></em></span></span></span></span></span></span><span><span><span><span><span><span><span><span><em><strong><span>How has your summer experience shaped the way you think about your power to
     impact the world? This might involve skills you’ve gained, information 
    you’ve learned, mentors you’ve connected with, or projects you’ve 
    completed.<br></span></strong></em></span></span></span></span></span></span></span></span><br><span><span><span><span><span><span><span><span><span>Before this summer, I knew I wanted to help solve some of the environmental challenges our world faces, but these problems often seem insurmountable.  I wasn’t sure if I would be qualified or capable enough to do this.  This internship introduced me to people who are working to help the environment one project at a time.  I’ve realized that I don’t need to come up with a grand solution; I can join this network of people, and all our individual projects will add up to have a large, positive impact on the environment.</span><em><strong><span><br></span></strong></em></span></span></span></span><em><strong><span><span><br></span></span></strong></em></span></span></span><em><strong><span><em><strong><span><span><br></span></span></strong></em><br></span></strong></em><br><br></span>
    </div>
]]>
</Body>
<Summary>Name:  Molissa Udevitz  Internship, Co-op or Research Site:  Alaska Department of Natural Resources Division of Forestry  Location of the Organization (City, State):  Palmer, Alaska  Title of Your...</Summary>
<TrackingUrl>https://my3.my.umbc.edu/api/v0/pixel/news/28269/guest@my.umbc.edu/5f1aa7b7a6f267fd35139d09c5987224/api/pixel</TrackingUrl>
<Group token="shriver">The Shriver Center</Group>
<GroupUrl>https://my3.my.umbc.edu/groups/shriver</GroupUrl>
<AvatarUrl>https://assets2-my.umbc.edu/system/shared/avatars/groups/000/000/008/0bfad113286cf6b1bc6dedbdbfc7e5ef/xsmall.png?1441293069</AvatarUrl>
<AvatarUrl size="original">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/000/008/0bfad113286cf6b1bc6dedbdbfc7e5ef/original.jpg?1441293069</AvatarUrl>
<AvatarUrl size="xxlarge">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/008/0bfad113286cf6b1bc6dedbdbfc7e5ef/xxlarge.png?1441293069</AvatarUrl>
<AvatarUrl size="xlarge">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/000/008/0bfad113286cf6b1bc6dedbdbfc7e5ef/xlarge.png?1441293069</AvatarUrl>
<AvatarUrl size="large">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/000/008/0bfad113286cf6b1bc6dedbdbfc7e5ef/large.png?1441293069</AvatarUrl>
<AvatarUrl size="medium">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/000/008/0bfad113286cf6b1bc6dedbdbfc7e5ef/medium.png?1441293069</AvatarUrl>
<AvatarUrl size="small">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/008/0bfad113286cf6b1bc6dedbdbfc7e5ef/small.png?1441293069</AvatarUrl>
<AvatarUrl size="xsmall">https://assets2-my.umbc.edu/system/shared/avatars/groups/000/000/008/0bfad113286cf6b1bc6dedbdbfc7e5ef/xsmall.png?1441293069</AvatarUrl>
<AvatarUrl size="xxsmall">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/008/0bfad113286cf6b1bc6dedbdbfc7e5ef/xxsmall.png?1441293069</AvatarUrl>
<Sponsor>Shriver Center:Intern, Co-op, Research &amp; Service-Learning</Sponsor>
<ThumbnailUrl size="xxlarge">https://assets3-my.umbc.edu/system/shared/thumbnails/news/000/028/269/1d26b569fd3472b83bde7bbeb161ddfa/xxlarge.jpg?1366920372</ThumbnailUrl>
<ThumbnailUrl size="xlarge">https://assets4-my.umbc.edu/system/shared/thumbnails/news/000/028/269/1d26b569fd3472b83bde7bbeb161ddfa/xlarge.jpg?1366920372</ThumbnailUrl>
<ThumbnailUrl size="large">https://assets4-my.umbc.edu/system/shared/thumbnails/news/000/028/269/1d26b569fd3472b83bde7bbeb161ddfa/large.jpg?1366920372</ThumbnailUrl>
<ThumbnailUrl size="medium">https://assets1-my.umbc.edu/system/shared/thumbnails/news/000/028/269/1d26b569fd3472b83bde7bbeb161ddfa/medium.jpg?1366920372</ThumbnailUrl>
<ThumbnailUrl size="small">https://assets3-my.umbc.edu/system/shared/thumbnails/news/000/028/269/1d26b569fd3472b83bde7bbeb161ddfa/small.jpg?1366920372</ThumbnailUrl>
<ThumbnailUrl size="xsmall">https://assets3-my.umbc.edu/system/shared/thumbnails/news/000/028/269/1d26b569fd3472b83bde7bbeb161ddfa/xsmall.jpg?1366920372</ThumbnailUrl>
<ThumbnailUrl size="xxsmall">https://assets1-my.umbc.edu/system/shared/thumbnails/news/000/028/269/1d26b569fd3472b83bde7bbeb161ddfa/xxsmall.jpg?1366920372</ThumbnailUrl>
<PawCount>0</PawCount>
<CommentCount>0</CommentCount>
<CommentsAllowed>true</CommentsAllowed>
<PostedAt>Thu, 25 Apr 2013 16:07:08 -0400</PostedAt>
<EditAt>Thu, 25 Apr 2013 16:15:36 -0400</EditAt>
</NewsItem>

<NewsItem contentIssues="true" id="28408" important="false" status="posted" url="https://my3.my.umbc.edu/posts/28408">
<Title>Black and Latino Senior Reception 2013</Title>
<Body>
<![CDATA[
    <div class="html-content">The Chapter of Black and Latino Alumni and the Office of Student Life’s Mosaic: Center for Culture and Diversity hosted the Black and Latino Senior Reception yesterday to celebrate the achievements of the Class of 2013. This annual dessert reception … <a href="https://umbcalumni.wordpress.com/2013/04/25/black-and-latino-senior-reception-2013/" rel="nofollow external" class="bo">Continue reading <span>→</span></a>
    </div>
]]>
</Body>
<Summary>The Chapter of Black and Latino Alumni and the Office of Student Life’s Mosaic: Center for Culture and Diversity hosted the Black and Latino Senior Reception yesterday to celebrate the...</Summary>
<Website>https://umbcalumni.wordpress.com/2013/04/25/black-and-latino-senior-reception-2013/</Website>
<TrackingUrl>https://my3.my.umbc.edu/api/v0/pixel/news/28408/guest@my.umbc.edu/c15672e25ba088c527898fd6768052b8/api/pixel</TrackingUrl>
<Tag>uncategorized</Tag>
<Group token="retired-20">UMBC Alumni</Group>
<GroupUrl>https://my3.my.umbc.edu/groups/retired-20</GroupUrl>
<AvatarUrl>https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/020/08fe2621d8e716b02ec0da35256a998d/xsmall.png?1280681147</AvatarUrl>
<AvatarUrl size="original">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/020/08fe2621d8e716b02ec0da35256a998d/original.png?1280681147</AvatarUrl>
<AvatarUrl size="xxlarge">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/020/08fe2621d8e716b02ec0da35256a998d/xxlarge.png?1280681147</AvatarUrl>
<AvatarUrl size="xlarge">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/020/08fe2621d8e716b02ec0da35256a998d/xlarge.png?1280681147</AvatarUrl>
<AvatarUrl size="large">https://assets1-my.umbc.edu/system/shared/avatars/groups/000/000/020/08fe2621d8e716b02ec0da35256a998d/large.png?1280681147</AvatarUrl>
<AvatarUrl size="medium">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/020/08fe2621d8e716b02ec0da35256a998d/medium.png?1280681147</AvatarUrl>
<AvatarUrl size="small">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/020/08fe2621d8e716b02ec0da35256a998d/small.png?1280681147</AvatarUrl>
<AvatarUrl size="xsmall">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/020/08fe2621d8e716b02ec0da35256a998d/xsmall.png?1280681147</AvatarUrl>
<AvatarUrl size="xxsmall">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/020/08fe2621d8e716b02ec0da35256a998d/xxsmall.png?1280681147</AvatarUrl>
<Sponsor>UMBC Alumni</Sponsor>
<PawCount>0</PawCount>
<CommentCount>0</CommentCount>
<CommentsAllowed>false</CommentsAllowed>
<PostedAt>Thu, 25 Apr 2013 15:48:38 -0400</PostedAt>
</NewsItem>

<NewsItem contentIssues="false" id="107009" important="false" status="posted" url="https://my3.my.umbc.edu/posts/107009">
<Title>Black and Latino Senior Reception 2013</Title>
<Body>
<![CDATA[
    <div class="html-content">The Chapter of Black and Latino Alumni and the Office of Student Life’s Mosaic: Center for Culture and Diversity hosted …</div>
]]>
</Body>
<Summary>The Chapter of Black and Latino Alumni and the Office of Student Life’s Mosaic: Center for Culture and Diversity hosted …</Summary>
<Website>https://magazine.umbc.edu/black-and-latino-senior-reception-2013/</Website>
<TrackingUrl>https://my3.my.umbc.edu/api/v0/pixel/news/107009/guest@my.umbc.edu/0a9a9a42689b06bc58b0b685b0f7665e/api/pixel</TrackingUrl>
<Tag>alumni</Tag>
<Group token="retired-1945">UMBC Magazine</Group>
<GroupUrl>https://my3.my.umbc.edu/groups/retired-1945</GroupUrl>
<AvatarUrl>https://assets1-my.umbc.edu/images/avatars/group/8/xsmall.png?1787842820</AvatarUrl>
<AvatarUrl size="original">https://assets4-my.umbc.edu/images/avatars/group/8/original.png?1787842820</AvatarUrl>
<AvatarUrl size="xxlarge">https://assets3-my.umbc.edu/images/avatars/group/8/xxlarge.png?1787842820</AvatarUrl>
<AvatarUrl size="xlarge">https://assets3-my.umbc.edu/images/avatars/group/8/xlarge.png?1787842820</AvatarUrl>
<AvatarUrl size="large">https://assets2-my.umbc.edu/images/avatars/group/8/large.png?1787842820</AvatarUrl>
<AvatarUrl size="medium">https://assets3-my.umbc.edu/images/avatars/group/8/medium.png?1787842820</AvatarUrl>
<AvatarUrl size="small">https://assets3-my.umbc.edu/images/avatars/group/8/small.png?1787842820</AvatarUrl>
<AvatarUrl size="xsmall">https://assets1-my.umbc.edu/images/avatars/group/8/xsmall.png?1787842820</AvatarUrl>
<AvatarUrl size="xxsmall">https://assets4-my.umbc.edu/images/avatars/group/8/xxsmall.png?1787842820</AvatarUrl>
<Sponsor>UMBC Magazine</Sponsor>
<PawCount>0</PawCount>
<CommentCount>0</CommentCount>
<CommentsAllowed>false</CommentsAllowed>
<PostedAt>Thu, 25 Apr 2013 15:48:38 -0400</PostedAt>
</NewsItem>

<NewsItem contentIssues="true" id="28424" important="false" status="posted" url="https://my3.my.umbc.edu/posts/28424">
<Title>Deal of the week: 54% off PsDefaults</Title>
<Body>
<![CDATA[
    <div class="html-content">
    <p><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/thumbnail21.jpg" alt="Thumbnail" width="200" height="160" style="max-width: 100%; height: auto;">It’s easy to become jaded with an application, especially an application like Photoshop, where you open up a new document to be presented with a blank screen.</p> <p>Professional results are easy to achieve with the right know-how, but professional results take time to produce even for experienced artworkers.</p> <p>So this week our sister site, <a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo">MightyDeals.com,</a> has put together a great deal to spice up your copy of Photoshop. For a limited time you can get <a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo">54% off PsDefaults,</a> a set of Photoshop resources to save time, and maybe even inspire you.</p> <p>The collection, which is a collaboration between the teams at MediaLoot and WeGraphics, includes brushes, patterns, styles and shapes for Adobe Photoshop.</p> <p>Compatible with almost every version of Photoshop including CS2, CS3, CS4, CS5, CS5.5 and CS6; there are more than 1600 items in the collection. That includes over 600 brushes, more than 100 actions, over 350 shapes, 200+ gradients, 150+ patterns and over 140 styles.</p> <p>The resources are all royalty free and certain to save you hours of trial and error. They may even make you look at Photoshop in a whole new way.</p> <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0011.jpg" width="650" style="max-width: 100%; height: auto;"></a></p> <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0021.jpg" width="650" style="max-width: 100%; height: auto;"></a></p> <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0031.jpg" width="650" style="max-width: 100%; height: auto;"></a></p> <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0041.jpg" width="650" style="max-width: 100%; height: auto;"></a></p> <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0051.jpg" width="650" style="max-width: 100%; height: auto;"></a></p> <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0061.jpg" width="650" style="max-width: 100%; height: auto;"></a></p> <p><br><br> </p>
    <table width="100%"> <tbody>
    <tr> <td> <a href="http://www.mightydeals.com/deal/freelance-starter-kit-3.html?ref=inwidget" rel="nofollow external" class="bo"><strong>The Ultimate Freelance Starter Kit – only $29</strong></a> </td> <td> <a href="http://www.mightydeals.com/?ref=inwidget" rel="nofollow external" class="bo"><br> <img src="http://mightydeals.com/web/images/widget-logo.png" height="40" width="90" style="max-width: 100%; height: auto;"><br> </a> </td> </tr> </tbody>
    </table> <p><br> </p> <a href="http://www.webdesignerdepot.com/2013/04/deal-of-the-week-54-off-psdefaults/" rel="nofollow external" class="bo">Source</a> <div><table border="0"><tbody><tr><td>
    <a href="http://share.feedsportal.com/share/twitter/?u=http%3A%2F%2Fwww.webdesignerdepot.com%2F2013%2F04%2Fdeal-of-the-week-54-off-psdefaults%2F&amp;t=Deal+of+the+week%3A+54%25+off+PsDefaults" rel="nofollow external" class="bo"><img src="http://res3.feedsportal.com/social/twitter.png" style="max-width: 100%; height: auto;"></a> <a href="http://share.feedsportal.com/share/facebook/?u=http%3A%2F%2Fwww.webdesignerdepot.com%2F2013%2F04%2Fdeal-of-the-week-54-off-psdefaults%2F&amp;t=Deal+of+the+week%3A+54%25+off+PsDefaults" rel="nofollow external" class="bo"><img src="http://res3.feedsportal.com/social/facebook.png" style="max-width: 100%; height: auto;"></a> <a href="http://share.feedsportal.com/share/linkedin/?u=http%3A%2F%2Fwww.webdesignerdepot.com%2F2013%2F04%2Fdeal-of-the-week-54-off-psdefaults%2F&amp;t=Deal+of+the+week%3A+54%25+off+PsDefaults" rel="nofollow external" class="bo"><img src="http://res3.feedsportal.com/social/linkedin.png" style="max-width: 100%; height: auto;"></a> <a href="http://share.feedsportal.com/share/gplus/?u=http%3A%2F%2Fwww.webdesignerdepot.com%2F2013%2F04%2Fdeal-of-the-week-54-off-psdefaults%2F&amp;t=Deal+of+the+week%3A+54%25+off+PsDefaults" rel="nofollow external" class="bo"><img src="http://res3.feedsportal.com/social/googleplus.png" style="max-width: 100%; height: auto;"></a> <a href="http://share.feedsportal.com/share/email/?u=http%3A%2F%2Fwww.webdesignerdepot.com%2F2013%2F04%2Fdeal-of-the-week-54-off-psdefaults%2F&amp;t=Deal+of+the+week%3A+54%25+off+PsDefaults" rel="nofollow external" class="bo"><img src="http://res3.feedsportal.com/social/email.png" style="max-width: 100%; height: auto;"></a>
    </td></tr></tbody></table></div>
    <br><br><a href="http://da.feedsportal.com/r/164876685506/u/49/f/657673/c/35285/s/2b4ad687/a2.htm" rel="nofollow external" class="bo"><img src="http://da.feedsportal.com/r/164876685506/u/49/f/657673/c/35285/s/2b4ad687/a2.img" style="max-width: 100%; height: auto;"></a>
    </div>
]]>
</Body>
<Summary>It’s easy to become jaded with an application, especially an application like Photoshop, where you open up a new document to be presented with a blank screen.   Professional results are easy to...</Summary>
<Website>http://rss.feedsportal.com/c/35285/f/657673/s/2b4ad687/l/0L0Swebdesignerdepot0N0C20A130C0A40Cdeal0Eof0Ethe0Eweek0E540Eoff0Epsdefaults0C/story01.htm</Website>
<TrackingUrl>https://my3.my.umbc.edu/api/v0/pixel/news/28424/guest@my.umbc.edu/bf7439f0252f43545374990752a22960/api/pixel</TrackingUrl>
<Tag>adobe-photoshop</Tag>
<Tag>art</Tag>
<Tag>brushes</Tag>
<Tag>css</Tag>
<Tag>deal</Tag>
<Tag>deals</Tag>
<Tag>design</Tag>
<Tag>development</Tag>
<Tag>html</Tag>
<Tag>html5</Tag>
<Tag>illustrator</Tag>
<Tag>javascript</Tag>
<Tag>mightydeals-com</Tag>
<Tag>mysql</Tag>
<Tag>oracle</Tag>
<Tag>photoshop</Tag>
<Tag>php</Tag>
<Tag>psdefaults</Tag>
<Tag>sql</Tag>
<Group token="retired-583">Web Developer - Build Group</Group>
<GroupUrl>https://my3.my.umbc.edu/groups/retired-583</GroupUrl>
<AvatarUrl>https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xsmall.png?1363101197</AvatarUrl>
<AvatarUrl size="original">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/original.jpg?1363101197</AvatarUrl>
<AvatarUrl size="xxlarge">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xxlarge.png?1363101197</AvatarUrl>
<AvatarUrl size="xlarge">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xlarge.png?1363101197</AvatarUrl>
<AvatarUrl size="large">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/large.png?1363101197</AvatarUrl>
<AvatarUrl size="medium">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/medium.png?1363101197</AvatarUrl>
<AvatarUrl size="small">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/small.png?1363101197</AvatarUrl>
<AvatarUrl size="xsmall">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xsmall.png?1363101197</AvatarUrl>
<AvatarUrl size="xxsmall">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xxsmall.png?1363101197</AvatarUrl>
<Sponsor>Web Developer - Build Group</Sponsor>
<PawCount>0</PawCount>
<CommentCount>0</CommentCount>
<CommentsAllowed>true</CommentsAllowed>
<PostedAt>Thu, 25 Apr 2013 15:15:28 -0400</PostedAt>
<EditAt>Thu, 25 Apr 2013 15:15:28 -0400</EditAt>
</NewsItem>

<NewsItem contentIssues="true" id="28262" important="false" status="posted" url="https://my3.my.umbc.edu/posts/28262">
<Title>Deal of the week: 54% off PsDefaults</Title>
<Body>
<![CDATA[
    <div class="html-content">
    <p><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/thumbnail21.jpg" alt="Thumbnail" width="200" height="160" style="max-width: 100%; height: auto;">It’s easy to become jaded with an application, especially an application like Photoshop, where you open up a new document to be presented with a blank screen.</p>
    <p>Professional results are easy to achieve with the right know-how, but professional results take time to produce even for experienced artworkers.</p>
    <p>So this week our sister site, <a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo">MightyDeals.com,</a> has put together a great deal to spice up your copy of Photoshop. For a limited time you can get <a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo">54% off PsDefaults,</a> a set of Photoshop resources to save time, and maybe even inspire you.</p>
    <p>The collection, which is a collaboration between the teams at MediaLoot and WeGraphics, includes brushes, patterns, styles and shapes for Adobe Photoshop.</p>
    <p>Compatible with almost every version of Photoshop including CS2, CS3, CS4, CS5, CS5.5 and CS6; there are more than 1600 items in the collection. That includes over 600 brushes, more than 100 actions, over 350 shapes, 200+ gradients, 150+ patterns and over 140 styles.</p>
    <p>The resources are all royalty free and certain to save you hours of trial and error. They may even make you look at Photoshop in a whole new way.</p>
    <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0011.jpg" width="650" style="max-width: 100%; height: auto;"></a></p>
    <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0021.jpg" width="650" style="max-width: 100%; height: auto;"></a></p>
    <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0031.jpg" width="650" style="max-width: 100%; height: auto;"></a></p>
    <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0041.jpg" width="650" style="max-width: 100%; height: auto;"></a></p>
    <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0051.jpg" width="650" style="max-width: 100%; height: auto;"></a></p>
    <p><a href="http://www.mightydeals.com/deal/psdefaults.html?ref=wddpostpspresets" rel="nofollow external" class="bo"><img src="http://netdna.webdesignerdepot.com/uploads/2013/04/0061.jpg" width="650" style="max-width: 100%; height: auto;"></a></p>
    <p><br><br>
    </p>
    <table width="100%">
    <tbody>
    <tr>
    <td>
          <a href="http://www.mightydeals.com/deal/freelance-starter-kit-3.html?ref=inwidget" rel="nofollow external" class="bo"><strong>The Ultimate Freelance Starter Kit – only $29</strong></a>
        </td>
    <td>
          <a href="http://www.mightydeals.com/?ref=inwidget" rel="nofollow external" class="bo"><br>
            <img src="http://mightydeals.com/web/images/widget-logo.png" height="40" width="90" style="max-width: 100%; height: auto;"><br>
          </a>
        </td>
    </tr>
    </tbody>
    </table>
    <p><br> </p>
    <a href="http://www.webdesignerdepot.com/2013/04/deal-of-the-week-54-off-psdefaults/" rel="nofollow external" class="bo">Source</a>
    </div>
]]>
</Body>
<Summary>It’s easy to become jaded with an application, especially an application like Photoshop, where you open up a new document to be presented with a blank screen.   Professional results are easy to...</Summary>
<Website>http://www.webdesignerdepot.com/2013/04/deal-of-the-week-54-off-psdefaults/</Website>
<TrackingUrl>https://my3.my.umbc.edu/api/v0/pixel/news/28262/guest@my.umbc.edu/c3ebab91f751b97e4b1639e665d9b102/api/pixel</TrackingUrl>
<Tag>adobe-photoshop</Tag>
<Tag>art</Tag>
<Tag>brushes</Tag>
<Tag>css</Tag>
<Tag>deal</Tag>
<Tag>deals</Tag>
<Tag>design</Tag>
<Tag>development</Tag>
<Tag>html</Tag>
<Tag>html5</Tag>
<Tag>illustrator</Tag>
<Tag>javascript</Tag>
<Tag>mightydeals-com</Tag>
<Tag>mysql</Tag>
<Tag>oracle</Tag>
<Tag>photoshop</Tag>
<Tag>php</Tag>
<Tag>psdefaults</Tag>
<Tag>sql</Tag>
<Group token="retired-583">Web Developer - Build Group</Group>
<GroupUrl>https://my3.my.umbc.edu/groups/retired-583</GroupUrl>
<AvatarUrl>https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xsmall.png?1363101197</AvatarUrl>
<AvatarUrl size="original">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/original.jpg?1363101197</AvatarUrl>
<AvatarUrl size="xxlarge">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xxlarge.png?1363101197</AvatarUrl>
<AvatarUrl size="xlarge">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xlarge.png?1363101197</AvatarUrl>
<AvatarUrl size="large">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/large.png?1363101197</AvatarUrl>
<AvatarUrl size="medium">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/medium.png?1363101197</AvatarUrl>
<AvatarUrl size="small">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/small.png?1363101197</AvatarUrl>
<AvatarUrl size="xsmall">https://assets3-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xsmall.png?1363101197</AvatarUrl>
<AvatarUrl size="xxsmall">https://assets4-my.umbc.edu/system/shared/avatars/groups/000/000/583/fc60f5d7abc2e080599bb6dc465db54d/xxsmall.png?1363101197</AvatarUrl>
<Sponsor>Web Developer - Build Group</Sponsor>
<PawCount>0</PawCount>
<CommentCount>0</CommentCount>
<CommentsAllowed>true</CommentsAllowed>
<PostedAt>Thu, 25 Apr 2013 15:15:28 -0400</PostedAt>
<EditAt>Thu, 25 Apr 2013 15:15:28 -0400</EditAt>
</NewsItem>

</News>
