From 2de1fb64335cf8f288fd174b2a7f4dec1d35fbd4 Mon Sep 17 00:00:00 2001 From: yubaolee Date: Thu, 21 Apr 2016 15:48:38 +0800 Subject: [PATCH] =?UTF-8?q?1.0=E6=AD=A3=E5=BC=8F=E7=89=88=20=E4=BF=AE?= =?UTF-8?q?=E5=A4=8Dbeta=E7=89=88=E6=9C=AA=E8=83=BD=E8=A7=A3=E5=86=B3?= =?UTF-8?q?=E7=9A=84BUG=EF=BC=9B=20=E5=85=A8=E9=9D=A2=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E9=A1=B5=E9=9D=A2=E7=BB=93=E6=9E=84=EF=BC=8C=E9=87=87=E7=94=A8?= =?UTF-8?q?=E9=9D=A2=E5=90=91=E5=AF=B9=E8=B1=A1JS=E5=BC=80=E5=8F=91?= =?UTF-8?q?=EF=BC=9B=20=E4=BC=98=E5=8C=96=E8=BF=9B=E5=87=BA=E5=BA=93?= =?UTF-8?q?=E7=AE=A1=E7=90=86=E7=A4=BA=E4=BE=8B=EF=BC=8C=E5=AF=B9=E8=B5=84?= =?UTF-8?q?=E6=BA=90=E7=9A=84=E5=BA=94=E7=94=A8=E6=9B=B4=E5=8A=A0=E6=B8=85?= =?UTF-8?q?=E6=99=B0=EF=BC=9B=20=E5=AE=8C=E6=95=B4=E7=9A=84SQL=E5=88=9D?= =?UTF-8?q?=E5=A7=8B=E6=95=B0=E6=8D=AE=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- OpenAuth.App/StockManagerApp.cs | 76 +---- OpenAuth.Domain/Interface/IOrgRepository.cs | 7 + OpenAuth.Domain/OpenAuth.Domain.csproj | 1 + OpenAuth.Domain/Service/AuthoriseService.cs | 1 + .../Service/StockManagerService.cs | 91 ++++++ OpenAuth.Mvc/AutofacExt.cs | 1 + OpenAuth.Mvc/BllScripts/stockManager.js | 9 +- OpenAuth.Mvc/Content/js/purl.js | 267 ++++++++++++++++++ OpenAuth.Mvc/Content/js/util.js | 16 ++ .../Controllers/StockManagerController.cs | 14 +- OpenAuth.Mvc/Views/StockManager/Index.cshtml | 8 +- OpenAuth.Repository/OrgRepository.cs | 14 + 建表&初始化数据.sql | Bin 138774 -> 140876 bytes 13 files changed, 423 insertions(+), 82 deletions(-) create mode 100644 OpenAuth.Domain/Service/StockManagerService.cs create mode 100644 OpenAuth.Mvc/Content/js/purl.js create mode 100644 OpenAuth.Mvc/Content/js/util.js diff --git a/OpenAuth.App/StockManagerApp.cs b/OpenAuth.App/StockManagerApp.cs index ddd784c0..6c33e46d 100644 --- a/OpenAuth.App/StockManagerApp.cs +++ b/OpenAuth.App/StockManagerApp.cs @@ -1,94 +1,36 @@ - -using OpenAuth.Domain; -using OpenAuth.Domain.Interface; -using System.Collections.Generic; -using System.Linq; +using OpenAuth.Domain; using Infrastructure; -using Infrastructure.Helper; -using OpenAuth.App.ViewModel; +using OpenAuth.Domain.Service; namespace OpenAuth.App { public class StockManagerApp { - private IStockRepository _repository; - private IOrgRepository _orgRepository; + private StockManagerService _service; - public StockManagerApp(IStockRepository repository, - IOrgRepository orgRepository) + public StockManagerApp(StockManagerService service) { - _repository = repository; - _orgRepository = orgRepository; + _service = service; } /// /// 根据部门ID得到进出库信息 /// - public dynamic Load(int orgId, int pageindex, int pagesize) + public dynamic Load(string username, int orgId, int pageindex, int pagesize) { - IEnumerable Stocks; - //var user = AutofacExt.GetFromFac().GetLoginUser(); - //var loginOrgs = user.AccessedOrgs.Select(u => u.Id).ToArray(); - - //int total; - //if (orgId == 0) - //{ - - // if (loginOrgs.Length == 0) //改用户没有任何可见机构 - // { - // Stocks = _repository.Find(pageindex, pagesize, "", u => u.User == user.User.Account); - // total = _repository.GetCount(u =>u.User ==user.User.Account); - // } - // else - // { - // Stocks = _repository.LoadInOrgs(pageindex, pagesize, loginOrgs); - // total = _repository.GetStockCntInOrgs(loginOrgs); - // } - - //} - //else //加载选择的机构及用户可访问的所有子机构 - //{ - // var orgs = _orgRepository.GetSubOrgs(orgId).Where(u =>loginOrgs.Contains(u.Id)); - // List orgIds = orgs.Select(u => u.Id).ToList(); - // orgIds.Add(orgId); - // Stocks = _repository.LoadInOrgs(pageindex, pagesize, orgIds.ToArray()); - // total = _repository.GetStockCntInOrgs(orgIds.ToArray()); - //} - - return new - { - // total = total, - // list = Stocks, - pageCurrent = pageindex - }; - } - - public Stock Find(int id) - { - var stock = _repository.FindSingle(u => u.Id == id); - if (stock == null) return new Stock(); - - return stock; + return _service.Load(username, orgId, pageindex, pagesize); } public void Delete(int id) { - _repository.Delete(id); + _service.Delete(id); } public void AddOrUpdate(Stock model) { Stock stock = new Stock(); model.CopyTo(stock); - - if (stock.Id == 0) - { - _repository.Add(stock); - } - else - { - _repository.Update(stock); - } + _service.AddOrUpdate(stock); } diff --git a/OpenAuth.Domain/Interface/IOrgRepository.cs b/OpenAuth.Domain/Interface/IOrgRepository.cs index 7b7f76d4..9d12f062 100644 --- a/OpenAuth.Domain/Interface/IOrgRepository.cs +++ b/OpenAuth.Domain/Interface/IOrgRepository.cs @@ -17,5 +17,12 @@ namespace OpenAuth.Domain.Interface /// /// 部门ID IEnumerable GetSubOrgs(int orgId); + + /// + /// 获取包括自己在内的全部子部门 + /// + /// The org identifier. + /// IEnumerable<Org>. + IEnumerable GetSubWithOwn(int orgId); } } diff --git a/OpenAuth.Domain/OpenAuth.Domain.csproj b/OpenAuth.Domain/OpenAuth.Domain.csproj index ed6bc197..1c6f3011 100644 --- a/OpenAuth.Domain/OpenAuth.Domain.csproj +++ b/OpenAuth.Domain/OpenAuth.Domain.csproj @@ -64,6 +64,7 @@ + diff --git a/OpenAuth.Domain/Service/AuthoriseService.cs b/OpenAuth.Domain/Service/AuthoriseService.cs index d6a1dec8..a4cec20e 100644 --- a/OpenAuth.Domain/Service/AuthoriseService.cs +++ b/OpenAuth.Domain/Service/AuthoriseService.cs @@ -109,6 +109,7 @@ namespace OpenAuth.Domain.Service } else { + _user = _repository.FindSingle(u => u.Account == name); //用户角色 var userRoleIds = _relevanceRepository.Find(u => u.FirstId == _user.Id && u.Key == "UserRole").Select(u => u.SecondId).ToList(); diff --git a/OpenAuth.Domain/Service/StockManagerService.cs b/OpenAuth.Domain/Service/StockManagerService.cs new file mode 100644 index 00000000..41bf53de --- /dev/null +++ b/OpenAuth.Domain/Service/StockManagerService.cs @@ -0,0 +1,91 @@ +using System; +using System.Linq; +using System.Linq.Expressions; +using OpenAuth.Domain.Interface; + +namespace OpenAuth.Domain.Service +{ + /// + /// 领域服务 + /// 进出库管理服务 + /// + public class StockManagerService + { + private IStockRepository _repository; + private IOrgRepository _orgRepository; + private AuthoriseService _authoriseService; + + public StockManagerService(IStockRepository repository, + IOrgRepository orgRepository, AuthoriseService service) + { + _repository = repository; + _orgRepository = orgRepository; + _authoriseService = service; + } + + /// + /// 根据部门ID得到进出库信息 + /// + public dynamic Load(string username, int orgId, int pageindex, int pagesize) + { + + _authoriseService.GetUserAccessed(username); + if (_authoriseService.Orgs.Count == 0) //用户没有任何可见机构 + { + return new + { + total = 0, + pageCurrent = pageindex + }; + } + + var orgIds = _authoriseService.Orgs.Select(u => u.Id).ToArray(); //用户可访问的机构ID + + var orgs = _orgRepository.GetSubWithOwn(orgId) //点击的节点与用户可访问的机构合并 + .Where(u => orgIds.Contains(u.Id)) + .Select(u => u.Id).ToArray(); + + var keys = _authoriseService.Resources.Select(r => r.Key); //用户可访问的资源的KEY列表 + + //由于库存Stock表开始没有设计资源有关的字段,暂时用User字段代替 + Expression> exp = u => orgs.Contains(u.OrgId) && (u.User == "" || keys.Contains(u.User)); + var stocks = _repository.Find(pageindex, pagesize, "", exp); + int total = _repository.GetCount(exp); + + + return new + { + total = total, + list = stocks, + pageCurrent = pageindex + }; + } + + public Stock Find(int id) + { + var stock = _repository.FindSingle(u => u.Id == id); + if (stock == null) return new Stock(); + + return stock; + } + + public void Delete(int id) + { + _repository.Delete(id); + } + + public void AddOrUpdate(Stock stock) + { + + if (stock.Id == 0) + { + _repository.Add(stock); + } + else + { + _repository.Update(stock); + } + + } + } +} diff --git a/OpenAuth.Mvc/AutofacExt.cs b/OpenAuth.Mvc/AutofacExt.cs index 5dc243c5..4f720627 100644 --- a/OpenAuth.Mvc/AutofacExt.cs +++ b/OpenAuth.Mvc/AutofacExt.cs @@ -46,6 +46,7 @@ namespace OpenAuth.Mvc builder.RegisterType(); builder.RegisterType(); builder.RegisterType(); + builder.RegisterType(); // Register your MVC controllers. builder.RegisterControllers(typeof(MvcApplication).Assembly); diff --git a/OpenAuth.Mvc/BllScripts/stockManager.js b/OpenAuth.Mvc/BllScripts/stockManager.js index 7d08ae4e..2355b429 100644 --- a/OpenAuth.Mvc/BllScripts/stockManager.js +++ b/OpenAuth.Mvc/BllScripts/stockManager.js @@ -38,8 +38,9 @@ function MainGrid() { }, { name: 'User', - label: '操作人', - width: 100 + label: '可见范围(测试资源使用)', + width: 100, + items: [{ '': '全部可见' }, { 'ADMIN': '管理员可见' },{'DEV':'开发可见'}], }, { name: 'Time', @@ -193,10 +194,10 @@ var editDlg = function () { show(); $('#Id').val(ret.Id); $('#Name').val(ret.Name); - $('#Number').selectpicker('val', ret.Number); + $('#Number').val(ret.Number); $('#Price').val(ret.Price); $('#Status').selectpicker('val', ret.Status); - $('#User').val(ret.User); + $('#User').selectpicker('val', ret.User); $('#Time').val(ret.Time); $('#OrgId').val(ret.OrgId); parentTree.show(); diff --git a/OpenAuth.Mvc/Content/js/purl.js b/OpenAuth.Mvc/Content/js/purl.js new file mode 100644 index 00000000..d785ff3a --- /dev/null +++ b/OpenAuth.Mvc/Content/js/purl.js @@ -0,0 +1,267 @@ +/* + * Purl (A JavaScript URL parser) v2.3.1 + * Developed and maintanined by Mark Perkins, mark@allmarkedup.com + * Source repository: https://github.com/allmarkedup/jQuery-URL-Parser + * Licensed under an MIT-style license. See https://github.com/allmarkedup/jQuery-URL-Parser/blob/master/LICENSE for details. + */ + +;(function(factory) { + if (typeof define === 'function' && define.amd) { + define(factory); + } else { + window.purl = factory(); + } +})(function() { + + var tag2attr = { + a : 'href', + img : 'src', + form : 'action', + base : 'href', + script : 'src', + iframe : 'src', + link : 'href', + embed : 'src', + object : 'data' + }, + + key = ['source', 'protocol', 'authority', 'userInfo', 'user', 'password', 'host', 'port', 'relative', 'path', 'directory', 'file', 'query', 'fragment'], // keys available to query + + aliases = { 'anchor' : 'fragment' }, // aliases for backwards compatability + + parser = { + strict : /^(?:([^:\/?#]+):)?(?:\/\/((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?))?((((?:[^?#\/]*\/)*)([^?#]*))(?:\?([^#]*))?(?:#(.*))?)/, //less intuitive, more accurate to the specs + loose : /^(?:(?![^:@]+:[^:@\/]*@)([^:\/?#.]+):)?(?:\/\/)?((?:(([^:@]*):?([^:@]*))?@)?([^:\/?#]*)(?::(\d*))?)(((\/(?:[^?#](?![^?#\/]*\.[^?#\/.]+(?:[?#]|$)))*\/?)?([^?#\/]*))(?:\?([^#]*))?(?:#(.*))?)/ // more intuitive, fails on relative paths and deviates from specs + }, + + isint = /^[0-9]+$/; + + function parseUri( url, strictMode ) { + var str = decodeURI( url ), + res = parser[ strictMode || false ? 'strict' : 'loose' ].exec( str ), + uri = { attr : {}, param : {}, seg : {} }, + i = 14; + + while ( i-- ) { + uri.attr[ key[i] ] = res[i] || ''; + } + + // build query and fragment parameters + uri.param['query'] = parseString(uri.attr['query']); + uri.param['fragment'] = parseString(uri.attr['fragment']); + + // split path and fragement into segments + uri.seg['path'] = uri.attr.path.replace(/^\/+|\/+$/g,'').split('/'); + uri.seg['fragment'] = uri.attr.fragment.replace(/^\/+|\/+$/g,'').split('/'); + + // compile a 'base' domain attribute + uri.attr['base'] = uri.attr.host ? (uri.attr.protocol ? uri.attr.protocol+'://'+uri.attr.host : uri.attr.host) + (uri.attr.port ? ':'+uri.attr.port : '') : ''; + + return uri; + } + + function getAttrName( elm ) { + var tn = elm.tagName; + if ( typeof tn !== 'undefined' ) return tag2attr[tn.toLowerCase()]; + return tn; + } + + function promote(parent, key) { + if (parent[key].length === 0) return parent[key] = {}; + var t = {}; + for (var i in parent[key]) t[i] = parent[key][i]; + parent[key] = t; + return t; + } + + function parse(parts, parent, key, val) { + var part = parts.shift(); + if (!part) { + if (isArray(parent[key])) { + parent[key].push(val); + } else if ('object' == typeof parent[key]) { + parent[key] = val; + } else if ('undefined' == typeof parent[key]) { + parent[key] = val; + } else { + parent[key] = [parent[key], val]; + } + } else { + var obj = parent[key] = parent[key] || []; + if (']' == part) { + if (isArray(obj)) { + if ('' !== val) obj.push(val); + } else if ('object' == typeof obj) { + obj[keys(obj).length] = val; + } else { + obj = parent[key] = [parent[key], val]; + } + } else if (~part.indexOf(']')) { + part = part.substr(0, part.length - 1); + if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part, val); + // key + } else { + if (!isint.test(part) && isArray(obj)) obj = promote(parent, key); + parse(parts, obj, part, val); + } + } + } + + function merge(parent, key, val) { + if (~key.indexOf(']')) { + var parts = key.split('['); + parse(parts, parent, 'base', val); + } else { + if (!isint.test(key) && isArray(parent.base)) { + var t = {}; + for (var k in parent.base) t[k] = parent.base[k]; + parent.base = t; + } + if (key !== '') { + set(parent.base, key, val); + } + } + return parent; + } + + function parseString(str) { + return reduce(String(str).split(/&|;/), function(ret, pair) { + try { + pair = decodeURIComponent(pair.replace(/\+/g, ' ')); + } catch(e) { + // ignore + } + var eql = pair.indexOf('='), + brace = lastBraceInKey(pair), + key = pair.substr(0, brace || eql), + val = pair.substr(brace || eql, pair.length); + + val = val.substr(val.indexOf('=') + 1, val.length); + + if (key === '') { + key = pair; + val = ''; + } + + return merge(ret, key, val); + }, { base: {} }).base; + } + + function set(obj, key, val) { + var v = obj[key]; + if (typeof v === 'undefined') { + obj[key] = val; + } else if (isArray(v)) { + v.push(val); + } else { + obj[key] = [v, val]; + } + } + + function lastBraceInKey(str) { + var len = str.length, + brace, + c; + for (var i = 0; i < len; ++i) { + c = str[i]; + if (']' == c) brace = false; + if ('[' == c) brace = true; + if ('=' == c && !brace) return i; + } + } + + function reduce(obj, accumulator){ + var i = 0, + l = obj.length >> 0, + curr = arguments[2]; + while (i < l) { + if (i in obj) curr = accumulator.call(undefined, curr, obj[i], i, obj); + ++i; + } + return curr; + } + + function isArray(vArg) { + return Object.prototype.toString.call(vArg) === "[object Array]"; + } + + function keys(obj) { + var key_array = []; + for ( var prop in obj ) { + if ( obj.hasOwnProperty(prop) ) key_array.push(prop); + } + return key_array; + } + + function purl( url, strictMode ) { + if ( arguments.length === 1 && url === true ) { + strictMode = true; + url = undefined; + } + strictMode = strictMode || false; + url = url || window.location.toString(); + + return { + + data : parseUri(url, strictMode), + + // get various attributes from the URI + attr : function( attr ) { + attr = aliases[attr] || attr; + return typeof attr !== 'undefined' ? this.data.attr[attr] : this.data.attr; + }, + + // return query string parameters + param : function( param ) { + return typeof param !== 'undefined' ? this.data.param.query[param] : this.data.param.query; + }, + + // return fragment parameters + fparam : function( param ) { + return typeof param !== 'undefined' ? this.data.param.fragment[param] : this.data.param.fragment; + }, + + // return path segments + segment : function( seg ) { + if ( typeof seg === 'undefined' ) { + return this.data.seg.path; + } else { + seg = seg < 0 ? this.data.seg.path.length + seg : seg - 1; // negative segments count from the end + return this.data.seg.path[seg]; + } + }, + + // return fragment segments + fsegment : function( seg ) { + if ( typeof seg === 'undefined' ) { + return this.data.seg.fragment; + } else { + seg = seg < 0 ? this.data.seg.fragment.length + seg : seg - 1; // negative segments count from the end + return this.data.seg.fragment[seg]; + } + } + + }; + + } + + purl.jQuery = function($){ + if ($ != null) { + $.fn.url = function( strictMode ) { + var url = ''; + if ( this.length ) { + url = $(this).attr( getAttrName(this[0]) ) || ''; + } + return purl( url, strictMode ); + }; + + $.url = purl; + } + }; + + purl.jQuery(window.jQuery); + + return purl; + +}); \ No newline at end of file diff --git a/OpenAuth.Mvc/Content/js/util.js b/OpenAuth.Mvc/Content/js/util.js new file mode 100644 index 00000000..3fd54aec --- /dev/null +++ b/OpenAuth.Mvc/Content/js/util.js @@ -0,0 +1,16 @@ +// *********************************************************************** +// Assembly : OpenAuth.Mvc +// Author : yubaolee +// Created : 04-20-2016 +// +// Last Modified By : yubaolee +// Last Modified On : 04-20-2016 +// Contact : www.cnblogs.com/yubaolee +// File: util.js +// *********************************************************************** + + +//获取URL参数 +function getURLParameter(name) { + return decodeURIComponent((new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.search) || [, ""])[1].replace(/\+/g, '%20')) || null; +} \ No newline at end of file diff --git a/OpenAuth.Mvc/Controllers/StockManagerController.cs b/OpenAuth.Mvc/Controllers/StockManagerController.cs index 8af9522d..5f72b983 100644 --- a/OpenAuth.Mvc/Controllers/StockManagerController.cs +++ b/OpenAuth.Mvc/Controllers/StockManagerController.cs @@ -3,11 +3,13 @@ using OpenAuth.App; using OpenAuth.Domain; using System; using System.Web.Mvc; -using Infrastructure.Helper; -using OpenAuth.App.ViewModel; namespace OpenAuth.Mvc.Controllers { + /// + /// 进出库管理 + /// 本示例主要演示如何使用用户拥有的机构/资源 + /// public class StockManagerController : BaseController { private StockManagerApp _app; @@ -24,11 +26,6 @@ namespace OpenAuth.Mvc.Controllers return View(); } - public ActionResult Add(int id = 0) - { - return View(_app.Find(id)); - } - //添加或修改Stock [HttpPost] public string Add(Stock model) @@ -37,7 +34,6 @@ namespace OpenAuth.Mvc.Controllers { var newmodel = new Stock(); model.CopyTo(newmodel); - newmodel.User = AutofacExt.GetFromFac().GetLoginUser().User.Account; _app.AddOrUpdate(newmodel); } catch (Exception ex) @@ -53,7 +49,7 @@ namespace OpenAuth.Mvc.Controllers /// public string Load(int parentId, int pageCurrent = 1, int pageSize = 30) { - return JsonHelper.Instance.Serialize(_app.Load(parentId, pageCurrent, pageSize)); + return JsonHelper.Instance.Serialize(_app.Load(User.Identity.Name, parentId, pageCurrent, pageSize)); } public string Delete(int Id) diff --git a/OpenAuth.Mvc/Views/StockManager/Index.cshtml b/OpenAuth.Mvc/Views/StockManager/Index.cshtml index 5550e697..cab48eea 100644 --- a/OpenAuth.Mvc/Views/StockManager/Index.cshtml +++ b/OpenAuth.Mvc/Views/StockManager/Index.cshtml @@ -52,8 +52,12 @@ - - + + diff --git a/OpenAuth.Repository/OrgRepository.cs b/OpenAuth.Repository/OrgRepository.cs index c9ee66ad..bed1c0b8 100644 --- a/OpenAuth.Repository/OrgRepository.cs +++ b/OpenAuth.Repository/OrgRepository.cs @@ -38,5 +38,19 @@ namespace OpenAuth.Repository return Find(u => u.CascadeId.Contains(cascadeId) && u.Id != orgId); } + + public IEnumerable GetSubWithOwn(int orgId) + { + string cascadeId = "0."; + if (orgId != 0) + { + var org = FindSingle(u => u.Id == orgId); + if (org == null) + throw new Exception("未能找到指定对象信息"); + cascadeId = org.CascadeId; + } + + return Find(u => u.CascadeId.Contains(cascadeId)); + } } } diff --git a/建表&初始化数据.sql b/建表&初始化数据.sql index 86ff72689b5a532cc54c6a0cfd50f0bdfdf7864a..c50bb3995f21e715248878a52644ba1756c919b1 100644 GIT binary patch delta 3235 zcmai14NTN!7=QorvAaKrhf<PB zdEUE+&d*JQgQmXeHNn5%*fq%#8yj5ee=Hoi^C$<;_ol#8 zBi(Tru(nxtC!pIH;&cYOOupA^+^9a30@EM()Xjkh7ouDuV}0r=y*7B8 zf<=y7p9YkrWkT!W_=yIM!##V;B2`*+i;(CBADgx#MZq~|CL0FA$OyNiz< zWmpEu8ju{BF?jrdb`tnfaYiQBi2-)Po%~M6bnY9L4&Iu|!Om}Q$RVH+7}TAVoRXLr z?C$9v4YqIiux2!Ue_JzF{-|Sn@uy?##D5+`$@^K#n;92=8PQHIo|CBk=f9SMWDxH~ zWfz_K%Q}4W@6sI%mUu;?U3L{=pZp;SvFz$;iHYr&UO&e!W5%36?`lT=&HbveYfU2j z71^g$l$G$tEgp8~nOJxFdP<_oDeV1-w&YnxA?)=}kQca{QOm=UkI!furw(4!jOs%= zIc!psDP2C_m<({Qjlt%Z-lIXXb@~cv-M(fFx;MNd?~g*wCIvGJ zms_;;Iv-nyhu;h`=^@lQ1`TbJBVCVd(bjESwRQS7jU1m9?0?&6mu=VEU1}f{yRuz> z77q`0X?Am0JOn;4+8H6uF6)kmzCC(dS_NMWoYDun5C6C_3Y>&%E|~JbTTa=(`!nqM05eNRmNyf zZ>8}ItYWCWiZ8^+Qy!DADCaA{@DU@wgcqaq5wTM!zt#~AO$GE0GmXiKQQ6@5E2{P^ z1H0@|ensjb*@I=lJg^^(RS@OAld_i>A)2Z#tu z-^~SUYYEec_NbF}+T5sU99S1EXGK#DZ;!!C-E1>xs^N?Dc#PbERcT+FqeeortHQct zg=3I~x*U0Mh3t^!O*At-sQOXw%ArbEM;4 zXj9_4iX}Ha$G6fUFg=&PSmo?QwRXCB!&~l8>v0fNMoGgBkue@_?BLU#SYI!)Dh%X> zVUNl^)5uNFMtt23^ju|^$INH6uf0ZVaLC5-u`^~kyY7AIdn>!{K9t?z;aGi#JPSxZ z`uQ$cQ_Q8rl0bG{HamhV&t(N4cHki0=Uv6v0*lgN&!QUGc{dS!?hNclk$tj{=MjJ( z>Mbz8w$!X@4DGd^B)d+p@%&c7se}AXPeZe(c!hpesKie+I*QN1&mQ&z3u+$+SCd7K z#2Sap>PSvg1M6aK@WHVh`sO8%pDsOtd+xK4@6H6#od#Zai;@^U3*U2Z=G2*rf(JZ| WIu8H&fKXn}mf1YlKbxNrneq>2pUSoX delta 2850 zcmb7GeN2-_7{6-^w&kTQtU6^XAKPSXg!KbTaf*V_m~3J}MT3&nuc?y}{9<7Vxz(uKh+$$Dwkb0>7n2dExEaDo_VL_%Zwr2H^q=>hyL+DB z`@7#gch6n8pxx81^(VN&KV4GKB}K5VJh{bdpehPiw?sq#CJk#e(#=p^K9S+@FVI`2 zXN%&ffz6Mj@%*!eo!3wYk7r5oR1b~m)Ar1w23YM(dfGxV$@9cYvhiyp7PK5B2`xLB ziZhw`wUKNnHcn!lu{4*;f9JuhLr;D1cd4Fr>*#oDXTRxaam+kYLpG3&WF>hGt~EW$ zJbLQn#6l4#nK_o4m^X&z-s4+*I2o?uLM8gFI+LWaU@V=7G;^7E2J#(9kBFy+=0bjJ ziimAnXo3c}393A1CK;&-q^3;PA4Q|t*(mxuxLPOwpWlix^cEMefHi2T7FktABASL; zSXB;<=R4POM@6G37Y)jS(v(8tCUZ#%nNMCOMI?{RA%!HBq@(;r*dAK8dRy%L{u<_2 z(eY!m9~e(1X$s!eV|w`Tn)K92JnMZ(R-#>1wX$-#j5gt3w9wozB4!Y0XdQ`YyARQ( zAPUA7nV$td|MPJg;??KZL*FL-#93rEu51>0aRkEFl>IsAi@0EadLejHZ4s(ocg8HAmb})#pu(pG!^vH^+k;@K*TT^j*;Z!}JKVXH3NH=X z9?Qm*=joqK@<|pRfv7zLcTYZB8cmboB5KZeA{+OJ?}QC*@4d%er?`{C&^q9UHXo0H_3fgSPWxco zxuG#O1tIZzIqVBY$5@a#XP=2X&iSJcwZqPyL`do{;2yEV9yz2y#^*R9Cv32E&4h<~ z3MS|YN50t0Q6WDl+MY9_tvj(+8nTh}+D{kcQ5wHHL2&?&b%3#O-# zfG4BBrvPtGN$o`OueCqN5!4pqK>EwWoZb`x?t%QLC}V$ zL&=ZuwAw}N!+XsIIr*(vcuALNZ(S1Y_V0ZBK6c^>XA%|ljG63M(59t~zEF(iWe~j0 zdT31;eH4~K4JNd=SrVm?0|Y#WN>sec$(`QArNbT1p*OHfAL|Lv$^*TN;$dS`XLzvc zc$rF+Xm7JwrZv-?8`*W20W-~$`F$67du<$r+7bz>SNQ_(t(7RayEO33ntIWh`G*F2 zUOj-F(-c1j3T2fygi%`6CX6ZT8-#IrLz6HXHu(dk)tySj)EdQ6|K^cE^;?MX_2xds zsBJ`}or>PK5l#Krg91C0zZ4t#J>7)y5C6~-$cHwq(VXR|PF z)+r-Lb}2q5_T0p&6ErYTj~JD{CSlm>+tKJ#h6g?w3=HgRQ+nq=^$WF8vT%vXt20_6 zl)TPpk`-T9zL3J@Mnl~KTy1#?FYw!h(YpxM;3K_dC=@sP{08V>Qj48vl^E&v_!XaJ zicfEc1~Q5baCgN%nJ4~dm?qmkiJC#uk3MDPL}wKVbR2YQA`AnM+Z_4xD}#s0#TTEd zXm_w$6&_PZu}RBcH3d7omCO@IQ~29ejTN82Xt^77dkpYViKN}XxMtY{Ui@9~0!J2N OY_-PI7Hhof3G=_l1c|T!