From 4b0a5eb28827cc85bad4c1c268eb369a7fdc01d8 Mon Sep 17 00:00:00 2001 From: Lucas Constantino Date: Tue, 30 Sep 2014 20:15:50 -0300 Subject: [PATCH 1/2] Modified request interceptor engine to allow the usage of promised based interceptors. --- src/restangular.js | 142 +++++++++++++++++++++++++++++++++------------ 1 file changed, 106 insertions(+), 36 deletions(-) diff --git a/src/restangular.js b/src/restangular.js index 5362b84c..a52e9aeb 100644 --- a/src/restangular.js +++ b/src/restangular.js @@ -13,6 +13,9 @@ var restangular = angular.module('restangular', []); restangular.provider('Restangular', function() { + // Make $q available on callbacks via late variable fullfillment. + var $Q; + // Configuration var Configurer = {}; Configurer.init = function(object, config) { @@ -65,7 +68,7 @@ restangular.provider('Restangular', function() { config.defaultHttpFields = values; return this; }; - + /** * Always return plain data, no restangularized object **/ @@ -350,10 +353,27 @@ restangular.provider('Restangular', function() { config.fullRequestInterceptor = function(element, operation, path, url, headers, params, httpConfig) { var interceptors = angular.copy(config.requestInterceptors); var defaultRequest = config.defaultInterceptor(element, operation, path, url, headers, params, httpConfig); - return _.reduce(interceptors, function(request, interceptor) { - return _.extend(request, interceptor(request.element, operation, - path, url, request.headers, request.params, request.httpConfig)); - }, defaultRequest); + var promise = $Q.when(defaultRequest); + + _.forEach(interceptors, function (interceptor) { + promise = promise.then(function (request) { + var args = [ + request.element, + operation, + path, + url, + request.headers, + request.params, + request.httpConfig + ]; + + return $Q.when(interceptor.apply(window, args)).then(function (req) { + return _.extend(request, req); + }); + }); + }); + + return promise; }; object.addRequestInterceptor = function(interceptor) { @@ -775,6 +795,8 @@ restangular.provider('Restangular', function() { this.$get = ['$http', '$q', function($http, $q) { + // Fullfill $Q. + $Q = $q; function createServiceForConfiguration(config) { var service = {}; @@ -1064,9 +1086,6 @@ restangular.provider('Restangular', function() { var url = urlHandler.fetchUrl(this, what); var whatFetched = what || __this[config.restangularFields.route]; - var request = config.fullRequestInterceptor(null, operation, - whatFetched, url, headers || {}, reqParams || {}, this[config.restangularFields.httpConfig] || {}); - var filledArray = []; filledArray = config.transformElem(filledArray, true, whatFetched, service); @@ -1076,7 +1095,10 @@ restangular.provider('Restangular', function() { method = 'jsonp'; } - var okCallback = function(response) { + /** + * Called upon response success. + */ + function okCallback(response) { var resData = response.data; var fullParams = response.config.params; var data = parseResponse(resData, operation, whatFetched, url, response, deferred); @@ -1131,17 +1153,45 @@ restangular.provider('Restangular', function() { filledArray ); } - }; + } - urlHandler.resource(this, $http, request.httpConfig, request.headers, request.params, what, - this[config.restangularFields.etag], operation)[method]().then(okCallback, function error(response) { + /** + * Called upon response or interception error. + */ + function errorCallback(response) { if (response.status === 304 && __this[config.restangularFields.restangularCollection]) { resolvePromise(deferred, response, __this, filledArray); } else if ( _.every(config.errorInterceptors, function(cb) { return cb(response, deferred, okCallback) !== false; }) ) { // triggered if no callback returns false deferred.reject(response); } - }); + } + + /** + * Called with resolved request from interceptors. + */ + function makeRequest(request) { + urlHandler.resource.apply(urlHandler, [ + __this, + $http, + request.httpConfig, + request.headers, + request.params, + what, + __this[config.restangularFields.etag], + operation + ])[method]().then(okCallback, errorCallback); + } + + config.fullRequestInterceptor.apply(config, [ + null, + operation, + whatFetched, + url, + headers || {}, + reqParams || {}, + this[config.restangularFields.httpConfig] || {} + ]).then(makeRequest, errorCallback); return restangularizePromise(deferred.promise, true, filledArray); } @@ -1173,13 +1223,14 @@ restangular.provider('Restangular', function() { if (_.isObject(callObj) && config.isRestangularized(callObj)) { callObj = stripRestangular(callObj); } - var request = config.fullRequestInterceptor(callObj, operation, route, fetchUrl, - headers || {}, resParams || {}, this[config.restangularFields.httpConfig] || {}); var filledObject = {}; filledObject = config.transformElem(filledObject, false, route, service); - var okCallback = function(response) { + /** + * Called upon response success. + */ + function okCallback(response) { var resData = response.data; var fullParams = response.config.params; var elem = parseResponse(resData, operation, route, fetchUrl, response, deferred); @@ -1218,40 +1269,59 @@ restangular.provider('Restangular', function() { } else { resolvePromise(deferred, response, undefined, filledObject); } - }; + } - var errorCallback = function(response) { + /** + * Called upon response or interception error. + */ + function errorCallback(response) { if (response.status === 304 && config.isSafe(operation)) { resolvePromise(deferred, response, __this, filledObject); } else if ( _.every(config.errorInterceptors, function(cb) { return cb(response, deferred, okCallback) !== false; }) ) { // triggered if no callback returns false deferred.reject(response); } - }; - // Overriding HTTP Method - var callOperation = operation; - var callHeaders = _.extend({}, request.headers); - var isOverrideOperation = config.isOverridenMethod(operation); - if (isOverrideOperation) { - callOperation = 'post'; - callHeaders = _.extend(callHeaders, {'X-HTTP-Method-Override': operation === 'remove' ? 'DELETE' : operation.toUpperCase()}); - } else if (config.jsonp && callOperation === 'get') { - callOperation = 'jsonp'; } - if (config.isSafe(operation)) { + /** + * Called with resolved request from interceptors. + */ + function makeRequest(request) { + // Overring HTTP Method + var callOperation = operation; + var callHeaders = _.extend({}, request.headers); + var isOverrideOperation = config.isOverridenMethod(operation); if (isOverrideOperation) { - urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params, - what, etag, callOperation)[callOperation]({}).then(okCallback, errorCallback); + callOperation = 'post'; + callHeaders = _.extend(callHeaders, {'X-HTTP-Method-Override': operation === 'remove' ? 'DELETE' : operation.toUpperCase()}); + } else if (config.jsonp && callOperation === 'get') { + callOperation = 'jsonp'; + } + + if (config.isSafe(operation)) { + if (isOverrideOperation) { + urlHandler.resource(__this, $http, request.httpConfig, callHeaders, request.params, + what, etag, callOperation)[callOperation]({}).then(okCallback, errorCallback); + } else { + urlHandler.resource(__this, $http, request.httpConfig, callHeaders, request.params, + what, etag, callOperation)[callOperation]().then(okCallback, errorCallback); + } } else { - urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params, - what, etag, callOperation)[callOperation]().then(okCallback, errorCallback); + urlHandler.resource(__this, $http, request.httpConfig, callHeaders, request.params, + what, etag, callOperation)[callOperation](request.element).then(okCallback, errorCallback); } - } else { - urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params, - what, etag, callOperation)[callOperation](request.element).then(okCallback, errorCallback); } + config.fullRequestInterceptor.apply(window, [ + callObj, + operation, + route, + fetchUrl, + headers || {}, + resParams || {}, + this[config.restangularFields.httpConfig] || {} + ]).then(makeRequest, errorCallback); + return restangularizePromise(deferred.promise, false, filledObject); } From 1a20ede81abaeffaab1974fe661ea84e68bbd1df Mon Sep 17 00:00:00 2001 From: Lucas Constantino Date: Tue, 30 Sep 2014 21:51:55 -0300 Subject: [PATCH 2/2] Make a build --- dist/restangular.js | 208 +++++++++++++++++++++++++++++----------- dist/restangular.min.js | 4 +- dist/restangular.zip | Bin 68322 -> 71324 bytes 3 files changed, 156 insertions(+), 56 deletions(-) diff --git a/dist/restangular.js b/dist/restangular.js index dd2e369e..12421b23 100644 --- a/dist/restangular.js +++ b/dist/restangular.js @@ -1,13 +1,26 @@ /** * Restful Resources service for AngularJS apps - * @version v1.5.2 - 2016-02-08 * @link https://github.com/mgonto/restangular + * @version v1.5.2 - 2016-10-26 * @link https://github.com/mgonto/restangular * @author Martin Gontovnikas * @license MIT License, http://www.opensource.org/licenses/MIT - */(function() { + */(function (root, factory) { + // https://github.com/umdjs/umd/blob/master/templates/returnExports.js + if (typeof define === 'function' && define.amd) { + define(['lodash', 'angular'], factory); + } else if (typeof module === 'object' && module.exports) { + module.exports = factory(require('lodash'), require('angular')); + } else { + // No global export, Restangular will register itself as Angular.js module + factory(root._, root.angular); + } +}(this, function (_, angular) { var restangular = angular.module('restangular', []); restangular.provider('Restangular', function() { + // Make $q available on callbacks via late variable fullfillment. + var $Q; + // Configuration var Configurer = {}; Configurer.init = function(object, config) { @@ -61,6 +74,15 @@ restangular.provider('Restangular', function() { return this; }; + /** + * Always return plain data, no restangularized object + **/ + config.plainByDefault = config.plainByDefault || false; + object.setPlainByDefault = function(value) { + config.plainByDefault = value === true ? true : false; + return this; + } + config.withHttpValues = function(httpLocalConfig, obj) { return _.defaults(obj, httpLocalConfig, config.defaultHttpFields); }; @@ -188,12 +210,14 @@ restangular.provider('Restangular', function() { oneUrl: 'oneUrl', allUrl: 'allUrl', customPUT: 'customPUT', + customPATCH: 'customPATCH', customPOST: 'customPOST', customDELETE: 'customDELETE', customGET: 'customGET', customGETLIST: 'customGETLIST', customOperation: 'customOperation', doPUT: 'doPUT', + doPATCH: 'doPATCH', doPOST: 'doPOST', doDELETE: 'doDELETE', doGET: 'doGET', @@ -334,10 +358,27 @@ restangular.provider('Restangular', function() { config.fullRequestInterceptor = function(element, operation, path, url, headers, params, httpConfig) { var interceptors = angular.copy(config.requestInterceptors); var defaultRequest = config.defaultInterceptor(element, operation, path, url, headers, params, httpConfig); - return _.reduce(interceptors, function(request, interceptor) { - return _.extend(request, interceptor(request.element, operation, - path, url, request.headers, request.params, request.httpConfig)); - }, defaultRequest); + var promise = $Q.when(defaultRequest); + + _.forEach(interceptors, function (interceptor) { + promise = promise.then(function (request) { + var args = [ + request.element, + operation, + path, + url, + request.headers, + request.params, + request.httpConfig + ]; + + return $Q.when(interceptor.apply(window, args)).then(function (req) { + return _.extend(request, req); + }); + }); + }); + + return promise; }; object.addRequestInterceptor = function(interceptor) { @@ -641,7 +682,7 @@ restangular.provider('Restangular', function() { Path.prototype = new BaseCreator(); Path.prototype.normalizeUrl = function (url){ - var parts = /(http[s]?:\/\/)?(.*)?/.exec(url); + var parts = /((?:http[s]?:)?\/\/)?(.*)?/.exec(url); parts[2] = parts[2].replace(/[\\\/]+/g, '/'); return (typeof parts[1] !== 'undefined')? parts[1] + parts[2] : parts[2]; }; @@ -759,6 +800,8 @@ restangular.provider('Restangular', function() { this.$get = ['$http', '$q', function($http, $q) { + // Fullfill $Q. + $Q = $q; function createServiceForConfiguration(config) { var service = {}; @@ -927,20 +970,16 @@ restangular.provider('Restangular', function() { function addCustomOperation(elem) { elem[config.restangularFields.customOperation] = _.bind(customFunction, elem); - _.each(['put', 'post', 'get', 'delete'], function(oper) { + var requestMethods = { get: customFunction, delete: customFunction }; + _.each(['put', 'patch', 'post'], function(name) { + requestMethods[name] = function(operation, elem, path, params, headers) { + return _.bind(customFunction, this)(operation, path, params, headers, elem); + }; + }); + _.each(requestMethods, function(requestFunc, name) { + var callOperation = name === 'delete' ? 'remove' : name; _.each(['do', 'custom'], function(alias) { - var callOperation = oper === 'delete' ? 'remove' : oper; - var name = alias + oper.toUpperCase(); - var callFunction; - - if (callOperation !== 'put' && callOperation !== 'post') { - callFunction = customFunction; - } else { - callFunction = function(operation, elem, path, params, headers) { - return _.bind(customFunction, this)(operation, path, params, headers, elem); - }; - } - elem[name] = _.bind(callFunction, elem, callOperation); + elem[alias + name.toUpperCase()] = _.bind(requestFunc, elem, callOperation); }); }); elem[config.restangularFields.customGETLIST] = _.bind(fetchFunction, elem); @@ -1006,7 +1045,9 @@ restangular.provider('Restangular', function() { function restangularizeCollectionAndElements(parent, element, route) { var collection = restangularizeCollection(parent, element, route, false); _.each(collection, function(elem) { - restangularizeElem(parent, elem, route, false); + if (elem) { + restangularizeElem(parent, elem, route, false); + } }); return collection; } @@ -1050,9 +1091,6 @@ restangular.provider('Restangular', function() { var url = urlHandler.fetchUrl(this, what); var whatFetched = what || __this[config.restangularFields.route]; - var request = config.fullRequestInterceptor(null, operation, - whatFetched, url, headers || {}, reqParams || {}, this[config.restangularFields.httpConfig] || {}); - var filledArray = []; filledArray = config.transformElem(filledArray, true, whatFetched, service); @@ -1062,7 +1100,10 @@ restangular.provider('Restangular', function() { method = 'jsonp'; } - var okCallback = function(response) { + /** + * Called upon response success. + */ + function okCallback(response) { var resData = response.data; var fullParams = response.config.params; var data = parseResponse(resData, operation, whatFetched, url, response, deferred); @@ -1074,6 +1115,11 @@ restangular.provider('Restangular', function() { if (!_.isArray(data)) { throw new Error('Response for getList SHOULD be an array and not an object or something else'); } + + if (true === config.plainByDefault) { + return resolvePromise(deferred, response, data, filledArray); + } + var processedData = _.map(data, function(elem) { if (!__this[config.restangularFields.restangularCollection]) { return restangularizeElem(__this, elem, what, true, data); @@ -1112,17 +1158,45 @@ restangular.provider('Restangular', function() { filledArray ); } - }; + } - urlHandler.resource(this, $http, request.httpConfig, request.headers, request.params, what, - this[config.restangularFields.etag], operation)[method]().then(okCallback, function error(response) { + /** + * Called upon response or interception error. + */ + function errorCallback(response) { if (response.status === 304 && __this[config.restangularFields.restangularCollection]) { resolvePromise(deferred, response, __this, filledArray); } else if ( _.every(config.errorInterceptors, function(cb) { return cb(response, deferred, okCallback) !== false; }) ) { // triggered if no callback returns false deferred.reject(response); } - }); + } + + /** + * Called with resolved request from interceptors. + */ + function makeRequest(request) { + urlHandler.resource.apply(urlHandler, [ + __this, + $http, + request.httpConfig, + request.headers, + request.params, + what, + __this[config.restangularFields.etag], + operation + ])[method]().then(okCallback, errorCallback); + } + + config.fullRequestInterceptor.apply(config, [ + null, + operation, + whatFetched, + url, + headers || {}, + reqParams || {}, + this[config.restangularFields.httpConfig] || {} + ]).then(makeRequest, errorCallback); return restangularizePromise(deferred.promise, true, filledArray); } @@ -1154,18 +1228,25 @@ restangular.provider('Restangular', function() { if (_.isObject(callObj) && config.isRestangularized(callObj)) { callObj = stripRestangular(callObj); } - var request = config.fullRequestInterceptor(callObj, operation, route, fetchUrl, - headers || {}, resParams || {}, this[config.restangularFields.httpConfig] || {}); var filledObject = {}; filledObject = config.transformElem(filledObject, false, route, service); - var okCallback = function(response) { + /** + * Called upon response success. + */ + function okCallback(response) { var resData = response.data; var fullParams = response.config.params; var elem = parseResponse(resData, operation, route, fetchUrl, response, deferred); + if (elem) { var data; + + if (true === config.plainByDefault) { + return resolvePromise(deferred, response, elem, filledObject); + } + if (operation === 'post' && !__this[config.restangularFields.restangularCollection]) { data = restangularizeElem( __this[config.restangularFields.parentResource], @@ -1193,40 +1274,59 @@ restangular.provider('Restangular', function() { } else { resolvePromise(deferred, response, undefined, filledObject); } - }; + } - var errorCallback = function(response) { + /** + * Called upon response or interception error. + */ + function errorCallback(response) { if (response.status === 304 && config.isSafe(operation)) { resolvePromise(deferred, response, __this, filledObject); } else if ( _.every(config.errorInterceptors, function(cb) { return cb(response, deferred, okCallback) !== false; }) ) { // triggered if no callback returns false deferred.reject(response); } - }; - // Overriding HTTP Method - var callOperation = operation; - var callHeaders = _.extend({}, request.headers); - var isOverrideOperation = config.isOverridenMethod(operation); - if (isOverrideOperation) { - callOperation = 'post'; - callHeaders = _.extend(callHeaders, {'X-HTTP-Method-Override': operation === 'remove' ? 'DELETE' : operation.toUpperCase()}); - } else if (config.jsonp && callOperation === 'get') { - callOperation = 'jsonp'; } - if (config.isSafe(operation)) { + /** + * Called with resolved request from interceptors. + */ + function makeRequest(request) { + // Overring HTTP Method + var callOperation = operation; + var callHeaders = _.extend({}, request.headers); + var isOverrideOperation = config.isOverridenMethod(operation); if (isOverrideOperation) { - urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params, - what, etag, callOperation)[callOperation]({}).then(okCallback, errorCallback); + callOperation = 'post'; + callHeaders = _.extend(callHeaders, {'X-HTTP-Method-Override': operation === 'remove' ? 'DELETE' : operation.toUpperCase()}); + } else if (config.jsonp && callOperation === 'get') { + callOperation = 'jsonp'; + } + + if (config.isSafe(operation)) { + if (isOverrideOperation) { + urlHandler.resource(__this, $http, request.httpConfig, callHeaders, request.params, + what, etag, callOperation)[callOperation]({}).then(okCallback, errorCallback); + } else { + urlHandler.resource(__this, $http, request.httpConfig, callHeaders, request.params, + what, etag, callOperation)[callOperation]().then(okCallback, errorCallback); + } } else { - urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params, - what, etag, callOperation)[callOperation]().then(okCallback, errorCallback); + urlHandler.resource(__this, $http, request.httpConfig, callHeaders, request.params, + what, etag, callOperation)[callOperation](request.element).then(okCallback, errorCallback); } - } else { - urlHandler.resource(this, $http, request.httpConfig, callHeaders, request.params, - what, etag, callOperation)[callOperation](request.element).then(okCallback, errorCallback); } + config.fullRequestInterceptor.apply(window, [ + callObj, + operation, + route, + fetchUrl, + headers || {}, + resParams || {}, + this[config.restangularFields.httpConfig] || {} + ]).then(makeRequest, errorCallback); + return restangularizePromise(deferred.promise, false, filledObject); } @@ -1351,5 +1451,5 @@ restangular.provider('Restangular', function() { return createServiceForConfiguration(globalConfiguration); }]; }); - -})(); + return restangular.name; +})); diff --git a/dist/restangular.min.js b/dist/restangular.min.js index f0599d58..fdec4dc2 100644 --- a/dist/restangular.min.js +++ b/dist/restangular.min.js @@ -1,6 +1,6 @@ /** * Restful Resources service for AngularJS apps - * @version v1.5.2 - 2016-02-08 * @link https://github.com/mgonto/restangular + * @version v1.5.2 - 2016-10-26 * @link https://github.com/mgonto/restangular * @author Martin Gontovnikas * @license MIT License, http://www.opensource.org/licenses/MIT - */!function(){var a=angular.module("restangular",[]);a.provider("Restangular",function(){var a={};a.init=function(a,b){function c(a,b,c,d){var e={};return _.each(_.keys(d),function(f){var g=d[f];g.params=_.extend({},g.params,a.defaultRequestParams[g.method.toLowerCase()]),_.isEmpty(g.params)&&delete g.params,a.isSafe(g.method)?e[f]=function(){return b(_.extend(g,{url:c}))}:e[f]=function(a){return b(_.extend(g,{url:c,data:a}))}}),e}a.configuration=b;var d=["get","head","options","trace","getlist"];b.isSafe=function(a){return _.includes(d,a.toLowerCase())};var e=/^https?:\/\//i;b.isAbsoluteUrl=function(a){return _.isUndefined(b.absoluteUrl)||_.isNull(b.absoluteUrl)?a&&e.test(a):b.absoluteUrl},b.absoluteUrl=_.isUndefined(b.absoluteUrl)?!0:b.absoluteUrl,a.setSelfLinkAbsoluteUrl=function(a){b.absoluteUrl=a},b.baseUrl=_.isUndefined(b.baseUrl)?"":b.baseUrl,a.setBaseUrl=function(a){return b.baseUrl=/\/$/.test(a)?a.substring(0,a.length-1):a,this},b.extraFields=b.extraFields||[],a.setExtraFields=function(a){return b.extraFields=a,this},b.defaultHttpFields=b.defaultHttpFields||{},a.setDefaultHttpFields=function(a){return b.defaultHttpFields=a,this},b.withHttpValues=function(a,c){return _.defaults(c,a,b.defaultHttpFields)},b.encodeIds=_.isUndefined(b.encodeIds)?!0:b.encodeIds,a.setEncodeIds=function(a){b.encodeIds=a},b.defaultRequestParams=b.defaultRequestParams||{get:{},post:{},put:{},remove:{},common:{}},a.setDefaultRequestParams=function(a,c){var d=[],e=c||a;return _.isUndefined(c)?d.push("common"):_.isArray(a)?d=a:d.push(a),_.each(d,function(a){b.defaultRequestParams[a]=e}),this},a.requestParams=b.defaultRequestParams,b.defaultHeaders=b.defaultHeaders||{},a.setDefaultHeaders=function(c){return b.defaultHeaders=c,a.defaultHeaders=b.defaultHeaders,this},a.defaultHeaders=b.defaultHeaders,b.methodOverriders=b.methodOverriders||[],a.setMethodOverriders=function(a){var c=_.extend([],a);return b.isOverridenMethod("delete",c)&&c.push("remove"),b.methodOverriders=c,this},b.jsonp=_.isUndefined(b.jsonp)?!1:b.jsonp,a.setJsonp=function(a){b.jsonp=a},b.isOverridenMethod=function(a,c){var d=c||b.methodOverriders;return!_.isUndefined(_.find(d,function(b){return b.toLowerCase()===a.toLowerCase()}))},b.urlCreator=b.urlCreator||"path",a.setUrlCreator=function(a){if(!_.has(b.urlCreatorFactory,a))throw new Error("URL Path selected isn't valid");return b.urlCreator=a,this},b.restangularFields=b.restangularFields||{id:"id",route:"route",parentResource:"parentResource",restangularCollection:"restangularCollection",cannonicalId:"__cannonicalId",etag:"restangularEtag",selfLink:"href",get:"get",getList:"getList",put:"put",post:"post",remove:"remove",head:"head",trace:"trace",options:"options",patch:"patch",getRestangularUrl:"getRestangularUrl",getRequestedUrl:"getRequestedUrl",putElement:"putElement",addRestangularMethod:"addRestangularMethod",getParentList:"getParentList",clone:"clone",ids:"ids",httpConfig:"_$httpConfig",reqParams:"reqParams",one:"one",all:"all",several:"several",oneUrl:"oneUrl",allUrl:"allUrl",customPUT:"customPUT",customPOST:"customPOST",customDELETE:"customDELETE",customGET:"customGET",customGETLIST:"customGETLIST",customOperation:"customOperation",doPUT:"doPUT",doPOST:"doPOST",doDELETE:"doDELETE",doGET:"doGET",doGETLIST:"doGETLIST",fromServer:"fromServer",withConfig:"withConfig",withHttpConfig:"withHttpConfig",singleOne:"singleOne",plain:"plain",save:"save",restangularized:"restangularized"},a.setRestangularFields=function(a){return b.restangularFields=_.extend(b.restangularFields,a),this},b.isRestangularized=function(a){return!!a[b.restangularFields.restangularized]},b.setFieldToElem=function(a,b,c){var d=a.split("."),e=b;return _.each(_.initial(d),function(a){e[a]={},e=e[a]}),e[_.last(d)]=c,this},b.getFieldFromElem=function(a,b){var c=a.split("."),d=b;return _.each(c,function(a){d&&(d=d[a])}),angular.copy(d)},b.setIdToElem=function(a,c){return b.setFieldToElem(b.restangularFields.id,a,c),this},b.getIdFromElem=function(a){return b.getFieldFromElem(b.restangularFields.id,a)},b.isValidId=function(a){return""!==a&&!_.isUndefined(a)&&!_.isNull(a)},b.setUrlToElem=function(a,c){return b.setFieldToElem(b.restangularFields.selfLink,a,c),this},b.getUrlFromElem=function(a){return b.getFieldFromElem(b.restangularFields.selfLink,a)},b.useCannonicalId=_.isUndefined(b.useCannonicalId)?!1:b.useCannonicalId,a.setUseCannonicalId=function(a){return b.useCannonicalId=a,this},b.getCannonicalIdFromElem=function(a){var c=a[b.restangularFields.cannonicalId],d=b.isValidId(c)?c:b.getIdFromElem(a);return d},b.responseInterceptors=b.responseInterceptors||[],b.defaultResponseInterceptor=function(a){return a},b.responseExtractor=function(a,c,d,e,f,g){var h=angular.copy(b.responseInterceptors);h.push(b.defaultResponseInterceptor);var i=a;return _.each(h,function(a){i=a(i,c,d,e,f,g)}),i},a.addResponseInterceptor=function(a){return b.responseInterceptors.push(a),this},b.errorInterceptors=b.errorInterceptors||[],a.addErrorInterceptor=function(a){return b.errorInterceptors.push(a),this},a.setResponseInterceptor=a.addResponseInterceptor,a.setResponseExtractor=a.addResponseInterceptor,a.setErrorInterceptor=a.addErrorInterceptor,b.requestInterceptors=b.requestInterceptors||[],b.defaultInterceptor=function(a,b,c,d,e,f,g){return{element:a,headers:e,params:f,httpConfig:g}},b.fullRequestInterceptor=function(a,c,d,e,f,g,h){var i=angular.copy(b.requestInterceptors),j=b.defaultInterceptor(a,c,d,e,f,g,h);return _.reduce(i,function(a,b){return _.extend(a,b(a.element,c,d,e,a.headers,a.params,a.httpConfig))},j)},a.addRequestInterceptor=function(a){return b.requestInterceptors.push(function(b,c,d,e,f,g,h){return{headers:f,params:g,element:a(b,c,d,e),httpConfig:h}}),this},a.setRequestInterceptor=a.addRequestInterceptor,a.addFullRequestInterceptor=function(a){return b.requestInterceptors.push(a),this},a.setFullRequestInterceptor=a.addFullRequestInterceptor,b.onBeforeElemRestangularized=b.onBeforeElemRestangularized||function(a){return a},a.setOnBeforeElemRestangularized=function(a){return b.onBeforeElemRestangularized=a,this},a.setRestangularizePromiseInterceptor=function(a){return b.restangularizePromiseInterceptor=a,this},b.onElemRestangularized=b.onElemRestangularized||function(a){return a},a.setOnElemRestangularized=function(a){return b.onElemRestangularized=a,this},b.shouldSaveParent=b.shouldSaveParent||function(){return!0},a.setParentless=function(a){return _.isArray(a)?b.shouldSaveParent=function(b){return!_.includes(a,b)}:_.isBoolean(a)&&(b.shouldSaveParent=function(){return!a}),this},b.suffix=_.isUndefined(b.suffix)?null:b.suffix,a.setRequestSuffix=function(a){return b.suffix=a,this},b.transformers=b.transformers||{},a.addElementTransformer=function(c,d,e){var f=null,g=null;2===arguments.length?g=d:(g=e,f=d);var h=b.transformers[c];return h||(h=b.transformers[c]=[]),h.push(function(a,b){return _.isNull(f)||a===f?g(b):b}),a},a.extendCollection=function(b,c){return a.addElementTransformer(b,!0,c)},a.extendModel=function(b,c){return a.addElementTransformer(b,!1,c)},b.transformElem=function(a,c,d,e,f){if(!f&&!b.transformLocalElements&&!a[b.restangularFields.fromServer])return a;var g=b.transformers[d],h=a;return g&&_.each(g,function(a){h=a(c,h)}),b.onElemRestangularized(h,c,d,e)},b.transformLocalElements=_.isUndefined(b.transformLocalElements)?!1:b.transformLocalElements,a.setTransformOnlyServerElements=function(a){b.transformLocalElements=!a},b.fullResponse=_.isUndefined(b.fullResponse)?!1:b.fullResponse,a.setFullResponse=function(a){return b.fullResponse=a,this},b.urlCreatorFactory={};var f=function(){};f.prototype.setConfig=function(a){return this.config=a,this},f.prototype.parentsArray=function(a){for(var b=[];a;)b.push(a),a=a[this.config.restangularFields.parentResource];return b.reverse()},f.prototype.resource=function(a,d,e,f,g,h,i,j){var k=_.defaults(g||{},this.config.defaultRequestParams.common),l=_.defaults(f||{},this.config.defaultHeaders);i&&(b.isSafe(j)?l["If-None-Match"]=i:l["If-Match"]=i);var m=this.base(a);if(h){var n="";/\/$/.test(m)||(n+="/"),n+=h,m+=n}return this.config.suffix&&-1===m.indexOf(this.config.suffix,m.length-this.config.suffix.length)&&!this.config.getUrlFromElem(a)&&(m+=this.config.suffix),a[this.config.restangularFields.httpConfig]=void 0,c(this.config,d,m,{getList:this.config.withHttpValues(e,{method:"GET",params:k,headers:l}),get:this.config.withHttpValues(e,{method:"GET",params:k,headers:l}),jsonp:this.config.withHttpValues(e,{method:"jsonp",params:k,headers:l}),put:this.config.withHttpValues(e,{method:"PUT",params:k,headers:l}),post:this.config.withHttpValues(e,{method:"POST",params:k,headers:l}),remove:this.config.withHttpValues(e,{method:"DELETE",params:k,headers:l}),head:this.config.withHttpValues(e,{method:"HEAD",params:k,headers:l}),trace:this.config.withHttpValues(e,{method:"TRACE",params:k,headers:l}),options:this.config.withHttpValues(e,{method:"OPTIONS",params:k,headers:l}),patch:this.config.withHttpValues(e,{method:"PATCH",params:k,headers:l})})};var g=function(){};g.prototype=new f,g.prototype.normalizeUrl=function(a){var b=/(http[s]?:\/\/)?(.*)?/.exec(a);return b[2]=b[2].replace(/[\\\/]+/g,"/"),"undefined"!=typeof b[1]?b[1]+b[2]:b[2]},g.prototype.base=function(a){var c=this;return _.reduce(this.parentsArray(a),function(a,d){var e,f=c.config.getUrlFromElem(d);if(f){if(c.config.isAbsoluteUrl(f))return f;e=f}else if(e=d[c.config.restangularFields.route],d[c.config.restangularFields.restangularCollection]){var g=d[c.config.restangularFields.ids];g&&(e+="/"+g.join(","))}else{var h;h=c.config.useCannonicalId?c.config.getCannonicalIdFromElem(d):c.config.getIdFromElem(d),b.isValidId(h)&&!d.singleOne&&(e+="/"+(c.config.encodeIds?encodeURIComponent(h):h))}return a=a.replace(/\/$/,"")+"/"+e,c.normalizeUrl(a)},this.config.baseUrl)},g.prototype.fetchUrl=function(a,b){var c=this.base(a);return b&&(c+="/"+b),c},g.prototype.fetchRequestedUrl=function(a,c){function d(a){var b=[];for(var c in a)a.hasOwnProperty(c)&&b.push(c);return b.sort()}function e(a,b,c){for(var e=d(a),f=0;fjInDZFe77x?_9a1sAhl-TjwkIbO=fik6*~olw=!K%0?=PB}Tv{)hh5o!*EakI%j^^xq zu@FiXK*)+qa&anW+HuJ+<5t#`G)&`9;v(A=?Uo>L#!@2EpntMZ5w(a*`rE5 zdNxr?>-nDX%2o%kz^r7Z3#NaajBS+C&N_B9WyXqp5z!nn#qP@PO4ZGh=JG+#n} zdO_ML4hX(UVpE)+BNi^C&>`#r!U{RG#OigkaxrNYz!p!U80QROp}^t&L;8d%bsd)U zN!?28Q7{K$kLl@jRF6#*q)AJcNPyC$p0{{+yp&GIvCoW|ErzfSbVyyJ19fws4BWen zjV!OfaA*36K2-omNa7OYZ)GJzFY2n4wbAMw*ZQDoNJ0wiW6K+c_{d#Tmzi+sbRC}k`R9}kB32t{|a-0EU=+% zZg|B7Yd7pXxO-n%>WP&KMLRP>Z|rc>(`%e&!{$wMmo$%WxP(rh%i9?XdZvL7p(9B% zD?^>>2xCwa92cVCTa~0kp}3vjqsNl6#q_^wEK9PLg`i_*4(8=*9i6H|(s>FMiEc%T zq;5o-TO`e(f3z7rpD17_5oblw;fxNMX_LgJI-S>wUOQ*zbuxFiT{P$PVzRoWluuVT zxO9`IZkYK(RVSM`)n4`n05EoQY5Mjx?(u~dbkxOVp^q^kJ(o*Q$w#cLVIP6^;)IH_ z07I&oK@{0by-ka;2ex^tlcgdX*q__0*)QwY&YjqHad3@17$zW#6vhX`%HZ6yLtk6N zPY!_F>nJ%%l<&A}l*D^@VD7}Vue6kj(azC^%wp0uh~?8#!Yqa*p*4FQds6{dX|rh7 zwo9`@eQCi%A(K=h(vvF{3C+Ox7>Bi-T_|!)bBM`VJ!9gOTYXHd-bRE*j5FovF801J ztYNc9_p|HfRnk6$z2zbK1KAj1%%qhn?ptWnjF+=w_Y%1WgJ{N6pBJ_95JD6W0-)2eR|eNn|T$u z!@k6%&0SLCX{4%UD3FOtdk>H=xwkg$bQ3Cvqw)#?E1Hsc2<+}0LzoNB#pDr z-_*`}KHJQGda9lkmG2a&KE8$hxB>9-93L(1!oICc3r$lZq5F0>G{L# z{^Rwqu;7K>?#MuXH=Sqt(MI;bXF8XVakJ6e+Suh|jdQnt`nkpbcd9;j>uopuKTz}j z{$LPB4jp2bp1Okl;LdUOvm0Aj@2Q4LQ;41ZY#+N~wA0`G z$EV_~?GM(lH^01+6#D8KKj?SyF@W4~H09S&pQ3Yg;Bx%b?nSULr;i1j=EWjjH@$}*S~o4*o&j*ok#ySQAX0hZn^uQmyvv~tgBIF zI_RQ$P}8dNhVE{WKZKAa42nlN5)|n{Pz^faZg3n#!a)&mR!E3=y1TnN*dMHV-C5A0 zUeNCnR#bv8N&~zV6eS#$b%f%&7lu0lID7R>Lmp!=a*!*g+3Xm{SGWR8)78oDhSPni)xq4*J)Pc~cF_ zh<1r7?5@We0w&w|z$G0f2_~=awam0p(5l{MW+LNQJ@Y^(#@_fqW1ksv(wKel<=%{W zZ8I~_B!fNmfP#5%JkWNDS(C6~nd&@jW~O6@*kDb{hJA)=2WvVaw2tj6rLn{Yig0K{ zzfYN5ft`M~`Tfq83UW-1V#K^1Dm2f`#%#mfk5kVVh}Q>!`$pnapZaR+I$sNy1UD58 zJX+bvUj1q)V6d$Z2HRnw!r%-Ie2ii}FIy5*Xn$twfunZclt|iv(yV+m2PR2^@?nF855f z`k@`rt-*&{vGG*F&gQgvHpQC(Q_cXPURUt39wHJ?o%!6Ntb)76tjOXj`0JA<1nF&` zJ@?T1rfLJ!L#SLC0BpAYzK#3!YWRWb)&LUW8^i@r+?_XdWc}bx=}Cpue7R>>qDg zEn1y&25b5H&!Ec7AK6N%2zFz7kB8$X^v2rPhvyrm`{A>%)HcFPK?>5Suq?4Czj z(%fqa;hJDXA(ys_axfGGzH2d8ypHaJtMGu94y5%tF^DWq766EeYxG3EA)<%UC@*5* zxMp~Jc<(pb4#7#f%f+gfGisJIt4uB4-7O3H3KpP(W^PK3b4dY4_ZtW8JqU(1cJ9f> z4JIKgXMt#yO*T5Raie9Z6r{M@385Ci&OX+}?tg4~gGq0E%3fq*L`qB=rb&Dis{lN+ zjQxgB1(j*xLwSWnx$u>c(h)Y<9Bl%-Kkk8oD9 z<1?!-P-8F*k1K?jQFu47alhg5Q1>7rMu#8mYFq?B#II!>T=3Z0#y<9V!vME-w{WnB z93YjmE3Bs2Dy}Bfq-qKENkLn=4iLGf6)6GKChK^-zj|E8$gNLw;Cbg0&G?D=i$G>w z4^HX5jrKG&Yeq;nj6F4^zz|(-Aco+V%aFI8I0UMPZ)sw6Pt>)0hgMVSggAJ*a&Sy5 zD{7|V2YmYk+&TQ>Q`M{%6NS%=ClcVIQ|e4t*aJYzYT4@2o$Q%x#PAA~g8Jo#R~>+_ zkwbQ9l4`&z3;t;GoYTW$D>o<-pHtH(AIxABYp=&9yqJOCSJ+n;J zPnw7UP|U^X4?HceF882Yr{*x?C!~qEazRBJ@(6kH>QGliX?QSLNBse}I z;A+GeS1rv8K$G3wIy>-q^NJV{4rhXbeY>gN;z=cUb3}FhJanhlB?Rg8Kt?e99Tf_R zm&-7g;uyLN8gnYL^QKqza?ju&4szf5PS>s)8lF#>AMH@qOL3xA0d56N7Q6Jh_XI39 z{oIEG)?a+Ly;E?Fqq!g0bT_~)$Vv9z?}ipRdU;tHNRht70C-M2p$ujs z!Ts^R19sNz8=`uAa9m4;MWgpFv@ffX8{?T5%w_-)o8v`nEf^d?y4lq)GQ}*EOSZRZ z!G1(Q_-(1#ZJIp`b8MlDGET)QMGFh+?#{CGp3Q+QyXJer6;R8*9gsZJhTGb?ePa6j zNr+$A=}WhwI9bo0|K5t`IKKgOvS~;>t4_m>US+ZMFKhwE9D06JJuFM43E>QT&-1|r zTCab;OEJ`G5ygjtJlYPb0+PeN>CmlQiS2y8J?I-fa?Qbo#hcjfIJR^5!gP9H?8c5pUu>`$ehs+Lez@KR&VZ4}%3QliZ_ zoU2!bSd^W7sUe`VCl9o?BBJvUgV)K(NZ_Eg7~47Av|6YnfE0=uW5aipxq4%V2OU##MqV} zw3MlECDL%6>`~W{RZz_DhAX;niZV^3QCP)?0;C)<=|jY;g&s!r*Ntbo&DTHxH=$_=c?2WP1FuiIrO}U0g)d2Ve3*;r6*)AZ0?5}TXk_uHx_c` zppGGx@`j|ZTh|4r&u{XaF=OKT#xx+b%HVS^H?SA4Ygp$FKH#I$97_XD$K9?Xw&g4# z1ig}H)}rtjcVdaSyM?W8-N%XiTq?Uf8b4}X@9Z$|r@UnqPf4kSL}yX|+KEAb{qjneGzIp~rUTK|4el<|mF9CVx4DBemDZD=+)_s23H8bDZe*r4AsjMU z5$7PZsmXC*WE5NjvB76A^FgbPwM$uCB%;{LziKGpA!o%VkIcX=!1C9qq7;*P`-qg#g733S?8*2A%YteG z4wbbe-pvmExVe!i%gVfB<%$prscs8v)Z#MD-(8jfdb24PjxQKGC z!lqTDq`PiQj<>)J&z)6vpmt*bQKLKxcSm538l?&(nzR^d$+n&i zZYR_mMN+o?IDy zo^2ei*oMPhFN2K>L-a?}gO&Yy!w{J;jtRsPYbVG}AK4{$$ZBgh3;2J`q4MuiKqpfH!BTs;IP;?@K;Zx6P33kmp( zuLf5XXg3si5cD3JTE>PZ>&mWr3_*dowc^$cdKDg0#l2K`XcpI2;xihkPZ76%JZ7Wc z_=pBqe=c8%x`6~yt2BtaHOe);J#tSs#3ij@ue*c?g(l!A&N_&&+|P1+Wyhe{53UzA zV=yQp*SJdK4uOyq`>9LcY@ci^NI?~dGq}8Vegj`--M^H*3hJ5u{`$Yt2 zWEc|~g%hZEsTPt_mvpSQObDx)7XZocy;om-=3}?Zyu^ zdzAOPjSv2+)g5?++ZKp6u) zkKQVlq(oaaOPt0kmN;!7&4xc*=kae!bvowp%9~KjE2o2a<&*tUmk_l>_8ubaggT1N z7i3JWWn_wTrk0UMz(}9b5?`qX44>`lv}5Ge*93ZZHyH^z;SJ>9;VCM3eU!cDKQ0-W za{Z|=L`u(*iP0~388zwiPL>Z^A;%g8u=u_q4%q1$brdNc+$6!Kp|I=EZdw}CaR0%U zzjhId1KMk?>IcQTZlF)AQ!qKN=uN}ehh7T>V(hM)o7p#BTU*{qRLP0Ec!mtZLlRsI z(wDn&6q%jUgj0u2XdjeKHKXQK8?)0q?&7gqCGetRT9A-1L77tm=T%gGfgpTLLd0e4 z4}TrGgfhJC7#XX%Dt42;!!m`~2{rG=YI-Q6=WyRow{D9GD-QprcWH?u3Spe?;6zI= z@iC!<(M9(&;%!zLNWuo4Zxm1|60iai^z| z!L>9b$dgah7CrGGnpCF8czjaAx5G~4GNwi*VEDK!^y=gEA__Zra^!}!!7a%Cpqd$1 z@a?PYe78oIAG4%46I@-@v`<$vT9DU_;7O5qRI)^ogd!BnY0;S(0og6XYM!h1Je|%H z3v*Cr?!gNcny%5s#O*AU1)ZYC1dFEoiXJaKi||UY&^uF9i}_D(VzG~R1cG7rOS}|L zgupHB1#Vd0FQ;9^N5|!h>1^kl{SCXhmDO}0fm=T43%Y?l_c~B>;7AmnHQLC^y6A#rk7l+MJ{9jOqiqK}HY_J=*M9!-u?`%Uh zCdJjG%7EAe{-Y9s%~@t1Eo$Rd&pruKL3N<@x`u$++iCn_nFOHQnd?t&x3dZIkz;h3Ey>6s8%6ABt}zwHgATPW)kx#x35e)fN4(k7GVKLCu_i} zcut;XIxFwwbTA!0sq9N&xkR`Y`)(tu;$Pp@*tBz}0|a!ggdix~cj6OH)$K!e;q)a$ zA96R>gS>IyM6NItXdeK?9blDjwYk*yr3Ov!}bRFm|LkGrTeLcA6{CfDm!Cl;utA{Yl8 zpmHPwqDEou_&gL2ARa<_8xx83Wf`?)bb|MYju5*e-*UQS{6QPu0L*B2qN+-l(?Ho9 zE+k|g$Ky{oq=b^7ufT?nWJmJ!WjB4C3y`8p=U%rAk%%P6(MBP5*}d5}p*Fy>IJ&$= z@C^DMTjCswN9jmo{8kG2y!UyU^QBqD-{w_>#;8Cn3i7Cu;qIG0;gUyTS7mjSmmu6V ziv*6N7@nWBVlI>95z$JeeL=+?J}f#a`~*8koiuNh`0Wl%`I-w9P3xkoj8F0=e0`vV zdZ;@q?dt(CUr)x@Qz+)GoUf?m&d!U?A+_?AyY`500^BjnOJWfF=2x2cx{XJ8n_CEr zX-GVv#KCMGO(!OyoLT&_rwS40vAg3_q$bJ%k#hLb$|Tqp%Zg;0cF{F In*wP1Pa_YG?f?J) delta 12895 zcmbVT3vgW3dG^|pWy`i~qqk-3)k?_s+Se-y0u3uJLN+oMwvhl6nhIg=?!9++rG051 zGD1>z(rGi~Rd7y;Cet#3G^LXg6BA7{P0~E3la@e22~9%4Jc12`I1cZU43h-+`_H-O z-n){VPQxVH-E;o)pa1;t|3Alnf4u7SJyk6u2UbtKmX9j;htbb$03jG_$ zTH@6`7w_)*AS-?EzFNgDWn#r-HlwgLt0ot|zv^qN*@;jMd-Xuw!WY&xZ)DGI`QF0U z+pfQ0W8Ny3@|oa~aNaUYF^dg^n`@Q4HCeI>MJ>qAUDC*Qer+9ls(VvIGE=njF)LTh z<|Ra!ZQfnKy*B9nmoth9Em+E@w4j3|oM7KM(H!=E7K^#P*^Hfxt7@OKa!w1HmTi<$ z#T&%VET}gvM0zd@txW)Yv@q5mS@_5e|6aFX7{6>~^D~>3Y@xVA3+{+p{KK?TR?*rq zrUl)DXLD9w4bHH-xjoE2-ojp=Z7b85+*6P|W#oeyBW(rsppi-%h2X9r0fmd%n{xQv zYZNTSCDU6HGg7I24vYJ0ediAblXg&{>0vB4NCd%lT@UWam5MtK1iQL|%gxbYKx+k_ zAcvHjfWBC%P|T*~0K5CM7j5#B0SKEtd4D~7e`XhZw0i^F^e@%y&t`|JiRw9a?B*?@ zU=VCdkJ5R^0DdGKO=e6^ti-zT*K<4T*dw3(Ak&Z5FKqkN$!d0JreMhG=J&fdH0LiVp;ZQYC`7M49?jW}W-yYq{)=RYG0vJ!jz zABUNC_ZoK51Dy*`KX7K%4xcg+cQ|d!F{tOkPX`)2RqpN%4o?9%X|jXRb^G`ZcGvOC z*<;7AVSn|Ni&*5L5WDrEkFj4obQQjDW|x0u6TAGLb?oDxS;xLTSi{bJvjuQF*zvD4 zfUyVJt0#7{z7yT-;KQo(`)2mw&Fk0?4qw1NbZ51;bbOR)TJ;LLyM|2@>eiMzqOcV3e*;@a2=jy z#1hJp@Psv8P)t>mixgV`$8~em9_x#Tb6kz}BVp_Iq6K?_cGKW$Qf|#)Z(iM0j)#R} z!EGGO9+hrmOx2ErlZC-_t~jkoJZe{$a8^M%qTvjM8x7k6j6kFITiDt=lse-O9R)6_UN#b&Q`NcZ2*I;c&oo4qfzV8&XhaMGoKrPx&Irf2`z;Bh(4&3Cc9VVi5p7M> zA%$>V4dOGgRLQi!9}rn_Hg%4#vh?m-$wL?VBe!(l(%qfxBMbx4LN-+@S~ulWgs4nh zxG4h`PiHv!GY}nw=dT z1MD{+?Evi0A8p(n4Lh-JKN#n(STZ&{3q>5BO++t17QfXhZziq~tZb7$;iDUshLn_157vY=*5sHr!B2Ym}lILQ;Vfe`( zZY_K4Tnwaxsf*SvLFCd=iGL|v)UkKRbt8HL1}=b=9=`w_yYumFK^&3z74zH=X_G3M z7G?Kuu4m6YzAdo~u9!neG(29&W^zj;%|{{SUPzgL7XrSP16K-HAmD<%^}n|6@W~M( zT)MSG9=pE2X{D*LQ;*btAX@1^bX{NMQOG|*NN{R<^Ok`eQ;&Y;i3T`$=p2kv4*Kaz z+DiM8aKb3Sb$ILc88NJ$hV2YL5!vaV(G8a)zL+9SaADzzyH>JW{`+s)${+s{>_7YC z?d+<@YT?nA0=sT_nMsI8Zo`IuLe?87Y+IAO!!pOnFh2j2)-sPuLbA~Da3PmU7L`yq z1osSgyf{Kpgi9K!iXa8OutuTw@DY|y-^jI(9to!m_)AkAgPsa&h=!3O^CRxdXVZho z|8$#$UaLP;v8}me+gOE}nO$9qiGXN~sn|#c=vX#4jm_v($9~$f)o(Qr8sGGAmbO%g z2lcGysj78wRgyCH>Q6%rOX+igYicQ&z}Y3uA$HqO8g_<4NTm@LAauXOHxN_#5RW1T zr>Fc>>mR4*;kO&vT&QL}sj^GZb5C_FPmlwBh$9b|3f5jDlgVb1NWh28C5E+V-Z8O7 zqtMTppY3RaelEi1Dk=Nc&(!LeZj46RTfb{y=YF=K0djI#g3Mj*k42&^_;hQPNkZsR zxzEK1vTXQ?D9b*5@s(UfbJQOt|S6mo7(ItM(;?8zzix z7pOe;Cv~6ie&KXWeUdUQ2N$#?N#V=b*~~uibOVf_M{Q$uC)eWJ{m<05B3@A1J>->? z1t(D6eX@a8)Ho3AqtCa&7zcJXuhb3Jd$Og4dxRUT!lEPb$!0z|xCk{C-hHyMnHa$X zgMU|qhkrZSx<>kWHt=i{d*|dHkomgS%0pmMcSEbg%f(y)!vMP)XbjV2_dnmv?tZQw%ch_2fGqBPzO7o$ zG_8b|y>;|LNo)r%pAo-@jN}&oxEpoUQZXJI-29wT+-Q zi70U$W~-aR7!y!7Kcdmtm{hIA?5wiPG%_$%bIh7;Jl%+PfRl&YNXiWaXuChIM3H)v z$0zmq`l&W{_OUv4`czX>RBP{n=ftp6kQ_ofiERI|7Mi{c)4hD!N0o>@vM=SDfjUEB z+=dH}vdvdDuf`YhcoZ*&u3XO^I$bklaDNkDd_;3hgSV2$jCXZ88DiXLLh1}akO?O! zZgKruuOx)s@Hl}TH!YSY$Y`nNX%P{$5+|R1NrR5!2m9_z)mKHsHUup_(Bjn2x-uYE;oUxoAPLS?ZM*_T5+3mXoC85IV0t$JPGSXlTgZ zeO)$V?LK6nwG$fClMylK{ubJn)+xE*l@Ls&4+3;NV@3~!`cMdVc8kg_4OLPyyYx^u zavOXmwDc}LGsjJEYbMCCh-%a^ldi7ay->Y0+j#BPK$^||BD4ky!Qs%rY}_U+6G)aW zg_g1xesS^UnBtoQkJ7CD)r%BMn-RrzBy`Q-;gBXAWn@Bgd}kyD1wpFBZacFz^nU}h zFTdIuu-KEYwrs9Mfj%FhP<<#yZaUw7IW+zVy2B4WeB-j<>?6Ot2*K4o#npoc2M-UP z=OA>b#fbM04qUw)IIBC;+37=k_=bVK%i?7pI@5(S&z;#)zv#@QEwtT;56#HH;l2Bp z+iwo0D7pvnN;OAAB%dv2i_2nlrj|e_B7A9R=shI4Nv*C@FZqHe%f`!hmV(BK!o$UzF-wRpKXPee= ztAjtrz*ctl>{>AB-LroIfRSIfcA%}~&({)^sG8wIG80c(!x;c&wsD?-54ziJb{=;kQ$a^MKr)G$= zC*Npocha*_Hw0Mld0ycJKREnGYlqBXyn-9HYUq^X%M72D-)O$ZgBy;HTQO?KfN-x( zSIknyh*6|`B1^OpHg<*d&@RxAs*e5#Q9k)b+b!I<e~(qC;|1Oz3f;J5jIu$3=@n?SHeQoA>(UQG*r;@w$P;O(*x_K_@mE zoj2+Nt*doY!*|wxu8BSI=B6!9UwkBNQ-d3|r#3=Gf&|(4R$WIW$PFT`w9E=vieL}K z8Y#T+KKnt51j&4J3SM?h&g4Osvq7LhQeD%+ql)MpT25kNaS90Q*|#=rbdcU57xtDL z*tWM;?Rb|m3Y89J55K)tBBw;(rMI3vZ`WKP zk1}34b>TZ}99iV0K`UV~26vH<6^hL%xz&r+0`rjmkkgCyG3sa>;L3eKUz zkkb+fRJc%Sf+GGN`=5^5tZ*6PXZQZtoU4;@sfA8nN6}NHUg@ZnM@=U?qWmZ9rO^W;a;FV{M zBVIzXe6X^9fB5YN_F{Ui8rLjUE8q;IHSN8scQ7>Rc)=nr6pQT1-!yJX(qY9xO(dMs zDVstIS^aOr9q=c#X(g_4T1PIKyjzU@?zgvI&S~=aZ3#+=5*SA1>WL+*W6Q6my_c*` z$<>ZeMZX*-Ar(AL?Hz;EQjTQ!2u}3Y`#Zxh404X#4@v+m(L&V448cVj;m#~~qi{M= zh5~36^bMb(9>VK!GYwtmu_dOPl)OPTs5@lj<0UHn3ebU1yti$BdsUzY!REw!Td%aV zUbtC33I~o`3nQ0HO)F8-Nn6Jq2sN>?sVVY^@Wv@6M!`0nELgm_;qp-1HQOgoa_NgH zV0XS3+y$SCHWjw?z9=dAjHn4Tdj3sx#mYb)BQE_lxxqOh4g@p!ov> z7s)H#n1g+!Kt6}VN22UMe%HBXl6DuZo6aj8r+k1k#o2EZ8c_^EFOUM_1Nwx&;$|o` z=FtLPA7MZJ{dQ_e^Ts)JK!PDpj`rhrES;UQa4|uN%PwlO`fsjHo$rIb8L|zr8GY|R z5RrVs3HTLRg+zG3I>1#!@42ntx+DmV!;DdFav;hXe)#^j znmBmC7rnoG6@9j!YmvOzi`tCO5$uV-tacNEX*q$|U0*7?Y#sECH$XkyiG6YcSwbU8 z-JQAGo2h5#&aIYvU*j8ZLVqCUE!ppzx@RP?RxTNmnX{hCcjwU1 zGgX0xAzT!~Gr4#6MBXCW$hRI$l9wIVy_{YY4e(MEx-mN|$y;SPR3=3Ly%CaV=hK_s=fD3#>7q?Zp;FE13LW*!x7HgEdzyAlx)?fI$d zfYC`3rVJ--)%^tptm2M1=E_vXF>N)1Dd>wqhejHq_7Otov4X9^ zHfdp?psw%F@(x_l#guX}MX?s?Wk!v-Fi5^RNAL33I z-$bJaNIcPfKs*des-w9vMGY4dRz{ihj*Y;5NzVtsGxU^;MzK`r>T+mrRVsUpO-_s)Ui3DD`(%+QmRf_|%$b>XBLpJTj((glav z9-(+JwQl}LYXh4b2FNIugBZGUT}{8U0?ukP;s^%?c|3^kneVR+G#)fGo++UK^liFF z*ba{4UThF1*ol{NPUu4Y(>e@5?8BpPXJ&~pK}3^!TtI1geUi(&zLhf@tpzvxFeJTX z#4pqZ)^DN=&1o)7QfWnLR|9=hCiR>$iHCxuq15V!ZMH#HhL+Yc8ams!|C~6#VV0=S zDJ?O~62+#pG|Z|0pUsiUiS1(ueq?ge`Sf`wte%|}p-5fZk4Ak#5n-#N+NKc2891L= z7uWz#hQez8?sb9MRRls+)|+2i+o)v`Kw)882|2DGLD>f3q&o=+LWi|<5J7%LSPzqHFtQX4*?aW zHLBVGM2Hs)A@2plK)*7L9F=FmzGZjJui6mkDjWSFr_ULo=K{XWmXd$hjq>yv20IOn z0XD~@B7Qo}Z5(c(f2q#^VeT!Nb_eKme1)auwP|&9daR7cUXFj5(vGT;KLLgGFMrbd zGH6hW^19DQ30%pz=Sq4ZGB14Zg;gWIyVaF&15Pe43Jpg+T&IAtgB_%MQSid9fX*y52fb}wrh+2>fh5KTp>E2DAFZ=Xe zG|f0yEC`7r7^6hBkPza{q9*4ocg_}bsH6HE&5a}!JpSU3FEvxT5PTyXxIl1?8?PXE zT*7OZWJG+MfBk|$YdMMb2NDuIdz7>W523%tGfF(W@n7LP#e7r?RlJQv!$wjg9-6}U zqeh9*Qyhz4zPO05BkoGnq9ahoyUAsq2T>OXPSMsCJe?X=!{{v`_V-y~v}9!+fJ6#& zoOsO&ld{VhoBu+Bg>fgZ^`@Kw%=Y1WxvWsoOazmepsm{UOltUOW+YFqq46G-?jk7c z?vrA)M-yWh^WTf3PNo=aVaDAA-+|v{i#11^4AY55bh@6-#3bR6ZPao-GZ`DT#hySo&M`D6~4!~DteWq8Ldm*)g^ z=x52-%;?Hfg+z}S9K$OJ7eYF9M{4e(qh7bS%