diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..8ccaba8 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 4 +end_of_line = lf +trim_trailing_whitespace = true + +[*.{php,css,js,html}] +indent_style = tab +insert_final_newline = true + +[package*.json] +indent_size = 2 \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/0_support-ticket.md b/.github/ISSUE_TEMPLATE/0_support-ticket.md index 3308ed4..feb7163 100644 --- a/.github/ISSUE_TEMPLATE/0_support-ticket.md +++ b/.github/ISSUE_TEMPLATE/0_support-ticket.md @@ -1,7 +1,7 @@ --- name: Support Ticket about: Get support for an issue you are experiencing -title: "[Support] " +title: "" labels: support assignees: '' @@ -9,11 +9,11 @@ assignees: '' ## Description of Problem - +(Clearly describe the issue you are experiencing here, and fill in the necessary details below) ## Details * URL of Page exhibiting problem: * Browser(s) exhibiting problem (Firefox, Chrome, etc.): * Version of SLB Installed: -* Other plugins installed: +* Other plugins installed: diff --git a/.github/ISSUE_TEMPLATE/1_feature-request.md b/.github/ISSUE_TEMPLATE/1_feature-request.md index a1c9284..70c04c8 100644 --- a/.github/ISSUE_TEMPLATE/1_feature-request.md +++ b/.github/ISSUE_TEMPLATE/1_feature-request.md @@ -1,7 +1,7 @@ --- name: Feature request about: Enhance! Suggest an idea for SLB. -title: "[Request] " +title: "[Request]: " labels: enhancement assignees: '' @@ -9,11 +9,11 @@ assignees: '' ## Description of feature - +(Describe your feature or idea here) ## This feature would be used to - +(Describe usage here) ## If you added this feature, I would: diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000..f71dabf --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: false +contact_links: + - name: Feedback & Support + url: https://github.com/archetyped/simple-lightbox/wiki/Feedback-&-Support + about: How to share feedback and get support for Simple Lightbox \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feedback.md b/.github/ISSUE_TEMPLATE/feedback.md index 3bfbebb..6606437 100644 --- a/.github/ISSUE_TEMPLATE/feedback.md +++ b/.github/ISSUE_TEMPLATE/feedback.md @@ -1,7 +1,7 @@ --- name: Feedback about: Share your feedback -title: "[Feedback] " +title: "[Feedback]: " labels: feedback assignees: '' diff --git a/.gitignore b/.gitignore index a0e3f08..67257d1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +.ds_store .vscode .sass-cache node_modules/ diff --git a/Gruntfile.js b/Gruntfile.js index 1371405..e7de8a8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -44,6 +44,6 @@ module.exports = function(grunt) { grunt.loadTasks('grunt'); // Default Tasks - grunt.registerTask('build', ['phplint', 'jshint:all', 'uglify', 'sass']); + grunt.registerTask('build', ['jshint:all', 'uglify', 'sass']); grunt.registerTask('watch_all', ['watch:js', 'watch:sass']); -}; \ No newline at end of file +}; diff --git a/changelog.txt b/changelog.txt index 4d2622a..0f0d6a9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,3 +1,16 @@ += 2.9.0 = + +* Add: Support WebP image format +* Add: Support AVIF image format +* Add: Documentation link to readme file +* Optimize: Code cleanup/refactoring +* Optimize: WPCS validation (Phase 1) +* Optimize: Activate links after all other filters +* Optimize: Plugin metadata retrieval +* Update: Confirm WordPress 6.0 compatibility +* Update: Build dependencies +* Update: GitHub issue templates + = 2.8.1 = * Update: PHP 5.6 Compatibility diff --git a/client/js/prod/lib.admin.js b/client/js/prod/lib.admin.js index a7ed50e..b873643 100644 --- a/client/js/prod/lib.admin.js +++ b/client/js/prod/lib.admin.js @@ -1 +1 @@ -window.SLB&&SLB.attach&&function($){SLB.attach("Admin",{init:function(){postboxes&&postboxes.add_postbox_toggles(pagenow)}}),$(document).ready(function(){SLB.Admin.init()})}(jQuery); \ No newline at end of file +window.SLB&&SLB.attach&&!function($){SLB.attach("Admin",{init:function(){postboxes&&postboxes.add_postbox_toggles(pagenow)}}),$(document).ready(function(){SLB.Admin.init()})}(jQuery); \ No newline at end of file diff --git a/client/js/prod/lib.core.js b/client/js/prod/lib.core.js index ed1b3f9..9134be3 100644 --- a/client/js/prod/lib.core.js +++ b/client/js/prod/lib.core.js @@ -1 +1 @@ -window.jQuery&&function($){"use strict";function Class(){}var c_init=!1,Base={base:!(Class.extend=function(members){var _super=this.prototype;c_init=!0;var val,name,proto=new this;for(name in c_init=!1,proto)$.isPlainObject(proto[name])&&(val=$.extend({},proto[name]),proto[name]=val);function make_handler(nm,fn){return function(){var tmp=this._super;this._super=_super[nm];var ret=fn.apply(this,arguments);return this._super=tmp,ret}}for(name in members)"function"==typeof members[name]&&"function"==typeof _super[name]?proto[name]=make_handler(name,members[name]):proto[name]=$.isPlainObject(members[name])?$.extend({},members[name]):members[name];function Class(){c_init||("function"==typeof this._init&&this._init.apply(this,arguments),"function"==typeof this._c&&this._c.apply(this,arguments))}return((Class.prototype=proto).constructor=Class).extend=this.extend,Class}),_parent:null,prefix:"slb",_init:function(){this._set_parent()},_set_parent:function(p){this.util.is_set(p)&&(this._parent=p),this.util._parent=this},attach:function(member,data,simple){var ret=data;return simple=void 0!==simple&&!!simple,"string"===$.type(member)&&($.isPlainObject(data)&&!simple&&(data._parent=this,data=this.Class.extend(data)),this[member]="function"===$.type(data)?new data:data,ret=this[member]),ret},has_child:function(child){if(!this.util.is_string(child))return!1;var children=child.split(".");child=null;var x,o=this;for(x=0;x').get(0)},parse_query:function(uri){var i,temp,key,val,delim_vars="&",delim_val="=",query={raw:[],parsed:{},string:""};if(0===(uri=this.parse_uri(uri)).search.indexOf("?"))for(query.raw=uri.search.substr(1).split(delim_vars),i=0;i').get(0)},parse_query:function(uri){var i,key,temp,delim_vars="&",delim_val="=",query={raw:[],parsed:{},string:""};if(0===(uri=this.parse_uri(uri)).search.indexOf("?"))for(query.raw=uri.search.substr(1).split(delim_vars),i=0;i');$("head").append(out.join(""))}}},Component={_slug:"component",_ns:null,_refs:{},_reciprocal:!1,_dom:null,_attributes:!1,_attr_default:{},_attr_default_parsed:!1,_attr_init:null,_attr_map:{},_events:{},_status:null,_id:"",_c:function(id,attributes){this._set_id(id),this.util.is_obj(attributes)&&(this._attr_init=attributes),this._hooks()},_set_parent:function(){this._super(View)},_hooks:function(){},_set_id:function(id){return this.util.is_empty(this._id)&&(this._id=this.util.is_string(id)?id:this.util.guid()),this._id},get_id:function(ns){var id=this._id;return this.util.is_bool(ns)&&ns&&(id=this.add_ns(id)),id},get_ns:function(){return null===this._ns&&(this._ns=this.util.add_prefix(this._slug)),this._ns},add_ns:function(val){return this.util.is_string(val)?this.get_ns()+"_"+val:""},get_status:function(id,raw){var ret=!1;return this.util.in_obj(this._status,id)&&(ret=raw?this._status[id]:!!this._status[id]),ret},set_status:function(id,val){return this.util.is_string(id)?(this.util.is_set(val)||(val=!0),this.util.is_obj(this._status,!1)||(this._status={}),this._status[id]=val):this.util.is_set(val)||(val=!1),val},get_controller:function(){return this.get_parent()},has_reference:function(ref){return!!(this.util.is_string(ref)&&ref in this&&ref in this.get_references())},get_references:function(){return this._refs},get_reference:function(ref){return this.has_reference(ref)?this._refs[ref]:null},get_component:function(cname,options){var c=null;if(!this.has_reference(cname))return c;options=$.extend({},{check_attr:!0,get_default:!1},options);var ctype=this.get_reference(cname);return this.util.is_type(this[cname],ctype)?this[cname]:(c=this[cname]=null,options.check_attr&&(c=this.get_attribute(cname),this.util.is_empty(c)||(c=this.set_component(cname,c))),this.util.is_empty(c)&&options.get_default&&(c=this.get_controller().get_component(ctype)),c)},set_component:function(name,ref,validate){if(!this.has_reference(name))return null;if(this.util.is_empty(ref))ref=null;else{var ctype=this.get_reference(name);this.util.is_string(ref,!1)&&(ref=this.get_controller().get_component(ctype,ref)),this.util.is_type(ref,ctype)&&(!this.util.is_func(validate)||validate.call(this,ref))||(ref=null)}return this[name]=ref,this[name]},clear_component:function(name){this.set_component(name,null)},init_attributes:function(force){if(this.util.is_bool(force)||(force=!1),force||!this.util.is_obj(this._attributes)){var a=this._attributes={};$.extend(a,this.init_default_attributes()),this.util.is_obj(this._attr_init)&&$.extend(a,this._attr_init),$.extend(a,this.get_dom_attributes())}},init_default_attributes:function(){if(!this._attr_default_parsed&&this.util.is_obj(this._attr_map)){var opts=this.get_controller().get_options(this.util.obj_keys(this._attr_map));if(this.util.is_obj(opts)){for(var opt in this._attr_map)opt in opts&&null!==this._attr_map[opt]&&(opts[this._attr_map[opt]]=opts[opt],delete opts[opt]);$.extend(!0,this._attr_default,opts)}this._attr_default_parsed=!0}return this._attr_default},get_dom_attributes:function(){var attrs={},el=this.dom_get(null,{init:!1});if(0",options.tag),attrs).appendTo(d)).length&&this.util.is_method(options,"success")&&options.success.call(r,r),$(r).append(options.content),$(r)},dom_has:function(){return!!this.dom_get().length},get_data_key:function(){return this.get_ns()},on:function(event,fn,options){if(!this.util.is_string(event)||!this.util.is_func(fn)){var t=this,args=Array.prototype.slice.call(arguments,1);return this.util.is_array(event)?$.each(event,function(idx,val){t.on.apply(t,[val].concat(args))}):this.util.is_obj(event)&&$.each(event,function(ev,hdl){t.on.apply(t,[ev,hdl].concat(args))}),this}this.util.is_obj(options,!1)||(options={}),options=$.extend({},{clear:!1},options),this.util.is_obj(this._events,!1)||(this._events={});var es=this._events;return event in es&&this.util.is_obj(es[event],!1)&&!options.clear||(es[event]=[]),es[event].push(fn),this},trigger:function(event,data){var dfr=$.Deferred(),dfrs=[],t=this;if(this.util.is_array(event))return $.each(event,function(idx,val){dfrs.push(t.trigger(val,data))}),$.when.apply(t,dfrs).done(function(){dfr.resolve()}),dfr.promise();if(!(this.util.is_string(event)&&event in this._events))return dfr.resolve(),dfr.promise();var ev={type:event,data:null};return this.util.is_set(data)&&(ev.data=data),$.each(this._events[event],function(idx,fn){dfrs.push(fn.call(t,ev,t))}),$.when.apply(this,dfrs).done(function(){dfr.resolve()}),dfr.promise()}};View.Component=Component=SLB.Class.extend(Component);var Viewer={_slug:"viewer",_refs:{item:"Content_Item",theme:"Theme"},_reciprocal:!0,_attr_default:{loop:!0,animate:!0,autofit:!0,overlay_enabled:!0,overlay_opacity:"0.8",title_default:!1,container:null,slideshow_enabled:!0,slideshow_autostart:!1,slideshow_duration:2,slideshow_active:!1,slideshow_timer:null,labels:{close:"close",nav_prev:"« prev",nav_next:"next »",slideshow_start:"start slideshow",slideshow_stop:"stop slideshow",group_status:"Image %current% of %total%",loading:"loading"}},_attr_map:{theme:null,group_loop:"loop",ui_autofit:"autofit",ui_animate:"animate",ui_overlay_opacity:"overlay_opacity",ui_labels:"labels",ui_title_default:"title_default",slideshow_enabled:null,slideshow_autostart:null,slideshow_duration:null},item:null,item_queued:null,theme:null,item_working:null,active:!1,init:!1,open:!1,loading:!1,_hooks:function(){var t=this;this.on(["item-prev","item-next"],function(){t.trigger("item-change")}).on(["close","item-change"],function(){t.unload().done(function(){t.unlock()})})},get_item:function(){return this.get_component("item")},set_item:function(item){this.clear_item(!1);var i=this.set_component("item",item,function(item){return item.has_type()});return!this.util.is_empty(i)},clear_item:function(full){this.util.is_bool(full)||(full=!0);var item=this.get_item();item&&item.reset(),full&&this.clear_component("item")},get_theme:function(){var ret=this.get_component("theme",{check_attr:!1});return this.util.is_empty(ret)&&(ret=this.set_component("theme",new View.Theme(this))),ret},set_theme:function(theme){this.set_component("theme",theme)},lock:function(){return this.set_status("item_working",$.Deferred())},get_lock:function(simple,full){this.util.is_bool(simple)||(simple=!1),this.util.is_bool(full)||(full=!1);var s="item_working";if(simple)return this.get_status(s);var r=this.get_status(s,!0);return this.util.is_promise(r)||(r=this.lock()),full?r:r.promise()},is_locked:function(){return this.get_lock(!0)},unlock:function(){return this.get_lock(!1,!0).resolve()},set_active:function(mode){return this.util.is_bool(mode)||(mode=!0),this.set_status("active",mode)},is_active:function(){return this.get_status("active")},set_loading:function(mode){var dfr=$.Deferred();this.util.is_bool(mode)||(mode=!0),this.loading=mode,this.slideshow_active()&&this.slideshow_pause(mode);var m=mode?"addClass":"removeClass";return $(this.dom_get())[m]("loading"),mode?this.get_theme().transition("load").always(function(){dfr.resolve()}):dfr.resolve(),dfr.promise()},unset_loading:function(){return this.set_loading(!1)},get_loading:function(){return!!this.util.is_bool(this.loading)&&this.loading},is_loading:function(){return this.get_loading()},show:function(item){this.item_queued=item;var vt="theme_valid",valid=!0;if(this.has_attribute(vt)?valid=this.get_attribute(vt,!0):(valid=!(!this.get_theme()||""===this.get_theme().get_template().get_layout(!1)),this.set_attribute(vt,valid)),!valid)return this.close(),!1;function fin(){if(v.lock(),v.set_status("show_deferred",!1),!v.set_item(v.item_queued))return v.close(),!1;v.history_add(),v.set_active(),v.render()}var v=this;this.is_locked()?this.get_status("show_deferred")||(this.set_status("show_deferred"),this.get_lock().always(function(){fin()})):fin()},history_handle:function(e){var state=e.originalEvent.state;if(this.util.is_string(state.item,!1))this.get_controller().get_item(state.item).show({event:e}),this.trigger("item-change");else{var count=this.history_get(!0);this.history_set(0),-1!==count&&this.close()}},history_get:function(full){return this.get_status("history_count",full)},history_set:function(val){return this.set_status("history_count",val)},history_add:function(){if(!history.pushState)return!1;var item=this.get_item(),opts=item.get_attribute("options_show"),count=this.history_get()?this.history_get(!0):0;if(this.util.in_obj(opts,"event")){var e=opts.event.originalEvent;this.util.in_obj(e,"state")&&this.util.in_obj(e.state,"count")&&(count=e.state.count)}else{var state={viewer:this.get_id(),item:null,count:count};count||history.replaceState(state,null),state.item=this.get_controller().save_item(item).get_id(),state.count=++count,history.pushState(state,"")}this.history_set(count)},history_reset:function(){var count=this.history_get(!0);count&&(this.history_set(-1),history.go(-1*count))},is_open:function(){return"none"!==this.dom_get().css("display")},render:function(){var v=this,thm=this.get_theme();v.dom_prep(),this.get_status("render-events")||(this.set_status("render-events"),thm.on("render-loading",function(ev,thm){var dfr=$.Deferred();if(!v.is_active())return dfr.reject(),dfr.promise();function set_pos(){v.dom_get().css("top",$(window).scrollTop())}function always(){v.set_loading().always(function(){dfr.resolve()})}return v.is_open()?thm.transition("unload").fail(function(){set_pos(),thm.dom_get_tag("item","content").attr("style","")}).always(always):thm.transition("open").always(function(){always(),v.events_open(),v.open=!0}).fail(function(){set_pos(),v.get_overlay().show(),v.dom_get().show()}),dfr.promise()}).on("render-complete",function(ev,thm){if(!v.is_active())return!1;var d=v.dom_get(),classes=["item_single","item_multi"],ms=["addClass","removeClass"];v.get_item().get_group().is_single()||ms.reverse(),$.each(ms,function(idx,val){d[val](classes[idx])}),v.events_complete(),thm.transition("complete").fail(function(){if(v.get_attribute("autofit",!0)){var dims=$.extend({display:"inline-block"},thm.get_item_dimensions());thm.dom_get_tag("item","content").css(dims)}}).always(function(){v.unset_loading(),v.trigger("render-complete"),v.init=!0})})),thm.render()},dom_get_container:function(){var sel=this.get_attribute("container");this.util.is_empty(sel)&&(sel="#"+this.add_ns("wrap"));var c=$(sel);if(!c.length){var id=0===sel.indexOf("#")?sel.substr(1):sel;c=$("
",{id:id}).appendTo("body")}return c},dom_init:function(){var d=this.dom_set($("
",{id:this.get_id(!0),class:this.get_ns()})).appendTo(this.dom_get_container()).hide(),thm=this.get_theme();d.addClass(thm.get_classes(" "));var v=this;this.get_status("render-init")||(this.set_status("render-init"),thm.on("render-init",function(ev){v.dom_put("layout",ev.data)})),thm.render(!0)},dom_prep:function(mode){var m=this.util.is_bool(mode)&&!mode?"removeClass":"addClass";$("html")[m](this.util.add_prefix("overlay"))},dom_restore:function(){this.dom_prep(!1)},get_layout:function(){return this.dom_get("layout",{put:{success:function(){$(this).hide()}}})},animation_enabled:function(){return this.get_attribute("animate",!0)},overlay_enabled:function(){var ov=this.get_attribute("overlay_enabled");return!!this.util.is_bool(ov)&&ov},get_overlay:function(){var o=null,v=this;return this.overlay_enabled()&&(o=this.dom_get("overlay",{put:{success:function(){$(this).hide().css("opacity",v.get_attribute("overlay_opacity"))}}})),$(o)},unload:function(){var dfr=$.Deferred();return this.get_theme().dom_get_tag("item").text(""),dfr.resolve(),dfr.promise()},reset:function(){this.dom_get().hide(),this.dom_restore(),this.history_reset(),this.clear_item(),this.set_active(!1),this.set_loading(!1),this.slideshow_stop(),this.keys_disable(),this.unlock()},get_labels:function(){return this.get_attribute("labels",{})},get_label:function(name){var lbls=this.get_labels();return name in lbls?lbls[name]:""},events_open:function(){if(this.keys_enable(),this.open)return!1;var l=this.get_layout();l.children().click(function(ev){ev.stopPropagation()});function close(){v.close()}var v=this;l.click(close),this.get_overlay().click(close),this.trigger("events-open")},events_complete:function(){if(this.init)return!1;this.trigger("events-complete")},keys_enable:function(mode){this.util.is_bool(mode)||(mode=!0);var e=["keyup",this.util.get_prefix()].join("."),v=this;mode?$(document).on(e,function(ev){return v.keys_control(ev)}):$(document).off(e)},keys_disable:function(){this.keys_enable(!1)},keys_control:function(ev){var handlers={27:this.close,37:this.item_prev,39:this.item_next};if("rtl"===document.documentElement.getAttribute("dir")&&(handlers[37]=this.item_next,handlers[39]=this.item_prev),ev.which in handlers)return handlers[ev.which].call(this),!1},slideshow_enabled:function(){var o=this.get_attribute("slideshow_enabled");return!(!(this.util.is_bool(o)&&o&&this.get_item())||this.get_item().get_group().is_single())},slideshow_active:function(){return!(!this.slideshow_enabled()||!(this.get_attribute("slideshow_active")||!this.init&&this.get_attribute("slideshow_autostart")))},slideshow_clear_timer:function(){clearInterval(this.get_attribute("slideshow_timer"))},slideshow_set_timer:function(callback){this.set_attribute("slideshow_timer",setInterval(callback,1e3*this.get_attribute("slideshow_duration")))},slideshow_start:function(){if(!this.slideshow_enabled())return!1;this.set_attribute("slideshow_active",!0),this.dom_get().addClass("slideshow_active"),this.slideshow_clear_timer();var v=this;this.slideshow_set_timer(function(){v.slideshow_pause(),v.item_next()}),this.trigger("slideshow-start")},slideshow_stop:function(full){this.util.is_bool(full)||(full=!0),full&&(this.set_attribute("slideshow_active",!1),this.dom_get().removeClass("slideshow_active")),this.slideshow_clear_timer(),this.trigger("slideshow-stop")},slideshow_toggle:function(){if(!this.slideshow_enabled())return!1;this.slideshow_active()?this.slideshow_stop():this.slideshow_start(),this.trigger("slideshow-toggle")},slideshow_pause:function(mode){this.util.is_bool(mode)||(mode=!0),this.slideshow_active()&&(mode?this.slideshow_stop(!1):this.slideshow_start()),this.trigger("slideshow-pause")},slideshow_resume:function(){this.slideshow_pause(!1)},item_next:function(){var g=this.get_item().get_group(!0),v=this,ev="item-next",st=["events","viewer",ev].join("_");g.get_status(st)||(g.set_status(st),g.on(ev,function(e){v.trigger(e.type)})),g.show_next()},item_prev:function(){var g=this.get_item().get_group(!0),v=this,ev="item-prev",st=["events","viewer",ev].join("_");g.get_status(st)||(g.set_status(st),g.on(ev,function(){v.trigger(ev)})),g.show_prev()},close:function(){this.set_active(!1);var v=this,thm=this.get_theme();return thm.transition("unload").always(function(){thm.transition("close",!0).always(function(){v.reset(),v.trigger("close")})}).fail(function(){thm.dom_get_tag("item","content").attr("style","")}),!1}};View.Viewer=Component.extend(Viewer);var Group={_slug:"group",_reciprocal:!0,_refs:{current:"Content_Item"},current:null,selector:null,_hooks:function(){var t=this;this.on(["item-prev","item-next"],function(){t.trigger("item-change")})},get_selector:function(){return this.util.is_empty(this.selector)&&(this.selector=this.util.format('a[%s="%s"]',this.dom_get_attribute(),this.get_id())),this.selector},get_items:function(){var items=$(this.get_selector());return 0===items.length&&this.has_current()&&(items=this.get_current().dom_get()),items},get_item:function(idx){this.util.is_int(idx)||(idx=0);var items=this.get_items(),max=this.get_size()-1;return maxoffset.width&&(max.width-=offset.width),max.height>offset.height&&(max.height-=offset.height);var factor=Math.min(max.width/dims.width,max.height/dims.height);factor<1&&$.each(dims,function(key){dims[key]=Math.round(dims[key]*factor)})}return $.extend({},dims)},get_dimensions:function(){var dims=this.get_item_dimensions(),offset=this.get_offset();return $.each(dims,function(key){dims[key]+=offset[key]}),dims},get_breakpoints:function(){return this.get_attribute_recursive("breakpoints")},get_breakpoint:function(target){var ret=0;if(this.util.is_string(target)){var b=this.get_attribute_recursive("breakpoints");this.util.is_obj(b)&&target in b&&(ret=b[target])}return ret},render:function(init){var thm=this,tpl=this.get_template(),st="events_render";this.get_status(st)||(this.set_status(st),tpl.on(["render-init","render-loading","render-complete"],function(ev){return thm.trigger(ev.type,ev.data)})),tpl.render(init)},transition:function(event,clear_queue){var dfr=null,attr="transition",v=this.get_viewer(),fx_temp=null,anim_on=v.animation_enabled();if(v.get_attribute(attr,!0)&&this.util.is_string(event)){clear_queue&&v.get_layout().find("*").each(function(){for(var el=$(this);el.queue().length;)el.stop(!1,!0)});var trns,attr_set=[attr,"set"].join("_");if(this.get_attribute(attr_set))trns=this.get_attribute(attr,{});else{var models=this.get_ancestors(!0);trns=[],this.set_attribute(attr_set,!0);var thm=this;$.each(models,function(idx,model){attr in model&&thm.util.is_obj(model[attr])&&trns.push(model[attr])}),trns.push({}),trns=this.set_attribute(attr,$.extend.apply($,trns.reverse()))}this.util.is_method(trns,event)&&(anim_on||(fx_temp=$.fx.off,$.fx.off=!0),dfr=trns[event].call(this,v,$.Deferred()))}return this.util.is_promise(dfr)||(dfr=$.Deferred()).reject(),dfr.always(function(){null!==fx_temp&&($.fx.off=fx_temp)}),dfr.promise()}};View.Theme=Modeled_Component.extend(Theme);var Template={_slug:"template",_reciprocal:!0,_refs:{theme:"Theme"},_attr_default:{layout_uri:"",layout_raw:"",layout_parsed:"",tags:null,model:null},theme:null,_c:function(attributes){this._super("",attributes)},_hooks:function(){this.on("dom_init",function(ev){var tags=this.get_tags(null,null,!0),names=[],t=this;$.each(tags,function(idx,tag){var name=tag.get_name();-1===$.inArray(name,names)&&(names.push(name),tag.get_handler().trigger(ev.type,{template:t}))})})},get_theme:function(){return this.get_component("theme")},render:function(init){var v=this.get_theme().get_viewer();if(this.util.is_bool(init)||(init=!1),init)this.trigger("render-init",this.dom_get());else{if(!v.is_active())return!1;var item=v.get_item();if(!this.util.is_type(item,View.Content_Item))return v.close(),!1;if(v.is_active()&&this.has_tags()){var loading_promise=this.trigger("render-loading"),tpl=this,tags=this.get_tags(),tag_promises=[];$.when(item.load(),loading_promise).done(function(){return!!v.is_active()&&($.each(tags,function(idx,tag){if(!v.is_active())return!1;tag_promises.push(tag.render(item).done(function(r){if(!v.is_active())return!1;r.tag.dom_get().html(r.output)}))}),!!v.is_active()&&void $.when.apply($,tag_promises).done(function(){tpl.trigger("render-complete")}))})}}},get_layout:function(parsed){return this.util.is_bool(parsed)||(parsed=!0),parsed?this.parse_layout():this.get_attribute("layout_raw","")},parse_layout:function(){var a="layout_parsed",ret=this.get_attribute(a);return this.util.is_string(ret)||(ret=this.sanitize_layout(this.get_layout(!1)),ret=this.parse_tags(ret),this.set_attribute(a,ret)),ret},sanitize_layout:function(l){if(this.util.is_empty(l))return l;var rtype=this.util.is_string(l)?"string":null,dom=$(l),tag_temp=this.get_tag_temp(),cls=tag_temp.get_class(),cls_new=["x",cls].join("_");switch($(tag_temp.get_selector(),dom).each(function(){$(this).removeClass(cls).addClass(cls_new)}),rtype){case"string":l=dom=dom.wrap("
").parent().html();break;default:l=dom}return l},parse_tags:function(l){if(!this.util.is_string(l))return"";for(var match,re=/\{{2}\s*(\w.*?)\s*\}{2}/gim;match=re.exec(l);)l=l.substring(0,match.index)+this.get_tag_container(match[1])+l.substring(match.index+match[0].length);return l},get_tag_container:function(tag){var attr=this.get_tag_attribute();return this.util.format('',attr,encodeURI(tag))},get_tag_attribute:function(){return this.get_tag_temp().dom_get_attribute()},get_tag:function(idx){var ret=null;if(this.has_tags()){var tags=this.get_tags();(!this.util.is_int(idx)||idx<0||idx>=tags.length)&&(idx=0),ret=tags[idx]}return ret},get_tags:function(name,prop,isolate){this.util.is_bool(isolate)||(isolate=!1);var a="tags",tags=this.get_attribute(a);if(!this.util.is_array(tags)){tags=[];var d=this.dom_get(),attr=this.get_tag_attribute(),nodes=$(d).find("["+attr+"]");$(nodes).each(function(){var el=$(this),tag=new View.Template_Tag(decodeURI(el.attr(attr)));tag.has_handler()&&(tags.push(tag),isolate||(tag.dom_set(el),el.addClass(tag.get_classes(" ")))),isolate||el.removeAttr(attr)}),isolate||this.set_attribute(a,tags,!1)}if(!this.util.is_empty(tags)&&this.util.is_string(name)){this.util.is_string(prop)||(prop=!1);for(var tags_filtered=[],tc=null,x=0;x');$("head").append(out.join(""))}}},Component={_slug:"component",_ns:null,_refs:{},_reciprocal:!1,_dom:null,_attributes:!1,_attr_default:{},_attr_default_parsed:!1,_attr_init:null,_attr_map:{},_events:{},_status:null,_id:"",_c:function(id,attributes){this._set_id(id),this.util.is_obj(attributes)&&(this._attr_init=attributes),this._hooks()},_set_parent:function(){this._super(View)},_hooks:function(){},_set_id:function(id){return this.util.is_empty(this._id)&&(this._id=this.util.is_string(id)?id:this.util.guid()),this._id},get_id:function(ns){var id=this._id;return id=this.util.is_bool(ns)&&ns?this.add_ns(id):id},get_ns:function(){return null===this._ns&&(this._ns=this.util.add_prefix(this._slug)),this._ns},add_ns:function(val){return this.util.is_string(val)?this.get_ns()+"_"+val:""},get_status:function(id,raw){var ret=!1;return ret=this.util.in_obj(this._status,id)?raw?this._status[id]:!!this._status[id]:ret},set_status:function(id,val){return this.util.is_string(id)?(this.util.is_set(val)||(val=!0),this.util.is_obj(this._status,!1)||(this._status={}),this._status[id]=val):this.util.is_set(val)||(val=!1),val},get_controller:function(){return this.get_parent()},has_reference:function(ref){return!!(this.util.is_string(ref)&&ref in this&&ref in this.get_references())},get_references:function(){return this._refs},get_reference:function(ref){return this.has_reference(ref)?this._refs[ref]:null},get_component:function(cname,options){var c=null;if(this.has_reference(cname)){options=$.extend({},{check_attr:!0,get_default:!1},options);var ctype=this.get_reference(cname);if(this.util.is_type(this[cname],ctype))return this[cname];c=this[cname]=null,options.check_attr&&(c=this.get_attribute(cname),this.util.is_empty(c)||(c=this.set_component(cname,c))),this.util.is_empty(c)&&options.get_default&&(c=this.get_controller().get_component(ctype))}return c},set_component:function(name,ref,validate){var ctype;return this.has_reference(name)?((this.util.is_empty(ref)||(ctype=this.get_reference(name),this.util.is_string(ref,!1)&&(ref=this.get_controller().get_component(ctype,ref)),!this.util.is_type(ref,ctype)||this.util.is_func(validate)&&!validate.call(this,ref)))&&(ref=null),this[name]=ref,this[name]):null},clear_component:function(name){this.set_component(name,null)},init_attributes:function(force){!(force=this.util.is_bool(force)?force:!1)&&this.util.is_obj(this._attributes)||(force=this._attributes={},$.extend(force,this.init_default_attributes()),this.util.is_obj(this._attr_init)&&$.extend(force,this._attr_init),$.extend(force,this.get_dom_attributes()))},init_default_attributes:function(){if(!this._attr_default_parsed&&this.util.is_obj(this._attr_map)){var opts=this.get_controller().get_options(this.util.obj_keys(this._attr_map));if(this.util.is_obj(opts)){for(var opt in this._attr_map)opt in opts&&null!==this._attr_map[opt]&&(opts[this._attr_map[opt]]=opts[opt],delete opts[opt]);$.extend(!0,this._attr_default,opts)}this._attr_default_parsed=!0}return this._attr_default},get_dom_attributes:function(){var attr_prefix,attr_key,attrs={},el=this.dom_get(null,{init:!1});return 0",options.tag),attrs).appendTo(content)).length&&this.util.is_method(options,"success")&&options.success.call(r,r),$(r).append(options.content)}return $(r)},dom_has:function(){return!!this.dom_get().length},get_data_key:function(){return this.get_ns()},on:function(event,fn,options){var t,args,es;return this.util.is_string(event)&&this.util.is_func(fn)?(this.util.is_obj(options,!1)||(options={}),options=$.extend({},{clear:!1},options),this.util.is_obj(this._events,!1)||(this._events={}),event in(es=this._events)&&this.util.is_obj(es[event],!1)&&!options.clear||(es[event]=[]),es[event].push(fn)):(t=this,args=Array.prototype.slice.call(arguments,1),this.util.is_array(event)?$.each(event,function(idx,val){t.on.apply(t,[val].concat(args))}):this.util.is_obj(event)&&$.each(event,function(ev,hdl){t.on.apply(t,[ev,hdl].concat(args))})),this},trigger:function(event,data){var ev,dfr=$.Deferred(),dfrs=[],t=this;return this.util.is_array(event)?($.each(event,function(idx,val){dfrs.push(t.trigger(val,data))}),$.when.apply(t,dfrs).done(function(){dfr.resolve()})):this.util.is_string(event)&&event in this._events?(ev={type:event,data:null},this.util.is_set(data)&&(ev.data=data),$.each(this._events[event],function(idx,fn){dfrs.push(fn.call(t,ev,t))}),$.when.apply(this,dfrs).done(function(){dfr.resolve()})):dfr.resolve(),dfr.promise()}},Viewer=(View.Component=Component=SLB.Class.extend(Component),{_slug:"viewer",_refs:{item:"Content_Item",theme:"Theme"},_reciprocal:!0,_attr_default:{loop:!0,animate:!0,autofit:!0,overlay_enabled:!0,overlay_opacity:"0.8",title_default:!1,container:null,slideshow_enabled:!0,slideshow_autostart:!1,slideshow_duration:2,slideshow_active:!1,slideshow_timer:null,labels:{close:"close",nav_prev:"« prev",nav_next:"next »",slideshow_start:"start slideshow",slideshow_stop:"stop slideshow",group_status:"Image %current% of %total%",loading:"loading"}},_attr_map:{theme:null,group_loop:"loop",ui_autofit:"autofit",ui_animate:"animate",ui_overlay_opacity:"overlay_opacity",ui_labels:"labels",ui_title_default:"title_default",slideshow_enabled:null,slideshow_autostart:null,slideshow_duration:null},item:null,item_queued:null,theme:null,item_working:null,active:!1,init:!1,open:!1,loading:!1,_hooks:function(){var t=this;this.on(["item-prev","item-next"],function(){t.trigger("item-change")}).on(["close","item-change"],function(){t.unload().done(function(){t.unlock()})})},get_item:function(){return this.get_component("item")},set_item:function(item){this.clear_item(!1);item=this.set_component("item",item,function(item){return item.has_type()});return!this.util.is_empty(item)},clear_item:function(full){this.util.is_bool(full)||(full=!0);var item=this.get_item();item&&item.reset(),full&&this.clear_component("item")},get_theme:function(){var ret=this.get_component("theme",{check_attr:!1});return ret=this.util.is_empty(ret)?this.set_component("theme",new View.Theme(this)):ret},set_theme:function(theme){this.set_component("theme",theme)},lock:function(){return this.set_status("item_working",$.Deferred())},get_lock:function(simple,full){this.util.is_bool(simple)||(simple=!1),this.util.is_bool(full)||(full=!1);var s="item_working";return simple?this.get_status(s):(simple=this.get_status(s,!0),this.util.is_promise(simple)||(simple=this.lock()),full?simple:simple.promise())},is_locked:function(){return this.get_lock(!0)},unlock:function(){return this.get_lock(!1,!0).resolve()},set_active:function(mode){return this.util.is_bool(mode)||(mode=!0),this.set_status("active",mode)},is_active:function(){return this.get_status("active")},set_loading:function(mode){var dfr=$.Deferred(),m=(this.util.is_bool(mode)||(mode=!0),this.loading=mode,this.slideshow_active()&&this.slideshow_pause(mode),mode?"addClass":"removeClass");return $(this.dom_get())[m]("loading"),mode?this.get_theme().transition("load").always(function(){dfr.resolve()}):dfr.resolve(),dfr.promise()},unset_loading:function(){return this.set_loading(!1)},get_loading:function(){return!!this.util.is_bool(this.loading)&&this.loading},is_loading:function(){return this.get_loading()},show:function(item){this.item_queued=item;var fin_set="show_deferred",item="theme_valid",valid=!0;if(this.has_attribute(item)?valid=this.get_attribute(item,!0):(valid=!(!this.get_theme()||""===this.get_theme().get_template().get_layout(!1)),this.set_attribute(item,valid)),!valid)return this.close(),!1;function fin(){if(v.lock(),v.set_status(fin_set,!1),!v.set_item(v.item_queued))return v.close();v.history_add(),v.set_active(),v.render()}var v=this;this.is_locked()?this.get_status(fin_set)||(this.set_status(fin_set),this.get_lock().always(function(){fin()})):fin()},history_handle:function(e){var state=e.originalEvent.state;this.util.is_string(state.item,!1)?(this.get_controller().get_item(state.item).show({event:e}),this.trigger("item-change")):(state=this.history_get(!0),this.history_set(0),-1!==state&&this.close())},history_get:function(full){return this.get_status("history_count",full)},history_set:function(val){return this.set_status("history_count",val)},history_add:function(){if(!history.pushState)return!1;var item=this.get_item(),opts=item.get_attribute("options_show"),count=this.history_get()?this.history_get(!0):0;this.util.in_obj(opts,"event")?(opts=opts.event.originalEvent,this.util.in_obj(opts,"state")&&this.util.in_obj(opts.state,"count")&&(count=opts.state.count)):(opts={viewer:this.get_id(),item:null,count:count},count||history.replaceState(opts,null),opts.item=this.get_controller().save_item(item).get_id(),opts.count=++count,history.pushState(opts,"")),this.history_set(count)},history_reset:function(){var count=this.history_get(!0);count&&(this.history_set(-1),history.go(-1*count))},is_open:function(){return"none"!==this.dom_get().css("display")},render:function(){var v=this,thm=this.get_theme();v.dom_prep(),this.get_status("render-events")||(this.set_status("render-events"),thm.on("render-loading",function(ev,thm){var set_pos,always,dfr=$.Deferred();return v.is_active()?(set_pos=function(){v.dom_get().css("top",$(window).scrollTop())},always=function(){v.set_loading().always(function(){dfr.resolve()})},v.is_open()?thm.transition("unload").fail(function(){set_pos(),thm.dom_get_tag("item","content").attr("style","")}).always(always):thm.transition("open").always(function(){always(),v.events_open(),v.open=!0}).fail(function(){set_pos(),v.get_overlay().show(),v.dom_get().show()})):dfr.reject(),dfr.promise()}).on("render-complete",function(ev,thm){if(!v.is_active())return!1;var d=v.dom_get(),classes=["item_single","item_multi"],ms=["addClass","removeClass"];v.get_item().get_group().is_single()||ms.reverse(),$.each(ms,function(idx,val){d[val](classes[idx])}),v.events_complete(),thm.transition("complete").fail(function(){var dims;v.get_attribute("autofit",!0)&&(dims=$.extend({display:"inline-block"},thm.get_item_dimensions()),thm.dom_get_tag("item","content").css(dims))}).always(function(){v.unset_loading(),v.trigger("render-complete"),v.init=!0})})),thm.render()},dom_get_container:function(){var sel=this.get_attribute("container"),c=(this.util.is_empty(sel)&&(sel="#"+this.add_ns("wrap")),$(sel));return c.length||(sel=0===sel.indexOf("#")?sel.substr(1):sel,c=$("
",{id:sel}).appendTo("body")),c},dom_init:function(){var d=this.dom_set($("
",{id:this.get_id(!0),class:this.get_ns()})).appendTo(this.dom_get_container()).hide(),thm=this.get_theme(),v=(d.addClass(thm.get_classes(" ")),this);this.get_status("render-init")||(this.set_status("render-init"),thm.on("render-init",function(ev){v.dom_put("layout",ev.data)})),thm.render(!0)},dom_prep:function(mode){mode=this.util.is_bool(mode)&&!mode?"removeClass":"addClass";$("html")[mode](this.util.add_prefix("overlay"))},dom_restore:function(){this.dom_prep(!1)},get_layout:function(){return this.dom_get("layout",{put:{success:function(){$(this).hide()}}})},animation_enabled:function(){return this.get_attribute("animate",!0)},overlay_enabled:function(){var ov=this.get_attribute("overlay_enabled");return!!this.util.is_bool(ov)&&ov},get_overlay:function(){var o=null,v=this;return this.overlay_enabled()&&(o=this.dom_get("overlay",{put:{success:function(){$(this).hide().css("opacity",v.get_attribute("overlay_opacity"))}}})),$(o)},unload:function(){var dfr=$.Deferred();return this.get_theme().dom_get_tag("item").text(""),dfr.resolve(),dfr.promise()},reset:function(){this.dom_get().hide(),this.dom_restore(),this.history_reset(),this.clear_item(),this.set_active(!1),this.set_loading(!1),this.slideshow_stop(),this.keys_disable(),this.unlock()},get_labels:function(){return this.get_attribute("labels",{})},get_label:function(name){var lbls=this.get_labels();return name in lbls?lbls[name]:""},events_open:function(){if(this.keys_enable(),this.open)return!1;function close(){v.close()}var l=this.get_layout(),v=(l.children().click(function(ev){ev.stopPropagation()}),this);l.click(close),this.get_overlay().click(close),this.trigger("events-open")},events_complete:function(){if(this.init)return!1;this.trigger("events-complete")},keys_enable:function(mode){this.util.is_bool(mode)||(mode=!0);var e=["keyup",this.util.get_prefix()].join("."),v=this;mode?$(document).on(e,function(ev){return v.keys_control(ev)}):$(document).off(e)},keys_disable:function(){this.keys_enable(!1)},keys_control:function(ev){var handlers={27:this.close,37:this.item_prev,39:this.item_next};if("rtl"===document.documentElement.getAttribute("dir")&&(handlers[37]=this.item_next,handlers[39]=this.item_prev),ev.which in handlers)return handlers[ev.which].call(this),!1},slideshow_enabled:function(){var o=this.get_attribute("slideshow_enabled");return!(!(this.util.is_bool(o)&&o&&this.get_item())||this.get_item().get_group().is_single())},slideshow_active:function(){return!(!this.slideshow_enabled()||!(this.get_attribute("slideshow_active")||!this.init&&this.get_attribute("slideshow_autostart")))},slideshow_clear_timer:function(){clearInterval(this.get_attribute("slideshow_timer"))},slideshow_set_timer:function(callback){this.set_attribute("slideshow_timer",setInterval(callback,1e3*this.get_attribute("slideshow_duration")))},slideshow_start:function(){if(!this.slideshow_enabled())return!1;this.set_attribute("slideshow_active",!0),this.dom_get().addClass("slideshow_active"),this.slideshow_clear_timer();var v=this;this.slideshow_set_timer(function(){v.slideshow_pause(),v.item_next()}),this.trigger("slideshow-start")},slideshow_stop:function(full){(full=this.util.is_bool(full)?full:!0)&&(this.set_attribute("slideshow_active",!1),this.dom_get().removeClass("slideshow_active")),this.slideshow_clear_timer(),this.trigger("slideshow-stop")},slideshow_toggle:function(){if(!this.slideshow_enabled())return!1;this.slideshow_active()?this.slideshow_stop():this.slideshow_start(),this.trigger("slideshow-toggle")},slideshow_pause:function(mode){this.util.is_bool(mode)||(mode=!0),this.slideshow_active()&&(mode?this.slideshow_stop(!1):this.slideshow_start()),this.trigger("slideshow-pause")},slideshow_resume:function(){this.slideshow_pause(!1)},item_next:function(){var g=this.get_item().get_group(!0),v=this,ev="item-next",st=["events","viewer",ev].join("_");g.get_status(st)||(g.set_status(st),g.on(ev,function(e){v.trigger(e.type)})),g.show_next()},item_prev:function(){var g=this.get_item().get_group(!0),v=this,ev="item-prev",st=["events","viewer",ev].join("_");g.get_status(st)||(g.set_status(st),g.on(ev,function(){v.trigger(ev)})),g.show_prev()},close:function(){this.set_active(!1);var v=this,thm=this.get_theme();return thm.transition("unload").always(function(){thm.transition("close",!0).always(function(){v.reset(),v.trigger("close")})}).fail(function(){thm.dom_get_tag("item","content").attr("style","")}),!1}}),Viewer=(View.Viewer=Component.extend(Viewer),{_slug:"group",_reciprocal:!0,_refs:{current:"Content_Item"},current:null,selector:null,_hooks:function(){var t=this;this.on(["item-prev","item-next"],function(){t.trigger("item-change")})},get_selector:function(){return this.util.is_empty(this.selector)&&(this.selector=this.util.format('a[%s="%s"]',this.dom_get_attribute(),this.get_id())),this.selector},get_items:function(){var items=$(this.get_selector());return items=0===items.length&&this.has_current()?this.get_current().dom_get():items},get_item:function(idx){this.util.is_int(idx)||(idx=0);var items=this.get_items(),max=this.get_size()-1;return items.get(idx=maxoffset.width&&(v.width-=offset.width),v.height>offset.height&&(v.height-=offset.height),(factor=Math.min(v.width/dims.width,v.height/dims.height))<1&&$.each(dims,function(key){dims[key]=Math.round(dims[key]*factor)})),$.extend({},dims)},get_dimensions:function(){var dims=this.get_item_dimensions(),offset=this.get_offset();return $.each(dims,function(key){dims[key]+=offset[key]}),dims},get_breakpoints:function(){return this.get_attribute_recursive("breakpoints")},get_breakpoint:function(target){var b,ret=0;return this.util.is_string(target)&&(b=this.get_attribute_recursive("breakpoints"),this.util.is_obj(b)&&target in b&&(ret=b[target])),ret},render:function(init){var thm=this,tpl=this.get_template(),st="events_render";this.get_status(st)||(this.set_status(st),tpl.on(["render-init","render-loading","render-complete"],function(ev){return thm.trigger(ev.type,ev.data)})),tpl.render(init)},transition:function(event,clear_queue){var models,trns,thm,dfr=null,attr="transition",v=this.get_viewer(),fx_temp=null,anim_on=v.animation_enabled();return v.get_attribute(attr,!0)&&this.util.is_string(event)&&(clear_queue&&v.get_layout().find("*").each(function(){for(var el=$(this);el.queue().length;)el.stop(!1,!0)}),clear_queue=[attr,"set"].join("_"),trns=this.get_attribute(clear_queue)?this.get_attribute(attr,{}):(models=this.get_ancestors(!0),trns=[],this.set_attribute(clear_queue,!0),thm=this,$.each(models,function(idx,model){attr in model&&thm.util.is_obj(model[attr])&&trns.push(model[attr])}),trns.push({}),this.set_attribute(attr,$.extend.apply($,trns.reverse()))),this.util.is_method(trns,event)&&(anim_on||(fx_temp=$.fx.off,$.fx.off=!0),dfr=trns[event].call(this,v,$.Deferred()))),this.util.is_promise(dfr)||(dfr=$.Deferred()).reject(),dfr.always(function(){null!==fx_temp&&($.fx.off=fx_temp)}),dfr.promise()}}),{_slug:"template",_reciprocal:!0,_refs:{theme:"Theme"},_attr_default:{layout_uri:"",layout_raw:"",layout_parsed:"",tags:null,model:null},theme:null,_c:function(attributes){this._super("",attributes)},_hooks:function(){this.on("dom_init",function(ev){var tags=this.get_tags(null,null,!0),names=[],t=this;$.each(tags,function(idx,tag){var name=tag.get_name();-1===$.inArray(name,names)&&(names.push(name),tag.get_handler().trigger(ev.type,{template:t}))})})},get_theme:function(){return this.get_component("theme")},render:function(init){var item,tpl,tags,tag_promises,v=this.get_theme().get_viewer();if(!(init=this.util.is_bool(init)?init:!1))return!!v.is_active()&&(item=v.get_item(),this.util.is_type(item,View.Content_Item)?void(v.is_active()&&this.has_tags()&&(init=this.trigger("render-loading"),tags=(tpl=this).get_tags(),tag_promises=[],$.when(item.load(),init).done(function(){return!!v.is_active()&&($.each(tags,function(idx,tag){if(!v.is_active())return!1;tag_promises.push(tag.render(item).done(function(r){if(!v.is_active())return!1;r.tag.dom_get().html(r.output)}))}),!!v.is_active()&&void $.when.apply($,tag_promises).done(function(){tpl.trigger("render-complete")}))}))):(v.close(),!1));this.trigger("render-init",this.dom_get())},get_layout:function(parsed){return(parsed=this.util.is_bool(parsed)?parsed:!0)?this.parse_layout():this.get_attribute("layout_raw","")},parse_layout:function(){var a="layout_parsed",ret=this.get_attribute(a);return this.util.is_string(ret)||(ret=this.sanitize_layout(this.get_layout(!1)),ret=this.parse_tags(ret),this.set_attribute(a,ret)),ret},sanitize_layout:function(l){var rtype,dom,tag_temp,cls,cls_new;return this.util.is_empty(l)||(rtype=this.util.is_string(l)?"string":null,dom=$(l),tag_temp=this.get_tag_temp(),cls=tag_temp.get_class(),cls_new=["x",cls].join("_"),$(tag_temp.get_selector(),dom).each(function(){$(this).removeClass(cls).addClass(cls_new)}),l="string"===rtype?dom=dom.wrap("
").parent().html():dom),l},parse_tags:function(l){if(!this.util.is_string(l))return"";for(var match,re=/\{{2}\s*(\w.*?)\s*\}{2}/gim;match=re.exec(l);)l=l.substring(0,match.index)+this.get_tag_container(match[1])+l.substring(match.index+match[0].length);return l},get_tag_container:function(tag){var attr=this.get_tag_attribute();return this.util.format('',attr,encodeURI(tag))},get_tag_attribute:function(){return this.get_tag_temp().dom_get_attribute()},get_tag:function(idx){var tags,ret=null;return ret=this.has_tags()?(tags=this.get_tags())[idx=!this.util.is_int(idx)||idx<0||idx>=tags.length?0:idx]:ret},get_tags:function(name,prop,isolate){this.util.is_bool(isolate)||(isolate=!1);var attr,d,a="tags",tags=this.get_attribute(a);if(this.util.is_array(tags)||(tags=[],d=this.dom_get(),attr=this.get_tag_attribute(),d=$(d).find("["+attr+"]"),$(d).each(function(){var el=$(this),tag=new View.Template_Tag(decodeURI(el.attr(attr)));tag.has_handler()&&(tags.push(tag),isolate||(tag.dom_set(el),el.addClass(tag.get_classes(" ")))),isolate||el.removeAttr(attr)}),isolate||this.set_attribute(a,tags,!1)),!this.util.is_empty(tags)&&this.util.is_string(name)){this.util.is_string(prop)||(prop=!1);for(var tags_filtered=[],tc=null,x=0;x",{src:item.get_uri()});dfr.resolve(out)}()}),img.src=item.get_uri(),dfr.promise()}})}(jQuery); \ No newline at end of file +window.SLB&&SLB.has_child("View.extend_content_handler")&&!function($){SLB.View.extend_content_handler("image",{render:function(item,dfr){var img=new Image;return $(img).on("load",function(e){var out;item.set_data(img),item.set_attribute("dimensions",{width:img.width,height:img.height}),out=$("",{src:item.get_uri()}),dfr.resolve(out)}),img.src=item.get_uri(),dfr.promise()}})}(jQuery); \ No newline at end of file diff --git a/controller.php b/controller.php index 1e6982b..f11adb6 100644 --- a/controller.php +++ b/controller.php @@ -20,19 +20,19 @@ class SLB_Lightbox extends SLB_Base { * Themes collection * @var SLB_Themes */ - var $themes = null; + public $themes = null; /** * Content types * @var SLB_Content_Handlers */ - var $handlers = null; + public $handlers = null; /** * Template tags * @var SLB_Template_Tags */ - var $template_tags = null; + public $template_tags = null; /** * Media item template. @@ -61,14 +61,10 @@ class SLB_Lightbox extends SLB_Base { * } */ private $media_item_template = [ - 'id' => null, - 'type' => null, + 'id' => null, + 'type' => null, 'internal' => false, - 'source' => '', - /* @future: Metadata - 'media' => [], - 'meta' => [] - END @future: Metadata */ + 'source' => '', ]; /** @@ -104,7 +100,10 @@ class SLB_Lightbox extends SLB_Base { * } * } */ - private $media_items_raw = [ 'props' => [], 'uri' => [] ]; + private $media_items_raw = [ + 'props' => [], + 'uri' => [], + ]; /** * Manage excluded content @@ -112,9 +111,9 @@ class SLB_Lightbox extends SLB_Base { */ private $exclude = null; - private $groups = array ( - 'auto' => 0, - 'manual' => array(), + private $groups = array( + 'auto' => 0, + 'manual' => array(), ); /** @@ -155,9 +154,9 @@ public function __construct() { parent::__construct(); // Init instances $this->fields = new SLB_Fields(); - $this->themes = new SLB_Themes($this); - if ( !is_admin() ) { - $this->template_tags = new SLB_Template_Tags($this); + $this->themes = new SLB_Themes( $this ); + if ( ! is_admin() ) { + $this->template_tags = new SLB_Template_Tags( $this ); } } @@ -165,7 +164,7 @@ public function __construct() { public function _init() { parent::_init(); - $this->util->do_action('init'); + $this->util->do_action( 'init' ); } /** @@ -173,32 +172,32 @@ public function _init() { * @uses parent::_client_files() * @return void */ - protected function _client_files($files = null) { - $js_path = 'client/js/'; + protected function _client_files( $files = null ) { + $js_path = 'client/js/'; $js_path .= ( SLB_DEV ) ? 'dev' : 'prod'; - $files = array ( - 'scripts' => array ( - 'core' => array ( - 'file' => "$js_path/lib.core.js", - 'deps' => 'jquery', - 'enqueue' => false, - 'in_footer' => true, + $files = array( + 'scripts' => array( + 'core' => array( + 'file' => "$js_path/lib.core.js", + 'deps' => 'jquery', + 'enqueue' => false, + 'in_footer' => true, ), - 'view' => array ( - 'file' => "$js_path/lib.view.js", - 'deps' => array('[core]'), - 'context' => array( array('public', $this->m('is_request_valid')) ), - 'in_footer' => true, + 'view' => array( + 'file' => "$js_path/lib.view.js", + 'deps' => array( '[core]' ), + 'context' => array( array( 'public', $this->m( 'is_request_valid' ) ) ), + 'in_footer' => true, + ), + ), + 'styles' => array( + 'core' => array( + 'file' => 'client/css/app.css', + 'context' => array( 'public' ), ), ), - 'styles' => array ( - 'core' => array ( - 'file' => 'client/css/app.css', - 'context' => array('public'), - ) - ) ); - parent::_client_files($files); + parent::_client_files( $files ); } /** @@ -209,61 +208,109 @@ protected function _hooks() { parent::_hooks(); /* Admin */ - add_action('admin_menu', $this->m('admin_menus')); - $this->util->add_filter('admin_plugin_row_meta_support', $this->m('admin_plugin_row_meta_support')); + add_action( 'admin_menu', $this->m( 'admin_menus' ) ); /* Init */ - add_action('wp', $this->m('_hooks_init')); + add_action( 'wp', $this->m( '_hooks_init' ) ); } /** - * Init Hooks + * Initialize hooks. + * + * @return void */ public function _hooks_init() { - if ( $this->is_enabled() ) { - $priority = $this->util->priority('low'); - - // Init lightbox - add_action('wp_footer', $this->m('client_footer')); - $this->util->add_action('footer_script', $this->m('client_init'), 1); - $this->util->add_filter('footer_script', $this->m('client_script_media'), 2); - // Link activation - add_filter('the_content', $this->m('activate_links'), $priority); - add_filter('get_post_galleries', $this->m('activate_galleries'), $priority); - $this->util->add_filter('post_process_links', $this->m('activate_groups'), 11); - $this->util->add_filter('validate_uri_regex', $this->m('validate_uri_regex_default'), 1); - // Content exclusion - $this->util->add_filter('pre_process_links', $this->m('exclude_content')); - $this->util->add_filter('pre_exclude_content', $this->m('exclude_shortcodes')); - $this->util->add_filter('post_process_links', $this->m('restore_excluded_content')); - - // Grouping - if ( $this->options->get_bool('group_post') ) { - $this->util->add_filter('get_group_id', $this->m('post_group_id'), 1); - } + if ( ! $this->is_enabled() ) { + return; + } + // Callback for hooks that need to have method added to end of stack. + $cb_hooks_add_last = $this->m( 'hooks_add_last' ); + + // Init lightbox + add_action( 'wp_footer', $this->m( 'client_footer' ) ); + $this->util->add_action( 'footer_script', $this->m( 'client_init' ), 1 ); + $this->util->add_filter( 'footer_script', $this->m( 'client_script_media' ), 2 ); + // Link activation + add_filter( 'the_content', $cb_hooks_add_last ); + add_filter( 'get_post_galleries', $cb_hooks_add_last ); + $this->util->add_filter( 'post_process_links', $this->m( 'activate_groups' ), 11 ); + $this->util->add_filter( 'validate_uri_regex', $this->m( 'validate_uri_regex_default' ), 1 ); + // Content exclusion + $this->util->add_filter( 'pre_process_links', $this->m( 'exclude_content' ) ); + $this->util->add_filter( 'pre_exclude_content', $this->m( 'exclude_shortcodes' ) ); + $this->util->add_filter( 'post_process_links', $this->m( 'restore_excluded_content' ) ); - // Shortcode grouping - if ( $this->options->get_bool('group_gallery') ) { - add_filter('the_content', $this->m('group_shortcodes'), 1); - } + // Grouping + if ( $this->options->get_bool( 'group_post' ) ) { + $this->util->add_filter( 'get_group_id', $this->m( 'post_group_id' ), 1 ); + } - // Widgets - if ( $this->options->get_bool('enabled_widget') ) { - add_action('dynamic_sidebar_before', $this->m('widget_process_nested')); - add_action('dynamic_sidebar', $this->m('widget_process_start'), PHP_INT_MAX); - add_filter('dynamic_sidebar_params', $this->m('widget_process_inter'), PHP_INT_MAX); - add_action('dynamic_sidebar_after', $this->m('widget_process_finish'), PHP_INT_MAX - 1); - add_action('dynamic_sidebar_after', $this->m('widget_process_nested_finish'), PHP_INT_MAX); - } else { - add_action('dynamic_sidebar_before', $this->m('widget_block_start')); - add_action('dynamic_sidebar_after', $this->m('widget_block_finish')); - } + // Shortcode grouping + if ( $this->options->get_bool( 'group_gallery' ) ) { + add_filter( 'the_content', $this->m( 'group_shortcodes' ), 1 ); + } - // Menus - if ( $this->options->get_bool('enabled_menu') ) { - add_filter('wp_nav_menu', $this->m('menu_process'), $priority, 2); - } + // Widgets + if ( $this->options->get_bool( 'enabled_widget' ) ) { + add_action( 'dynamic_sidebar_before', $this->m( 'widget_process_nested' ) ); + add_action( 'dynamic_sidebar', $cb_hooks_add_last ); + add_filter( 'dynamic_sidebar_params', $this->m( 'widget_process_inter' ), 1 ); + add_action( 'dynamic_sidebar_after', $cb_hooks_add_last ); + add_action( 'dynamic_sidebar_after', $cb_hooks_add_last ); + } else { + add_action( 'dynamic_sidebar_before', $this->m( 'widget_block_start' ) ); + add_action( 'dynamic_sidebar_after', $this->m( 'widget_block_finish' ) ); + } + + // Menus + if ( $this->options->get_bool( 'enabled_menu' ) ) { + add_filter( 'wp_nav_menu', $cb_hooks_add_last ); + } + } + + /** + * Adds hook(s) to end of filter/action stack. + * + * @param string $data Optional. Data being filtered. + * @return string Filtered content. + */ + public function hooks_add_last( $data = null ) { + global $wp_filter; + + $tag = current_filter(); + + // Stop processing on invalid hook. + if ( empty( $tag ) || ! is_string( $tag ) ) { + return $data; } + + // Get lowest priority for filter. + $max_priority = max( array_keys( $wp_filter[ $tag ]->callbacks ) ) + 123; + + switch ( $tag ) { + case 'the_content': + add_filter( $tag, $this->m( 'activate_links' ), $max_priority ); + break; + case 'get_post_galleries': + add_filter( $tag, $this->m( 'activate_galleries' ), $max_priority ); + break; + case 'dynamic_sidebar': + add_action( $tag, $this->m( 'widget_process_start' ), $max_priority ); + break; + case 'dynamic_sidebar_after': + add_action( $tag, $this->m( 'widget_process_finish' ), $max_priority ); + add_action( $tag, $this->m( 'widget_process_nested_finish' ), $max_priority ); + break; + case 'wp_nav_menu': + add_filter( $tag, $this->m( 'menu_process' ), $max_priority, 2 ); + break; + } + + // Remove init hook. + remove_filter( $tag, $this->m( __FUNCTION__ ) ); + + // Return content (for filters). + return $data; } /** @@ -272,12 +319,12 @@ public function _hooks_init() { * @param array $group_segments Group ID segments * @return array Modified group ID segments */ - public function post_group_id($group_segments) { + public function post_group_id( $group_segments ) { if ( in_the_loop() ) { // Prepend post ID to group ID $post = get_post(); if ( $post ) { - array_unshift($group_segments, $post->ID); + array_unshift( $group_segments, $post->ID ); } } return $group_segments; @@ -288,76 +335,207 @@ public function post_group_id($group_segments) { */ protected function _options() { // Setup options - $opts = array ( - 'groups' => array ( - 'activation' => array ( 'title' => __('Activation', 'simple-lightbox'), 'priority' => 10), - 'grouping' => array ( 'title' => __('Grouping', 'simple-lightbox'), 'priority' => 20), - 'ui' => array ( 'title' => __('UI', 'simple-lightbox'), 'priority' => 30), - 'labels' => array ( 'title' => __('Labels', 'simple-lightbox'), 'priority' => 40), + $opts = array( + 'groups' => array( + 'activation' => array( + 'title' => __( 'Activation', 'simple-lightbox' ), + 'priority' => 10, + ), + 'grouping' => array( + 'title' => __( 'Grouping', 'simple-lightbox' ), + 'priority' => 20, + ), + 'ui' => array( + 'title' => __( 'UI', 'simple-lightbox' ), + 'priority' => 30, + ), + 'labels' => array( + 'title' => __( 'Labels', 'simple-lightbox' ), + 'priority' => 40, + ), + ), + 'items' => array( + 'enabled' => array( + 'title' => __( 'Enable Lightbox Functionality', 'simple-lightbox' ), + 'default' => true, + 'group' => array( 'activation', 10 ), + ), + 'enabled_home' => array( + 'title' => __( 'Enable on Home page', 'simple-lightbox' ), + 'default' => true, + 'group' => array( 'activation', 20 ), + ), + 'enabled_post' => array( + 'title' => __( 'Enable on Single Posts', 'simple-lightbox' ), + 'default' => true, + 'group' => array( 'activation', 30 ), + ), + 'enabled_page' => array( + 'title' => __( 'Enable on Pages', 'simple-lightbox' ), + 'default' => true, + 'group' => array( 'activation', 40 ), + ), + 'enabled_archive' => array( + 'title' => __( 'Enable on Archive Pages (tags, categories, etc.)', 'simple-lightbox' ), + 'default' => true, + 'group' => array( 'activation', 50 ), + ), + 'enabled_widget' => array( + 'title' => __( 'Enable for Widgets', 'simple-lightbox' ), + 'default' => false, + 'group' => array( 'activation', 60 ), + ), + 'enabled_menu' => array( + 'title' => __( 'Enable for Menus', 'simple-lightbox' ), + 'default' => false, + 'group' => array( 'activation', 60 ), + ), + 'group_links' => array( + 'title' => __( 'Group items (for displaying as a slideshow)', 'simple-lightbox' ), + 'default' => true, + 'group' => array( 'grouping', 10 ), + ), + 'group_post' => array( + 'title' => __( 'Group items by Post (e.g. on pages with multiple posts)', 'simple-lightbox' ), + 'default' => true, + 'group' => array( 'grouping', 20 ), + ), + 'group_gallery' => array( + 'title' => __( 'Group gallery items separately', 'simple-lightbox' ), + 'default' => false, + 'group' => array( 'grouping', 30 ), + ), + 'group_widget' => array( + 'title' => __( 'Group widget items separately', 'simple-lightbox' ), + 'default' => false, + 'group' => array( 'grouping', 40 ), + ), + 'group_menu' => array( + 'title' => __( 'Group menu items separately', 'simple-lightbox' ), + 'default' => false, + 'group' => array( 'grouping', 50 ), + ), + 'ui_autofit' => array( + 'title' => __( 'Resize lightbox to fit in window', 'simple-lightbox' ), + 'default' => true, + 'group' => array( 'ui', 10 ), + 'in_client' => true, + ), + 'ui_animate' => array( + 'title' => __( 'Enable animations', 'simple-lightbox' ), + 'default' => true, + 'group' => array( 'ui', 20 ), + 'in_client' => true, + ), + 'slideshow_autostart' => array( + 'title' => __( 'Start Slideshow Automatically', 'simple-lightbox' ), + 'default' => true, + 'group' => array( 'ui', 30 ), + 'in_client' => true, + ), + 'slideshow_duration' => array( + 'title' => __( 'Slide Duration (Seconds)', 'simple-lightbox' ), + 'default' => '6', + 'attr' => array( + 'size' => 3, + 'maxlength' => 3, + ), + 'group' => array( 'ui', 40 ), + 'in_client' => true, + ), + 'group_loop' => array( + 'title' => __( 'Loop through items', 'simple-lightbox' ), + 'default' => true, + 'group' => array( 'ui', 50 ), + 'in_client' => true, + ), + 'ui_overlay_opacity' => array( + 'title' => __( 'Overlay Opacity (0 - 1)', 'simple-lightbox' ), + 'default' => '0.8', + 'attr' => array( + 'size' => 3, + 'maxlength' => 3, + ), + 'group' => array( 'ui', 60 ), + 'in_client' => true, + ), + 'ui_title_default' => array( + 'title' => __( 'Enable default title', 'simple-lightbox' ), + 'default' => false, + 'group' => array( 'ui', 70 ), + 'in_client' => true, + ), + 'txt_loading' => array( + 'title' => __( 'Loading indicator', 'simple-lightbox' ), + 'default' => 'Loading', + 'group' => array( 'labels', 20 ), + ), + 'txt_close' => array( + 'title' => __( 'Close button', 'simple-lightbox' ), + 'default' => 'Close', + 'group' => array( 'labels', 10 ), + ), + 'txt_nav_next' => array( + 'title' => __( 'Next Item button', 'simple-lightbox' ), + 'default' => 'Next', + 'group' => array( 'labels', 30 ), + ), + 'txt_nav_prev' => array( + 'title' => __( 'Previous Item button', 'simple-lightbox' ), + 'default' => 'Previous', + 'group' => array( 'labels', 40 ), + ), + 'txt_slideshow_start' => array( + 'title' => __( 'Start Slideshow button', 'simple-lightbox' ), + 'default' => 'Start slideshow', + 'group' => array( 'labels', 50 ), + ), + 'txt_slideshow_stop' => array( + 'title' => __( 'Stop Slideshow button', 'simple-lightbox' ), + 'default' => 'Stop slideshow', + 'group' => array( 'labels', 60 ), + ), + 'txt_group_status' => array( + 'title' => __( 'Slideshow status format', 'simple-lightbox' ), + 'default' => 'Item %current% of %total%', + 'group' => array( 'labels', 70 ), + ), ), - 'items' => array ( - 'enabled' => array('title' => __('Enable Lightbox Functionality', 'simple-lightbox'), 'default' => true, 'group' => array('activation', 10)), - 'enabled_home' => array('title' => __('Enable on Home page', 'simple-lightbox'), 'default' => true, 'group' => array('activation', 20)), - 'enabled_post' => array('title' => __('Enable on Single Posts', 'simple-lightbox'), 'default' => true, 'group' => array('activation', 30)), - 'enabled_page' => array('title' => __('Enable on Pages', 'simple-lightbox'), 'default' => true, 'group' => array('activation', 40)), - 'enabled_archive' => array('title' => __('Enable on Archive Pages (tags, categories, etc.)', 'simple-lightbox'), 'default' => true, 'group' => array('activation', 50)), - 'enabled_widget' => array('title' => __('Enable for Widgets', 'simple-lightbox'), 'default' => false, 'group' => array('activation', 60)), - 'enabled_menu' => array('title' => __('Enable for Menus', 'simple-lightbox'), 'default' => false, 'group' => array('activation', 60)), - 'group_links' => array('title' => __('Group items (for displaying as a slideshow)', 'simple-lightbox'), 'default' => true, 'group' => array('grouping', 10)), - 'group_post' => array('title' => __('Group items by Post (e.g. on pages with multiple posts)', 'simple-lightbox'), 'default' => true, 'group' => array('grouping', 20)), - 'group_gallery' => array('title' => __('Group gallery items separately', 'simple-lightbox'), 'default' => false, 'group' => array('grouping', 30)), - 'group_widget' => array('title' => __('Group widget items separately', 'simple-lightbox'), 'default' => false, 'group' => array('grouping', 40)), - 'group_menu' => array('title' => __('Group menu items separately', 'simple-lightbox'), 'default' => false, 'group' => array('grouping', 50)), - 'ui_autofit' => array('title' => __('Resize lightbox to fit in window', 'simple-lightbox'), 'default' => true, 'group' => array('ui', 10), 'in_client' => true), - 'ui_animate' => array('title' => __('Enable animations', 'simple-lightbox'), 'default' => true, 'group' => array('ui', 20), 'in_client' => true), - 'slideshow_autostart' => array('title' => __('Start Slideshow Automatically', 'simple-lightbox'), 'default' => true, 'group' => array('ui', 30), 'in_client' => true), - 'slideshow_duration' => array('title' => __('Slide Duration (Seconds)', 'simple-lightbox'), 'default' => '6', 'attr' => array('size' => 3, 'maxlength' => 3), 'group' => array('ui', 40), 'in_client' => true), - 'group_loop' => array('title' => __('Loop through items', 'simple-lightbox'),'default' => true, 'group' => array('ui', 50), 'in_client' => true), - 'ui_overlay_opacity' => array('title' => __('Overlay Opacity (0 - 1)', 'simple-lightbox'), 'default' => '0.8', 'attr' => array('size' => 3, 'maxlength' => 3), 'group' => array('ui', 60), 'in_client' => true), - 'ui_title_default' => array('title' => __('Enable default title', 'simple-lightbox'), 'default' => false, 'group' => array('ui', 70), 'in_client' => true), - 'txt_loading' => array('title' => __('Loading indicator', 'simple-lightbox'), 'default' => 'Loading', 'group' => array('labels', 20)), - 'txt_close' => array('title' => __('Close button', 'simple-lightbox'), 'default' => 'Close', 'group' => array('labels', 10)), - 'txt_nav_next' => array('title' => __('Next Item button', 'simple-lightbox'), 'default' => 'Next', 'group' => array('labels', 30)), - 'txt_nav_prev' => array('title' => __('Previous Item button', 'simple-lightbox'), 'default' => 'Previous', 'group' => array('labels', 40)), - 'txt_slideshow_start' => array('title' => __('Start Slideshow button', 'simple-lightbox'), 'default' => 'Start slideshow', 'group' => array('labels', 50)), - 'txt_slideshow_stop' => array('title' => __('Stop Slideshow button', 'simple-lightbox'),'default' => 'Stop slideshow', 'group' => array('labels', 60)), - 'txt_group_status' => array('title' => __('Slideshow status format', 'simple-lightbox'), 'default' => 'Item %current% of %total%', 'group' => array('labels', 70)) + 'legacy' => array( + 'header_activation' => null, + 'header_enabled' => null, + 'header_strings' => null, + 'header_ui' => null, + 'activate_attachments' => null, + 'validate_links' => null, + 'enabled_compat' => null, + 'enabled_single' => array( 'enabled_post', 'enabled_page' ), + 'enabled_caption' => null, + 'enabled_desc' => null, + 'ui_enabled_caption' => null, + 'ui_caption_src' => null, + 'ui_enabled_desc' => null, + 'caption_src' => null, + 'animate' => 'ui_animate', + 'overlay_opacity' => 'ui_overlay_opacity', + 'loop' => 'group_loop', + 'autostart' => 'slideshow_autostart', + 'duration' => 'slideshow_duration', + 'txt_numDisplayPrefix' => null, + 'txt_numDisplaySeparator' => null, + 'txt_closeLink' => 'txt_link_close', + 'txt_nextLink' => 'txt_link_next', + 'txt_prevLink' => 'txt_link_prev', + 'txt_startSlideshow' => 'txt_slideshow_start', + 'txt_stopSlideshow' => 'txt_slideshow_stop', + 'txt_loadingMsg' => 'txt_loading', + 'txt_link_next' => 'txt_nav_next', + 'txt_link_prev' => 'txt_nav_prev', + 'txt_link_close' => 'txt_close', ), - 'legacy' => array ( - 'header_activation' => null, - 'header_enabled' => null, - 'header_strings' => null, - 'header_ui' => null, - 'activate_attachments' => null, - 'validate_links' => null, - 'enabled_compat' => null, - 'enabled_single' => array('enabled_post', 'enabled_page'), - 'enabled_caption' => null, - 'enabled_desc' => null, - 'ui_enabled_caption' => null, - 'ui_caption_src' => null, - 'ui_enabled_desc' => null, - 'caption_src' => null, - 'animate' => 'ui_animate', - 'overlay_opacity' => 'ui_overlay_opacity', - 'loop' => 'group_loop', - 'autostart' => 'slideshow_autostart', - 'duration' => 'slideshow_duration', - 'txt_numDisplayPrefix' => null, - 'txt_numDisplaySeparator' => null, - 'txt_closeLink' => 'txt_link_close', - 'txt_nextLink' => 'txt_link_next', - 'txt_prevLink' => 'txt_link_prev', - 'txt_startSlideshow' => 'txt_slideshow_start', - 'txt_stopSlideshow' => 'txt_slideshow_stop', - 'txt_loadingMsg' => 'txt_loading', - 'txt_link_next' => 'txt_nav_next', - 'txt_link_prev' => 'txt_nav_prev', - 'txt_link_close' => 'txt_close', - ) ); - parent::_set_options($opts); + parent::_set_options( $opts ); } /* Methods */ @@ -371,28 +549,28 @@ protected function _options() { function admin_menus() { // Build options page $lbls_opts = array( - 'menu' => __('Lightbox', 'simple-lightbox'), - 'header' => __('Lightbox Settings', 'simple-lightbox'), - 'plugin_action' => __('Settings', 'simple-lightbox') + 'menu' => __( 'Lightbox', 'simple-lightbox' ), + 'header' => __( 'Lightbox Settings', 'simple-lightbox' ), + 'plugin_action' => __( 'Settings', 'simple-lightbox' ), ); - $pg_opts = $this->admin->add_theme_page('options', $lbls_opts) + $pg_opts = $this->admin->add_theme_page( 'options', $lbls_opts ) ->require_form() - ->add_content('options', 'Options', $this->options); + ->add_content( 'options', 'Options', $this->options ); // Add Support information - $support = $this->util->get_plugin_info('SupportURI'); - if ( !empty($support) ) { - $pg_opts->add_content('support', __('Feedback & Support', 'simple-lightbox'), $this->m('theme_page_callback_support'), 'secondary'); + $support = $this->util->get_plugin_info( 'SupportURI' ); + if ( ! empty( $support ) ) { + $pg_opts->add_content( 'support', __( 'Feedback & Support', 'simple-lightbox' ), $this->m( 'theme_page_callback_support' ), 'secondary' ); } // Add Actions - $lbls_reset = array ( - 'title' => __('Reset', 'simple-lightbox'), - 'confirm' => __('Are you sure you want to reset Simple Lightbox\'s settings?', 'simple-lightbox'), - 'success' => __('Settings have been reset', 'simple-lightbox'), - 'failure' => __('Settings were not reset', 'simple-lightbox') + $lbls_reset = array( + 'title' => __( 'Reset', 'simple-lightbox' ), + 'confirm' => __( 'Are you sure you want to reset Simple Lightbox\'s settings?', 'simple-lightbox' ), + 'success' => __( 'Settings have been reset', 'simple-lightbox' ), + 'failure' => __( 'Settings were not reset', 'simple-lightbox' ), ); - $this->admin->add_action('reset', $lbls_reset, $this->options); + $this->admin->add_action( 'reset', $lbls_reset, $this->options ); } /** @@ -400,21 +578,19 @@ function admin_menus() { */ public function theme_page_callback_support() { // Description - $desc = __("

Simple Lightbox thrives on your feedback!

Click the button below to get help, request a feature, or provide some feedback!

", 'simple-lightbox'); + $desc = __( '

Simple Lightbox thrives on your feedback!

Click the button below to get help, request a feature, or provide some feedback!

', 'simple-lightbox' ); echo $desc; // Link - $lnk_uri = $this->util->get_plugin_info('SupportURI'); - $lnk_txt = __('Get Support & Provide Feedback', 'simple-lightbox'); - echo $this->util->build_html_link($lnk_uri, $lnk_txt, array('target' => '_blank', 'class' => 'button')); - } - - /** - * Filter support link text in plugin metadata - * @param string $text Original link text - * @return string Modified link text - */ - public function admin_plugin_row_meta_support($text) { - return __("Feedback & Support", 'simple-lightbox'); + $lnk_uri = $this->util->get_plugin_info( 'SupportURI' ); + $lnk_txt = __( 'Get Support & Provide Feedback', 'simple-lightbox' ); + echo $this->util->build_html_link( + $lnk_uri, + $lnk_txt, + array( + 'target' => '_blank', + 'class' => 'button', + ) + ); } /*-** Functionality **-*/ @@ -425,32 +601,34 @@ public function admin_plugin_row_meta_support($text) { */ function is_enabled() { static $ret = null; - if ( is_null($ret) ) { - $ret = ( !is_admin() && $this->options->get_bool('enabled') && !is_feed() ) ? true : false; + if ( is_null( $ret ) ) { + $ret = ( ! is_admin() && $this->options->get_bool( 'enabled' ) && ! is_feed() ) ? true : false; if ( $ret ) { $opt = ''; // Determine option to check if ( is_home() || is_front_page() ) { $opt = 'home'; - } - elseif ( is_singular() ) { + } elseif ( is_singular() ) { $opt = ( is_page() ) ? 'page' : 'post'; - } - elseif ( is_archive() || is_search() ) { + } elseif ( is_archive() || is_search() ) { $opt = 'archive'; } // Check sub-option - if ( !empty($opt) && ( $opt = 'enabled_' . $opt ) && $this->options->has($opt) ) { - $ret = $this->options->get_bool($opt); + if ( ! empty( $opt ) ) { + // Prefix option name. + $opt = 'enabled_' . $opt; + if ( $this->options->has( $opt ) ) { + $ret = $this->options->get_bool( $opt ); + } } } } // Filter return value - if ( !is_admin() ) { - $ret = $this->util->apply_filters('is_enabled', $ret); + if ( ! is_admin() ) { + $ret = $this->util->apply_filters( 'is_enabled', $ret ); } // Return value (force boolean) - return !!$ret; + return ! ! $ret; } /** @@ -459,22 +637,25 @@ function is_enabled() { * @param string $content Content to validate * @return bool TRUE if content is valid (FALSE otherwise) */ - protected function is_content_valid($content) { + protected function is_content_valid( $content ) { // Invalid hooks - if ( doing_filter('get_the_excerpt') ) + if ( doing_filter( 'get_the_excerpt' ) ) { return false; + } // Non-string value - if ( !is_string($content) ) + if ( ! is_string( $content ) ) { return false; + } // Empty string - $content = trim($content); - if ( empty($content) ) + $content = trim( $content ); + if ( empty( $content ) ) { return false; + } // Content is valid - return $this->util->apply_filters('is_content_valid', true, $content); + return $this->util->apply_filters( 'is_content_valid', true, $content ); } /** @@ -483,28 +664,28 @@ protected function is_content_valid($content) { * @param array $galleries A list of galleries in post * @return A list of galleries with links activated */ - function activate_galleries($galleries) { + function activate_galleries( $galleries ) { // Validate - if ( empty($galleries) ) { + if ( empty( $galleries ) ) { return $galleries; } // Check galleries for HTML output - $gallery = reset($galleries); - if ( is_array($gallery) ) { + $gallery = reset( $galleries ); + if ( is_array( $gallery ) ) { return $galleries; } // Activate galleries - $group = ( $this->options->get_bool('group_gallery') ) ? true : null; + $group = ( $this->options->get_bool( 'group_gallery' ) ) ? true : null; foreach ( $galleries as $key => $val ) { - if ( !is_null($group) ) { + if ( ! is_null( $group ) ) { $group = 'gallery_' . $key; } // Activate links in gallery - $gallery = $this->process_links($val, $group); + $gallery = $this->process_links( $val, $group ); // Save modified gallery - $galleries[$key] = $gallery; + $galleries[ $key ] = $gallery; } return $galleries; @@ -518,19 +699,19 @@ function activate_galleries($galleries) { * @param string (optonal) $group Group ID for content * @return string Post content */ - public function activate_links($content, $group = null) { + public function activate_links( $content, $group = null ) { // Validate content - if ( !$this->is_content_valid($content) ) { + if ( ! $this->is_content_valid( $content ) ) { return $content; } // Filter content before processing links - $content = $this->util->apply_filters('pre_process_links', $content); + $content = $this->util->apply_filters( 'pre_process_links', $content ); // Process links - $content = $this->process_links($content, $group); + $content = $this->process_links( $content, $group ); // Filter content after processing links - $content = $this->util->apply_filters('post_process_links', $content); + $content = $this->util->apply_filters( 'post_process_links', $content ); return $content; } @@ -543,139 +724,143 @@ public function activate_links($content, $group = null) { * @param string (optional) $group Group to add links to (Default: none) * @return string Content with processed links */ - protected function process_links($content, $group = null) { + protected function process_links( $content, $group = null ) { // Extract links - $links = $this->get_links($content, true); + $links = $this->get_links( $content, true ); // Do not process content without links - if ( empty($links) ) { + if ( empty( $links ) ) { return $content; } // Process links - static $protocol = array('http://', 'https://'); - static $qv_att = 'attachment_id'; + static $protocol = array( 'http://', 'https://' ); + static $qv_att = 'attachment_id'; static $uri_origin = null; - if ( !is_array($uri_origin) ) { - $uri_parts = array_fill_keys(array('scheme', 'host', 'path'), ''); - $uri_origin = wp_parse_args(parse_url( strtolower(home_url()) ), $uri_parts); + if ( ! is_array( $uri_origin ) ) { + $uri_parts = array_fill_keys( array( 'scheme', 'host', 'path' ), '' ); + $uri_origin = wp_parse_args( wp_parse_url( strtolower( home_url() ) ), $uri_parts ); } static $uri_proto = null; - if ( empty($uri_proto) ) { - $uri_proto = (object) array('raw' => '', 'source' => '', 'parts' => ''); + if ( empty( $uri_proto ) ) { + $uri_proto = (object) array( + 'raw' => '', + 'source' => '', + 'parts' => '', + ); } - $uri_parts_required = array('host' => ''); + $uri_parts_required = array( 'host' => '' ); // Setup group properties $g_props = (object) array( - 'enabled' => $this->options->get_bool('group_links'), - 'attr' => 'group', - 'base' => '', - 'legacy_prefix' => 'lightbox[', - 'legacy_suffix' => ']' + 'enabled' => $this->options->get_bool( 'group_links' ), + 'attr' => 'group', + 'base' => '', + 'legacy_prefix' => 'lightbox[', + 'legacy_suffix' => ']', ); if ( $g_props->enabled ) { - $g_props->base = ( is_scalar($group) ) ? trim(strval($group)) : ''; + $g_props->base = ( is_scalar( $group ) ) ? trim( strval( $group ) ) : ''; } // Initialize content handlers - if ( !( $this->handlers instanceof SLB_Content_Handlers ) ) { - $this->handlers = new SLB_Content_Handlers($this); + if ( ! ( $this->handlers instanceof SLB_Content_Handlers ) ) { + $this->handlers = new SLB_Content_Handlers( $this ); } // Iterate through and activate supported links foreach ( $links as $link ) { // Init vars - $pid = 0; - $link_new = $link; - $uri = clone $uri_proto; - $type = false; + $pid = 0; + $link_new = $link; + $uri = clone $uri_proto; + $type = false; $props_extra = array(); - $key = null; - $internal = false; + $key = null; + $internal = false; // Parse link attributes - $attrs = $this->util->parse_attribute_string($link_new, array('href' => '')); + $attrs = $this->util->parse_attribute_string( $link_new, array( 'href' => '' ) ); // Get URI $uri->raw = $attrs['href']; // Stop processing invalid links - if ( !$this->validate_uri($uri->raw) - || $this->has_attribute($attrs, 'active', false) // Previously-processed + if ( ! $this->validate_uri( $uri->raw ) + || $this->has_attribute( $attrs, 'active' ) // Previously-processed. ) { continue; } // Normalize URI (make absolute) - $uri->source = WP_HTTP::make_absolute_url($uri->raw, $uri_origin['scheme'] . '://' . $uri_origin['host']); + $uri->source = WP_HTTP::make_absolute_url( $uri->raw, $uri_origin['scheme'] . '://' . $uri_origin['host'] ); // URI cached? - $key = $this->get_media_item_id($uri->source); + $key = $this->get_media_item_id( $uri->source ); // Internal URI? (e.g. attachments) - if ( !$key ) { - $uri->parts = array_merge( $uri_parts_required, (array) parse_url($uri->source) ); - $internal = ( $uri->parts['host'] === $uri_origin['host'] ) ? true : false; + if ( ! $key ) { + $uri->parts = array_merge( $uri_parts_required, (array) wp_parse_url( $uri->source ) ); + $internal = ( $uri->parts['host'] === $uri_origin['host'] ) ? true : false; // Attachment? - if ( $internal && is_local_attachment($uri->source) ) { - $pid = url_to_postid($uri->source); - $src = wp_get_attachment_url($pid); - if ( !!$src ) { - $uri->source = $src; + if ( $internal && is_local_attachment( $uri->source ) ) { + $pid = url_to_postid( $uri->source ); + $src = wp_get_attachment_url( $pid ); + if ( ! ! $src ) { + $uri->source = $src; $props_extra['id'] = $pid; // Check cache for attachment source URI - $key = $this->get_media_item_id($uri->source); + $key = $this->get_media_item_id( $uri->source ); } - unset($src); + unset( $src ); } } // Determine content type - if ( !$key ) { + if ( ! $key ) { // Get handler match - $hdl_result = $this->handlers->match($uri->source); - if ( !!$hdl_result->handler ) { - $type = $hdl_result->handler->get_id(); + $hdl_result = $this->handlers->match( $uri->source ); + if ( ! ! $hdl_result->handler ) { + $type = $hdl_result->handler->get_id(); $props_extra = $hdl_result->props; // Updated source URI - if ( isset($props_extra['uri']) ) { + if ( isset( $props_extra['uri'] ) ) { $uri->source = $props_extra['uri']; - unset($props_extra['uri']); + unset( $props_extra['uri'] ); } } // Cache valid item - if ( !!$type ) { - $key = $this->cache_media_item($uri, $type, $internal, $props_extra); + if ( ! ! $type ) { + $key = $this->cache_media_item( $uri, $type, $internal, $props_extra ); } } // Stop processing invalid links - if ( !$key ) { + if ( ! $key ) { // Cache invalid URI - $this->validated_uris[$uri->source] = false; + $this->validated_uris[ $uri->source ] = false; if ( $uri->raw !== $uri->source ) { - $this->validated_uris[$uri->raw] = false; + $this->validated_uris[ $uri->raw ] = false; } continue; } // Activate link - $this->set_attribute($attrs, 'active'); - $this->set_attribute($attrs, 'asset', $key); + $this->set_attribute( $attrs, 'active' ); + $this->set_attribute( $attrs, 'asset', $key ); // Mark internal links if ( $internal ) { - $this->set_attribute($attrs, 'internal', $pid); + $this->set_attribute( $attrs, 'internal', $pid ); } // Set group (if enabled) if ( $g_props->enabled ) { $group = array(); // Get preset group attribute - $g = ( $this->has_attribute($attrs, $g_props->attr) ) ? $this->get_attribute($attrs, $g_props->attr) : ''; - if ( is_string($g) && ($g = trim($g)) && !empty($g) ) { - $group[] = $g; - } elseif ( !empty($g_props->base) ) { + $g = ( $this->has_attribute( $attrs, $g_props->attr ) ) ? $this->get_attribute( $attrs, $g_props->attr ) : ''; + if ( ! empty( $g ) ) { + $group[] = $g; + } elseif ( ! empty( $g_props->base ) ) { $group[] = $g_props->base; } @@ -686,31 +871,31 @@ protected function process_links($content, $group = null) { * * @param array $group Components used to build group ID */ - $group = $this->util->apply_filters('get_group_id', $group); + $group = $this->util->apply_filters( 'get_group_id', $group ); // Default group - if ( empty($group) || !is_array($group) ) { + if ( empty( $group ) || ! is_array( $group ) ) { $group = $this->get_prefix(); } else { - $group = implode('_', $group); + $group = implode( '_', $group ); } // Set group attribute - $this->set_attribute($attrs, $g_props->attr, $group); - unset($g); + $this->set_attribute( $attrs, $g_props->attr, $group ); + unset( $g ); } // Filter attributes - $attrs = $this->util->apply_filters('process_link_attributes', $attrs); + $attrs = $this->util->apply_filters( 'process_link_attributes', $attrs ); // Update link in content - $link_new = 'util->build_attribute_string($attrs) . '>'; - $content = str_replace($link, $link_new, $content); + $link_new = 'util->build_attribute_string( $attrs ) . '>'; + $content = str_replace( $link, $link_new, $content ); } // Handle widget content - if ( !!$this->widget_processing && 'the_content' == current_filter() ) { - $content = $this->exclude_wrap($content); + if ( ! ! $this->widget_processing && 'the_content' === current_filter() ) { + $content = $this->exclude_wrap( $content ); } return $content; @@ -722,13 +907,14 @@ protected function process_links($content, $group = null) { * @param bool (optional) $unique Remove duplicates from returned links (Default: FALSE) * @return array Links in content */ - function get_links($content, $unique = false) { - $rgx = "/\).)*\shref=[^\>\<]++\>/i"; + function get_links( $content, $unique = false ) { + $rgx = "/\).)*\shref=[^\>\<]++\>/i"; $links = []; - preg_match_all($rgx, $content, $links); + preg_match_all( $rgx, $content, $links ); $links = $links[0]; - if ( $unique ) - $links = array_unique($links); + if ( $unique ) { + $links = array_unique( $links ); + } return $links; } @@ -740,28 +926,30 @@ function get_links($content, $unique = false) { * @param string $uri URI to validate * @return bool TRUE if URI is valid */ - protected function validate_uri($uri) { + protected function validate_uri( $uri ) { static $patterns = null; // Previously-validated URI - if ( isset($this->validated_uris[$uri]) ) - return $this->validated_uris[$uri]; + if ( isset( $this->validated_uris[ $uri ] ) ) { + return $this->validated_uris[ $uri ]; + } $valid = true; // Boilerplate validation - if ( empty($uri) // Empty - || 0 === strpos($uri, '#') // Anchor - ) + if ( empty( $uri ) // Empty + || 0 === strpos( $uri, '#' ) // Anchor + ) { $valid = false; + } // Regex matching if ( $valid ) { // Get patterns - if ( is_null($patterns) ) { - $patterns = $this->util->apply_filters('validate_uri_regex', array()); + if ( is_null( $patterns ) ) { + $patterns = $this->util->apply_filters( 'validate_uri_regex', array() ); } // Iterate through patterns until match found foreach ( $patterns as $pattern ) { - if ( 1 === preg_match($pattern, $uri) ) { + if ( 1 === preg_match( $pattern, $uri ) ) { $valid = false; break; } @@ -769,7 +957,7 @@ protected function validate_uri($uri) { } // Cache - $this->validated_uris[$uri] = $valid; + $this->validated_uris[ $uri ] = $valid; return $valid; } @@ -777,7 +965,7 @@ protected function validate_uri($uri) { * Add URI validation regex pattern * @param */ - public function validate_uri_regex_default($patterns) { + public function validate_uri_regex_default( $patterns ) { $patterns[] = '@^https?://[^/]*(wikipedia|wikimedia)\.org/wiki/file:.*$@i'; return $patterns; } @@ -798,17 +986,18 @@ public function is_request_valid() { * Sets options/settings to initialize lightbox functionality on page load * @return void */ - function client_init($client_script) { + function client_init( $client_script ) { // Get options $options = $this->options->build_client_output(); // Load UI Strings - if ( ($labels = $this->build_labels()) && !empty($labels) ) { + $labels = $this->build_labels(); + if ( ! empty( $labels ) ) { $options['ui_labels'] = $labels; } // Build client output - $client_script[] = $this->util->call_client_method('View.init', $options); + $client_script[] = $this->util->call_client_method( 'View.init', $options ); return $client_script; } @@ -819,23 +1008,24 @@ function client_init($client_script) { * @uses `_wp_attachment_metadata` to retrieve attachment metadata */ function client_footer() { - if ( !$this->has_cached_media_items() ) + if ( ! $this->has_cached_media_items() ) { return false; + } // Set up hooks - add_action('wp_print_footer_scripts', $this->m('client_footer_script')); + add_action( 'wp_print_footer_scripts', $this->m( 'client_footer_script' ) ); // Build client output - $this->util->do_action('footer'); + $this->util->do_action( 'footer' ); } /** * Output client footer scripts */ function client_footer_script() { - $client_script = $this->util->apply_filters('footer_script', array()); - if ( !empty($client_script) ) { - echo $this->util->build_script_element($client_script, 'footer', true, true); + $client_script = $this->util->apply_filters( 'footer_script', array() ); + if ( ! empty( $client_script ) ) { + echo $this->util->build_script_element( $client_script, 'footer', true, true ); } } @@ -846,7 +1036,7 @@ function client_footer_script() { * @return array Modified script commands. * TODO Refactor */ - public function client_script_media($client_script) { + public function client_script_media( $client_script ) { global $wpdb; // Init. @@ -856,140 +1046,108 @@ public function client_script_media($client_script) { $m_internals = []; foreach ( $this->media_items as $key => $p ) { if ( $p->internal ) { - $m_internals[$key] =& $this->media_items[$key]; + $m_internals[ $key ] =& $this->media_items[ $key ]; } } // Cleanup. - unset($key, $p); + unset( $key, $p ); // Process internal links. - if ( !empty($m_internals) ) { - $uris_base = []; + if ( ! empty( $m_internals ) ) { + $uris_base = []; $uri_prefix = wp_upload_dir(); - $uri_prefix = $this->util->normalize_path($uri_prefix['baseurl'], true); + $uri_prefix = $this->util->normalize_path( $uri_prefix['baseurl'], true ); foreach ( $m_internals as $key => $p ) { // Prepare internal links. // Create relative URIs for attachment data retrieval. - if ( !$p->id && strpos($p->source, $uri_prefix) === 0 ) { - $uris_base[str_replace($uri_prefix, '', $p->source)] = $key; + if ( ! $p->id && strpos( $p->source, $uri_prefix ) === 0 ) { + $uris_base[ str_replace( $uri_prefix, '', $p->source ) ] = $key; } } // Cleanup. - unset($key, $p); + unset( $key, $p ); // Retrieve attachment IDs. - $uris_flat = "('" . implode("','", array_keys($uris_base)) . "')"; - $q = $wpdb->prepare("SELECT post_id, meta_value FROM $wpdb->postmeta WHERE `meta_key` = %s AND LOWER(`meta_value`) IN $uris_flat LIMIT %d", '_wp_attached_file', count($uris_base)); - $pids = $wpdb->get_results($q); + $uris_flat = "('" . implode( "','", array_keys( $uris_base ) ) . "')"; + $q = $wpdb->prepare( "SELECT post_id, meta_value FROM $wpdb->postmeta WHERE `meta_key` = %s AND LOWER(`meta_value`) IN $uris_flat LIMIT %d", '_wp_attached_file', count( $uris_base ) ); + $pids = $wpdb->get_results( $q ); // Match IDs to URIs. if ( $pids ) { foreach ( $pids as $pd ) { $file =& $pd->meta_value; - if ( isset($uris_base[$file]) ) { - $m_internals[ $uris_base[$file] ]->id = absint($pd->post_id); + if ( isset( $uris_base[ $file ] ) ) { + $m_internals[ $uris_base[ $file ] ]->id = absint( $pd->post_id ); } } } // Cleanup. - unset($uris_base, $uris_flat, $q, $pids, $pd, $file); + unset( $uris_base, $uris_flat, $q, $pids, $pd, $file ); } // Process items with attachment IDs. $pids = []; foreach ( $this->media_items as $key => $p ) { // Add post ID to query. - if ( !!$p->id ) { + if ( ! ! $p->id ) { // Create array for ID (support multiple URIs per ID). - if ( !isset($pids[$p->id]) ) { - $pids[$p->id] = []; + if ( ! isset( $pids[ $p->id ] ) ) { + $pids[ $p->id ] = []; } // Add URI to ID. - $pids[$p->id][] = $key; + $pids[ $p->id ][] = $key; } } // Cleanup. - unset($key, $p); + unset( $key, $p ); // Retrieve attachment properties. - if ( !empty($pids) ) { - $pids_flat = array_keys($pids); + if ( ! empty( $pids ) ) { + $pids_flat = array_keys( $pids ); // Retrieve attachment post data. - $atts = get_posts(array('post_type' => 'attachment', 'include' => $pids_flat)); + $atts = get_posts( + array( + 'post_type' => 'attachment', + 'include' => $pids_flat, + ) + ); // Process attachments. if ( $atts ) { - /* @future: Metadata - // Retrieve attachment metadata. - $pids_flat = "('" . implode("','", $pids_flat) . "')"; - $atts_meta = $wpdb->get_results($wpdb->prepare("SELECT `post_id`,`meta_value` FROM $wpdb->postmeta WHERE `post_id` IN $pids_flat AND `meta_key` = %s LIMIT %d", '_wp_attachment_metadata', count($atts))); - // Reindex metadata array by attachment ID. - if ( $atts_meta ) { - $meta = []; - foreach ( $atts_meta as $att_meta ) { - $meta[$att_meta->post_id] = $att_meta->meta_value; - } - $atts_meta = $meta; - // Cleanup. - unset($meta); - } else { - $atts_meta = []; - } - END @future: Metadata */ - - /* @future: Metadata - // Process attachment data. - $media_props = array('file', 'width', 'height'); - $media_original_name = 'full'; - END @future: Metadata */ - - $props_post_map = [ 'title' => 'post_title', 'caption' => 'post_excerpt', 'description' => 'post_content' ]; + $props_post_map = [ + 'title' => 'post_title', + 'caption' => 'post_excerpt', + 'description' => 'post_content', + ]; foreach ( $atts as $att ) { $data = []; - /* @future: Metadata - $data = [ 'meta' => [], 'media' => [ $media_original_name => [] ] ]; - END @future: Metadata */ // Remap post data to metadata. foreach ( $props_post_map as $props_post_key => $props_post_source ) { - $data[$props_post_key] = $att->{$props_post_source}; + $data[ $props_post_key ] = $att->{$props_post_source}; } // Cleanup. - unset($props_post_key, $props_post_source); - - /* @future: Metadata - // Process metadata. - if ( isset( $atts_meta[$att->ID] ) && ( $a = unserialize( $atts_meta[$att->ID] ) ) && is_array( $a ) ) { - // Media properties. - // Source file. - foreach ( $media_props as $d ) { - if ( isset($a[$d]) ) { - $data['media'][$media_original_name][$d] = $a[$d]; - } - } - // Cleanup. - unset( $a, $d ); - } - END @future: Metadata */ + unset( $props_post_key, $props_post_source ); + // Save data to corresponding media item(s). - if ( isset($pids[$att->ID]) ) { - foreach ( $pids[$att->ID] as $key ) { - $this->media_items[$key] = (object) array_merge( (array) $this->media_items[$key], $data ); + if ( isset( $pids[ $att->ID ] ) ) { + foreach ( $pids[ $att->ID ] as $key ) { + $this->media_items[ $key ] = (object) array_merge( (array) $this->media_items[ $key ], $data ); } } } // Cleanup. - unset($att, $data); + unset( $att, $data ); } // Cleanup. - unset($atts, $atts_meta, $m, $a, $uri, $pids, $pids_flat); + unset( $atts, $atts_meta, $m, $a, $uri, $pids, $pids_flat ); } // Filter media items. - $this->media_items = $this->util->apply_filters('media_items', $this->media_items); + $this->media_items = $this->util->apply_filters( 'media_items', $this->media_items ); // Build client output. - $obj = 'View.assets'; - $client_script[] = $this->util->extend_client_object($obj, $this->media_items); + $obj = 'View.assets'; + $client_script[] = $this->util->extend_client_object( $obj, $this->media_items ); return $client_script; } @@ -1007,33 +1165,36 @@ public function client_script_media($client_script) { * @param array $props (optional) Properties to store for item (Default: NULL) * @return string Unique ID for cached media item */ - private function cache_media_item($uri, $type, $internal, $props = null) { + private function cache_media_item( $uri, $type, $internal, $props = null ) { // Validate. - if ( !is_object($uri) || !is_string($type) ) { + if ( ! is_object( $uri ) || ! is_string( $type ) ) { return false; } // Check if URI already cached. - $key = $this->get_media_item_id($uri->source); + $key = $this->get_media_item_id( $uri->source ); // Cache new item. - if ( null == $key ) { + if ( null === $key ) { // Generate Unique ID. do { - $key = (string) mt_rand(); - } while ( isset($this->media_items_raw['props'][$key]) ); + $key = (string) wp_rand(); + } while ( isset( $this->media_items_raw['props'][ $key ] ) ); // Build properties object. $i = $this->media_item_template; - if ( is_array($props) && !empty($props) ) { - $i = array_merge($i, $props); + if ( is_array( $props ) && ! empty( $props ) ) { + $i = array_merge( $i, $props ); } - $i = array_merge( $i, [ - 'type' => $type, - 'source' => $uri->source, - 'internal' => $internal, - ] ); + $i = array_merge( + $i, + [ + 'type' => $type, + 'source' => $uri->source, + 'internal' => $internal, + ] + ); // Cache item properties. - $this->media_items_raw['props'][$key] = (object) $i; + $this->media_items_raw['props'][ $key ] = (object) $i; // Cache Source URI (point to properties object). - $this->media_items_raw['uri'][$uri->source] = $key; + $this->media_items_raw['uri'][ $uri->source ] = $key; } return $key; } @@ -1044,9 +1205,9 @@ private function cache_media_item($uri, $type, $internal, $props = null) { * @param string $uri Media item URI * @return string|null Media item ID (Default: NULL if URI doesn't exist in collection) */ - private function get_media_item_id($uri) { - if ( $this->media_item_cached($uri) ) { - return $this->media_items_raw['uri'][$uri]; + private function get_media_item_id( $uri ) { + if ( $this->media_item_cached( $uri ) ) { + return $this->media_items_raw['uri'][ $uri ]; } return null; } @@ -1056,8 +1217,8 @@ private function get_media_item_id($uri) { * @param string $uri URI of media item * @return boolean Whether media item has been cached */ - private function media_item_cached($uri) { - return ( is_string($uri) && !empty($uri) && isset($this->media_items_raw['uri'][$uri]) ) ? true : false; + private function media_item_cached( $uri ) { + return ( is_string( $uri ) && ! empty( $uri ) && isset( $this->media_items_raw['uri'][ $uri ] ) ) ? true : false; } /** @@ -1065,10 +1226,10 @@ private function media_item_cached($uri) { * @param string $uri Media item URI * @return object|null Media item properties (NULL if not set) */ - private function get_cached_media_item($uri) { - $key = $this->get_media_item_id($uri); - if ( null != $key ) { - return $this->media_items_raw['props'][$key]; + private function get_cached_media_item( $uri ) { + $key = $this->get_media_item_id( $uri ); + if ( null !== $key ) { + return $this->media_items_raw['props'][ $key ]; } return null; } @@ -1087,7 +1248,7 @@ private function &get_cached_media_items() { * @return boolean */ private function has_cached_media_items() { - return ( empty($this->media_items_raw['props']) ) ? false : true; + return ( empty( $this->media_items_raw['props'] ) ) ? false : true; } /*-** Exclusion **-*/ @@ -1099,12 +1260,12 @@ private function has_cached_media_items() { */ private function get_exclude() { // Initialize exclude data - if ( !is_object($this->exclude) ) { - $this->exclude = (object) array ( - 'tags' => $this->get_exclude_tags(), - 'ph' => $this->get_exclude_placeholder(), - 'group_default' => 'default', - 'cache' => array(), + if ( ! is_object( $this->exclude ) ) { + $this->exclude = (object) array( + 'tags' => $this->get_exclude_tags(), + 'ph' => $this->get_exclude_placeholder(), + 'group_default' => 'default', + 'cache' => array(), ); } return $this->exclude; @@ -1118,18 +1279,30 @@ private function get_exclude() { */ private function get_exclude_tags() { static $tags = null; - if ( null == $tags ) { - $base = $this->add_prefix('exclude'); - $tags = (object) array ( - 'base' => $base, - 'open' => $this->util->add_wrapper($base), - 'close' => $this->util->add_wrapper($base, '[/', ']') - ); - $tags->search ='#' . preg_quote($tags->open) . '(.*?)' . preg_quote($tags->close) . '#s'; + if ( null === $tags ) { + /* Init tag elements */ + $tags = (object) [ + // Tag base. + 'base' => $this->add_prefix( 'exclude' ), + ]; + // Opening tag. + $tags->open = $this->util->add_wrapper( $tags->base ); + // Closing tag. + $tags->close = $this->util->add_wrapper( $tags->base, '[/', ']' ); + + /* Build tag search pattern */ + + // Pattern delimeter. + $dlm = '#'; + // Pattern flags. + $flags = 's'; + // Tag search pattern. + $tags->search = $dlm . preg_quote( $tags->open, $dlm ) . '(.*?)' . preg_quote( $tags->close, $dlm ) . $dlm . $flags; } return $tags; } + /** * Get exclusion tag ("[slb_exclude]") * @uses `get_exclude_tags()` to retrieve tag @@ -1137,11 +1310,11 @@ private function get_exclude_tags() { * @param string $type (optional) Tag to retrieve (open or close) * @return string Exclusion tag */ - private function get_exclude_tag( $type = "open" ) { + private function get_exclude_tag( $type = 'open' ) { // Validate $tags = $this->get_exclude_tags(); - if ( !isset($tags->{$type}) ) { - $type = "open"; + if ( ! isset( $tags->{$type} ) ) { + $type = 'open'; } return $tags->{$type}; } @@ -1152,17 +1325,22 @@ private function get_exclude_tag( $type = "open" ) { */ private function get_exclude_placeholder() { static $ph; - if ( !is_object($ph) ) { - $ph = (object) array ( - 'base' => $this->add_prefix('exclude_temp'), - 'open' => '{{', - 'close' => '}}', - 'attrs' => array ( 'group' => '', 'key' => '' ), + if ( ! is_object( $ph ) ) { + $ph = (object) array( + 'base' => $this->add_prefix( 'exclude_temp' ), + 'open' => '{{', + 'close' => '}}', + 'attrs' => array( + 'group' => '', + 'key' => '', + ), ); // Search Patterns - $sub = '(.+?)'; - $ph->search = '#' . preg_quote($ph->open) . $ph->base . '\s+' . $sub . preg_quote($ph->close) . '#s'; - $ph->search_group = str_replace($sub, '(group="%s"\s+.?)', $ph->search); + $sub = '(.+?)'; + $dlm = '#'; + $flags = 's'; + $ph->search = $dlm . preg_quote( $ph->open, $dlm ) . $ph->base . '\s+' . $sub . preg_quote( $ph->close, $dlm ) . $dlm . $flags; + $ph->search_group = str_replace( $sub, '(group="%s"\s+.?)', $ph->search ); // Templates $attr_string = ''; foreach ( $ph->attrs as $attr => $val ) { @@ -1179,10 +1357,10 @@ private function get_exclude_placeholder() { * @param string $content Content to exclude * @return string Content wrapped in exclusion tags */ - private function exclude_wrap($content) { + private function exclude_wrap( $content ) { // Validate - if ( !is_string($content) ) { - $content = ""; + if ( ! is_string( $content ) ) { + $content = ''; } // Wrap $tags = $this->get_exclude_tags(); @@ -1195,39 +1373,39 @@ private function exclude_wrap($content) { * @param string $content Content to remove excluded content from * @return string Updated content */ - public function exclude_content($content, $group = null) { + public function exclude_content( $content, $group = null ) { $ex = $this->get_exclude(); // Setup cache - if ( !is_string($group) || empty($group) ) { + if ( ! is_string( $group ) || empty( $group ) ) { $group = $ex->group_default; } - if ( !isset($ex->cache[$group]) ) { - $ex->cache[$group] = array(); + if ( ! isset( $ex->cache[ $group ] ) ) { + $ex->cache[ $group ] = array(); } - $cache =& $ex->cache[$group]; + $cache =& $ex->cache[ $group ]; - $content = $this->util->apply_filters('pre_exclude_content', $content); + $content = $this->util->apply_filters( 'pre_exclude_content', $content ); // Search content $matches = null; - if ( false !== strpos($content, $ex->tags->open) && preg_match_all($ex->tags->search, $content, $matches) ) { + if ( false !== strpos( $content, $ex->tags->open ) && preg_match_all( $ex->tags->search, $content, $matches ) ) { // Determine index - $idx = ( !!end($cache) ) ? key($cache) : -1; - $ph = array(); + $idx = ( ! ! end( $cache ) ) ? key( $cache ) : -1; + $ph = array(); foreach ( $matches[1] as $midx => $match ) { // Update index $idx++; // Cache content - $cache[$idx] = $match; + $cache[ $idx ] = $match; // Build placeholder - $ph[] = sprintf($ex->ph->template, $group, $idx); + $ph[] = sprintf( $ex->ph->template, $group, $idx ); } - unset($midx, $match); + unset( $midx, $match ); // Replace content with placeholder - $content = str_replace($matches[0], $ph, $content); + $content = str_replace( $matches[0], $ph, $content ); // Cleanup - unset($matches, $ph); + unset( $matches, $ph ); } return $content; @@ -1238,12 +1416,12 @@ public function exclude_content($content, $group = null) { * @param string $content Content to exclude shortcodes from * @return string Content with shortcodes excluded */ - public function exclude_shortcodes($content) { + public function exclude_shortcodes( $content ) { // Get shortcodes to exclude - $shortcodes = $this->util->apply_filters('exclude_shortcodes', array( $this->add_prefix('group') )); + $shortcodes = $this->util->apply_filters( 'exclude_shortcodes', array( $this->add_prefix( 'group' ) ) ); // Set callback - $shortcodes = array_fill_keys($shortcodes, $this->m('exclude_shortcodes_handler')); - return $this->util->do_shortcode($content, $shortcodes); + $shortcodes = array_fill_keys( $shortcodes, $this->m( 'exclude_shortcodes_handler' ) ); + return $this->util->do_shortcode( $content, $shortcodes ); } /** @@ -1255,10 +1433,10 @@ public function exclude_shortcodes($content) { * @param string $tag Shortcode name * @return string Excluded shortcode */ - public function exclude_shortcodes_handler($attr, $content, $tag) { - $code = $this->util->make_shortcode($tag, $attr, $content); + public function exclude_shortcodes_handler( $attr, $content, $tag ) { + $code = $this->util->make_shortcode( $tag, $attr, $content ); // Exclude shortcode - return $this->exclude_wrap($code); + return $this->exclude_wrap( $code ); } /** @@ -1266,37 +1444,39 @@ public function exclude_shortcodes_handler($attr, $content, $tag) { * @param string $content Content to restore excluded content to * @return string Content with excluded content restored */ - public function restore_excluded_content($content, $group = null) { + public function restore_excluded_content( $content, $group = null ) { $ex = $this->get_exclude(); // Setup cache - if ( !is_string($group) || empty($group) ) { + if ( ! is_string( $group ) || empty( $group ) ) { $group = $ex->group_default; } // Nothing to restore if cache group doesn't exist - if ( !isset($ex->cache[$group]) ) { + if ( ! isset( $ex->cache[ $group ] ) ) { return $content; } - $cache =& $ex->cache[$group]; + $cache =& $ex->cache[ $group ]; // Search content for placeholders $matches = null; - if ( false !== strpos($content, $ex->ph->open . $ex->ph->base) && preg_match_all($ex->ph->search, $content, $matches) ) { + if ( false !== strpos( $content, $ex->ph->open . $ex->ph->base ) && preg_match_all( $ex->ph->search, $content, $matches ) ) { // Restore placeholders foreach ( $matches[1] as $idx => $ph ) { // Parse placeholder attributes - $attrs = $this->util->parse_attribute_string($ph, $ex->ph->attrs); + $attrs = $this->util->parse_attribute_string( $ph, $ex->ph->attrs ); // Validate if ( $attrs['group'] !== $group ) { continue; } // Restore content - $key = $attrs['key'] = intval($attrs['key']); - if ( isset($cache[$key]) ) { - $content = str_replace($matches[0][$idx], $cache[$key], $content); + $attrs['key'] = intval( $attrs['key'] ); + $key = $attrs['key']; + + if ( isset( $cache[ $key ] ) ) { + $content = str_replace( $matches[0][ $idx ], $cache[ $key ], $content ); } } // Cleanup - unset($idx, $ph, $matches, $key); + unset( $idx, $ph, $matches, $key ); } return $content; @@ -1310,8 +1490,8 @@ public function restore_excluded_content($content, $group = null) { */ function group_get_wrapper() { static $fmt = null; - if ( is_null($fmt) ) { - $fmt = $this->util->make_shortcode($this->add_prefix('group'), null, '%s'); + if ( is_null( $fmt ) ) { + $fmt = $this->util->make_shortcode( $this->add_prefix( 'group' ), null, '%s' ); } return $fmt; } @@ -1323,16 +1503,16 @@ function group_get_wrapper() { * @param string $content Post content * @return string Modified post content */ - function group_shortcodes($content) { - if ( !$this->is_content_valid($content) ) { + function group_shortcodes( $content ) { + if ( ! $this->is_content_valid( $content ) ) { return $content; } // Setup shortcodes to wrap - $shortcodes = $this->util->apply_filters('group_shortcodes', array( 'gallery', 'nggallery' )); + $shortcodes = $this->util->apply_filters( 'group_shortcodes', array( 'gallery', 'nggallery' ) ); // Set custom callback - $shortcodes = array_fill_keys($shortcodes, $this->m('group_shortcodes_handler')); + $shortcodes = array_fill_keys( $shortcodes, $this->m( 'group_shortcodes_handler' ) ); // Process gallery shortcodes - return $this->util->do_shortcode($content, $shortcodes); + return $this->util->do_shortcode( $content, $shortcodes ); } /** @@ -1342,10 +1522,10 @@ function group_shortcodes($content) { * @param string $tag Shortcode name * @return string Grouped shortcode */ - function group_shortcodes_handler($attr, $content, $tag) { - $code = $this->util->make_shortcode($tag, $attr, $content); + function group_shortcodes_handler( $attr, $content, $tag ) { + $code = $this->util->make_shortcode( $tag, $attr, $content ); // Wrap shortcode - return sprintf( $this->group_get_wrapper(), $code); + return sprintf( $this->group_get_wrapper(), $code ); } /** @@ -1353,8 +1533,8 @@ function group_shortcodes_handler($attr, $content, $tag) { * @param string $content Content to activate * @return string Updated content */ - public function activate_groups($content) { - return $this->util->do_shortcode($content, array( $this->add_prefix('group') => $this->m('activate_groups_handler') ) ); + public function activate_groups( $content ) { + return $this->util->do_shortcode( $content, array( $this->add_prefix( 'group' ) => $this->m( 'activate_groups_handler' ) ) ); } /** @@ -1364,18 +1544,18 @@ public function activate_groups($content) { * @param string $tag Shortcode name * @return string Grouped shortcode */ - function activate_groups_handler($attr, $content, $tag) { + function activate_groups_handler( $attr, $content, $tag ) { // Get Group ID // Custom group - if ( isset($attr['id']) ) { + if ( isset( $attr['id'] ) ) { $group = $attr['id']; - trim($group); + trim( $group ); } // Automatically-generated group - if ( empty($group) ) { - $group = 'auto_' . ++$this->groups['auto']; + if ( empty( $group ) ) { + $group = 'auto_' . ( ++$this->groups['auto'] ); } - return $this->process_links($content, $group); + return $this->process_links( $content, $group ); } /*-** Widgets **-*/ @@ -1386,17 +1566,17 @@ function activate_groups_handler($attr, $content, $tag) { * @param array $widget_args Widget arguments * @return void */ - public function widget_process_start($widget_args) { + public function widget_process_start( $widget_args ) { // Do not continue if a widget is currently being processed (avoid nested processing) if ( 0 < $this->widget_processing_level ) { return; } // Start widget processing - $this->widget_processing = true; + $this->widget_processing = true; $this->widget_processing_params = $widget_args; // Enable widget grouping - if ( $this->options->get_bool('group_widget') ) { - $this->util->add_filter('get_group_id', $this->m('widget_group_id')); + if ( $this->options->get_bool( 'group_widget' ) ) { + $this->util->add_filter( 'get_group_id', $this->m( 'widget_group_id' ) ); } // Begin output buffer ob_start(); @@ -1426,18 +1606,18 @@ public function widget_process_finish() { * - No widget is being processed * - Processing a nested widget */ - if ( !$this->widget_processing || 0 < $this->widget_processing_level ) { + if ( ! $this->widget_processing || 0 < $this->widget_processing_level ) { return; } // Activate widget output - $out = $this->activate_links(ob_get_clean()); + $out = $this->activate_links( ob_get_clean() ); // Clear grouping callback - if ( $this->options->get_bool('group_widget') ) { - $this->util->remove_filter('get_group_id', $this->m('widget_group_id')); + if ( $this->options->get_bool( 'group_widget' ) ) { + $this->util->remove_filter( 'get_group_id', $this->m( 'widget_group_id' ) ); } // End widget processing - $this->widget_processing = false; + $this->widget_processing = false; $this->widget_processing_params = null; // Output widget echo $out; @@ -1450,10 +1630,10 @@ public function widget_process_finish() { * @param array $group_segments Group ID segments * @return array Modified group ID segments */ - public function widget_group_id($group_segments) { + public function widget_group_id( $group_segments ) { // Add current widget ID to group ID - if ( isset($this->widget_processing_params['id']) ) { - array_unshift($group_segments, $this->widget_processing_params['id']); + if ( isset( $this->widget_processing_params['id'] ) ) { + array_unshift( $group_segments, $this->widget_processing_params['id'] ); } return $group_segments; } @@ -1466,7 +1646,7 @@ public function widget_group_id($group_segments) { */ public function widget_process_nested() { // Stop if no widget is being processed - if ( !$this->widget_processing ) { + if ( ! $this->widget_processing ) { return; } @@ -1490,7 +1670,7 @@ public function widget_process_nested_finish() { * @return void */ public function widget_block_start() { - $this->util->add_filter('is_content_valid', $this->m('widget_block_handle')); + $this->util->add_filter( 'is_content_valid', $this->m( 'widget_block_handle' ) ); } /** @@ -1498,13 +1678,13 @@ public function widget_block_start() { * @return void */ public function widget_block_finish() { - $this->util->remove_filter('is_content_valid', $this->m('widget_block_handle')); + $this->util->remove_filter( 'is_content_valid', $this->m( 'widget_block_handle' ) ); } /** * Handle widget activation blocking */ - public function widget_block_handle($is_content_valid) { + public function widget_block_handle( $is_content_valid ) { return false; } @@ -1518,16 +1698,16 @@ public function widget_block_handle($is_content_valid) { * @param string $nav_menu HTML content for navigation menu. * @param object $args Navigation menu's arguments. */ - public function menu_process($nav_menu, $args) { + public function menu_process( $nav_menu, $args ) { // Grouping - if ( $this->options->get_bool('group_menu') ) { + if ( $this->options->get_bool( 'group_menu' ) ) { // Generate group ID for menu $group = 'menu'; - $sep = '_'; - if ( !empty( $args->menu_id ) ) { + $sep = '_'; + if ( ! empty( $args->menu_id ) ) { $group .= $sep . $args->menu_id; - } elseif ( !empty( $args->menu ) ) { - $group .= $sep . ( ( is_object($args->menu) ) ? $args->menu->slug : $args->menu ); + } elseif ( ! empty( $args->menu ) ) { + $group .= $sep . ( ( is_object( $args->menu ) ) ? $args->menu->slug : $args->menu ); } $group = $this->group_id_unique( $group ); } else { @@ -1535,7 +1715,7 @@ public function menu_process($nav_menu, $args) { } // Process menu - $nav_menu = $this->activate_links($nav_menu, $group); + $nav_menu = $this->activate_links( $nav_menu, $group ); return $nav_menu; } @@ -1546,15 +1726,18 @@ public function menu_process($nav_menu, $args) { * @param string $group Group ID to check * @return string Unique group ID */ - public function group_id_unique($group) { + public function group_id_unique( $group ) { static $groups = array(); - while ( in_array($group, $groups) ) { + while ( in_array( $group, $groups, true ) ) { $patt = '#-(\d+)$#'; - if ( preg_match( $patt, $group, $matches ) ) - $group = preg_replace($patt, '-' . ++$matches[1], $group ); - else + if ( preg_match( $patt, $group, $matches ) ) { + $group = preg_replace( $patt, '-' . ( ++$matches[1] ), $group ); + } else { $group = $group . '-1'; + } } + // Add final group ID to array + $groups[] = $group; return $group; } @@ -1566,120 +1749,120 @@ public function group_id_unique($group) { * @param string $name (optional) Attribute base name * @return string Formatted attribute name */ - function make_attribute_name($name = '') { + function make_attribute_name( $name = '' ) { // Validate - if ( !is_string($name) ) { + if ( ! is_string( $name ) ) { $name = ''; } else { - $name = trim($name); + $name = trim( $name ); } // Setup $sep = '-'; $top = 'data'; // Generate valid name - if ( strpos($name, $top . $sep . $this->get_prefix()) !== 0 ) { - $name = $top . $sep . $this->add_prefix($name, $sep); + if ( strpos( $name, $top . $sep . $this->get_prefix() ) !== 0 ) { + $name = $top . $sep . $this->add_prefix( $name, $sep ); } return $name; } /** - * Set attribute to array - * Attribute is added to array if it does not exist - * @param array $attrs Array to add attribute to (Passed by reference) - * @param string $name Name of attribute to add - * @param string (optional) $value Attribute value - * @return array Updated attribute array + * Sets attribute value. + * + * Attribute is added to array if it does not already exist. + * + * @param string|array $attrs Array to set attribute on (Passed by reference). + * @param string $name Name of attribute to set. + * @param scalar $value Optional. Attribute value. + * @return array Updated attributes. */ - function set_attribute(&$attrs, $name, $value = true) { + function set_attribute( &$attrs, $name, $value = true ) { // Validate - $attrs = $this->get_attributes($attrs, false); - if ( !is_string($name) || empty($name) ) { + $attrs = $this->get_attributes( $attrs, false ); + // Stop if attribute name or value is invalid. + if ( ! is_string( $name ) || empty( trim( $name ) ) || ! is_scalar( $value ) ) { return $attrs; } - if ( !is_scalar($value) ) { - $value = true; - } - // Add attribute - $attrs = array_merge($attrs, array( $this->make_attribute_name($name) => strval($value) )); + // Set attribute value. + $attrs = array_merge( $attrs, array( $this->make_attribute_name( $name ) => $value ) ); return $attrs; } /** - * Convert attribute string into array - * @param string $attr_string Attribute string - * @param bool (optional) $internal Whether only internal attributes should be evaluated (Default: TRUE) - * @return array Attributes as associative array - */ - function get_attributes($attr_string, $internal = true) { - if ( is_string($attr_string) ) { - $attr_string = $this->util->parse_attribute_string($attr_string); - } - $ret = ( is_array($attr_string) ) ? $attr_string : array(); - // Filter out external attributes - if ( !empty($ret) && is_bool($internal) && $internal ) { - $ret_f = array(); - foreach ( $ret as $key => $val ) { - if ( strpos($key, $this->make_attribute_name()) == 0 ) { - $ret_f[$key] = $val; - } - } - if ( !empty($ret_f) ) { - $ret = $ret_f; - } + * Converts attribute string into array. + * + * @param string|array $attrs Attribute string to convert. Associative array also accepted. + * @param bool $internal Optional. Return only internal attributes. Default True. + * @return array Associative array of attributes (`attribute-name => attribute-value`). + */ + function get_attributes( $attrs, $internal = true ) { + // Parse attribute string. + $attrs = $this->util->parse_attribute_string( $attrs ); + // Include only internal attributes (if necessary). + if ( ! ! $internal && ! empty( $attrs ) ) { + $prefix = $this->make_attribute_name(); + $attrs = array_filter( + $attrs, + function( $key ) use ( $prefix ) { + return ( strpos( $key, $prefix ) === 0 ); + }, + ARRAY_FILTER_USE_KEY + ); } - return $ret; + return $attrs; } /** - * Retrieve attribute value - * @param string|array $attrs Attributes to retrieve attribute value from - * @param string $attr Attribute name to retrieve - * @param bool (optional) $internal Whether only internal attributes should be evaluated (Default: TRUE) - * @return string|bool Attribute value (Default: FALSE) + * Retrieves an attributes value from attribute string or array. + * + * @param string|array $attrs Attribute string to retrieve attribute value from. + * Associative array also accepted. + * @param string $attr Attribute to retrieve value for. + * @param bool $internal Optional. Retrieve internal attribute. Default true. + * @return scalar|null Attribute value. Null if attribute is invalid or does not exist. */ - function get_attribute($attrs, $attr, $internal = true) { - $ret = false; - // Validate - $attrs = $this->get_attributes($attrs, $internal); - if ( $internal ) { - $attr = $this->make_attribute_name($attr); + function get_attribute( $attrs, $attr, $internal = true ) { + // Validate. + $invalid = null; + if ( ! is_string( $attr ) || empty( trim( $attr ) ) ) { + return $invalid; + } + $attrs = $this->get_attributes( $attrs, $internal ); + if ( empty( $attrs ) ) { + return $invalid; } - if ( isset($attrs[$attr]) ) { - $ret = $attrs[$attr]; + // Format attribute name. + $attr = ( ! ! $internal ) ? $this->make_attribute_name( $attr ) : trim( $attr ); + // Stop if attribute does not exist or value is invalid. + if ( ! isset( $attrs[ $attr ] ) || ! is_scalar( $attrs[ $attr ] ) ) { + return $invalid; } + // Retreive value. + $ret = $attrs[ $attr ]; + // Validate value (type-specific). + if ( is_string( $ret ) ) { + $ret = trim( $ret ); + if ( '' === $ret ) { + return $invalid; + } + } + return $ret; } /** - * Checks if attribute exists - * If supplied, the attribute's value is also validated - * @param string|array $attrs Attributes to retrieve attribute value from - * @param string $attr Attribute name to retrieve - * @param mixed $value (optional) Attribute value to check for - * @param bool $internal (optional) Whether to check only internal attributes (Default: TRUE) - * @see get_attribute() - * @return bool Whether or not attribute (with matching value if specified) exists - */ - function has_attribute($attrs, $attr, $value = null, $internal = true) { - $a = $this->get_attribute($attrs, $attr, $internal); - $ret = false; - if ( $a !== false ) { - $ret = true; - // Check value - if ( !is_null($value) ) { - if ( is_string($value) ) { - $ret = ( $a == strval($value) ) ? true : false; - } elseif ( is_bool($value) ) { - $ret = ( !!$a == $value ) ? true : false; - } else { - $ret = false; - } - } - } - return $ret; + * Checks if attribute exists. + * + * @param string|array $attrs Attribute string to retrieve attribute value from. + * Associative array also accepted. + * @param string $attr Attribute to retrieve value for. + * @param bool $internal Optional. Retrieve internal attribute. Default true. + * @return bool True if attribute exists. False if attribute does not exist. + */ + function has_attribute( $attrs, $attr, $internal = true ) { + return ( null !== $this->get_attribute( $attrs, $attr, $internal ) ); } /** @@ -1690,9 +1873,12 @@ private function build_labels() { $ret = array(); /* Get all UI options */ $prefix = 'txt_'; - $opt_strings = array_filter( array_keys( $this->options->get_items() ), function ( $opt ) use ( $prefix ) { - return ( strpos( $opt, $prefix ) === 0 ); - } ); + $opt_strings = array_filter( + array_keys( $this->options->get_items() ), + function ( $opt ) use ( $prefix ) { + return ( strpos( $opt, $prefix ) === 0 ); + } + ); if ( count( $opt_strings ) ) { /* Build array of UI options */ foreach ( $opt_strings as $key ) { @@ -1702,4 +1888,4 @@ private function build_labels() { } return $ret; } -} \ No newline at end of file +} diff --git a/functions.php b/functions.php index 637dc5e..215eeb8 100644 --- a/functions.php +++ b/functions.php @@ -13,12 +13,12 @@ * @param string $content * @return string Updated content with activated links */ -function slb_activate($content, $group = null) { +function slb_activate( $content, $group = null ) { // Validate - if ( empty($content) ) { + if ( empty( $content ) ) { return $content; } // Activate links - $content = $GLOBALS['slb']->activate_links($content, $group); + $content = $GLOBALS['slb']->activate_links( $content, $group ); return $content; } diff --git a/includes/class.admin.php b/includes/class.admin.php index 84d3d71..cee99ae 100644 --- a/includes/class.admin.php +++ b/includes/class.admin.php @@ -1,661 +1,686 @@ - 'The settings have been reset', - 'beta' => 'Notice: This update is a Beta version. It is highly recommended that you test the update on a test server before updating the plugin on a production server.', - 'access_denied' => 'You do not have sufficient permissions' - ); - - /* Views */ - - /** - * Custom admin top-level menus - * Associative Array - * > Key: Menu ID - * > Val: Menu properties - * @var array - */ - protected $menus = array(); - - /** - * Custom admin pages - * Associative Array - * > Key: Page ID - * > Val: Page properties - * @var array - */ - protected $pages = array(); - - /** - * Custom admin sections - * Associative Array - * > Key: Section ID - * > Val: Section properties - * @var array - */ - protected $sections = array(); - - /** - * Actions - * Index Array - * @var array - */ - protected $actions = array(); - - /* Constructor */ - - public function __construct(&$parent) { - parent::__construct(); - // Set parent - if ( is_object($parent) ) - $this->parent = $parent; - } - - /* Init */ - - protected function _hooks() { - parent::_hooks(); - // Init - add_action('admin_menu', $this->m('init_menus'), 11); - - // Plugin actions - add_action('admin_action_' . $this->add_prefix('admin'), $this->m('handle_action')); - - // Notices - add_action('admin_notices', $this->m('handle_notices')); - - // Plugin listing - add_filter('plugin_action_links_' . $this->util->get_plugin_base_name(), $this->m('plugin_action_links'), 10, 4); - add_filter('plugin_row_meta', $this->m('plugin_row_meta'), 10, 4); - add_action('in_plugin_update_message-' . $this->util->get_plugin_base_name(), $this->m('plugin_update_message'), 10, 2); - add_filter('site_transient_update_plugins', $this->m('plugin_update_transient')); - } - - /** - * Declare client files (scripts, styles) - * @uses parent::_client_files() - * @return void - */ - protected function _client_files($files = null) { - $js_path = 'client/js/'; - $js_path .= ( SLB_DEV ) ? 'dev' : 'prod'; - $pfx = $this->get_prefix(); - $files = array ( - 'scripts' => array ( - 'admin' => array ( - 'file' => "$js_path/lib.admin.js", - 'deps' => array('[core]'), - 'context' => array( "admin_page_$pfx" ), - 'in_footer' => true, - ), - ), - 'styles' => array ( - 'admin' => array ( - 'file' => 'client/css/admin.css', - 'context' => array( "admin_page_$pfx", 'admin_page_plugins' ) - ) - ) - ); - parent::_client_files($files); - } - - /* Handlers */ - - /** - * Handle routing of internal action to appropriate handler - */ - public function handle_action() { - // Parse action - $t = 'type'; - $g = 'group'; - $o = 'obj'; - $this->add_prefix_ref($t); - $this->add_prefix_ref($g); - $this->add_prefix_ref($o); - $r =& $_REQUEST; - - // Retrieve view that initiated the action - if ( isset($r[$t]) && 'view' == $r[$t] ) { - if ( isset($r[$g]) && ( $prop = $r[$g] . 's' ) && property_exists($this, $prop) && is_array($this->{$prop}) && isset($r[$o]) && isset($this->{$prop}[$r[$o]]) ) { - $view =& $this->{$prop}[$r[$o]]; - // Pass request to view - $view->do_callback(); - } - } - } - - /** - * Display notices - * Messages are localized upon display - * @uses `admin_notices` action hook to display messages - */ - public function handle_notices() { - $msgs = $this->util->apply_filters('admin_messages', array()); - foreach ( $msgs as $mid => $msg ) { - // Filter out empty messages - if ( empty($msg) ) - continue; - // Build and display message - $mid = $this->add_prefix('msg_' . $mid); - ?> -
-

- -

-
- menus as $menu ) { - // Register menu - $hook = add_menu_page($menu->get_label('title'), $menu->get_label('menu'), $menu->get_capability(), $menu->get_id(), $menu->get_callback()); - // Add hook to menu object - $menu->set_hookname($hook); - $this->menus[$menu->get_id_raw()] =& $menu; - } - - $page; - // Add subpages - foreach ( $this->pages as $page ) { - // Build Arguments - $args = array ( $page->get_label('header'), $page->get_label('menu'), $page->get_capability(), $page->get_id(), $page->get_callback() ); - $f = null; - // Handle pages for default WP menus - if ( $page->is_parent_wp() ) { - $f = 'add_' . $page->get_parent() . '_page'; - } - - // Handle pages for custom menus - if ( ! function_exists($f) ) { - array_unshift( $args, $page->get_parent() ); - $f = 'add_submenu_page'; - } - - // Add admin page - $hook = call_user_func_array($f, $args); - // Save hook to page properties - $page->set_hookname($hook); - $this->pages[$page->get_id_raw()] =& $page; - } - - // Add sections - $section; - foreach ( $this->sections as $section ) { - add_settings_section($section->get_id(), $section->get_title(), $section->get_callback(), $section->get_parent()); - } - } - - - /* Methods */ - - /** - * Add a new view - * @param string $type View type - * @param string $id Unique view ID - * @param array $args Arguments to pass to view constructor - * @return Admin_View|bool View instance (FALSE if view was not properly initialized) - */ - protected function add_view($type, $id, $args) { - // Validate request - $class = $this->add_prefix('admin_' . $type); - $collection = $type . 's'; - if ( !class_exists($class) ) { - $class = $this->add_prefix('admin_view'); - $collection = null; - } - // Create new instance - $r = new ReflectionClass($class); - $view = $r->newInstanceArgs($args); - if ( $view->is_valid() && !empty($collection) && property_exists($this, $collection) && is_array($this->{$collection}) ) - $this->{$collection}[$id] =& $view; - unset($r); - return $view; - } - - /** - * Add plugin action link - * @uses `add_view()` to init/attach action instance - * @param string $id Action ID - * @param array $labels Text for action - * > title - Link text (also title attribute value) - * > confirm - Confirmation message - * > success - Success message - * > failure - Failure message - * @param array $data Additional data for action - * @return obj Action instance - */ - public function add_action($id, $labels, $data = null) { - $args = func_get_args(); - return $this->add_view('action', $id, $args); - } - - /*-** Menus **-*/ - - /** - * Adds custom admin panel - * @param string $id Menu ID - * @param string|array $labels Text labels - * @param int $pos (optional) Menu position in navigation (index order) - * @return Admin_Menu Menu instance - */ - public function add_menu($id, $labels, $position = null) { - $args = array ( $id, $labels, null, null, null, $position ); - return $this->add_view('menu', $id, $args); - } - - /* Page */ - - /** - * Add admin page - * @uses this->pages - * @param string $id Page ID (unique) - * @param string $parent Menu ID to add page to - * @param string|array $labels Text labels (Associative array for multiple labels) - * > menu: Menu title - * > header: Page header - * @param string $capability (optional) Custom capability for accessing page - * @return Admin_Page Page instance - */ - public function add_page($id, $parent, $labels, $callback = null, $capability = null) { - $args = func_get_args(); - return $this->add_view('page', $id, $args); - } - - /* WP Pages */ - - /** - * Add admin page to a standard WP menu - * @uses this->add_page() - * @param string $id Page ID (unique) - * @param string $parent Name of WP menu to add page to - * @param string|array $labels Text labels (Associative array for multiple labels) - * > menu: Menu title - * > header: Page header - * @param string $capability (optional) Custom capability for accessing page - * @return Admin_Page Page instance - */ - public function add_wp_page($id, $parent, $labels, $callback = null, $capability = null) { - // Add page - $pg = $this->add_page($id, $parent, $labels, $capability); - // Set parent as WP - if ( $pg ) { - $pg->set_parent_wp(); - } - return $pg; - } - - /** - * Add admin page to Dashboard menu - * @see add_dashboard_page() - * @uses this->add_wp_page() - * @param string $id Page ID (unique) - * @param string|array $labels Text labels (Associative array for multiple labels) - * @param string $capability (optional) Custom capability for accessing page - * @return Admin_Page Page instance - */ - public function add_dashboard_page($id, $labels, $callback = null, $capability = null) { - return $this->add_wp_page($id, 'dashboard', $labels, $capability); - } - - /** - * Add admin page to Comments menu - * @see add_comments_page() - * @uses this->add_wp_page() - * @param string $id Page ID (unique) - * @param string|array $labels Text labels (Associative array for multiple labels) - * @param string $capability (optional) Custom capability for accessing page - * @return string Page ID - */ - public function add_comments_page($id, $labels, $callback = null, $capability = null) { - return $this->add_wp_page($id, 'comments', $labels, $capability); - } - - /** - * Add admin page to Links menu - * @see add_links_page() - * @uses this->add_wp_page() - * @param string $id Page ID (unique) - * @param string|array $labels Text labels (Associative array for multiple labels) - * @param string $capability (optional) Custom capability for accessing page - * @return string Page ID - */ - public function add_links_page($id, $labels, $callback = null, $capability = null) { - return $this->add_wp_page($id, 'links', $labels, $capability); - } - - - /** - * Add admin page to Posts menu - * @see add_posts_page() - * @uses this->add_wp_page() - * @param string $id Page ID (unique) - * @param string|array $labels Text labels (Associative array for multiple labels) - * @param string $capability (optional) Custom capability for accessing page - * @return string Page ID - */ - public function add_posts_page($id, $labels, $callback = null, $capability = null) { - return $this->add_wp_page($id, 'posts', $labels, $capability); - } - - /** - * Add admin page to Pages menu - * @see add_pages_page() - * @uses this->add_wp_page() - * @param string $id Page ID (unique) - * @param string|array $labels Text labels (Associative array for multiple labels) - * @param string $capability (optional) Custom capability for accessing page - * @return string Page ID - */ - public function add_pages_page($id, $labels, $callback = null, $capability = null) { - return $this->add_wp_page($id, 'pages', $labels, $capability); - } - - /** - * Add admin page to Media menu - * @see add_media_page() - * @uses this->add_wp_page() - * @param string $id Page ID (unique) - * @param string|array $labels Text labels (Associative array for multiple labels) - * @param string $capability (optional) Custom capability for accessing page - * @return string Page ID - */ - public function add_media_page($id, $labels, $callback = null, $capability = null) { - return $this->add_wp_page($id, 'media', $labels, $capability); - } - - /** - * Add admin page to Themes menu - * @see add_theme_page() - * @uses this->add_wp_page() - * @param string $id Page ID (unique) - * @param string|array $labels Text labels (Associative array for multiple labels) - * @param string $capability (optional) Custom capability for accessing page - * @return string Page ID - */ - public function add_theme_page($id, $labels, $callback = null, $capability = null) { - return $this->add_wp_page($id, 'theme', $labels, $capability); - } - - /** - * Add admin page to Plugins menu - * @see add_plugins_page() - * @uses this->add_wp_page() - * @param string $id Page ID (unique) - * @param string|array $labels Text labels (Associative array for multiple labels) - * @param string $capability (optional) Custom capability for accessing page - * @return string Page ID - */ - public function add_plugins_page($id, $labels, $callback = null, $capability = null) { - return $this->add_wp_page($id, 'plugins', $labels, $capability); - } - - /** - * Add admin page to Options menu - * @see add_options_page() - * @uses this->add_wp_page() - * @param string $id Page ID (unique) - * @param string|array $labels Text labels (Associative array for multiple labels) - * @param string $capability (optional) Custom capability for accessing page - * @return string Page ID - */ - public function add_options_page($id, $labels, $callback = null, $capability = null) { - return $this->add_wp_page($id, 'options', $labels, $capability); - } - - /** - * Add admin page to Tools menu - * @see add_management_page() - * @uses this->add_wp_page() - * @param string $id Page ID (unique) - * @param string|array $labels Text labels (Associative array for multiple labels) - * @param string $capability (optional) Custom capability for accessing page - * @return string Page ID - */ - public function add_management_page($id, $labels, $callback = null, $capability = null) { - return $this->add_wp_page($id, 'management', $labels, $capability); - } - - /** - * Add admin page to Users menu - * @uses this->add_wp_page() - * @param string $id Page ID (unique) - * @param string|array $labels Text labels (Associative array for multiple labels) - * @param string $capability (optional) Custom capability for accessing page - * @return string Page ID - */ - public function add_users_page($id, $labels, $callback = null, $capability = null) { - return $this->add_wp_page($id, 'users', $labels, $capability); - } - - /* Section */ - - /** - * Add section - * @uses this->sections - * @param string $id Unique section ID - * @param string $page Page ID - * @param string $labels Label text - * @return obj Section instance - */ - public function add_section($id, $parent, $labels) { - $args = func_get_args(); - $section = $this->add_view('section', $id, $args); - - // Add Section - if ( $section->is_valid() ) - $this->sections[$id] = $section; - - return $section; - } - - /* Operations */ - - /** - * Adds custom links below plugin on plugin listing page - * @uses `plugin_action_links_$plugin-name` Filter hook - * @param $actions - * @param $plugin_file - * @param $plugin_data - * @param $context - */ - public function plugin_action_links($actions, $plugin_file, $plugin_data, $context) { - global $admin_page_hooks; - // Add link to settings (only if active) - if ( is_plugin_active($this->util->get_plugin_base_name()) ) { - /* Get Actions */ - - $acts = array(); - $type = 'plugin_action'; - - /* Get view links */ - foreach ( array('menus', 'pages', 'sections') as $views ) { - foreach ( $this->{$views} as $view ) { - if ( !$view->has_label($type) ) - continue; - $acts[] = (object) array ( - 'id' => $views . '_' . $view->get_id(), - 'label' => $view->get_label($type), - 'uri' => $view->get_uri(), - 'attributes' => array() - ); - } - } - - /* Get action links */ - $type = 'title'; - foreach ( $this->actions as $a ) { - if ( !$a->has_label($type) ) - continue; - $id = 'action_' . $a->get_id(); - $acts[] = (object) array ( - 'id' => $id, - 'label' => $a->get_label($type), - 'uri' => $a->get_uri(), - 'attributes' => $a->get_link_attr() - ); - } - unset($a); - - // Add links - $links = array(); - foreach ( $acts as $act ) { - $links[$act->id] = $this->util->build_html_link($act->uri, $act->label, $act->attributes); - } - - // Add links - $actions = array_merge($links, $actions); - } - return $actions; - } - - /** - * Update plugin listings metadata - * @param array $plugin_meta Plugin metadata - * @param string $plugin_file Plugin file - * @param array $plugin_data Plugin Data - * @param string $status Plugin status - * @return array Updated plugin metadata - */ - public function plugin_row_meta($plugin_meta, $plugin_file, $plugin_data, $status) { - $u = ( is_object($this->parent) && isset($this->parent->util) ) ? $this->parent->util : $this->util; - $hook_base = 'admin_plugin_row_meta_'; - if ( $plugin_file == $u->get_plugin_base_name() ) { - // Add metadata - // Support - $l = $u->get_plugin_info('SupportURI'); - if ( !empty($l) ) { - $t = __( $this->util->apply_filters($hook_base . 'support', 'Get Support'), 'simple-lightbox'); - $plugin_meta[] = $u->build_html_link($l, $t); - } - } - return $plugin_meta; - } - - /** - * Adds additional message for plugin updates - * @uses `in_plugin_update_message-$plugin-name` Action hook - * @uses this->plugin_update_get_message() - * @var array $plugin_data Current plugin data - * @var object $r Update response data - */ - public function plugin_update_message($plugin_data, $r) { - if ( !isset($r->new_version) ) - return false; - if ( stripos($r->new_version, 'beta') !== false ) { - $cls_notice = $this->add_prefix('notice'); - echo '
' . $this->plugin_update_get_message($r); - } - } - - /** - * Modify update plugins response data if necessary - * @uses `site_transient_update_plugins` Filter hook - * @uses this->plugin_update_get_message() - * @param obj $transient Transient data - * @return obj Modified transient data - */ - public function plugin_update_transient($transient) { - $n = $this->util->get_plugin_base_name(); - if ( isset($transient->response) && isset($transient->response[$n]) && is_object($transient->response[$n]) && !isset($transient->response[$n]->upgrade_notice) ) { - $r =& $transient->response[$n]; - $r->upgrade_notice = $this->plugin_update_get_message($r); - } - return $transient; - } - - /** - * Retrieve custom update message - * @uses this->get_message() - * @param obj $r Response data from plugin update API - * @return string Message (Default: empty string) - */ - protected function plugin_update_get_message($r) { - $msg = ''; - $cls_notice = $this->add_prefix('notice'); - if ( !is_object($r) || !isset($r->new_version) ) - return $msg; - if ( stripos($r->new_version, 'beta') !== false ) { - $msg = sprintf($this->get_message('beta'), $cls_notice); - } - return $msg; - } - - /*-** Messages **-*/ - - /** - * Retrieve stored messages - * @param string $msg_id Message ID - * @return string Message text - */ - public function get_message($msg_id) { - $msg = ''; - $msgs = $this->get_messages(); - if ( is_string($msg_id) && isset($msgs[$msg_id]) ) { - $msg = $msgs[$msg_id]; - } - return $msg; - } - - /** - * Retrieve all messages - * Initializes messages if necessary - * @uses $messages - * @return array Messages - */ - function get_messages() { - if ( empty($this->messages) ) { - // Initialize messages if necessary - $this->messages = array( - 'reset' => __('The settings have been reset', 'simple-lightbox'), - 'beta' => __('Notice: This update is a Beta version. It is highly recommended that you test the update on a test server before updating the plugin on a production server.', 'simple-lightbox'), - 'access_denied' => __('Access Denied', 'simple-lightbox'), - ); - } - return $this->messages; - } - - /** - * Set message text - * @uses this->messages - * @param string $id Message ID - * @param string $text Message text - */ - public function set_message($id, $text) { - $this->messages[trim($id)] = $text; - } -} \ No newline at end of file + 'The settings have been reset', + 'beta' => 'Notice: This update is a Beta version. It is highly recommended that you test the update on a test server before updating the plugin on a production server.', + 'access_denied' => 'You do not have sufficient permissions', + ); + + /* Views */ + + /** + * Custom admin top-level menus + * Associative Array + * > Key: Menu ID + * > Val: Menu properties + * @var array + */ + protected $menus = array(); + + /** + * Custom admin pages + * Associative Array + * > Key: Page ID + * > Val: Page properties + * @var array + */ + protected $pages = array(); + + /** + * Custom admin sections + * Associative Array + * > Key: Section ID + * > Val: Section properties + * @var array + */ + protected $sections = array(); + + /** + * Actions + * Index Array + * @var array + */ + protected $actions = array(); + + /* Constructor */ + + public function __construct( &$parent ) { + parent::__construct(); + // Set parent + if ( is_object( $parent ) ) { + $this->parent = $parent; + } + } + + /* Init */ + + protected function _hooks() { + parent::_hooks(); + // Init + add_action( 'admin_menu', $this->m( 'init_menus' ), 11 ); + + // Plugin actions + add_action( 'admin_action_' . $this->add_prefix( 'admin' ), $this->m( 'handle_action' ) ); + + // Notices + add_action( 'admin_notices', $this->m( 'handle_notices' ) ); + + // Plugin listing + add_filter( 'plugin_action_links_' . $this->util->get_plugin_base_name(), $this->m( 'plugin_action_links' ), 10, 4 ); + add_filter( 'plugin_row_meta', $this->m( 'plugin_row_meta' ), 10, 4 ); + add_action( 'in_plugin_update_message-' . $this->util->get_plugin_base_name(), $this->m( 'plugin_update_message' ), 10, 2 ); + add_filter( 'site_transient_update_plugins', $this->m( 'plugin_update_transient' ) ); + } + + /** + * Declare client files (scripts, styles) + * @uses parent::_client_files() + * @return void + */ + protected function _client_files( $files = null ) { + $js_path = 'client/js/'; + $js_path .= ( SLB_DEV ) ? 'dev' : 'prod'; + $pfx = $this->get_prefix(); + $files = array( + 'scripts' => array( + 'admin' => array( + 'file' => "$js_path/lib.admin.js", + 'deps' => array( '[core]' ), + 'context' => array( "admin_page_$pfx" ), + 'in_footer' => true, + ), + ), + 'styles' => array( + 'admin' => array( + 'file' => 'client/css/admin.css', + 'context' => array( "admin_page_$pfx", 'admin_page_plugins' ), + ), + ), + ); + parent::_client_files( $files ); + } + + /* Handlers */ + + /** + * Handles routing of internal action to appropriate handler. + * + * @return void + */ + public function handle_action() { + // Parse action + $t = 'type'; + $g = 'group'; + $o = 'obj'; + $this->add_prefix_ref( $t ); + $this->add_prefix_ref( $g ); + $this->add_prefix_ref( $o ); + $r =& $_REQUEST; + + // Confirm request contains necessary parameters. + if ( + ! isset( $r[ $t ], $r[ $g ], $r[ $o ] ) + || 'view' !== $r[ $t ] + ) { + return; + } + // Confirm specified view instance exists. + $prop = $r[ $g ] . 's'; + if ( + ! property_exists( $this, $prop ) + || ! is_array( $this->{$prop} ) + || ! isset( $this->{$prop}[ $r[ $o ] ] ) + ) { + return; + } + // Get view instance. + $view =& $this->{$prop}[ $r[ $o ] ]; + // Pass request to view instance. + if ( $view instanceof SLB_Admin_View ) { + $view->do_callback(); + } + } + + /** + * Display notices + * Messages are localized upon display + * @uses `admin_notices` action hook to display messages + */ + public function handle_notices() { + $msgs = $this->util->apply_filters( 'admin_messages', array() ); + foreach ( $msgs as $mid => $msg ) { + // Filter out empty messages + if ( empty( $msg ) ) { + continue; + } + // Build and display message + $mid = $this->add_prefix( 'msg_' . $mid ); + ?> +
+

+ +

+
+ menus as $menu ) { + // Register menu + $hook = add_menu_page( $menu->get_label( 'title' ), $menu->get_label( 'menu' ), $menu->get_capability(), $menu->get_id(), $menu->get_callback() ); + // Add hook to menu object + $menu->set_hookname( $hook ); + $this->menus[ $menu->get_id_raw() ] =& $menu; + } + + $page; + // Add subpages + foreach ( $this->pages as $page ) { + // Build Arguments + $args = array( $page->get_label( 'header' ), $page->get_label( 'menu' ), $page->get_capability(), $page->get_id(), $page->get_callback() ); + $f = null; + // Handle pages for default WP menus + if ( $page->is_parent_wp() ) { + $f = 'add_' . $page->get_parent() . '_page'; + } + + // Handle pages for custom menus + if ( ! function_exists( $f ) ) { + array_unshift( $args, $page->get_parent() ); + $f = 'add_submenu_page'; + } + + // Add admin page + $hook = call_user_func_array( $f, $args ); + // Save hook to page properties + $page->set_hookname( $hook ); + $this->pages[ $page->get_id_raw() ] =& $page; + } + + // Add sections + $section; + foreach ( $this->sections as $section ) { + add_settings_section( $section->get_id(), $section->get_title(), $section->get_callback(), $section->get_parent() ); + } + } + + + /* Methods */ + + /** + * Add a new view + * @param string $type View type + * @param string $id Unique view ID + * @param array $args Arguments to pass to view constructor + * @return Admin_View|bool View instance (FALSE if view was not properly initialized) + */ + protected function add_view( $type, $id, $args ) { + // Validate request + $class = $this->add_prefix( 'admin_' . $type ); + $collection = $type . 's'; + if ( ! class_exists( $class ) ) { + $class = $this->add_prefix( 'admin_view' ); + $collection = null; + } + // Create new instance + $r = new ReflectionClass( $class ); + $view = $r->newInstanceArgs( $args ); + if ( $view->is_valid() && ! empty( $collection ) && property_exists( $this, $collection ) && is_array( $this->{$collection} ) ) { + $this->{$collection}[ $id ] =& $view; + } + unset( $r ); + return $view; + } + + /** + * Add plugin action link + * @uses `add_view()` to init/attach action instance + * @param string $id Action ID + * @param array $labels Text for action + * > title - Link text (also title attribute value) + * > confirm - Confirmation message + * > success - Success message + * > failure - Failure message + * @param array $data Additional data for action + * @return obj Action instance + */ + public function add_action( $id, $labels, $data = null ) { + $args = func_get_args(); + return $this->add_view( 'action', $id, $args ); + } + + /*-** Menus **-*/ + + /** + * Adds custom admin panel + * @param string $id Menu ID + * @param string|array $labels Text labels + * @param int $pos (optional) Menu position in navigation (index order) + * @return Admin_Menu Menu instance + */ + public function add_menu( $id, $labels, $position = null ) { + $args = array( $id, $labels, null, null, null, $position ); + return $this->add_view( 'menu', $id, $args ); + } + + /* Page */ + + /** + * Add admin page + * @uses this->pages + * @param string $id Page ID (unique) + * @param string $parent Menu ID to add page to + * @param string|array $labels Text labels (Associative array for multiple labels) + * > menu: Menu title + * > header: Page header + * @param string $capability (optional) Custom capability for accessing page + * @return Admin_Page Page instance + */ + public function add_page( $id, $parent, $labels, $callback = null, $capability = null ) { + $args = func_get_args(); + return $this->add_view( 'page', $id, $args ); + } + + /* WP Pages */ + + /** + * Add admin page to a standard WP menu + * @uses this->add_page() + * @param string $id Page ID (unique) + * @param string $parent Name of WP menu to add page to + * @param string|array $labels Text labels (Associative array for multiple labels) + * > menu: Menu title + * > header: Page header + * @param string $capability (optional) Custom capability for accessing page + * @return Admin_Page Page instance + */ + public function add_wp_page( $id, $parent, $labels, $callback = null, $capability = null ) { + // Add page + $pg = $this->add_page( $id, $parent, $labels, $capability ); + // Set parent as WP + if ( $pg ) { + $pg->set_parent_wp(); + } + return $pg; + } + + /** + * Add admin page to Dashboard menu + * @see add_dashboard_page() + * @uses this->add_wp_page() + * @param string $id Page ID (unique) + * @param string|array $labels Text labels (Associative array for multiple labels) + * @param string $capability (optional) Custom capability for accessing page + * @return Admin_Page Page instance + */ + public function add_dashboard_page( $id, $labels, $callback = null, $capability = null ) { + return $this->add_wp_page( $id, 'dashboard', $labels, $capability ); + } + + /** + * Add admin page to Comments menu + * @see add_comments_page() + * @uses this->add_wp_page() + * @param string $id Page ID (unique) + * @param string|array $labels Text labels (Associative array for multiple labels) + * @param string $capability (optional) Custom capability for accessing page + * @return string Page ID + */ + public function add_comments_page( $id, $labels, $callback = null, $capability = null ) { + return $this->add_wp_page( $id, 'comments', $labels, $capability ); + } + + /** + * Add admin page to Links menu + * @see add_links_page() + * @uses this->add_wp_page() + * @param string $id Page ID (unique) + * @param string|array $labels Text labels (Associative array for multiple labels) + * @param string $capability (optional) Custom capability for accessing page + * @return string Page ID + */ + public function add_links_page( $id, $labels, $callback = null, $capability = null ) { + return $this->add_wp_page( $id, 'links', $labels, $capability ); + } + + + /** + * Add admin page to Posts menu + * @see add_posts_page() + * @uses this->add_wp_page() + * @param string $id Page ID (unique) + * @param string|array $labels Text labels (Associative array for multiple labels) + * @param string $capability (optional) Custom capability for accessing page + * @return string Page ID + */ + public function add_posts_page( $id, $labels, $callback = null, $capability = null ) { + return $this->add_wp_page( $id, 'posts', $labels, $capability ); + } + + /** + * Add admin page to Pages menu + * @see add_pages_page() + * @uses this->add_wp_page() + * @param string $id Page ID (unique) + * @param string|array $labels Text labels (Associative array for multiple labels) + * @param string $capability (optional) Custom capability for accessing page + * @return string Page ID + */ + public function add_pages_page( $id, $labels, $callback = null, $capability = null ) { + return $this->add_wp_page( $id, 'pages', $labels, $capability ); + } + + /** + * Add admin page to Media menu + * @see add_media_page() + * @uses this->add_wp_page() + * @param string $id Page ID (unique) + * @param string|array $labels Text labels (Associative array for multiple labels) + * @param string $capability (optional) Custom capability for accessing page + * @return string Page ID + */ + public function add_media_page( $id, $labels, $callback = null, $capability = null ) { + return $this->add_wp_page( $id, 'media', $labels, $capability ); + } + + /** + * Add admin page to Themes menu + * @see add_theme_page() + * @uses this->add_wp_page() + * @param string $id Page ID (unique) + * @param string|array $labels Text labels (Associative array for multiple labels) + * @param string $capability (optional) Custom capability for accessing page + * @return string Page ID + */ + public function add_theme_page( $id, $labels, $callback = null, $capability = null ) { + return $this->add_wp_page( $id, 'theme', $labels, $capability ); + } + + /** + * Add admin page to Plugins menu + * @see add_plugins_page() + * @uses this->add_wp_page() + * @param string $id Page ID (unique) + * @param string|array $labels Text labels (Associative array for multiple labels) + * @param string $capability (optional) Custom capability for accessing page + * @return string Page ID + */ + public function add_plugins_page( $id, $labels, $callback = null, $capability = null ) { + return $this->add_wp_page( $id, 'plugins', $labels, $capability ); + } + + /** + * Add admin page to Options menu + * @see add_options_page() + * @uses this->add_wp_page() + * @param string $id Page ID (unique) + * @param string|array $labels Text labels (Associative array for multiple labels) + * @param string $capability (optional) Custom capability for accessing page + * @return string Page ID + */ + public function add_options_page( $id, $labels, $callback = null, $capability = null ) { + return $this->add_wp_page( $id, 'options', $labels, $capability ); + } + + /** + * Add admin page to Tools menu + * @see add_management_page() + * @uses this->add_wp_page() + * @param string $id Page ID (unique) + * @param string|array $labels Text labels (Associative array for multiple labels) + * @param string $capability (optional) Custom capability for accessing page + * @return string Page ID + */ + public function add_management_page( $id, $labels, $callback = null, $capability = null ) { + return $this->add_wp_page( $id, 'management', $labels, $capability ); + } + + /** + * Add admin page to Users menu + * @uses this->add_wp_page() + * @param string $id Page ID (unique) + * @param string|array $labels Text labels (Associative array for multiple labels) + * @param string $capability (optional) Custom capability for accessing page + * @return string Page ID + */ + public function add_users_page( $id, $labels, $callback = null, $capability = null ) { + return $this->add_wp_page( $id, 'users', $labels, $capability ); + } + + /* Section */ + + /** + * Add section + * @uses this->sections + * @param string $id Unique section ID + * @param string $page Page ID + * @param string $labels Label text + * @return obj Section instance + */ + public function add_section( $id, $parent, $labels ) { + $args = func_get_args(); + $section = $this->add_view( 'section', $id, $args ); + + // Add Section + if ( $section->is_valid() ) { + $this->sections[ $id ] = $section; + } + + return $section; + } + + /* Operations */ + + /** + * Adds custom links below plugin on plugin listing page + * @uses `plugin_action_links_$plugin-name` Filter hook + * @param $actions + * @param $plugin_file + * @param $plugin_data + * @param $context + */ + public function plugin_action_links( $actions, $plugin_file, $plugin_data, $context ) { + global $admin_page_hooks; + // Add link to settings (only if active) + if ( is_plugin_active( $this->util->get_plugin_base_name() ) ) { + /* Get Actions */ + + $acts = array(); + $type = 'plugin_action'; + + /* Get view links */ + foreach ( array( 'menus', 'pages', 'sections' ) as $views ) { + foreach ( $this->{$views} as $view ) { + if ( ! $view->has_label( $type ) ) { + continue; + } + $acts[] = (object) array( + 'id' => $views . '_' . $view->get_id(), + 'label' => $view->get_label( $type ), + 'uri' => $view->get_uri(), + 'attributes' => array(), + ); + } + } + + /* Get action links */ + $type = 'title'; + foreach ( $this->actions as $a ) { + if ( ! $a->has_label( $type ) ) { + continue; + } + $id = 'action_' . $a->get_id(); + $acts[] = (object) array( + 'id' => $id, + 'label' => $a->get_label( $type ), + 'uri' => $a->get_uri(), + 'attributes' => $a->get_link_attr(), + ); + } + unset( $a ); + + // Add links + $links = array(); + foreach ( $acts as $act ) { + $links[ $act->id ] = $this->util->build_html_link( $act->uri, $act->label, $act->attributes ); + } + + // Add links + $actions = array_merge( $links, $actions ); + } + return $actions; + } + + /** + * Update plugin listings metadata + * @param array $plugin_meta Plugin metadata + * @param string $plugin_file Plugin file + * @param array $plugin_data Plugin Data + * @param string $status Plugin status + * @return array Updated plugin metadata + */ + public function plugin_row_meta( $plugin_meta, $plugin_file, $plugin_data, $status ) { + $u = ( is_object( $this->parent ) && isset( $this->parent->util ) ) ? $this->parent->util : $this->util; + $hook_base = 'admin_plugin_row_meta_'; + if ( $plugin_file === $u->get_plugin_base_name() ) { + // Add metadata + // Support + $l = $u->get_plugin_info( 'SupportURI' ); + if ( ! empty( $l ) ) { + $t = __( 'Feedback & Support', 'simple-lightbox' ); + $plugin_meta[] = $u->build_html_link( $l, $t ); + } + } + return $plugin_meta; + } + + /** + * Adds additional message for plugin updates + * @uses `in_plugin_update_message-$plugin-name` Action hook + * @uses this->plugin_update_get_message() + * @var array $plugin_data Current plugin data + * @var object $r Update response data + */ + public function plugin_update_message( $plugin_data, $r ) { + if ( ! isset( $r->new_version ) ) { + return false; + } + if ( stripos( $r->new_version, 'beta' ) !== false ) { + $cls_notice = $this->add_prefix( 'notice' ); + echo '
' . $this->plugin_update_get_message( $r ); + } + } + + /** + * Modify update plugins response data if necessary + * @uses `site_transient_update_plugins` Filter hook + * @uses this->plugin_update_get_message() + * @param obj $transient Transient data + * @return obj Modified transient data + */ + public function plugin_update_transient( $transient ) { + $n = $this->util->get_plugin_base_name(); + if ( isset( $transient->response ) && isset( $transient->response[ $n ] ) && is_object( $transient->response[ $n ] ) && ! isset( $transient->response[ $n ]->upgrade_notice ) ) { + $r =& $transient->response[ $n ]; + $r->upgrade_notice = $this->plugin_update_get_message( $r ); + } + return $transient; + } + + /** + * Retrieve custom update message + * @uses this->get_message() + * @param obj $r Response data from plugin update API + * @return string Message (Default: empty string) + */ + protected function plugin_update_get_message( $r ) { + $msg = ''; + $cls_notice = $this->add_prefix( 'notice' ); + if ( ! is_object( $r ) || ! isset( $r->new_version ) ) { + return $msg; + } + if ( stripos( $r->new_version, 'beta' ) !== false ) { + $msg = sprintf( $this->get_message( 'beta' ), $cls_notice ); + } + return $msg; + } + + /*-** Messages **-*/ + + /** + * Retrieve stored messages + * @param string $msg_id Message ID + * @return string Message text + */ + public function get_message( $msg_id ) { + $msg = ''; + $msgs = $this->get_messages(); + if ( is_string( $msg_id ) && isset( $msgs[ $msg_id ] ) ) { + $msg = $msgs[ $msg_id ]; + } + return $msg; + } + + /** + * Retrieve all messages + * Initializes messages if necessary + * @uses $messages + * @return array Messages + */ + function get_messages() { + if ( empty( $this->messages ) ) { + // Initialize messages if necessary + $this->messages = array( + 'reset' => __( 'The settings have been reset', 'simple-lightbox' ), + /* translators: 1: Notice CSS class */ + 'beta' => __( 'Notice: This update is a Beta version. It is highly recommended that you test the update on a test server before updating the plugin on a production server.', 'simple-lightbox' ), + 'access_denied' => __( 'Access Denied', 'simple-lightbox' ), + ); + } + return $this->messages; + } + + /** + * Set message text + * @uses this->messages + * @param string $id Message ID + * @param string $text Message text + */ + public function set_message( $id, $text ) { + $this->messages[ trim( $id ) ] = $text; + } +} diff --git a/includes/class.admin_action.php b/includes/class.admin_action.php index 88d700f..dd5ccba 100644 --- a/includes/class.admin_action.php +++ b/includes/class.admin_action.php @@ -23,11 +23,11 @@ class SLB_Admin_Action extends SLB_Admin_View { * @param obj $data Action data * @return obj Current instance */ - function __construct($id, $labels, $data = null) { - parent::__construct($id, $labels); + function __construct( $id, $labels, $data = null ) { + parent::__construct( $id, $labels ); // Default options instance - if ( !empty($data) ) { - $this->add_content('data', $data); + if ( ! empty( $data ) ) { + $this->add_content( 'data', $data ); } return $this; } @@ -41,8 +41,9 @@ function __construct($id, $labels, $data = null) { */ public function handle() { // Validate user - if ( ! current_user_can('activate_plugins') || ! check_admin_referer($this->get_id()) ) - wp_die(__('Access Denied', 'simple-lightbox')); + if ( ! current_user_can( 'activate_plugins' ) || ! check_admin_referer( $this->get_id() ) ) { + wp_die( __( 'Access Denied', 'simple-lightbox' ) ); + } // Get data $content = $this->get_content(); @@ -50,51 +51,51 @@ public function handle() { $success = true; // Iterate through data - $hook = $this->util->get_hook($this->get_id_raw()); + $hook = $this->util->get_hook( $this->get_id_raw() ); foreach ( $content as $c ) { // Trigger action - $res = apply_filters($hook, $success, $c->data, $this); + $res = apply_filters( $hook, $success, $c->data, $this ); // Set result - if ( !!$success ) { + if ( ! ! $success ) { $success = $res; } } // Set Status Message $lbl = ( $success ) ? 'success' : 'failure'; - $this->set_message($this->get_label($lbl)); + $this->set_message( $this->get_label( $lbl ) ); } /** * Get URI * @see Admin_View::get_uri() */ - public function get_uri($file = null, $format = null) { - return wp_nonce_url(add_query_arg($this->get_query_args(), remove_query_arg($this->get_query_args_remove(), $_SERVER['REQUEST_URI'])), $this->get_id()); + public function get_uri( $file = null, $format = null ) { + return wp_nonce_url( add_query_arg( $this->get_query_args(), remove_query_arg( $this->get_query_args_remove(), $_SERVER['REQUEST_URI'] ) ), $this->get_id() ); } protected function get_query_args() { - return array ( - 'action' => $this->add_prefix('admin'), - $this->add_prefix('type') => 'view', - $this->add_prefix('group') => 'action', - $this->add_prefix('obj') => $this->get_id_raw() + return array( + 'action' => $this->add_prefix( 'admin' ), + $this->add_prefix( 'type' ) => 'view', + $this->add_prefix( 'group' ) => 'action', + $this->add_prefix( 'obj' ) => $this->get_id_raw(), ); } protected function get_query_args_remove() { - $args_r = array ( + $args_r = array( '_wpnonce', - $this->add_prefix('action') + $this->add_prefix( 'action' ), ); return array_unique( array_merge( array_keys( $this->get_query_args() ), $args_r ) ); } public function get_link_attr() { - return array ( - 'class' => $this->util->get_hook($this->get_id_raw()), - 'onclick' => "return confirm('" . esc_js( $this->get_label('confirm') ) . "')" + return array( + 'class' => $this->util->get_hook( $this->get_id_raw() ), + 'onclick' => "return confirm('" . esc_js( $this->get_label( 'confirm' ) ) . "')", ); } @@ -103,7 +104,7 @@ public function get_link_attr() { /** * Save options */ - public function add_content($id, $data) { - return parent::add_content($id, array('data' => $data)); + public function add_content( $id, $data ) { + return parent::add_content( $id, array( 'data' => $data ) ); } -} \ No newline at end of file +} diff --git a/includes/class.admin_menu.php b/includes/class.admin_menu.php index c181300..2a8a012 100644 --- a/includes/class.admin_menu.php +++ b/includes/class.admin_menu.php @@ -18,11 +18,11 @@ class SLB_Admin_Menu extends SLB_Admin_View { /* Init */ - public function __construct($id, $labels, $callback = null, $capability = null, $icon = null, $position = null) { + public function __construct( $id, $labels, $callback = null, $capability = null, $icon = null, $position = null ) { // Default - parent::__construct($id, $labels, $callback, $capability, $icon); + parent::__construct( $id, $labels, $callback, $capability, $icon ); // Class specific - $this->set_position($position); + $this->set_position( $position ); return $this; } @@ -32,9 +32,10 @@ public function __construct($id, $labels, $callback = null, $capability = null, * Set menu position * @return obj Current instance */ - public function set_position($position) { - if ( is_int($position) ) + public function set_position( $position ) { + if ( is_int( $position ) ) { $this->position = $position; + } return $this; } -} \ No newline at end of file +} diff --git a/includes/class.admin_page.php b/includes/class.admin_page.php index 35fcde8..adfeab8 100644 --- a/includes/class.admin_page.php +++ b/includes/class.admin_page.php @@ -21,11 +21,11 @@ class SLB_Admin_Page extends SLB_Admin_View { /* Init */ - public function __construct($id, $parent, $labels, $callback = null, $capability = null) { + public function __construct( $id, $parent, $labels, $callback = null, $capability = null ) { // Default - parent::__construct($id, $labels, $callback, $capability); + parent::__construct( $id, $labels, $callback, $capability ); // Class specific - $this->set_parent($parent); + $this->set_parent( $parent ); return $this; } @@ -42,16 +42,16 @@ public function __construct($id, $parent, $labels, $callback = null, $capability * @param array $callback_args (optional) Additional data to pass callback (Default: NULL) * @return object Page instance reference */ - public function add_content($id, $title, $callback = null, $context = 'primary', $priority = 'default', $callback_args = null) { - return parent::add_content($id, array( - 'id' => $id, - 'title' => $title, - 'callback' => $callback, - 'context' => $context, - 'priority' => $priority, - 'callback_args' => $callback_args - ) - ); + public function add_content( $id, $title, $callback = null, $context = 'primary', $priority = 'default', $callback_args = null ) { + $opts = [ + 'id' => $id, + 'title' => $title, + 'callback' => $callback, + 'context' => $context, + 'priority' => $priority, + 'callback_args' => $callback_args, + ]; + return parent::add_content( $id, $opts ); } /** @@ -60,16 +60,16 @@ public function add_content($id, $title, $callback = null, $context = 'primary', */ protected function parse_content() { // Get raw content - $raw = $this->get_content(false); + $raw = $this->get_content( false ); // Group by context $content = array(); foreach ( $raw as $c ) { // Add new context - if ( !isset($content[$c->context]) ) { - $content[$c->context] = array(); + if ( ! isset( $content[ $c->context ] ) ) { + $content[ $c->context ] = array(); } // Add item to context - $content[$c->context][] = $c; + $content[ $c->context ][] = $c; } return $content; } @@ -78,34 +78,34 @@ protected function parse_content() { * Render content blocks * @param string $context (optional) Context to render */ - protected function render_content($context = 'primary') { + protected function render_content( $context = 'primary' ) { // Get content $content = $this->get_content(); // Check for context - if ( !isset($content[$context]) ) { + if ( ! isset( $content[ $context ] ) ) { return false; } - $content = $content[$context]; - $out = ''; + $content = $content[ $context ]; + $out = ''; // Render content ?>
screen = $screen; - // Callback - if ( is_callable($c->callback) ) { - $callback = $c->callback; - add_meta_box($c->id, $c->title, $c->callback, $c->screen, $c->context, $c->priority, $c->callback_args); - } else { - // Let handlers build output - $this->util->do_action('render_content', $c->callback, $this, $c); - } + foreach ( $content as $c ) { + $c->screen = $screen; + // Callback + if ( is_callable( $c->callback ) ) { + $callback = $c->callback; + add_meta_box( $c->id, $c->title, $c->callback, $c->screen, $c->context, $c->priority, $c->callback_args ); + } else { + // Let handlers build output + $this->util->do_action( 'render_content', $c->callback, $this, $c ); } + } // Output meta boxes - do_meta_boxes($screen, $context, null); + do_meta_boxes( $screen, $context, null ); ?>
_require('form_submit'); + $this->_require( 'form_submit' ); return $this; } @@ -125,7 +125,7 @@ public function require_form() { * @return bool TRUE if form submission required */ private function is_required_form() { - return $this->_is_required('form_submit'); + return $this->_is_required( 'form_submit' ); } /* Handlers */ @@ -138,50 +138,51 @@ private function is_required_form() { * @uses wp_die() to end execution when user does not have permission to access page */ public function handle() { - if ( !current_user_can($this->get_capability()) ) - wp_die(__('Access Denied', 'simple-lightbox')); - wp_enqueue_script('postbox'); + if ( ! current_user_can( $this->get_capability() ) ) { + wp_die( __( 'Access Denied', 'simple-lightbox' ) ); + } + wp_enqueue_script( 'postbox' ); ?>
-

get_label('header') ); ?>

+

get_label( 'header' ) ); ?>

is_required_form() ) { - // Build form output - $form_id = $this->add_prefix('admin_form_' . $this->get_id_raw()); - $nonce = (object) [ - 'action' => $this->get_id(), - 'name' => $this->get_id() . '_nonce', - ]; - ?> -
+ if ( $this->is_required_form() ) { + // Build form output + $form_id = $this->add_prefix( 'admin_form_' . $this->get_id_raw() ); + $nonce = (object) [ + 'action' => $this->get_id(), + 'name' => $this->get_id() . '_nonce', + ]; + ?> + action, $nonce->name ); - } + wp_nonce_field( $nonce->action, $nonce->name ); + } ?>
render_content('primary'); + $this->render_content( 'primary' ); ?>
render_content('secondary'); + $this->render_content( 'secondary' ); ?>

is_required_form() ) { - submit_button(); - ?> + if ( $this->is_required_form() ) { + submit_button(); + ?>
-
set_parent($parent); + $this->set_parent( $parent ); return $this; } @@ -32,12 +32,14 @@ public function __construct($id, $parent, $labels, $callback = null, $capability * @param string $format (optional) String format * @return string Section URI */ - public function get_uri($file = null, $format = null) { - if ( !is_string($file) ) + public function get_uri( $file = null, $format = null ) { + if ( ! is_string( $file ) ) { $file = 'options-' . $this->get_parent() . '.php'; - if ( !is_string($format) ) + } + if ( ! is_string( $format ) ) { $format = '%1$s#%2$s'; - return parent::get_uri($file, $format); + } + return parent::get_uri( $file, $format ); } /** @@ -46,6 +48,6 @@ public function get_uri($file = null, $format = null) { * @return string Title */ public function get_title() { - return sprintf('
%3$s
', $this->get_id(), $this->add_prefix('section_head'), $this->get_label('title')); + return sprintf( '
%3$s
', $this->get_id(), $this->add_prefix( 'section_head' ), $this->get_label( 'title' ) ); } -} \ No newline at end of file +} diff --git a/includes/class.admin_view.php b/includes/class.admin_view.php index 31ceb19..d13a96d 100644 --- a/includes/class.admin_view.php +++ b/includes/class.admin_view.php @@ -94,7 +94,10 @@ class SLB_Admin_View extends SLB_Base_Object { * @see this->required for more information * @var array */ - private $_required = array ( 'id' => 'string', 'labels' => 'array' ); + private $_required = array( + 'id' => 'string', + 'labels' => 'array', + ); /* Init */ @@ -102,32 +105,33 @@ class SLB_Admin_View extends SLB_Base_Object { * Constructor * @return obj Current instance */ - public function __construct($id, $labels, $callback = null, $capability = null, $icon = null) { + public function __construct( $id, $labels, $callback = null, $capability = null, $icon = null ) { $props = array( - 'labels' => $labels, - 'callback' => $callback, - 'capability' => $capability, - 'icon' => $icon, + 'labels' => $labels, + 'callback' => $callback, + 'capability' => $capability, + 'icon' => $icon, ); - parent::__construct($id, $props); + parent::__construct( $id, $props ); $this->init_required(); return $this; } protected function init_required() { - $this->required = array_merge($this->_required, $this->required); + $this->required = array_merge( $this->_required, $this->required ); // Check for parent requirement - if ( $this->parent_required ) + if ( $this->parent_required ) { $this->required['parent'] = 'string'; + } } /** * Set required feature * @param string $feature Required feature */ - protected function _require($feature) { - if ( !isset($this->_required[$feature]) ) { - $this->_required[$feature] = true; + protected function _require( $feature ) { + if ( ! isset( $this->_required[ $feature ] ) ) { + $this->_required[ $feature ] = true; } return $this; } @@ -137,8 +141,8 @@ protected function _require($feature) { * @param string $feature Feature to check for * @return bool TRUE if feature required */ - protected function _is_required($feature) { - return ( isset($this->_required[$feature]) ) ? true : false; + protected function _is_required( $feature ) { + return ( isset( $this->_required[ $feature ] ) ) ? true : false; } /* Property Methods */ @@ -148,10 +152,11 @@ protected function _is_required($feature) { * @param bool $formatted (optional) Whether ID should be formatted for external use or not * @return string ID */ - public function get_id($formatted = true) { + public function get_id( $formatted = true ) { $id = parent::get_id(); - if ( $formatted ) - $this->add_prefix_ref($id); + if ( $formatted ) { + $this->add_prefix_ref( $id ); + } return $id; } @@ -160,7 +165,7 @@ public function get_id($formatted = true) { * @return string Raw ID */ public function get_id_raw() { - return $this->get_id(false); + return $this->get_id( false ); } /** @@ -170,17 +175,18 @@ public function get_id_raw() { * @param string $default (optional) Default value if label type does not exist * @return string Label text */ - public function get_label($type, $default = null) { + public function get_label( $type, $default = null ) { // Retrieve existing label type - if ( $this->has_label($type) ) - return $this->labels[$type]; + if ( $this->has_label( $type ) ) { + return $this->labels[ $type ]; + } // Use default label if type is not set - if ( empty($default) && !empty($this->labels) ) { - reset($this->labels); - $default = current($this->labels); + if ( empty( $default ) && ! empty( $this->labels ) ) { + reset( $this->labels ); + $default = current( $this->labels ); } - return ( empty($default) ) ? '' : $default; + return ( empty( $default ) ) ? '' : $default; } /** @@ -188,21 +194,22 @@ public function get_label($type, $default = null) { * @param array|string $labels * @return obj Current instance */ - public function set_labels($labels) { - if ( empty($labels) ) + public function set_labels( $labels ) { + if ( empty( $labels ) ) { return this; + } // Single string - if ( is_string($labels) ) { - $labels = array ( $labels ); + if ( is_string( $labels ) ) { + $labels = array( $labels ); } // Array - if ( is_array($labels) ) { + if ( is_array( $labels ) ) { // Merge with existing labels - if ( empty($this->labels) || !is_array($this->labels) ) { + if ( empty( $this->labels ) || ! is_array( $this->labels ) ) { $this->labels = array(); } - $this->labels = array_merge($this->labels, $labels); + $this->labels = array_merge( $this->labels, $labels ); } return $this; } @@ -214,10 +221,10 @@ public function set_labels($labels) { * @param string $value Label value * @return obj Current instance */ - public function set_label($type, $value) { - if ( is_string($type) && is_string($value) ) { + public function set_label( $type, $value ) { + if ( is_string( $type ) && is_string( $value ) ) { $label = array( $type => $value ); - $this->set_labels($label); + $this->set_labels( $label ); } return $this; } @@ -227,8 +234,8 @@ public function set_label($type, $value) { * @param string $type Label type * @return bool TRUE if label exists, FALSE otherwise */ - public function has_label($type) { - return ( isset($this->labels[$type]) ); + public function has_label( $type ) { + return ( isset( $this->labels[ $type ] ) ); } /* Content */ @@ -240,9 +247,9 @@ public function has_label($type) { * @param array $args Content arguments (Defined by child class), converted to an object * @return obj Current View instance */ - public function add_content($id, $args) { + public function add_content( $id, $args ) { // Save parameters - $this->content_raw[$id] = (object) $args; + $this->content_raw[ $id ] = (object) $args; // Clear parsed content $this->content = array(); // Return instance reference @@ -252,19 +259,18 @@ public function add_content($id, $args) { /** * Retrieve content */ - protected function get_content($parsed = true) { - $content = $this->content_raw; - if ( $parsed ) { - // Return previously parsed content - if ( !empty($this->content) ) { - $content = $this->content; - } - elseif ( !empty($this->content_raw) ) { - // Parse content before returning - $content = $this->content = $this->parse_content(); - } + protected function get_content( $parsed = true ) { + // Return raw content. + if ( ! $parsed ) { + return $this->content_raw; + } + + // Return parsed content. + if ( empty( $this->content ) && ! empty( $this->content_raw ) ) { + $this->content = $this->parse_content(); } - return $content; + + return $this->content; } /** @@ -273,7 +279,7 @@ protected function get_content($parsed = true) { * @return array Parsed content */ protected function parse_content() { - return $this->get_content(false); + return $this->get_content( false ); } /** @@ -281,22 +287,23 @@ protected function parse_content() { * @return bool TRUE if content added */ protected function has_content() { - $raw = $this->get_content(false); - return !empty($raw); + $raw = $this->get_content( false ); + return ! empty( $raw ); } /** * Render content */ - protected function render_content($context = 'default') {} + protected function render_content( $context = 'default' ) {} /** * Retrieve view messages * @return array Messages */ protected function &get_messages() { - if ( !is_array($this->messages) ) + if ( ! is_array( $this->messages ) ) { $this->messages = array(); + } return $this->messages; } @@ -305,11 +312,12 @@ protected function &get_messages() { * @param string $text Message text * @return obj Current instance */ - public function set_message($text) { + public function set_message( $text ) { $msgs =& $this->get_messages(); - $text = trim($text); - if ( empty($msgs) && !empty($text) ) - $this->util->add_filter('admin_messages', $this->m('do_messages'), 10, 1, false); + $text = trim( $text ); + if ( empty( $msgs ) && ! empty( $text ) ) { + $this->util->add_filter( 'admin_messages', $this->m( 'do_messages' ), 10, 1, false ); + } $msgs[] = $text; return $this; } @@ -320,10 +328,11 @@ public function set_message($text) { * @param array $msgs Aggregated messages * @return array Merged messages array */ - public function do_messages($msgs = array()) { + public function do_messages( $msgs = array() ) { $m =& $this->get_messages(); - if ( !empty($m) ) - $msgs = array_merge($msgs, $m); + if ( ! empty( $m ) ) { + $msgs = array_merge( $msgs, $m ); + } return $msgs; } @@ -332,7 +341,7 @@ public function do_messages($msgs = array()) { * @return callback Callback (Default: standard handler method) */ public function get_callback() { - return ( $this->has_callback() ) ? $this->callback : $this->m('handle'); + return ( $this->has_callback() ) ? $this->callback : $this->m( 'handle' ); } /** @@ -340,8 +349,8 @@ public function get_callback() { * @param callback $callback Callback function to use * @return obj Current instance */ - public function set_callback($callback) { - $this->callback = ( is_callable($callback) ) ? $callback : null; + public function set_callback( $callback ) { + $this->callback = ( is_callable( $callback ) ) ? $callback : null; return $this; } @@ -350,14 +359,14 @@ public function set_callback($callback) { * @return bool TRUE if callback is set */ protected function has_callback() { - return ( !empty($this->callback) ) ? true : false; + return ( ! empty( $this->callback ) ) ? true : false; } /** * Run callback */ public function do_callback() { - call_user_func($this->get_callback()); + call_user_func( $this->get_callback() ); } /** @@ -373,9 +382,10 @@ public function get_capability() { * @param string $capability Capability * @return obj Current instance */ - public function set_capability($capability) { - if ( is_string($capability) && !empty($capability) ) + public function set_capability( $capability ) { + if ( is_string( $capability ) && ! empty( $capability ) ) { $this->capability = $capability; + } return $this; } @@ -384,14 +394,15 @@ public function set_capability($capability) { * @param string $icon Icon URI * @return obj Current instance */ - public function set_icon($icon) { - if ( !empty($icon) && is_string($icon) ) + public function set_icon( $icon ) { + if ( ! empty( $icon ) && is_string( $icon ) ) { $this->icon = $icon; + } return $this; } protected function get_hookname() { - return ( empty($this->hookname) ) ? '' : $this->hookname; + return ( empty( $this->hookname ) ) ? '' : $this->hookname; } /** @@ -399,9 +410,10 @@ protected function get_hookname() { * @param string $hookname Hookname value * @return obj Current instance */ - public function set_hookname($hookname) { - if ( !empty($hookname) && is_string($hookname) ) + public function set_hookname( $hookname ) { + if ( ! empty( $hookname ) && is_string( $hookname ) ) { $this->hookname = $hookname; + } return $this; } @@ -413,7 +425,7 @@ public function set_hookname($hookname) { */ public function get_parent() { $parent = parent::get_parent(); - return ( $this->is_parent_custom() ) ? $this->add_prefix($parent) : $parent; + return ( $this->is_parent_custom() ) ? $this->add_prefix( $parent ) : $parent; } /** @@ -421,10 +433,11 @@ public function get_parent() { * @param string $parent Parent ID * @return obj Current instance */ - public function set_parent($parent) { + public function set_parent( $parent ) { if ( $this->parent_required ) { - if ( !empty($parent) && is_string($parent) ) - $this->parent = $parent; + if ( ! empty( $parent ) && is_string( $parent ) ) { + $this->parent = $parent; + } } else { $this->parent = null; } @@ -436,9 +449,9 @@ public function set_parent($parent) { * @param bool $custom (optional) TRUE if custom, FALSE if WP * @return obj Current instance */ - protected function set_parent_custom($custom = true) { + protected function set_parent_custom( $custom = true ) { if ( $this->parent_required ) { - $this->parent_custom = !!$custom; + $this->parent_custom = ! ! $custom; } return $this; } @@ -449,7 +462,7 @@ protected function set_parent_custom($custom = true) { * @return obj Current instance */ public function set_parent_wp() { - $this->set_parent_custom(false); + $this->set_parent_custom( false ); return $this; } @@ -458,32 +471,34 @@ public function set_parent_wp() { * URI Structures: * > Top Level Menus: admin.php?page={menu_id} * > Pages: [parent_page_file.php|admin.php]?page={page_id} - * > Section: [parent_menu_uri]#{section_id} + * > Section: [parent_menu_uri]#{section_id} * * @uses $admin_page_hooks to determine if page is child of default WP page * @param string $file (optional) Base file name * @param string $format (optional) Format string for URI * @return string Object URI */ - public function get_uri($file = null, $format = null) { + public function get_uri( $file = null, $format = null ) { static $page_hooks = null; - $uri = ''; - if ( empty($file) ) + $uri = ''; + if ( empty( $file ) ) { $file = 'admin.php'; + } if ( $this->is_child() ) { - $parent = str_replace('_page_' . $this->get_id(), '', $this->get_hookname()); - if ( is_null($page_hooks) ) { - $page_hooks = array_flip($GLOBALS['admin_page_hooks']); + $parent = str_replace( '_page_' . $this->get_id(), '', $this->get_hookname() ); + if ( is_null( $page_hooks ) ) { + $page_hooks = array_flip( $GLOBALS['admin_page_hooks'] ); + } + if ( isset( $page_hooks[ $parent ] ) ) { + $file = $page_hooks[ $parent ]; } - if ( isset($page_hooks[$parent]) ) - $file = $page_hooks[$parent]; } - if ( empty($format) ) { - $delim = ( strpos($file, '?') === false ) ? '?' : '&'; + if ( empty( $format ) ) { + $delim = ( strpos( $file, '?' ) === false ) ? '?' : '&'; $format = '%1$s' . $delim . 'page=%2$s'; } - $uri = sprintf($format, $file, $this->get_id()); + $uri = sprintf( $format, $file, $this->get_id() ); return $uri; } @@ -503,15 +518,24 @@ public function handle() {} * @return bool TRUE if valid, FALSE if not valid */ public function is_valid() { - $valid = true; + $invalid = false; foreach ( $this->required as $prop => $type ) { - if ( empty($this->{$prop} ) - || ( !empty($type) && is_string($type) && ( $f = 'is_' . $type ) && function_exists($f) && !$f($this->{$prop}) ) ) { - $valid = false; - break; + // Baseline validation. + if ( + empty( $this->{$prop} ) + || empty( $type ) + || ! is_string( $type ) + ) { + return $invalid; + } + + // Validate data type. + $f = 'is_' . $type; + if ( ! function_exists( $f ) || ! $f( $this->{$prop} ) ) { + return $invalid; } } - return $valid; + return true; } protected function is_child() { @@ -523,7 +547,7 @@ protected function is_parent_custom() { } public function is_parent_wp() { - return ( $this->is_child() && !$this->parent_custom ) ? true : false; + return ( $this->is_child() && ! $this->parent_custom ) ? true : false; } -} \ No newline at end of file +} diff --git a/includes/class.base.php b/includes/class.base.php index bf04043..6fd15a1 100644 --- a/includes/class.base.php +++ b/includes/class.base.php @@ -1,555 +1,561 @@ - full - Fully-functional class - * > sub - Sub-class (attached to an instance) - * > object - Simple object class (no hooks, etc.) - * @var string - */ - protected $mode = 'full'; - - /** - * Indicates that instance is model (main controller) - * @var bool - */ - protected $model = false; - - /* Properties */ - - /** - * Variable name of base object in global scope - * @var string - */ - protected $base = 'slb'; - - /** - * Prefix for plugin-related data (attributes, DB tables, etc.) - * @var string - */ - public $prefix = 'slb'; - - /** - * Prefix to be added when creating internal hook (action/filter) tags - * Used by Utilities - * @var string - */ - public $hook_prefix = ''; - - /** - * Global data - * Facilitates sharing between decoupled objects - * @var array - */ - private static $globals = array(); - - protected $shared = array('options', 'admin'); - - /** - * Capabilities - * @var array - */ - protected $caps = null; - - protected $_init = false; - - private static $_init_passed = false; - - /* Client */ - - /** - * Client files - * @var array - * Structure - * > Key: unique file ID - * > Properties - * > file (string) File path (Relative to plugin base) - * > deps (array) Script dependencies - * > Internal dependencies are wrapped in square brackets ([]) - * > context (string|array) - * > Context in which the script should be included - * > in_footer (bool) optional [Default: FALSE] - * > If TRUE, file will be included in footer of page, otherwise it will be included in the header - * - * Array is processed and converted to an object on init - */ - private $client_files = array ( - 'scripts' => array(), - 'styles' => array() - ); - - /*-** Instances **-*/ - - /** - * Utilities - * @var SLB_Utilities - */ - var $util = null; - - /** - * Options - * @var SLB_Options - */ - protected $options = null; - - /** - * Admin - * @var SLB_Admin - */ - var $admin = null; - - /*-** Initialization **-*/ - - /** - * Constructor - */ - function __construct() { - $this->util = new SLB_Utilities($this); - if ( $this->can('init') ) { - $hook = 'init'; - if ( did_action($hook) || self::$_init_passed ) { - $this->_init(); - } else { - add_action($hook, $this->m('_init'), 1); - } - } - } - - /** - * Default initialization method - * @uses _init_passed - * @uses _env() - * @uses _options() - * @uses _admin() - * @uses _hooks() - * @uses _client_files() - */ - public function _init() { - self::$_init_passed = true; - if ( $this->_init || !isset($this) || !$this->can('init') ) - return false; - $this->_init = true; - // Environment - $this->_env(); - - if ( $this->can('control') ) { - // Options - $this->_options(); - - // Admin - if ( is_admin() ) - $this->_admin(); - } - - // Hooks - $this->_hooks(); - - // Client files - $this->_client_files(); - } - - /** - * Initialize environment (Localization, etc.) - */ - private function _env() { - if ( !$this->can('singleton') ) { - return false; - } - // Localization - $ldir = 'l10n'; - $lpath = $this->util->get_plugin_file_path($ldir, array(false, false)); - $lpath_abs = $this->util->get_file_path($ldir); - if ( is_dir($lpath_abs) ) { - load_plugin_textdomain('simple-lightbox', false, $lpath); - } - - // Context - add_action( ( is_admin() ) ? 'admin_print_footer_scripts' : 'wp_footer', $this->util->m('set_client_context'), $this->util->priority('client_footer_output') ); - } - - /** - * Initialize options - * To be implemented in child classes - */ - protected function _options() {} - - /** - * Initialize options - * To be called by child class - */ - protected function _set_options($options_config = null) { - $class = $this->util->get_class('Options'); - $key = 'options'; - if ( $this->shares($key) ) { - $opts = $this->gvar($key); - // Setup options instance - if ( !($opts instanceof $class) ) { - $opts = $this->gvar($key, new $class()); - } - } else { - $opts = new $class(); - } - // Load options - if ( $this->is_options_valid($options_config, false) ) { - $opts->load($options_config); - } - // Set instance property - $this->options = $opts; - } - - /** - * Initialize admin - * To be called by child class - */ - private function _admin() { - if ( !is_admin() ) { - return false; - } - $class = $this->util->get_class('Admin'); - $key = 'admin'; - if ( $this->shares($key) ) { - $adm = $this->gvar($key); - // Setup options instance - if ( !($adm instanceof $class) ) { - $adm = $this->gvar($key, new $class($this)); - } - } else { - $adm = new $class($this); - } - // Set instance property - $this->admin = $adm; - } - - /** - * Register default hooks - */ - protected function _hooks() { - $base = $this->util->get_plugin_base_file(); - // Activation - $func_activate = '_activate'; - if ( method_exists($this, $func_activate) ) - register_activation_hook($base, $this->m($func_activate)); - - // Deactivation - $func_deactivate = '_deactivate'; - if ( method_exists($this, $func_deactivate) ) - register_deactivation_hook($base, $this->m($func_deactivate)); - } - - /** - * Initialize client files - */ - protected function _client_files($files = null) { - // Validation - if ( !is_array($files) || empty($files) ) { - return false; - } - foreach ( $this->client_files as $key => $val ) { - if ( isset($files[$key]) && is_array($files[$key]) || !empty($files[$key]) ) { - $this->client_files[$key] = $this->util->parse_client_files($files[$key], $key); - } - // Remove empty file groups - if ( empty($this->client_files[$key]) ) { - unset($this->client_files[$key]); - } - } - - - // Stop if no files are set for registration - if ( empty($this->client_files) ) { - return false; - } - - // Register - add_action('init', $this->m('register_client_files')); - - // Enqueue - $hk_prfx = ( ( is_admin() ) ? 'admin' : 'wp' ); - $hk_enqueue = $hk_prfx . '_enqueue_scripts' ; - $hk_enqueue_ft = $hk_prfx . '_footer'; - add_action($hk_enqueue, $this->m('enqueue_client_files'), 10, 0); - add_action($hk_enqueue_ft, $this->m('enqueue_client_files_footer'), 1); - } - - /** - * Register client files - * @see enqueue_client_files() for actual loading of files based on context - * @uses `init` Action hook for execution - * @return void - */ - public function register_client_files() { - $v = $this->util->get_plugin_version(); - foreach ( $this->client_files as $type => $files ) { - $func = $this->get_client_files_handler($type, 'register'); - if ( !$func ) - continue; - foreach ( $files as $f ) { - // Get file URI - $f->file = ( !$this->util->is_file($f->file) && is_callable($f->file) ) ? call_user_func($f->file) : $this->util->get_file_url($f->file, true); - $params = array($f->id, $f->file, $f->deps, $v); - // Set additional parameters based on file type (script, style, etc.) - switch ( $type ) { - case 'scripts': - $params[] = $f->in_footer; - break; - case 'styles': - $params[] = $f->media; - break; - } - // Register file - call_user_func_array($func, $params); - } - } - } - - /** - * Enqueues files for client output (scripts/styles) based on context - * @uses `admin_enqueue_scripts` Action hook depending on context - * @uses `wp_enqueue_scripts` Action hook depending on context - * @param bool $footer (optional) Whether to enqueue footer files (Default: No) - * @return void - */ - function enqueue_client_files($footer = false) { - // Validate - if ( !is_bool($footer) ) { - $footer = false; - } - // Enqueue files - foreach ( $this->client_files as $type => $files ) { - $func = $this->get_client_files_handler($type, 'enqueue'); - if ( !$func ) { - continue; - } - foreach ( $files as $fkey => $f ) { - // Skip previously-enqueued files and shadow files - if ( $f->enqueued || !$f->enqueue ) { - continue; - } - // Enqueue files only for current location (header/footer) - if ( isset($f->in_footer) ) { - if ( $f->in_footer != $footer ) { - continue; - } - } elseif ( $footer ) { - continue; - } - $load = true; - // Global Callback - if ( is_callable($f->callback) && !call_user_func($f->callback) ) { - $load = false; - } - // Context - if ( $load && !empty($f->context) ) { - // Reset $load before evaluating context - $load = false; - // Iterate through contexts - foreach ( $f->context as $ctx ) { - // Context + Callback - if ( is_array($ctx) ) { - // Stop checking context if callback is invalid - if ( !is_callable($ctx[1]) || !call_user_func($ctx[1]) ) - continue; - $ctx = $ctx[0]; - } - // Stop checking context if valid context found - if ( $this->util->is_context($ctx) ) { - $load = true; - break; - } - } - } - // Load valid file - if ( $load ) { - // Mark file as enqueued - $this->client_files[$type]->{$fkey}->enqueued = true; - $func($f->id); - } - } - } - } - - /** - * Enqueue client files in the footer - */ - public function enqueue_client_files_footer() { - $this->enqueue_client_files(true); - } - - /** - * Build function name for handling client operations - */ - function get_client_files_handler($type, $action) { - $func = 'wp_' . $action . '_' . substr($type, 0, -1); - if ( !function_exists($func) ) - $func = false; - return $func; - } - - /*-** Reflection **-*/ - - /** - * Retrieve base object - * @return object|bool Base object (FALSE if object does not exist) - */ - function &get_base() { - $base = false; - if ( isset($GLOBALS[$this->base]) ) - $base =& $GLOBALS[$this->base]; - return $base; - } - - /*-** Method/Function calling **-*/ - - /** - * Returns callback to instance method - * @param string $method Method name - * @return array Callback array - */ - function m($method) { - return $this->util->m($this, $method); - } - - /*-** Prefix **-*/ - - /** - * Retrieve class prefix (with separator if set) - * @param bool|string $sep Separator to append to class prefix (Default: no separator) - * @return string Class prefix - */ - function get_prefix($sep = null) { - $args = func_get_args(); - return call_user_func_array($this->util->m($this->util, 'get_prefix'), $args); - } - - /** - * Check if a string is prefixed - * @param string $text Text to check for prefix - * @param string $sep (optional) Separator used - */ - function has_prefix($text, $sep = null) { - $args = func_get_args(); - return call_user_func_array($this->util->m($this->util, 'has_prefix'), $args); - } - - /** - * Prepend plugin prefix to some text - * @param string $text Text to add to prefix - * @param string $sep (optional) Text used to separate prefix and text - * @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not - * @return string Text with prefix prepended - */ - function add_prefix($text, $sep = null, $once = true) { - $args = func_get_args(); - return call_user_func_array($this->util->m($this->util, 'add_prefix'), $args); - } - - /** - * Prepend uppercased plugin prefix to some text - * @param string $text Text to add to prefix - * @param string $sep (optional) Text used to separate prefix and text - * @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not - * @return string Text with prefix prepended - */ - function add_prefix_uc($text, $sep = null, $once = true) { - $args = func_get_args(); - return call_user_func_array($this->util->m($this->util, 'add_prefix_uc'), $args); - } - - /** - * Add prefix to variable reference - * Updates actual variable rather than return value - * @uses SLB_Utilities::add_prefix_ref(); - * @param string $var Variable to add prefix to - * @param string $sep (optional) Separator text - * @param bool $once (optional) Add prefix only once - * @return void - */ - function add_prefix_ref(&$var, $sep = null, $once = true) { - $args = func_get_args(); - $args[0] =& $var; - call_user_func_array($this->util->m($this->util, 'add_prefix_ref'), $args); - } - - /** - * Remove prefix from specified string - * @param string $text String to remove prefix from - * @param string $sep (optional) Separator used with prefix - */ - function remove_prefix($text, $sep = null) { - $args = func_get_args(); - return call_user_func_array($this->util->m($this->util, 'remove_prefix'), $args); - } - - /*-** Capabilities **-*/ - - protected function can($cap) { - if ( is_null($this->caps) ) { - // Build capabilities based on instance properties - $this->caps = array( - 'init' => ( 'object' != $this->mode ) ? true : false, - 'singleton' => ( !!$this->model ) ? true : false, - 'control' => ( 'sub' == $this->mode || 'object' == $this->mode ) ? false : true, - ); - } - return ( isset($this->caps[$cap]) ) ? $this->caps[$cap] : false; - } - - /*-** Globals **-*/ - - /** - * Get/Set (internal) global variables - * @uses $globals to get/set global variables - * @param string $name Variable name - If no name is specified, entire globals array is returned - * @param mixed $val (optional) Set the value of a variable (Returns variable value if omitted) - * @return mixed Variable value - */ - private function gvar($name = null, $val = null) { - $g =& self::$globals; - if ( !is_array($g) ) { - $g = array(); - } - if ( !is_string($name) || empty($name) ) { - return $g; - } - $ret = $val; - if ( null !== $val ) { - // Set Value - $g[$name] = $val; - } elseif ( isset($g[$name]) ) { - // Retrieve variable - $ret = $g[$name]; - } - return $ret; - } - - private function shares($name) { - return ( !empty($this->shared) && in_array($name, $this->shared) ) ? true : false; - } - - /*-** Options **-*/ - - /** - * Checks if options are valid - * @param array $data Data to be used on options - * @return bool TRUE if options are valid, FALSE otherwise - */ - function is_options_valid($data, $check_var = true) { - $class = $this->util->get_class('Options'); - $ret = ( empty($data) || !is_array($data) || !class_exists($class) ) ? false : true; - if ( $ret && $check_var && !($this->options instanceof $class) ) - $ret = false; - return $ret; - } -} - -?> \ No newline at end of file + full - Fully-functional class + * > sub - Sub-class (attached to an instance) + * > object - Simple object class (no hooks, etc.) + * @var string + */ + protected $mode = 'full'; + + /** + * Indicates that instance is model (main controller) + * @var bool + */ + protected $model = false; + + /* Properties */ + + /** + * Variable name of base object in global scope + * @var string + */ + protected $base = 'slb'; + + /** + * Prefix for plugin-related data (attributes, DB tables, etc.) + * @var string + */ + public $prefix = 'slb'; + + /** + * Prefix to be added when creating internal hook (action/filter) tags + * Used by Utilities + * @var string + */ + public $hook_prefix = ''; + + /** + * Global data + * Facilitates sharing between decoupled objects + * @var array + */ + private static $globals = array(); + + protected $shared = array( 'options', 'admin' ); + + /** + * Capabilities + * @var array + */ + protected $caps = null; + + protected $_init = false; + + private static $_init_passed = false; + + /* Client */ + + /** + * Client files + * @var array + * Structure + * > Key: unique file ID + * > Properties + * > file (string) File path (Relative to plugin base) + * > deps (array) Script dependencies + * > Internal dependencies are wrapped in square brackets ([]) + * > context (string|array) + * > Context in which the script should be included + * > in_footer (bool) optional [Default: FALSE] + * > If TRUE, file will be included in footer of page, otherwise it will be included in the header + * + * Array is processed and converted to an object on init + */ + private $client_files = array( + 'scripts' => array(), + 'styles' => array(), + ); + + /*-** Instances **-*/ + + /** + * Utilities + * @var SLB_Utilities + */ + public $util = null; + + /** + * Options + * @var SLB_Options + */ + protected $options = null; + + /** + * Admin + * @var SLB_Admin + */ + public $admin = null; + + /*-** Initialization **-*/ + + /** + * Constructor + */ + function __construct() { + $this->util = new SLB_Utilities( $this ); + if ( $this->can( 'init' ) ) { + $hook = 'init'; + if ( did_action( $hook ) || self::$_init_passed ) { + $this->_init(); + } else { + add_action( $hook, $this->m( '_init' ), 1 ); + } + } + } + + /** + * Default initialization method + * @uses _init_passed + * @uses _env() + * @uses _options() + * @uses _admin() + * @uses _hooks() + * @uses _client_files() + */ + public function _init() { + self::$_init_passed = true; + if ( $this->_init || ! isset( $this ) || ! $this->can( 'init' ) ) { + return false; + } + $this->_init = true; + // Environment + $this->_env(); + + if ( $this->can( 'control' ) ) { + // Options + $this->_options(); + + // Admin + if ( is_admin() ) { + $this->_admin(); + } + } + + // Hooks + $this->_hooks(); + + // Client files + $this->_client_files(); + } + + /** + * Initialize environment (Localization, etc.) + */ + private function _env() { + if ( ! $this->can( 'singleton' ) ) { + return false; + } + // Localization + $ldir = 'l10n'; + $lpath = $this->util->get_plugin_file_path( $ldir, array( false, false ) ); + $lpath_abs = $this->util->get_file_path( $ldir ); + if ( is_dir( $lpath_abs ) ) { + load_plugin_textdomain( 'simple-lightbox', false, $lpath ); + } + + // Context + add_action( ( is_admin() ) ? 'admin_print_footer_scripts' : 'wp_footer', $this->util->m( 'set_client_context' ), $this->util->priority( 'client_footer_output' ) ); + } + + /** + * Initialize options + * To be implemented in child classes + */ + protected function _options() {} + + /** + * Initialize options + * To be called by child class + */ + protected function _set_options( $options_config = null ) { + $class = $this->util->get_class( 'Options' ); + $key = 'options'; + if ( $this->shares( $key ) ) { + $opts = $this->gvar( $key ); + // Setup options instance + if ( ! ( $opts instanceof $class ) ) { + $opts = $this->gvar( $key, new $class() ); + } + } else { + $opts = new $class(); + } + // Load options + if ( $this->is_options_valid( $options_config, false ) ) { + $opts->load( $options_config ); + } + // Set instance property + $this->options = $opts; + } + + /** + * Initialize admin + * To be called by child class + */ + private function _admin() { + if ( ! is_admin() ) { + return false; + } + $class = $this->util->get_class( 'Admin' ); + $key = 'admin'; + if ( $this->shares( $key ) ) { + $adm = $this->gvar( $key ); + // Setup options instance + if ( ! ( $adm instanceof $class ) ) { + $adm = $this->gvar( $key, new $class( $this ) ); + } + } else { + $adm = new $class( $this ); + } + // Set instance property + $this->admin = $adm; + } + + /** + * Register default hooks + */ + protected function _hooks() { + $base = $this->util->get_plugin_base_file(); + // Activation + $func_activate = '_activate'; + if ( method_exists( $this, $func_activate ) ) { + register_activation_hook( $base, $this->m( $func_activate ) ); + } + + // Deactivation + $func_deactivate = '_deactivate'; + if ( method_exists( $this, $func_deactivate ) ) { + register_deactivation_hook( $base, $this->m( $func_deactivate ) ); + } + } + + /** + * Initialize client files + */ + protected function _client_files( $files = null ) { + // Validation + if ( ! is_array( $files ) || empty( $files ) ) { + return false; + } + foreach ( $this->client_files as $key => $val ) { + if ( isset( $files[ $key ] ) && is_array( $files[ $key ] ) || ! empty( $files[ $key ] ) ) { + $this->client_files[ $key ] = $this->util->parse_client_files( $files[ $key ], $key ); + } + // Remove empty file groups + if ( empty( $this->client_files[ $key ] ) ) { + unset( $this->client_files[ $key ] ); + } + } + + // Stop if no files are set for registration + if ( empty( $this->client_files ) ) { + return false; + } + + // Register + add_action( 'init', $this->m( 'register_client_files' ) ); + + // Enqueue + $hk_prfx = ( ( is_admin() ) ? 'admin' : 'wp' ); + $hk_enqueue = $hk_prfx . '_enqueue_scripts'; + $hk_enqueue_ft = $hk_prfx . '_footer'; + add_action( $hk_enqueue, $this->m( 'enqueue_client_files' ), 10, 0 ); + add_action( $hk_enqueue_ft, $this->m( 'enqueue_client_files_footer' ), 1 ); + } + + /** + * Register client files + * @see enqueue_client_files() for actual loading of files based on context + * @uses `init` Action hook for execution + * @return void + */ + public function register_client_files() { + $v = $this->util->get_plugin_version(); + foreach ( $this->client_files as $type => $files ) { + $func = $this->get_client_files_handler( $type, 'register' ); + if ( ! $func ) { + continue; + } + foreach ( $files as $f ) { + // Get file URI + $f->file = ( ! $this->util->is_file( $f->file ) && is_callable( $f->file ) ) ? call_user_func( $f->file ) : $this->util->get_file_url( $f->file, true ); + $params = array( $f->id, $f->file, $f->deps, $v ); + // Set additional parameters based on file type (script, style, etc.) + switch ( $type ) { + case 'scripts': + $params[] = $f->in_footer; + break; + case 'styles': + $params[] = $f->media; + break; + } + // Register file + call_user_func_array( $func, $params ); + } + } + } + + /** + * Enqueues files for client output (scripts/styles) based on context + * @uses `admin_enqueue_scripts` Action hook depending on context + * @uses `wp_enqueue_scripts` Action hook depending on context + * @param bool $footer (optional) Whether to enqueue footer files (Default: No) + * @return void + */ + function enqueue_client_files( $footer = false ) { + // Validate + if ( ! is_bool( $footer ) ) { + $footer = false; + } + // Enqueue files + foreach ( $this->client_files as $type => $files ) { + $func = $this->get_client_files_handler( $type, 'enqueue' ); + if ( ! $func ) { + continue; + } + foreach ( $files as $fkey => $f ) { + // Skip previously-enqueued files and shadow files + if ( $f->enqueued || ! $f->enqueue ) { + continue; + } + // Enqueue files only for current location (header/footer) + if ( isset( $f->in_footer ) ) { + if ( $f->in_footer !== $footer ) { + continue; + } + } elseif ( $footer ) { + continue; + } + $load = true; + // Global Callback + if ( is_callable( $f->callback ) && ! call_user_func( $f->callback ) ) { + $load = false; + } + // Context + if ( $load && ! empty( $f->context ) ) { + // Reset $load before evaluating context + $load = false; + // Iterate through contexts + foreach ( $f->context as $ctx ) { + // Context + Callback + if ( is_array( $ctx ) ) { + // Stop checking context if callback is invalid + if ( ! is_callable( $ctx[1] ) || ! call_user_func( $ctx[1] ) ) { + continue; + } + $ctx = $ctx[0]; + } + // Stop checking context if valid context found + if ( $this->util->is_context( $ctx ) ) { + $load = true; + break; + } + } + } + // Load valid file + if ( $load ) { + // Mark file as enqueued + $this->client_files[ $type ]->{$fkey}->enqueued = true; + $func( $f->id ); + } + } + } + } + + /** + * Enqueue client files in the footer + */ + public function enqueue_client_files_footer() { + $this->enqueue_client_files( true ); + } + + /** + * Build function name for handling client operations + */ + function get_client_files_handler( $type, $action ) { + $func = 'wp_' . $action . '_' . substr( $type, 0, -1 ); + if ( ! function_exists( $func ) ) { + $func = false; + } + return $func; + } + + /*-** Reflection **-*/ + + /** + * Retrieve base object + * @return object|bool Base object (FALSE if object does not exist) + */ + function &get_base() { + $base = false; + if ( isset( $GLOBALS[ $this->base ] ) ) { + $base =& $GLOBALS[ $this->base ]; + } + return $base; + } + + /*-** Method/Function calling **-*/ + + /** + * Returns callback to instance method + * @param string $method Method name + * @return array Callback array + */ + function m( $method ) { + return $this->util->m( $this, $method ); + } + + /*-** Prefix **-*/ + + /** + * Retrieve class prefix (with separator if set) + * @param bool|string $sep Separator to append to class prefix (Default: no separator) + * @return string Class prefix + */ + function get_prefix( $sep = null ) { + $args = func_get_args(); + return call_user_func_array( $this->util->m( $this->util, 'get_prefix' ), $args ); + } + + /** + * Check if a string is prefixed + * @param string $text Text to check for prefix + * @param string $sep (optional) Separator used + */ + function has_prefix( $text, $sep = null ) { + $args = func_get_args(); + return call_user_func_array( $this->util->m( $this->util, 'has_prefix' ), $args ); + } + + /** + * Prepend plugin prefix to some text + * @param string $text Text to add to prefix + * @param string $sep (optional) Text used to separate prefix and text + * @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not + * @return string Text with prefix prepended + */ + function add_prefix( $text, $sep = null, $once = true ) { + $args = func_get_args(); + return call_user_func_array( $this->util->m( $this->util, 'add_prefix' ), $args ); + } + + /** + * Prepend uppercased plugin prefix to some text + * @param string $text Text to add to prefix + * @param string $sep (optional) Text used to separate prefix and text + * @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not + * @return string Text with prefix prepended + */ + function add_prefix_uc( $text, $sep = null, $once = true ) { + $args = func_get_args(); + return call_user_func_array( $this->util->m( $this->util, 'add_prefix_uc' ), $args ); + } + + /** + * Add prefix to variable reference + * Updates actual variable rather than return value + * @uses SLB_Utilities::add_prefix_ref(); + * @param string $var Variable to add prefix to + * @param string $sep (optional) Separator text + * @param bool $once (optional) Add prefix only once + * @return void + */ + function add_prefix_ref( &$var, $sep = null, $once = true ) { + $args = func_get_args(); + $args[0] =& $var; + call_user_func_array( $this->util->m( $this->util, 'add_prefix_ref' ), $args ); + } + + /** + * Remove prefix from specified string + * @param string $text String to remove prefix from + * @param string $sep (optional) Separator used with prefix + */ + function remove_prefix( $text, $sep = null ) { + $args = func_get_args(); + return call_user_func_array( $this->util->m( $this->util, 'remove_prefix' ), $args ); + } + + /*-** Capabilities **-*/ + + protected function can( $cap ) { + if ( is_null( $this->caps ) ) { + // Build capabilities based on instance properties + $this->caps = array( + 'init' => ( 'object' !== $this->mode ) ? true : false, + 'singleton' => ( ! ! $this->model ) ? true : false, + 'control' => ( 'sub' === $this->mode || 'object' === $this->mode ) ? false : true, + ); + } + return ( isset( $this->caps[ $cap ] ) ) ? $this->caps[ $cap ] : false; + } + + /*-** Globals **-*/ + + /** + * Get/Set (internal) global variables + * @uses $globals to get/set global variables + * @param string $name Variable name - If no name is specified, entire globals array is returned + * @param mixed $val (optional) Set the value of a variable (Returns variable value if omitted) + * @return mixed Variable value + */ + private function gvar( $name = null, $val = null ) { + $g =& self::$globals; + if ( ! is_array( $g ) ) { + $g = array(); + } + if ( ! is_string( $name ) || empty( $name ) ) { + return $g; + } + $ret = $val; + if ( null !== $val ) { + // Set Value + $g[ $name ] = $val; + } elseif ( isset( $g[ $name ] ) ) { + // Retrieve variable + $ret = $g[ $name ]; + } + return $ret; + } + + private function shares( $name ) { + return ( ! empty( $this->shared ) && in_array( $name, $this->shared, true ) ) ? true : false; + } + + /*-** Options **-*/ + + /** + * Checks if options are valid + * @param array $data Data to be used on options + * @return bool TRUE if options are valid, FALSE otherwise + */ + function is_options_valid( $data, $check_var = true ) { + $class = $this->util->get_class( 'Options' ); + $ret = ( empty( $data ) || ! is_array( $data ) || ! class_exists( $class ) ) ? false : true; + if ( $ret && $check_var && ! ( $this->options instanceof $class ) ) { + $ret = false; + } + return $ret; + } +} diff --git a/includes/class.base_collection.php b/includes/class.base_collection.php index 356ab93..a446cb9 100644 --- a/includes/class.base_collection.php +++ b/includes/class.base_collection.php @@ -1,369 +1,369 @@ -items) ) { - $this->items = array(); - if ( !empty($this->hook_prefix) ) { - $this->util->do_action('init', $this); - } - } - } - - /** - * Normalize/Validate item(s) - * TODO: If no items are specified, then collection is normalized - * Single items are wrapped in an array - * @param array|object $items Item(s) to validate - * @return array Validated items - */ - protected function normalize($items) { - if ( !is_array($items) ) { - $items = array($items); - } - // Validate item type - if ( !is_null($this->item_type) ) { - foreach ( $items as $idx => $item ) { - // Remove invalid items - if ( !( $item instanceof $this->item_type ) ) { - unset($items[$idx]); - } - } - } - if ( !empty($items) ) { - $items = array_values($items); - } - return $items; - } - - protected function item_valid($item) { - // Validate item type - return ( empty($this->item_type) || ( $item instanceof $this->item_type ) ) ? true : false; - } - - /** - * Validate item key - * Checks collection for existence of key as well - * @param string|int $key Key to check collection for - * @return bool TRUE if key is valid - */ - protected function key_valid($key) { - $this->init(); - return ( ( ( is_string($key) && !empty($key) ) || is_int($key) ) && isset($this->items[$key]) ) ? true : false; - } - - /** - * Generate key for item (for storing in collection, etc.) - * @param mixed $item Item to generate key for - * @return string|null Item key (NULL if no key generated) - */ - protected function get_key($item, $check_existing = false) { - $ret = null; - if ( $this->unique || !!$check_existing ) { - // Check for item in collection - if ( $this->has($item) ) { - $ret = array_search($item, $this->items); - } elseif ( !!$this->key_prop && ( is_object($item) || is_array($item) ) ) { - if ( !!$this->key_call ) { - $cb = $this->util->m($item, $this->key_prop); - if ( is_callable($cb) ) { - $ret = call_user_func($cb); - } - } elseif ( is_array($item) && isset($item[$this->key_prop]) ) { - $ret = $item[$this->key_prop]; - } elseif ( is_object($item) && isset($item->{$this->key_prop}) ) { - $ret = $item->{$this->key_prop}; - } - } - } - return $ret; - } - - /** - * Add item to collection - * @param mixed $item Item to add to collection - * @param array $meta (optional) Item metadata - * @return Current instance - */ - public function add($item, $meta = null) { - $this->init(); - // Validate - if ( $this->item_valid($item) ) { - // Add item to collection - $key = $this->get_key($item); - if ( !$key ) { - $this->items[] = $item; - $key = key($this->items); - } else { - $this->items[$key] = $item; - } - // Add metadata - if ( !!$key && is_array($meta) ) { - $this->add_meta($key, $meta); - } - } - return $this; - } - - /** - * Remove item from collection - * @param int|string $item Key of item to remove - * @return Current instance - */ - public function remove($item) { - if ( $this->key_valid($item) ) { - unset($this->items[$item]); - } - return $this; - } - - /** - * Clear collection - * @return Current instance - */ - public function clear() { - $this->items = array(); - return $this; - } - - /** - * Checks if item exists in the collection - * @param mixed $item Item(s) to check for - * @return bool TRUE if item(s) in collection - */ - public function has($items) { - // Attempt to locate item - return false; - } - - /** - * Retrieve item(s) from collection - * If no items specified, entire collection returned - * @param array $args (optional) Query arguments - * @return object|array Specified item(s) - */ - public function get($args = null) { - $this->init(); - // Parse args - $args_default = array( - 'orderby' => null, - 'order' => 'DESC', - 'include' => array(), - 'exclude' => array(), - ); - $r = wp_parse_args($args, $args_default); - - $items = $this->items; - - /* Sort */ - if ( !is_null($r['orderby']) ) { - // Validate - if ( !is_array($r['orderby']) ) { - $r['orderby'] = array('item' => $r['orderby']); - } - // Prep - $metas = ( isset($r['orderby']['meta']) ) ? $this->items_meta : array(); - // Sort - foreach ( $r['orderby'] as $stype => $sval ) { - /* Meta sorting */ - if ( 'meta' == $stype ) { - // Build sorting buckets - $buckets = array(); - foreach ( $metas as $item => $meta ) { - if ( !isset($meta[$sval]) ) { - continue; - } - // Create bucket - $idx = $meta[$sval]; - if ( !isset($buckets[ $idx ]) ) { - $buckets[ $idx ] = array(); - } - // Add item to bucket - $buckets[ $idx ][] = $item; - } - // Sort buckets - ksort($buckets, SORT_NUMERIC); - // Merge buckets - $pool = array(); - foreach ( $buckets as $bucket ) { - $pool = array_merge($pool, $bucket); - } - // Fill with items - $items = array_merge( array_fill_keys($pool, null), $items); - } - } - // Clear workers - unset($stype, $sval, $buckets, $pool, $item, $metas, $meta, $idx); - } - return $items; - } - - /* Metadata */ - - /** - * Add metadata for item - * @param string|int $item Item key - * @param string|array $meta_key Meta key to set (or array of metadata) - * @param mixed $meta_value (optional) Metadata value (if key set) - * @param bool $reset (optional) Whether to remove existing metadata first (Default: FALSE) - * @return object Current instance - */ - protected function add_meta($item, $meta_key, $meta_value = null, $reset = false) { - // Validate - if ( $this->key_valid($item) && ( is_array($meta_key) || is_string($meta_key) ) ) { - // Prepare metadata - $meta = ( is_string($meta_key) ) ? array($meta_key => $meta_value) : $meta_key; - // Reset existing meta (if necessary) - if ( is_array($meta_key) && func_num_args() > 2) { - $reset = func_get_arg(2); - } - if ( !!$reset ) { - unset($this->items_meta[$item]); - } - // Add metadata - if ( !isset($this->items_meta[$item]) ) { - $this->items_meta[$item] = array(); - } - $this->items_meta[$item] = array_merge($this->items_meta[$item], $meta); - } - return $this; - } - - /** - * Remove item metadata - * @param string $item Item key - * @return object Current instance - */ - protected function remove_meta($item, $meta_key = null) { - if ( $this->key_valid($item) && isset($this->items_meta[$item]) ) { - if ( is_string($meta_key) ) { - // Remove specific meta value - unset($this->items_meta[$item][$meta_key]); - } else { - // Remove all metadata - unset($this->items_meta[$item]); - } - } - return $this; - } - - /** - * Retrieve metadata - * @param string $item Item key - * @param string $meta_key (optional) Meta key (All metadata retrieved if no key specified) - * @return mixed|null Metadata value - */ - protected function get_meta($item, $meta_key = null) { - $ret = null; - if ( $this->key_valid($item) && isset($this->items_meta[$item]) ) { - if ( is_null($meta_key) ) { - $ret = $this->items_meta[$item]; - } elseif ( is_string($meta_key) && isset($this->items_meta[$item][$meta_key]) ) { - $ret = $this->items_meta[$item][$meta_key]; - } - } - return $ret; - } - - /* Collection */ - - /** - * Build entire collection of items - * Prints output - */ - function build($build_vars = array()) { - // Parse vars - $this->parse_build_vars($build_vars); - $this->util->do_action_ref_array('build_init', array($this)); - // Pre-build output - $this->util->do_action_ref_array('build_pre', array($this)); - // Build groups - $this->build_groups(); - // Post-build output - $this->util->do_action_ref_array('build_post', array($this)); - } - - /** - * Parses build variables prior to use - * @uses this->reset_build_vars() to reset build variables for each request - * @param array $build_vars Variables to use for current request - */ - function parse_build_vars($build_vars = array()) { - $this->reset_build_vars(); - $this->build_vars = $this->util->apply_filters('parse_build_vars', wp_parse_args($build_vars, $this->build_vars), $this); - } - - /** - * Reset build variables to defaults - * Default Variables - * > groups - array - Names of groups to build - * > context - string - Context of current request - * > layout - string - Name of default layout to use - */ - function reset_build_vars() { - $this->build_vars = wp_parse_args($this->build_vars, $this->build_vars_default); - } -} \ No newline at end of file +items ) ) { + $this->items = array(); + if ( ! empty( $this->hook_prefix ) ) { + $this->util->do_action( 'init', $this ); + } + } + } + + /** + * Normalize/Validate item(s) + * TODO: If no items are specified, then collection is normalized + * Single items are wrapped in an array + * @param array|object $items Item(s) to validate + * @return array Validated items + */ + protected function normalize( $items ) { + if ( ! is_array( $items ) ) { + $items = array( $items ); + } + // Validate item type + if ( ! is_null( $this->item_type ) ) { + foreach ( $items as $idx => $item ) { + // Remove invalid items + if ( ! ( $item instanceof $this->item_type ) ) { + unset( $items[ $idx ] ); + } + } + } + if ( ! empty( $items ) ) { + $items = array_values( $items ); + } + return $items; + } + + protected function item_valid( $item ) { + // Validate item type + return ( empty( $this->item_type ) || ( $item instanceof $this->item_type ) ) ? true : false; + } + + /** + * Validate item key + * Checks collection for existence of key as well + * @param string|int $key Key to check collection for + * @return bool TRUE if key is valid + */ + protected function key_valid( $key ) { + $this->init(); + return ( ( ( is_string( $key ) && ! empty( $key ) ) || is_int( $key ) ) && isset( $this->items[ $key ] ) ) ? true : false; + } + + /** + * Generate key for item (for storing in collection, etc.) + * @param mixed $item Item to generate key for + * @return string|null Item key (NULL if no key generated) + */ + protected function get_key( $item, $check_existing = false ) { + $ret = null; + if ( $this->unique || ! ! $check_existing ) { + // Check for item in collection + if ( $this->has( $item ) ) { + $ret = array_search( $item, $this->items, true ); + } elseif ( ! ! $this->key_prop && ( is_object( $item ) || is_array( $item ) ) ) { + if ( ! ! $this->key_call ) { + $cb = $this->util->m( $item, $this->key_prop ); + if ( is_callable( $cb ) ) { + $ret = call_user_func( $cb ); + } + } elseif ( is_array( $item ) && isset( $item[ $this->key_prop ] ) ) { + $ret = $item[ $this->key_prop ]; + } elseif ( is_object( $item ) && isset( $item->{$this->key_prop} ) ) { + $ret = $item->{$this->key_prop}; + } + } + } + return $ret; + } + + /** + * Add item to collection + * @param mixed $item Item to add to collection + * @param array $meta (optional) Item metadata + * @return Current instance + */ + public function add( $item, $meta = null ) { + $this->init(); + // Validate + if ( $this->item_valid( $item ) ) { + // Add item to collection + $key = $this->get_key( $item ); + if ( ! $key ) { + $this->items[] = $item; + $key = key( $this->items ); + } else { + $this->items[ $key ] = $item; + } + // Add metadata + if ( ! ! $key && is_array( $meta ) ) { + $this->add_meta( $key, $meta ); + } + } + return $this; + } + + /** + * Remove item from collection + * @param int|string $item Key of item to remove + * @return Current instance + */ + public function remove( $item ) { + if ( $this->key_valid( $item ) ) { + unset( $this->items[ $item ] ); + } + return $this; + } + + /** + * Clear collection + * @return Current instance + */ + public function clear() { + $this->items = array(); + return $this; + } + + /** + * Checks if item exists in the collection + * @param mixed $item Item(s) to check for + * @return bool TRUE if item(s) in collection + */ + public function has( $items ) { + // Attempt to locate item + return false; + } + + /** + * Retrieve item(s) from collection + * If no items specified, entire collection returned + * @param array $args (optional) Query arguments + * @return object|array Specified item(s) + */ + public function get( $args = null ) { + $this->init(); + // Parse args + $args_default = array( + 'orderby' => null, + 'order' => 'DESC', + 'include' => array(), + 'exclude' => array(), + ); + $r = wp_parse_args( $args, $args_default ); + + $items = $this->items; + + /* Sort */ + if ( ! is_null( $r['orderby'] ) ) { + // Validate + if ( ! is_array( $r['orderby'] ) ) { + $r['orderby'] = array( 'item' => $r['orderby'] ); + } + // Prep + $metas = ( isset( $r['orderby']['meta'] ) ) ? $this->items_meta : array(); + // Sort + foreach ( $r['orderby'] as $stype => $sval ) { + /* Meta sorting */ + if ( 'meta' === $stype ) { + // Build sorting buckets + $buckets = array(); + foreach ( $metas as $item => $meta ) { + if ( ! isset( $meta[ $sval ] ) ) { + continue; + } + // Create bucket + $idx = $meta[ $sval ]; + if ( ! isset( $buckets[ $idx ] ) ) { + $buckets[ $idx ] = array(); + } + // Add item to bucket + $buckets[ $idx ][] = $item; + } + // Sort buckets + ksort( $buckets, SORT_NUMERIC ); + // Merge buckets + $pool = array(); + foreach ( $buckets as $bucket ) { + $pool = array_merge( $pool, $bucket ); + } + // Fill with items + $items = array_merge( array_fill_keys( $pool, null ), $items ); + } + } + // Clear workers + unset( $stype, $sval, $buckets, $pool, $item, $metas, $meta, $idx ); + } + return $items; + } + + /* Metadata */ + + /** + * Add metadata for item + * @param string|int $item Item key + * @param string|array $meta_key Meta key to set (or array of metadata) + * @param mixed $meta_value (optional) Metadata value (if key set) + * @param bool $reset (optional) Whether to remove existing metadata first (Default: FALSE) + * @return object Current instance + */ + protected function add_meta( $item, $meta_key, $meta_value = null, $reset = false ) { + // Validate + if ( $this->key_valid( $item ) && ( is_array( $meta_key ) || is_string( $meta_key ) ) ) { + // Prepare metadata + $meta = ( is_string( $meta_key ) ) ? array( $meta_key => $meta_value ) : $meta_key; + // Reset existing meta (if necessary) + if ( is_array( $meta_key ) && func_num_args() > 2 ) { + $reset = func_get_arg( 2 ); + } + if ( ! ! $reset ) { + unset( $this->items_meta[ $item ] ); + } + // Add metadata + if ( ! isset( $this->items_meta[ $item ] ) ) { + $this->items_meta[ $item ] = array(); + } + $this->items_meta[ $item ] = array_merge( $this->items_meta[ $item ], $meta ); + } + return $this; + } + + /** + * Remove item metadata + * @param string $item Item key + * @return object Current instance + */ + protected function remove_meta( $item, $meta_key = null ) { + if ( $this->key_valid( $item ) && isset( $this->items_meta[ $item ] ) ) { + if ( is_string( $meta_key ) ) { + // Remove specific meta value + unset( $this->items_meta[ $item ][ $meta_key ] ); + } else { + // Remove all metadata + unset( $this->items_meta[ $item ] ); + } + } + return $this; + } + + /** + * Retrieve metadata + * @param string $item Item key + * @param string $meta_key (optional) Meta key (All metadata retrieved if no key specified) + * @return mixed|null Metadata value + */ + protected function get_meta( $item, $meta_key = null ) { + $ret = null; + if ( $this->key_valid( $item ) && isset( $this->items_meta[ $item ] ) ) { + if ( is_null( $meta_key ) ) { + $ret = $this->items_meta[ $item ]; + } elseif ( is_string( $meta_key ) && isset( $this->items_meta[ $item ][ $meta_key ] ) ) { + $ret = $this->items_meta[ $item ][ $meta_key ]; + } + } + return $ret; + } + + /* Collection */ + + /** + * Build entire collection of items + * Prints output + */ + function build( $build_vars = array() ) { + // Parse vars + $this->parse_build_vars( $build_vars ); + $this->util->do_action_ref_array( 'build_init', array( $this ) ); + // Pre-build output + $this->util->do_action_ref_array( 'build_pre', array( $this ) ); + // Build groups + $this->build_groups(); + // Post-build output + $this->util->do_action_ref_array( 'build_post', array( $this ) ); + } + + /** + * Parses build variables prior to use + * @uses this->reset_build_vars() to reset build variables for each request + * @param array $build_vars Variables to use for current request + */ + function parse_build_vars( $build_vars = array() ) { + $this->reset_build_vars(); + $this->build_vars = $this->util->apply_filters( 'parse_build_vars', wp_parse_args( $build_vars, $this->build_vars ), $this ); + } + + /** + * Reset build variables to defaults + * Default Variables + * > groups - array - Names of groups to build + * > context - string - Context of current request + * > layout - string - Name of default layout to use + */ + function reset_build_vars() { + $this->build_vars = wp_parse_args( $this->build_vars, $this->build_vars_default ); + } +} diff --git a/includes/class.base_object.php b/includes/class.base_object.php index 7a99b3d..1ae605a 100644 --- a/includes/class.base_object.php +++ b/includes/class.base_object.php @@ -1,337 +1,343 @@ - scripts array JS scripts - * > styles array Stylesheets - */ - protected $files = array( - 'scripts' => array(), - 'styles' => array() - ); - - /** - * Properties that can be inherited from parent - * @var array - */ - protected $parent_props = array(); - - /*-** Methods **-*/ - - /** - * Constructor - * @param string $id Unique ID for content type - * @param array $props (optional) Type properties (optional because props can be set post-init) - */ - public function __construct($id, $props = null) { - parent::__construct(); - $this - ->set_id($id) - ->set_props($props); - } - - /** - * Checks if object is valid - * To be overriden by child classes - */ - public function is_valid() { - return true; - } - - /*-** Getters/Setters **-*/ - - /** - * Get ID - * @return string ID - */ - public function get_id() { - return $this->id; - } - - /** - * Set ID - * @param string $id ID - * @return object Current instance - */ - public function set_id($id) { - $id = ( is_string($id) ) ? trim($id) : ''; - if ( !empty($id) ) { - $this->id = $id; - } - return $this; - } - - /** - * Set type properties - * @param array $props Type properties to set - */ - protected function set_props($props) { - if ( is_array($props) && !empty($props) ) { - foreach ( $props as $key => $val ) { - // Check for setter method - $m = 'set_' . $key; - if ( method_exists($this, $m) ) { - $this->{$m}($val); - } - } - } - return $this; - } - - /** - * Get parent - * @return object|null Parent - */ - public function get_parent() { - return $this->parent; - } - - /** - * Set parent - * @param object $parent Parent object - * @return object Current instance - */ - public function set_parent($parent) { - $this->parent = ( $parent instanceof $this ) ? $parent : null; - return $this; - } - - /** - * Check if parent is set - * @return bool TRUE if parent is set - */ - public function has_parent() { - return ( is_null($this->parent) ) ? false : true; - } - - /** - * Retrieve all ancestors - * @return array Ancestors - */ - public function get_ancestors() { - $ret = array(); - $curr = $this; - while ( $curr->has_parent() ) { - // Add ancestor - $ret[] = $par = $curr->get_parent(); - // Get next ancestor - $curr = $par; - } - return $ret; - } - - /* Files */ - - /** - * Add file - * @param string $type Group to add file to - * @param string $handle Name for resource - * @param string $src File URI - * @return object Current instance - */ - protected function add_file($type, $handle, $src, $deps = array()) { - if ( is_string($type) && is_string($handle) && is_string($src) ) { - // Validate dependencies - if ( !is_array($deps) ) { - $deps = array(); - } - // Init file group - if ( !isset($this->files[$type]) || !is_array($this->files[$type]) ) { - $this->files[$type] = array(); - } - // Add file to group - $this->files[$type][$handle] = array('handle' => $handle, 'uri' => $src, 'deps' => $deps); - } - return $this; - } - - /** - * Add multiple files - * @param string $type Group to add files to - * @param array $files Files to add - * @see add_file() for file parameters - * @return object Current instance - */ - protected function add_files($type, $files) { - if ( !is_array($files) || empty($files) ) - return false; - $m = $this->m('add_file'); - foreach ( $files as $file ) { - if ( !is_array($file) || empty($file) ) { - continue; - } - array_unshift($file, $type); - call_user_func_array($m, $file); - } - return $this; - } - - /** - * Retrieve files - * All files or a specific group of files can be retrieved - * @param string $type (optional) File group to retrieve - * @return array Files - */ - protected function get_files($type = null) { - $ret = $this->files; - if ( is_string($type) ) { - $ret = ( isset($ret[$type]) ) ? $ret[$type] : array(); - } - if ( !is_array($ret) ) { - $ret = array(); - } - return $ret; - } - - /** - * Retrieve file - * @param string $type Group to retrieve file from - * @param string $handle - * @param string $format (optional) Format of return value (Default: array) - * @return array|null File properties (Default: NULL) - */ - protected function get_file($type, $handle, $format = null) { - // Get files - $files = $this->get_files($type); - // Get specified file - $ret = ( is_string($type) && isset($files[$handle]) ) ? $files[$handle] : null; - // Format return value - if ( !empty($ret) && !!$format ) { - switch ( $format ) { - case 'uri': - $ret = $ret['uri']; - // Normalize URI - if ( !$this->util->is_uri($ret) ) { - $ret = $this->util->normalize_path(site_url(), $ret); - } - break; - case 'path': - $ret = $ret['uri']; - // Normalize path - if ( !$this->util->is_uri($ret) ) { - $ret = $this->util->get_relative_path($ret); - $ret = $this->util->normalize_path(ABSPATH, $ret); - } - break; - case 'object': - $ret = (object) $ret; - break; - case 'contents': - $ret = $ret['uri']; - if ( !$this->util->is_uri($ret) ) { - $ret = $this->util->normalize_path(site_url(), $ret); - } - $get = wp_safe_remote_get($ret); - $ret = ( !is_wp_error($get) && 200 == $get['response']['code'] ) ? $get['body'] : ''; - break; - } - } - return $ret; - } - - /** - * Add stylesheet - * @param string $handle Name of the stylesheet - * @param string $src Stylesheet URI - * @return object Current instance - */ - public function add_style($handle, $src, $deps = array()) { - return $this->add_file('styles', $handle, $src, $deps); - } - - /** - * Retrieve stylesheet files - * @return array Stylesheet files - */ - public function get_styles($opts = null) { - $files = $this->get_files('styles'); - if ( is_array($opts) ) { - $opts = (object) $opts; - } - if ( is_object($opts) && !empty($opts) ) { - // Parse options - // URI Format - if ( isset($opts->uri_format) ) { - foreach ( $files as $hdl => $props ) { - switch ( $opts->uri_format ) { - case 'full': - if ( !$this->util->is_uri($props['uri']) ) { - $files[$hdl]['uri'] = $this->util->normalize_path(site_url(), $props['uri']); - } - break; - } - } - } - } - return $files; - } - - /** - * Retrieve stylesheet file - * @param string $handle Name of stylesheet - * @param string $format (optional) Format of return value (@see `get_file()`) - * @return array|null File properties (Default: NULL) - */ - public function get_style($handle, $format = null) { - return $this->get_file('styles', $handle, $format); - } - - /** - * Add script - * @param string $handle Name of the script - * @param string $src Script URI - * @return object Current instance - */ - public function add_script($handle, $src, $deps = array()) { - return $this->add_file('scripts', $handle, $src, $deps); - } - - /** - * Retrieve script files - * @return array Script files - */ - public function get_scripts() { - return $this->get_files('scripts'); - } - - /** - * Retrieve script file - * @param string $handle Name of script - * @param string $format (optional) Format of return value (@see `get_file()`) - * @return array|null File properties (Default: NULL) - */ - public function get_script($handle, $format = null) { - return $this->get_file('scripts', $handle, $format); - } - -} \ No newline at end of file + scripts array JS scripts + * > styles array Stylesheets + */ + protected $files = array( + 'scripts' => array(), + 'styles' => array(), + ); + + /** + * Properties that can be inherited from parent + * @var array + */ + protected $parent_props = array(); + + /*-** Methods **-*/ + + /** + * Constructor + * @param string $id Unique ID for content type + * @param array $props (optional) Type properties (optional because props can be set post-init) + */ + public function __construct( $id, $props = null ) { + parent::__construct(); + $this + ->set_id( $id ) + ->set_props( $props ); + } + + /** + * Checks if object is valid + * To be overriden by child classes + */ + public function is_valid() { + return true; + } + + /*-** Getters/Setters **-*/ + + /** + * Get ID + * @return string ID + */ + public function get_id() { + return $this->id; + } + + /** + * Set ID + * @param string $id ID + * @return object Current instance + */ + public function set_id( $id ) { + $id = ( is_string( $id ) ) ? trim( $id ) : ''; + if ( ! empty( $id ) ) { + $this->id = $id; + } + return $this; + } + + /** + * Set type properties + * @param array $props Type properties to set + */ + protected function set_props( $props ) { + if ( is_array( $props ) && ! empty( $props ) ) { + foreach ( $props as $key => $val ) { + // Check for setter method + $m = 'set_' . $key; + if ( method_exists( $this, $m ) ) { + $this->{$m}( $val ); + } + } + } + return $this; + } + + /** + * Get parent + * @return object|null Parent + */ + public function get_parent() { + return $this->parent; + } + + /** + * Set parent + * @param object $parent Parent object + * @return object Current instance + */ + public function set_parent( $parent ) { + $this->parent = ( $parent instanceof $this ) ? $parent : null; + return $this; + } + + /** + * Check if parent is set + * @return bool TRUE if parent is set + */ + public function has_parent() { + return ( is_null( $this->parent ) ) ? false : true; + } + + /** + * Retrieve all ancestors + * @return array Ancestors + */ + public function get_ancestors() { + $ret = array(); + $curr = $this; + while ( $curr->has_parent() ) { + // Get next ancestor. + $curr = $curr->get_parent(); + // Add ancestor. + $ret[] = $curr; + } + + return $ret; + } + + /* Files */ + + /** + * Add file + * @param string $type Group to add file to + * @param string $handle Name for resource + * @param string $src File URI + * @return object Current instance + */ + protected function add_file( $type, $handle, $src, $deps = array() ) { + if ( is_string( $type ) && is_string( $handle ) && is_string( $src ) ) { + // Validate dependencies + if ( ! is_array( $deps ) ) { + $deps = array(); + } + // Init file group + if ( ! isset( $this->files[ $type ] ) || ! is_array( $this->files[ $type ] ) ) { + $this->files[ $type ] = array(); + } + // Add file to group + $this->files[ $type ][ $handle ] = array( + 'handle' => $handle, + 'uri' => $src, + 'deps' => $deps, + ); + } + return $this; + } + + /** + * Add multiple files + * @param string $type Group to add files to + * @param array $files Files to add + * @see add_file() for file parameters + * @return object Current instance + */ + protected function add_files( $type, $files ) { + if ( ! is_array( $files ) || empty( $files ) ) { + return false; + } + $m = $this->m( 'add_file' ); + foreach ( $files as $file ) { + if ( ! is_array( $file ) || empty( $file ) ) { + continue; + } + array_unshift( $file, $type ); + call_user_func_array( $m, $file ); + } + return $this; + } + + /** + * Retrieve files + * All files or a specific group of files can be retrieved + * @param string $type (optional) File group to retrieve + * @return array Files + */ + protected function get_files( $type = null ) { + $ret = $this->files; + if ( is_string( $type ) ) { + $ret = ( isset( $ret[ $type ] ) ) ? $ret[ $type ] : array(); + } + if ( ! is_array( $ret ) ) { + $ret = array(); + } + return $ret; + } + + /** + * Retrieve file + * @param string $type Group to retrieve file from + * @param string $handle + * @param string $format (optional) Format of return value (Default: array) + * @return array|null File properties (Default: NULL) + */ + protected function get_file( $type, $handle, $format = null ) { + // Get files + $files = $this->get_files( $type ); + // Get specified file + $ret = ( is_string( $type ) && isset( $files[ $handle ] ) ) ? $files[ $handle ] : null; + // Format return value + if ( ! empty( $ret ) && ! ! $format ) { + switch ( $format ) { + case 'uri': + $ret = $ret['uri']; + // Normalize URI + if ( ! $this->util->is_uri( $ret ) ) { + $ret = $this->util->normalize_path( site_url(), $ret ); + } + break; + case 'path': + $ret = $ret['uri']; + // Normalize path + if ( ! $this->util->is_uri( $ret ) ) { + $ret = $this->util->get_relative_path( $ret ); + $ret = $this->util->normalize_path( ABSPATH, $ret ); + } + break; + case 'object': + $ret = (object) $ret; + break; + case 'contents': + $ret = $ret['uri']; + if ( ! $this->util->is_uri( $ret ) ) { + $ret = $this->util->normalize_path( site_url(), $ret ); + } + $get = wp_safe_remote_get( $ret ); + $ret = ( ! is_wp_error( $get ) && 200 === $get['response']['code'] ) ? $get['body'] : ''; + break; + } + } + return $ret; + } + + /** + * Add stylesheet + * @param string $handle Name of the stylesheet + * @param string $src Stylesheet URI + * @return object Current instance + */ + public function add_style( $handle, $src, $deps = array() ) { + return $this->add_file( 'styles', $handle, $src, $deps ); + } + + /** + * Retrieve stylesheet files + * @return array Stylesheet files + */ + public function get_styles( $opts = null ) { + $files = $this->get_files( 'styles' ); + if ( is_array( $opts ) ) { + $opts = (object) $opts; + } + if ( is_object( $opts ) && ! empty( $opts ) ) { + // Parse options + // URI Format + if ( isset( $opts->uri_format ) ) { + foreach ( $files as $hdl => $props ) { + switch ( $opts->uri_format ) { + case 'full': + if ( ! $this->util->is_uri( $props['uri'] ) ) { + $files[ $hdl ]['uri'] = $this->util->normalize_path( site_url(), $props['uri'] ); + } + break; + } + } + } + } + return $files; + } + + /** + * Retrieve stylesheet file + * @param string $handle Name of stylesheet + * @param string $format (optional) Format of return value (@see `get_file()`) + * @return array|null File properties (Default: NULL) + */ + public function get_style( $handle, $format = null ) { + return $this->get_file( 'styles', $handle, $format ); + } + + /** + * Add script + * @param string $handle Name of the script + * @param string $src Script URI + * @return object Current instance + */ + public function add_script( $handle, $src, $deps = array() ) { + return $this->add_file( 'scripts', $handle, $src, $deps ); + } + + /** + * Retrieve script files + * @return array Script files + */ + public function get_scripts() { + return $this->get_files( 'scripts' ); + } + + /** + * Retrieve script file + * @param string $handle Name of script + * @param string $format (optional) Format of return value (@see `get_file()`) + * @return array|null File properties (Default: NULL) + */ + public function get_script( $handle, $format = null ) { + return $this->get_file( 'scripts', $handle, $format ); + } + +} diff --git a/includes/class.collection_controller.php b/includes/class.collection_controller.php index 210cc33..3593db6 100644 --- a/includes/class.collection_controller.php +++ b/includes/class.collection_controller.php @@ -19,8 +19,8 @@ class SLB_Collection_Controller extends SLB_Base_Collection { /* Methods */ - public function __construct($parent = null) { - $this->set_parent($parent); + public function __construct( $parent = null ) { + $this->set_parent( $parent ); parent::__construct(); } @@ -33,7 +33,7 @@ public function __construct($parent = null) { * @param SLB_Base $parent (optional) Parent instance * @return obj Current instance */ - protected function set_parent($parent = null) { + protected function set_parent( $parent = null ) { $this->parent = ( $parent instanceof SLB_Base ) ? $parent : null; return $this; } @@ -43,7 +43,7 @@ protected function set_parent($parent = null) { * @return bool TRUE if parent set */ protected function has_parent() { - return ( is_object($this->get_parent()) ) ? true : false; + return ( is_object( $this->get_parent() ) ) ? true : false; } /** @@ -54,4 +54,4 @@ protected function has_parent() { protected function get_parent() { return $this->parent; } -} \ No newline at end of file +} diff --git a/includes/class.component.php b/includes/class.component.php index cc07f60..d812849 100644 --- a/includes/class.component.php +++ b/includes/class.component.php @@ -17,7 +17,7 @@ class SLB_Component extends SLB_Base_Object { protected $props_required = array(); - private $props_required_base = array('id'); + private $props_required_base = array( 'id' ); /* Get/Set */ @@ -26,10 +26,10 @@ class SLB_Component extends SLB_Base_Object { * @param string $name Name * @return Current instance */ - public function set_name($name) { - if ( is_string($name) ) { - $name = trim($name); - if ( !empty($name) ) { + public function set_name( $name ) { + if ( is_string( $name ) ) { + $name = trim( $name ); + if ( ! empty( $name ) ) { $this->name = $name; } } @@ -40,12 +40,12 @@ public function get_name() { return $this->name; } - public function set_scripts($scripts) { - $this->add_files('scripts', $scripts); + public function set_scripts( $scripts ) { + $this->add_files( 'scripts', $scripts ); } - public function set_styles($styles) { - $this->add_files('styles', $styles); + public function set_styles( $styles ) { + $this->add_files( 'styles', $styles ); } /* Assets */ @@ -55,45 +55,45 @@ public function set_styles($styles) { * @param string $base_handle Base handle to format * @return string Formatted handle */ - public function get_handle($base_handle) { - return $this->add_prefix( array('asset', $this->get_id(), $base_handle), '-'); + public function get_handle( $base_handle ) { + return $this->add_prefix( array( 'asset', $this->get_id(), $base_handle ), '-' ); } /** * Enqueue files in client * @param string $type (optional) Type of file to load (singular) (Default: All client file types) */ - public function enqueue_client_files($type = null) { - if ( empty($type) ) { - $type = array ( 'script', 'style'); + public function enqueue_client_files( $type = null ) { + if ( empty( $type ) ) { + $type = array( 'script', 'style' ); } - if ( !is_array($type) ) { - $type = array ( $type ); + if ( ! is_array( $type ) ) { + $type = array( $type ); } foreach ( $type as $t ) { - $m = (object) array ( - 'get' => $this->m('get_' . $t . 's'), - 'enqueue' => 'wp_enqueue_' . $t, + $m = (object) array( + 'get' => $this->m( 'get_' . $t . 's' ), + 'enqueue' => 'wp_enqueue_' . $t, ); - $v = $this->util->get_plugin_version(); - $files = call_user_func($m->get); - $param_final = ( 'script' == $t ) ? true : 'all'; + $v = $this->util->get_plugin_version(); + $files = call_user_func( $m->get ); + $param_final = ( 'script' === $t ) ? true : 'all'; foreach ( $files as $f ) { $f = (object) $f; // Format handle - $handle = $this->get_handle($f->handle); + $handle = $this->get_handle( $f->handle ); // Format dependencies $deps = array(); foreach ( $f->deps as $dep ) { - if ( $this->util->has_wrapper($dep) ) { - $dep = $this->get_handle( $this->util->remove_wrapper($dep) ); + if ( $this->util->has_wrapper( $dep ) ) { + $dep = $this->get_handle( $this->util->remove_wrapper( $dep ) ); } $deps[] = $dep; } - call_user_func($m->enqueue, $handle, $f->uri, $deps, $v, $param_final); + call_user_func( $m->enqueue, $handle, $f->uri, $deps, $v, $param_final ); } - unset($files, $f, $param_final, $handle, $deps, $dep); + unset( $files, $f, $param_final, $handle, $deps, $dep ); } } @@ -101,14 +101,14 @@ public function enqueue_client_files($type = null) { * Enqueue scripts */ public function enqueue_scripts() { - $this->enqueue_client_files('script'); + $this->enqueue_client_files( 'script' ); } /** * Enqueue styles */ public function enqueue_styles() { - $this->enqueue_client_files('style'); + $this->enqueue_client_files( 'style' ); } /* Helpers */ @@ -122,9 +122,9 @@ public function is_valid() { $ret = parent::is_valid(); if ( $ret ) { // Check required component properties - $props = array_merge($this->props_required_base, $this->props_required); + $props = array_merge( $this->props_required_base, $this->props_required ); foreach ( $props as $prop ) { - if ( !isset($this->{$prop}) || empty($this->{$prop}) ) { + if ( ! isset( $this->{$prop} ) || empty( $this->{$prop} ) ) { $ret = false; break; } @@ -132,4 +132,4 @@ public function is_valid() { } return $ret; } -} \ No newline at end of file +} diff --git a/includes/class.content_handler.php b/includes/class.content_handler.php index d4edcbe..4bfda01 100644 --- a/includes/class.content_handler.php +++ b/includes/class.content_handler.php @@ -1,82 +1,82 @@ -match = ( is_callable($callback) ) ? $callback : null; - return $this; - } - - /** - * Retrieve match handler - * @return callback|null Match handler - */ - protected function get_match() { - return $this->match; - } - - /** - * Check if valid match set - */ - protected function has_match() { - return ( is_null($this->match) ) ? false : true; - } - - /** - * Match handler against URI - * @param string $uri URI to check for match - * @return bool TRUE if handler matches URI - */ - public function match($uri, $uri_raw = null) { - $ret = false; - if ( !!$uri && is_string($uri) && $this->has_match() ) { - $ret = call_user_func($this->get_match(), $uri, $uri_raw); - } - return $ret; - } - - /* Attributes */ - - public function set_attributes($callback) { - $this->attributes = ( is_callable($callback) ) ? $callback : null; - return $this; - } - - public function get_attributes() { - $ret = array(); - // Callback - if ( !is_null($this->attributes) ) { - $ret = call_user_func($this->attributes); - } - // Filter - $hook = sprintf('content_handler_%s_attributes', $this->get_id()); - $ret = $this->util->apply_filters($hook, $ret); - return ( is_array($ret) ) ? $ret : array(); - } -} \ No newline at end of file +match = ( is_callable( $callback ) ) ? $callback : null; + return $this; + } + + /** + * Retrieve match handler + * @return callback|null Match handler + */ + protected function get_match() { + return $this->match; + } + + /** + * Check if valid match set + */ + protected function has_match() { + return ( is_null( $this->match ) ) ? false : true; + } + + /** + * Match handler against URI + * @param string $uri URI to check for match + * @return bool TRUE if handler matches URI + */ + public function match( $uri, $uri_raw = null ) { + $ret = false; + if ( ! ! $uri && is_string( $uri ) && $this->has_match() ) { + $ret = call_user_func( $this->get_match(), $uri, $uri_raw ); + } + return $ret; + } + + /* Attributes */ + + public function set_attributes( $callback ) { + $this->attributes = ( is_callable( $callback ) ) ? $callback : null; + return $this; + } + + public function get_attributes() { + $ret = array(); + // Callback + if ( ! is_null( $this->attributes ) ) { + $ret = call_user_func( $this->attributes ); + } + // Filter + $hook = sprintf( 'content_handler_%s_attributes', $this->get_id() ); + $ret = $this->util->apply_filters( $hook, $ret ); + return ( is_array( $ret ) ) ? $ret : array(); + } +} diff --git a/includes/class.content_handlers.php b/includes/class.content_handlers.php index 486cd30..6b77e6b 100644 --- a/includes/class.content_handlers.php +++ b/includes/class.content_handlers.php @@ -31,9 +31,9 @@ class SLB_Content_Handlers extends SLB_Collection_Controller { protected function _hooks() { parent::_hooks(); - $this->util->add_action('init', $this->m('init_defaults'), 5); - $this->util->add_action('footer', $this->m('client_output'), 1, 0, false); - $this->util->add_filter('footer_script', $this->m('client_output_script'), $this->util->priority('client_footer_output'), 1, false); + $this->util->add_action( 'init', $this->m( 'init_defaults' ), 5 ); + $this->util->add_action( 'footer', $this->m( 'client_output' ), 1, 0, false ); + $this->util->add_filter( 'footer_script', $this->m( 'client_output_script' ), $this->util->priority( 'client_footer_output' ), 1, false ); } /* Collection Management */ @@ -47,23 +47,23 @@ protected function _hooks() { * @param array $props Handler properties * @return object Current instance */ - public function add($id, $props = array(), $priority = 10) { + public function add( $id, $props = array(), $priority = 10 ) { $this->clear_cache(); - if ( is_string($id) ) { + if ( is_string( $id ) ) { // Initialize new handler - $handler = new $this->item_type($id, $props); + $handler = new $this->item_type( $id, $props ); } else { // Remap parameters - $handler = func_get_arg(0); - if ( func_num_args() == 2 ) { - $priority = func_get_arg(1); + $handler = func_get_arg( 0 ); + if ( func_num_args() === 2 ) { + $priority = func_get_arg( 1 ); } } - if ( !is_int($priority) ) { + if ( ! is_int( $priority ) ) { $priority = 10; } // Add to collection - return parent::add($handler, array('priority' => $priority)); + return parent::add( $handler, array( 'priority' => $priority ) ); } /** @@ -72,9 +72,9 @@ public function add($id, $props = array(), $priority = 10) { * @see parent::remove() * @return object Current instance */ - public function remove($item) { + public function remove( $item ) { $this->clear_cache(); - return parent::remove($item); + return parent::remove( $item ); } /** @@ -95,12 +95,12 @@ public function clear() { * @param mixed $args Unused * @return array Handlers */ - public function get($args = null) { + public function get( $args = null ) { $items = $this->get_cache(); - if ( empty($items) ) { + if ( empty( $items ) ) { // Retrieve items - $items = parent::get( array( 'orderby' => array('meta' => 'priority') ) ); - $this->update_cache($items); + $items = parent::get( array( 'orderby' => array( 'meta' => 'priority' ) ) ); + $this->update_cache( $items ); } return $items; } @@ -113,20 +113,23 @@ public function get($args = null) { * > handler (Content_Handler) Matching handler instance (Default: NULL) * > props (array) Properties returned from matching handler (May be empty depending on handler) */ - public function match($uri) { - $ret = (object) array('handler' => null, 'props' => array()); + public function match( $uri ) { + $ret = (object) array( + 'handler' => null, + 'props' => array(), + ); foreach ( $this->get() as $handler ) { - $props = $handler->match($uri, $this); - if ( !!$props ) { + $props = $handler->match( $uri, $this ); + if ( ! ! $props ) { $ret->handler = $handler; // Add handler props - if ( is_array($props) ) { + if ( is_array( $props ) ) { $ret->props = $props; } // Save match $hid = $handler->get_id(); - if ( !isset($this->request_matches[$hid]) ) { - $this->request_matches[$hid] = $handler; + if ( ! isset( $this->request_matches[ $hid ] ) ) { + $this->request_matches[ $hid ] = $handler; } break; } @@ -143,9 +146,9 @@ public function match($uri) { * @return array Cached items (Default: empty array) */ protected function get_cache() { - $cprops= $this->get_cache_props(); - $items = wp_cache_get($cprops->key, $cprops->group); - return ( is_array($items) ) ? $items : array(); + $cprops = $this->get_cache_props(); + $items = wp_cache_get( $cprops->key, $cprops->group ); + return ( is_array( $items ) ) ? $items : array(); } /** @@ -155,9 +158,9 @@ protected function get_cache() { * @uses wp_cache_get() * @param array $data Item data to cache */ - protected function update_cache($data = null) { + protected function update_cache( $data = null ) { $props = $this->get_cache_props(); - wp_cache_set($props->key, $data, $props->group); + wp_cache_set( $props->key, $data, $props->group ); } /** @@ -173,9 +176,9 @@ protected function clear_cache() { * @return object Cache properties */ protected function get_cache_props() { - if ( !is_object($this->cache_props) ) { - $this->cache_props = (object) array ( - 'key' => $this->hook_prefix . '_items', + if ( ! is_object( $this->cache_props ) ) { + $this->cache_props = (object) array( + 'key' => $this->hook_prefix . '_items', 'group' => $this->get_prefix(), ); } @@ -188,20 +191,20 @@ protected function get_cache_props() { * Initialize default handlers * @param SLB_Content_Handlers $handlers Handlers controller */ - public function init_defaults($handlers) { - $src_base = $this->util->get_file_url('content-handlers', true); - $js_path = 'js/'; + public function init_defaults( $handlers ) { + $src_base = $this->util->get_file_url( 'content-handlers', true ); + $js_path = 'js/'; $js_path .= ( SLB_DEV ) ? 'dev' : 'prod'; - $defaults = array ( - 'image' => array ( - 'match' => $this->m('match_image'), - 'scripts' => array ( - array ( 'base', "$src_base/image/$js_path/handler.image.js" ), + $defaults = array( + 'image' => array( + 'match' => $this->m( 'match_image' ), + 'scripts' => array( + array( 'base', "$src_base/image/$js_path/handler.image.js" ), ), - ) + ), ); foreach ( $defaults as $id => $props ) { - $handlers->add($id, $props); + $handlers->add( $id, $props ); } } @@ -210,18 +213,18 @@ public function init_defaults($handlers) { * @param string $uri URI to match * @return bool|array TRUE if URI is image (array is used if extra data needs to be sent) */ - public function match_image($uri, $handlers) { + public function match_image( $uri, $handlers ) { // Basic matching - $match = ( $this->util->has_file_extension($uri, array('jpg', 'jpeg', 'jpe', 'jfif', 'jif', 'gif', 'png')) ) ? true : false; + $match = ( $this->util->has_file_extension( $uri, array( 'avif', 'jpg', 'jpeg', 'jpe', 'jfif', 'jif', 'gif', 'png', 'webp' ) ) ) ? true : false; // Filter result $extra = new stdClass(); - $match = $this->util->apply_filters('image_match', $match, $uri, $extra); + $match = $this->util->apply_filters( 'image_match', $match, $uri, $extra ); // Handle extra data passed from filters // Currently only `uri` supported - if ( $match && isset($extra->uri) && is_string($extra->uri) ) { - $match = array('uri' => $extra->uri); + if ( $match && isset( $extra->uri ) && is_string( $extra->uri ) ) { + $match = array( 'uri' => $extra->uri ); } return $match; @@ -245,33 +248,33 @@ public function client_output() { * @param array $commands Client script commands * @return array Modified script commands */ - public function client_output_script($commands) { - $out = array('/* CHDL */'); + public function client_output_script( $commands ) { + $out = array( '/* CHDL */' ); $code = array(); foreach ( $this->request_matches as $handler ) { // Attributes $attrs = $handler->get_attributes(); // Styles - $styles = $handler->get_styles(array('uri_format'=>'full')); - if ( !empty($styles) ) { - $attrs['styles'] = array_values($styles); + $styles = $handler->get_styles( array( 'uri_format' => 'full' ) ); + if ( ! empty( $styles ) ) { + $attrs['styles'] = array_values( $styles ); } - if ( empty($attrs) ) { + if ( empty( $attrs ) ) { continue; } // Setup client parameters $params = array( - sprintf("'%s'", $handler->get_id()), - json_encode($attrs), + sprintf( "'%s'", $handler->get_id() ), + wp_json_encode( $attrs ), ); // Extend handler in client - $code[] = $this->util->call_client_method('View.extend_content_handler', $params, false); + $code[] = $this->util->call_client_method( 'View.extend_content_handler', $params, false ); } - if ( !empty($code) ) { - $out[] = implode('', $code); - $commands[] = implode(PHP_EOL, $out); + if ( ! empty( $code ) ) { + $out[] = implode( '', $code ); + $commands[] = implode( PHP_EOL, $out ); } return $commands; } -} \ No newline at end of file +} diff --git a/includes/class.field.php b/includes/class.field.php index 6be3c07..5a7780d 100644 --- a/includes/class.field.php +++ b/includes/class.field.php @@ -1,2 +1,2 @@ Value: Placeholder for special character * @var array */ - var $special_chars = null; + public $special_chars = null; - var $special_chars_default = array( - '{' => '%SQB_L%', - '}' => '%SQB_R%', + public $special_chars_default = array( + '{' => '%SQB_L%', + '}' => '%SQB_R%', ); /** * Reference to parent object that current instance inherits from * @var object */ - var $parent = null; + public $parent = null; /** * Title * @var string */ - var $title = ''; + public $title = ''; /** * @var string Short description */ - var $description = ''; + public $description = ''; /** * @var array Object Properties */ - var $properties = array(); + public $properties = array(); /** * Initialization properties @@ -85,27 +85,27 @@ class SLB_Field_Base extends SLB_Base { * Reason: Faster searching over large arrays * @var array Groupings of Properties */ - var $property_groups = array(); + public $property_groups = array(); /** * Keys to filter out of properties array before setting properties * @var array */ - var $property_filter = array('group'); + public $property_filter = array( 'group' ); /** * Define order of properties * Useful when processing order is important (e.g. one property depends on another) * @var array */ - var $property_priority = array(); + public $property_priority = array(); /** * Data for object * May also contain data for nested objects * @var mixed */ - var $data = null; + public $data = null; /** * Whether data has been fetched or not @@ -116,18 +116,18 @@ class SLB_Field_Base extends SLB_Base { /** * @var array Script resources to include for object */ - var $scripts = array(); + public $scripts = array(); /** * @var array CSS style resources to include for object */ - var $styles = array(); + public $styles = array(); /** * Hooks (Filters/Actions) for object * @var array */ - var $hooks = array(); + public $hooks = array(); /** * Mapping of child properties to parent members @@ -137,7 +137,7 @@ class SLB_Field_Base extends SLB_Base { * > Val: Parent property to map TO * @var array */ - var $map = null; + public $map = null; /** * Options used when building collection (callbacks, etc.) @@ -146,23 +146,23 @@ class SLB_Field_Base extends SLB_Base { * > Value: Option value * @var array */ - var $build_vars = array(); + public $build_vars = array(); - var $build_vars_default = array(); + public $build_vars_default = array(); /** * Constructor */ - function __construct($id = '', $properties = null) { + function __construct( $id = '', $properties = null ) { parent::__construct(); // Normalize Properties - $args = func_get_args(); - $defaults = $this->integrate_id($id); - $properties = $this->make_properties($args, $defaults); + $args = func_get_args(); + $defaults = $this->integrate_id( $id ); + $properties = $this->make_properties( $args, $defaults ); // Save init properties $this->properties_init = $properties; // Set Properties - $this->set_properties($properties); + $this->set_properties( $properties ); } /* Getters/Setters */ @@ -172,19 +172,20 @@ function __construct($id = '', $properties = null) { * @param array $path Path to check for * @return bool TRUE if path exists in object, FALSE otherwise */ - function path_isset($path = '') { + function path_isset( $path = '' ) { // Stop execution if no path is supplied - if ( empty($path) ) + if ( empty( $path ) ) { return false; + } $args = func_get_args(); - $path = $this->util->build_path($args); + $path = $this->util->build_path( $args ); $item =& $this; // Iterate over path and check if each level exists before moving on to the next - for ($x = 0; $x < count($path); $x++) { - if ( $this->util->property_exists($item, $path[$x]) ) { + $path_size = count( $path ); + for ( $x = 0; $x < $path_size; $x++ ) { + if ( $this->util->property_exists( $item, $path[ $x ] ) ) { // Set $item as reference to next level in path for next iteration - $item =& $this->util->get_property($item, $path[$x]); - // $item =& $item[ $path[$x] ]; + $item =& $this->util->get_property( $item, $path[ $x ] ); } else { return false; } @@ -198,16 +199,19 @@ function path_isset($path = '') { * @param array $path Path to retrieve value from. Each item in array is a deeper dimension * @return mixed Value at specified path */ - function &get_path_value($path = '') { - $ret = ''; - $path = $this->util->build_path(func_get_args()); - if ( $this->path_isset($path) ) { + function &get_path_value( $path = '' ) { + $ret = ''; + $path = $this->util->build_path( func_get_args() ); + if ( $this->path_isset( $path ) ) { $ret =& $this; - for ($x = 0; $x < count($path); $x++) { - if ( 0 == $x ) - $ret =& $ret->{ $path[$x] }; - else - $ret =& $ret[ $path[$x] ]; + + $path_size = count( $path ); + for ( $x = 0; $x < $path_size; $x++ ) { + if ( 0 === $x ) { + $ret =& $ret->{ $path[ $x ] }; + } else { + $ret =& $ret[ $path[ $x ] ]; + } } } return $ret; @@ -219,34 +223,37 @@ function &get_path_value($path = '') { * @param string $name Value to retrieve from member * @return mixed Member value if found (Default: empty string) */ - function get_parent_value($member, $name = '', $default = '') { + function get_parent_value( $member, $name = '', $default = '' ) { $parent = $this->get_parent(); - return $this->get_object_value($parent, $member, $name, $default, 'parent'); + return $this->get_object_value( $parent, $member, $name, $default, 'parent' ); } /** - * Retrieves specified member value - * Handles inherited values - * Merging corresponding parents if value is an array (e.g. for property groups) - * @param string|array $member Member to search. May also contain a path to the desired member - * @param string $name Value to retrieve from member - * @param mixed $default Default value if no value found (Default: empty string) - * @param string $dir Direction to move through hierarchy to find value - * Possible Values: - * parent (default) - Search through field parents - * current - Do not search through connected objects - * container - Search through field containers - * caller - Search through field callers - * @return mixed Specified member value - * @todo Return reference + * Retrieves specified member value. + * + * Handles inherited values and merges corresponding parents + * if value is an array (e.g. for property groups). + * + * @param string|array $member Member to get value from. + * @param string|array $name Optional. Element/Path to Element to retrieve from member. Default none. + * @param mixed $default Optional. Default value to return if no data retrieved. Default empty string. + * @param string $dir Optional. Direction to move through hierarchy to find value. + * Possible Values: + * * parent (default) - Search through field parents. + * * current - Do not search through connected objects. + * * container - Search through field containers. + * * caller - Search through field callers. + * @return mixed Specified member value. + * @todo Return reference. */ - function &get_member_value($member, $name = '', $default = '', $dir = 'parent') { + function &get_member_value( $member, $name = '', $default = '', $dir = 'parent' ) { // Check if path to member is supplied $path = array(); - if ( is_array($member) && isset($member['tag']) ) { - if ( isset($member['attributes']['ref_base']) ) { - if ( 'root' != $member['attributes']['ref_base'] ) + if ( is_array( $member ) && isset( $member['tag'] ) ) { + if ( isset( $member['attributes']['ref_base'] ) ) { + if ( 'root' !== $member['attributes']['ref_base'] ) { $path[] = $member['attributes']['ref_base']; + } } else { $path[] = 'properties'; } @@ -255,49 +262,62 @@ function &get_member_value($member, $name = '', $default = '', $dir = 'parent') } else { $path = $member; } - - $path = $this->util->build_path($path, $name); + // Prep name. + if ( is_string( $name ) ) { + $name = trim( $name ); + } + $path = $this->util->build_path( $path, $name ); // Set defaults and prepare data - $val = $default; - $inherit = false; + $val = $default; + $inherit = false; $inherit_tag = '{inherit}'; - /* Determine whether the value must be retrieved from a parent/container object + /** + * Determines whether the value must be retrieved from a parent/container object. + * * Conditions: - * > Path does not exist in current field - * > Path exists and is not an object, but at least one of the following is true: - * > Value at path is an array (e.g. properties, elements, etc. array) - * > Parent/container values should be merged with retrieved array - * > Value at path is a string that inherits from another field - * > Value from other field will be retrieved and will replace inheritance placeholder in retrieved value - */ - + * + * 1. Path does not exist in current field. + * 2. Path exists and is not an object, but at least one of the following is true: + * * Value at path is an array (e.g. properties, elements, etc. array): + * * - Parent/container values should be merged with retrieved array. + * * Value at path is a string that inherits from another field: + * * - Value from other field will be retrieved and will replace + * inheritance placeholder in retrieved value + * @var bool + */ $deeper = false; - if ( !$this->path_isset($path) ) + if ( ! $this->path_isset( $path ) ) { $deeper = true; - else { - $val = $this->get_path_value($path); - if ( !is_object($val) && ( is_array($val) || ($inherit = strpos($val, $inherit_tag)) !== false ) ) + } else { + $val = $this->get_path_value( $path ); + if ( is_array( $val ) ) { + $deeper = true; + } elseif ( is_string( $val ) && false !== strpos( $val, $inherit_tag ) ) { $deeper = true; - else - $deeper = false; + // Value inherits from another field. + $inherit = true; + } } - if ( $deeper && 'current' != $dir ) { + + if ( $deeper && 'current' !== $dir ) { $ex_val = ''; // Get Parent value (recursive) - if ( 'parent' == $dir ) - $ex_val = $this->get_parent_value($member, $name, $default); - elseif ( method_exists($this, 'get_container_value') ) - $ex_val = $this->get_container_value($member, $name, $default); + if ( 'parent' === $dir ) { + $ex_val = $this->get_parent_value( $member, $name, $default ); + } elseif ( method_exists( $this, 'get_container_value' ) ) { + $ex_val = $this->get_container_value( $member, $name, $default ); + } // Handle inheritance - if ( is_array($val) ) { + if ( is_array( $val ) ) { // Combine Arrays - if ( is_array($ex_val) ) - $val = array_merge($ex_val, $val); - } elseif ( $inherit !== false ) { + if ( is_array( $ex_val ) ) { + $val = array_merge( $ex_val, $val ); + } + } elseif ( false !== $inherit ) { // Replace placeholder with inherited string - $val = str_replace($inherit_tag, $ex_val, $val); + $val = str_replace( $inherit_tag, $ex_val, $val ); } else { // Default: Set parent value as value $val = $ex_val; @@ -316,10 +336,11 @@ function &get_member_value($member, $name = '', $default = '', $dir = 'parent') * @param string $dir Direction to move through hierarchy to find value @see SLB_Field_Type::get_member_value() for possible values * @return mixed Member value if found (Default: $default) */ - function get_object_value(&$object, $member, $name = '', $default = '', $dir = 'parent') { + function get_object_value( &$object, $member, $name = '', $default = '', $dir = 'parent' ) { $ret = $default; - if ( is_object($object) && method_exists($object, 'get_member_value') ) - $ret = $object->get_member_value($member, $name, $default, $dir); + if ( is_object( $object ) && method_exists( $object, 'get_member_value' ) ) { + $ret = $object->get_member_value( $member, $name, $default, $dir ); + } return $ret; } @@ -327,10 +348,11 @@ function get_object_value(&$object, $member, $name = '', $default = '', $dir = ' * Set item ID * @param string $id Unique item ID */ - function set_id($id) { - if ( empty($id) || !is_string($id) ) + function set_id( $id ) { + if ( empty( $id ) || ! is_string( $id ) ) { return false; - $this->id = trim($id); + } + $this->id = trim( $id ); } /** @@ -338,101 +360,116 @@ function set_id($id) { * @param array|string $options (optional) Options or ID of format to use * @return string item ID */ - function get_id($options = array()) { - $item_id = trim($this->id); + function get_id( $options = array() ) { + $item_id = trim( $this->id ); $formats = $this->get_id_formats(); // Setup options - $wrap_default = array('open' => '', 'close' => '', 'segment_open' => '', 'segment_close' => ''); + $wrap_default = array( + 'open' => '', + 'close' => '', + 'segment_open' => '', + 'segment_close' => '', + ); $options_default = array( - 'format' => null, - 'wrap' => array(), - 'segments_pre' => null, - 'prefix' => '', - 'recursive' => false + 'format' => null, + 'wrap' => array(), + 'segments_pre' => null, + 'prefix' => '', + 'recursive' => false, ); // Load options based on format - if ( !is_array($options) ) - $options = array('format' => $options); - if ( isset($options['format']) && is_string($options['format']) && isset($formats[$options['format']]) ) - $options_default = wp_parse_args($formats[$options['format']], $options_default); - else - unset($options['format']); - $options = wp_parse_args($options, $options_default); + if ( ! is_array( $options ) ) { + $options = array( 'format' => $options ); + } + if ( isset( $options['format'] ) && is_string( $options['format'] ) && isset( $formats[ $options['format'] ] ) ) { + $options_default = wp_parse_args( $formats[ $options['format'] ], $options_default ); + } else { + unset( $options['format'] ); + } + $options = wp_parse_args( $options, $options_default ); // Import options into function - extract($options); + extract( $options ); // Validate options - $wrap = wp_parse_args($wrap, $wrap_default); + $wrap = wp_parse_args( $wrap, $wrap_default ); - if ( !is_array($segments_pre) ) - $segments_pre = array($segments_pre); - $segments_pre = array_reverse($segments_pre); + if ( ! is_array( $segments_pre ) ) { + $segments_pre = array( $segments_pre ); + } + $segments_pre = array_reverse( $segments_pre ); // Format ID based on options - $item_id = array($item_id); + $item_id = array( $item_id ); // Add parent objects to ID - if ( !!$recursive ) { + if ( ! ! $recursive ) { // Create array of ID components $m = 'get_caller'; - $c = ( method_exists($this, $m) ) ? $this->{$m}() : null; - while ( !!$c ) { + $c = ( method_exists( $this, $m ) ) ? $this->{$m}() : null; + while ( ! ! $c ) { // Add ID of current caller to array - if ( method_exists($c, 'get_id') && ( $itemp = $c->get_id() ) && !empty($itemp) ) - $item_id = $itemp; + if ( method_exists( $c, 'get_id' ) && ! strlen( $c->get_id() ) > 0 ) { + $item_id = $c->get_id(); + } // Get parent object - $c = ( method_exists($c, $m) ) ? $c->{$m}() : null; - $itemp = ''; + $c = ( method_exists( $c, $m ) ) ? $c->{$m}() : null; } - unset($c); + unset( $c ); } // Additional segments (Pre) foreach ( $segments_pre as $seg ) { - if ( is_null($seg) ) + if ( is_null( $seg ) ) { continue; - if ( is_object($seg) ) - $seg = (array)$seg; - if ( is_array($seg) ) - $item_id = array_merge($item_id, array_reverse($seg)); - elseif ( '' != strval($seg) ) - $item_id[] = strval($seg); + } + if ( is_object( $seg ) ) { + $seg = (array) $seg; + } + if ( is_array( $seg ) ) { + $item_id = array_merge( $item_id, array_reverse( $seg ) ); + } elseif ( '' !== strval( $seg ) ) { + $item_id[] = strval( $seg ); + } } // Prefix - if ( is_array($prefix) ) { + if ( is_array( $prefix ) ) { // Array is sequence of instance methods to call on object // Last array member can be an array of parameters to pass to methods - $count = count($prefix); - $args = ( $count > 1 && is_array($prefix[$count - 1]) ) ? array_pop($prefix) : array(); - $p = $this; - $val = ''; + $count = count( $prefix ); + $args = ( $count > 1 && is_array( $prefix[ $count - 1 ] ) ) ? array_pop( $prefix ) : array(); + $p = $this; + $val = ''; // Iterate through methods foreach ( $prefix as $m ) { - if ( !method_exists($p, $m) ) + if ( ! method_exists( $p, $m ) ) { continue; + } // Build callback - $m = $this->util->m($p, $m); + $m = $this->util->m( $p, $m ); // Call callback - $val = call_user_func_array($m, $args); + $val = call_user_func_array( $m, $args ); // Returned value may be an instance object - if ( is_object($val) ) + if ( is_object( $val ) ) { $p = $val; // Use returned object in next round - else - array_unshift($args, $val); // Pass returned value as parameter to next method on using current object + } else { + array_unshift( $args, $val ); // Pass returned value as parameter to next method on using current object + } } $prefix = $val; - unset($p, $val); + unset( $p, $val ); + } + if ( is_numeric( $prefix ) ) { + $prefix = strval( $prefix ); } - if ( is_numeric($prefix) ) - $prefix = strval($prefix); - if ( empty($prefix) || !is_string($prefix) ) + if ( empty( $prefix ) || ! is_string( $prefix ) ) { $prefix = ''; + } // Convert array to string - $item_id = $prefix . $wrap['open'] . implode($wrap['segment_close'] . $wrap['segment_open'], array_reverse($item_id)) . $wrap['close']; + $item_id = $prefix . $wrap['open'] . implode( $wrap['segment_close'] . $wrap['segment_open'], array_reverse( $item_id ) ) . $wrap['close']; return $item_id; } @@ -460,8 +497,11 @@ private function init_id_formats() { $this->add_id_format( 'attr_id', [ - 'wrap' => [ 'open' => '_', 'segment_open' => '_' ], - 'prefix' => [ 'get_container', 'get_id', 'add_prefix' ], + 'wrap' => [ + 'open' => '_', + 'segment_open' => '_', + ], + 'prefix' => [ 'get_container', 'get_id', 'add_prefix' ], 'recursive' => true, ], true @@ -469,9 +509,14 @@ private function init_id_formats() { $this->add_id_format( 'attr_name', [ - 'wrap' => [ 'open' => '[', 'close' => ']', 'segment_open' => '[', 'segment_close' => ']' ], - 'prefix' => [ 'get_container', 'get_id', 'add_prefix' ], - 'recursive' => true, + 'wrap' => [ + 'open' => '[', + 'close' => ']', + 'segment_open' => '[', + 'segment_close' => ']', + ], + 'prefix' => [ 'get_container', 'get_id', 'add_prefix' ], + 'recursive' => true, ], true ); @@ -495,18 +540,25 @@ protected function add_id_format( $name, array $options, $overwrite = false ) { // Init ID formats before adding new ones. $this->init_id_formats(); // Validate args. - $name = trim($name); + $name = trim( $name ); // Stop if name invalid. if ( empty( $name ) ) { return; } $overwrite = (bool) $overwrite; // Do not add format if name matches existing format (when overwriting not allowed). - if ( ! $overwrite && in_array( $name, array_keys( $this->id_formats ) ) ) { + if ( ! $overwrite && in_array( $name, array_keys( $this->id_formats ), true ) ) { return; } // Normlize options. - $options = wp_parse_args( $options, [ 'wrap' => [], 'prefix' => [], 'recursive' => false ] ); + $options = wp_parse_args( + $options, + [ + 'wrap' => [], + 'prefix' => [], + 'recursive' => false, + ] + ); // Add format. $this->id_formats[ $name ] = $options; } @@ -517,80 +569,85 @@ protected function add_id_format( $name, array $options, $overwrite = false ) { * @param bool $top (optional) Whether to traverse through the field hierarchy to get data for field (Default: TRUE) * @return mixed Value at specified path */ - function get_data($context = '', $top = true) { - $opt_d = array('context' => '', 'top' => true); - $args = func_get_args(); - $a = false; - if ( count($args) == 1 && is_array($args[0]) && !empty($args[0]) ) { - $a = true; - $args = wp_parse_args($args[0], $opt_d); - extract($args); + function get_data( $context = '', $top = true ) { + $opt_d = array( + 'context' => '', + 'top' => true, + ); + $args = func_get_args(); + $a = false; + if ( count( $args ) === 1 && is_array( $args[0] ) && ! empty( $args[0] ) ) { + $a = true; + $args = wp_parse_args( $args[0], $opt_d ); + extract( $args ); } - if ( is_string($top) ) { - if ( 'false' == $top ) + if ( is_string( $top ) ) { + if ( 'false' === $top ) { $top = false; - elseif ( 'true' == $top ) + } elseif ( 'true' === $top ) { $top = true; - elseif ( is_numeric($top) ) - $top = intval($top); + } elseif ( is_numeric( $top ) ) { + $top = intval( $top ); + } } - $top = !!$top; - $obj =& $this; - $obj_path = array($this); - $path = array(); + $top = ! ! $top; + $obj =& $this; + $obj_path = array( $this ); + $path = array(); if ( $top ) { // Iterate through hiearchy to get top-most object - while ( !empty($obj) ) { + while ( ! empty( $obj ) ) { $new = null; // Try to get caller first - if ( method_exists($obj, 'get_caller') ) { + if ( method_exists( $obj, 'get_caller' ) ) { $checked = true; - $new =& $obj->get_caller(); + $new =& $obj->get_caller(); } // Try to get container if no caller found - if ( empty($new) && method_exists($obj, 'get_container') ) { + if ( empty( $new ) && method_exists( $obj, 'get_container' ) ) { $checked = true; - $new =& $obj->get_container(); + $new =& $obj->get_container(); // Load data - if ( method_exists($new, 'load_data') ) { + if ( method_exists( $new, 'load_data' ) ) { $new->load_data(); } } $obj =& $new; - unset($new); + unset( $new ); // Stop iteration - if ( !empty($obj) ) { + if ( ! empty( $obj ) ) { // Add object to path if it is valid $obj_path[] =& $obj; } } - unset($obj); + unset( $obj ); } // Check each object (starting with top-most) for matching data for current field // Reverse array - $obj_path = array_reverse($obj_path); + $obj_path = array_reverse( $obj_path ); // Build path for data location foreach ( $obj_path as $obj ) { - if ( method_exists($obj, 'get_id') ) + if ( method_exists( $obj, 'get_id' ) ) { $path[] = $obj->get_id(); + } } // Iterate through objects - while ( !empty($obj_path) ) { + while ( ! empty( $obj_path ) ) { // Get next object - $obj = array_shift($obj_path); + $obj = array_shift( $obj_path ); // Shorten path - array_shift($path); + array_shift( $path ); // Check for value in object and stop iteration if matching data found - $val = $this->get_object_value($obj, 'data', $path, null, 'current'); - if ( !is_null($val) ) { + $val = $this->get_object_value( $obj, 'data', $path, null, 'current' ); + if ( ! is_null( $val ) ) { break; } } - return $this->format($val, $context); + return $this->format( $val, $context ); } /** @@ -599,8 +656,8 @@ function get_data($context = '', $top = true) { * @param mixed $value Value to set * @param string|array $name Name of value to set (Can also be path to value) */ - function set_data($value, $name = '') { - $ref =& $this->get_path_value('data', $name); + function set_data( $value, $name = '' ) { + $ref =& $this->get_path_value( 'data', $name ); $ref = $value; } @@ -612,34 +669,38 @@ function set_data($value, $name = '') { * @uses SLB_Fields::get() to retrieve field type object reference * @param string|object $parent Parent ID or reference */ - function set_parent($parent = null) { + function set_parent( $parent = null ) { // Stop processing if parent empty - if ( empty($parent) && !is_string($this->parent) ) + if ( empty( $parent ) && ! is_string( $this->parent ) ) { return false; + } // Parent passed as object reference wrapped in array - if ( is_array($parent) && isset($parent[0]) && is_object($parent[0]) ) + if ( is_array( $parent ) && isset( $parent[0] ) && is_object( $parent[0] ) ) { $parent = $parent[0]; + } // No parent set but parent ID (previously) set in object - if ( empty($parent) && is_string($this->parent) ) + if ( empty( $parent ) && is_string( $this->parent ) ) { $parent = $this->parent; + } // Retrieve reference object if ID was supplied - if ( is_string($parent) ) { - $parent = trim($parent); + if ( is_string( $parent ) ) { + $parent = trim( $parent ); // Get parent object reference /** * @var SLB */ $b = $this->get_base(); - if ( !!$b && isset($b->fields) && $b->fields->has($parent) ) { - $parent = $b->fields->get($parent); + if ( ! ! $b && isset( $b->fields ) && $b->fields->has( $parent ) ) { + $parent = $b->fields->get( $parent ); } } // Set parent value on object - if ( is_string($parent) || is_object($parent) ) + if ( is_string( $parent ) || is_object( $parent ) ) { $this->parent = $parent; + } } /** @@ -655,24 +716,25 @@ function get_parent() { * @param string $title Title for object * @param string $plural Plural form of title */ - function set_title($title = '') { - if ( is_scalar($title) ) - $this->title = strip_tags(trim($title)); + function set_title( $title = '' ) { + if ( is_scalar( $title ) ) { + $this->title = wp_strip_all_tags( trim( $title ) ); + } } /** * Retrieve object title */ function get_title() { - return $this->get_member_value('title', '','', 'current'); + return $this->get_member_value( 'title', '', '', 'current' ); } /** * Set object description * @param string $description Description for object */ - function set_description($description = '') { - $this->description = strip_tags(trim($description)); + function set_description( $description = '' ) { + $this->description = wp_strip_all_tags( trim( $description ) ); } /** @@ -681,36 +743,42 @@ function set_description($description = '') { */ function get_description() { $dir = 'current'; - return $this->get_member_value('description', '','', $dir); - return $desc; + return $this->get_member_value( 'description', '', '', $dir ); } /** - * Sets multiple properties on field type at once - * @param array $properties Properties. Each element is an array containing the arguments to set a new property - * @return boolean TRUE if successful, FALSE otherwise + * Sets multiple properties on field type at once. + * + * @param array $properties Properties to set - each element is an + * array containing the arguments to set a + * new property. + * @return void + * @todo Test refactored code. */ - function set_properties($properties) { - if ( !is_array($properties) ) { - return false; + function set_properties( $properties ) { + if ( ! is_array( $properties ) ) { + return; } // Normalize properties - $properties = $this->remap_properties($properties); - $properties = $this->sort_properties($properties); - // Set Member properties + $properties = $this->remap_properties( $properties ); + $properties = $this->sort_properties( $properties ); + + // Set Member properties. foreach ( $properties as $prop => $val ) { - if ( ( $m = 'set_' . $prop ) && method_exists($this, $m) ) { - $this->{$m}($val); + $m = 'set_' . $prop; + if ( method_exists( $this, $m ) ) { + $this->{$m}( $val ); // Remove member property from array - unset($properties[$prop]); + unset( $properties[ $prop ] ); } + unset( $m ); } // Filter properties - $properties = $this->filter_properties($properties); + $properties = $this->filter_properties( $properties ); // Set additional instance properties - foreach ( $properties as $name => $val) { - $this->set_property($name, $val); + foreach ( $properties as $name => $val ) { + $this->set_property( $name, $val ); } } @@ -721,9 +789,9 @@ function set_properties($properties) { * @param array $properties Associative array of properties * @return array Remapped properties */ - function remap_properties($properties) { + function remap_properties( $properties ) { // Return remapped properties - return $this->util->array_remap($properties, $this->map); + return $this->util->array_remap( $properties, $this->map ); } /** @@ -731,21 +799,23 @@ function remap_properties($properties) { * @uses this::property_priority * @return array Sorted priorities */ - function sort_properties($properties) { + function sort_properties( $properties ) { // Stop if sorting not necessary - if ( empty($properties) || !is_array($properties) || empty($this->property_priority) || !is_array($this->property_priority) ) + if ( empty( $properties ) || ! is_array( $properties ) || empty( $this->property_priority ) || ! is_array( $this->property_priority ) ) { return $properties; + } $props = array(); foreach ( $this->property_priority as $prop ) { - if ( !array_key_exists($prop, $properties) ) + if ( ! array_key_exists( $prop, $properties ) ) { continue; + } // Add to new array - $props[$prop] = $properties[$prop]; + $props[ $prop ] = $properties[ $prop ]; // Remove from old array - unset($properties[$prop]); + unset( $properties[ $prop ] ); } // Append any remaining properties - $props = array_merge($props, $properties); + $props = array_merge( $props, $properties ); return $props; } @@ -755,28 +825,28 @@ function sort_properties($properties) { * @param array $signature (optional) Default properties * @return array Normalized properties */ - function make_properties($props, $signature = array()) { + function make_properties( $props, $signature = array() ) { $p = array(); - if ( is_array($props) ) { + if ( is_array( $props ) ) { foreach ( $props as $prop ) { - if ( is_array($prop) ) { - $p = array_merge($prop, $p); + if ( is_array( $prop ) ) { + $p = array_merge( $prop, $p ); } } } $props = $p; - if ( is_array($signature) ) { - $props = array_merge($signature, $props); + if ( is_array( $signature ) ) { + $props = array_merge( $signature, $props ); } return $props; } - function validate_id($id) { - return ( is_scalar($id) && !empty($id) ) ? true : false; + function validate_id( $id ) { + return ( is_scalar( $id ) && ! empty( $id ) ) ? true : false; } - function integrate_id($id) { - return ( $this->validate_id($id) ) ? array('id' => $id) : array(); + function integrate_id( $id ) { + return ( $this->validate_id( $id ) ) ? array( 'id' => $id ) : array(); } /** @@ -785,8 +855,8 @@ function integrate_id($id) { * @param array $props Properties * @return array Filtered properties */ - function filter_properties($props = array()) { - return $this->util->array_filter_keys($props, $this->property_filter); + function filter_properties( $props = array() ) { + return $this->util->array_filter_keys( $props, $this->property_filter ); } /** @@ -796,18 +866,19 @@ function filter_properties($props = array()) { * @param string|array $group Group(s) property belongs to * @return boolean TRUE if property is successfully added to field type, FALSE otherwise */ - function set_property($name, $value = '', $group = null) { + function set_property( $name, $value = '', $group = null ) { // Do not add if property name is not a string - if ( !is_string($name) ) + if ( ! is_string( $name ) ) { return false; + } // Create property array - $prop_arr = array(); + $prop_arr = array(); $prop_arr['value'] = $value; // Add to properties array - $this->properties[$name] = $value; + $this->properties[ $name ] = $value; // Add property to specified groups - if ( !empty($group) ) { - $this->set_group_property($group, $name); + if ( ! empty( $group ) ) { + $this->set_group_property( $group, $name ); } return true; } @@ -817,8 +888,8 @@ function set_property($name, $value = '', $group = null) { * @param string $name Name of property to retrieve * @return mixed Specified Property if exists (Default: Empty string) */ - function get_property($name) { - $val = $this->get_member_value('properties', $name); + function get_property( $name ) { + $val = $this->get_member_value( 'properties', $name ); return $val; } @@ -826,14 +897,15 @@ function get_property($name) { * Removes a property from item * @param string $name Property ID */ - function remove_property($name) { + function remove_property( $name ) { // Remove property - if ( isset($this->properties[$name]) ) - unset($this->properties[$name]); + if ( isset( $this->properties[ $name ] ) ) { + unset( $this->properties[ $name ] ); + } // Remove from group - foreach ( array_keys($this->property_groups) as $g ) { - if ( isset($this->property_groups[$g][$name]) ) { - unset($this->property_groups[$g][$name]); + foreach ( array_keys( $this->property_groups ) as $g ) { + if ( isset( $this->property_groups[ $g ][ $name ] ) ) { + unset( $this->property_groups[ $g ][ $name ] ); break; } } @@ -844,21 +916,23 @@ function remove_property($name) { * @param string|array $group Group(s) to add property to * @param string $property Property to add to group */ - function set_group_property($group, $property) { - if ( is_string($group) && isset($this->property_groups[$group][$property]) ) + function set_group_property( $group, $property ) { + if ( is_string( $group ) && isset( $this->property_groups[ $group ][ $property ] ) ) { return; - if ( !is_array($group) ) { - $group = array($group); + } + if ( ! is_array( $group ) ) { + $group = array( $group ); } - foreach ($group as $g) { - $g = trim($g); + foreach ( $group as $g ) { + $g = trim( $g ); // Initialize group if it doesn't already exist - if ( !isset($this->property_groups[$g]) ) - $this->property_groups[$g] = array(); + if ( ! isset( $this->property_groups[ $g ] ) ) { + $this->property_groups[ $g ] = array(); + } // Add property to group - $this->property_groups[$g][$property] = null; + $this->property_groups[ $g ][ $property ] = null; } } @@ -867,8 +941,8 @@ function set_group_property($group, $property) { * @param string $group Group to retrieve * @return array Array of properties in specified group */ - function get_group($group) { - return $this->get_member_value('property_groups', $group, array()); + function get_group( $group ) { + return $this->get_member_value( 'property_groups', $group, array() ); } /** @@ -888,7 +962,7 @@ function save() { * @return array Hooks */ function get_hooks() { - return $this->get_member_value('hooks', '', array()); + return $this->get_member_value( 'hooks', '', array() ); } /** @@ -899,19 +973,21 @@ function get_hooks() { * @param $priority * @param $accepted_args */ - function add_hook($tag, $function_to_add, $priority = 10, $accepted_args = 1) { + function add_hook( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { // Create new array for tag (if not already set) - if ( !isset($this->hooks[$tag]) ) - $this->hooks[$tag] = array(); + if ( ! isset( $this->hooks[ $tag ] ) ) { + $this->hooks[ $tag ] = array(); + } // Build Unique ID - if ( is_string($function_to_add) ) + if ( is_string( $function_to_add ) ) { $id = $function_to_add; - elseif ( is_array($function_to_add) && !empty($function_to_add) ) - $id = strval($function_to_add[count($function_to_add) - 1]); - else - $id = 'function_' . ( count($this->hooks[$tag]) + 1 ); + } elseif ( is_array( $function_to_add ) && ! empty( $function_to_add ) ) { + $id = strval( $function_to_add[ count( $function_to_add ) - 1 ] ); + } else { + $id = 'function_' . ( count( $this->hooks[ $tag ] ) + 1 ); + } // Add hook - $this->hooks[$tag][$id] = func_get_args(); + $this->hooks[ $tag ][ $id ] = func_get_args(); } /** @@ -922,8 +998,8 @@ function add_hook($tag, $function_to_add, $priority = 10, $accepted_args = 1) { * @param $priority * @param $accepted_args */ - function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) { - $this->add_hook($tag, $function_to_add, $priority, $accepted_args); + function add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { + $this->add_hook( $tag, $function_to_add, $priority, $accepted_args ); } /** @@ -934,8 +1010,8 @@ function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1) * @param $priority * @param $accepted_args */ - function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) { - $this->add_hook($tag, $function_to_add, $priority, $accepted_args); + function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1 ) { + $this->add_hook( $tag, $function_to_add, $priority, $accepted_args ); } /*-** Dependencies **-*/ @@ -951,22 +1027,27 @@ function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1) * @param $ver * @param $ex */ - function add_dependency($type, $context, $handle, $src = false, $deps = array(), $ver = false, $ex = false) { + function add_dependency( $type, $context, $handle, $src = false, $deps = array(), $ver = false, $ex = false ) { $args = func_get_args(); // Remove type/context from arguments - $args = array_slice($args, 2); + $args = array_slice( $args, 2 ); // Set context - if ( !is_array($context) ) { + if ( ! is_array( $context ) ) { // Wrap single contexts in an array - if ( is_string($context) ) - $context = array($context); - else + if ( is_string( $context ) ) { + $context = array( $context ); + } else { $context = array(); + } } // Add file to instance property - if ( isset($this->{$type}) && is_array($this->{$type}) ) - $this->{$type}[$handle] = array('context' => $context, 'params' => $args); + if ( isset( $this->{$type} ) && is_array( $this->{$type} ) ) { + $this->{$type}[ $handle ] = array( + 'context' => $context, + 'params' => $args, + ); + } } /** @@ -982,8 +1063,8 @@ function add_dependency($type, $context, $handle, $src = false, $deps = array(), function add_script( $context, $handle, $src = false, $deps = array(), $ver = false, $in_footer = false ) { $args = func_get_args(); // Add file type to front of arguments array - array_unshift($args, 'scripts'); - call_user_func_array($this->m('add_dependency'), $args); + array_unshift( $args, 'scripts' ); + call_user_func_array( $this->m( 'add_dependency' ), $args ); } /** @@ -991,7 +1072,7 @@ function add_script( $context, $handle, $src = false, $deps = array(), $ver = fa * @return array Script dependencies */ function get_scripts() { - return $this->get_member_value('scripts', '', array()); + return $this->get_member_value( 'scripts', '', array() ); } /** @@ -1006,8 +1087,8 @@ function get_scripts() { */ function add_style( $handle, $src = false, $deps = array(), $ver = false, $media = false ) { $args = func_get_args(); - array_unshift($args, 'styles'); - call_user_func_array($this->m('add_dependency'), $args); + array_unshift( $args, 'styles' ); + call_user_func_array( $this->m( 'add_dependency' ), $args ); } /** @@ -1015,7 +1096,7 @@ function add_style( $handle, $src = false, $deps = array(), $ver = false, $media * @return array Style dependencies */ function get_styles() { - return $this->get_member_value('styles', '', array()); + return $this->get_member_value( 'styles', '', array() ); } /* Helpers */ @@ -1026,13 +1107,13 @@ function get_styles() { * @param string $context Current context * @return mixed Formatted value */ - function format($value, $context = '') { - if ( is_scalar($context) && !empty($context) ) { - $handler = 'format_' . trim(strval($context)); + function format( $value, $context = '' ) { + if ( is_scalar( $context ) && ! empty( $context ) ) { + $handler = 'format_' . trim( strval( $context ) ); // Only process if context is valid and has a handler - if ( !empty($context) && method_exists($this, $handler) ) { + if ( ! empty( $context ) && method_exists( $this, $handler ) ) { // Pass value to handler - $value = $this->{$handler}($value, $context); + $value = $this->{$handler}( $value, $context ); } } // Return formatted value @@ -1083,26 +1164,29 @@ function format_text( $value ) { * @param string $context (Optional) Formatting context * @return mixed Formatted value */ - function format_final($value, $context = '') { - if ( !is_string($value) ) + function format_final( $value, $context = '' ) { + if ( ! is_string( $value ) ) { return $value; + } // Restore special chars - return $this->restore_special_chars($value, $context); + return $this->restore_special_chars( $value, $context ); } - function preserve_special_chars($value, $context = '') { - if ( !is_string($value) ) + function preserve_special_chars( $value, $context = '' ) { + if ( ! is_string( $value ) ) { return $value; + } $specials = $this->get_special_chars(); - return str_replace(array_keys($specials), $specials, $value); + return str_replace( array_keys( $specials ), $specials, $value ); } - function restore_special_chars($value, $context = '') { - if ( !is_string($value) ) + function restore_special_chars( $value, $context = '' ) { + if ( ! is_string( $value ) ) { return $value; + } $specials = $this->get_special_chars(); - return str_replace($specials, array_keys($specials), $value); + return str_replace( $specials, array_keys( $specials ), $value ); } /** @@ -1113,6 +1197,6 @@ function restore_special_chars($value, $context = '') { * @return array Special characters/placeholders */ function get_special_chars() { - return wp_parse_args($this->special_chars, $this->special_chars_default); + return wp_parse_args( $this->special_chars, $this->special_chars_default ); } -} \ No newline at end of file +} diff --git a/includes/class.field_collection.php b/includes/class.field_collection.php index 83837f7..fc08228 100644 --- a/includes/class.field_collection.php +++ b/includes/class.field_collection.php @@ -17,20 +17,20 @@ class SLB_Field_Collection extends SLB_Field_Base { * Item type * @var string */ - var $item_type = 'SLB_Field'; + public $item_type = 'SLB_Field'; /** * Indexed array of items in collection * @var array */ - var $items = array(); + public $items = array(); - var $build_vars_default = array ( - 'groups' => array(), - 'context' => '', - 'layout' => 'form', - 'build' => true, - 'build_groups' => true, + public $build_vars_default = array( + 'groups' => array(), + 'context' => '', + 'layout' => 'form', + 'build' => true, + 'build_groups' => true, ); /** @@ -43,7 +43,7 @@ class SLB_Field_Collection extends SLB_Field_Base { * > items array Items in group * @var array */ - var $groups = array(); + public $groups = array(); protected $properties_init = null; @@ -59,11 +59,11 @@ class SLB_Field_Collection extends SLB_Field_Base { * @param string $id Collection ID * @param array $properties (optional) Properties to set for collection (Default: none) */ - public function __construct($id, $properties = null) { - $args = func_get_args(); - $properties = $this->make_properties($args); + public function __construct( $id, $properties = null ) { + $args = func_get_args(); + $properties = $this->make_properties( $args ); // Parent constructor - parent::__construct($properties); + parent::__construct( $properties ); // Save initial properties $this->properties_init = $properties; @@ -73,7 +73,7 @@ public function _init() { parent::_init(); // Load properties. - $this->load($this->properties_init, false); + $this->load( $this->properties_init, false ); // Add custom ID format(s). $this->add_id_format( @@ -97,17 +97,17 @@ public function _init() { * @param bool $update (optional) Update (TRUE) or overwrite (FALSE) items/groups (Default: TRUE) * @return object Current instance */ - public function load($properties, $update = true) { - $args = func_get_args(); - $properties = $this->make_properties($args); - if ( !empty($properties) ) { + public function load( $properties, $update = true ) { + $args = func_get_args(); + $properties = $this->make_properties( $args ); + if ( ! empty( $properties ) ) { // Groups - if ( isset($properties['groups']) ) { - $this->add_groups($properties['groups'], $update); + if ( isset( $properties['groups'] ) ) { + $this->add_groups( $properties['groups'], $update ); } // Items - if ( isset($properties['items']) ) { - $this->add_items($properties['items'], $update); + if ( isset( $properties['items'] ) ) { + $this->add_items( $properties['items'], $update ); } } return $this; @@ -132,30 +132,32 @@ function load_data() { /** * Set data for an item * @param mixed $item Field to set data for - * > string Field ID - * > object Field Reference - * > array Data for multiple items (associative array [field ID => data]) + * > string Field ID + * > object Field Reference + * > array Data for multiple items (associative array [field ID => data]) * @param mixed $value Data to set * @param bool $save (optional) Whether or not data should be saved to DB (Default: Yes) */ - function set_data($item, $value = '', $save = true, $force_set = false) { + function set_data( $item, $value = '', $save = true, $force_set = false ) { // Set data for entire collection - if ( is_array($item) ) { - $this->data = wp_parse_args($item, $this->data); + if ( is_array( $item ) ) { + $this->data = wp_parse_args( $item, $this->data ); // Update save option $args = func_get_args(); - if ( 2 == count($args) && is_bool($args[1]) ) { + if ( 2 === count( $args ) && is_bool( $args[1] ) ) { $save = $args[1]; } - } - // Get $item's ID - elseif ( is_object($item) && method_exists($item, 'get_id') ) + } elseif ( is_object( $item ) && method_exists( $item, 'get_id' ) ) { + // Get $item's ID $item = $item->get_id(); + } // Set data - if ( is_string($item) && !empty($item) && ( isset($this->items[$item]) || !!$force_set ) ) - $this->data[$item] = $value; - if ( !!$save ) + if ( is_string( $item ) && ! empty( $item ) && ( isset( $this->items[ $item ] ) || ! ! $force_set ) ) { + $this->data[ $item ] = $value; + } + if ( ! ! $save ) { $this->save(); + } } /* Item */ @@ -167,56 +169,58 @@ function set_data($item, $value = '', $save = true, $force_set = false) { * @param bool $update (optional) Update or overwrite existing item (Default: FALSE) * @return object Newly-added item */ - function add($id, $properties = array(), $update = false) { - $item; + function add( $id, $properties = array(), $update = false ) { + $item = null; $args = func_get_args(); - // Properties - foreach ( array_reverse($args) as $arg ) { - if ( is_array($arg) ) { + // Get properties. + foreach ( array_reverse( $args ) as $arg ) { + if ( is_array( $arg ) ) { $properties = $arg; break; } } - if ( !is_array($properties) ) { + if ( ! is_array( $properties ) ) { $properties = array(); } - // Handle item instance + // Prep item. if ( $id instanceof $this->item_type ) { + // Use existing item. $item = $id; - $item->set_properties($properties); - } elseif ( class_exists($this->item_type) ) { - $defaults = array ( - 'parent' => null, - 'group' => null + $item->set_properties( $properties ); + } elseif ( class_exists( $this->item_type ) ) { + // Create new item. + $defaults = array( + 'parent' => null, + 'group' => null, ); - $properties = array_merge($defaults, $properties); - if ( is_string($id) ) { + $properties = array_merge( $defaults, $properties ); + if ( is_string( $id ) ) { $properties['id'] = $id; } - if ( !!$update && $this->has($properties['id']) ) { + if ( ! ! $update && $this->has( $properties['id'] ) ) { // Update existing item - $item = $this->get($properties['id']); - $item->set_properties($properties); + $item = $this->get( $properties['id'] ); + $item->set_properties( $properties ); } else { // Init item $type = $this->item_type; - $item = new $type($properties); + $item = new $type( $properties ); } } - if ( empty($item) || 0 == strlen($item->get_id()) ) { + if ( empty( $item ) || strlen( $item->get_id() ) === 0 ) { return false; } // Set container - $item->set_container($this); + $item->set_container( $this ); // Add item to collection - $this->items[$item->get_id()] = $item; + $this->items[ $item->get_id() ] = $item; - if ( isset($properties['group']) ) { - $this->add_to_group($properties['group'], $item->get_id()); + if ( isset( $properties['group'] ) ) { + $this->add_to_group( $properties['group'], $item->get_id() ); } return $item; @@ -227,21 +231,22 @@ function add($id, $properties = array(), $update = false) { * @param string|object $item Object or item ID to remove * @param bool $save (optional) Whether to save the collection after removing item (Default: YES) */ - function remove($item, $save = true) { + function remove( $item, $save = true ) { // Remove item - if ( $this->has($item) ) { - $item = $this->get($item); + if ( $this->has( $item ) ) { + $item = $this->get( $item ); $item = $item->get_id(); // Remove from items array - unset($this->items[$item]); + unset( $this->items[ $item ] ); // Remove item from groups - $this->remove_from_group($item); + $this->remove_from_group( $item ); } // Remove item data from collection - $this->remove_data($item, false); + $this->remove_data( $item, false ); - if ( !!$save ) + if ( ! ! $save ) { $this->save(); + } } /** @@ -249,56 +254,67 @@ function remove($item, $save = true) { * @param string|object $item Object or item ID to remove * @param bool $save (optional) Whether to save the collection after removing item (Default: YES) */ - function remove_data($item, $save = true) { + function remove_data( $item, $save = true ) { // Get item ID from object - if ( $this->has($item) ) { - $item = $this->get($item); + if ( $this->has( $item ) ) { + $item = $this->get( $item ); $item = $item->get_id(); } // Remove data from data member - if ( is_string($item) && is_array($this->data) ) { - unset($this->data[$item]); - if ( !!$save ) + if ( is_string( $item ) && is_array( $this->data ) ) { + unset( $this->data[ $item ] ); + if ( ! ! $save ) { $this->save(); + } } } /** - * Checks if item exists in the collection - * @param string $item Item ID - * @return bool TRUE if item exists, FALSE otherwise + * Checks if item exists in the collection. + * + * @param string|object $item Item ID or instance. + * @return bool True if item is in collection, False otherwise. */ - function has($item) { - return ( !is_string($item) || empty($item) || is_null($this->get_member_value('items', $item, null)) ) ? false : true; + function has( $item ) { + // Item ID. + if ( is_string( $item ) ) { + return in_array( $item, array_keys( $this->get_items() ), true ); + } + // Item instance. + if ( $item instanceof $this->item_type ) { + $items = $this->get_items( null, false ); + $id = $item->get_id(); + return ( isset( $items[ $id ] ) && $item === $items[ $id ] ); + } + return false; } /** - * Retrieve specified item in collection - * @param string|object $item Item object or ID to retrieve - * @return SLB_Field Specified item + * Retrieve specified item in collection. + * + * @param string|object $item Item ID or instance to retrieve. + * @return SLB_Field|null Specified item. Null if item is not in collection. */ - function get($item, $safe_mode = false) { - if ( $this->has($item) ) { - if ( !is_object($item) || !($item instanceof $this->item_type) ) { - if ( is_string($item) ) { - $item = trim($item); - $item =& $this->items[$item]; - } - else { - $item = false; - } + function get( $item, $safe_mode = false ) { + $invalid = null; + // Stop processing if item is not in collection. + if ( ! $this->has( $item ) ) { + return $invalid; + } + // Get item instance from ID. + if ( is_string( $item ) ) { + $items = $this->get_items( null, false ); + if ( isset( $items[ $item ] ) ) { + $item = $items[ $item ]; } - } else { - $item = false; } - - if ( !!$safe_mode && !is_object($item) ) { - // Fallback: Return empty item if no item exists - $type = $this->item_type; - $item = new $type(''); + // Return valid item instance. + if ( $item instanceof $this->item_type ) { + return $item; } - return $item; + // Invalid item. + return $invalid; } /** @@ -306,20 +322,21 @@ function get($item, $safe_mode = false) { * @param $item Item to get data for * @param $context (optional) Context * @param $top (optional) Iterate through ancestors to get data (Default: Yes) - * @return mixed Item data + * @return mixed|null Item data. Null if no data retrieved. */ - function get_data($item = null, $context = '', $top = true) { + function get_data( $item = null, $context = '', $top = true ) { $this->load_data(); $ret = null; - if ( $this->has($item) ) { - $item = $this->get($item); - $ret = $item->get_data($context, $top); + if ( $this->has( $item ) ) { + $item = $this->get( $item ); + $ret = $item->get_data( $context, $top ); } else { - $ret = parent::get_data($context, $top); + $ret = parent::get_data( $context, $top ); } - if ( is_string($item) && is_array($ret) && isset($ret[$item]) ) - $ret = $ret[$item]; + if ( is_string( $item ) && is_array( $ret ) && isset( $ret[ $item ] ) ) { + $ret = $ret[ $item ]; + } return $ret; } @@ -333,14 +350,14 @@ function get_data($item = null, $context = '', $top = true) { * > Val (array): Item properties * @return void */ - function add_items($items = array(), $update = false) { + function add_items( $items = array(), $update = false ) { // Validate - if ( !is_array($items) || empty($items) ) { + if ( ! is_array( $items ) || empty( $items ) ) { return false; } // Add items foreach ( $items as $id => $props ) { - $this->add($id, $props, $update); + $this->add( $id, $props, $update ); } } @@ -348,28 +365,28 @@ function add_items($items = array(), $update = false) { * Retrieve reference to items in collection * @return array Collection items (reference) */ - function &get_items($group = null, $sort = 'priority') { - $gset = $this->group_exists($group); + function &get_items( $group = null, $sort = 'priority' ) { + $gset = $this->group_exists( $group ); if ( $gset ) { - $items = $this->get_group_items($group); - } elseif ( !empty($group) ) { + $items = $this->get_group_items( $group ); + } elseif ( ! empty( $group ) ) { $items = array(); } else { $items = $this->items; } - if ( !empty($items) ) { + if ( ! empty( $items ) ) { // Sort items - if ( !empty($sort) && is_string($sort) ) { - if ( 'priority' == $sort ) { + if ( ! empty( $sort ) && is_string( $sort ) ) { + if ( 'priority' === $sort ) { if ( $gset ) { // Sort by priority - ksort($items, SORT_NUMERIC); + ksort( $items, SORT_NUMERIC ); } } } // Release from buckets if ( $gset ) { - $items = call_user_func_array('array_merge', $items); + $items = call_user_func_array( 'array_merge', $items ); } } return $items; @@ -380,22 +397,39 @@ function &get_items($group = null, $sort = 'priority') { * If no group specified, all items in collection are built * @param string|object $group (optional) Group to build items for (ID or instance object) */ - function build_items($group = null) { + function build_items( $group = null ) { // Get group items - $items =& $this->get_items($group); - if ( empty($items) ) { + $items =& $this->get_items( $group ); + if ( empty( $items ) ) { return false; } - $this->util->do_action_ref_array('build_items_pre', array($this)); + $this->util->do_action_ref_array( 'build_items_pre', array( $this ) ); foreach ( $items as $item ) { $item->build(); } - $this->util->do_action_ref_array('build_items_post', array($this)); + $this->util->do_action_ref_array( 'build_items_post', array( $this ) ); } /* Group */ + /** + * Sanitizes group ID. + * + * @param string $id Group ID. + * @param bool $fallback Optional. Use fallback group if ID is invalid. Default true. + * @return string Sanitized group ID. + */ + protected function sanitize_group_id( $id, $fallback = true ) { + // Sanitize. + $id = sanitize_title_with_dashes( $id ); + // Use default ID (fallback). + if ( strlen( $id ) === 0 && ! ! $fallback ) { + $id = 'default'; + } + return $id; + } + /** * Add groups to collection * @param array $groups Associative array of group properties @@ -403,14 +437,14 @@ function build_items($group = null) { * > Key (string): group ID * > Val (string): Group Title */ - function add_groups($groups = array(), $update = false) { + function add_groups( $groups = array(), $update = false ) { // Validate - if ( !is_array($groups) || empty($groups) ) { + if ( ! is_array( $groups ) || empty( $groups ) ) { return false; } // Iterate foreach ( $groups as $id => $props ) { - $this->add_group($id, $props, null, $update); + $this->add_group( $id, $props, null, $update ); } } @@ -423,196 +457,236 @@ function add_groups($groups = array(), $update = false) { * @param array $items (optional) ID's of existing items to add to group * @return object Group object */ - function &add_group($id, $properties = array(), $items = array(), $update = false) { + function &add_group( $id, $properties = array(), $items = array(), $update = false ) { // Create new group and set properties - $default = array ( - 'title' => '', - 'description' => '', - 'priority' => 10 + $default = array( + 'title' => '', + 'description' => '', + 'priority' => 10, ); - $p = ( is_array($properties) ) ? array_merge($default, $properties) : $default; - if ( !is_int($p['priority']) || $p['priority'] < 0 ) { + $p = ( is_array( $properties ) ) ? array_merge( $default, $properties ) : $default; + if ( ! is_int( $p['priority'] ) || $p['priority'] < 0 ) { $p['priority'] = $default['priority']; } - $id = trim($id); + $id = $this->sanitize_group_id( $id ); // Retrieve or init group - if ( !!$update && $this->group_exists($id) ) { - $grp = $this->get_group($id); - $grp->title = $p['title']; + if ( ! ! $update && $this->group_exists( $id ) ) { + $grp = $this->get_group( $id ); + $grp->title = $p['title']; $grp->description = $p['description']; - $grp->priority = $p['priority']; + $grp->priority = $p['priority']; } else { - $this->groups[$id] =& $this->create_group($id, $p['title'], $p['description'], $p['priority']); + $this->groups[ $id ] =& $this->create_group( $id, $p['title'], $p['description'], $p['priority'] ); } // Add items to group (if supplied) - if ( !empty($items) && is_array($items) ) { - $this->add_to_group($id, $items); + if ( ! empty( $items ) && is_array( $items ) ) { + $this->add_to_group( $id, $items ); } - return $this->groups[$id]; + return $this->groups[ $id ]; } /** * Remove specified group from collection * @param string $id Group ID to remove */ - function remove_group($id) { - $id = trim($id); - if ( $this->group_exists($id) ) { - unset($this->groups[$id]); + function remove_group( $id ) { + $id = trim( $id ); + if ( $this->group_exists( $id ) ) { + unset( $this->groups[ $id ] ); } } /** - * Standardized method to create a new item group + * Creates a new item group. + * * @param string $title Group title (used in meta boxes, etc.) * @param string $description Short description of group's purpose * @param int $priority (optional) Group priority (e.g. used to sort groups during output) - * @return object Group object - */ - function &create_group($id = '', $title = '', $description = '', $priority = 10) { + * @return object { + * Group object. + * + * @type string $id ID. + * @type string $title Title. + * @type string $description Description. + * @type int $priority Priority (relative to other groups in collection). + * @type array $items { + * Group items. Grouped by item priority. + * Items indexed by item ID. + * Example: `$items[10]['item_id'] = {item} + * } + * } + */ + function &create_group( $id = '', $title = '', $description = '', $priority = 10 ) { // Create new group object $group = new stdClass(); /* Set group properties */ // Set ID - $id = ( is_scalar($id) ) ? trim($id) : ''; + $id = ( is_scalar( $id ) ) ? trim( $id ) : ''; $group->id = $id; // Set Title - $title = ( is_scalar($title) ) ? trim($title) : ''; + $title = ( is_scalar( $title ) ) ? trim( $title ) : ''; $group->title = $title; // Set Description - $description = ( is_scalar($description) ) ? trim($description) : ''; + $description = ( is_scalar( $description ) ) ? trim( $description ) : ''; $group->description = $description; // Priority - $group->priority = ( is_int($priority) ) ? $priority : 10; + $group->priority = ( is_int( $priority ) ) ? $priority : 10; // Create array to hold items $group->items = array(); return $group; } /** - * Checks if group exists in collection - * @param string $id Group name - * @return bool TRUE if group exists, FALSE otherwise + * Checks if group exists in collection. + * + * @param string|object $id Group name or object. + * @return bool True if group exists, False otherwise. */ - function group_exists($group) { - $ret = false; - if ( is_object($group) ) { - $ret = true; - } elseif ( is_string($group) && ($group = trim($group)) && strlen($group) > 0 ) { - $group = trim($group); - // Check if group exists - $ret = !is_null($this->get_member_value('groups', $group, null)); + function group_exists( $group ) { + if ( is_object( $group ) ) { + return true; } - return $ret; - } - - /** - * Adds item to a group in the collection - * Group is created if it does not already exist - * @param string|array $group ID of group (or group parameters if new group) to add item to - * @param string|array $items Name or array of item(s) to add to group - */ - function add_to_group($group, $items, $priority = 10) { - // Validate - if ( empty($items) || empty($group) || ( !is_string($group) && !is_array($group) ) ) { + if ( ! is_string( $group ) ) { return false; } - - // Get group ID - if ( is_string($group) ) { - $group = array($group, $priority); + $group = $this->sanitize_group_id( $group ); + if ( strlen( $group ) === 0 ) { + return false; } - list($gid, $priority) = $group; - $gid = trim(sanitize_title_with_dashes($gid)); - if ( empty($gid) ) { + // Check if group exists + return ( ! is_null( $this->get_member_value( 'groups', $group, null ) ) ); + } + + /** + * Adds item to a group in the collection. + * + * Group is created if it does not already exist. + * + * @param string|array $group { + * Group ID (or parameters array) to add item to. + * + * Array structure: + * + * @type string $0 Group ID. + * @type int $1 Item priority in group. + * } + * @param string|object|array $items Item ID/Instance or array of items to add to group. + * @param int $priority Optional. Default priority to set for items in group. Default 10. + * @return bool True if item(s) successfully added to group. + * False if item(s) not added to group. + */ + function add_to_group( $group, $items, $priority = 10 ) { + // Validate. + if ( empty( $items ) || empty( $group ) || ( ! is_string( $group ) && ! is_array( $group ) ) ) { return false; } - // Item priority - if ( !is_int($priority) ) { - $priority = 10; + // Parse group properties. + if ( is_string( $group ) ) { + $gid = $group; + } elseif ( is_array( $group ) ) { + $group = array_values( $group ); + if ( count( $group ) < 2 ) { + $group[] = $priority; + } + list( $gid, $priority ) = $group; } - // Prepare group - if ( !$this->group_exists($gid) ) { - // TODO Follow - call_user_func($this->m('add_group'), $gid, $group); + // Format group ID. + $gid = $this->sanitize_group_id( $gid ); + if ( strlen( $gid ) === 0 ) { + return false; } + + // Item priority. + $priority = (int) $priority; + // Prepare items - if ( !is_array($items) ) { - $items = array($items); + if ( ! is_array( $items ) ) { + $items = [ $items ]; } - // Add Items + + // Add Items. + $items_skipped = []; foreach ( $items as $item ) { - // Skip if not in current collection - $itm_ref = $this->get($item); - if ( !$itm_ref ) { + // Skip if item is not in current collection. + $itm_ref = $this->get( $item ); + if ( ! $itm_ref ) { + $items_skipped[] = $item; continue; } - $itm_id = $itm_ref->get_id(); - // Remove item from any other group it's in (items can only be in one group) - foreach ( $this->get_groups() as $group ) { - foreach ( $group->items as $tmp_pri => $tmp_items ) { - if ( isset($group->items[$tmp_pri][$itm_id]) ) { - unset($group->items[$tmp_pri][$itm_id]); - } - } - } - // Add reference to item in group - $items =& $this->get_group($gid)->items; - if ( !isset($items[$priority]) ) { - $items[$priority] = array(); + // Remove item from all groups (items can only be in one group). + $this->remove_from_group( $itm_ref ); + // Add reference to item in group. + $items =& $this->get_group( $gid )->items; + // Ensure priority level exists for group. + if ( ! isset( $items[ $priority ] ) ) { + $items[ $priority ] = array(); } - $items[$priority][$itm_id] = $itm_ref; + // Add item to group. + $items[ $priority ][ $itm_ref->get_id() ] = $itm_ref; } - unset($itm_ref); + unset( $itm_ref ); + return ( count( $items_skipped ) < count( $items ) ); } /** - * Remove item from a group - * If no group is specified, then item is removed from all groups - * @param string|object $item Object or ID of item to remove from group - * @param string $group (optional) Group ID to remove item from + * Removes item from a group. + * + * If group is not specified, item is removed from all groups. + * + * @param string|object $item ID or object of item to remove from group. + * @param string|object|array $groups Optional. Group(s) to remove item from. Default null. + * - @type string Group ID. + * - @type object Group object. + * - @type array Multiple groups (ID or object). + * @return void */ - function remove_from_group($item, $group = '') { - // Get ID of item to remove or stop execution if item invalid - $item = $this->get($item); + function remove_from_group( $item, $groups = null ) { + // Validate item. + $item = $this->get( $item ); + if ( ! $item ) { + return; + } + // Get item ID. $item = $item->get_id(); - if ( !$item ) - return false; + // Validate item ID. + if ( ! $item ) { + return; + } - // Remove item from group - if ( !empty($group) ) { - // Remove item from single group - if ( ($group =& $this->get_group($group)) && isset($group->items[$item]) ) { - unset($group->items[$item]); - } - } else { - // Remove item from all groups - foreach ( array_keys($this->groups) as $group ) { - if ( ($group =& $this->get_group($group)) && isset($group->items[$item]) ) { - unset($group->items[$item]); - } + // Setup groups. + if ( is_string( $groups ) || is_object( $groups ) ) { + $groups = [ $groups ]; + } elseif ( ! is_array( $groups ) ) { + $groups = array_keys( $this->get_groups() ); + } + + // Remove item from group(s). + foreach ( $groups as $group ) { + $group = $this->get_group( $group ); + foreach ( array_keys( $group->items ) as $priority ) { + unset( $group->items[ $priority ][ $item ] ); } } } /** - * Retrieve specified group - * @param string $group ID of group to retrieve - * @return object Reference to specified group + * Retrieves specified group. + * + * @param string|object $group Group ID or object to retrieve. + * @return object Reference to specified group. */ - function &get_group($group) { - if ( is_object($group) ) { + function &get_group( $group ) { + if ( is_object( $group ) ) { return $group; } - if ( is_string($group) ) { - $group = trim($group); - } - // Create group if it doesn't already exist - if ( ! $this->group_exists($group) ) { - $this->add_group($group); + // Create group if it doesn't already exist. + if ( ! $this->group_exists( $group ) ) { + return $this->add_group( $group ); } - return $this->get_member_value('groups', $group); + // Get existing group. + $group = $this->sanitize_group_id( $group ); + return $this->get_member_value( 'groups', $group ); } /** @@ -621,31 +695,31 @@ function &get_group($group) { * @param object|string $group Group object or group ID * @return array Group's items */ - function &get_group_items($group) { - $group =& $this->get_group($group); + function &get_group_items( $group ) { + $group =& $this->get_group( $group ); return $group->items; } /** * Retrieve all groups in collection - * @return array Reference to group objects - */ - function &get_groups($opts = array()) { - $groups =& $this->get_member_value('groups'); - if ( is_array($opts) && !empty($opts) ) { - extract($opts, EXTR_SKIP); - if ( !empty($groups) && !empty($sort) && is_string($sort) ) { - if ( property_exists(current($groups), $sort) ) { + * @return object[] Reference to group objects + */ + function &get_groups( $opts = array() ) { + $groups =& $this->get_member_value( 'groups' ); + if ( is_array( $opts ) && ! empty( $opts ) ) { + extract( $opts, EXTR_SKIP ); + if ( ! empty( $groups ) && ! empty( $sort ) && is_string( $sort ) ) { + if ( property_exists( current( $groups ), $sort ) ) { // Sort groups by property - $sfunc = function ( $a, $b ) use ($sort) { + $sfunc = function ( $a, $b ) use ( $sort ) { $ap = $a->$sort; $bp = $b->$sort; - if ( $ap == $bp ) { + if ( $ap === $bp ) { return 0; } return ( $ap > $bp ) ? 1 : -1; }; - uasort($groups, $sfunc); + uasort( $groups, $sfunc ); } } } @@ -657,45 +731,45 @@ function &get_groups($opts = array()) { * @uses self::build_vars to determine groups to build */ function build_groups() { - $this->util->do_action_ref_array('build_groups_pre', array($this)); + $this->util->do_action_ref_array( 'build_groups_pre', array( $this ) ); // Get groups to build - $groups = ( !empty($this->build_vars['groups']) ) ? $this->build_vars['groups'] : array_keys($this->get_groups(array('sort' => 'priority'))); + $groups = ( ! empty( $this->build_vars['groups'] ) ) ? $this->build_vars['groups'] : array_keys( $this->get_groups( array( 'sort' => 'priority' ) ) ); // Check options - if ( is_callable($this->build_vars['build_groups']) ) { + if ( is_callable( $this->build_vars['build_groups'] ) ) { // Pass groups to callback to build output - call_user_func_array($this->build_vars['build_groups'], array($this, $groups)); - } elseif ( !!$this->build_vars['build_groups'] ) { + call_user_func_array( $this->build_vars['build_groups'], array( $this, $groups ) ); + } elseif ( ! ! $this->build_vars['build_groups'] ) { // Build groups foreach ( $groups as $group ) { - $this->build_group($group); + $this->build_group( $group ); } } - $this->util->do_action_ref_array('build_groups_post', array($this)); + $this->util->do_action_ref_array( 'build_groups_post', array( $this ) ); } /** * Build group */ - function build_group($group) { - if ( !$this->group_exists($group) ) { + function build_group( $group ) { + if ( ! $this->group_exists( $group ) ) { return false; } - $group =& $this->get_group($group); + $group =& $this->get_group( $group ); // Stop processing if group contains no items - if ( !count($this->get_items($group)) ) { + if ( ! count( $this->get_items( $group ) ) ) { return false; } // Pre action - $this->util->do_action_ref_array('build_group_pre', array($this, $group)); + $this->util->do_action_ref_array( 'build_group_pre', array( $this, $group ) ); // Build items - $this->build_items($group); + $this->build_items( $group ); // Post action - $this->util->do_action_ref_array('build_group_post', array($this, $group)); + $this->util->do_action_ref_array( 'build_group_post', array( $this, $group ) ); } /* Collection */ @@ -704,16 +778,16 @@ function build_group($group) { * Build entire collection of items * Prints output */ - function build($build_vars = array()) { + function build( $build_vars = array() ) { // Parse vars - $this->parse_build_vars($build_vars); - $this->util->do_action_ref_array('build_init', array($this)); + $this->parse_build_vars( $build_vars ); + $this->util->do_action_ref_array( 'build_init', array( $this ) ); // Pre-build output - $this->util->do_action_ref_array('build_pre', array($this)); + $this->util->do_action_ref_array( 'build_pre', array( $this ) ); // Build groups $this->build_groups(); // Post-build output - $this->util->do_action_ref_array('build_post', array($this)); + $this->util->do_action_ref_array( 'build_post', array( $this ) ); } /** @@ -721,8 +795,8 @@ function build($build_vars = array()) { * @param string $key Variable name * @param mixed $val Variable value */ - function set_build_var($key, $val) { - $this->build_vars[$key] = $val; + function set_build_var( $key, $val ) { + $this->build_vars[ $key ] = $val; } /** @@ -731,17 +805,17 @@ function set_build_var($key, $val) { * @param mixed $default Value if variable is not set * @return mixed Variable value */ - function get_build_var($key, $default = null) { - return ( array_key_exists($key, $this->build_vars) ) ? $this->build_vars[$key] : $default; + function get_build_var( $key, $default = null ) { + return ( array_key_exists( $key, $this->build_vars ) ) ? $this->build_vars[ $key ] : $default; } /** * Delete build variable * @param string $key Variable name to delete */ - function delete_build_var($key) { - if ( array_key_exists($key, $this->build_vars) ) { - unset($this->build_vars[$key]); + function delete_build_var( $key ) { + if ( array_key_exists( $key, $this->build_vars ) ) { + unset( $this->build_vars[ $key ] ); } } @@ -750,19 +824,19 @@ function delete_build_var($key) { * @uses this->reset_build_vars() to reset build variables for each request * @param array $build_vars Variables to use for current request */ - function parse_build_vars($build_vars = array()) { + function parse_build_vars( $build_vars = array() ) { $this->reset_build_vars(); - $this->build_vars = $this->util->apply_filters('parse_build_vars', wp_parse_args($build_vars, $this->build_vars), $this); + $this->build_vars = $this->util->apply_filters( 'parse_build_vars', wp_parse_args( $build_vars, $this->build_vars ), $this ); } /** * Reset build variables to defaults * Default Variables - * > groups - array - Names of groups to build - * > context - string - Context of current request - * > layout - string - Name of default layout to use + * > groups - array - Names of groups to build + * > context - string - Context of current request + * > layout - string - Name of default layout to use */ function reset_build_vars() { - $this->build_vars = wp_parse_args($this->build_vars, $this->build_vars_default); + $this->build_vars = wp_parse_args( $this->build_vars, $this->build_vars_default ); } -} \ No newline at end of file +} diff --git a/includes/class.field_type.php b/includes/class.field_type.php index 410a6a4..f6fcd39 100644 --- a/includes/class.field_type.php +++ b/includes/class.field_type.php @@ -12,39 +12,40 @@ class SLB_Field_Type extends SLB_Field_Base { /** * @var array Array of Field types that make up current Field type */ - var $elements = array(); + public $elements = array(); /** * @var array Field type layouts */ - var $layout = array(); + public $layout = array(); /** * @var SLB_Field_Type Parent field type (reference) */ - var $parent = null; + public $parent = null; /** * Object that field is in * @var SLB_Field|SLB_Field_Type|SLB_Field_Collection */ - var $container = null; + public $container = null; /** * Object that called field * Used to determine field hierarchy/nesting * @var SLB_Field|SLB_Field_Type|SLB_Field_Collection */ - var $caller = null; + public $caller = null; - function __construct($id = '', $parent = null) { - $args = func_get_args(); - $defaults = $this->integrate_id($id); - if ( !is_array($parent) ) + function __construct( $id = '', $parent = null ) { + $args = func_get_args(); + $defaults = $this->integrate_id( $id ); + if ( ! is_array( $parent ) ) { $defaults['parent'] = $parent; + } - $props = $this->make_properties($args, $defaults); - parent::__construct($props); + $props = $this->make_properties( $args, $defaults ); + parent::__construct( $props ); } /* Getters/Setters */ @@ -55,9 +56,9 @@ function __construct($id = '', $parent = null) { * @param string $name Value to retrieve from member * @return mixed Member value if found (Default: empty string) */ - function get_container_value($member, $name = '', $default = '') { + function get_container_value( $member, $name = '', $default = '' ) { $container =& $this->get_container(); - return $this->get_object_value($container, $member, $name, $default, 'container'); + return $this->get_object_value( $container, $member, $name, $default, 'container' ); } /** @@ -66,9 +67,9 @@ function get_container_value($member, $name = '', $default = '') { * @param string $name Value to retrieve from member * @return mixed Member value if found (Default: empty string) */ - function get_caller_value($member, $name = '', $default = '') { + function get_caller_value( $member, $name = '', $default = '' ) { $caller =& $this->get_caller(); - return $this->get_object_value($caller, $member, $name, $default, 'caller'); + return $this->get_object_value( $caller, $member, $name, $default, 'caller' ); } /** @@ -76,8 +77,8 @@ function get_caller_value($member, $name = '', $default = '') { * Reference is cleared if no valid object is passed to method * @param object $container */ - function set_container(&$container) { - if ( !empty($container) && is_object($container) ) { + function set_container( &$container ) { + if ( ! empty( $container ) && is_object( $container ) ) { // Set as param as container for current field $this->container =& $container; } else { @@ -99,8 +100,9 @@ function clear_container() { */ function &get_container() { $ret = null; - if ( $this->has_container() ) + if ( $this->has_container() ) { $ret =& $this->container; + } return $ret; } @@ -109,7 +111,7 @@ function &get_container() { * @return bool TRUE if field is contained, FALSE otherwise */ function has_container() { - return !empty($this->container); + return ! empty( $this->container ); } /** @@ -117,18 +119,19 @@ function has_container() { * Any existing reference is cleared if no valid object is passed to method * @param object $caller Calling object */ - function set_caller(&$caller) { - if ( !empty($caller) && is_object($caller) ) + function set_caller( &$caller ) { + if ( ! empty( $caller ) && is_object( $caller ) ) { $this->caller =& $caller; - else + } else { $this->clear_caller(); + } } /** * Clears reference to calling object of current field */ function clear_caller() { - unset($this->caller); + unset( $this->caller ); } /** @@ -137,8 +140,9 @@ function clear_caller() { */ function &get_caller() { $ret = null; - if ( $this->has_caller() ) + if ( $this->has_caller() ) { $ret =& $this->caller; + } return $ret; } @@ -147,7 +151,7 @@ function &get_caller() { * @return bool TRUE if field is called by another field, FALSE otherwise */ function has_caller() { - return !empty($this->caller); + return ! empty( $this->caller ); } /** @@ -157,18 +161,19 @@ function has_caller() { * @param array $properties Properties for element (passed as keyed associative array) * @param string $id_prop Name of property to set $name to (e.g. ID, etc.) */ - function set_element($name, $type, $properties = array(), $id_prop = 'id') { - $name = trim(strval($name)); - if ( empty($name) ) + function set_element( $name, $type, $properties = array(), $id_prop = 'id' ) { + $name = trim( strval( $name ) ); + if ( empty( $name ) ) { return false; + } // Create new field for element - $el = new SLB_Field($name, $type); + $el = new SLB_Field( $name, $type ); // Set container to current field instance - $el->set_container($this); + $el->set_container( $this ); // Add properties to element - $el->set_properties($properties); + $el->set_properties( $properties ); // Save element to current instance - $this->elements[$name] =& $el; + $this->elements[ $name ] =& $el; } /** @@ -176,11 +181,12 @@ function set_element($name, $type, $properties = array(), $id_prop = 'id') { * @param string $name Name of layout * @param string $value Layout text */ - function set_layout($name, $value = '') { - if ( !is_string($name) ) + function set_layout( $name, $value = '' ) { + if ( ! is_string( $name ) ) { return false; - $name = trim($name); - $this->layout[$name] = $value; + } + $name = trim( $name ); + $this->layout[ $name ] = $value; return true; } @@ -190,29 +196,36 @@ function set_layout($name, $value = '') { * @param bool $parse_nested (optional) Whether nested layouts should be expanded in retreived layout or not (Default: TRUE) * @return string Specified layout text */ - function get_layout($name = 'form', $parse_nested = true) { + function get_layout( $name = 'form', $parse_nested = true ) { // Retrieve specified layout (use $name value if no layout by that name exists) - if ( empty($name) ) - $name = $this->get_container_value('build_vars', 'layout', 'form'); - $layout = $this->get_member_value('layout', $name, $name); + if ( empty( $name ) ) { + $name = $this->get_container_value( 'build_vars', 'layout', 'form' ); + } + $layout = $this->get_member_value( 'layout', $name, $name ); // Find all nested layouts in current layout - if ( !empty($layout) && !!$parse_nested ) { + if ( ! empty( $layout ) && ! ! $parse_nested ) { $ph = $this->get_placeholder_defaults(); - - while ($ph->match = $this->parse_layout($layout, $ph->pattern_layout)) { + // Check layout for placeholders. + $ph->match = $this->parse_layout( $layout, $ph->pattern_layout ); + while ( ! empty( $ph->match ) ) { // Iterate through the different types of layout placeholders - foreach ($ph->match as $tag => $instances) { + foreach ( $ph->match as $tag => $instances ) { // Iterate through instances of a specific type of layout placeholder - foreach ($instances as $instance) { + foreach ( $instances as $instance ) { // Get nested layout - $nested_layout = $this->get_member_value($instance); + $nested_layout = $this->get_member_value( $instance ); + + if ( empty( $nested_layout ) ) { + continue; + } - // Replace layout placeholder with retrieved item data - if ( !empty($nested_layout) ) - $layout = str_replace($ph->start . $instance['match'] . $ph->end, $nested_layout, $layout); + // Replace layout placeholder with retrieved item data. + $layout = str_replace( $ph->start . $instance['match'] . $ph->end, $nested_layout, $layout ); } } + // Check layout for placeholders. + $ph->match = $this->parse_layout( $layout, $ph->pattern_layout ); } } @@ -220,20 +233,19 @@ function get_layout($name = 'form', $parse_nested = true) { } /** - * Checks if specified layout exists - * Finds layout if it exists in current object or any of its parents - * @param string $layout Name of layout to check for - * @return bool TRUE if layout exists, FALSE otherwise + * Checks if specified layout exists. + * + * Finds layout if it exists in current object or any of its parents. + * + * @param string $layout Name of layout to check for. + * @return bool True if layout exists, False otherwise. */ - function has_layout($layout) { - $ret = false; - if ( is_string($layout) && ($layout = trim($layout)) && !empty($layout) ) { - $layout = $this->get_member_value('layout', $layout, false); - if ( $layout !== false ) - $ret = true; + function has_layout( $layout ) { + if ( is_string( $layout ) && ! empty( trim( $layout ) ) ) { + return false; } - - return $ret; + $layout = $this->get_member_value( 'layout', trim( $layout ), false ); + return ( false !== $layout ); } /** @@ -242,9 +254,9 @@ function has_layout($layout) { * @param string $layout_content Layout content (markup) * @return bool TRUE if layout is valid, FALSE otherwise */ - function is_valid_layout($layout_content) { + function is_valid_layout( $layout_content ) { $ph = $this->get_placeholder_defaults(); - return preg_match($ph->pattern_general, $layout_content); + return preg_match( $ph->pattern_general, $layout_content ); } /** @@ -252,16 +264,16 @@ function is_valid_layout($layout_content) { * @param string $layout Layout data * @param string $search Regular expression pattern to search layout for * @return array Associative array containing all of the regular expression matches in the layout data - * Array Structure: - * root => placeholder tags - * => Tag instances (array) - * 'tag' => (string) tag name - * 'match' => (string) placeholder match - * 'attributes' => (array) attributes + * Array Structure: + * root => placeholder tags + * => Tag instances (array) + * 'tag' => (string) tag name + * 'match' => (string) placeholder match + * 'attributes' => (array) attributes */ - function parse_layout($layout, $search) { + function parse_layout( $layout, $search ) { $parse_match = ''; - $result = []; + $result = []; // Find all nested layouts in layout. $match_value = preg_match_all( $search, $layout, $parse_match, PREG_PATTERN_ORDER ); @@ -273,13 +285,13 @@ function parse_layout($layout, $search) { /* Process matches */ - $ph_xml = ''; - $ph_root_tag = 'ph_root_element'; - $ph_start_xml = '<'; - $ph_end_xml = ' />'; + $ph_xml = ''; + $ph_root_tag = 'ph_root_element'; + $ph_start_xml = '<'; + $ph_end_xml = ' />'; $ph_wrap_start = '<' . $ph_root_tag . '>'; - $ph_wrap_end = ''; - $parse_result = []; + $ph_wrap_end = ''; + $parse_result = []; // Get all matched elements. $parse_match = $parse_match[1]; @@ -291,17 +303,17 @@ function parse_layout($layout, $search) { $ph_xml = $ph_wrap_start . $ph_xml . $ph_wrap_end; // Parse XML data. $ph_prs = xml_parser_create(); - xml_parser_set_option($ph_prs, XML_OPTION_SKIP_WHITE, 1); - xml_parser_set_option($ph_prs, XML_OPTION_CASE_FOLDING, 0); - $ph_parsed = xml_parse_into_struct($ph_prs, $ph_xml, $parse_result['values'], $parse_result['index']); - xml_parser_free($ph_prs); + xml_parser_set_option( $ph_prs, XML_OPTION_SKIP_WHITE, 1 ); + xml_parser_set_option( $ph_prs, XML_OPTION_CASE_FOLDING, 0 ); + $ph_parsed = xml_parse_into_struct( $ph_prs, $ph_xml, $parse_result['values'], $parse_result['index'] ); + xml_parser_free( $ph_prs ); // Stop if placeholder parsing failed. if ( ! $ph_parsed ) { return $result; } - unset( $parse_result['index'][$ph_root_tag] ); + unset( $parse_result['index'][ $ph_root_tag ] ); // Build structured array with all parsed data. $ph_default = [ @@ -317,12 +329,12 @@ function parse_layout($layout, $search) { // Process placeholder instances. foreach ( $instances as $instance ) { // Skip instance if it doesn't exist in parse results. - if ( !isset( $parse_result['values'][ $instance ] ) ) { + if ( ! isset( $parse_result['values'][ $instance ] ) ) { continue; } // Stop processing instance if a previously-saved instance with the same options already exists. foreach ( $result[ $tag ] as $tag_match ) { - if ( $tag_match['match'] == $parse_match[ $instance - 1 ] ) { + if ( $tag_match['match'] === $parse_match[ $instance - 1 ] ) { continue 2; } } @@ -354,12 +366,12 @@ function parse_layout($layout, $search) { * @return object Object with properties for evaluating layout placeholders */ function get_placeholder_defaults() { - $ph = new stdClass(); - $ph->start = '{'; - $ph->end = '}'; - $ph->reserved = array('ref' => 'ref_base'); + $ph = new stdClass(); + $ph->start = '{'; + $ph->end = '}'; + $ph->reserved = array( 'ref' => 'ref_base' ); $ph->pattern_general = '/' . $ph->start . '([a-zA-Z0-9_].*?)' . $ph->end . '/i'; - $ph->pattern_layout = '/' . $ph->start . '([a-zA-Z0-9].*?\s+' . $ph->reserved['ref'] . '="layout.*?".*?)' . $ph->end . '/i'; + $ph->pattern_layout = '/' . $ph->start . '([a-zA-Z0-9].*?\s+' . $ph->reserved['ref'] . '="layout.*?".*?)' . $ph->end . '/i'; return $ph; } @@ -368,10 +380,10 @@ function get_placeholder_defaults() { * @param string $layout (optional) Layout to build * @param string $data Data to pass to layout */ - function build($layout = null, $data = null) { - $this->util->do_action_ref_array('build_pre', array($this)); - echo $this->build_layout($layout, $data); - $this->util->do_action_ref_array('build_post', array($this)); + function build( $layout = null, $data = null ) { + $this->util->do_action_ref_array( 'build_pre', array( $this ) ); + echo $this->build_layout( $layout, $data ); + $this->util->do_action_ref_array( 'build_post', array( $this ) ); } /** @@ -379,18 +391,18 @@ function build($layout = null, $data = null) { * @param string $layout (optional) Name of layout to build * @param array $data Additional data for current item */ - function build_layout($layout = 'form', $data = null) { + function build_layout( $layout = 'form', $data = null ) { $out_default = ''; // Get base layout - $out = $this->get_layout($layout); + $out = $this->get_layout( $layout ); // Only parse valid layouts - if ( $this->is_valid_layout($out) ) { + if ( $this->is_valid_layout( $out ) ) { $out = $this->process_placeholders( $out, $layout, $data ); } else { $out = $out_default; } /* Return generated value */ - $out = $this->format_final($out); + $out = $this->format_final( $out ); return $out; } @@ -410,8 +422,11 @@ public function process_placeholders( $str, $layout = 'form', $data = null ) { // Parse Layout. $ph = $this->get_placeholder_defaults(); - // Search layout for placeholders. - while ( $ph->match = $this->parse_layout( $str, $ph->pattern_general ) ) { + // Check layout for placeholders. + $ph->match = $this->parse_layout( $str, $ph->pattern_general ); + + // Parse placeholders in layout. + while ( ! empty( $ph->match ) ) { // Iterate through placeholders (tag, id, etc.) foreach ( $ph->match as $tag => $instances ) { // Iterate through instances of current placeholder @@ -432,14 +447,16 @@ public function process_placeholders( $str, $layout = 'form', $data = null ) { } // Clear value if value not a string - if ( !is_scalar( $target_property ) ) { + if ( ! is_scalar( $target_property ) ) { $target_property = ''; } // Replace layout placeholder with retrieved item data $str = str_replace( $ph->start . $instance['match'] . $ph->end, $target_property, $str ); } } + // Check layout for placeholders. + $ph->match = $this->parse_layout( $str, $ph->pattern_general ); } return $str; } -} \ No newline at end of file +} diff --git a/includes/class.fields.php b/includes/class.fields.php index 4435db5..4f42e77 100644 --- a/includes/class.fields.php +++ b/includes/class.fields.php @@ -1,446 +1,518 @@ -m('register_types')); - // Init placeholders - add_action('init', $this->m('register_placeholders')); - } - - /* Field Types */ - - /** - * Initialize fields - */ - function register_types() { - /* Field Types */ - - // Base - $base = new SLB_Field_Type('base'); - $base->set_description(__('Default Element', 'simple-lightbox')); - $base->set_property('tag', 'span'); - $base->set_property('class', '', 'attr'); - $base->set_layout('form_attr', '{tag} name="{field_name}" id="{field_id}" {properties ref_base="root" group="attr"}'); - $base->set_layout('form', '<{form_attr ref_base="layout"} />'); - $base->set_layout('label', ''); - $base->set_layout('display', '{data context="display"}'); - $this->add($base); - - // Base closed - $base_closed = new SLB_Field_Type('base_closed'); - $base_closed->set_parent('base'); - $base_closed->set_description(__('Default Element (Closed Tag)', 'simple-lightbox')); - $base_closed->set_layout('form_start', '<{tag} id="{field_id}" name="{field_name}" {properties ref_base="root" group="attr"}>'); - $base_closed->set_layout('form_end', ''); - $base_closed->set_layout('form', '{form_start ref_base="layout"}{data}{form_end ref_base="layout"}'); - $this->add($base_closed); - - // Input - $input = new SLB_Field_Type('input', 'base'); - $input->set_description(__('Default Input Element', 'simple-lightbox')); - $input->set_property('tag', 'input'); - $input->set_property('type', 'text', 'attr'); - $input->set_property('value', '{data}', 'attr'); - $this->add($input); - - // Text input - $text = new SLB_Field_Type('text', 'input'); - $text->set_description(__('Text Box', 'simple-lightbox')); - $text->set_property('size', 15, 'attr'); - $text->set_property('label'); - $text->set_layout('form', '{label ref_base="layout"} {inherit}'); - $this->add($text); - - // Checkbox - $cb = new SLB_Field_Type('checkbox', 'input'); - $cb->set_property('type', 'checkbox'); - $cb->set_property('value', null); - $cb->set_layout('form_attr', '{inherit} {checked}'); - $cb->set_layout('form', '{label ref_base="layout"} <{form_attr ref_base="layout"} />'); - $this->add($cb); - - // Textarea - $ta = new SLB_Field_Type('textarea', 'base_closed'); - $ta->set_property('tag', 'textarea'); - $ta->set_property('cols', 40, 'attr'); - $ta->set_property('rows', 3, 'attr'); - $this->add($ta); - - // Rich Text - $rt = new SLB_Field_Type('richtext', 'textarea'); - $rt->set_property('class', 'theEditor {inherit}'); - $rt->set_layout('form', '
{inherit}
'); - $rt->add_action('admin_print_footer_scripts', 'wp_tiny_mce', 25); - $this->add($rt); - - // Hidden - $hidden = new SLB_Field_Type('hidden'); - $hidden->set_parent('input'); - $hidden->set_description(__('Hidden Field', 'simple-lightbox')); - $hidden->set_property('type', 'hidden'); - $this->add($hidden); - - // Select - $select = new SLB_Field_Type('select', 'base_closed'); - $select->set_description(__('Select tag', 'simple-lightbox')); - $select->set_property('tag', 'select'); - $select->set_property('tag_option', 'option'); - $select->set_property('options', array()); - $select->set_layout('form', '{label ref_base="layout"} {form_start ref_base="layout"}{option_loop ref_base="layout"}{form_end ref_base="layout"}'); - $select->set_layout('option_loop', '{loop data="properties.options" layout="option" layout_data="option_data"}'); - $select->set_layout('option', '<{tag_option} value="{data_ext id="option_value" context="attr"}">{data_ext id="option_text" context="text"}'); - $select->set_layout('option_data', '<{tag_option} value="{data_ext id="option_value" context="attr"}" selected="selected">{data_ext id="option_text" context="text"}'); - $this->add($select); - - // Span - $span = new SLB_Field_Type('span', 'base_closed'); - $span->set_description(__('Inline wrapper', 'simple-lightbox')); - $span->set_property('tag', 'span'); - $span->set_property('value', 'Hello there!'); - $this->add($span); - - // Enable plugins to modify (add, remove, etc.) field types - $this->util->do_action_ref_array('register_fields', array($this), false); - - // Signal completion of field registration - $this->util->do_action_ref_array('fields_registered', array($this), false); - } - - /* Placeholder handlers */ - - function register_placeholders() { - // Default placeholder handlers - $this->register_placeholder('all', $this->m('process_placeholder_default'), 11); - $this->register_placeholder('field_id', $this->m('process_placeholder_id')); - $this->register_placeholder('field_name', $this->m('process_placeholder_name')); - $this->register_placeholder('data', $this->m('process_placeholder_data')); - $this->register_placeholder('data_ext',$this->m('process_placeholder_data_ext')); - $this->register_placeholder('loop', $this->m('process_placeholder_loop')); - $this->register_placeholder('label', $this->m('process_placeholder_label')); - $this->register_placeholder('checked', $this->m('process_placeholder_checked')); - - // Allow other code to register placeholders - $this->util->do_action_ref_array('register_field_placeholders', array($this), false); - - // Signal completion of field placeholder registration - $this->util->do_action_ref_array('field_placeholders_registered', array($this), false); - } - - /** - * Register a function to handle a placeholder - * Multiple handlers may be registered for a single placeholder - * Adds filter hook to WP for handling specified placeholder - * Placeholders are in layouts and are replaced with data at runtime - * @uses add_filter() - * @param string $placeholder Name of placeholder to add handler for (Using 'all' will set the function as a handler for all placeholders - * @param callback $callback Function to set as a handler - * @param int $priority (optional) Priority of handler - * @return void - */ - function register_placeholder($placeholder, $callback, $priority = 10) { - if ( 'all' == $placeholder ) - $placeholder = ''; - else - $placeholder = '_' . $placeholder; - $hook = $this->add_prefix('process_placeholder' . $placeholder); - add_filter($hook, $callback, $priority, 5); - } - - /** - * Default placeholder processing - * To be executed when current placeholder has not been handled by another handler - * @param string $output Value to be used in place of placeholder - * @param SLB_Field $item Field containing placeholder - * @param array $placeholder Current placeholder - * @see SLB_Field::parse_layout for structure of $placeholder array - * @param string $layout Layout to build - * @param array $data Extended data for item - * @return string Value to use in place of current placeholder - */ - function process_placeholder_default($output, $item, $placeholder, $layout, $data) { - // Validate parameters before processing - if ( empty($output) && ($item instanceof SLB_Field_Type) && is_array($placeholder) ) { - // Build path to replacement data - $output = $item->get_member_value($placeholder); - - // Check if value is group (properties, etc.) - // All groups must have additional attributes (beyond reserved attributes) that define how items in group are used - if (is_array($output) - && !empty($placeholder['attributes']) - && is_array($placeholder['attributes']) - && ($ph = $item->get_placeholder_defaults()) - && $attribs = array_diff(array_keys($placeholder['attributes']), array_values($ph->reserved)) - ) { - /* Targeted property is an array, but the placeholder contains additional options on how property is to be used */ - - // Find items matching criteria in $output - // Check for group criteria - if ( 'properties' == $placeholder['tag'] && ($prop_group = $item->get_group($placeholder['attributes']['group'])) && !empty($prop_group) ) { - /* Process group */ - $group_out = array(); - // Iterate through properties in group and build string. - foreach ( array_keys( $prop_group ) as $prop_key ) { - $prop_val = $item->get_property( $prop_key ); - if ( !is_null( $prop_val ) ) { - // Process placeholders. - $prop_val = $item->process_placeholders( $prop_val, $layout, $data ); - // Add property to attribute string output. - $group_out[] = esc_attr( $prop_key ) . '="' . esc_attr( $prop_val ) . '"'; - } - } - $output = implode(' ', $group_out); - } - } elseif ( is_object($output) && ($output instanceof $item->base_class) ) { - /* Targeted property is actually a nested item */ - // Set caller to current item - $output->set_caller($item); - // Build layout for nested element - $output = $output->build_layout($layout); - } - } - - return $output; - } - - /** - * Renders field ID formatted for a form field's `id` attribute. - * - * ID is formatted to be unique identifier for form field. - * Example: `options_field_id`. - * Registered as handler for `{field_id}` placeholder. - * - * @param string $output Placeholder's rendered value. - * @param SLB_Field $item Field containing placeholder. - * @param array &$placeholder Placeholder being processed. - * @param string $layout Name of layout being built. - * @param array $data Additional data for current field. - * @return string Field's ID (formatted for a form field's `id` attribute). - */ - function process_placeholder_id( $output, $item, &$placeholder, $layout, $data ) { - // Get attributes - $args = wp_parse_args($placeholder['attributes'], array('format' => 'attr_id')); - $output = $item->get_id($args); - // Set default placeholder context. - if ( ! isset( $placeholder['attributes']['context'] ) ) { - $placeholder['attributes']['context'] = 'attr'; - } - return $output; - } - - /** - * Renders field ID formatted for a form field's `name` attribute. - * - * ID is formatted to be part of an associative array for processing form submission. - * Example: `options[field_id]`. - * Registered as handler for `{field_name}` placeholder. - * - * @param string $output Placeholder's rendered value. - * @param SLB_Field $item Field containing placeholder. - * @param array &$placeholder Placeholder being processed. - * @param string $layout Name of layout being built. - * @param array $data Additional data for current field. - * @return string Field's ID (formatted for a form field's `name` attribute). - */ - function process_placeholder_name($output, $item, &$placeholder, $layout, $data) { - // Get attributes - $args = wp_parse_args($placeholder['attributes'], array('format' => 'attr_name')); - $output = $item->get_id($args); - // Set default placeholder context. - if ( ! isset( $placeholder['attributes']['context'] ) ) { - $placeholder['attributes']['context'] = 'attr'; - } - return $output; - } - - /** - * Build item label - * @see SLB_Fields::process_placeholder_default for parameter descriptions - * @return string Field label - */ - function process_placeholder_label($output, $item, $placeholder, $layout, $data) { - // Check if item has label property (e.g. sub-elements) - $out = $item->get_property('label'); - // If property not set, use item title - if ( empty($out) ) - $out = $item->get_title(); - return $out; - } - - /** - * Retrieve data for item - * @see SLB_Field_Type::process_placeholder_default for parameter descriptions - * @return string Placeholder output - */ - function process_placeholder_data($output, $item, $placeholder, $layout) { - $opts = $placeholder['attributes']; - // Strip context from data retrieval options (Formatting handled upstream). - if ( is_array( $opts ) ) { - unset( $opts['context'] ); - } - // Get data - $out = $item->get_data($opts); - if ( ! is_null($out) ) { - // Get specific member in value (e.g. value from a specific item element) - if ( isset($opts['element']) && is_array($out) && ( $el = $opts['element'] ) && isset($out[$el]) ) - $out = $out[$el]; - } - - // Return data - return $out; - } - - /** - * Set checked attribute on item - * Evaluates item's data to see if item should be checked or not - * @see SLB_Fields::process_placeholder_default for parameter descriptions - * @return string Appropriate checkbox attribute - */ - function process_placeholder_checked($output, $item, $placeholder, $layout, $data) { - $out = ''; - $c = $item->get_container(); - $d = ( isset($c->data[$item->get_id()]) ) ? $c->data[$item->get_id()] : null; - $item->set_property('d', true); - if ( $item->get_data() ) - $out = 'checked="checked"'; - $item->set_property('d', false); - return $out; - } - - /** - * Loops over data to build item output - * Options: - * data - Dot-delimited path in item that contains data to loop through - * layout - Name of layout to use for each data item in loop - * layout_data - Name of layout to use for data item that matches previously-saved item data - * @see SLB_Field_Type::process_placeholder_default for parameter descriptions - * @return string Placeholder output - */ - function process_placeholder_loop($output, $item, $placeholder, $layout, $data) { - // Setup loop options - $attr_defaults = array ( - 'layout' => '', - 'layout_data' => null, - 'data' => '' - ); - $attr = wp_parse_args($placeholder['attributes'], $attr_defaults); - if ( is_null($attr['layout_data']) ) - $attr['layout_data'] =& $attr['layout']; - // Get data for loop - $path = explode('.', $attr['data']); - $loop_data = $item->get_member_value($path); - - // Check if data is callback - if ( is_callable($loop_data) ) - $loop_data = call_user_func($loop_data); - - // Get item data - $data = $item->get_data(); - - // Iterate over data and build output - $out = array(); - if ( is_array($loop_data) && !empty($loop_data) ) { - foreach ( $loop_data as $value => $label ) { - // Load appropriate layout based on item value - $layout = ( ($data === 0 && $value === $data) xor $data == $value ) ? $attr['layout_data'] : $attr['layout']; - // Stop processing if no valid layout is returned - if ( empty($layout) ) - continue; - // Prep extended item data - $data_ext = array('option_value' => $value, 'option_text' => $label); - $out[] = $item->build_layout($layout, $data_ext); - } - } - - // Return output - return implode($out); - } - - /** - * Returns specified value from extended data array for item. - * - * @param string $output Value to be used in place of placeholder. - * @param SLB_Field $item Field containing placeholder. - * @param array $placeholder Current placeholder. - * @see SLB_Field::parse_layout for structure of `$placeholder` array. - * @param string $layout Name of layout being built. - * @param array $data Extended data for item. - * - * @return string Processed value. - */ - function process_placeholder_data_ext( $output, SLB_Field $item, array $placeholder, $layout, array $data ) { - $key = ( isset( $placeholder['attributes']['id'] ) ) ? $placeholder['attributes']['id'] : false; - if ( !! $key && isset( $data[ $key ] ) && is_scalar( $data[ $key ] ) ) { - $output = strval( $data[ $key ] ); - } - - return $output; - } - - /* Build */ - - /** - * Output items in a group - * @param string $group ID of Group to output - * @return string Group output - * TODO Make compatible with parent::build_group() - */ - function build_group($group) { - $out = array(); - $classnames = (object) array( - 'multi' => 'multi_field', - 'single' => 'single_field', - 'elements' => 'has_elements' - ); - - // Stop execution if group does not exist - if ( $this->group_exists($group) && $group =& $this->get_group($group) ) { - $group_items = ( count($group->items) > 1 ) ? $classnames->multi : $classnames->single . ( ( ( $fs = array_keys($group->items) ) && ( $f =& $group->items[$fs[0]] ) && ( $els = $f->get_member_value('elements', '', null) ) && !empty($els) ) ? '_' . $classnames->elements : '' ); - $classname = array($this->add_prefix('attributes_wrap'), $group_items); - $out[] = '
'; // Wrap all items in group - - // Build layout for each item in group - foreach ( array_keys($group->items) as $item_id ) { - $item =& $group->items[$item_id]; - $item->set_caller($this); - // Start item output - $id = $this->add_prefix('field_' . $item->get_id()); - $out[] = '
'; - // Build item layout - $out[] = $item->build_layout(); - // end item output - $out[] = '
'; - $item->clear_caller(); - } - $out[] = '
'; // Close items container - // Add description if exists - if ( !empty($group->description) ) - $out[] = '

' . $group->description . '

'; - } - - // Return group output - return implode($out); - } -} \ No newline at end of file +m( 'register_types' ) ); + // Init placeholders + add_action( 'init', $this->m( 'register_placeholders' ) ); + } + + /* Field Types */ + + /** + * Initialize fields + */ + function register_types() { + /* Field Types */ + + // Base + $base = new SLB_Field_Type( 'base' ); + $base->set_description( __( 'Default Element', 'simple-lightbox' ) ); + $base->set_property( 'tag', 'span' ); + $base->set_property( 'class', '', 'attr' ); + $base->set_layout( 'form_attr', '{tag} name="{field_name}" id="{field_id}" {properties ref_base="root" group="attr"}' ); + $base->set_layout( 'form', '<{form_attr ref_base="layout"} />' ); + $base->set_layout( 'label', '' ); + $base->set_layout( 'display', '{data context="display"}' ); + $this->add( $base ); + + // Base closed + $base_closed = new SLB_Field_Type( 'base_closed' ); + $base_closed->set_parent( 'base' ); + $base_closed->set_description( __( 'Default Element (Closed Tag)', 'simple-lightbox' ) ); + $base_closed->set_layout( 'form_start', '<{tag} id="{field_id}" name="{field_name}" {properties ref_base="root" group="attr"}>' ); + $base_closed->set_layout( 'form_end', '' ); + $base_closed->set_layout( 'form', '{form_start ref_base="layout"}{data}{form_end ref_base="layout"}' ); + $this->add( $base_closed ); + + // Input + $input = new SLB_Field_Type( 'input', 'base' ); + $input->set_description( __( 'Default Input Element', 'simple-lightbox' ) ); + $input->set_property( 'tag', 'input' ); + $input->set_property( 'type', 'text', 'attr' ); + $input->set_property( 'value', '{data}', 'attr' ); + $this->add( $input ); + + // Text input + $text = new SLB_Field_Type( 'text', 'input' ); + $text->set_description( __( 'Text Box', 'simple-lightbox' ) ); + $text->set_property( 'size', 15, 'attr' ); + $text->set_property( 'label' ); + $text->set_layout( 'form', '{label ref_base="layout"} {inherit}' ); + $this->add( $text ); + + // Checkbox + $cb = new SLB_Field_Type( 'checkbox', 'input' ); + $cb->set_property( 'type', 'checkbox' ); + $cb->set_property( 'value', null ); + $cb->set_layout( 'form_attr', '{inherit} {checked}' ); + $cb->set_layout( 'form', '{label ref_base="layout"} <{form_attr ref_base="layout"} />' ); + $this->add( $cb ); + + // Textarea + $ta = new SLB_Field_Type( 'textarea', 'base_closed' ); + $ta->set_property( 'tag', 'textarea' ); + $ta->set_property( 'cols', 40, 'attr' ); + $ta->set_property( 'rows', 3, 'attr' ); + $this->add( $ta ); + + // Rich Text + $rt = new SLB_Field_Type( 'richtext', 'textarea' ); + $rt->set_property( 'class', 'theEditor {inherit}' ); + $rt->set_layout( 'form', '
{inherit}
' ); + $rt->add_action( 'admin_print_footer_scripts', 'wp_tiny_mce', 25 ); + $this->add( $rt ); + + // Hidden + $hidden = new SLB_Field_Type( 'hidden' ); + $hidden->set_parent( 'input' ); + $hidden->set_description( __( 'Hidden Field', 'simple-lightbox' ) ); + $hidden->set_property( 'type', 'hidden' ); + $this->add( $hidden ); + + // Select + $select = new SLB_Field_Type( 'select', 'base_closed' ); + $select->set_description( __( 'Select tag', 'simple-lightbox' ) ); + $select->set_property( 'tag', 'select' ); + $select->set_property( 'tag_option', 'option' ); + $select->set_property( 'options', array() ); + $select->set_layout( 'form', '{label ref_base="layout"} {form_start ref_base="layout"}{option_loop ref_base="layout"}{form_end ref_base="layout"}' ); + $select->set_layout( 'option_loop', '{loop data="properties.options" layout="option" layout_data="option_data"}' ); + $select->set_layout( 'option', '<{tag_option} value="{data_ext id="option_value" context="attr"}">{data_ext id="option_text" context="text"}' ); + $select->set_layout( 'option_data', '<{tag_option} value="{data_ext id="option_value" context="attr"}" selected="selected">{data_ext id="option_text" context="text"}' ); + $this->add( $select ); + + // Span + $span = new SLB_Field_Type( 'span', 'base_closed' ); + $span->set_description( __( 'Inline wrapper', 'simple-lightbox' ) ); + $span->set_property( 'tag', 'span' ); + $span->set_property( 'value', 'Hello there!' ); + $this->add( $span ); + + // Enable plugins to modify (add, remove, etc.) field types + $this->util->do_action_ref_array( 'register_fields', array( $this ), false ); + + // Signal completion of field registration + $this->util->do_action_ref_array( 'fields_registered', array( $this ), false ); + } + + /* Placeholder handlers */ + + function register_placeholders() { + // Default placeholder handlers + $this->register_placeholder( 'all', $this->m( 'process_placeholder_default' ), 11 ); + $this->register_placeholder( 'field_id', $this->m( 'process_placeholder_id' ) ); + $this->register_placeholder( 'field_name', $this->m( 'process_placeholder_name' ) ); + $this->register_placeholder( 'data', $this->m( 'process_placeholder_data' ) ); + $this->register_placeholder( 'data_ext', $this->m( 'process_placeholder_data_ext' ) ); + $this->register_placeholder( 'loop', $this->m( 'process_placeholder_loop' ) ); + $this->register_placeholder( 'label', $this->m( 'process_placeholder_label' ) ); + $this->register_placeholder( 'checked', $this->m( 'process_placeholder_checked' ) ); + + // Allow other code to register placeholders + $this->util->do_action_ref_array( 'register_field_placeholders', array( $this ), false ); + + // Signal completion of field placeholder registration + $this->util->do_action_ref_array( 'field_placeholders_registered', array( $this ), false ); + } + + /** + * Register a function to handle a placeholder + * Multiple handlers may be registered for a single placeholder + * Adds filter hook to WP for handling specified placeholder + * Placeholders are in layouts and are replaced with data at runtime + * @uses add_filter() + * @param string $placeholder Name of placeholder to add handler for (Using 'all' will set the function as a handler for all placeholders + * @param callback $callback Function to set as a handler + * @param int $priority (optional) Priority of handler + * @return void + */ + function register_placeholder( $placeholder, $callback, $priority = 10 ) { + if ( 'all' === $placeholder ) { + $placeholder = ''; + } else { + $placeholder = '_' . $placeholder; + } + $hook = $this->add_prefix( 'process_placeholder' . $placeholder ); + add_filter( $hook, $callback, $priority, 5 ); + } + + /** + * Handles default placeholder processing. + * + * Processes placeholders that have not been processed by another handler. + * + * @param string $output Value to be used in place of placeholder. Should be empty. + * @param SLB_Field $item Field containing placeholder. + * @param array $placeholder Current placeholder. + * @see SLB_Field::parse_layout for structure of `$placeholder` array. + * @param string $layout Layout to build. + * @param array $data Extended data for item. + * @return string Value to use in place of current placeholder. + */ + function process_placeholder_default( $output, $item, $placeholder, $layout, $data ) { + // Validate parameters before processing. + if ( + ! empty( $output ) + || ( ! $item instanceof SLB_Field_Type ) + || ! is_array( $placeholder ) + ) { + return $output; + } + + // Build path to replacement data. + $output = $item->get_member_value( $placeholder ); + + // Check if value is group (properties, etc.) + // All groups must have additional attributes (beyond reserved attributes) that define how items in group are used + if ( + is_array( $output ) + && ! empty( $placeholder['attributes'] ) + && is_array( $placeholder['attributes'] ) + && 'properties' === $placeholder['tag'] + ) { + // Targeted property is an array. + // Placeholder contains additional options on how property is to be used. + + // Find items matching criteria in $output + // Check for group criteria + $prop_group = $item->get_group( $placeholder['attributes']['group'] ); + if ( ! empty( $prop_group ) ) { + /* Process group */ + $group_out = array(); + // Iterate through properties in group and build string. + foreach ( array_keys( $prop_group ) as $prop_key ) { + $prop_val = $item->get_property( $prop_key ); + if ( is_null( $prop_val ) ) { + continue; + } + // Process placeholders. + $prop_val = $item->process_placeholders( $prop_val, $layout, $data ); + // Add property to attribute string output. + $group_out[] = esc_attr( $prop_key ) . '="' . esc_attr( $prop_val ) . '"'; + } + $output = implode( ' ', $group_out ); + } + } elseif ( is_object( $output ) && ( $output instanceof $item->base_class ) ) { + /* Targeted property is actually a nested item */ + // Set caller to current item + $output->set_caller( $item ); + // Build layout for nested element + $output = $output->build_layout( $layout ); + } + + return $output; + } + + /** + * Renders field ID formatted for a form field's `id` attribute. + * + * ID is formatted to be unique identifier for form field. + * Example: `options_field_id`. + * Registered as handler for `{field_id}` placeholder. + * + * @param string $output Placeholder's rendered value. + * @param SLB_Field $item Field containing placeholder. + * @param array &$placeholder Placeholder being processed. + * @param string $layout Name of layout being built. + * @param array $data Additional data for current field. + * @return string Field's ID (formatted for a form field's `id` attribute). + */ + function process_placeholder_id( $output, $item, &$placeholder, $layout, $data ) { + // Get attributes + $args = wp_parse_args( $placeholder['attributes'], array( 'format' => 'attr_id' ) ); + $output = $item->get_id( $args ); + // Set default placeholder context. + if ( ! isset( $placeholder['attributes']['context'] ) ) { + $placeholder['attributes']['context'] = 'attr'; + } + return $output; + } + + /** + * Renders field ID formatted for a form field's `name` attribute. + * + * ID is formatted to be part of an associative array for processing form submission. + * Example: `options[field_id]`. + * Registered as handler for `{field_name}` placeholder. + * + * @param string $output Placeholder's rendered value. + * @param SLB_Field $item Field containing placeholder. + * @param array &$placeholder Placeholder being processed. + * @param string $layout Name of layout being built. + * @param array $data Additional data for current field. + * @return string Field's ID (formatted for a form field's `name` attribute). + */ + function process_placeholder_name( $output, $item, &$placeholder, $layout, $data ) { + // Get attributes + $args = wp_parse_args( $placeholder['attributes'], array( 'format' => 'attr_name' ) ); + $output = $item->get_id( $args ); + // Set default placeholder context. + if ( ! isset( $placeholder['attributes']['context'] ) ) { + $placeholder['attributes']['context'] = 'attr'; + } + return $output; + } + + /** + * Build item label + * @see SLB_Fields::process_placeholder_default for parameter descriptions + * @return string Field label + */ + function process_placeholder_label( $output, $item, $placeholder, $layout, $data ) { + // Check if item has label property (e.g. sub-elements) + $out = $item->get_property( 'label' ); + // If property not set, use item title + if ( empty( $out ) ) { + $out = $item->get_title(); + } + return $out; + } + + /** + * Retrieve data for item + * @see SLB_Field_Type::process_placeholder_default for parameter descriptions + * @return string Placeholder output + */ + function process_placeholder_data( $output, $item, $placeholder, $layout ) { + $opts = $placeholder['attributes']; + // Strip context from data retrieval options (Formatting handled upstream). + if ( is_array( $opts ) ) { + unset( $opts['context'] ); + } + // Get data + $out = $item->get_data( $opts ); + // Get specific member in value (e.g. value from a specific item element). + if ( + is_array( $out ) + && is_array( $opts ) + && isset( $opts['element'] ) + && isset( $out[ $opts['element'] ] ) + ) { + $out = $out[ $opts['element'] ]; + } + + // Return data + return $out; + } + + /** + * Set checked attribute on item + * Evaluates item's data to see if item should be checked or not + * @see SLB_Fields::process_placeholder_default for parameter descriptions + * @return string Appropriate checkbox attribute + */ + function process_placeholder_checked( $output, $item, $placeholder, $layout, $data ) { + $out = ''; + $c = $item->get_container(); + $d = ( isset( $c->data[ $item->get_id() ] ) ) ? $c->data[ $item->get_id() ] : null; + $item->set_property( 'd', true ); + if ( $item->get_data() ) { + $out = 'checked="checked"'; + } + $item->set_property( 'd', false ); + return $out; + } + + /** + * Loops over data to build item output + * Options: + * data - Dot-delimited path in item that contains data to loop through + * layout - Name of layout to use for each data item in loop + * layout_data - Name of layout to use for data item that matches previously-saved item data + * @see SLB_Field_Type::process_placeholder_default for parameter descriptions + * @return string Placeholder output + */ + function process_placeholder_loop( $output, $item, $placeholder, $layout, $data ) { + // Setup loop options + $attr_defaults = array( + 'layout' => '', + 'layout_data' => null, + 'data' => '', + ); + $attr = wp_parse_args( $placeholder['attributes'], $attr_defaults ); + if ( is_null( $attr['layout_data'] ) ) { + $attr['layout_data'] =& $attr['layout']; + } + // Get data for loop + $path = explode( '.', $attr['data'] ); + $loop_data = $item->get_member_value( $path ); + + // Check if data is callback + if ( is_callable( $loop_data ) ) { + $loop_data = call_user_func( $loop_data ); + } + + // Get item data + $data = $item->get_data(); + + // Iterate over data and build output + $out = array(); + if ( is_array( $loop_data ) && ! empty( $loop_data ) ) { + foreach ( $loop_data as $value => $label ) { + // Load appropriate layout based on item value + $layout = ( ( 0 === $data && $value === $data ) xor $data === $value ) ? $attr['layout_data'] : $attr['layout']; + // Stop processing if no valid layout is returned + if ( empty( $layout ) ) { + continue; + } + // Prep extended item data + $data_ext = array( + 'option_value' => $value, + 'option_text' => $label, + ); + $out[] = $item->build_layout( $layout, $data_ext ); + } + } + + // Return output + return implode( $out ); + } + + /** + * Returns specified value from extended data array for item. + * + * @param string $output Value to be used in place of placeholder. + * @param SLB_Field $item Field containing placeholder. + * @param array $placeholder Current placeholder. + * @see SLB_Field::parse_layout for structure of `$placeholder` array. + * @param string $layout Name of layout being built. + * @param array $data Extended data for item. + * + * @return string Processed value. + */ + function process_placeholder_data_ext( $output, SLB_Field $item, array $placeholder, $layout, array $data ) { + $key = ( isset( $placeholder['attributes']['id'] ) ) ? $placeholder['attributes']['id'] : false; + if ( ! ! $key && isset( $data[ $key ] ) && is_scalar( $data[ $key ] ) ) { + $output = strval( $data[ $key ] ); + } + + return $output; + } + + /* Build */ + + /** + * Outputs items in a group. + * + * @param string $group ID of Group to output. + * @return string Group output. + * @todo Make compatible with parent::build_group() + */ + function build_group( $group ) { + $out = array(); + + /** + * Renders group output as a string. + * + * @uses $out Array containing group output. + * @return string Group output. + */ + $render_output = function() use ( $out ) { + // Combine output. + return implode( '', $out ); + }; + + // Stop if group does not exist. + if ( ! $this->group_exists( $group ) ) { + return $render_output(); + } + + // Classnames. + $cls = (object) [ + 'multi' => 'multi_field', + 'single' => 'single_field', + 'elements' => 'has_elements', + 'group_desc' => $this->add_prefix( 'group_description' ), + 'group_wrap' => $this->add_prefix( 'attributes_wrap' ), + 'item_wrap' => $this->add_prefix( 'attribute_wrap' ), + ]; + // Templates. + $tpl = (object) [ + 'container_start' => '
', + 'container_end' => '
', + 'item_start' => '
', + 'item_end' => '
', + 'text_block' => '

%2$s

', + ]; + + // Process group. + $group = $this->get_group( $group ); + $group_items = ( count( $group->items ) > 1 ) ? $cls->multi : $cls->single; + $fs = array_keys( $group->items ); + $f =& $group->items[ $fs[0] ]; + $els = $f->get_member_value( 'elements', '', null ); + + if ( ! empty( $els ) ) { + $group_items .= '_' . $cls->elements; + } + + // Wrap items with container element. + $classname = array( $cls->group_wrap, $group_items ); + $out[] = sprintf( $tpl->container_start, implode( ' ', $classname ) ); + + // Clear temp variables. + unset( $fs, $f, $els, $classname ); + + // Build layout for each item in group + foreach ( array_keys( $group->items ) as $item_id ) { + // Init item. + $item =& $group->items[ $item_id ]; + $item->set_caller( $this ); + + // Start item output. + $id = $this->add_prefix( 'field_' . $item->get_id() ); + $out[] = sprintf( $tpl->item_start, $id, $cls->item_wrap ); + // Build item layout. + $out[] = $item->build_layout(); + // End item output. + $out[] = $tpl->item_end; + + // Cleanup. + $item->clear_caller(); + unset( $item, $id ); + } + // Close items container. + $out[] = $tpl->container_end; + + // Add description if exists + if ( ! empty( $group->description ) ) { + $out[] = sprintf( $tpl->text_block, $cls->group_desc, $group->description ); + } + // Render and return output. + return $render_output(); + } +} diff --git a/includes/class.option.php b/includes/class.option.php index 7aa8cad..e587366 100644 --- a/includes/class.option.php +++ b/includes/class.option.php @@ -15,19 +15,19 @@ class SLB_Option extends SLB_Field { * Determines whether option will be sent to client * @var bool */ - var $in_client = false; + public $in_client = false; /** * Child mapping * @see SLB_Field_Base::map * @var array */ - var $map = array ( - 'default' => 'data', - 'attr' => 'properties' + public $map = array( + 'default' => 'data', + 'attr' => 'properties', ); - var $property_priority = array ('id', 'data', 'parent'); + public $property_priority = array( 'id', 'data', 'parent' ); /* Init */ @@ -38,18 +38,23 @@ class SLB_Option extends SLB_Field { * @param $title * @param $default */ - function __construct($id, $title = '', $default = '') { + function __construct( $id, $title = '', $default = '' ) { // Normalize properties - $args = func_get_args(); - $defaults = array ('title' => '', 'default' => ''); - $props = $this->make_properties($args, $defaults); + $args = func_get_args(); + $defaults = array( + 'title' => '', + 'default' => '', + ); + $props = $this->make_properties( $args, $defaults ); // Validate - if ( is_scalar($id) ) + if ( is_scalar( $id ) ) { $props['id'] = $id; - if ( !is_string($props['title']) ) + } + if ( ! is_string( $props['title'] ) ) { $props['title'] = ''; + } // Send to parent constructor - parent::__construct($props); + parent::__construct( $props ); } /* Getters/Setters */ @@ -58,25 +63,26 @@ function __construct($id, $title = '', $default = '') { * Retrieve default value for option * @return mixed Default option value */ - function get_default($context = '') { - return $this->get_data($context, false); + function get_default( $context = '' ) { + return $this->get_data( $context, false ); } /** * Sets parent based on default value */ - function set_parent($parent = null) { + function set_parent( $parent = null ) { $p = $this->get_parent(); - if ( empty($parent) && empty($p) ) { + if ( empty( $parent ) && empty( $p ) ) { $parent = 'text'; - $d = $this->get_default(); - if ( is_bool($d) ) + $d = $this->get_default(); + if ( is_bool( $d ) ) { $parent = 'checkbox'; + } $parent = 'option_' . $parent; - } elseif ( !empty($p) && !is_object($p) ) { + } elseif ( ! empty( $p ) && ! is_object( $p ) ) { $parent =& $p; } - parent::set_parent($parent); + parent::set_parent( $parent ); } /** @@ -85,8 +91,8 @@ function set_parent($parent = null) { * @param bool Whether or not option should be included in client output (Default: false) * @return void */ - function set_in_client($in_client = false) { - $this->in_client = !!$in_client; + function set_in_client( $in_client = false ) { + $this->in_client = ! ! $in_client; } /** @@ -107,19 +113,19 @@ function get_in_client() { * @param string $context (optional) Current context * @return string Formatted value */ - function format_display($value, $context = '') { - if ( !is_string($value) ) { - if ( is_bool($value) ) { - $value = ( $value ) ? __('Enabled', 'simple-lightbox') : __('Disabled', 'simple-lightbox'); - } - elseif ( is_null($value) ) + function format_display( $value, $context = '' ) { + if ( ! is_string( $value ) ) { + if ( is_bool( $value ) ) { + $value = ( $value ) ? __( 'Enabled', 'simple-lightbox' ) : __( 'Disabled', 'simple-lightbox' ); + } elseif ( is_null( $value ) ) { $value = ''; - else - $value = strval($value); - } elseif ( empty($value) ) { + } else { + $value = strval( $value ); + } + } elseif ( empty( $value ) ) { $value = 'empty'; } - return htmlentities($value); + return htmlentities( $value ); } /** @@ -129,15 +135,17 @@ function format_display($value, $context = '') { * @param string $context (optional) Current context * @return mixed Formatted option value */ - function format_default($value, $context = '') { + function format_default( $value, $context = '' ) { // Get default value $d = $this->get_default(); - if ( empty($d) ) + if ( empty( $d ) ) { return $value; - if ( is_bool($d) ) - $value = $this->format_bool($value); - elseif ( is_string($d) ) - $value = $this->format_string($value); + } + if ( is_bool( $d ) ) { + $value = $this->format_bool( $value ); + } elseif ( is_string( $d ) ) { + $value = $this->format_string( $value ); + } return $value; } @@ -148,9 +156,10 @@ function format_default($value, $context = '') { * @param string $context (optional) Current context * @return bool Option value */ - function format_bool($value, $context = '') { - if ( !is_bool($value) ) - $value = !!$value; + function format_bool( $value, $context = '' ) { + if ( ! is_bool( $value ) ) { + $value = ! ! $value; + } return $value; } @@ -161,19 +170,16 @@ function format_bool($value, $context = '') { * @param string $context (optional) Current context * @return string Option string value */ - function format_string($value, $context = '') { - if ( is_bool($value) ) { + function format_string( $value, $context = '' ) { + if ( is_bool( $value ) ) { $value = ( $value ) ? 'true' : 'false'; - } - elseif ( is_object($value) ) { - $value = get_class($value); - } - elseif ( is_array($value) ) { - $value = implode(' ', $value); - } - else { - $value = strval($value); + } elseif ( is_object( $value ) ) { + $value = get_class( $value ); + } elseif ( is_array( $value ) ) { + $value = implode( ' ', $value ); + } else { + $value = strval( $value ); } return $value; } -} \ No newline at end of file +} diff --git a/includes/class.options.php b/includes/class.options.php index f9c09f2..f481ab3 100644 --- a/includes/class.options.php +++ b/includes/class.options.php @@ -1,679 +1,696 @@ - false, - 'validate_post' => false, - 'save_pre' => false, - 'save_post' => false - ); - - /* Init */ - - function __construct($id = '', $props = array()) { - // Validate arguments - $args = func_get_args(); - // Set default ID - if ( !$this->validate_id($id) ) { - $id = 'options'; - } - $defaults = $this->integrate_id($id); - $props = $this->make_properties($args, $defaults); - parent::__construct($props); - $this->add_prefix_ref($this->version_key); - } - - protected function _hooks() { - parent::_hooks(); - // Register fields - $this->util->add_action('register_fields', $this->m('register_fields'), 10, 1, false); - // Set option parents - $this->util->add_action('fields_registered', $this->m('set_parents'), 10, 1, false); - // Building - $this->util->add_action('build_init', $this->m('build_init')); - // Admin - $this->util->add_action('admin_page_render_content', $this->m('admin_page_render_content'), 10, 3, false); - $this->util->add_filter('admin_action_reset', $this->m('admin_action_reset'), 10, 3, false); - } - - /* Legacy/Migration */ - - /** - * Checks whether new version has been installed and migrates necessary settings - * @uses $version_key as option name - * @uses get_option() to retrieve saved version number - * @uses SLB_Utilities::get_plugin_version() to retrieve current version - * @return bool TRUE if version has been changed - */ - function check_update() { - if ( !$this->version_checked ) { - $this->version_checked = true; - $version_changed = false; - // Get version from DB - $vo = $this->get_version(); - // Get current version - $vn = $this->util->get_plugin_version(); - // Compare versions - if ( $vo != $vn ) { - // Update saved version - $this->set_version($vn); - // Migrate old version to new version - if ( strcasecmp($vo, $vn) < 0 ) { - // Force full migration - $version_changed = true; - } - } - // Migrate - $this->migrate($version_changed); - } - - return $this->version_checked; - } - - /** - * Save plugin version to DB - * If no version supplied, will fetch plugin data to determine version - * @uses $version_key as option name - * @uses update_option() to save version to options table - * @param string $ver (optional) Plugin version - */ - function set_version($ver = null) { - if ( empty($ver) ) { - $ver = $this->util->get_plugin_version(); - } - return update_option($this->version_key, $ver); - } - - /** - * Retrieve saved version data - * @return string Saved version - */ - function get_version() { - return get_option($this->version_key, ''); - } - - /** - * Migrate options from old versions to current version - * @uses self::items_migrated to determine if simple migration has been performed in current request or not - * @uses self::save() to save data after migration - * @param bool $full Whether to perform a full migration or not (Default: No) - */ - function migrate($full = false) { - if ( !$full && $this->items_migrated ) - return false; - - // Legacy options - $d = null; - $this->load_data(); - - $items = $this->get_items(); - - // Migrate separate options to unified option - if ( $full ) { - foreach ( $items as $opt => $props ) { - $oid = $this->add_prefix($opt); - $o = get_option($oid, $d); - if ( $o !== $d ) { - // Migrate value to data array - $this->set_data($opt, $o, false); - // Delete legacy option - delete_option($oid); - } - } - } - - // Migrate legacy items - if ( is_array($this->properties_init) && isset($this->properties_init['legacy']) && is_array($this->properties_init['legacy']) ) { - $l =& $this->properties_init['legacy']; - // Normalize legacy map - foreach ( $l as $opt => $dest ) { - if ( !is_array($dest) ) { - if ( is_string($dest) ) - $l[$opt] = array($dest); - else - unset($l[$opt]); - } - } - - /* Separate options */ - if ( $full ) { - foreach ( $l as $opt => $dest ) { - $oid = $this->add_prefix($opt); - $o = get_option($oid, $d); - // Only migrate valid values - if ( $o !== $d ) { - // Process destinations - foreach ( $dest as $id ) { - $this->set_data($id, $o, false, true); - } - } - // Remove legacy option - delete_option($oid); - } - } - - /* Simple Migration (Internal options only) */ - - // Get existing items that are also legacy items - $opts = array_intersect_key($this->get_data(), $l); - foreach ( $opts as $opt => $val ) { - $d = $this->get_data($opt); - // Migrate data from old option to new option - $dest = $l[$opt]; - // Validate new options to send data to - foreach ( $dest as $id ) { - $this->set_data($id, $d, false, true); - } - // Remove legacy option - $this->remove($opt, false); - } - } - // Save changes - $this->save(); - // Set flag - $this->items_migrated = true; - } - - /* Option setup */ - - /** - * Get elements for creating fields - * @return obj - */ - function get_field_elements() { - static $o = null; - if ( empty($o) ) { - $o = new stdClass(); - /* Layout */ - $layout = new stdClass(); - $layout->label = ''; - $layout->label_ref = '{label ref_base="layout"}'; - $layout->field_pre = '
'; - $layout->field_post = '
'; - $layout->opt_pre = '
'; - $layout->opt_post = '
'; - $layout->form = '<{form_attr ref_base="layout"} /> (' . __('Default', 'simple-lightbox') . ': {data context="display" top="0"})'; - /* Combine */ - $o->layout =& $layout; - } - return $o; - } - - /** - * Register option-specific fields - * @param SLB_Fields $fields Reference to global fields object - * @return void - */ - function register_fields($fields) { - // Layouts - $o = $this->get_field_elements(); - $l =& $o->layout; - - $form = implode('', array ( - $l->opt_pre, - $l->label_ref, - $l->field_pre, - $l->form, - $l->field_post, - $l->opt_post - )); - - // Text input - $otxt = new SLB_Field_Type('option_text', 'text'); - $otxt->set_property('class', '{inherit} code'); - $otxt->set_property('size', null); - $otxt->set_property('value', '{data}'); - $otxt->set_layout('label', $l->label); - $otxt->set_layout('form', $form); - $fields->add($otxt); - - // Checkbox - $ocb = new SLB_Field_Type('option_checkbox', 'checkbox'); - $ocb->set_layout('label', $l->label); - $ocb->set_layout('field_reference', sprintf( '', "{$this->get_id('formatted')}_items[]" ) ); - $ocb->set_layout('form', '{field_reference ref_base="layout"}' . $form); - $fields->add($ocb); - - // Select - $othm = new SLB_Field_Type('option_select', 'select'); - $othm->set_layout('label', $l->label); - $othm->set_layout('form_start', $l->field_pre . '{inherit}'); - $othm->set_layout('form_end', '{inherit}' . $l->field_post); - $othm->set_layout('form', $l->opt_pre . '{inherit}' . $l->opt_post); - $fields->add($othm); - } - - /** - * Set parent field types for options - * Parent only set for Admin pages - * @uses SLB_Option::set_parent() to set parent field for each option item - * @uses is_admin() to determine if current request is admin page - * @param object $fields Collection of default field types - * @return void - */ - function set_parents($fields) { - if ( !is_admin() ) - return false; - $items = &$this->get_items(); - foreach ( array_keys($items) as $opt ) { - $items[$opt]->set_parent(); - } - foreach ( $this->items as $opt ) { - $p = $opt->parent; - if ( is_object($p) ) - $p = 'o:' . $p->id; - } - } - - /* Processing */ - - /** - * Validates option data. - * - * Validates option values (e.g. prior to saving to DB, after form submission, etc.). - * Values are formatted and sanitized according to corresponding option's data type - * (e.g. boolean, string, number, etc.). - * - * @since 1.5.5 - * - * @param array $values Optional. Option data to validate. - * Indexed by option ID. - * Default form-submission data used. - * @return array Validated data. Indexed by option ID. - */ - function validate( $values = null ) { - /** @var array $values_valid Validated option data. Indexed by option ID. */ - $values_valid = []; - // Enforce values data type. - if ( ! is_array( $values ) ) { - /** @var array $values */ - $values = []; - } - /** - * Generates query variable using common base. - * - * @since 2.8.0 - * - * @param string $text Optional. Text to append to base. - * - * @return string Query variable name. Format: "{base}_{text}". Default "{base}". - */ - $qv = function ( $text = '' ) { - static $base; - // Get base. - if ( empty( $base ) ) { - $base = $this->get_id( 'formatted' ); - } - $out = $base; - // Append text to base. - if ( is_string( $text ) && ! empty( $text ) ) { - $out .= "_{$text}"; - } - return $out; - }; - // Get options form field group ID. - $qvar = $qv(); - // Use form submission data when no values provided. - if ( empty( $values ) && isset( $_POST[ $qvar ] ) && check_admin_referer( $qvar, $qv( 'nonce' ) ) ) { - /** @var array $values */ - $values = $_POST[ $qvar ]; - // Append non-submitted, but rendered fields (e.g. unchecked checkboxes) - $qvar_items = $qv( 'items' ); - /** @var string[] $items_bool Boolean options rendered in submitted form. */ - $items_bool = ( isset( $_POST[ $qvar_items ] ) ) ? $_POST[ $qvar_items ] : null; - if ( ! empty( $items_bool ) && is_array( $items_bool) ) { - foreach ( $items_bool as $item_id ) { - // Add missing boolean options (false == unchecked). - if ( ! array_key_exists( $item_id, $values ) && $this->has( $item_id ) && is_bool( $this->get_default( $item_id ) ) ) { - $values_valid[ $item_id ] = false; - } - } - } - unset( $qvar, $qvar_items, $items_bool, $item_id ); - } - // Process values. - /** - * @var string $id Option ID. - * @var mixed $val Option value (raw/unsanitized). - */ - foreach ( $values as $id => $val ) { - // Do not process invalid option IDs or invalid (non-scalar) data. - if ( ! $this->has( $id ) || ! is_scalar( $val ) ) { - continue; - } - // Conform to option's data type and sanitize. - /** @var scalar $d Option's default data. */ - $d = $this->get_default( $id ); - // Boolean. - if ( is_bool( $d ) ) { - $val = !! $val; - } - // Numeric - do not process non-numeric values for int/float fields. - elseif ( ( is_int( $d ) || is_float( $d ) ) && ! is_numeric( $val ) ) { - continue; - } - // Integer. - elseif ( is_int( $d ) ) { - $val = (int) $val; - } - // Float. - elseif ( is_float( $d ) ) { - $val = (float) $val; - } - // Defaut: Handle as string. - else { - $val = sanitize_text_field( wp_unslash( $val ) ); - } - // Add to validated data. - $values_valid[ $id ] = $val; - } - unset( $id, $val ); - - // Return validated values. - return $values_valid; - } - - /* Data */ - - /** - * Retrieve options from database - * @uses get_option to retrieve option data - * @return array Options data - */ - function fetch_data($sanitize = true) { - // Get data - $data = get_option($this->get_key(), null); - if ( $sanitize && is_array($data) ) { - // Sanitize loaded data based on default values - foreach ( $data as $id => $val ) { - if ( $this->has($id) ) { - $opt = $this->get($id); - if ( is_bool($opt->get_default()) ) - $data[$id] = !!$val; - } - } - } - return $data; - } - - /** - * Retrieves option data for collection - * @see SLB_Field_Collection::load_data() - */ - function load_data() { - if ( !$this->data_loaded ) { - // Retrieve data - $this->data = $this->fetch_data(); - parent::load_data(); - // Check update - $this->check_update(); - } - } - - /** - * Resets option values to their default values - * @param bool $hard Reset all options if TRUE (default), Reset only unset options if FALSE - */ - function reset($hard = true) { - $this->load_data(); - // Reset data - if ( $hard ) { - $this->data = null; - } - // Save - $this->save(); - } - - /** - * Save options data to database - */ - function save() { - $this->normalize_data(); - update_option($this->get_key(), $this->data); - } - - /** - * Normalize data - * Assures that data in collection match items - * @uses self::data to reset and save collection data after normalization - */ - function normalize_data() { - $data = array(); - foreach ( $this->get_items() as $id => $opt ) { - $data[$id] = $opt->get_data(); - } - $this->data =& $data; - return $data; - } - - /* Collection */ - - /** - * Build key for saving/retrieving data to options table - * @return string Key - */ - function get_key() { - return $this->add_prefix($this->get_id()); - } - - /** - * Add option to collection - * @uses SLB_Field_Collection::add() to add item - * @param string $id Unique item ID - * @param array $properties Item properties - * @param bool $update (optional) Should item be updated or overwritten (Default: FALSE) - * @return SLB_Option Option instance - */ - function &add($id, $properties = array(), $update = false) { - // Create item - $args = func_get_args(); - $ret = call_user_func_array(array('parent', 'add'), $args); - return $ret; - } - - /** - * Retrieve option value - * @uses get_data() to retrieve option data - * @param string $option Option ID to retrieve value for - * @param string $context (optional) Context for formatting data - * @return mixed Option value - */ - function get_value($option, $context = '') { - return $this->get_data($option, $context); - } - - /** - * Retrieve option value as boolean (true/false) - * @uses get_data() to retrieve option data - * @param string $option Option ID to retrieve value for - * @return bool Option value - */ - function get_bool($option) { - return $this->get_value($option, 'bool'); - } - - function get_string($option) { - return $this->get_value($option, 'string'); - } - - /** - * Retrieve option's default value - * @uses get_data() to retrieve option data - * @param string $option Option ID to retrieve value for - * @param string $context (optional) Context for formatting data - * @return mixed Option's default value - */ - function get_default($option, $context = '') { - return $this->get_data($option, $context, false); - } - - /* Output */ - - function build_init() { - if ( $this->build_vars['validate_pre'] ) { - $values = $this->validate(); - if ( $this->build_vars['save_pre'] ) { - $this->set_data($values); - } - } - } - - /** - * Build array of option values for client output - * @return array Associative array of options - */ - function build_client_output() { - $items = $this->get_items(); - $out = array(); - foreach ( $items as $option ) { - if ( !$option->get_in_client() ) - continue; - $out[$option->get_id()] = $option->get_data('default'); - } - return $out; - } - - /* Admin */ - - /** - * Handles output building for options on admin pages - * @param obj|array $opts Options instance or Array of options instance and groups to build - * @param obj $page Admin Page instance - * @param obj $state Admin Page state properties - */ - public function admin_page_render_content($opts, $page, $state) { - $groups = null; - if ( is_array($opts) && count($opts) == 2 ) { - $groups = $opts[1]; - $opts = $opts[0]; - } - if ( $opts === $this ) { - // Set build variables and callbacks - $this->set_build_var('admin_page', $page); - $this->set_build_var('admin_state', $state); - if ( !empty($groups) ) { - $this->set_build_var('groups', $groups); - } - $hooks = array ( - 'filter' => array ( - 'parse_build_vars' => array( $this->m('admin_parse_build_vars'), 10, 2 ) - ) - ); - - // Add hooks - foreach ( $hooks as $type => $hook ) { - $m = 'add_' . $type; - foreach ( $hook as $tag => $args ) { - array_unshift($args, $tag); - call_user_func_array($this->util->m($m), $args); - } - } - - // Build output - $this->build(array('build_groups' => $this->m('admin_build_groups'))); - - // Remove hooks - foreach ( $hooks as $type => $hook ) { - $m = 'remove_' . $type; - foreach ( $hook as $tag => $args ) { - call_user_func($this->util->m($m), $tag, $args[0]); - } - } - // Clear custom build vars - $this->delete_build_var('admin_page'); - $this->delete_build_var('admin_state'); - } - } - - /** - * Builds option groups output - */ - public function admin_build_groups() { - $page = $this->get_build_var('admin_page'); - $state = $this->get_build_var('admin_state'); - $groups = $this->get_build_var('groups'); - - // Get all groups - $groups_all = $this->get_groups(); - if ( empty($groups) ) { - $groups = array_keys($groups_all); - } - // Iterate through groups - foreach ( $groups as $gid ) { - // Validate - if ( !isset($groups_all[$gid]) || !count($this->get_items($gid)) ) { - continue; - } - // Add meta box for each group - $g = $groups_all[$gid]; - add_meta_box($g->id, $g->title, $this->m('admin_build_group'), $state->screen, $state->context, $state->priority, array('group' => $g->id, 'page' => $page)); - } - } - - /** - * Group output handler for admin pages - * @param obj $obj Object passed by `do_meta_boxes()` call (Default: NULL) - * @param array $box Meta box properties - */ - public function admin_build_group($obj, $box) { - $a = $box['args']; - $group = $a['group']; - $this->build_group($group); - } - - /** - * Parse build vars - * @uses `options_parse_build_vars` filter hook - */ - public function admin_parse_build_vars($vars, $opts) { - // Handle form submission - if ( isset($_POST[$opts->get_id('formatted')]) ) { - $vars['validate_pre'] = $vars['save_pre'] = true; - } - return $vars; - } - - /** - * Admin reset handler - * @param bool $res Current result - * @param obj $opts Options instance - * @param obj $reset Admin Reset instance - */ - public function admin_action_reset($res, $opts, $reset) { - // Only process matching options instance - if ( $opts === $this ) { - // Reset options - $this->reset(); - // Set result - $res = true; - } - return $res; - } -} \ No newline at end of file + false, + 'validate_post' => false, + 'save_pre' => false, + 'save_post' => false, + ); + + /* Init */ + + function __construct( $id = '', $props = array() ) { + // Validate arguments + $args = func_get_args(); + // Set default ID + if ( ! $this->validate_id( $id ) ) { + $id = 'options'; + } + $defaults = $this->integrate_id( $id ); + $props = $this->make_properties( $args, $defaults ); + parent::__construct( $props ); + $this->add_prefix_ref( $this->version_key ); + } + + protected function _hooks() { + parent::_hooks(); + // Register fields + $this->util->add_action( 'register_fields', $this->m( 'register_fields' ), 10, 1, false ); + // Set option parents + $this->util->add_action( 'fields_registered', $this->m( 'set_parents' ), 10, 1, false ); + // Building + $this->util->add_action( 'build_init', $this->m( 'build_init' ) ); + // Admin + $this->util->add_action( 'admin_page_render_content', $this->m( 'admin_page_render_content' ), 10, 3, false ); + $this->util->add_filter( 'admin_action_reset', $this->m( 'admin_action_reset' ), 10, 3, false ); + } + + /* Legacy/Migration */ + + /** + * Checks whether new version has been installed and migrates necessary settings + * @uses $version_key as option name + * @uses get_option() to retrieve saved version number + * @uses SLB_Utilities::get_plugin_version() to retrieve current version + * @return bool TRUE if version has been changed + */ + function check_update() { + if ( ! $this->version_checked ) { + $this->version_checked = true; + $version_changed = false; + // Get version from DB + $vo = $this->get_version(); + // Get current version + $vn = $this->util->get_plugin_version(); + // Compare versions + if ( $vo !== $vn ) { + // Update saved version + $this->set_version( $vn ); + // Migrate old version to new version + if ( strcasecmp( $vo, $vn ) < 0 ) { + // Force full migration + $version_changed = true; + } + } + // Migrate + $this->migrate( $version_changed ); + } + + return $this->version_checked; + } + + /** + * Save plugin version to DB + * If no version supplied, will fetch plugin data to determine version + * @uses $version_key as option name + * @uses update_option() to save version to options table + * @param string $ver (optional) Plugin version + */ + function set_version( $ver = null ) { + if ( empty( $ver ) ) { + $ver = $this->util->get_plugin_version(); + } + return update_option( $this->version_key, $ver ); + } + + /** + * Retrieve saved version data + * @return string Saved version + */ + function get_version() { + return get_option( $this->version_key, '' ); + } + + /** + * Migrate options from old versions to current version + * @uses self::items_migrated to determine if simple migration has been performed in current request or not + * @uses self::save() to save data after migration + * @param bool $full Whether to perform a full migration or not (Default: No) + */ + function migrate( $full = false ) { + if ( ! $full && $this->items_migrated ) { + return false; + } + + // Legacy options + $d = null; + $this->load_data(); + + $items = $this->get_items(); + + // Migrate separate options to unified option + if ( $full ) { + foreach ( $items as $opt => $props ) { + $oid = $this->add_prefix( $opt ); + $o = get_option( $oid, $d ); + if ( $o !== $d ) { + // Migrate value to data array + $this->set_data( $opt, $o, false ); + // Delete legacy option + delete_option( $oid ); + } + } + } + + // Migrate legacy items + if ( is_array( $this->properties_init ) && isset( $this->properties_init['legacy'] ) && is_array( $this->properties_init['legacy'] ) ) { + $l =& $this->properties_init['legacy']; + // Normalize legacy map + foreach ( $l as $opt => $dest ) { + if ( ! is_array( $dest ) ) { + if ( is_string( $dest ) ) { + $l[ $opt ] = array( $dest ); + } else { + unset( $l[ $opt ] ); + } + } + } + + /* Separate options */ + if ( $full ) { + foreach ( $l as $opt => $dest ) { + $oid = $this->add_prefix( $opt ); + $o = get_option( $oid, $d ); + // Only migrate valid values + if ( $o !== $d ) { + // Process destinations + foreach ( $dest as $id ) { + $this->set_data( $id, $o, false, true ); + } + } + // Remove legacy option + delete_option( $oid ); + } + } + + /* Simple Migration (Internal options only) */ + + // Get existing items that are also legacy items + $opts = array_intersect_key( $this->get_data(), $l ); + foreach ( $opts as $opt => $val ) { + $d = $this->get_data( $opt ); + // Migrate data from old option to new option + $dest = $l[ $opt ]; + // Validate new options to send data to + foreach ( $dest as $id ) { + $this->set_data( $id, $d, false, true ); + } + // Remove legacy option + $this->remove( $opt, false ); + } + } + // Save changes + $this->save(); + // Set flag + $this->items_migrated = true; + } + + /* Option setup */ + + /** + * Get elements for creating fields + * @return obj + */ + function get_field_elements() { + static $o = null; + if ( empty( $o ) ) { + $o = new stdClass(); + /* Layout */ + $layout = new stdClass(); + $layout->label = ''; + $layout->label_ref = '{label ref_base="layout"}'; + $layout->field_pre = '
'; + $layout->field_post = '
'; + $layout->opt_pre = '
'; + $layout->opt_post = '
'; + $layout->form = '<{form_attr ref_base="layout"} /> (' . __( 'Default', 'simple-lightbox' ) . ': {data context="display" top="0"})'; + /* Combine */ + $o->layout =& $layout; + } + return $o; + } + + /** + * Register option-specific fields + * @param SLB_Fields $fields Reference to global fields object + * @return void + */ + function register_fields( $fields ) { + // Layouts + $o = $this->get_field_elements(); + $l =& $o->layout; + + $form = implode( + '', + array( + $l->opt_pre, + $l->label_ref, + $l->field_pre, + $l->form, + $l->field_post, + $l->opt_post, + ) + ); + + // Text input + $otxt = new SLB_Field_Type( 'option_text', 'text' ); + $otxt->set_property( 'class', '{inherit} code' ); + $otxt->set_property( 'size', null ); + $otxt->set_property( 'value', '{data}' ); + $otxt->set_layout( 'label', $l->label ); + $otxt->set_layout( 'form', $form ); + $fields->add( $otxt ); + + // Checkbox + $ocb = new SLB_Field_Type( 'option_checkbox', 'checkbox' ); + $ocb->set_layout( 'label', $l->label ); + $ocb->set_layout( 'field_reference', sprintf( '', "{$this->get_id('formatted')}_items[]" ) ); + $ocb->set_layout( 'form', '{field_reference ref_base="layout"}' . $form ); + $fields->add( $ocb ); + + // Select + $othm = new SLB_Field_Type( 'option_select', 'select' ); + $othm->set_layout( 'label', $l->label ); + $othm->set_layout( 'form_start', $l->field_pre . '{inherit}' ); + $othm->set_layout( 'form_end', '{inherit}' . $l->field_post ); + $othm->set_layout( 'form', $l->opt_pre . '{inherit}' . $l->opt_post ); + $fields->add( $othm ); + } + + /** + * Set parent field types for options + * Parent only set for Admin pages + * @uses SLB_Option::set_parent() to set parent field for each option item + * @uses is_admin() to determine if current request is admin page + * @param object $fields Collection of default field types + * @return void + */ + function set_parents( $fields ) { + if ( ! is_admin() ) { + return false; + } + $items = &$this->get_items(); + foreach ( array_keys( $items ) as $opt ) { + $items[ $opt ]->set_parent(); + } + foreach ( $this->items as $opt ) { + $p = $opt->parent; + if ( is_object( $p ) ) { + $p = 'o:' . $p->id; + } + } + } + + /* Processing */ + + /** + * Validates option data. + * + * Validates option values (e.g. prior to saving to DB, after form submission, etc.). + * Values are formatted and sanitized according to corresponding option's data type + * (e.g. boolean, string, number, etc.). + * + * @since 1.5.5 + * + * @param array $values Optional. Option data to validate. + * Indexed by option ID. + * Default form-submission data used. + * @return array Validated data. Indexed by option ID. + */ + function validate( $values = null ) { + /** @var array $values_valid Validated option data. Indexed by option ID. */ + $values_valid = []; + // Enforce values data type. + if ( ! is_array( $values ) ) { + /** @var array $values */ + $values = []; + } + /** + * Generates query variable using common base. + * + * @since 2.8.0 + * + * @param string $text Optional. Text to append to base. + * + * @return string Query variable name. Format: "{base}_{text}". Default "{base}". + */ + $qv = function ( $text = '' ) { + static $base; + // Get base. + if ( empty( $base ) ) { + $base = $this->get_id( 'formatted' ); + } + $out = $base; + // Append text to base. + if ( is_string( $text ) && ! empty( $text ) ) { + $out .= "_{$text}"; + } + return $out; + }; + // Get options form field group ID. + $qvar = $qv(); + // Use form submission data when no values provided. + if ( empty( $values ) && isset( $_POST[ $qvar ] ) && check_admin_referer( $qvar, $qv( 'nonce' ) ) ) { + /** @var array $values */ + $values = $_POST[ $qvar ]; + // Append non-submitted, but rendered fields (e.g. unchecked checkboxes) + $qvar_items = $qv( 'items' ); + /** @var string[] $items_bool Boolean options rendered in submitted form. */ + $items_bool = ( isset( $_POST[ $qvar_items ] ) ) ? $_POST[ $qvar_items ] : null; + if ( ! empty( $items_bool ) && is_array( $items_bool ) ) { + foreach ( $items_bool as $item_id ) { + // Add missing boolean options (false == unchecked). + if ( ! array_key_exists( $item_id, $values ) && $this->has( $item_id ) && is_bool( $this->get_default( $item_id ) ) ) { + $values_valid[ $item_id ] = false; + } + } + } + unset( $qvar, $qvar_items, $items_bool, $item_id ); + } + // Process values. + /** + * @var string $id Option ID. + * @var mixed $val Option value (raw/unsanitized). + */ + foreach ( $values as $id => $val ) { + // Do not process invalid option IDs or invalid (non-scalar) data. + if ( ! $this->has( $id ) || ! is_scalar( $val ) ) { + continue; + } + // Conform to option's data type and sanitize. + /** @var scalar $d Option's default data. */ + $d = $this->get_default( $id ); + if ( is_bool( $d ) ) { + // Boolean. + $val = ! ! $val; + } elseif ( ( is_int( $d ) || is_float( $d ) ) && ! is_numeric( $val ) ) { + // Numeric - do not process non-numeric values for int/float fields. + continue; + } elseif ( is_int( $d ) ) { + // Integer. + $val = (int) $val; + } elseif ( is_float( $d ) ) { + // Float. + $val = (float) $val; + } else { + // Defaut: Handle as string. + $val = sanitize_text_field( wp_unslash( $val ) ); + } + // Add to validated data. + $values_valid[ $id ] = $val; + } + unset( $id, $val ); + + // Return validated values. + return $values_valid; + } + + /* Data */ + + /** + * Retrieve options from database + * @uses get_option to retrieve option data + * @return array Options data + */ + function fetch_data( $sanitize = true ) { + // Get data + $data = get_option( $this->get_key(), null ); + if ( $sanitize && is_array( $data ) ) { + // Sanitize loaded data based on default values + foreach ( $data as $id => $val ) { + if ( $this->has( $id ) ) { + $opt = $this->get( $id ); + if ( is_bool( $opt->get_default() ) ) { + $data[ $id ] = ! ! $val; + } + } + } + } + return $data; + } + + /** + * Retrieves option data for collection + * @see SLB_Field_Collection::load_data() + */ + function load_data() { + if ( ! $this->data_loaded ) { + // Retrieve data + $this->data = $this->fetch_data(); + parent::load_data(); + // Check update + $this->check_update(); + } + } + + /** + * Resets option values to their default values + * @param bool $hard Reset all options if TRUE (default), Reset only unset options if FALSE + */ + function reset( $hard = true ) { + $this->load_data(); + // Reset data + if ( $hard ) { + $this->data = null; + } + // Save + $this->save(); + } + + /** + * Save options data to database + */ + function save() { + $this->normalize_data(); + update_option( $this->get_key(), $this->data ); + } + + /** + * Normalize data + * Assures that data in collection match items + * @uses self::data to reset and save collection data after normalization + */ + function normalize_data() { + $data = array(); + foreach ( $this->get_items() as $id => $opt ) { + $data[ $id ] = $opt->get_data(); + } + $this->data =& $data; + return $data; + } + + /* Collection */ + + /** + * Build key for saving/retrieving data to options table + * @return string Key + */ + function get_key() { + return $this->add_prefix( $this->get_id() ); + } + + /** + * Add option to collection + * @uses SLB_Field_Collection::add() to add item + * @param string $id Unique item ID + * @param array $properties Item properties + * @param bool $update (optional) Should item be updated or overwritten (Default: FALSE) + * @return SLB_Option Option instance + */ + function &add( $id, $properties = array(), $update = false ) { + // Create item + $args = func_get_args(); + $ret = call_user_func_array( array( 'parent', 'add' ), $args ); + return $ret; + } + + /** + * Retrieve option value + * @uses get_data() to retrieve option data + * @param string $option Option ID to retrieve value for + * @param string $context (optional) Context for formatting data + * @return mixed Option value + */ + function get_value( $option, $context = '' ) { + return $this->get_data( $option, $context ); + } + + /** + * Retrieve option value as boolean (true/false) + * @uses get_data() to retrieve option data + * @param string $option Option ID to retrieve value for + * @return bool Option value + */ + function get_bool( $option ) { + return $this->get_value( $option, 'bool' ); + } + + function get_string( $option ) { + return $this->get_value( $option, 'string' ); + } + + /** + * Retrieve option's default value + * @uses get_data() to retrieve option data + * @param string $option Option ID to retrieve value for + * @param string $context (optional) Context for formatting data + * @return mixed Option's default value + */ + function get_default( $option, $context = '' ) { + return $this->get_data( $option, $context, false ); + } + + /* Output */ + + function build_init() { + if ( $this->build_vars['validate_pre'] ) { + $values = $this->validate(); + if ( $this->build_vars['save_pre'] ) { + $this->set_data( $values ); + } + } + } + + /** + * Build array of option values for client output + * @return array Associative array of options + */ + function build_client_output() { + $items = $this->get_items(); + $out = array(); + foreach ( $items as $option ) { + if ( ! $option->get_in_client() ) { + continue; + } + $out[ $option->get_id() ] = $option->get_data( 'default' ); + } + return $out; + } + + /* Admin */ + + /** + * Handles output building for options on admin pages + * @param obj|array $opts Options instance or Array of options instance and groups to build + * @param obj $page Admin Page instance + * @param obj $state Admin Page state properties + */ + public function admin_page_render_content( $opts, $page, $state ) { + $groups = null; + if ( is_array( $opts ) && count( $opts ) === 2 ) { + $groups = $opts[1]; + $opts = $opts[0]; + } + if ( $opts === $this ) { + // Set build variables and callbacks + $this->set_build_var( 'admin_page', $page ); + $this->set_build_var( 'admin_state', $state ); + if ( ! empty( $groups ) ) { + $this->set_build_var( 'groups', $groups ); + } + $hooks = array( + 'filter' => array( + 'parse_build_vars' => array( $this->m( 'admin_parse_build_vars' ), 10, 2 ), + ), + ); + + // Add hooks + foreach ( $hooks as $type => $hook ) { + $m = 'add_' . $type; + foreach ( $hook as $tag => $args ) { + array_unshift( $args, $tag ); + call_user_func_array( $this->util->m( $m ), $args ); + } + } + + // Build output + $this->build( array( 'build_groups' => $this->m( 'admin_build_groups' ) ) ); + + // Remove hooks + foreach ( $hooks as $type => $hook ) { + $m = 'remove_' . $type; + foreach ( $hook as $tag => $args ) { + call_user_func( $this->util->m( $m ), $tag, $args[0] ); + } + } + // Clear custom build vars + $this->delete_build_var( 'admin_page' ); + $this->delete_build_var( 'admin_state' ); + } + } + + /** + * Builds option groups output + */ + public function admin_build_groups() { + $page = $this->get_build_var( 'admin_page' ); + $state = $this->get_build_var( 'admin_state' ); + $groups = $this->get_build_var( 'groups' ); + + // Get all groups + $groups_all = $this->get_groups(); + if ( empty( $groups ) ) { + $groups = array_keys( $groups_all ); + } + // Iterate through groups + foreach ( $groups as $gid ) { + // Validate + if ( ! isset( $groups_all[ $gid ] ) || ! count( $this->get_items( $gid ) ) ) { + continue; + } + // Add meta box for each group + $g = $groups_all[ $gid ]; + add_meta_box( + $g->id, + $g->title, + $this->m( 'admin_build_group' ), + $state->screen, + $state->context, + $state->priority, + array( + 'group' => $g->id, + 'page' => $page, + ) + ); + } + } + + /** + * Group output handler for admin pages + * @param obj $obj Object passed by `do_meta_boxes()` call (Default: NULL) + * @param array $box Meta box properties + */ + public function admin_build_group( $obj, $box ) { + $a = $box['args']; + $group = $a['group']; + $this->build_group( $group ); + } + + /** + * Parse build vars + * @uses `options_parse_build_vars` filter hook + */ + public function admin_parse_build_vars( $vars, $opts ) { + // Handle form submission + if ( isset( $_POST[ $opts->get_id( 'formatted' ) ] ) ) { + $vars['save_pre'] = true; + $vars['validate_pre'] = true; + } + return $vars; + } + + /** + * Admin reset handler + * @param bool $res Current result + * @param obj $opts Options instance + * @param obj $reset Admin Reset instance + */ + public function admin_action_reset( $res, $opts, $reset ) { + // Only process matching options instance + if ( $opts === $this ) { + // Reset options + $this->reset(); + // Set result + $res = true; + } + return $res; + } +} diff --git a/includes/class.template_tag.php b/includes/class.template_tag.php index 145960e..c5f1ead 100644 --- a/includes/class.template_tag.php +++ b/includes/class.template_tag.php @@ -6,4 +6,4 @@ * @subpackage Template * @author Archetyped */ -class SLB_Template_Tag extends SLB_Component { } \ No newline at end of file +class SLB_Template_Tag extends SLB_Component { } diff --git a/includes/class.template_tags.php b/includes/class.template_tags.php index d624512..b037073 100644 --- a/includes/class.template_tags.php +++ b/includes/class.template_tags.php @@ -31,9 +31,9 @@ class SLB_Template_Tags extends SLB_Collection_Controller { protected function _hooks() { parent::_hooks(); - $this->util->add_action('init', $this->m('init_defaults')); - $this->util->add_action('footer', $this->m('client_output'), 1, 0, false); - $this->util->add_filter('footer_script', $this->m('client_output_script'), $this->util->priority('client_footer_output'), 1, false); + $this->util->add_action( 'init', $this->m( 'init_defaults' ) ); + $this->util->add_action( 'footer', $this->m( 'client_output' ), 1, 0, false ); + $this->util->add_filter( 'footer_script', $this->m( 'client_output_script' ), $this->util->priority( 'client_footer_output' ), 1, false ); } /* Collection Management */ @@ -46,10 +46,10 @@ protected function _hooks() { * @param array $props Tag properties * @return object Current instance */ - public function add($id, $props = array()) { - $o = ( is_string($id) ) ? new $this->item_type($id, $props) : $id; + public function add( $id, $props = array() ) { + $o = ( is_string( $id ) ) ? new $this->item_type( $id, $props ) : $id; // Add to collection - return parent::add($o); + return parent::add( $o ); } /* Defaults */ @@ -58,24 +58,24 @@ public function add($id, $props = array()) { * Initialize default template tags * @param SLB_Template_Tags $tags Tags controller */ - public function init_defaults($tags) { - $js_path = 'js/'; + public function init_defaults( $tags ) { + $js_path = 'js/'; $js_path .= ( SLB_DEV ) ? 'dev' : 'prod'; - $src_base = $this->util->get_file_url('template-tags', true); - $defaults = array ( - 'item' => array ( - 'scripts' => array ( - array ( 'base', "$src_base/item/$js_path/tag.item.js" ), - ) + $src_base = $this->util->get_file_url( 'template-tags', true ); + $defaults = array( + 'item' => array( + 'scripts' => array( + array( 'base', "$src_base/item/$js_path/tag.item.js" ), + ), ), - 'ui' => array ( - 'scripts' => array ( - array ( 'base', "$src_base/ui/$js_path/tag.ui.js" ), - ) + 'ui' => array( + 'scripts' => array( + array( 'base', "$src_base/ui/$js_path/tag.ui.js" ), + ), ), ); foreach ( $defaults as $id => $props ) { - $tags->add($id, $props); + $tags->add( $id, $props ); } } @@ -96,27 +96,27 @@ public function client_output() { * @param array $commands Client script commands * @return array Modified script commands */ - public function client_output_script($commands) { - $out = array('/* TPLT */'); + public function client_output_script( $commands ) { + $out = array( '/* TPLT */' ); $code = array(); foreach ( $this->get() as $tag ) { - $styles = $tag->get_styles(array('uri_format'=>'full')); - if ( empty($styles) ) { + $styles = $tag->get_styles( array( 'uri_format' => 'full' ) ); + if ( empty( $styles ) ) { continue; } // Setup client parameters - $params = array( - sprintf("'%s'", $tag->get_id()), + $params = array( + sprintf( "'%s'", $tag->get_id() ), ); - $params[] = json_encode( array('styles' => array_values($styles)) ); + $params[] = wp_json_encode( array( 'styles' => array_values( $styles ) ) ); // Extend handler in client - $code[] = $this->util->call_client_method('View.extend_template_tag_handler', $params, false); + $code[] = $this->util->call_client_method( 'View.extend_template_tag_handler', $params, false ); } - if ( !empty($code) ) { - $out[] = implode('', $code); - $commands[] = implode(PHP_EOL, $out); + if ( ! empty( $code ) ) { + $out[] = implode( '', $code ); + $commands[] = implode( PHP_EOL, $out ); } return $commands; } -} \ No newline at end of file +} diff --git a/includes/class.theme.php b/includes/class.theme.php index 405162c..99d849c 100644 --- a/includes/class.theme.php +++ b/includes/class.theme.php @@ -9,7 +9,7 @@ class SLB_Theme extends SLB_Component { /* Properties */ - protected $props_required = array('name'); + protected $props_required = array( 'name' ); /** * Public flag @@ -24,7 +24,7 @@ class SLB_Theme extends SLB_Component { * @param bool $sort_topdown (optional) Ancestor sorting (Default: Nearest to Farthest) * @return array Theme's ancestors (sorted by nearest to most distant ancestor) */ - public function get_ancestors($sort_topdown = false) { + public function get_ancestors( $sort_topdown = false ) { $ret = array(); /** * @var SLB_Theme @@ -33,7 +33,7 @@ public function get_ancestors($sort_topdown = false) { while ( $thm->has_parent() ) { $par = $thm->get_parent(); // Add ancestor - if ( $par->is_valid() && !in_array($par, $ret, true) ) { + if ( $par->is_valid() && ! in_array( $par, $ret, true ) ) { $ret[] = $par; } // Get next ancestor @@ -41,7 +41,7 @@ public function get_ancestors($sort_topdown = false) { } // Sorting if ( $sort_topdown ) { - $ret = array_reverse($ret); + $ret = array_reverse( $ret ); } return $ret; } @@ -50,8 +50,8 @@ public function get_ancestors($sort_topdown = false) { * Set public flag * @param bool $public */ - public function set_public($public) { - $this->public = !!$public; + public function set_public( $public ) { + $this->public = ! ! $public; } /** @@ -59,7 +59,7 @@ public function set_public($public) { * @return bool */ public function get_public() { - return !!$this->public; + return ! ! $this->public; } /* Templates */ @@ -71,8 +71,8 @@ public function get_public() { * @param string $src Template URI * @return obj Current instance */ - protected function add_template($handle, $src) { - return $this->add_file('template', $handle, $src); + protected function add_template( $handle, $src ) { + return $this->add_file( 'template', $handle, $src ); } /** @@ -82,8 +82,8 @@ protected function add_template($handle, $src) { * @param string $format (optional) Return value format * @return mixed Template file (Default: array of file properties @see `Base_Object::add_file()`) */ - protected function get_template($handle, $format = null) { - return $this->get_file('template', $handle, $format); + protected function get_template( $handle, $format = null ) { + return $this->get_file( 'template', $handle, $format ); } /* Layout */ @@ -94,8 +94,8 @@ protected function get_template($handle, $format = null) { * @param string $src Layout file URI * @return Current instance */ - public function set_layout($src) { - return $this->add_template('layout', $src); + public function set_layout( $src ) { + return $this->add_template( 'layout', $src ); } /** @@ -103,7 +103,7 @@ public function set_layout($src) { * @param string $format (optional) Layout data format * @return mixed Theme layout */ - public function get_layout($format = null) { - return $this->get_template('layout', $format); + public function get_layout( $format = null ) { + return $this->get_template( 'layout', $format ); } -} \ No newline at end of file +} diff --git a/includes/class.themes.php b/includes/class.themes.php index 729adfb..3a60ed2 100644 --- a/includes/class.themes.php +++ b/includes/class.themes.php @@ -1,296 +1,303 @@ -util->add_action('init', $this->m('init_defaults'), 1); - - // Client output - $this->util->add_action('footer', $this->m('client_output'), 1, 0, false); - $this->util->add_filter('footer_script', $this->m('client_output_script'), $this->util->priority('client_footer_output'), 1, false); - } - - protected function _options() { - $opts = array ( - 'items' => array ( - 'theme_default' => array ( - 'title' => __('Theme', 'simple-lightbox'), - 'default' => $this->get_default_id(), - 'group' => array('ui', 0), - 'parent' => 'option_select', - 'options' => $this->m('opt_get_field_values'), - 'in_client' => true - ), - ) - ); - - parent::_set_options($opts); - } - - /** - * Add default themes - * @param SLB_Themes $themes Themes controller - */ - function init_defaults($themes) { - $js_path = 'js/'; - $js_path .= ( SLB_DEV ) ? 'dev' : 'prod'; - $scheme = is_ssl() ? 'https' : 'http'; - $baseline = $this->add_prefix('baseline'); - $src_base = $this->util->get_file_url('themes', true); - $defaults = array ( - $baseline => array ( - 'name' => __('Baseline', 'simple-lightbox'), - 'public' => false, - 'layout' => "$src_base/baseline/layout.html", - 'scripts' => array ( - array ( 'base', $src_base . "/baseline/$js_path/client.js" ), - ), - 'styles' => array ( - array ( 'base', "$src_base/baseline/css/style.css" ), - ), - ), - $this->get_default_id() => array ( - 'name' => __('Default (Light)', 'simple-lightbox'), - 'parent' => $baseline, - 'scripts' => array ( - array ( 'base', $src_base . "/default/$js_path/client.js" ), - ), - 'styles' => array ( - array ( 'base', "$src_base/default/css/style.css" ), - ), - ), - $this->add_prefix('black') => array ( - 'name' => __('Default (Dark)', 'simple-lightbox'), - 'parent' => $this->get_default_id(), - 'styles' => array ( - array ( 'base', "$src_base/black/css/style.css" ) - ) - ), - ); - - foreach ( $defaults as $id => $props ) { - $themes->add($id, $props); - } - } - - /* Collection management */ - - /** - * Add theme - * Accepts properties to create new theme or previously-created theme instance - * @uses parent::add() - * @param string|object $id Theme ID (or Theme object) - * @param array $props Theme properties - * @return object Current instance - */ - public function add($id, $props = array()) { - // Prepare parent - if ( isset($props['parent']) && !($props['parent'] instanceof $this->item_type) ) { - $pid = $props['parent']; - $items = $this->get(array('include_private' => true)); - if ( isset($items[$pid]) ) { - $props['parent'] = $items[$pid]; - } - } - $o = ( is_string($id) ) ? new $this->item_type($id, $props) : $id; - // Add to collection - return parent::add($o); - } - - /** - * Get themes - * @param array $args (optional) Arguments - * @return array Themes - */ - public function get($args = null) { - // Normalize arguments - $args_default = array( - 'include_public' => true, - 'include_private' => false, - ); - $r = wp_parse_args($args, $args_default); - $r['include_public'] = !!$r['include_public']; - $r['include_private'] = !!$r['include_private']; - - $items = parent::get($args); - - if ( empty($items) ) - return $items; - - /* Process custom arguments */ - - // Filter - $items_exclude = array(); - // Identify excluded themes - $filter_props = array('include_public' => true, 'include_private' => false); - foreach ( $filter_props as $filter_prop => $filter_value ) { - if ( !$r[ $filter_prop ] ) { - foreach ( $items as $id => $item ) { - if ( $item->get_public() == $filter_value ) { - $items_exclude[] = $id; - } - } - } - } - // Filter themes from collection - $items = array_diff_key($items, array_fill_keys($items_exclude, null)); - return $items; - } - - /* Helpers */ - - /** - * Retrieve default theme ID - * @uses `$id_default` - * @return string Default theme ID - */ - public function get_default_id() { - if ( !$this->id_default ) { - $this->id_default = $this->add_prefix('default'); - } - return $this->id_default; - } - - /** - * Retrieve currently-selected theme - * @return SLB_Theme Selected theme - */ - protected function get_selected() { - // Get themes - $thms = $this->get(); - // Retrieve currently-selected theme - $id = $this->options->get_value('theme_default'); - if ( !isset($thms[$id]) ) { - $id = $this->get_default_id(); - } - return $thms[$id]; - } - - /* Output */ - - /** - * Build client output - */ - public function client_output() { - // Process active theme - $thm = $this->get_selected(); - - // Get theme ancestors - $thms = $thm->get_ancestors(true); - $thms[] = $thm; - - foreach ( $thms as $thm ) { - // Load files - $thm->enqueue_scripts(); - } - } - - /** - * Client output script - * - * @param array $commands Client script commands - * @return array Modified script commands - */ - public function client_output_script($commands) { - // Theme - $thm = $this->get_selected(); - - // Process theme ancestors - $thms = $thm->get_ancestors(true); - $thms[] = $thm; - - $out = array('/* THM */'); - $code = array(); - - // Build output for each theme - foreach ( $thms as $thm ) { - // Setup client parameters - $params = array( - sprintf("'%s'", $thm->get_id()), - ); - // Theme properties - $thm_props = array( - 'name' => $thm->get_name(), - 'parent' => ( $thm->has_parent() ) ? $thm->get_parent()->get_id() : '', - 'styles' => array_values($thm->get_styles(array('uri_format'=>'full'))), - ); - /* Optional properties */ - // Layout - $layout = $thm->get_layout('contents'); - if ( !empty($layout) ) { - // Format - $layout = str_replace(array("\n", "\r", "\t"), '', $layout); - // Save - $thm_props['layout_raw'] = $layout; - } - // Add properties to parameters - $params[] = json_encode($thm_props); - - // Add theme to client - $code[] = $this->util->call_client_method('View.extend_theme', $params, false); - } - - if ( !empty($code) ) { - $out[] = implode('', $code); - $commands[] = implode(PHP_EOL, $out); - } - return $commands; - } - - /* Options */ - - /** - * Retrieve themes for use in option field - * @uses self::theme_default - * @return array Theme options - */ - public function opt_get_field_values() { - // Get themes - $items = $this->get(); - $d = $this->get_default_id(); - // Pop out default theme - if ( isset($items[$d]) ) { - $itm_d = $items[$d]; - unset($items[$d]); - } - - // Sort themes by name - uasort( $items, function( $a, $b ) { - return strcmp( $a->get_name(), $b->get_name() ); - }); - - // Insert default theme at top of array - if ( isset($itm_d) ) { - $items = array( $d => $itm_d ) + $items; - } - - // Build options - foreach ( $items as $item ) { - $items[$item->get_id()] = $item->get_name(); - } - return $items; - } -} \ No newline at end of file +util->add_action( 'init', $this->m( 'init_defaults' ), 1 ); + + // Client output + $this->util->add_action( 'footer', $this->m( 'client_output' ), 1, 0, false ); + $this->util->add_filter( 'footer_script', $this->m( 'client_output_script' ), $this->util->priority( 'client_footer_output' ), 1, false ); + } + + protected function _options() { + $opts = array( + 'items' => array( + 'theme_default' => array( + 'title' => __( 'Theme', 'simple-lightbox' ), + 'default' => $this->get_default_id(), + 'group' => array( 'ui', 0 ), + 'parent' => 'option_select', + 'options' => $this->m( 'opt_get_field_values' ), + 'in_client' => true, + ), + ), + ); + + parent::_set_options( $opts ); + } + + /** + * Add default themes + * @param SLB_Themes $themes Themes controller + */ + function init_defaults( $themes ) { + $js_path = 'js/'; + $js_path .= ( SLB_DEV ) ? 'dev' : 'prod'; + $scheme = is_ssl() ? 'https' : 'http'; + $baseline = $this->add_prefix( 'baseline' ); + $src_base = $this->util->get_file_url( 'themes', true ); + $defaults = array( + $baseline => array( + 'name' => __( 'Baseline', 'simple-lightbox' ), + 'public' => false, + 'layout' => "$src_base/baseline/layout.html", + 'scripts' => array( + array( 'base', $src_base . "/baseline/$js_path/client.js" ), + ), + 'styles' => array( + array( 'base', "$src_base/baseline/css/style.css" ), + ), + ), + $this->get_default_id() => array( + 'name' => __( 'Default (Light)', 'simple-lightbox' ), + 'parent' => $baseline, + 'scripts' => array( + array( 'base', $src_base . "/default/$js_path/client.js" ), + ), + 'styles' => array( + array( 'base', "$src_base/default/css/style.css" ), + ), + ), + $this->add_prefix( 'black' ) => array( + 'name' => __( 'Default (Dark)', 'simple-lightbox' ), + 'parent' => $this->get_default_id(), + 'styles' => array( + array( 'base', "$src_base/black/css/style.css" ), + ), + ), + ); + + foreach ( $defaults as $id => $props ) { + $themes->add( $id, $props ); + } + } + + /* Collection management */ + + /** + * Add theme + * Accepts properties to create new theme or previously-created theme instance + * @uses parent::add() + * @param string|object $id Theme ID (or Theme object) + * @param array $props Theme properties + * @return object Current instance + */ + public function add( $id, $props = array() ) { + // Prepare parent + if ( isset( $props['parent'] ) && ! ( $props['parent'] instanceof $this->item_type ) ) { + $pid = $props['parent']; + $items = $this->get( array( 'include_private' => true ) ); + if ( isset( $items[ $pid ] ) ) { + $props['parent'] = $items[ $pid ]; + } + } + $o = ( is_string( $id ) ) ? new $this->item_type( $id, $props ) : $id; + // Add to collection + return parent::add( $o ); + } + + /** + * Get themes + * @param array $args (optional) Arguments + * @return array Themes + */ + public function get( $args = null ) { + // Normalize arguments + $args_default = array( + 'include_public' => true, + 'include_private' => false, + ); + $r = wp_parse_args( $args, $args_default ); + $r['include_public'] = ! ! $r['include_public']; + $r['include_private'] = ! ! $r['include_private']; + + $items = parent::get( $args ); + + if ( empty( $items ) ) { + return $items; + } + + /* Process custom arguments */ + + // Filter + $items_exclude = array(); + // Identify excluded themes + $filter_props = array( + 'include_public' => true, + 'include_private' => false, + ); + foreach ( $filter_props as $filter_prop => $filter_value ) { + if ( ! $r[ $filter_prop ] ) { + foreach ( $items as $id => $item ) { + if ( $item->get_public() === $filter_value ) { + $items_exclude[] = $id; + } + } + } + } + // Filter themes from collection + $items = array_diff_key( $items, array_fill_keys( $items_exclude, null ) ); + return $items; + } + + /* Helpers */ + + /** + * Retrieve default theme ID + * @uses `$id_default` + * @return string Default theme ID + */ + public function get_default_id() { + if ( ! $this->id_default ) { + $this->id_default = $this->add_prefix( 'default' ); + } + return $this->id_default; + } + + /** + * Retrieve currently-selected theme + * @return SLB_Theme Selected theme + */ + protected function get_selected() { + // Get themes + $thms = $this->get(); + // Retrieve currently-selected theme + $id = $this->options->get_value( 'theme_default' ); + if ( ! isset( $thms[ $id ] ) ) { + $id = $this->get_default_id(); + } + return $thms[ $id ]; + } + + /* Output */ + + /** + * Build client output + */ + public function client_output() { + // Process active theme + $thm = $this->get_selected(); + + // Get theme ancestors + $thms = $thm->get_ancestors( true ); + $thms[] = $thm; + + foreach ( $thms as $thm ) { + // Load files + $thm->enqueue_scripts(); + } + } + + /** + * Client output script + * + * @param array $commands Client script commands + * @return array Modified script commands + */ + public function client_output_script( $commands ) { + // Theme + $thm = $this->get_selected(); + + // Process theme ancestors + $thms = $thm->get_ancestors( true ); + $thms[] = $thm; + + $out = array( '/* THM */' ); + $code = array(); + + // Build output for each theme + foreach ( $thms as $thm ) { + // Setup client parameters + $params = array( + sprintf( "'%s'", $thm->get_id() ), + ); + // Theme properties + $thm_props = array( + 'name' => $thm->get_name(), + 'parent' => ( $thm->has_parent() ) ? $thm->get_parent()->get_id() : '', + 'styles' => array_values( $thm->get_styles( array( 'uri_format' => 'full' ) ) ), + ); + /* Optional properties */ + // Layout + $layout = $thm->get_layout( 'contents' ); + if ( ! empty( $layout ) ) { + // Format + $layout = str_replace( array( "\n", "\r", "\t" ), '', $layout ); + // Save + $thm_props['layout_raw'] = $layout; + } + // Add properties to parameters + $params[] = wp_json_encode( $thm_props ); + + // Add theme to client + $code[] = $this->util->call_client_method( 'View.extend_theme', $params, false ); + } + + if ( ! empty( $code ) ) { + $out[] = implode( '', $code ); + $commands[] = implode( PHP_EOL, $out ); + } + return $commands; + } + + /* Options */ + + /** + * Retrieve themes for use in option field + * @uses self::theme_default + * @return array Theme options + */ + public function opt_get_field_values() { + // Get themes + $items = $this->get(); + $d = $this->get_default_id(); + // Pop out default theme + if ( isset( $items[ $d ] ) ) { + $itm_d = $items[ $d ]; + unset( $items[ $d ] ); + } + + // Sort themes by name + uasort( + $items, + function( $a, $b ) { + return strcmp( $a->get_name(), $b->get_name() ); + } + ); + + // Insert default theme at top of array + if ( isset( $itm_d ) ) { + $items = array( $d => $itm_d ) + $items; + } + + // Build options + foreach ( $items as $item ) { + $items[ $item->get_id() ] = $item->get_name(); + } + return $items; + } +} diff --git a/includes/class.utilities.php b/includes/class.utilities.php index e067d50..f87ed02 100644 --- a/includes/class.utilities.php +++ b/includes/class.utilities.php @@ -1,1863 +1,2038 @@ - null, - 'file' => null, - 'name' => null, - 'data' => null, - 'uri' => null, - 'headers' => array ( - 'Name' => 'Plugin Name', - 'PluginURI' => 'Plugin URI', - 'SupportURI' => 'Support URI', - 'Version' => 'Version', - 'Description' => 'Description', - 'Author' => 'Author', - 'AuthorURI' => 'Author URI', - ) - ); - - /** - * Plugin base path - * @var string - */ - private $_path_base = null; - - /** - * Standard hook priorities - * @var array - */ - private $_priorities = array ( - 'high' => 1, - 'low' => 99, - 'safe' => 15, - 'client_footer_output' => 25, - ); - - /* Constructors */ - - function __construct($obj) { - if ( is_object($obj) ) { - $this->_parent = $obj; - } - } - - /** - * Returns callback array to instance method - * @param object $obj Instance object - * @param string $method Name of method - * @return array Callback array - */ - function m($obj, $method = '') { - if ( is_string($obj) ) { - $method = $obj; - $obj = null; - } - if ( !is_object($obj) && isset($this) ) { - $obj = $this; - } - $cb = array($obj, $method); - return $cb; - } - - /* Helper Functions */ - - /*-** Prefix **-*/ - - /** - * Get valid separator - * @param string $sep (optional) Separator supplied - * @return string Separator - */ - function get_sep($sep = false) { - if ( is_null($sep) ) - $sep = ''; - return ( is_string($sep) ) ? $sep : '_'; - } - - /** - * Retrieve class prefix (with separator if set) - * @param bool|string $sep Separator to append to class prefix (Default: no separator) - * @return string Class prefix - */ - function get_prefix($sep = null) { - $sep = $this->get_sep($sep); - $prefix = ( !empty($this->_parent->prefix) ) ? $this->_parent->prefix . $sep : ''; - return $prefix; - } - - /** - * Check if a string is prefixed - * @param string|array $text Text to check for prefix - * @param string $sep (optional) Separator used - */ - function has_prefix($text, $sep = null) { - if ( empty($text) ) - return false; - if ( !is_array($text) ) - $text = array($text); - $text = array_values($text); - $text = $text[0]; - return ( !empty($text) && stripos($text, $this->get_prefix($sep)) === 0 ); - } - - /** - * Prepend plugin prefix to some text - * @param string|array $text Text to add to prefix - * @param string $sep (optional) Text used to separate prefix and text - * @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not - * @return string Text with prefix prepended - */ - function add_prefix($text, $sep = '_', $once = true) { - // Normalize data type (array) - if ( empty($text) ) - $text = array(''); - if ( !is_array($text) ) - $text = array($text); - // Add prefix (if necessary) - if ( !$once || ( $once && !$this->has_prefix($text, $sep) ) ) - array_unshift($text, $this->get_prefix()); - return implode($sep, $text); - } - - /** - * Prepend uppercased plugin prefix to some text - * @param string|array $text Text to add to prefix - * @param string $sep (optional) Text used to separate prefix and text - * @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not - * @return string Text with prefix prepended - */ - function add_prefix_uc($text, $sep = '_', $once = true) { - $args = func_get_args(); - $var = call_user_func_array($this->m($this, 'add_prefix'), $args); - $pre = $this->get_prefix(); - return str_replace($pre . $sep, strtoupper($pre) . $sep, $var); - } - - /** - * Add prefix to variable reference - * Updates actual variable rather than return value - * @uses add_prefix() to add prefix to variable - * @param string $var Variable to add prefix to - * @param string $sep (optional) Separator text - * @param bool $once (optional) Add prefix only once - * @return void - */ - function add_prefix_ref(&$var, $sep = null, $once = true) { - $args = func_get_args(); - $var = call_user_func_array($this->m($this, 'add_prefix'), $args); - } - - /** - * Remove prefix from specified string - * @param string $text String to remove prefix from - * @param string $sep (optional) Separator used with prefix - */ - function remove_prefix($text, $sep = '_') { - if ( $this->has_prefix($text,$sep) ) - $text = substr($text, strlen($this->get_prefix($sep))); - return $text; - } - - /** - * Returns Database prefix for plugin-related DB Tables - * @return string Database prefix - */ - function get_db_prefix() { - global $wpdb; - return $wpdb->prefix . $this->get_prefix('_'); - } - - /*-** Priority **-*/ - - /** - * Retrieve standard priority - * @var string $id Priority ID to retrieve - * @return int Priority - */ - public function priority($id = null) { - $pri = 10; - if ( !is_null($id) && array_key_exists($id, $this->_priorities) ) { - $pri = $this->_priorities[$id]; - } - return $pri; - } - - /* Wrapped Values */ - - /** - * Create wrapper object - * Properties - * > start - * > end - * @param string|array $start Start text (Can also be array defining start & end values) - * @param string $end (optional) End text - * If $end not defined, then $start is used - * @return obj Wrapper - */ - function get_wrapper($start = null, $end = null) { - // Validate existing wrapper - if ( is_object($start) && isset($start->start) && isset($start->end) ) - return $start; - - // Initialize wrapper - $w = array ( - 'start' => '[', - 'end' => ']', - ); - - if ( !empty($start) ) { - if ( is_string($start) ) { - $w['start'] = $start; - } elseif ( is_array($start) ) { - $start = array_values($start); - if ( is_string($start) ) { - $w['start'] = $start[0]; - } - if ( isset($start[1]) && is_string($start[1]) ) { - $w['end'] = $start[1]; - } - } - } - if ( is_string($end) ) { - $w['end'] = $end; - } - - return (object) $w; - } - - /** - * Check if text is wrapped by specified character(s) - * @uses this->get_wrapper() to Validate wrapper text - * @param string $text Text to check - * @param string|array $start (optional) Start text (Array defines both start/end text) - * @param string $end (optional) End text - */ - function has_wrapper($text, $start = null, $end = null) { - if ( !is_string($text) || empty($text) ) - return false; - // Validate wrapper - $w = $this->get_wrapper($start, $end); - - // Check for wrapper - return ( substr($text, 0, strlen($w->start)) == $w->start && substr($text, -1, strlen($w->end)) == $w->end ) ? true : false; - } - - /** - * Remove wrapper from specified text - * @uses this->has_wrapper() to check if text is wrapped - * @uses this->get_wrapper() to retrieve wrapper object - * @param string $text Text to check - * @param string|array $start (optional) Start text (Array defines both start/end text) - * @param string $end (optional) End text - * @return string Unwrapped text - */ - function remove_wrapper($text, $start = null, $end = null) { - if ( $this->has_wrapper($text, $start, $end) ) { - $w = $this->get_wrapper($start, $end); - $text = substr($text, strlen($w->start), strlen($text) - strlen($w->start) - strlen($w->end) ); - } - - return $text; - } - - /** - * Add wrapper to specified text - * @uses Utilities::get_wrapper() to retrieve wrapper object - * @param string $text Text to wrap - * @param string|array $start (optional) Start text (Array defines both start/end text) - * @param string $end (optional) End text - * @param bool $once (optional) Whether to wrap text only once (Default: TRUE) - * @return string Wrapped text - */ - function add_wrapper($text, $start = null, $end = null, $once = true) { - $w = $this->get_wrapper($start, $end); - if ( !$once || !$this->has_wrapper($text, $w) ) - $text = $w->start . $text . $w->end; - return $text; - } - - /*-** Client **-*/ - - /** - * Parses client files array - * > Adds ID property (prefixed file key) - * > Parses and validates internal dependencies - * > Converts properties array to object - * Properties - * > file (string|array): File name (string) or callback (array) to retrieve file name - * > deps (array) [optional]: Dependencies - * > Values wrapped in square brackets (`[` & `]`) are internal files - * > callback (string|array) [optional]: Global callback to determine whether file should be loaded - * > Values wrapped in square brackets (`[` & `]`) are internal methods (of parent object) - * > context (array) [optional]: Context(s) in which to load the file - * Acceptable values - * > string: Context name - * > array: Context name + callback (both must return TRUE to load file) - * > Callback follows same pattern as `callback` member - * @param array $files Files array - * @return object Client files - */ - function parse_client_files($files, $type = 'scripts') { - if ( is_array($files) && !empty($files) ) { - // Defaults - $defaults = array( - 'file' => null, - 'deps' => array(), - 'callback' => null, - 'context' => array(), - 'enqueue' => true, - 'enqueued' => false - ); - switch ( $type ) { - case 'styles': - $defaults['media'] = 'all'; - break; - default: - $defaults['in_footer'] = false; - } - // Iterate through files - /** - * $h (string) handle - * $p (array) properties - */ - foreach ( $files as $h => $p ) { - unset($file, $cb, $ctxs, $ctx); - // Set ID - $p['id'] = $this->add_prefix($h); - // Type Validation - /** - * $m (string) property name - * $d (mixed) default value - */ - foreach ( $defaults as $m => $d ) { - // Check if value requires validation - if ( !is_array($d) || !isset($p[$m]) || is_array($p[$m]) ) - continue; - // Wrap value in array or destroy it - if ( is_scalar($p[$m]) ) - $p[$m] = array($p[$m]); - else - unset($p[$m]); - } - - // Normalize file properties - $p = array_merge($defaults, $p); - - /* File name */ - - // Validate file - $file =& $p['file']; - - // Determine if filename or callback - if ( !$this->is_file($file) ) - $file = ( is_callable($file) ) ? $file : null; - // Remove invalid file and move on to next - if ( empty($file) ) { - unset($files[$h]); - continue; - } - - /* Dependencies */ - - // Format internal dependencies - foreach ( $p['deps'] as $idx => $dep ) { - if ( $this->has_wrapper($dep) ) { - $dep = $this->remove_wrapper($dep); - $p['deps'][$idx] = $this->add_prefix($dep); - } - } - - /* Context */ - - // Validate callback - $cb =& $p['callback']; - if ( !is_null($cb) && !is_callable($cb) ) { - // Remove files with invalid callbacks (will never be loaded) - unset($files[$h]); - continue; - } - - // Validate contexts - $ctxs =& $p['context']; - $ctxs = array_unique($ctxs); - $has_contexts = ( count($ctxs) > 0 ) ? true : false; - foreach ( $ctxs as $idx => $ctx ) { - // Convert to array - $ctx = array_values( array_slice( (array) $ctx, 0, 2 ) ); - switch ( count($ctx) ) { - case 1 : - // Simple context - $ctx = $ctx[0]; - break; - case 2 : - // Context + Callback - if ( is_callable($ctx[1]) ) { - break; - } - // Continue to default case if callback is invalid - default : - // Context is invalid - $ctx = false; - break; - } - - // Remove invalid contexts - if ( empty($ctx) ) { - unset($ctxs[$idx]); - } else { - $ctxs[$idx] = $ctx; - } - } - // Remove file if all specified contexts invalid (no context is OK) - if ( $has_contexts && empty($ctxs) ) { - unset($files[$h]); - continue; - } - $ctxs = array_values($ctxs); - - /* Finalize Properties */ - - // Convert properties to object - $files[$h] = (object) $p; - } - } - // Cast to object before returning - $files = (object) $files; - return $files; - } - - /** - * Build JS client object - * @param string (optional) $path Additional object path - * @return string Client object - */ - function get_client_object($path = null) { - $obj = strtoupper($this->get_prefix()); - if ( !empty($path) && is_string($path) ) { - if ( 0 !== strpos($path, '[') ) - $obj .= '.'; - $obj .= $path; - } - return $obj; - } - - /** - * Build jQuery JS expression to add data to specified client object - * @param string|obj $obj Name of client object (Set to root object if not a valid name) - * @param mixed $data Data to add to client object - * @param bool (optional) $out Whether or not to output code (Default: false) - * @return string JS expression to extend client object - */ - function extend_client_object($obj, $data = null, $out = false) { - // Validate parameters - $args = func_get_args(); - switch ( count($args) ) { - case 2: - if ( !is_scalar($args[0]) ) { - if ( is_bool($args[1]) ) - $out = $args[1]; - } else { - break; - } - case 1: - $data = $args[0]; - $obj = null; - break; - } - // Default client object - if ( !is_string($obj) || empty($obj) ) - $obj = null; - // Default data - if ( is_array($data) ) { - $data = (object)$data; - } - // Build expression - if ( empty($data) || ( empty($obj) && is_scalar($data) ) ) { - $ret = ''; - } else { - $c_obj = $this->get_client_object($obj); - $ret = $this->validate_client_object($obj, sprintf('{$.extend(%1$s, %2$s);}', $c_obj, json_encode($data)) ); - if ( $out ) - echo $this->build_script_element($ret, 'context', true, true); - } - return $ret; - } - - /** - * Validate client object $obj before running command $cmd - * - * @param string $obj Full object name - * @param string $cmd (optional) Command to wrap in validation - * @return string Command wrapped in validation block - * If no command is specified the validation conditions are returned - */ - public function validate_client_object($obj, $cmd = null) { - // Get base object - $base = $this->get_client_object(); - - // Build condition - $sep = '.'; - $obj = trim($obj, $sep); - // Strip base object - if ( 0 === strpos($obj, $base . $sep) ) { - $obj = substr($obj, strlen($base . $sep)); - } - $fmt = '!!window.%1$s'; - if ( !empty($obj) ) { - $fmt .= ' && %1$s.has_child(\'%2$s\')'; - } - $condition = sprintf($fmt, $base, $obj); - - // Wrap command in validation - if ( !empty($cmd) && is_string($cmd) ) { - $condition = sprintf('if ( %1$s ) { %2$s }', $condition, $cmd); - } - return $condition; - } - - /** - * Build client method call - * @uses get_client_object() to generate the body of the method call - * @param string $method Method name - * @param array|string $params (optional) Parameters to pass to method - * @param bool $encode (optional) JSON-encode parameters? (Default: TRUE) - * @param bool $validate (optional) Validate method before calling it? - * @return string Method call - */ - function call_client_method($method, $params = null, $encode = true, $validate = true) { - $ret = ''; - if ( !is_string($method) || empty($method) ) { - return $ret; - } - $encode = !!$encode; - $validate = !!$validate; - - // Build parameters - if ( !is_null($params) ) { - if ( $encode ) { - $params = wp_json_encode($params); - } elseif ( is_array($params) ) { - $params = implode(',', $params); - } - } - if ( !is_string($params) ) { - $params = ''; - } - $ret = sprintf('%s(%s);', $this->get_client_object($method), $params); - if ( $validate ) { - $ret = $this->validate_client_object($method, $ret); - } - return $ret; - } - - /*-** WP **-*/ - - /** - * Checks if $post is a valid Post object - * If $post is not valid, assigns global post object to $post (if available) - * @return bool TRUE if $post is valid object by end of function processing - * @param object $post Post object to evaluate - */ - function check_post(&$post) { - if (empty($post)) { - if (isset($GLOBALS['post'])) { - $post = $GLOBALS['post']; - $GLOBALS['post'] =& $post; - } - else - return false; - } - if (is_array($post)) - $post = (object) $post; - elseif (is_numeric($post)) - $post = get_post($post); - if (!is_object($post)) - return false; - return true; - } - - - /** - * Retrieve parent object - * @return obj|bool Parent object (FALSE if no valid parent set) - */ - function get_parent() { - if ( is_object($this->_parent) ) { - return $this->_parent; - } else { - return false; - } - } - - /** - * Retrieve parent property value - * @uses self::get_parent() - * @param string $prop Property name - * @param mixed $default Default value - * @return mixed Parent property value - */ - function get_parent_property($prop, $default = '') { - $p = $this->get_parent(); - return ( !!$p && property_exists($p, $prop) ) ? $p->{$prop} : $default; - } - - /* Hooks */ - - /** - * Retrieve formatted name for internal hooks - * Prefixes with parent prefix and hook prefix - * @uses self::get_parent_property() to retrieve hook prefix - * @uses self::add_prefix() - * @param string $tag Base tag - * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) - * @return string Formatted hook - */ - function get_hook($tag, $hook_prefix = true) { - // Hook prefix - $hook = ''; - if ( is_bool($hook_prefix) && $hook_prefix ) { - $hook = $this->get_parent_property('hook_prefix', ''); - } elseif ( is_string($hook_prefix) ) { - $hook = $hook_prefix; - } - if ( !empty($hook) ) - $hook .= '_'; - // Prefix - return $this->add_prefix($hook . $tag); - } - - /** - * Run internal action - * Namespaces $tag - * @uses self::get_hook() - * @see do_action() - * @param string|array $tag Action hook. If array, get hook prefix - */ - function do_action($tag, $arg = '') { - // Handle hook prefix - $hook_prefix = true; - if ( is_array($tag) ) { - $hook_prefix = $tag[1]; - $tag = $tag[0]; - } - $args = func_get_args(); - $args[0] = $this->get_hook($tag, $hook_prefix); - return call_user_func_array('do_action', $args); - } - - /** - * Run internal action passing arguments in array - * @uses do_action_ref_array() - * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) - */ - function do_action_ref_array($tag, $args, $hook_prefix = true) { - return do_action_ref_array($this->get_hook($tag, $hook_prefix), $args); - } - - /** - * Run internal filter - * Namespaces $tag - * @uses self::get_hook() - * @see apply_filters() - * @param string|array $tag Action hook. If array, get hook prefix - */ - function apply_filters($tag, $value) { - // Handle hook prefix - $hook_prefix = true; - if ( is_array($tag) ) { - $hook_prefix = $tag[1]; - $tag = $tag[0]; - } - $args = func_get_args(); - $args[0] = $this->get_hook($tag, $hook_prefix); - return call_user_func_array('apply_filters', $args); - } - - /** - * Run internal filter passing arguments in array - * @uses apply_filters_ref_array() - * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) - */ - function apply_filters_ref_array($tag, $args, $hook_prefix = true) { - return apply_filters_ref_array($this->get_hook($tag, $hook_prefix), $args); - } - - /** - * Add internal action - * Namespaces $tag - * @uses self::get_hook() - * @see add_action() - * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) - */ - function add_action($tag, $function_to_add, $priority = 10, $accepted_args = 1, $hook_prefix = true) { - return add_action($this->get_hook($tag, $hook_prefix), $function_to_add, $priority, $accepted_args); - } - - /** - * Add internal filter - * Namespaces $tag - * @uses self::get_hook() - * @see add_filter() - * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) - */ - function add_filter($tag, $function_to_add, $priority = 10, $accepted_args = 1, $hook_prefix = true) { - return add_filter($this->get_hook($tag, $hook_prefix), $function_to_add, $priority, $accepted_args); - } - - /** - * Remove internal action - * Namespaces $tag - * @uses self::get_hook() - * @uses remove_action() - * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) - */ - function remove_action($tag, $function_to_remove, $priority = 10, $accepted_args = 1, $hook_prefix = true) { - return remove_action($this->get_hook($tag, $hook_prefix), $function_to_remove, $priority, $accepted_args); - } - - /** - * Remove internal filter - * Namespaces $tag - * @uses self::get_hook() - * @uses remove_filter() - * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) - */ - function remove_filter($tag, $function_to_remove, $priority = 10, $accepted_args = 1, $hook_prefix = true) { - return remove_filter($this->get_hook($tag, $hook_prefix), $function_to_remove, $priority, $accepted_args); - } - - /* Shortcode */ - - /** - * Process specific shortcode(s) in content - * Default: Process all existing shortcodes - * @uses $shortcode_tags - array tag => callback - * @uses do_shortcode() - * - * @param string $content Content to process for shortcodes - * @param string|array $shortcode Single tag or array of tags to process - * > Associative array sets temporary callbacks for shortcodes (`tag => callback`) - */ - public function do_shortcode($content, $shortcode = null) { - global $shortcode_tags; - - // Process custom shortcodes - if ( !is_null($shortcode) ) { - // Cast to array - $shortcode = (array) $shortcode; - // Backup and reset shortcode handlers - $tags_temp = $shortcode_tags; - $shortcode_tags = array(); - // Register specified tags - foreach ( $shortcode as $key => $val ) { - if ( is_string($key) && is_callable($val) ) { - // Tag w/custom callback - $shortcode_tags[$key] = $val; - } elseif ( is_int($key) && is_string($val) && isset($tags_temp[$val]) ) { - // Tag with default callback - $shortcode_tags[$val] = $tags_temp[$val]; - } - } - } - - // Process shortcodes in content - $content = do_shortcode($content); - - // Restore default shortcode handlers - if ( isset($tags_temp) ) { - $shortcode_tags = $tags_temp; - unset($tags_temp); - } - - return $content; - } - - /** - * Build shortcode tag - * @param string $tag Shortcode base - * @param array (optional) $attr Shortcode attributes - * @param string (optional) $content Shortcode content - * @return string Shortcode tag - */ - public function make_shortcode($tag, $attr = null, $content = null) { - return $this->build_element(array ( - 'tag' => $tag, - 'attributes' => $attr, - 'content' => $content, - )); - } - - /* Meta */ - - /** - * Retrieves post metadata for internal methods - * Metadata set internally is wrapped in an array so it is unwrapped before returned the retrieved value - * @see get_post_meta() - * @param int $post_id Post ID - * @param string $key Name of metadata to retrieve - * @param boolean $single Whether or not to retrieve single value or not - * @return mixed Retrieved post metadata - */ - function post_meta_get($post_id, $key, $single = false) { - $meta_value = get_post_meta($post_id, $this->post_meta_get_key($key), $single); - if (is_array($meta_value) && count($meta_value) == 1) - $meta_value = $meta_value[0]; - return $meta_value; - } - - /** - * Wraps metadata in array for storage in database - * @param mixed $meta_value Value to be set as metadata - * @return array Wrapped metadata value - */ - function post_meta_prepare_value($meta_value) { - return array($meta_value); - } - - /** - * Adds Metadata for a post to database - * For internal methods - * @see add_post_meta - * @param $post_id - * @param $meta_key - * @param $meta_value - * @param $unique - * @return boolean Result of operation - */ - function post_meta_add($post_id, $meta_key, $meta_value, $unique = false) { - $meta_value = $this->post_meta_value_prepare($meta_value); - return add_post_meta($post_id, $meta_key, $meta_value, $unique); - } - - /** - * Updates post metadata for internal data/methods - * @see update_post_meta() - * @param $post_id - * @param $meta_key - * @param $meta_value - * @param $prev_value - * @return boolean Result of operation - */ - function post_meta_update($post_id, $meta_key, $meta_value, $prev_value = '') { - $meta_value = $this->post_meta_prepare_value($meta_value); - return update_post_meta($post_id, $meta_key, $meta_value, $prev_value); - } - - /** - * Builds postmeta key for custom data set by plugin - * @param string $key Base key name - * @return string Formatted postmeta key - */ - function post_meta_get_key($key) { - $sep = '_'; - if ( strpos($key, $sep . $this->prefix) !== 0 ) { - $key_base = func_get_args(); - if ( !empty($key_base) ) { - $key = array_merge((array)$this->prefix, $key_base); - return $sep . implode($sep, $key); - } - } - - return $key; - } - - /** - * Creates a meta key for storing post meta data - * Prefixes standard prefixed text with underscore to hide meta data on post edit forms - * @param string $text Text to use as base of meta key - * @return string Formatted meta key - */ - function make_meta_key($text = '') { - return '_' . $this->add_prefix($text); - } - - /* Class */ - - /** - * Retrieve name of internal class - * @param string $class Base name of class - * @return string Full name of internal class - */ - function get_class($class) { - return $this->add_prefix_uc($class); - } - - /* Context */ - - /** - * Retrieve context for current request - * @return array Context - */ - function get_context() { - // Context - static $ctx = null; - if ( !is_array($ctx) ) { - // Standard - $ctx = array($this->build_context()); - // Action - $action = $this->get_action(); - if ( !empty($action) ) { - $ctx[] = $this->build_context('action', $action); - } - // Post type - $post_type = $this->get_post_type(); - if ( !empty($action) ) { - $ctx[] = $this->build_context('post-type', $post_type); - } - // Admin page - if ( is_admin() ) { - global $pagenow; - $pg = $this->strip_file_extension($pagenow); - $ctx[] = $this->build_context('page', $pg); - // Query String - if ( isset($_SERVER['QUERY_STRING']) ) { - parse_str($_SERVER['QUERY_STRING'], $qv); - if ( isset($qv['page']) ) { - $ctx[] = $this->build_context('page', $qv['page']); - if ( stripos($qv['page'], $this->get_prefix()) === 0 ) { - $ctx[] = $this->build_context('page', $this->get_prefix()); - } - } - } - // Action - if ( !empty($action) ) { - $ctx[] = $this->build_context('page', $pg, 'action', $action); - $ctx[] = $this->build_context('post-type', $post_type, 'action', $action); - } - } - // User - $u = wp_get_current_user(); - $ctx[] = $this->build_context('user', ( $u->ID ) ? 'registered' : 'guest', false); - } - - return $ctx; - } - - /** - * Builds context from multiple components - * Usage: - * > $prefix can be omitted and context strings can be added as needed - * > Multiple context strings may be passed to be joined together - * - * @param string (optional) $context Variable number of components to add to context - * @param bool (optional) $prefix Whether or not to prefix context with request type (public or admin) [Default: TRUE] - * @return string Context - */ - function build_context($context = null, $prefix = true) { - $args = func_get_args(); - // Get prefix option - if ( !empty($args) ) { - $prefix = ( is_bool($args[count($args) - 1]) ) ? array_pop($args) : true; - } - - // Validate - $context = array_filter($args, 'is_string'); - $sep = '_'; - - // Context Prefix - if ( $prefix ) - array_unshift($context, ( is_admin() ) ? 'admin' : 'public' ); - return implode($sep, $context); - } - - /** - * Check if context exists in current request - * @param string $context Context to check for - * @return bool TRUE if context exists FALSE otherwise - */ - function is_context($context) { - $ret = false; - if ( is_scalar($context) ) - $context = array($context); - if ( is_array($context) && !empty($context) ) { - $ictx = array_intersect($this->get_context(), $context); - if ( !empty($ictx) ) - $ret = true; - } - return $ret; - } - - /** - * Output current context to client-side - * @uses `wp_head` action hook - * @uses `admin_head` action hook - * @return void - */ - function set_client_context() { - $ctx = new stdClass(); - $ctx->context = $this->get_context(); - $this->extend_client_object($ctx, true); - } - - /* Path */ - - /** - * Joins and normalizes the slashes in the paths passed to method - * All forward/back slashes are converted to forward slashes - * Multiple path segments can be passed as additional argments - * @param string $path Path to normalize - * @param bool|array $trailing_slash (optional) Whether or not normalized path should have a trailing slash or not (Default: FALSE) - * If array is passed, first index is trailing, second is leading slash - * If multiple path segments are passed, $trailing_slash will be the LAST parameter (default value used if omitted) - */ - function normalize_path($path, $trailing_slash = false) { - $sl_f = '/'; - $sl_b = '\\'; - $parts = func_get_args(); - // Slash defaults (trailing, leading); - $slashes = array(false, true); - if ( func_num_args() > 1 ) { - // Get last argument - $arg_last = $parts[count($parts) - 1]; - if ( is_bool($arg_last) ) { - $arg_last = array($arg_last); - } - - if ( is_array($arg_last) && count($arg_last) > 0 && is_bool($arg_last[0]) ) { - // Remove slash paramter from args array - array_pop($parts); - // Normalize slashes options - if ( isset($arg_last[0]) ) - $slashes[0] = $arg_last[0]; - if ( isset($arg_last[1]) ) - $slashes[1] = $arg_last[1]; - } - } - // Extract to slash options local variables - list($trailing_slash, $leading_slash) = $slashes; - - // Clean path segments - foreach ( $parts as $key => $part ) { - // Trim slashes/spaces - $parts[$key] = trim($part, " " . $sl_f . $sl_b); - - // Verify path segment still contains value - if ( empty($parts[$key]) ) { - unset($parts[$key]); - continue; - } - } - - // Join path parts together - $parts = implode($sl_b, $parts); - $parts = str_replace($sl_b, $sl_f, $parts); - // Add trailing slash (if necessary) - if ( $trailing_slash ) - $parts .= $sl_f; - // Add leading slash (if necessary) - $regex = '#^.+:[\\/]#'; - if ( $leading_slash && !preg_match($regex, $parts) ) { - $parts = $sl_f . $parts; - } - return $parts; - } - - /** - * Returns URL of file (assumes that it is in plugin directory) - * @param string $file name of file get URL - * @param string|bool $relative Path that URI should be relative to (Default: full path) - * @return string File URL - */ - function get_file_url($file, $relative = null) { - if ( is_string($file) && '' != trim($file) ) { - $file = str_replace(' ', '%20', $this->normalize_path($this->get_url_base(false, $relative), $file)); - } - return $file; - } - - /** - * Returns path to plugin file - * @param string $file file name - * @return string File path - */ - function get_file_path($file, $relative = null) { - // Build path - if ( is_string($file) && '' != trim($file) ) { - $file = $this->normalize_path($this->get_path_base($relative), $file); - } - return $file; - } - - function get_plugin_file_path($file, $trailing_slash = false) { - if ( is_string($file) && '' != trim($file) ) - $file = $this->normalize_path($this->get_plugin_base(), $file, $trailing_slash); - return $file; - } - - /** - * Checks if value is valid file name - * @param string $filename File name to check - * @return bool TRUE if valid file name, FALSE otherwise - */ - function is_file($filename) { - $ext = $this->get_file_extension($filename); - return ( empty($ext) ) ? false : true; - } - - /** - * Check if string is valid URI - * @param string $uri String to check - * @return bool TRUE if string is valid URI - */ - function is_uri($uri) { - return ( preg_match('|^(https?:)?//|', $uri) ) ? true : false; - } - - /** - * Retrieves file extension - * @param string $file file name/path - * @param bool (optional) $lowercase Whether lowercase extension should be returned (Default: TRUE) - * @return string File's extension - */ - function get_file_extension($file, $lowercase = true) { - $ret = ''; - $sep = '.'; - // Validate - if ( !is_string($file) ) - return $ret; - // Strip query string (if necessary) - if ( ( $qpos = strpos($file, '?') ) && $qpos !== false ) { - $file = substr($file, 0, $qpos); - } - if ( ( $rpos = strrpos($file, $sep) ) > 0 ) - $ret = substr($file, $rpos + 1); - if ( !!$lowercase ) - $ret = strtolower($ret); - return $ret; - } - - /** - * Checks if file has specified extension - * @uses get_file_extension() - * @param string $file File name/path - * @param string|array $extension File ending(s) to check $file for - * @param bool (optional) Whether check should be case senstive or not (Default: FALSE) - * @return bool TRUE if file has extension - */ - function has_file_extension($file, $extension, $case_sensitive = false) { - if ( !is_array($extension) ) - $extension = array(strval($extension)); - if ( !$case_sensitive ) { - // Normalize extensions - $extension = array_map('strtolower', $extension); - } - return ( in_array($this->get_file_extension($file, !$case_sensitive), $extension) ) ? true : false; - } - - /** - * Removes file extension from file name - * The extension is the text following the last period ('.') in the file name - * @uses get_file_extension() - * @param string $file File name - * @return string File name without extension - */ - function strip_file_extension($file) { - $ext = $this->get_file_extension($file); - if ( !empty($ext) ) { - $file = substr($file, 0, (strlen($ext) + 1) * -1); - } - return $file; - } - - /** - * Retrieve base URL for plugin-specific files - * @uses get_plugin_base() - * @uses normalize_path() - * @return string Base URL - */ - function get_url_base($trailing_slash = false, $relative = null) { - $ret = $this->_plugin['uri']; - if ( empty($ret) ) { - $ret = $this->normalize_path(plugins_url(), $this->get_plugin_base()); - } - // Trailing slash - if ( !!$trailing_slash ) { - $ret .= '/'; - } - // Relative - if ( !empty($relative) ) { - // Default - if ( is_bool($relative) ) { - $relative = site_url(); - } - // Custom - if ( is_string($relative) ) { - $ret = $this->get_relative_path($ret, $relative); - } - } - - return $ret; - } - - /** - * Retrieve plugin's base path - * @uses WP_PLUGIN_DIR - * @uses get_plugin_base() - * @uses normalize_path() - * @return string Base path - */ - function get_path_base($relative = null) { - $ret = $this->_path_base; - if ( empty($ret) ) { - // Get base directory of parent object - if ( $this->get_parent() ) { - $r = new ReflectionClass(get_class($this->get_parent())); - $base = $r->getFileName(); - unset($r); - } else { - $base = __FILE__; - } - // Extract base path - $base = $this->normalize_path($base); - if ( 0 === strpos($base, $this->normalize_path(WP_PLUGIN_DIR)) ) { - $end = strpos($base, '/', strlen(WP_PLUGIN_DIR) + 1); - $base = substr($base, 0, $end); - } - $ret = $this->_path_base = $base; - } - // Make relative path - if ( !empty($relative) ) { - // Default - if ( is_bool($relative) ) { - $relative = ABSPATH; - } - // Custom - if ( is_string($relative) ) { - $ret = $this->get_relative_path($ret, $relative); - } - } - return $ret; - } - - /** - * Retrieve relative path for absolute paths - * @param string $path Path to modify - * @param string $relative (optional) Base path to make $path relative to (Default: Site's base path) - * @return string Relative path - */ - function get_relative_path($path, $relative = true) { - // Default base path - if ( !is_string($relative) ) { - $relative = ABSPATH; - } - if ( !empty($relative) && !empty($path) ) { - $relative = $this->normalize_path($relative); - $path = $this->normalize_path($path); - // Strip base path - if ( strpos($path, $relative) === 0 ) { - $path = substr($path, strlen($relative)); - } - } - return $path; - } - - /** - * Retrieve plugin's base directory - * @uses WP_PLUGIN_DIR - * @uses Utilities::get_path_base() to retrieve plugin base path - * @uses Utilities::_plugin_base to save plugin base - * @return string Base directory - */ - function get_plugin_base() { - $ret = $this->_plugin['base']; - if ( empty($ret) ) { - $ret = $this->_plugin['base'] = basename($this->get_path_base()); - } - return $ret; - } - - /** - * Retrieve plugin's base file path - * @uses get_path_base() - * @uses get_file_path() - * @return string Base file path - */ - function get_plugin_base_file() { - $ret = $this->_plugin['file']; - if ( empty($ret) ) { - $dir = @opendir($this->get_path_base()); - if ( $dir ) { - while ( ($ftemp = readdir($dir)) !== false ) { - // Only process PHP files - $ftemp = $this->get_file_path($ftemp); - if ( !$this->has_file_extension($ftemp, 'php') || !is_readable($ftemp) ) - continue; - // Check for data - $data = get_file_data($ftemp, $this->_plugin['headers']); - if ( !empty($data['Name']) ) { - // Set base file - $ret = $ftemp; - // Save plugin data - $this->set_plugin_info($data); - break; - } - } - } - @closedir($dir); - } - // Return - return $ret; - } - - /** - * Retrieve plugin's internal name - * Internal name is used by WP core - * @uses get_plugin_base_file() - * @uses plugin_basename() - * @return string Internal plugin name - */ - function get_plugin_base_name() { - $ret = $this->_plugin['name']; - if ( empty($ret) ) { - $ret = $this->_plugin['name'] = plugin_basename( $this->get_plugin_base_file() ); - } - return $ret; - } - - private function set_plugin_info($data) { - if ( is_array($data) ) { - $this->_plugin['data'] = $data; - } - } - - /** - * Retrieve plugin info - * Parses info comment in main plugin file - * @uses get_plugin_base_file() to retrieve plugin info - * @return array|string Plugin info (specific value if field set) - */ - function get_plugin_info($field = null) { - $ret = $this->_plugin['data']; - // Get plugin data - if ( empty($ret) ) { - $this->get_plugin_base_file(); - $ret = $this->_plugin['data']; - } - // Return specified field - if ( !empty($field) ) { - $ret = ( is_array($ret) && isset($ret[$field]) ) ? $ret[$field] : ''; - } - return $ret; - } - - /** - * Retrieve plugin version - * @uses get_plugin_info() - * @param bool $strip_desc Strip any additional version text - * @return string Plugin version - */ - function get_plugin_version($strip_desc = true) { - // Retrieve version - $ret = $this->get_plugin_info('Version'); - // Format - if ( !empty($ret) && $strip_desc ) { - $ret = explode(' ', $ret, 2); - $ret = $ret[0]; - } - // Return - return $ret; - } - - /** - * Retrieve current post type based on URL query variables - * @return string|null Current post type - */ - public function get_post_type() { - if ( isset($_GET['post_type']) && !empty($_GET['post_type']) ) { - return $_GET['post_type']; - } - $pt = null; - if ( isset($_GET['post']) && is_numeric($_GET['post']) ) { - $pt = get_post_type($_GET['post']); - } - return $pt; - } - - /** - * Retrieve current action based on URL query variables - * @param mixed $default (optional) Default action if no action exists - * @return string Current action - */ - function get_action($default = null) { - $action = ''; - - // Check if action is set in URL - if ( isset($_GET['action']) ) - $action = $_GET['action']; - // Otherwise, Determine action based on plugin admin page suffix - elseif ( isset($_GET['page']) && ($pos = strrpos($_GET['page'], '-')) && $pos !== false && ( $pos != strlen($_GET['page']) - 1 ) ) - $action = trim(substr($_GET['page'], $pos + 1), '-_'); - - // Determine action for core admin pages - if ( ( !isset($_GET['page']) || empty($action) ) && isset($_SERVER['SCRIPT_NAME']) ) { - $actions = array( - 'add' => array('page-new', 'post-new'), - 'edit-item' => array('page', 'post'), - 'edit' => array('edit', 'edit-pages') - ); - $page = basename($_SERVER['SCRIPT_NAME'], '.php'); - - foreach ( $actions as $act => $pages ) { - if ( in_array($page, $pages) ) { - $action = $act; - break; - } - } - } - if ( empty($action) ) - $action = $default; - return $action; - } - - /*-** General **-*/ - - /** - * Checks if a property exists in a class or object - * Compatibility method for PHP 4 - * @param mixed $class Class or object to check - * @param string $property Name of property to look for in $class - */ - function property_exists($class, $property) { - if ( !is_object($class) && !is_array($class) ) - return false; - if ( function_exists('property_exists') && is_object($class) ) { - return property_exists($class, $property); - } else { - return array_key_exists($property, $class); - } - } - - /** - * Retrieve specified property from object or array - * @param object|array $obj Object or array to get property from - * @param string $property Property name to retrieve - * @return mixed Property value - */ - function &get_property(&$obj, $property) { - $property = trim($property); - // Object - if ( is_object($obj) ) - return $obj->{$property}; - // Array - if ( is_array($obj) ) - return $obj[$property]; - // Class - if ( is_string($obj) && class_exists($obj) ) { - $cvars = get_class_vars($obj); - if ( isset($cvars[$property]) ) - return $cvars[$property]; - } - } - - /** - * Remap array members based on a - * mapping of source/destination keys - * @param array $properties Associative array of properties - * @param array $map Source/Destination mapping - * > Key: Source member - * > Val: Destination member - * @param bool $overwrite If TRUE, source value will be set in destination regardless of whether member already exists or not - * @return array Remapped properties - */ - function array_remap($arr, $map = array(), $overwrite = false) { - if ( !empty($map) && is_array($map) ) { - // Iterate through mappings - foreach ( $map as $from => $to ) { - if ( !array_key_exists($from, $arr) ) - continue; - $move = $overwrite; - // Only remap if parent property doesn't already exist in array - if ( !array_key_exists($to, $arr) ) - $move = true; - if ( $move ) { - // Move member value to new key - $arr[$to] = $arr[$from]; - // Remove source member - unset($arr[$from]); - } - } - } - // Return remapped properties - return $arr; - } - - function array_filter_keys($arr, $keys) { - if ( is_array($arr) && !empty($arr) && is_array($keys) && !empty($keys) ) { - foreach ( $keys as $rem ) { - if ( array_key_exists($rem, $arr) ) - unset($arr[$rem]); - } - } - - return $arr; - } - - /** - * Insert an item into an array at the specified position - * @param mixed $item Item to insert into array - * @param int $pos Index position to insert item into array - * @return array Modified array - */ - function array_insert($array, $item, $pos = null) { - array_splice($array, $pos, 0, $item); - return $array; - } - - /** - * Merges 1 or more arrays together - * Methodology - * - Set first parameter as base array - * - All other parameters will be merged into base array - * - Iterate through other parameters (arrays) - * - Skip all non-array parameters - * - Iterate though key/value pairs of current array - * - Merge item in base array with current item based on key name - * - If the current item's value AND the corresponding item in the base array are BOTH arrays, recursively merge the the arrays - * - If the current item's value OR the corresponding item in the base array is NOT an array, current item overwrites base item - * @param array Variable number of arrays - * @param array $arr1 Default array - * @return array Merged array - */ - function array_merge_recursive_distinct($arr1) { - // Get all arrays passed to function - $args = func_get_args(); - if ( empty($args) ) - return false; - // Return empty array if first parameter is not an array - if ( !is_array($args[0]) ) - return array(); - // Set first array as base array - $merged = $args[0]; - // Iterate through arrays to merge - $arg_length = count($args); - for ( $x = 1; $x < $arg_length; $x++ ) { - // Skip if argument is not an array (only merge arrays) - if ( !is_array($args[$x]) ) - continue; - // Iterate through argument items - foreach ( $args[$x] as $key => $val ) { - // Generate key for numeric indexes - if ( is_int($key) ) { - // Add new item to merged array - $merged[] = null; - // Get key of new item - $key = array_pop(array_keys($merged)); - } - if ( !isset($merged[$key]) || !is_array($merged[$key]) || !is_array($val) ) { - $merged[$key] = $val; - } elseif ( is_array($merged[$key]) && is_array($val) ) { - $merged[$key] = $this->array_merge_recursive_distinct($merged[$key], $val); - } - } - } - return $merged; - } - - /** - * Replaces string value in one array with the value of the matching element in a another array - * - * @param string $search Text to search for in array - * @param array $arr_replace Array to use for replacing values - * @param array $arr_subject Array to search for specified value - * @return array Searched array with replacements made - */ - function array_replace_recursive($search, $arr_replace, $arr_subject) { - foreach ($arr_subject as $key => $val) { - // Skip element if key does not exist in the replacement array - if (!isset($arr_replace[$key])) - continue; - // If element values for both arrays are strings, replace text - if (is_string($val) && strpos($val, $search) !== false && is_string($arr_replace[$key])) - $arr_subject[$key] = str_replace($search, $arr_replace[$key], $val); - // If value in both arrays are arrays, recursively replace text - if (is_array($val) && is_array($arr_replace[$key])) - $arr_subject[$key] = $this->array_replace_recursive($search, $arr_replace[$key], $val); - } - - return $arr_subject; - } - - /** - * Checks if item at specified path in array is set - * @param array $arr Array to check for item - * @param array $path Array of segments that form path to array (each array item is a deeper dimension in the array) - * @return boolean TRUE if item is set in array, FALSE otherwise - */ - function array_item_isset(&$arr, &$path) { - $f_path = $this->get_array_path($path); - return eval('return isset($arr' . $f_path . ');'); - } - - /** - * Build formatted string based on array values - * Array values in formatted string will be ordered by index order - * @param array $attribute Values to build string with - * @param string $format (optional) Format name (Default: Multidimensional array representation > ['value1']['value2']['value3'], etc.) - * @return string Formatted string based on array values - */ - function get_array_path($attribute = '', $format = null) { - // Formatted value - $fmtd = ''; - if (!empty($attribute)) { - // Make sure attribute is array - if (!is_array($attribute)) { - $attribute = array($attribute); - } - // Format attribute - $format = strtolower($format); - switch ($format) { - case 'id': - $fmtd = array_shift($attribute) . '[' . implode('][', $attribute) . ']'; - break; - case 'metadata': - case 'attribute': - // Join segments - $delim = '_'; - $fmtd = implode($delim, $attribute); - // Replace white space and repeating delimiters - $fmtd = str_replace(' ', $delim, $fmtd); - while (strpos($fmtd, $delim.$delim) !== false) - $fmtd = str_replace($delim.$delim, $delim, $fmtd); - // Prefix formatted value with delimeter for metadata keys - if ('metadata' == $format) - $fmtd = $delim . $fmtd; - break; - case 'path': - case 'post': - default: - $fmtd = '["' . implode('"]["', $attribute) . '"]'; - } - } - return $fmtd; - } - - /** - * Builds array of path elements based on arguments - * Each item in path array represents a deeper level in structure path is for (object, array, filesystem, etc.) - * @param array|string Value to add to the path - * @return array 1-dimensional array of path elements - */ - function build_path() { - $path = array(); - $args = func_get_args(); - - // Iterate through parameters and build path - foreach ( $args as $arg ) { - if ( empty($arg) ) - continue; - - if (is_array($arg)) { - // Recurse through array items to pull out any more arrays - foreach ($arg as $key => $val) { - $path = array_merge($path, $this->build_path($val)); - } - // $path = array_merge($path, array_values($arg)); - } elseif ( is_scalar($arg) ) { - $path[] = $arg; - } - } - - return $path; - } - - /** - * Build generic element - * @param array $args - * @return string Element output - */ - public function build_element($args = array()) { - $ret = ''; - $args_default = array( - 'tag' => '', - 'wrap' => false, - 'content' => '', - 'attributes' => array(), - 'format' => array(), - ); - $format_default = array( - 'open' => '[%s]', - 'close' => '[/%s]', - ); - $args = wp_parse_args($args, $args_default); - $args['format'] = wp_parse_args($args['format'], $format_default); - - // Validate - if ( !is_string($args['tag']) || empty($args['tag']) ) { - return $ret; - } - - $args = (object) $args; - - $args->attributes = $this->build_attribute_string($args->attributes); - if ( strlen($args->attributes) > 0 ) { - $args->attributes = ' ' . $args->attributes; - } - - // Build output - $args->format = (object) $args->format; - $ret = sprintf( $args->format->open, $args->tag . $args->attributes); - - // Wrap content if necessary - if ( $args->wrap || ( is_string($args->content) && !empty($args->content) ) ) { - $ret .= $args->content . sprintf( $args->format->close, $args->tag); - } - - return $ret; - } - - /** - * Parse string of attributes into array - * For XML/XHTML tag attributes - * @param string $txt Attribute text (Can be full tag or just attributes) - * @return array Attributes as associative array - */ - function parse_attribute_string($txt, $defaults = array()) { - $txt = trim($txt, ' >'); - $matches = $attr = array(); - // Strip tag - if ( $txt[0] == '<' && ($s = strpos($txt, ' ')) && $s !== false ) { - $txt = trim(substr($txt, $s + 1)); - } - // Parse attributes - $rgx = "/\b(\w+.*?)=([\"'])(.*?)\\2(?:\s|$)/i"; - preg_match_all($rgx, $txt, $matches); - if ( count($matches) > 3 ) { - foreach ( $matches[1] as $sub_idx => $val ) { - if ( isset($matches[3][$sub_idx]) ) - $attr[trim($val)] = trim($matches[3][$sub_idx]); - } - } - // Destroy parsing vars - unset($txt, $matches); - - return array_merge($defaults, $attr); - } - - /** - * Builds attribute string for HTML element - * @param array $attr Attributes - * @return string Formatted attribute string - */ - function build_attribute_string($attr) { - $ret = ''; - if ( is_object($attr) ) { - $attr = (array) $attr; - } - if ( is_array($attr) && !empty($attr) ) { - array_map('esc_attr', $attr); - $attr_str = array(); - foreach ( $attr as $key => $val ) { - $attr_str[] = $key . '="' . $val . '"'; - } - $ret = implode(' ', $attr_str); - } - return $ret; - } - - /* HTML */ - - /** - * Generate HTML element based on values - * @param $args Element arguments - * @return string Generated HTML element - */ - public function build_html_element($args) { - $args_default = array( - 'tag' => 'span', - 'content' => '', - 'attributes' => array() - ); - $args = wp_parse_args($args, $args_default); - $args['format'] = array( - 'open' => '<%s>', - 'close' => '', - ); - // Build element - return $this->build_element($args); - } - - /** - * Build HTML link element - * @uses build_html_element() to build link output - * @param string $uri Link URI - * @param string $content Link content - * @param $array (optional) $attributes Additional link attributes - * @return string HTML link element - */ - function build_html_link($uri, $content, $attributes = array()) { - $attributes = array_merge(array('href' => $uri, 'title' => $content), $attributes); - return $this->build_html_element(array('tag' => 'a', 'wrap' => true, 'content' => $content, 'attributes' => $attributes)); - } - - /** - * Generate external stylesheet element - * @param $url Stylesheet URL - * @return string Stylesheet element - */ - function build_stylesheet_element($url) { - $attributes = array('href' => $url, 'type' => 'text/css', 'rel' => 'stylesheet'); - return $this->build_html_element(array('tag' => 'link', 'wrap' => false, 'attributes' => $attributes)); - } - - /** - * Build client-side script element - * - * @param string $content Script content - * @param string $id (optional) Element ID - * @param bool $wrap_jquery (optional) Wrap commands in jQuery? (Default: Yes) - * @param bool $wait_doc_ready (optional) Wait until document is fully loaded before executing commands? (Default: No) - */ - function build_script_element($content = '', $id = '', $wrap_jquery = true, $wait_doc_ready = false) { - // Stop processing invalid content - if ( is_array($content) && !empty($content) ) { - $content = implode(PHP_EOL, $content); - } - if ( empty($content) || !is_string($content) ) { - return ''; - } - $attributes = array('type' => 'text/javascript'); - $start = array('/* */'); - if ( $wrap_jquery ) { - $start[] = 'if ( !!window.jQuery ) {(function($){'; - $end[] = '})(jQuery);}'; - - // Add event handler (if necessary) - if ( $wait_doc_ready ) { - $start[] = '$(document).ready(function(){'; - $end[] = '})'; - } - } - - // Reverse order of end values - $end = array_reverse($end); - $content = implode('', array_merge($start, array($content), $end)); - if ( is_string($id) && !empty($id) ) { - $attributes['id'] = $this->add_prefix($id); - } - return $this->build_html_element(array('tag' => 'script', 'content' => $content, 'wrap' => true, 'attributes' => $attributes)) . PHP_EOL; - } -} \ No newline at end of file + null, + 'file' => null, + 'name' => null, + 'data' => null, + 'uri' => null, + 'headers' => array( + 'Name' => 'Plugin Name', + 'PluginURI' => 'Plugin URI', + 'SupportURI' => 'Support URI', + 'Version' => 'Version', + 'Description' => 'Description', + 'Author' => 'Author', + 'AuthorURI' => 'Author URI', + ), + ); + + /** + * Plugin base path + * @var string + */ + private $_path_base = null; + + /** + * Standard hook priorities + * @var array + */ + private $_priorities = array( + 'high' => 1, + 'low' => 99, + 'safe' => 15, + 'client_footer_output' => 25, + ); + + /* Constructors */ + + function __construct( $obj ) { + if ( is_object( $obj ) ) { + $this->_parent = $obj; + } + } + + /** + * Returns callback array to instance method + * @param object $obj Instance object + * @param string $method Name of method + * @return array Callback array + */ + function m( $obj, $method = '' ) { + if ( is_string( $obj ) ) { + $method = $obj; + $obj = null; + } + if ( ! is_object( $obj ) && isset( $this ) ) { + $obj = $this; + } + $cb = array( $obj, $method ); + return $cb; + } + + /* Helper Functions */ + + /*-** Prefix **-*/ + + /** + * Get valid separator + * @param string $sep (optional) Separator supplied + * @return string Separator + */ + function get_sep( $sep = false ) { + if ( is_null( $sep ) ) { + $sep = ''; + } + return ( is_string( $sep ) ) ? $sep : '_'; + } + + /** + * Retrieve class prefix (with separator if set) + * @param bool|string $sep Separator to append to class prefix (Default: no separator) + * @return string Class prefix + */ + function get_prefix( $sep = null ) { + $sep = $this->get_sep( $sep ); + $prefix = ( ! empty( $this->_parent->prefix ) ) ? $this->_parent->prefix . $sep : ''; + return $prefix; + } + + /** + * Check if a string is prefixed + * @param string|array $text Text to check for prefix + * @param string $sep (optional) Separator used + */ + function has_prefix( $text, $sep = null ) { + if ( empty( $text ) ) { + return false; + } + if ( ! is_array( $text ) ) { + $text = array( $text ); + } + $text = array_values( $text ); + $text = $text[0]; + return ( ! empty( $text ) && stripos( $text, $this->get_prefix( $sep ) ) === 0 ); + } + + /** + * Prepend plugin prefix to some text + * @param string|array $text Text to add to prefix + * @param string $sep (optional) Text used to separate prefix and text + * @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not + * @return string Text with prefix prepended + */ + function add_prefix( $text, $sep = '_', $once = true ) { + // Normalize data type (array) + if ( empty( $text ) ) { + $text = array( '' ); + } + if ( ! is_array( $text ) ) { + $text = array( $text ); + } + // Add prefix (if necessary) + if ( ! $once || ( $once && ! $this->has_prefix( $text, $sep ) ) ) { + array_unshift( $text, $this->get_prefix() ); + } + return implode( $sep, $text ); + } + + /** + * Prepend uppercased plugin prefix to some text + * @param string|array $text Text to add to prefix + * @param string $sep (optional) Text used to separate prefix and text + * @param bool $once (optional) Whether to add prefix to text that already contains a prefix or not + * @return string Text with prefix prepended + */ + function add_prefix_uc( $text, $sep = '_', $once = true ) { + $args = func_get_args(); + $var = call_user_func_array( $this->m( $this, 'add_prefix' ), $args ); + $pre = $this->get_prefix(); + return str_replace( $pre . $sep, strtoupper( $pre ) . $sep, $var ); + } + + /** + * Add prefix to variable reference + * Updates actual variable rather than return value + * @uses add_prefix() to add prefix to variable + * @param string $var Variable to add prefix to + * @param string $sep (optional) Separator text + * @param bool $once (optional) Add prefix only once + * @return void + */ + function add_prefix_ref( &$var, $sep = null, $once = true ) { + $args = func_get_args(); + $var = call_user_func_array( $this->m( $this, 'add_prefix' ), $args ); + } + + /** + * Remove prefix from specified string + * @param string $text String to remove prefix from + * @param string $sep (optional) Separator used with prefix + */ + function remove_prefix( $text, $sep = '_' ) { + if ( $this->has_prefix( $text, $sep ) ) { + $text = substr( $text, strlen( $this->get_prefix( $sep ) ) ); + } + return $text; + } + + /** + * Returns Database prefix for plugin-related DB Tables + * @return string Database prefix + */ + function get_db_prefix() { + global $wpdb; + return $wpdb->prefix . $this->get_prefix( '_' ); + } + + /*-** Priority **-*/ + + /** + * Retrieve standard priority + * @var string $id Priority ID to retrieve + * @return int Priority + */ + public function priority( $id = null ) { + $pri = 10; + if ( ! is_null( $id ) && array_key_exists( $id, $this->_priorities ) ) { + $pri = $this->_priorities[ $id ]; + } + return $pri; + } + + /* Wrapped Values */ + + /** + * Create wrapper object + * Properties + * > start + * > end + * @param string|array $start Start text (Can also be array defining start & end values) + * @param string $end (optional) End text + * If $end not defined, then $start is used + * @return obj Wrapper + */ + function get_wrapper( $start = null, $end = null ) { + // Validate existing wrapper + if ( is_object( $start ) && isset( $start->start ) && isset( $start->end ) ) { + return $start; + } + + // Initialize wrapper + $w = array( + 'start' => '[', + 'end' => ']', + ); + + if ( ! empty( $start ) ) { + if ( is_string( $start ) ) { + $w['start'] = $start; + } elseif ( is_array( $start ) ) { + $start = array_values( $start ); + if ( is_string( $start ) ) { + $w['start'] = $start[0]; + } + if ( isset( $start[1] ) && is_string( $start[1] ) ) { + $w['end'] = $start[1]; + } + } + } + if ( is_string( $end ) ) { + $w['end'] = $end; + } + + return (object) $w; + } + + /** + * Check if text is wrapped by specified character(s) + * @uses this->get_wrapper() to Validate wrapper text + * @param string $text Text to check + * @param string|array $start (optional) Start text (Array defines both start/end text) + * @param string $end (optional) End text + */ + function has_wrapper( $text, $start = null, $end = null ) { + if ( ! is_string( $text ) || empty( $text ) ) { + return false; + } + // Validate wrapper + $w = $this->get_wrapper( $start, $end ); + + // Check for wrapper + return ( substr( $text, 0, strlen( $w->start ) ) === $w->start && substr( $text, -1, strlen( $w->end ) ) === $w->end ) ? true : false; + } + + /** + * Remove wrapper from specified text + * @uses this->has_wrapper() to check if text is wrapped + * @uses this->get_wrapper() to retrieve wrapper object + * @param string $text Text to check + * @param string|array $start (optional) Start text (Array defines both start/end text) + * @param string $end (optional) End text + * @return string Unwrapped text + */ + function remove_wrapper( $text, $start = null, $end = null ) { + if ( $this->has_wrapper( $text, $start, $end ) ) { + $w = $this->get_wrapper( $start, $end ); + $text = substr( $text, strlen( $w->start ), strlen( $text ) - strlen( $w->start ) - strlen( $w->end ) ); + } + + return $text; + } + + /** + * Add wrapper to specified text + * @uses Utilities::get_wrapper() to retrieve wrapper object + * @param string $text Text to wrap + * @param string|array $start (optional) Start text (Array defines both start/end text) + * @param string $end (optional) End text + * @param bool $once (optional) Whether to wrap text only once (Default: TRUE) + * @return string Wrapped text + */ + function add_wrapper( $text, $start = null, $end = null, $once = true ) { + $w = $this->get_wrapper( $start, $end ); + if ( ! $once || ! $this->has_wrapper( $text, $w ) ) { + $text = $w->start . $text . $w->end; + } + return $text; + } + + /*-** Client **-*/ + + /** + * Parses client files array + * > Adds ID property (prefixed file key) + * > Parses and validates internal dependencies + * > Converts properties array to object + * Properties + * > file (string|array): File name (string) or callback (array) to retrieve file name + * > deps (array) [optional]: Dependencies + * > Values wrapped in square brackets (`[` & `]`) are internal files + * > callback (string|array) [optional]: Global callback to determine whether file should be loaded + * > Values wrapped in square brackets (`[` & `]`) are internal methods (of parent object) + * > context (array) [optional]: Context(s) in which to load the file + * Acceptable values + * > string: Context name + * > array: Context name + callback (both must return TRUE to load file) + * > Callback follows same pattern as `callback` member + * @param array $files Files array + * @return object Client files + */ + function parse_client_files( $files, $type = 'scripts' ) { + if ( is_array( $files ) && ! empty( $files ) ) { + // Defaults + $defaults = array( + 'file' => null, + 'deps' => array(), + 'callback' => null, + 'context' => array(), + 'enqueue' => true, + 'enqueued' => false, + ); + switch ( $type ) { + case 'styles': + $defaults['media'] = 'all'; + break; + default: + $defaults['in_footer'] = false; + } + // Iterate through files + /** + * $h (string) handle + * $p (array) properties + */ + foreach ( $files as $h => $p ) { + unset( $file, $cb, $ctxs, $ctx ); + // Set ID + $p['id'] = $this->add_prefix( $h ); + // Type Validation + /** + * $m (string) property name + * $d (mixed) default value + */ + foreach ( $defaults as $m => $d ) { + // Check if value requires validation + if ( ! is_array( $d ) || ! isset( $p[ $m ] ) || is_array( $p[ $m ] ) ) { + continue; + } + // Wrap value in array or destroy it + if ( is_scalar( $p[ $m ] ) ) { + $p[ $m ] = array( $p[ $m ] ); + } else { + unset( $p[ $m ] ); + } + } + + // Normalize file properties + $p = array_merge( $defaults, $p ); + + /* File name */ + + // Validate file + $file =& $p['file']; + + // Determine if filename or callback + if ( ! $this->is_file( $file ) ) { + $file = ( is_callable( $file ) ) ? $file : null; + } + // Remove invalid file and move on to next + if ( empty( $file ) ) { + unset( $files[ $h ] ); + continue; + } + + /* Dependencies */ + + // Format internal dependencies + foreach ( $p['deps'] as $idx => $dep ) { + if ( $this->has_wrapper( $dep ) ) { + $dep = $this->remove_wrapper( $dep ); + $p['deps'][ $idx ] = $this->add_prefix( $dep ); + } + } + + /* Context */ + + // Validate callback + $cb =& $p['callback']; + if ( ! is_null( $cb ) && ! is_callable( $cb ) ) { + // Remove files with invalid callbacks (will never be loaded) + unset( $files[ $h ] ); + continue; + } + + // Validate contexts + $ctxs =& $p['context']; + $ctxs = array_unique( $ctxs ); + $has_contexts = ( count( $ctxs ) > 0 ) ? true : false; + foreach ( $ctxs as $idx => $ctx ) { + // Convert to array + $ctx = array_values( array_slice( (array) $ctx, 0, 2 ) ); + switch ( count( $ctx ) ) { + case 1: + // Simple context + $ctx = $ctx[0]; + break; + case 2: + // Context + Callback + if ( is_callable( $ctx[1] ) ) { + break; + } + // Continue to default case if callback is invalid + default: + // Context is invalid + $ctx = false; + break; + } + + // Remove invalid contexts + if ( empty( $ctx ) ) { + unset( $ctxs[ $idx ] ); + } else { + $ctxs[ $idx ] = $ctx; + } + } + // Remove file if all specified contexts invalid (no context is OK) + if ( $has_contexts && empty( $ctxs ) ) { + unset( $files[ $h ] ); + continue; + } + $ctxs = array_values( $ctxs ); + + /* Finalize Properties */ + + // Convert properties to object + $files[ $h ] = (object) $p; + } + } + // Cast to object before returning + $files = (object) $files; + return $files; + } + + /** + * Build JS client object + * @param string (optional) $path Additional object path + * @return string Client object + */ + function get_client_object( $path = null ) { + $obj = strtoupper( $this->get_prefix() ); + if ( ! empty( $path ) && is_string( $path ) ) { + if ( 0 !== strpos( $path, '[' ) ) { + $obj .= '.'; + } + $obj .= $path; + } + return $obj; + } + + /** + * Build jQuery JS expression to add data to specified client object + * @param string|obj $obj Name of client object (Set to root object if not a valid name) + * @param mixed $data Data to add to client object + * @param bool (optional) $out Whether or not to output code (Default: false) + * @return string JS expression to extend client object + */ + function extend_client_object( $obj, $data = null, $out = false ) { + // Validate parameters + $args = func_get_args(); + switch ( count( $args ) ) { + case 2: + if ( ! is_scalar( $args[0] ) ) { + if ( is_bool( $args[1] ) ) { + $out = $args[1]; + } + } else { + break; + } + // no break. + case 1: + $data = $args[0]; + $obj = null; + break; + } + // Default client object + if ( ! is_string( $obj ) || empty( $obj ) ) { + $obj = null; + } + // Default data + if ( is_array( $data ) ) { + $data = (object) $data; + } + // Build expression + if ( empty( $data ) || ( empty( $obj ) && is_scalar( $data ) ) ) { + $ret = ''; + } else { + $c_obj = $this->get_client_object( $obj ); + $ret = $this->validate_client_object( $obj, sprintf( '{$.extend(%1$s, %2$s);}', $c_obj, wp_json_encode( $data ) ) ); + if ( $out ) { + echo $this->build_script_element( $ret, 'context', true, true ); + } + } + return $ret; + } + + /** + * Validate client object $obj before running command $cmd + * + * @param string $obj Full object name + * @param string $cmd (optional) Command to wrap in validation + * @return string Command wrapped in validation block + * If no command is specified the validation conditions are returned + */ + public function validate_client_object( $obj, $cmd = null ) { + // Get base object + $base = $this->get_client_object(); + + // Build condition + $sep = '.'; + $obj = trim( $obj, $sep ); + // Strip base object + if ( 0 === strpos( $obj, $base . $sep ) ) { + $obj = substr( $obj, strlen( $base . $sep ) ); + } + $fmt = '!!window.%1$s'; + if ( ! empty( $obj ) ) { + $fmt .= ' && %1$s.has_child(\'%2$s\')'; + } + $condition = sprintf( $fmt, $base, $obj ); + + // Wrap command in validation + if ( ! empty( $cmd ) && is_string( $cmd ) ) { + $condition = sprintf( 'if ( %1$s ) { %2$s }', $condition, $cmd ); + } + return $condition; + } + + /** + * Build client method call + * @uses get_client_object() to generate the body of the method call + * @param string $method Method name + * @param array|string $params (optional) Parameters to pass to method + * @param bool $encode (optional) JSON-encode parameters? (Default: TRUE) + * @param bool $validate (optional) Validate method before calling it? + * @return string Method call + */ + function call_client_method( $method, $params = null, $encode = true, $validate = true ) { + $ret = ''; + if ( ! is_string( $method ) || empty( $method ) ) { + return $ret; + } + $encode = ! ! $encode; + $validate = ! ! $validate; + + // Build parameters + if ( ! is_null( $params ) ) { + if ( $encode ) { + $params = wp_json_encode( $params ); + } elseif ( is_array( $params ) ) { + $params = implode( ',', $params ); + } + } + if ( ! is_string( $params ) ) { + $params = ''; + } + $ret = sprintf( '%s(%s);', $this->get_client_object( $method ), $params ); + if ( $validate ) { + $ret = $this->validate_client_object( $method, $ret ); + } + return $ret; + } + + /*-** WP **-*/ + + /** + * Retrieve parent object + * @return obj|bool Parent object (FALSE if no valid parent set) + */ + function get_parent() { + if ( is_object( $this->_parent ) ) { + return $this->_parent; + } else { + return false; + } + } + + /** + * Retrieve parent property value + * @uses self::get_parent() + * @param string $prop Property name + * @param mixed $default Default value + * @return mixed Parent property value + */ + function get_parent_property( $prop, $default = '' ) { + $p = $this->get_parent(); + return ( ! ! $p && property_exists( $p, $prop ) ) ? $p->{$prop} : $default; + } + + /* Hooks */ + + /** + * Retrieve formatted name for internal hooks + * Prefixes with parent prefix and hook prefix + * @uses self::get_parent_property() to retrieve hook prefix + * @uses self::add_prefix() + * @param string $tag Base tag + * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) + * @return string Formatted hook + */ + function get_hook( $tag, $hook_prefix = true ) { + // Hook prefix + $hook = ''; + if ( is_bool( $hook_prefix ) && $hook_prefix ) { + $hook = $this->get_parent_property( 'hook_prefix', '' ); + } elseif ( is_string( $hook_prefix ) ) { + $hook = $hook_prefix; + } + if ( ! empty( $hook ) ) { + $hook .= '_'; + } + // Prefix + return $this->add_prefix( $hook . $tag ); + } + + /** + * Run internal action + * Namespaces $tag + * @uses self::get_hook() + * @see do_action() + * @param string|array $tag Action hook. If array, get hook prefix + */ + function do_action( $tag, $arg = '' ) { + // Handle hook prefix + $hook_prefix = true; + if ( is_array( $tag ) ) { + $hook_prefix = $tag[1]; + $tag = $tag[0]; + } + $args = func_get_args(); + $args[0] = $this->get_hook( $tag, $hook_prefix ); + return call_user_func_array( 'do_action', $args ); + } + + /** + * Run internal action passing arguments in array + * @uses do_action_ref_array() + * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) + */ + function do_action_ref_array( $tag, $args, $hook_prefix = true ) { + return do_action_ref_array( $this->get_hook( $tag, $hook_prefix ), $args ); + } + + /** + * Run internal filter + * Namespaces $tag + * @uses self::get_hook() + * @see apply_filters() + * @param string|array $tag Action hook. If array, get hook prefix + */ + function apply_filters( $tag, $value ) { + // Handle hook prefix + $hook_prefix = true; + if ( is_array( $tag ) ) { + $hook_prefix = $tag[1]; + $tag = $tag[0]; + } + $args = func_get_args(); + $args[0] = $this->get_hook( $tag, $hook_prefix ); + return call_user_func_array( 'apply_filters', $args ); + } + + /** + * Run internal filter passing arguments in array + * @uses apply_filters_ref_array() + * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) + */ + function apply_filters_ref_array( $tag, $args, $hook_prefix = true ) { + return apply_filters_ref_array( $this->get_hook( $tag, $hook_prefix ), $args ); + } + + /** + * Add internal action + * Namespaces $tag + * @uses self::get_hook() + * @see add_action() + * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) + */ + function add_action( $tag, $function_to_add, $priority = 10, $accepted_args = 1, $hook_prefix = true ) { + return add_action( $this->get_hook( $tag, $hook_prefix ), $function_to_add, $priority, $accepted_args ); + } + + /** + * Add internal filter + * Namespaces $tag + * @uses self::get_hook() + * @see add_filter() + * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) + */ + function add_filter( $tag, $function_to_add, $priority = 10, $accepted_args = 1, $hook_prefix = true ) { + return add_filter( $this->get_hook( $tag, $hook_prefix ), $function_to_add, $priority, $accepted_args ); + } + + /** + * Remove internal action + * Namespaces $tag + * @uses self::get_hook() + * @uses remove_action() + * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) + */ + function remove_action( $tag, $function_to_remove, $priority = 10, $accepted_args = 1, $hook_prefix = true ) { + return remove_action( $this->get_hook( $tag, $hook_prefix ), $function_to_remove, $priority, $accepted_args ); + } + + /** + * Remove internal filter + * Namespaces $tag + * @uses self::get_hook() + * @uses remove_filter() + * @param bool|string $hook_prefix (optional) Secondary prefix to use for hook (Default: Use predefined hook name, FALSE: no secondary hook) + */ + function remove_filter( $tag, $function_to_remove, $priority = 10, $accepted_args = 1, $hook_prefix = true ) { + return remove_filter( $this->get_hook( $tag, $hook_prefix ), $function_to_remove, $priority, $accepted_args ); + } + + /* Shortcode */ + + /** + * Process specific shortcode(s) in content + * Default: Process all existing shortcodes + * @uses $shortcode_tags - array tag => callback + * @uses do_shortcode() + * + * @param string $content Content to process for shortcodes + * @param string|array $shortcode Single tag or array of tags to process + * > Associative array sets temporary callbacks for shortcodes (`tag => callback`) + */ + public function do_shortcode( $content, $shortcode = null ) { + global $shortcode_tags; + + // Process custom shortcodes + if ( ! is_null( $shortcode ) ) { + // Cast to array + $shortcode = (array) $shortcode; + // Backup and reset shortcode handlers + $tags_temp = $shortcode_tags; + $shortcode_tags = array(); + // Register specified tags + foreach ( $shortcode as $key => $val ) { + if ( is_string( $key ) && is_callable( $val ) ) { + // Tag w/custom callback + $shortcode_tags[ $key ] = $val; + } elseif ( is_int( $key ) && is_string( $val ) && isset( $tags_temp[ $val ] ) ) { + // Tag with default callback + $shortcode_tags[ $val ] = $tags_temp[ $val ]; + } + } + } + + // Process shortcodes in content + $content = do_shortcode( $content ); + + // Restore default shortcode handlers + if ( isset( $tags_temp ) ) { + $shortcode_tags = $tags_temp; + unset( $tags_temp ); + } + + return $content; + } + + /** + * Build shortcode tag + * @param string $tag Shortcode base + * @param array (optional) $attr Shortcode attributes + * @param string (optional) $content Shortcode content + * @return string Shortcode tag + */ + public function make_shortcode( $tag, $attr = null, $content = null ) { + return $this->build_element( + array( + 'tag' => $tag, + 'attributes' => $attr, + 'content' => $content, + ) + ); + } + + /* Meta */ + + /** + * Retrieves post metadata for internal methods + * Metadata set internally is wrapped in an array so it is unwrapped before returned the retrieved value + * @see get_post_meta() + * @param int $post_id Post ID + * @param string $key Name of metadata to retrieve + * @param boolean $single Whether or not to retrieve single value or not + * @return mixed Retrieved post metadata + */ + function post_meta_get( $post_id, $key, $single = false ) { + $meta_value = get_post_meta( $post_id, $this->post_meta_get_key( $key ), $single ); + if ( is_array( $meta_value ) && count( $meta_value ) === 1 ) { + $meta_value = $meta_value[0]; + } + return $meta_value; + } + + /** + * Wraps metadata in array for storage in database + * @param mixed $meta_value Value to be set as metadata + * @return array Wrapped metadata value + */ + function post_meta_prepare_value( $meta_value ) { + return array( $meta_value ); + } + + /** + * Adds Metadata for a post to database + * For internal methods + * @see add_post_meta + * @param $post_id + * @param $meta_key + * @param $meta_value + * @param $unique + * @return boolean Result of operation + */ + function post_meta_add( $post_id, $meta_key, $meta_value, $unique = false ) { + $meta_value = $this->post_meta_value_prepare( $meta_value ); + return add_post_meta( $post_id, $meta_key, $meta_value, $unique ); + } + + /** + * Updates post metadata for internal data/methods + * @see update_post_meta() + * @param $post_id + * @param $meta_key + * @param $meta_value + * @param $prev_value + * @return boolean Result of operation + */ + function post_meta_update( $post_id, $meta_key, $meta_value, $prev_value = '' ) { + $meta_value = $this->post_meta_prepare_value( $meta_value ); + return update_post_meta( $post_id, $meta_key, $meta_value, $prev_value ); + } + + /** + * Builds postmeta key for custom data set by plugin + * @param string $key Base key name + * @return string Formatted postmeta key + */ + function post_meta_get_key( $key ) { + $sep = '_'; + if ( strpos( $key, $sep . $this->prefix ) !== 0 ) { + $key_base = func_get_args(); + if ( ! empty( $key_base ) ) { + $key = array_merge( (array) $this->prefix, $key_base ); + return $sep . implode( $sep, $key ); + } + } + + return $key; + } + + /** + * Creates a meta key for storing post meta data + * Prefixes standard prefixed text with underscore to hide meta data on post edit forms + * @param string $text Text to use as base of meta key + * @return string Formatted meta key + */ + function make_meta_key( $text = '' ) { + return '_' . $this->add_prefix( $text ); + } + + /* Class */ + + /** + * Retrieve name of internal class + * @param string $class Base name of class + * @return string Full name of internal class + */ + function get_class( $class ) { + return $this->add_prefix_uc( $class ); + } + + /* Context */ + + /** + * Retrieve context for current request + * @return array Context + */ + function get_context() { + // Context + static $ctx = null; + if ( ! is_array( $ctx ) ) { + // Standard + $ctx = array( $this->build_context() ); + // Action + $action = $this->get_action(); + if ( ! empty( $action ) ) { + $ctx[] = $this->build_context( 'action', $action ); + } + // Post type + $post_type = $this->get_post_type(); + if ( ! empty( $action ) ) { + $ctx[] = $this->build_context( 'post-type', $post_type ); + } + // Admin page + if ( is_admin() ) { + global $pagenow; + $pg = $this->strip_file_extension( $pagenow ); + $ctx[] = $this->build_context( 'page', $pg ); + // Query String + if ( isset( $_SERVER['QUERY_STRING'] ) ) { + parse_str( $_SERVER['QUERY_STRING'], $qv ); + if ( isset( $qv['page'] ) ) { + $ctx[] = $this->build_context( 'page', $qv['page'] ); + if ( stripos( $qv['page'], $this->get_prefix() ) === 0 ) { + $ctx[] = $this->build_context( 'page', $this->get_prefix() ); + } + } + } + // Action + if ( ! empty( $action ) ) { + $ctx[] = $this->build_context( 'page', $pg, 'action', $action ); + $ctx[] = $this->build_context( 'post-type', $post_type, 'action', $action ); + } + } + // User + $u = wp_get_current_user(); + $ctx[] = $this->build_context( 'user', ( $u->ID ) ? 'registered' : 'guest', false ); + } + + return $ctx; + } + + /** + * Builds context from multiple components + * Usage: + * > $prefix can be omitted and context strings can be added as needed + * > Multiple context strings may be passed to be joined together + * + * @param string (optional) $context Variable number of components to add to context + * @param bool (optional) $prefix Whether or not to prefix context with request type (public or admin) [Default: TRUE] + * @return string Context + */ + function build_context( $context = null, $prefix = true ) { + $args = func_get_args(); + // Get prefix option + if ( ! empty( $args ) ) { + $prefix = ( is_bool( $args[ count( $args ) - 1 ] ) ) ? array_pop( $args ) : true; + } + + // Validate + $context = array_filter( $args, 'is_string' ); + $sep = '_'; + + // Context Prefix + if ( $prefix ) { + array_unshift( $context, ( is_admin() ) ? 'admin' : 'public' ); + } + return implode( $sep, $context ); + } + + /** + * Check if context exists in current request + * @param string $context Context to check for + * @return bool TRUE if context exists FALSE otherwise + */ + function is_context( $context ) { + $ret = false; + if ( is_scalar( $context ) ) { + $context = array( $context ); + } + if ( is_array( $context ) && ! empty( $context ) ) { + $ictx = array_intersect( $this->get_context(), $context ); + if ( ! empty( $ictx ) ) { + $ret = true; + } + } + return $ret; + } + + /** + * Output current context to client-side + * @uses `wp_head` action hook + * @uses `admin_head` action hook + * @return void + */ + function set_client_context() { + $ctx = new stdClass(); + $ctx->context = $this->get_context(); + $this->extend_client_object( $ctx, true ); + } + + /* Path */ + + /** + * Joins and normalizes the slashes in the paths passed to method + * All forward/back slashes are converted to forward slashes + * Multiple path segments can be passed as additional argments + * @param string $path Path to normalize + * @param bool|array $trailing_slash (optional) Whether or not normalized path should have a trailing slash or not (Default: FALSE) + * If array is passed, first index is trailing, second is leading slash + * If multiple path segments are passed, $trailing_slash will be the LAST parameter (default value used if omitted) + */ + function normalize_path( $path, $trailing_slash = false ) { + $sl_f = '/'; + $sl_b = '\\'; + $parts = func_get_args(); + // Slash defaults (trailing, leading); + $slashes = array( false, true ); + if ( func_num_args() > 1 ) { + // Get last argument + $arg_last = $parts[ count( $parts ) - 1 ]; + if ( is_bool( $arg_last ) ) { + $arg_last = array( $arg_last ); + } + + if ( is_array( $arg_last ) && count( $arg_last ) > 0 && is_bool( $arg_last[0] ) ) { + // Remove slash paramter from args array + array_pop( $parts ); + // Normalize slashes options + if ( isset( $arg_last[0] ) ) { + $slashes[0] = $arg_last[0]; + } + if ( isset( $arg_last[1] ) ) { + $slashes[1] = $arg_last[1]; + } + } + } + // Extract to slash options local variables + list($trailing_slash, $leading_slash) = $slashes; + + // Clean path segments + foreach ( $parts as $key => $part ) { + // Trim slashes/spaces + $parts[ $key ] = trim( $part, ' ' . $sl_f . $sl_b ); + + // Verify path segment still contains value + if ( empty( $parts[ $key ] ) ) { + unset( $parts[ $key ] ); + continue; + } + } + + // Join path parts together + $parts = implode( $sl_b, $parts ); + $parts = str_replace( $sl_b, $sl_f, $parts ); + // Add trailing slash (if necessary) + if ( $trailing_slash ) { + $parts .= $sl_f; + } + // Add leading slash (if necessary) + $regex = '#^.+:[\\/]#'; + if ( $leading_slash && ! preg_match( $regex, $parts ) ) { + $parts = $sl_f . $parts; + } + return $parts; + } + + /** + * Returns URL of file (assumes that it is in plugin directory) + * @param string $file name of file get URL + * @param string|bool $relative Path that URI should be relative to (Default: full path) + * @return string File URL + */ + function get_file_url( $file, $relative = null ) { + if ( is_string( $file ) && '' !== trim( $file ) ) { + $file = str_replace( ' ', '%20', $this->normalize_path( $this->get_url_base( false, $relative ), $file ) ); + } + return $file; + } + + /** + * Returns path to plugin file + * @param string $file file name + * @return string File path + */ + function get_file_path( $file, $relative = null ) { + // Build path + if ( is_string( $file ) && '' !== trim( $file ) ) { + $file = $this->normalize_path( $this->get_path_base( $relative ), $file ); + } + return $file; + } + + function get_plugin_file_path( $file, $trailing_slash = false ) { + if ( is_string( $file ) && '' !== trim( $file ) ) { + $file = $this->normalize_path( $this->get_plugin_base(), $file, $trailing_slash ); + } + return $file; + } + + /** + * Checks if value is valid file name + * @param string $filename File name to check + * @return bool TRUE if valid file name, FALSE otherwise + */ + function is_file( $filename ) { + $ext = $this->get_file_extension( $filename ); + return ( empty( $ext ) ) ? false : true; + } + + /** + * Check if string is valid URI + * @param string $uri String to check + * @return bool TRUE if string is valid URI + */ + function is_uri( $uri ) { + return ( preg_match( '|^(https?:)?//|', $uri ) ) ? true : false; + } + + /** + * Retrieves file extension. + * + * @param string $file File path. + * @param bool $lowercase Optional. Format extension as lowercase. Default true. + * @return string Extension of file. Empty string if no extension found. + */ + function get_file_extension( $file, $lowercase = true ) { + $ret = ''; + $sep = '.'; + // Validate: String must contain extension separator. + if ( ! is_string( $file ) || false === strrpos( $file, $sep ) ) { + return $ret; + } + // Strip query string if necessary. + $qpos = strpos( $file, '?' ); + if ( false !== $qpos ) { + $file = substr( $file, 0, $qpos ); + } + // Get basename. + $file = wp_basename( $file ); + + // Get extension. + $rpos = strrpos( $file, $sep ); + if ( $rpos > 0 ) { + $ret = substr( $file, $rpos + 1 ); + } + // Format output. + if ( ! ! $lowercase ) { + $ret = strtolower( $ret ); + } + return $ret; + } + + /** + * Checks if file has specified extension + * @uses get_file_extension() + * @param string $file File name/path + * @param string|array $extension File ending(s) to check $file for + * @param bool (optional) Whether check should be case senstive or not (Default: FALSE) + * @return bool TRUE if file has extension + */ + function has_file_extension( $file, $extension, $case_sensitive = false ) { + if ( ! is_array( $extension ) ) { + $extension = array( strval( $extension ) ); + } + if ( ! $case_sensitive ) { + // Normalize extensions + $extension = array_map( 'strtolower', $extension ); + } + return ( in_array( $this->get_file_extension( $file, ! $case_sensitive ), $extension, true ) ) ? true : false; + } + + /** + * Removes file extension from file name + * The extension is the text following the last period ('.') in the file name + * @uses get_file_extension() + * @param string $file File name + * @return string File name without extension + */ + function strip_file_extension( $file ) { + $ext = $this->get_file_extension( $file ); + if ( ! empty( $ext ) ) { + $file = substr( $file, 0, ( strlen( $ext ) + 1 ) * -1 ); + } + return $file; + } + + /** + * Retrieve base URL for plugin-specific files + * @uses get_plugin_base() + * @uses normalize_path() + * @return string Base URL + */ + function get_url_base( $trailing_slash = false, $relative = null ) { + $ret = $this->get_meta( 'uri' ); + if ( empty( $ret ) ) { + $ret = $this->normalize_path( plugins_url(), $this->get_plugin_base() ); + } + // Trailing slash + if ( ! ! $trailing_slash ) { + $ret .= '/'; + } + // Relative + if ( ! empty( $relative ) ) { + // Default + if ( is_bool( $relative ) ) { + $relative = site_url(); + } + // Custom + if ( is_string( $relative ) ) { + $ret = $this->get_relative_path( $ret, $relative ); + } + } + + return $ret; + } + + /** + * Retrieves the plugin's base path. + * + * @param bool|string $relative Optional. Return a path relative to WordPress (true) or a custom directory (string). Default null. + * @return string Plugin's base path. + */ + function get_path_base( $relative = null ) { + // Get base path (if necessary). + if ( empty( $this->_path_base ) ) { + // Get base directory of parent object + if ( $this->get_parent() ) { + $r = new ReflectionClass( get_class( $this->get_parent() ) ); + $base = $r->getFileName(); + unset( $r ); + } else { + $base = __FILE__; + } + // Extract base path + $base = $this->normalize_path( $base ); + if ( 0 === strpos( $base, $this->normalize_path( WP_PLUGIN_DIR ) ) ) { + $end = strpos( $base, '/', strlen( WP_PLUGIN_DIR ) + 1 ); + $base = substr( $base, 0, $end ); + } + // Save base path. + $this->_path_base = $base; + } + + // Return full base path (based on parameters). + if ( empty( $relative ) ) { + return $this->_path_base; + } + + // Make relative path. + $ret = $this->_path_base; + + // Default: Relative to WordPress absolute path. + if ( is_bool( $relative ) ) { + $relative = ABSPATH; + } + // Get relative path. + if ( is_string( $relative ) ) { + $ret = $this->get_relative_path( $ret, $relative ); + } + return $ret; + } + + /** + * Retrieve relative path for absolute paths + * @param string $path Path to modify + * @param string $relative (optional) Base path to make $path relative to (Default: Site's base path) + * @return string Relative path + */ + function get_relative_path( $path, $relative = true ) { + // Default base path + if ( ! is_string( $relative ) ) { + $relative = ABSPATH; + } + if ( ! empty( $relative ) && ! empty( $path ) ) { + $relative = $this->normalize_path( $relative ); + $path = $this->normalize_path( $path ); + // Strip base path + if ( strpos( $path, $relative ) === 0 ) { + $path = substr( $path, strlen( $relative ) ); + } + } + return $path; + } + + /** + * Retrieves plugin metadata. + * + * @param string $key Metadata key to retrieve. + * @return mixed Value of specified metadata key. Null if key does not exist. + */ + private function get_meta( $key ) { + $key = sanitize_key( $key ); + // Get metadata value. + return ( strlen( $key ) > 0 && isset( $this->plugin_meta[ $key ] ) ) ? $this->plugin_meta[ $key ] : null; + } + + /** + * Checks if plugin metadata exists. + * + * @param string $key Metadata key to check for. + * @return bool True if metadata key is set. False if not. + */ + private function has_meta( $key ) { + $val = $this->get_meta( $key ); + return ( ! is_null( $val ) ); + } + + /** + * Sets plugin metadata. + * + * @param string $key Metadata key to set. + * @param mixed $val Metadata value to set. + * @return mixed Metadata value set. + */ + private function set_meta( $key, $val ) { + // Validate key. + $key = sanitize_key( $key ); + if ( strlen( $key ) > 0 ) { + // Set metadata. + $this->plugin_meta[ $key ] = $val; + } + return $val; + } + + /** + * Retrieve plugin's base directory + * @uses WP_PLUGIN_DIR + * @uses Utilities::get_path_base() to retrieve plugin base path + * @uses Utilities::_plugin_base to save plugin base + * @return string Base directory + */ + function get_plugin_base() { + $ret = $this->get_meta( 'base' ); + if ( empty( $ret ) ) { + $ret = $this->set_meta( 'base', basename( $this->get_path_base() ) ); + } + return $ret; + } + + /** + * Retrieves plugin's base file path. + * + * @return string Full path to plugin's base file. + */ + function get_plugin_base_file() { + // Get stored data (if previously set). + $key = 'file'; + $ret = $this->get_meta( $key ); + if ( ! empty( $ret ) ) { + return $ret; + } + + // Scan directory (DirectoryIterator) + foreach ( new DirectoryIterator( $this->get_path_base() ) as $f_info ) { + // Stop processing invalid items. + if ( $f_info->isDot() || ! $f_info->isFile() || $f_info->getExtension() !== 'php' || ! $f_info->isReadable() ) { + continue; + } + + $ftemp = $f_info->getPathname(); + // Check for metadata. + $data = get_file_data( $ftemp, $this->get_meta( 'headers' ) ); + // Stop processing if no metadata found. + if ( empty( $data['Name'] ) ) { + continue; + } + // Set base file. + $ret = $this->set_meta( $key, $ftemp ); + // Save plugin data. + $this->set_plugin_info( $data ); + // Stop processing files. + break; + } + // Return base file. + return $ret; + } + + /** + * Retrieve plugin's internal name + * Internal name is used by WP core + * @uses get_plugin_base_file() + * @uses plugin_basename() + * @return string Internal plugin name + */ + function get_plugin_base_name() { + $ret = $this->get_meta( 'name' ); + if ( empty( $ret ) ) { + $ret = $this->set_meta( 'name', plugin_basename( $this->get_plugin_base_file() ) ); + } + return $ret; + } + + /** + * Sets plugin information. + * + * @param array $data Plugin info to set. + * @return void + */ + private function set_plugin_info( $data ) { + if ( is_array( $data ) ) { + $this->set_meta( 'data', $data ); + } + } + + /** + * Retrieves plugin info. + * + * @param string $field Plugin info to retrieve. + * @return array|string Full plugin info array, or specific field value. + */ + public function get_plugin_info( $field = null ) { + $key = 'data'; + // Initialize plugin headers (if necessary). + if ( ! $this->has_meta( $key ) ) { + $this->get_plugin_base_file(); + } + // Get plugin data. + $ret = $this->get_meta( $key ); + // Return specified field. + if ( ! empty( $field ) && is_string( $field ) ) { + $ret = ( is_array( $ret ) && isset( $ret[ $field ] ) ) ? $ret[ $field ] : ''; + } + return $ret; + } + + /** + * Retrieve plugin version + * @uses get_plugin_info() + * @param bool $strip_desc Strip any additional version text + * @return string Plugin version + */ + function get_plugin_version( $strip_desc = true ) { + // Retrieve version + $ret = $this->get_plugin_info( 'Version' ); + // Format + if ( ! empty( $ret ) && $strip_desc ) { + $ret = explode( ' ', $ret, 2 ); + $ret = $ret[0]; + } + // Return + return $ret; + } + + /** + * Retrieve current post type based on URL query variables + * @return string|null Current post type + */ + public function get_post_type() { + if ( isset( $_GET['post_type'] ) && ! empty( $_GET['post_type'] ) ) { + return $_GET['post_type']; + } + $pt = null; + if ( isset( $_GET['post'] ) && is_numeric( $_GET['post'] ) ) { + $pt = get_post_type( $_GET['post'] ); + } + return $pt; + } + + /** + * Retrieves current action based on URL query variables. + * + * @param mixed $default Optional. Default action if no action exists. Default null. + * @return string Current action. + */ + function get_action( $default = null ) { + $action = ''; + + // Check if action is set in URL + if ( isset( $_GET['action'] ) ) { + $action = $_GET['action']; + } elseif ( isset( $_GET['page'] ) ) { + $pos = strrpos( $_GET['page'], '-' ); + if ( false !== $pos && ( ( strlen( $_GET['page'] ) - 1 ) !== $pos ) ) { + // Otherwise, Determine action based on plugin admin page suffix + $action = trim( substr( $_GET['page'], $pos + 1 ), '-_' ); + } + } + + // Determine action for core admin pages + if ( ( ! isset( $_GET['page'] ) || empty( $action ) ) && isset( $_SERVER['SCRIPT_NAME'] ) ) { + $actions = array( + 'add' => array( 'page-new', 'post-new' ), + 'edit-item' => array( 'page', 'post' ), + 'edit' => array( 'edit', 'edit-pages' ), + ); + $page = basename( $_SERVER['SCRIPT_NAME'], '.php' ); + + foreach ( $actions as $act => $pages ) { + if ( in_array( $page, $pages, true ) ) { + $action = $act; + break; + } + } + } + if ( empty( $action ) ) { + $action = $default; + } + return $action; + } + + /*-** General **-*/ + + /** + * Checks if a property exists in a class or object + * Compatibility method for PHP 4 + * @param mixed $class Class or object to check + * @param string $property Name of property to look for in $class + */ + function property_exists( $class, $property ) { + if ( ! is_object( $class ) && ! is_array( $class ) ) { + return false; + } + if ( function_exists( 'property_exists' ) && is_object( $class ) ) { + return property_exists( $class, $property ); + } else { + return array_key_exists( $property, $class ); + } + } + + /** + * Retrieve specified property from object or array + * @param object|array $obj Object or array to get property from + * @param string $property Property name to retrieve + * @return mixed Property value + */ + function &get_property( &$obj, $property ) { + $property = trim( $property ); + // Object + if ( is_object( $obj ) ) { + return $obj->{$property}; + } + // Array + if ( is_array( $obj ) ) { + return $obj[ $property ]; + } + // Class + if ( is_string( $obj ) && class_exists( $obj ) ) { + $cvars = get_class_vars( $obj ); + if ( isset( $cvars[ $property ] ) ) { + return $cvars[ $property ]; + } + } + } + + /** + * Remap array members based on a + * mapping of source/destination keys + * @param array $properties Associative array of properties + * @param array $map Source/Destination mapping + * > Key: Source member + * > Val: Destination member + * @param bool $overwrite If TRUE, source value will be set in destination regardless of whether member already exists or not + * @return array Remapped properties + */ + function array_remap( $arr, $map = array(), $overwrite = false ) { + if ( ! empty( $map ) && is_array( $map ) ) { + // Iterate through mappings + foreach ( $map as $from => $to ) { + if ( ! array_key_exists( $from, $arr ) ) { + continue; + } + $move = $overwrite; + // Only remap if parent property doesn't already exist in array + if ( ! array_key_exists( $to, $arr ) ) { + $move = true; + } + if ( $move ) { + // Move member value to new key + $arr[ $to ] = $arr[ $from ]; + // Remove source member + unset( $arr[ $from ] ); + } + } + } + // Return remapped properties + return $arr; + } + + function array_filter_keys( $arr, $keys ) { + if ( is_array( $arr ) && ! empty( $arr ) && is_array( $keys ) && ! empty( $keys ) ) { + foreach ( $keys as $rem ) { + if ( array_key_exists( $rem, $arr ) ) { + unset( $arr[ $rem ] ); + } + } + } + + return $arr; + } + + /** + * Insert an item into an array at the specified position + * @param mixed $item Item to insert into array + * @param int $pos Index position to insert item into array + * @return array Modified array + */ + function array_insert( $array, $item, $pos = null ) { + array_splice( $array, $pos, 0, $item ); + return $array; + } + + /** + * Merges 1 or more arrays together + * Methodology + * - Set first parameter as base array + * - All other parameters will be merged into base array + * - Iterate through other parameters (arrays) + * - Skip all non-array parameters + * - Iterate though key/value pairs of current array + * - Merge item in base array with current item based on key name + * - If the current item's value AND the corresponding item in the base array are BOTH arrays, recursively merge the the arrays + * - If the current item's value OR the corresponding item in the base array is NOT an array, current item overwrites base item + * @param array Variable number of arrays + * @param array $arr1 Default array + * @return array Merged array + */ + function array_merge_recursive_distinct( $arr1 ) { + // Get all arrays passed to function + $args = func_get_args(); + if ( empty( $args ) ) { + return false; + } + // Return empty array if first parameter is not an array + if ( ! is_array( $args[0] ) ) { + return array(); + } + // Set first array as base array + $merged = $args[0]; + // Iterate through arrays to merge + $arg_length = count( $args ); + for ( $x = 1; $x < $arg_length; $x++ ) { + // Skip if argument is not an array (only merge arrays) + if ( ! is_array( $args[ $x ] ) ) { + continue; + } + // Iterate through argument items + foreach ( $args[ $x ] as $key => $val ) { + // Generate key for numeric indexes + if ( is_int( $key ) ) { + // Add new item to merged array + $merged[] = null; + // Get key of new item + $key = array_pop( array_keys( $merged ) ); + } + if ( ! isset( $merged[ $key ] ) || ! is_array( $merged[ $key ] ) || ! is_array( $val ) ) { + $merged[ $key ] = $val; + } elseif ( is_array( $merged[ $key ] ) && is_array( $val ) ) { + $merged[ $key ] = $this->array_merge_recursive_distinct( $merged[ $key ], $val ); + } + } + } + return $merged; + } + + /** + * Replaces string value in one array with the value of the matching element in a another array + * + * @param string $search Text to search for in array + * @param array $arr_replace Array to use for replacing values + * @param array $arr_subject Array to search for specified value + * @return array Searched array with replacements made + */ + function array_replace_recursive( $search, $arr_replace, $arr_subject ) { + foreach ( $arr_subject as $key => $val ) { + // Skip element if key does not exist in the replacement array + if ( ! isset( $arr_replace[ $key ] ) ) { + continue; + } + // If element values for both arrays are strings, replace text + if ( is_string( $val ) && strpos( $val, $search ) !== false && is_string( $arr_replace[ $key ] ) ) { + $arr_subject[ $key ] = str_replace( $search, $arr_replace[ $key ], $val ); + } + // If value in both arrays are arrays, recursively replace text + if ( is_array( $val ) && is_array( $arr_replace[ $key ] ) ) { + $arr_subject[ $key ] = $this->array_replace_recursive( $search, $arr_replace[ $key ], $val ); + } + } + + return $arr_subject; + } + + /** + * Checks if item at specified path in array is set + * @param array $arr Array to check for item + * @param array $path Array of segments that form path to array (each array item is a deeper dimension in the array) + * @return boolean TRUE if item is set in array, FALSE otherwise + */ + function array_item_isset( &$arr, &$path ) { + $f_path = $this->get_array_path( $path ); + return eval( 'return isset($arr' . $f_path . ');' ); + } + + /** + * Build formatted string based on array values + * Array values in formatted string will be ordered by index order + * @param array $attribute Values to build string with + * @param string $format (optional) Format name (Default: Multidimensional array representation > ['value1']['value2']['value3'], etc.) + * @return string Formatted string based on array values + */ + function get_array_path( $attribute = '', $format = null ) { + // Formatted value + $fmtd = ''; + if ( ! empty( $attribute ) ) { + // Make sure attribute is array + if ( ! is_array( $attribute ) ) { + $attribute = array( $attribute ); + } + // Format attribute + $format = strtolower( $format ); + switch ( $format ) { + case 'id': + $fmtd = array_shift( $attribute ) . '[' . implode( '][', $attribute ) . ']'; + break; + case 'metadata': + case 'attribute': + // Join segments + $delim = '_'; + $fmtd = implode( $delim, $attribute ); + // Replace white space and repeating delimiters + $fmtd = str_replace( ' ', $delim, $fmtd ); + while ( strpos( $fmtd, $delim . $delim ) !== false ) { + $fmtd = str_replace( $delim . $delim, $delim, $fmtd ); + } + // Prefix formatted value with delimeter for metadata keys + if ( 'metadata' === $format ) { + $fmtd = $delim . $fmtd; + } + break; + case 'path': + case 'post': + default: + $fmtd = '["' . implode( '"]["', $attribute ) . '"]'; + } + } + return $fmtd; + } + + /** + * Builds array of path elements based on arguments + * Each item in path array represents a deeper level in structure path is for (object, array, filesystem, etc.) + * @param array|string Value to add to the path + * @return array 1-dimensional array of path elements + */ + function build_path() { + $path = array(); + $args = func_get_args(); + + // Iterate through parameters and build path + foreach ( $args as $arg ) { + if ( empty( $arg ) ) { + continue; + } + + if ( is_array( $arg ) ) { + // Recurse through array items to pull out any more arrays + foreach ( $arg as $key => $val ) { + $path = array_merge( $path, $this->build_path( $val ) ); + } + } elseif ( is_scalar( $arg ) ) { + $path[] = $arg; + } + } + + return $path; + } + + /** + * Build generic element + * @param array $args + * @return string Element output + */ + public function build_element( $args = array() ) { + $ret = ''; + $args_default = array( + 'tag' => '', + 'wrap' => false, + 'content' => '', + 'attributes' => array(), + 'format' => array(), + ); + $format_default = array( + 'open' => '[%s]', + 'close' => '[/%s]', + ); + $args = wp_parse_args( $args, $args_default ); + $args['format'] = wp_parse_args( $args['format'], $format_default ); + + // Validate + if ( ! is_string( $args['tag'] ) || empty( $args['tag'] ) ) { + return $ret; + } + + $args = (object) $args; + + $args->attributes = $this->build_attribute_string( $args->attributes ); + if ( strlen( $args->attributes ) > 0 ) { + $args->attributes = ' ' . $args->attributes; + } + + // Build output + $args->format = (object) $args->format; + $ret = sprintf( $args->format->open, $args->tag . $args->attributes ); + + // Wrap content if necessary + if ( $args->wrap || ( is_string( $args->content ) && ! empty( $args->content ) ) ) { + $ret .= $args->content . sprintf( $args->format->close, $args->tag ); + } + + return $ret; + } + + /** + * Parses string of attributes into associative array. + * + * For parsing XML/XHTML tag attributes. + * + * @param string $attrs Attribute string. Can be full tag or just attributes. + * @param array $defaults Optional. Default attributes. + * @return array Attributes as associative array. + */ + function parse_attribute_string( $attrs, $defaults = array() ) { + /** + * Builds output. + * + * Merges defaults into attributes array. + * + * @param array $attrs Attributes array. + * @return array Attributes (including defaults). + */ + $output = function( $attrs ) use ( $defaults ) { + // Validate attributes array. + if ( ! is_array( $attrs ) ) { + $attrs = []; + } + // Validate defaults. + if ( ! is_array( $defaults ) ) { + $defaults = []; + } + return array_merge( $defaults, $attrs ); + }; + + // Handle invalid or non-string attributes. + if ( ! is_string( $attrs ) || false === strpos( $attrs, '=' ) ) { + return $output( $attrs ); + } + // Clean up attribute string. + $attrs = trim( $attrs ); + // Strip tag (if necessary). + if ( '<' === $attrs[0] || '>' === $attrs[-1] ) { + $rgx = '/^(?:(?:<\w.*?)\s+)?([^\s].+?)\s*(?:\/?>)?$/i'; + $attrs = preg_replace( $rgx, '$1', $attrs ); + } + unset( $rgx ); + + // Parse attributes. + $rgx = '/\b(?\w[^\s]+?)=(?["\'])(?.*?)(?P=quote)(?:\s+|$)/i'; + preg_match_all( $rgx, $attrs, $matches, PREG_SET_ORDER ); + if ( ! empty( $matches ) ) { + $attrs = []; + foreach ( $matches as $match ) { + $attrs[ $match['attr'] ] = $match['val']; + } + } + unset( $rgx, $matches, $match ); + + // Return parsed attributes (merged with defaults). + return $output( $attrs ); + } + + /** + * Builds attribute string. + * + * Attribute string formatted for HTML/XML elements. + * + * @param array $attr Attributes to build string from. + * @return string Formatted attribute string. + */ + function build_attribute_string( $attr ) { + $ret = ''; + if ( is_object( $attr ) ) { + $attr = (array) $attr; + } + // Stop processing invalid/empty attributes. + if ( ! is_array( $attr ) || empty( $attr ) ) { + return $ret; + } + // Build attribute string. + $attr_str = array(); + foreach ( $attr as $key => $val ) { + // Skip attributes with invalid names or values. + if ( ! is_string( $key ) || ! is_scalar( $val ) ) { + continue; + } + // Format attribute output. + $attr_str[] = sprintf( + '%1$s="%2$s"', + // Remove spaces from attribute name. + esc_attr( str_replace( [ ' ', '=' ], '-', $key ) ), + esc_attr( $val ) + ); + } + + $ret = implode( ' ', $attr_str ); + return $ret; + } + + /* HTML */ + + /** + * Generate HTML element based on values + * @param $args Element arguments + * @return string Generated HTML element + */ + public function build_html_element( $args ) { + $args_default = array( + 'tag' => 'span', + 'content' => '', + 'attributes' => array(), + ); + $args = wp_parse_args( $args, $args_default ); + $args['format'] = array( + 'open' => '<%s>', + 'close' => '', + ); + // Build element + return $this->build_element( $args ); + } + + /** + * Build HTML link element + * @uses build_html_element() to build link output + * @param string $uri Link URI + * @param string $content Link content + * @param $array (optional) $attributes Additional link attributes + * @return string HTML link element + */ + function build_html_link( $uri, $content, $attributes = array() ) { + $attributes = array_merge( + array( + 'href' => $uri, + 'title' => $content, + ), + $attributes + ); + return $this->build_html_element( + array( + 'tag' => 'a', + 'wrap' => true, + 'content' => $content, + 'attributes' => $attributes, + ) + ); + } + + /** + * Generate external stylesheet element + * @param $url Stylesheet URL + * @return string Stylesheet element + */ + function build_stylesheet_element( $url ) { + $attributes = array( + 'href' => $url, + 'type' => 'text/css', + 'rel' => 'stylesheet', + ); + return $this->build_html_element( + array( + 'tag' => 'link', + 'wrap' => false, + 'attributes' => $attributes, + ) + ); + } + + /** + * Build client-side script element + * + * @param string $content Script content + * @param string $id (optional) Element ID + * @param bool $wrap_jquery (optional) Wrap commands in jQuery? (Default: Yes) + * @param bool $wait_doc_ready (optional) Wait until document is fully loaded before executing commands? (Default: No) + */ + function build_script_element( $content = '', $id = '', $wrap_jquery = true, $wait_doc_ready = false ) { + // Stop processing invalid content + if ( is_array( $content ) && ! empty( $content ) ) { + $content = implode( PHP_EOL, $content ); + } + if ( empty( $content ) || ! is_string( $content ) ) { + return ''; + } + $attributes = array( 'type' => 'text/javascript' ); + $start = array( '/* */' ); + if ( $wrap_jquery ) { + $start[] = 'if ( !!window.jQuery ) {(function($){'; + $end[] = '})(jQuery);}'; + + // Add event handler (if necessary) + if ( $wait_doc_ready ) { + $start[] = '$(document).ready(function(){'; + $end[] = '})'; + } + } + + // Reverse order of end values + $end = array_reverse( $end ); + $content = implode( '', array_merge( $start, array( $content ), $end ) ); + if ( is_string( $id ) && ! empty( $id ) ) { + $attributes['id'] = $this->add_prefix( $id ); + } + return $this->build_html_element( + array( + 'tag' => 'script', + 'content' => $content, + 'wrap' => true, + 'attributes' => $attributes, + ) + ) . PHP_EOL; + } +} diff --git a/load.php b/load.php index b358ed9..553037e 100644 --- a/load.php +++ b/load.php @@ -2,8 +2,8 @@ /* Constants */ -if ( !defined('SLB_DEV') ) { - define('SLB_DEV', ( isset( $_REQUEST['slb_dev'] ) && !!$_REQUEST['slb_dev'] ) ); +if ( ! defined( 'SLB_DEV' ) ) { + define( 'SLB_DEV', ( isset( $_REQUEST['slb_dev'] ) && ! ! $_REQUEST['slb_dev'] ) ); } /* Class Management */ @@ -12,27 +12,27 @@ * Class loading handler * @param string $classname Class to load */ -function slb_autoload($classname) { +function slb_autoload( $classname ) { $prefix = 'slb_'; - $cls = strtolower($classname); + $cls = strtolower( $classname ); // Remove prefix - if ( 0 !== strpos($cls, $prefix) ) { + if ( 0 !== strpos( $cls, $prefix ) ) { return false; } // Format class for filename - $fn = 'class.' . substr($cls, strlen($prefix)) . '.php'; + $fn = 'class.' . substr( $cls, strlen( $prefix ) ) . '.php'; // Build path - $path = dirname(__FILE__) . '/' . "includes/" . $fn; + $path = dirname( __FILE__ ) . '/includes/' . $fn; // Load file - if ( is_readable($path) ) { + if ( is_readable( $path ) ) { require $path; } } -spl_autoload_register('slb_autoload'); +spl_autoload_register( 'slb_autoload' ); /* Load Assets */ -$path = dirname(__FILE__) . '/'; +$path = dirname( __FILE__ ) . '/'; require_once $path . 'controller.php'; $GLOBALS['slb'] = new SLB_Lightbox(); -require_once $path . 'functions.php'; \ No newline at end of file +require_once $path . 'functions.php'; diff --git a/main.php b/main.php index 898f360..59a234b 100644 --- a/main.php +++ b/main.php @@ -1,48 +1,48 @@ - - * @copyright 2019 Archetyped - * - * Plugin Name: Simple Lightbox - * Plugin URI: http://archetyped.com/tools/simple-lightbox/ - * Description: The highly customizable lightbox for WordPress - * Version: 2.8.1 - * Requires at least: 5.3 - * Requires PHP: 5.6.20 - * Text Domain: simple-lightbox - * Domain Path: /l10n - * Author: Archetyped - * Author URI: http://archetyped.com - * Support URI: https://github.com/archetyped/simple-lightbox/wiki/Feedback-&-Support -*/ - -require_once dirname( __FILE__ ) . '/includes/class-requirements-check.php'; - -/* @var array Plugin Requirements */ -$slb_requirements = new SLB_Requirements_Check( - array( - 'name' => __( 'Simple Lightbox', 'simple-lightbox' ), - 'file' => __FILE__, - 'uri' => array( - 'reference' => 'https://github.com/archetyped/simple-lightbox/wiki/Requirements', - ), - ) -); - -// Check requirements before initializing plugin. -if ( $slb_requirements->passes() ) { - /** - * Initialize SLB - * - * @return void - */ - function slb_init() { - require_once dirname( __FILE__ ) . '/load.php'; - } - add_action( 'init', 'slb_init', 1 ); -} - -unset( $slb_requirements ); + + * @copyright 2022 Archetyped + * + * Plugin Name: Simple Lightbox + * Plugin URI: http://archetyped.com/tools/simple-lightbox/ + * Description: The highly customizable lightbox for WordPress + * Version: 2.9.0 + * Requires at least: 5.3 + * Requires PHP: 5.6.20 + * Text Domain: simple-lightbox + * Domain Path: /l10n + * Author: Archetyped + * Author URI: http://archetyped.com + * Support URI: https://github.com/archetyped/simple-lightbox/wiki/Feedback-&-Support +*/ + +require_once dirname( __FILE__ ) . '/includes/class-requirements-check.php'; + +/* @var array Plugin Requirements */ +$slb_requirements = new SLB_Requirements_Check( + array( + 'name' => __( 'Simple Lightbox', 'simple-lightbox' ), + 'file' => __FILE__, + 'uri' => array( + 'reference' => 'https://github.com/archetyped/simple-lightbox/wiki/Requirements', + ), + ) +); + +// Check requirements before initializing plugin. +if ( $slb_requirements->passes() ) { + /** + * Initialize SLB + * + * @return void + */ + function slb_init() { + require_once dirname( __FILE__ ) . '/load.php'; + } + add_action( 'init', 'slb_init', 1 ); +} + +unset( $slb_requirements ); diff --git a/package-lock.json b/package-lock.json index 472be9c..c100c5d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,13 +1,4949 @@ { "name": "simple-lightbox", - "version": "2.8.1", - "lockfileVersion": 1, + "version": "2.9.0", + "lockfileVersion": 2, "requires": true, + "packages": { + "": { + "version": "2.9.0", + "license": "GPLv2", + "devDependencies": { + "grunt": "^1.5.3", + "grunt-contrib-jshint": "^3.2.0", + "grunt-contrib-uglify": "^5.2.2", + "grunt-contrib-watch": "^1.1.0", + "grunt-phplint": "0.1.0", + "grunt-sass": "^3.1.0", + "jshint-stylish": "^2.2.1", + "load-grunt-tasks": "^5.1.0", + "node-sass": "^7.0.1", + "time-grunt": "^2.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/@babel/highlight/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "node_modules/@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "dependencies": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "node_modules/@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "dependencies": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@types/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "node_modules/@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "node_modules/@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", + "dev": true + }, + "node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "dev": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/are-we-there-yet/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/array-differ": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", + "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/arrify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", + "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "dev": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha512-VUeSMD8nEGBWaZK4lizI1sf3yEC7pnAQ/mrI7pC2fBz2s/tq5jWWEngTwaf0Gruu/OoXRGLGg1XFqpYBiGTYJA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "dev": true + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", + "dev": true + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "dev": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/beeper": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", + "integrity": "sha512-3vqtKL1N45I5dV0RdssXZG7X6pCqQrWPNOlBPZPrd+QkE2HEhR57Z04m0KtpbsZH73j+a3F8UD1TQnn+ExTvIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/body": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", + "integrity": "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==", + "dev": true, + "dependencies": { + "continuable-cache": "^0.3.1", + "error": "^7.0.0", + "raw-body": "~1.1.0", + "safe-json-parse": "~1.0.1" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/bytes": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", + "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", + "dev": true + }, + "node_modules/cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "dependencies": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/cache-swap": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/cache-swap/-/cache-swap-0.3.0.tgz", + "integrity": "sha512-rwePCa4iVqXHrEEmQEoLR3Kea4aCTCf7JfX+mJA4Fd61Vb738TItRRv1v++emp9wfnRUKbXpIYfRJY4ThWK09g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.1", + "object-assign": "^4.0.1", + "rimraf": "^2.4.0" + } + }, + "node_modules/cache-swap/node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/cache-swap/node_modules/rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase-keys": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "dev": true + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/cli": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", + "integrity": "sha512-41U72MB56TfUMGndAKK8vJ78eooOD4Z5NOL4xEfjc0c23s+6EYKXlXsmACBVclLP1yOfWCgEganVzddVrSNoTg==", + "dev": true, + "dependencies": { + "exit": "0.1.2", + "glob": "^7.1.1" + }, + "engines": { + "node": ">=0.2.5" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/coffee-script": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", + "integrity": "sha512-QjQ1T4BqyHv19k6XSfdhy/QLlIOhywz0ekBUCa9h71zYMJlfDTGan/Z1JXzYkZ6v8R+GhvL/p4FZPbPW8WNXlg==", + "deprecated": "CoffeeScript on NPM has moved to \"coffeescript\" (no hyphen)", + "dev": true, + "bin": { + "cake": "bin/cake", + "coffee": "bin/coffee" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true, + "bin": { + "color-support": "bin.js" + } + }, + "node_modules/colors": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", + "integrity": "sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/console-browserify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", + "integrity": "sha512-duS7VP5pvfsNLDvL1O4VOEbw37AI3A4ZUQYemvDlnpGrNu9tprR7BYWpDYwC0Xia0Zxz5ZupdiIrUp0GH1aXfg==", + "dev": true, + "dependencies": { + "date-now": "^0.1.4" + } + }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "dev": true + }, + "node_modules/continuable-cache": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", + "integrity": "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==", + "dev": true + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/date-now": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", + "integrity": "sha512-AsElvov3LoNB7tf5k37H2jYSB+ZZPMT5sG2QjJCcdlV5chIv6htBUBUui2IKRjgtKAKtCBN7Zbwa+MtwLjSeNw==", + "dev": true + }, + "node_modules/date-time": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/date-time/-/date-time-1.1.0.tgz", + "integrity": "sha512-RrxZQ06cdKe7YQ5oqIxs3GMc7W3vXscy7Ds+aZIqmxA59QnVtTiCseA4jbzVUub9xCbo9GuYVZo0OrZLYXnnmw==", + "dev": true, + "dependencies": { + "time-zone": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dateformat": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==", + "dev": true, + "dependencies": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/decamelize-keys/node_modules/map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dom-serializer": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", + "dev": true, + "dependencies": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + } + }, + "node_modules/dom-serializer/node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", + "dev": true, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domelementtype": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.1.tgz", + "integrity": "sha512-BSKB+TSpMpFI/HOxCNr1O8aMOTZ8hT3pM3GQ0w/mWRmkhEDSFJkkyzz4XQsBV44BChwGkrDfMyjVD0eA2aFV3w==", + "dev": true + }, + "node_modules/domhandler": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", + "integrity": "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ==", + "dev": true, + "dependencies": { + "domelementtype": "1" + } + }, + "node_modules/domutils": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", + "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", + "dev": true, + "dependencies": { + "dom-serializer": "0", + "domelementtype": "1" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", + "dev": true + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "dev": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/entities": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", + "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==", + "dev": true + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", + "dev": true + }, + "node_modules/error": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", + "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", + "dev": true, + "dependencies": { + "string-template": "~0.2.1" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/eventemitter2": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", + "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==", + "dev": true + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "dev": true, + "engines": [ + "node >=0.6.0" + ] + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/faye-websocket": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", + "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", + "dev": true, + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/findup-sync": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", + "integrity": "sha512-z8Nrwhi6wzxNMIbxlrTzuUW6KWuKkogZ/7OdDVq+0+kxn77KUH1nipx8iU6suqkHqc4y6n7a9A8IpmxY/pTjWg==", + "dev": true, + "dependencies": { + "glob": "~5.0.0" + }, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/findup-sync/node_modules/glob": { + "version": "5.0.15", + "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", + "dev": true, + "dependencies": { + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "2 || 3", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "dependencies": { + "for-in": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "dependencies": { + "globule": "^1.0.0" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/getobject": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.2.tgz", + "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "dependencies": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/global-prefix/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, + "node_modules/globule": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", + "dev": true, + "dependencies": { + "glob": "~7.1.1", + "lodash": "^4.17.21", + "minimatch": "~3.0.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", + "dev": true + }, + "node_modules/grunt": { + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.5.3.tgz", + "integrity": "sha512-mKwmo4X2d8/4c/BmcOETHek675uOqw0RuA/zy12jaspWqvTp4+ZeQF1W+OTpcbncnaBsfbQJ6l0l4j+Sn/GmaQ==", + "dev": true, + "dependencies": { + "dateformat": "~3.0.3", + "eventemitter2": "~0.4.13", + "exit": "~0.1.2", + "findup-sync": "~0.3.0", + "glob": "~7.1.6", + "grunt-cli": "~1.4.3", + "grunt-known-options": "~2.0.0", + "grunt-legacy-log": "~3.0.0", + "grunt-legacy-util": "~2.0.1", + "iconv-lite": "~0.4.13", + "js-yaml": "~3.14.0", + "minimatch": "~3.0.4", + "mkdirp": "~1.0.4", + "nopt": "~3.0.6", + "rimraf": "~3.0.2" + }, + "bin": { + "grunt": "bin/grunt" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/grunt-cli": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", + "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", + "dev": true, + "dependencies": { + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~4.0.1", + "v8flags": "~3.2.0" + }, + "bin": { + "grunt": "bin/grunt" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-cli/node_modules/nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", + "dev": true, + "dependencies": { + "abbrev": "1", + "osenv": "^0.1.4" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/grunt-contrib-jshint": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-3.2.0.tgz", + "integrity": "sha512-pcXWCSZWfoMSvcV4BwH21TUtLtcX0Ms8IGuOPIcLeXK3fud9KclY7iqMKY94jFx8TxZzh028YYtpR+io8DiEaQ==", + "dev": true, + "dependencies": { + "chalk": "~4.1.2", + "hooker": "^0.2.3", + "jshint": "~2.13.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-contrib-uglify": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-5.2.2.tgz", + "integrity": "sha512-ITxiWxrjjP+RZu/aJ5GLvdele+sxlznh+6fK9Qckio5ma8f7Iv8woZjRkGfafvpuygxNefOJNc+hfjjBayRn2Q==", + "dev": true, + "dependencies": { + "chalk": "^4.1.2", + "maxmin": "^3.0.0", + "uglify-js": "^3.16.1", + "uri-path": "^1.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/grunt-contrib-watch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-watch/-/grunt-contrib-watch-1.1.0.tgz", + "integrity": "sha512-yGweN+0DW5yM+oo58fRu/XIRrPcn3r4tQx+nL7eMRwjpvk+rQY6R8o94BPK0i2UhTg9FN21hS+m8vR8v9vXfeg==", + "dev": true, + "dependencies": { + "async": "^2.6.0", + "gaze": "^1.1.0", + "lodash": "^4.17.10", + "tiny-lr": "^1.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/grunt-known-options": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", + "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/grunt-legacy-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz", + "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==", + "dev": true, + "dependencies": { + "colors": "~1.1.2", + "grunt-legacy-log-utils": "~2.1.0", + "hooker": "~0.2.3", + "lodash": "~4.17.19" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/grunt-legacy-log-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz", + "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==", + "dev": true, + "dependencies": { + "chalk": "~4.1.0", + "lodash": "~4.17.19" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-legacy-util": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", + "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", + "dev": true, + "dependencies": { + "async": "~3.2.0", + "exit": "~0.1.2", + "getobject": "~1.0.0", + "hooker": "~0.2.3", + "lodash": "~4.17.21", + "underscore.string": "~3.3.5", + "which": "~2.0.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/grunt-legacy-util/node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + }, + "node_modules/grunt-phplint": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/grunt-phplint/-/grunt-phplint-0.1.0.tgz", + "integrity": "sha512-Fac/6pP1VEZhTNSN5kMc341yxyLVr7uvSChzBmAV4XOANH2MTf1eIeY7cTRER+PyY054dkdN/Eh6z2CG1nuaYw==", + "dev": true, + "dependencies": { + "cache-swap": "~0.3.0", + "grunt": "~0.4.1" + } + }, + "node_modules/grunt-phplint/node_modules/argparse": { + "version": "0.1.16", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", + "integrity": "sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw==", + "dev": true, + "dependencies": { + "underscore": "~1.7.0", + "underscore.string": "~2.4.0" + } + }, + "node_modules/grunt-phplint/node_modules/argparse/node_modules/underscore.string": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", + "integrity": "sha512-yxkabuCaIBnzfIvX3kBxQqCs0ar/bfJwDnFEHJUm/ZrRVhT3IItdRF5cZjARLzEnyQYtIUhsZ2LG2j3HidFOFQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/grunt-phplint/node_modules/async": { + "version": "0.1.22", + "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", + "integrity": "sha512-2tEzliJmf5fHNafNwQLJXUasGzQCVctvsNkXmnlELHwypU0p08/rHohYvkqKIjyXpx+0rkrYv6QbhJ+UF4QkBg==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/grunt-phplint/node_modules/colors": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", + "integrity": "sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==", + "dev": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/grunt-phplint/node_modules/dateformat": { + "version": "1.0.2-1.2.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz", + "integrity": "sha512-AXvW8g7tO4ilk5HgOWeDmPi/ZPaCnMJ+9Cg1I3p19w6mcvAAXBuuGEXAxybC+Djj1PSZUiHUcyoYu7WneCX8gQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/grunt-phplint/node_modules/esprima": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", + "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/grunt-phplint/node_modules/findup-sync": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", + "integrity": "sha512-yjftfYnF4ThYEvKEV/kEFR15dmtyXTAh3vQnzpJUoc7Naj5y1P0Ck7Zs1+Vroa00E3KT3IYsk756S+8WA5dNLw==", + "dev": true, + "dependencies": { + "glob": "~3.2.9", + "lodash": "~2.4.1" + }, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/grunt-phplint/node_modules/findup-sync/node_modules/glob": { + "version": "3.2.11", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", + "integrity": "sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g==", + "dev": true, + "dependencies": { + "inherits": "2", + "minimatch": "0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/grunt-phplint/node_modules/findup-sync/node_modules/lodash": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", + "dev": true, + "engines": [ + "node", + "rhino" + ] + }, + "node_modules/grunt-phplint/node_modules/findup-sync/node_modules/minimatch": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", + "integrity": "sha512-WFX1jI1AaxNTZVOHLBVazwTWKaQjoykSzCBNXB72vDTCzopQGtyP91tKdFK5cv1+qMwPyiTu1HqUriqplI8pcA==", + "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "dev": true, + "dependencies": { + "lru-cache": "2", + "sigmund": "~1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/grunt-phplint/node_modules/getobject": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha512-hIGEBfnHcZpWkXPsAVeVmpYDvfy/matVl03yOY91FPmnpCC12Lm5izNxCjO3lHAeO6uaTwMxu7g450Siknlhig==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/grunt-phplint/node_modules/glob": { + "version": "3.1.21", + "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", + "integrity": "sha512-ANhy2V2+tFpRajE3wN4DhkNQ08KDr0Ir1qL12/cUe5+a7STEK8jkW4onUYuY8/06qAFuT5je7mjAqzx0eKI2tQ==", + "dev": true, + "dependencies": { + "graceful-fs": "~1.2.0", + "inherits": "1", + "minimatch": "~0.2.11" + }, + "engines": { + "node": "*" + } + }, + "node_modules/grunt-phplint/node_modules/glob/node_modules/inherits": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", + "integrity": "sha512-Al67oatbRSo3RV5hRqIoln6Y5yMVbJSIn4jEJNL7VCImzq/kLr7vvb6sFRJXqr8rpHc/2kJOM+y0sPKN47VdzA==", + "dev": true + }, + "node_modules/grunt-phplint/node_modules/graceful-fs": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", + "integrity": "sha512-iiTUZ5vZ+2ZV+h71XAgwCSu6+NAizhFU3Yw8aC/hH5SQ3SnISqEqAek40imAFGtDcwJKNhXvSY+hzIolnLwcdQ==", + "deprecated": "please upgrade to graceful-fs 4 for compatibility with current and future versions of Node.js", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/grunt-phplint/node_modules/grunt": { + "version": "0.4.5", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", + "integrity": "sha512-1iq3ylLjzXqz/KSq1OAE2qhnpcbkF2WyhsQcavZt+YmgvHu0EbPMEhGhy2gr0FP67isHpRdfwjB5WVeXXcJemQ==", + "dev": true, + "dependencies": { + "async": "~0.1.22", + "coffee-script": "~1.3.3", + "colors": "~0.6.2", + "dateformat": "1.0.2-1.2.3", + "eventemitter2": "~0.4.13", + "exit": "~0.1.1", + "findup-sync": "~0.1.2", + "getobject": "~0.1.0", + "glob": "~3.1.21", + "grunt-legacy-log": "~0.1.0", + "grunt-legacy-util": "~0.2.0", + "hooker": "~0.2.3", + "iconv-lite": "~0.2.11", + "js-yaml": "~2.0.5", + "lodash": "~0.9.2", + "minimatch": "~0.2.12", + "nopt": "~1.0.10", + "rimraf": "~2.2.8", + "underscore.string": "~2.2.1", + "which": "~1.0.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/grunt-phplint/node_modules/grunt-legacy-log": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", + "integrity": "sha512-qYs/uM0ImdzwIXLhS4O5WLV5soAM+PEqqHI/hzSxlo450ERSccEhnXqoeDA9ZozOdaWuYnzTOTwRcVRogleMxg==", + "dev": true, + "dependencies": { + "colors": "~0.6.2", + "grunt-legacy-log-utils": "~0.1.1", + "hooker": "~0.2.3", + "lodash": "~2.4.1", + "underscore.string": "~2.3.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/grunt-phplint/node_modules/grunt-legacy-log-utils": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", + "integrity": "sha512-D0vbUX00TFYCKNZtcZzemMpwT8TR/FdRs1pmfiBw6qnUw80PfsjV+lhIozY/3eJ3PSG2zj89wd2mH/7f4tNAlw==", + "dev": true, + "dependencies": { + "colors": "~0.6.2", + "lodash": "~2.4.1", + "underscore.string": "~2.3.3" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/grunt-phplint/node_modules/grunt-legacy-log-utils/node_modules/lodash": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", + "dev": true, + "engines": [ + "node", + "rhino" + ] + }, + "node_modules/grunt-phplint/node_modules/grunt-legacy-log-utils/node_modules/underscore.string": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "integrity": "sha512-hbD5MibthuDAu4yA5wxes5bzFgqd3PpBJuClbRxaNddxfdsz+qf+1kHwrGQFrmchmDHb9iNU+6EHDn8uj0xDJg==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/grunt-phplint/node_modules/grunt-legacy-log/node_modules/lodash": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", + "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", + "dev": true, + "engines": [ + "node", + "rhino" + ] + }, + "node_modules/grunt-phplint/node_modules/grunt-legacy-log/node_modules/underscore.string": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "integrity": "sha512-hbD5MibthuDAu4yA5wxes5bzFgqd3PpBJuClbRxaNddxfdsz+qf+1kHwrGQFrmchmDHb9iNU+6EHDn8uj0xDJg==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/grunt-phplint/node_modules/grunt-legacy-util": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", + "integrity": "sha512-cXPbfF8aM+pvveQeN1K872D5fRm30xfJWZiS63Y8W8oyIPLClCsmI8bW96Txqzac9cyL4lRqEBhbhJ3n5EzUUQ==", + "dev": true, + "dependencies": { + "async": "~0.1.22", + "exit": "~0.1.1", + "getobject": "~0.1.0", + "hooker": "~0.2.3", + "lodash": "~0.9.2", + "underscore.string": "~2.2.1", + "which": "~1.0.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/grunt-phplint/node_modules/iconv-lite": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", + "integrity": "sha512-KhmFWgaQZY83Cbhi+ADInoUQ8Etn6BG5fikM9syeOjQltvR45h7cRKJ/9uvQEuD61I3Uju77yYce0/LhKVClQw==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/grunt-phplint/node_modules/js-yaml": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", + "integrity": "sha512-VEKcIksckDBUhg2JS874xVouiPkywVUh4yyUmLCDe1Zg3bCd6M+F1eGPenPeHLc2XC8pp9G8bsuofK0NeEqRkA==", + "dev": true, + "dependencies": { + "argparse": "~ 0.1.11", + "esprima": "~ 1.0.2" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + }, + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/grunt-phplint/node_modules/lodash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", + "integrity": "sha512-LVbt/rjK62gSbhehDVKL0vlaime4Y1IBixL+bKeNfoY4L2zab/jGrxU6Ka05tMA/zBxkTk5t3ivtphdyYupczw==", + "dev": true, + "engines": [ + "node", + "rhino" + ] + }, + "node_modules/grunt-phplint/node_modules/lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==", + "dev": true + }, + "node_modules/grunt-phplint/node_modules/minimatch": { + "version": "0.2.14", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", + "integrity": "sha512-zZ+Jy8lVWlvqqeM8iZB7w7KmQkoJn8djM585z88rywrEbzoqawVa9FR5p2hwD+y74nfuKOjmNvi9gtWJNLqHvA==", + "deprecated": "Please update to minimatch 3.0.2 or higher to avoid a RegExp DoS issue", + "dev": true, + "dependencies": { + "lru-cache": "2", + "sigmund": "~1.0.0" + }, + "engines": { + "node": "*" + } + }, + "node_modules/grunt-phplint/node_modules/nopt": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/grunt-phplint/node_modules/rimraf": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", + "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", + "dev": true, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/grunt-phplint/node_modules/underscore.string": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", + "integrity": "sha512-3FVmhXqelrj6gfgp3Bn6tOavJvW0dNH2T+heTD38JRxIrAbiuzbqjknszoOYj3DyFB1nWiLj208Qt2no/L4cIA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/grunt-phplint/node_modules/which": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", + "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==", + "dev": true, + "bin": { + "which": "bin/which" + } + }, + "node_modules/grunt-sass": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/grunt-sass/-/grunt-sass-3.1.0.tgz", + "integrity": "sha512-90s27H7FoCDcA8C8+R0GwC+ntYD3lG6S/jqcavWm3bn9RiJTmSfOvfbFa1PXx4NbBWuiGQMLfQTj/JvvqT5w6A==", + "dev": true, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "grunt": ">=1" + } + }, + "node_modules/gzip-size": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.1", + "pify": "^4.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/har-validator": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", + "dev": true, + "dependencies": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "dev": true + }, + "node_modules/homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "dependencies": { + "parse-passwd": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/hooker": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", + "integrity": "sha512-t+UerCsQviSymAInD01Pw+Dn/usmz1sRO+3Zk1+lx8eg+WKpD2ulcwWqHHL0+aseRBr+3+vIhiG1K1JTwaIcTA==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/hosted-git-info": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/htmlparser2": { + "version": "3.8.3", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", + "integrity": "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q==", + "dev": true, + "dependencies": { + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", + "dev": true + }, + "node_modules/http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "dependencies": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", + "dev": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + }, + "engines": { + "node": ">=0.8", + "npm": ">=1.3.7" + } + }, + "node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true + }, + "node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "node_modules/interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha512-CLM8SNMDu7C5psFCn6Wg/tgpj/bKAg7hc2gWqcuR9OD5Ft9PhBpIu8PLicPeis+xDd6YX2ncI8MCA64I9tftIA==", + "dev": true + }, + "node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", + "dev": true + }, + "node_modules/irregular-plurals": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.4.0.tgz", + "integrity": "sha512-kniTIJmaZYiwa17eTtWIfm0K342seyugl6vuC8DiiyiRAJWAVlLkqGCI0Im0neo0TkXw+pRcKaBPRdcKHnQJ6Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "dependencies": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "dependencies": { + "is-unc-path": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "dev": true + }, + "node_modules/is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "dependencies": { + "unc-path-regex": "^0.1.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "dev": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "dev": true + }, + "node_modules/js-base64": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", + "dev": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "dev": true + }, + "node_modules/jshint": { + "version": "2.13.5", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.13.5.tgz", + "integrity": "sha512-dB2n1w3OaQ35PLcBGIWXlszjbPZwsgZoxsg6G8PtNf2cFMC1l0fObkYLUuXqTTdi6tKw4sAjfUseTdmDMHQRcg==", + "dev": true, + "dependencies": { + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.21", + "minimatch": "~3.0.2", + "strip-json-comments": "1.0.x" + }, + "bin": { + "jshint": "bin/jshint" + } + }, + "node_modules/jshint-stylish": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/jshint-stylish/-/jshint-stylish-2.2.1.tgz", + "integrity": "sha512-7ySPIM1/gONcJ1isbd1IPKuBzQ/iDTvofILFSsIaMrWZUO7OJkV9kdU0O6O1pxM+bNj/9mbJ31LyXgQgOhIa0A==", + "dev": true, + "dependencies": { + "beeper": "^1.1.0", + "chalk": "^1.0.0", + "log-symbols": "^1.0.0", + "plur": "^2.1.0", + "string-length": "^1.0.0", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jshint-stylish/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jshint-stylish/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jshint-stylish/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jshint-stylish/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/jshint-stylish/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "dev": true + }, + "node_modules/jsprim": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", + "dev": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "dev": true, + "dependencies": { + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/liftup/node_modules/findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "dependencies": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/livereload-js": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", + "integrity": "sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==", + "dev": true + }, + "node_modules/load-grunt-tasks": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/load-grunt-tasks/-/load-grunt-tasks-5.1.0.tgz", + "integrity": "sha512-oNj0Jlka1TsfDe+9He0kcA1cRln+TMoTsEByW7ij6kyktNLxBKJtslCFEvFrLC2Dj0S19IWJh3fOCIjLby2Xrg==", + "dev": true, + "dependencies": { + "arrify": "^2.0.1", + "multimatch": "^4.0.0", + "pkg-up": "^3.1.0", + "resolve-pkg": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "peerDependencies": { + "grunt": ">=1" + } + }, + "node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true + }, + "node_modules/log-symbols": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", + "integrity": "sha512-mmPrW0Fh2fxOzdBbFv4g1m6pR72haFLPJ2G5SJEELf1y+iaQrDG6cWCPjy54RHYbZAt7X+ls690Kw62AdWXBzQ==", + "dev": true, + "dependencies": { + "chalk": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/log-symbols/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/log-symbols/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "dependencies": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/maxmin": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-3.0.0.tgz", + "integrity": "sha512-wcahMInmGtg/7c6a75fr21Ch/Ks1Tb+Jtoan5Ft4bAI0ZvJqyOw8kkM7e7p8hDSzY805vmxwHT50KcjGwKyJ0g==", + "dev": true, + "dependencies": { + "chalk": "^4.1.0", + "figures": "^3.2.0", + "gzip-size": "^5.1.1", + "pretty-bytes": "^5.3.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/meow": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", + "dev": true, + "dependencies": { + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", + "dev": true + }, + "node_modules/minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", + "dev": true, + "dependencies": { + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minimist-options/node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minipass": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", + "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "dependencies": { + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + }, + "engines": { + "node": ">=8" + }, + "optionalDependencies": { + "encoding": "^0.1.12" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/multimatch": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", + "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", + "dev": true, + "dependencies": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nan": { + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", + "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-gyp": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "dev": true, + "dependencies": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": ">= 10.12.0" + } + }, + "node_modules/node-gyp/node_modules/are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/node-gyp/node_modules/npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/node-gyp/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/node-gyp/node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/node-sass": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.1.tgz", + "integrity": "sha512-uMy+Xt29NlqKCFdFRZyXKOTqGt+QaKHexv9STj2WeLottnlqZEEWx6Bj0MXNthmFRRdM/YwyNo/8Tr46TOM0jQ==", + "dev": true, + "hasInstallScript": true, + "dependencies": { + "async-foreach": "^0.1.3", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "lodash": "^4.17.15", + "meow": "^9.0.0", + "nan": "^2.13.2", + "node-gyp": "^8.4.1", + "npmlog": "^5.0.0", + "request": "^2.88.0", + "sass-graph": "4.0.0", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "bin": { + "node-sass": "bin/node-sass" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", + "dev": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + } + }, + "node_modules/normalize-package-data": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "dev": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, + "node_modules/number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true, + "engines": { + "node": "*" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, + "dependencies": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", + "dev": true, + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "dependencies": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "dev": true, + "dependencies": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-ms": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz", + "integrity": "sha512-LpH1Cf5EYuVjkBvCDBYvkUPh+iv2bk3FHflxHkpCYT0/FZ1d3N3uJaLiHr4yGuMcFUhv6eAivitTvWZI4B/chg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", + "dev": true, + "dependencies": { + "path-root-regex": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pkg-up": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", + "integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==", + "dev": true, + "dependencies": { + "find-up": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/plur": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz", + "integrity": "sha512-WhcHk576xg9y/iv6RWOuroZgsqvCbJN+XGvAypCJwLAYs2iWDp5LUmvaCdV6JR2O0SMBf8l6p7A94AyLCFVMlQ==", + "dev": true, + "dependencies": { + "irregular-plurals": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-ms": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz", + "integrity": "sha512-H2enpsxzDhuzRl3zeSQpQMirn8dB0Z/gxW96j06tMfTviUWvX14gjKb7qd1gtkUyYhDPuoNe00K5PqNvy2oQNg==", + "dev": true, + "dependencies": { + "is-finite": "^1.0.1", + "parse-ms": "^1.0.0", + "plur": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/pretty-ms/node_modules/plur": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz", + "integrity": "sha512-qSnKBSZeDY8ApxwhfVIwKwF36KVJqb1/9nzYYq3j3vdwocULCXT8f8fQGkiw1Nk9BGfxiDagEe/pwakA+bOBqw==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", + "dev": true + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "dev": true + }, + "node_modules/punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/qs": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true, + "engines": { + "node": ">=0.6" + } + }, + "node_modules/quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/raw-body": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", + "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", + "dev": true, + "dependencies": { + "bytes": "1", + "string_decoder": "0.10" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/read-pkg": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", + "dev": true, + "dependencies": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", + "dev": true, + "dependencies": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/read-pkg-up/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg-up/node_modules/type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/read-pkg/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "node_modules/read-pkg/node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/read-pkg/node_modules/semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/read-pkg/node_modules/type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/readable-stream": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", + "dev": true, + "dependencies": { + "resolve": "^1.9.0" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", + "dev": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", + "dev": true, + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-pkg": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg/-/resolve-pkg-2.0.0.tgz", + "integrity": "sha512-+1lzwXehGCXSeryaISr6WujZzowloigEofRB+dj75y9RRa/obVcYgbHJd53tdYw8pvZj8GojXaaENws8Ktw/hQ==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safe-json-parse": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", + "integrity": "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==", + "dev": true + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "node_modules/sass-graph": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-4.0.0.tgz", + "integrity": "sha512-WSO/MfXqKH7/TS8RdkCX3lVkPFQzCgbqdGsmSKq6tlPU+GpGEsa/5aW18JqItnqh+lPtcjifqdZ/VmiILkKckQ==", + "dev": true, + "dependencies": { + "glob": "^7.0.0", + "lodash": "^4.17.11", + "scss-tokenizer": "^0.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "sassgraph": "bin/sassgraph" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/scss-tokenizer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.3.0.tgz", + "integrity": "sha512-14Zl9GcbBvOT9057ZKjpz5yPOyUWG2ojd9D5io28wHRYsOrs7U95Q+KNL87+32p8rc+LvDpbu/i9ZYjM9Q+FsQ==", + "dev": true, + "dependencies": { + "js-base64": "^2.4.3", + "source-map": "^0.7.1" + } + }, + "node_modules/semver": { + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "dev": true + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sigmund": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", + "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", + "dev": true + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", + "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "dev": true, + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "dev": true, + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/spdx-correct": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", + "dev": true, + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", + "dev": true + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", + "dev": true + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "dev": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "dependencies": { + "minipass": "^3.1.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "dev": true, + "dependencies": { + "readable-stream": "^2.0.1" + } + }, + "node_modules/stdout-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true + }, + "node_modules/stdout-stream/node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dev": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/stdout-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "node_modules/stdout-stream/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, + "node_modules/string-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", + "integrity": "sha512-MNCACnufWUf3pQ57O5WTBMkKhzYIaKEcUioO0XHrTMafrbBaNk4IyDOLHBv5xbXO0jLLdsYWeFjpjG2hVHRDtw==", + "dev": true, + "dependencies": { + "strip-ansi": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-length/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-length/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/string-template": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==", + "dev": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", + "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==", + "dev": true, + "bin": { + "strip-json-comments": "cli.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/tar": { + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", + "dev": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/time-grunt": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/time-grunt/-/time-grunt-2.0.0.tgz", + "integrity": "sha512-iQD2AeDYCAJrsPC/eUsfYZD9UT7TuBOmUIgFV5zeTQgRk6yLJKoc3aYR0gusJ0m+bG13B6qrDZ0SwPLe0/htHw==", + "deprecated": "Deprecated because Grunt is practically unmaintained. Move on to something better. This package will continue to work with Grunt v1, but it will not receive any updates.", + "dev": true, + "dependencies": { + "chalk": "^1.0.0", + "date-time": "^1.1.0", + "figures": "^1.0.0", + "hooker": "^0.2.3", + "number-is-nan": "^1.0.0", + "pretty-ms": "^2.1.0", + "text-table": "^0.2.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/time-grunt/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/time-grunt/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/time-grunt/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "dev": true, + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/time-grunt/node_modules/figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/time-grunt/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/time-grunt/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/time-zone": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-0.1.0.tgz", + "integrity": "sha512-S5CjtVIkeBTnlsaZP3gjsTb78ClBe74sEcgEoBwAVUKnTRDAGqUtLLIZHMsIyqOWjt9DGQpLMMoD8ZKIfP2ddQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tiny-lr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/tiny-lr/-/tiny-lr-1.1.1.tgz", + "integrity": "sha512-44yhA3tsaRoMOjQQ+5v5mVdqef+kH6Qze9jTpqtVufgYjYt08zyZAwNwwVBj3i1rJMnR52IxOW0LK0vBzgAkuA==", + "dev": true, + "dependencies": { + "body": "^5.1.0", + "debug": "^3.1.0", + "faye-websocket": "~0.10.0", + "livereload-js": "^2.3.0", + "object-assign": "^4.1.0", + "qs": "^6.4.0" + } + }, + "node_modules/tiny-lr/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "dev": true, + "dependencies": { + "glob": "^7.1.2" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "dev": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "node_modules/type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/uglify-js": { + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz", + "integrity": "sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg==", + "dev": true, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/underscore": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", + "integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA==", + "dev": true + }, + "node_modules/underscore.string": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz", + "integrity": "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==", + "dev": true, + "dependencies": { + "sprintf-js": "^1.1.1", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/underscore.string/node_modules/sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + }, + "node_modules/unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "dependencies": { + "unique-slug": "^2.0.0" + } + }, + "node_modules/unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", + "integrity": "sha512-8pMuAn4KacYdGMkFaoQARicp4HSw24/DHOVKWqVRJ8LhhAwPPFpdGvdL9184JVmUwe7vz7Z9n6IqI6t5n2ELdg==", + "dev": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true + }, + "node_modules/uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", + "dev": true, + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dev": true, + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "dev": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", + "dev": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + } + }, "dependencies": { + "@babel/code-frame": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz", + "integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==", + "dev": true, + "requires": { + "@babel/highlight": "^7.18.6" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz", + "integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==", + "dev": true + }, + "@babel/highlight": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz", + "integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.18.6", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "@gar/promisify": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.3.tgz", + "integrity": "sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==", + "dev": true + }, + "@npmcli/fs": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-1.1.1.tgz", + "integrity": "sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==", + "dev": true, + "requires": { + "@gar/promisify": "^1.0.1", + "semver": "^7.3.5" + } + }, + "@npmcli/move-file": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.1.2.tgz", + "integrity": "sha512-1SUf/Cg2GzGDyaf15aR9St9TWlb+XvbZXWpDx8YKs7MLzMH/BCeopv+y9vzrzgkfykCGuWOlSu3mZhj2+FQcrg==", + "dev": true, + "requires": { + "mkdirp": "^1.0.4", + "rimraf": "^3.0.2" + } + }, + "@tootallnate/once": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz", + "integrity": "sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw==", + "dev": true + }, "@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==", + "dev": true + }, + "@types/minimist": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@types/minimist/-/minimist-1.2.2.tgz", + "integrity": "sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ==", + "dev": true + }, + "@types/normalize-package-data": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.1.tgz", + "integrity": "sha512-Gj7cI7z+98M282Tqmp2K5EIsoouUEzbBJhQQzDE3jSIRk6r9gsz0oUokqIUR4u1R3dMHo0pDHM7sNOHyhulypw==", "dev": true }, "abbrev": { @@ -16,89 +4952,97 @@ "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", "dev": true }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "requires": { + "debug": "4" + } + }, + "agentkeepalive": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.2.1.tgz", + "integrity": "sha512-Zn4cw2NEqd+9fiSVWMscnjyQ1a8Yfoc5oBajLeo5w+YBHgDUcEBY2hS4YpTz6iN5f/2zQiktcuM6tS8x1p9dpA==", + "dev": true, + "requires": { + "debug": "^4.1.0", + "depd": "^1.1.2", + "humanize-ms": "^1.2.1" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dev": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, "ajv": { - "version": "6.10.2", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", - "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, "requires": { - "fast-deep-equal": "^2.0.1", + "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, - "amdefine": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", - "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", - "dev": true - }, "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true }, "ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "requires": { - "color-convert": "^1.9.0" + "color-convert": "^2.0.1" } }, "aproba": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", - "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", "dev": true }, "are-we-there-yet": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", - "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", "dev": true, "requires": { "delegates": "^1.0.0", - "readable-stream": "^2.0.6" + "readable-stream": "^3.6.0" }, "dependencies": { - "isarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", - "dev": true - }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" } }, - "safe-buffer": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", - "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", - "dev": true - }, "string_decoder": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", - "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", "dev": true, "requires": { - "safe-buffer": "~5.1.0" + "safe-buffer": "~5.2.0" } } } @@ -110,14 +5054,6 @@ "dev": true, "requires": { "sprintf-js": "~1.0.2" - }, - "dependencies": { - "sprintf-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=", - "dev": true - } } }, "array-differ": { @@ -126,10 +5062,16 @@ "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", "dev": true }, - "array-find-index": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", - "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==", + "dev": true + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", "dev": true }, "array-union": { @@ -145,9 +5087,9 @@ "dev": true }, "asn1": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", - "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, "requires": { "safer-buffer": "~2.1.0" @@ -156,49 +5098,52 @@ "assert-plus": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true }, "async": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/async/-/async-1.5.2.tgz", - "integrity": "sha1-7GphrlZIDAw8skHJVhjiCJL5Zyo=", - "dev": true + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } }, "async-foreach": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", - "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "integrity": "sha512-VUeSMD8nEGBWaZK4lizI1sf3yEC7pnAQ/mrI7pC2fBz2s/tq5jWWEngTwaf0Gruu/OoXRGLGg1XFqpYBiGTYJA==", "dev": true }, "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true }, "aws4": { - "version": "1.8.0", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.8.0.tgz", - "integrity": "sha512-ReZxvNHIOv88FlT7rxcXIIC0fPt4KZqZbOlivyWtXLt8ESx84zd3kMC6iK5jVeS2qt+g7ftS7ye4fi06X5rtRQ==", + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.11.0.tgz", + "integrity": "sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==", "dev": true }, "balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "dev": true }, "bcrypt-pbkdf": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, "requires": { "tweetnacl": "^0.14.3" @@ -207,22 +5152,13 @@ "beeper": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz", - "integrity": "sha1-5tXqjF2tABMEpwsiY4RH9pyy+Ak=", + "integrity": "sha512-3vqtKL1N45I5dV0RdssXZG7X6pCqQrWPNOlBPZPrd+QkE2HEhR57Z04m0KtpbsZH73j+a3F8UD1TQnn+ExTvIA==", "dev": true }, - "block-stream": { - "version": "0.0.9", - "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", - "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", - "dev": true, - "requires": { - "inherits": "~2.0.0" - } - }, "body": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/body/-/body-5.1.0.tgz", - "integrity": "sha1-5LoM5BCkaTYyM2dgnstOZVMSUGk=", + "integrity": "sha512-chUsBxGRtuElD6fmw1gHLpvnKdVLK302peeFa9ZqAEk8TyzZ3fygLyUEDDPTJvL9+Bor0dIwn6ePOsRM2y0zQQ==", "dev": true, "requires": { "continuable-cache": "^0.3.1", @@ -241,125 +5177,176 @@ "concat-map": "0.0.1" } }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, "bytes": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/bytes/-/bytes-1.0.0.tgz", - "integrity": "sha1-NWnt6Lo0MV+rmcPpLLBMciDeH6g=", - "dev": true + "integrity": "sha512-/x68VkHLeTl3/Ll8IvxdwzhrT+IyKc52e/oyHhA2RwqPqswSnjVbSddfPRwAsJtbilMAPSRWwAlpxdYsSWOTKQ==", + "dev": true + }, + "cacache": { + "version": "15.3.0", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz", + "integrity": "sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ==", + "dev": true, + "requires": { + "@npmcli/fs": "^1.0.0", + "@npmcli/move-file": "^1.0.1", + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "glob": "^7.1.4", + "infer-owner": "^1.0.4", + "lru-cache": "^6.0.0", + "minipass": "^3.1.1", + "minipass-collect": "^1.0.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.2", + "mkdirp": "^1.0.3", + "p-map": "^4.0.0", + "promise-inflight": "^1.0.1", + "rimraf": "^3.0.2", + "ssri": "^8.0.1", + "tar": "^6.0.2", + "unique-filename": "^1.1.1" + } }, "cache-swap": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/cache-swap/-/cache-swap-0.3.0.tgz", - "integrity": "sha1-HFQaoQilAQb2ML3Zj+HeyLoTP1E=", + "integrity": "sha512-rwePCa4iVqXHrEEmQEoLR3Kea4aCTCf7JfX+mJA4Fd61Vb738TItRRv1v++emp9wfnRUKbXpIYfRJY4ThWK09g==", "dev": true, "requires": { "graceful-fs": "^4.1.2", "mkdirp": "^0.5.1", "object-assign": "^4.0.1", "rimraf": "^2.4.0" + }, + "dependencies": { + "mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "requires": { + "minimist": "^1.2.6" + } + }, + "rimraf": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } } }, "camelcase": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", - "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "dev": true }, "camelcase-keys": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", - "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-6.2.2.tgz", + "integrity": "sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg==", "dev": true, "requires": { - "camelcase": "^2.0.0", - "map-obj": "^1.0.0" + "camelcase": "^5.3.1", + "map-obj": "^4.0.0", + "quick-lru": "^4.0.1" } }, "caseless": { "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true }, "chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", "dev": true, "requires": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "dev": true + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "dev": true + }, "cli": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cli/-/cli-1.0.1.tgz", - "integrity": "sha1-IoF1NPJL+klQw01TLUjsvGIbjBQ=", + "integrity": "sha512-41U72MB56TfUMGndAKK8vJ78eooOD4Z5NOL4xEfjc0c23s+6EYKXlXsmACBVclLP1yOfWCgEganVzddVrSNoTg==", "dev": true, "requires": { "exit": "0.1.2", "glob": "^7.1.1" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } } }, "cliui": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", - "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "code-point-at": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", - "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", - "dev": true - }, - "coffeescript": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-1.10.0.tgz", - "integrity": "sha1-56qDAZF+9iGzXYo580jc3R234z4=", + "coffee-script": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", + "integrity": "sha512-QjQ1T4BqyHv19k6XSfdhy/QLlIOhywz0ekBUCa9h71zYMJlfDTGan/Z1JXzYkZ6v8R+GhvL/p4FZPbPW8WNXlg==", "dev": true }, "color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "requires": { - "color-name": "1.1.3" + "color-name": "~1.1.4" } }, "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "color-support": { "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", "dev": true }, "colors": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/colors/-/colors-1.1.2.tgz", - "integrity": "sha1-FopHAXVran9RoSzgyXv6KMCE7WM=", + "integrity": "sha512-ENwblkFQpqqia6b++zLD/KUWafYlVY/UNnAp7oz7LY7E924wmpye416wBOmvv/HMWzl8gL1kJlfvId/1Dg176w==", "dev": true }, "combined-stream": { @@ -371,22 +5358,16 @@ "delayed-stream": "~1.0.0" } }, - "commander": { - "version": "2.20.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz", - "integrity": "sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==", - "dev": true - }, "concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "dev": true }, "console-browserify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz", - "integrity": "sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA=", + "integrity": "sha512-duS7VP5pvfsNLDvL1O4VOEbw37AI3A4ZUQYemvDlnpGrNu9tprR7BYWpDYwC0Xia0Zxz5ZupdiIrUp0GH1aXfg==", "dev": true, "requires": { "date-now": "^0.1.4" @@ -395,56 +5376,36 @@ "console-control-strings": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", "dev": true }, "continuable-cache": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/continuable-cache/-/continuable-cache-0.3.1.tgz", - "integrity": "sha1-vXJ6f67XfnH/OYWskzUakSczrQ8=", + "integrity": "sha512-TF30kpKhTH8AGCG3dut0rdd/19B7Z+qCnrMoBLpyQu/2drZdNrrpcjPEoJeSVsQM+8KmWG5O56oPDjSSUsuTyA==", "dev": true }, "core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "dev": true }, "cross-spawn": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", - "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", - "dev": true, - "requires": { - "lru-cache": "^4.0.1", - "which": "^1.2.9" - }, - "dependencies": { - "lru-cache": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", - "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", - "dev": true, - "requires": { - "pseudomap": "^1.0.2", - "yallist": "^2.1.2" - } - } - } - }, - "currently-unhandled": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", - "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", "dev": true, "requires": { - "array-find-index": "^1.0.1" + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" } }, "dashdash": { "version": "1.14.1", "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "requires": { "assert-plus": "^1.0.0" @@ -453,59 +5414,85 @@ "date-now": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz", - "integrity": "sha1-6vQ5/U1ISK105cx9vvIAZyueNFs=", + "integrity": "sha512-AsElvov3LoNB7tf5k37H2jYSB+ZZPMT5sG2QjJCcdlV5chIv6htBUBUui2IKRjgtKAKtCBN7Zbwa+MtwLjSeNw==", "dev": true }, "date-time": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/date-time/-/date-time-1.1.0.tgz", - "integrity": "sha1-GIdtC9pMGf5w3Tv0sDTygbEqQLY=", + "integrity": "sha512-RrxZQ06cdKe7YQ5oqIxs3GMc7W3vXscy7Ds+aZIqmxA59QnVtTiCseA4jbzVUub9xCbo9GuYVZo0OrZLYXnnmw==", "dev": true, "requires": { "time-zone": "^0.1.0" } }, "dateformat": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.12.tgz", - "integrity": "sha1-nxJLZ1lMk3/3BpMuSmQsyo27/uk=", - "dev": true, - "requires": { - "get-stdin": "^4.0.1", - "meow": "^3.3.0" - } + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-3.0.3.tgz", + "integrity": "sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==", + "dev": true }, "debug": { - "version": "3.2.6", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz", - "integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==", + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", "dev": true, "requires": { - "ms": "^2.1.1" + "ms": "2.1.2" } }, "decamelize": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "dev": true }, + "decamelize-keys": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/decamelize-keys/-/decamelize-keys-1.1.0.tgz", + "integrity": "sha512-ocLWuYzRPoS9bfiSdDd3cxvrzovVMZnRDVEzAs+hWIVXGDbHxWMECij2OBuyB/An0FFW/nLuq6Kv1i/YC5Qfzg==", + "dev": true, + "requires": { + "decamelize": "^1.1.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha512-7N/q3lyZ+LVCp7PzuxrJr4KMbBE2hW7BT7YNia330OFxIf4d3r5zVpicP2650l7CPN6RM9zOJRl3NGpqSiw3Eg==", + "dev": true + } + } + }, "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true }, "delegates": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "dev": true + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "dev": true + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==", "dev": true }, "dom-serializer": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.1.tgz", - "integrity": "sha512-sK3ujri04WyjwQXVoK4PU3y8ula1stq10GJZpqHIUgoGZdsGzAGu65BnU3d08aTVSvO7mGPZUc0wTEDL+qGE0Q==", + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.2.2.tgz", + "integrity": "sha512-2/xPb3ORsQ42nHYiSunXkDjPLBaEj/xTwUO4B7XCZQTRk7EBtTOPaygh10YAAh2OI1Qrp6NWfpAhzswj0ydt9g==", "dev": true, "requires": { "domelementtype": "^2.0.1", @@ -513,15 +5500,15 @@ }, "dependencies": { "domelementtype": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.0.1.tgz", - "integrity": "sha512-5HOHUDsYZWV8FGWN0Njbr/Rn7f/eWSQi1v7+HsUVwXgn8nWWlL64zKDkS0n8ZmQ3mlWOMuXOnR+7Nx/5tMO5AQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", "dev": true }, "entities": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz", - "integrity": "sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw==", + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-2.2.0.tgz", + "integrity": "sha512-p92if5Nz619I0w+akJrLZH0MX0Pb5DX39XOwQTtXSdQQOaYH03S1uIQp4mhOZtAXrxq4ViO67YTiLBo2638o9A==", "dev": true } } @@ -535,7 +5522,7 @@ "domhandler": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz", - "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=", + "integrity": "sha512-q9bUwjfp7Eif8jWxxxPSykdRZAb6GkguBGSgvvCrhI9wB71W2K/Kvv4E61CF/mcCfnVJDeDWx/Vb/uAqbDj6UQ==", "dev": true, "requires": { "domelementtype": "1" @@ -544,7 +5531,7 @@ "domutils": { "version": "1.5.1", "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz", - "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=", + "integrity": "sha512-gSu5Oi/I+3wDENBsOWBiRK1eoGxcywYSqg3rR960/+EfY0CF4EX1VPkgHOZ3WiS/Jg2DtliF6BhWcHlfpYUcGw==", "dev": true, "requires": { "dom-serializer": "0", @@ -552,35 +5539,74 @@ } }, "duplexer": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz", - "integrity": "sha1-rOb/gIwc5mtX0ev5eXessCM0z8E=", + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", "dev": true }, "ecc-jsbn": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "requires": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" } }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "dev": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, "entities": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz", - "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY=", + "integrity": "sha512-LbLqfXgJMmy81t+7c14mnulFHJ170cM6E+0vMXR9k/ZiZwgX8i5pNgjTCX3SO4VeUsFLV+8InixoretwU+MjBQ==", + "dev": true + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "dev": true + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", "dev": true }, "error": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/error/-/error-7.0.2.tgz", - "integrity": "sha1-pfdf/02ZJhJt2sDqXcOOaJFTywI=", + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/error/-/error-7.2.1.tgz", + "integrity": "sha512-fo9HBvWnx3NGUKMvMwB/CBCMMrfEJgbDTVDEkPygA3Bdd3lM1OyCd+rbQ8BwnpF6GdVeOLDNmyL4N5Bg80ZvdA==", "dev": true, "requires": { - "string-template": "~0.2.1", - "xtend": "~4.0.0" + "string-template": "~0.2.1" } }, "error-ex": { @@ -592,10 +5618,16 @@ "is-arrayish": "^0.2.1" } }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, "escape-string-regexp": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", "dev": true }, "esprima": { @@ -607,15 +5639,24 @@ "eventemitter2": { "version": "0.4.14", "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-0.4.14.tgz", - "integrity": "sha1-j2G3XN4BKy6esoTUVFWDtWQ7Yas=", + "integrity": "sha512-K7J4xq5xAD5jHsGM5ReWXRTFa3JRGofHiMcVgQ8PRwgWxzjHpMWCIzsmyf60+mh8KLsqYPcjUMa0AC4hd6lPyQ==", "dev": true }, "exit": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha1-BjJjj42HfMghB9MKD/8aF8uhzQw=", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, "extend": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", @@ -625,54 +5666,61 @@ "extsprintf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true }, "fast-deep-equal": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", - "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, "fast-json-stable-stringify": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", - "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "dev": true }, "faye-websocket": { "version": "0.10.0", "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.10.0.tgz", - "integrity": "sha1-TkkvjQTftviQA1B/btvy1QHnxvQ=", + "integrity": "sha512-Xhj93RXbMSq8urNCUq4p9l0P6hnySJ/7YNRhYNug0bLOuii7pKO7xQFb5mx9xZXWCar88pLPb805PvUkwrLZpQ==", "dev": true, "requires": { "websocket-driver": ">=0.5.1" } }, "figures": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", - "integrity": "sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", "dev": true, "requires": { - "escape-string-regexp": "^1.0.5", - "object-assign": "^4.1.0" + "escape-string-regexp": "^1.0.5" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" } }, "find-up": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", - "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "dev": true, "requires": { - "path-exists": "^2.0.0", - "pinkie-promise": "^2.0.0" + "locate-path": "^3.0.0" } }, "findup-sync": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.3.0.tgz", - "integrity": "sha1-N5MKpdgWt3fANEXhlmzGeQpMCxY=", + "integrity": "sha512-z8Nrwhi6wzxNMIbxlrTzuUW6KWuKkogZ/7OdDVq+0+kxn77KUH1nipx8iU6suqkHqc4y6n7a9A8IpmxY/pTjWg==", "dev": true, "requires": { "glob": "~5.0.0" @@ -681,7 +5729,7 @@ "glob": { "version": "5.0.15", "resolved": "https://registry.npmjs.org/glob/-/glob-5.0.15.tgz", - "integrity": "sha1-G8k2ueAvSmA/zCIuz3Yz0wuLk7E=", + "integrity": "sha512-c9IPMazfRITpmAAKi22dK1VKxGDX9ehhqfABDriL/lzO92xcUKEJPQHrVA/2YHSNFB4iFlykVmWvwo48nr3OxA==", "dev": true, "requires": { "inflight": "^1.0.4", @@ -693,10 +5741,44 @@ } } }, + "fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, "forever-agent": { "version": "0.6.1", "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true }, "form-data": { @@ -710,38 +5792,42 @@ "mime-types": "^2.1.12" } }, + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, "fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "fstream": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", - "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "inherits": "~2.0.0", - "mkdirp": ">=0.5 0", - "rimraf": "2" - } + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true }, "gauge": { - "version": "2.7.4", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", - "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", "dev": true, "requires": { - "aproba": "^1.0.3", + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.0", - "object-assign": "^4.1.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", "signal-exit": "^3.0.0", - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wide-align": "^1.1.0" + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" } }, "gaze": { @@ -754,144 +5840,166 @@ } }, "get-caller-file": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", - "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "dev": true }, "get-stdin": { "version": "4.0.1", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", - "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "integrity": "sha512-F5aQMywwJ2n85s4hJPTT9RPxGmubonuB10MNYo17/xph174n2MIR33HRguhzVag10O/npM7SPk73LMZNP+FaWw==", "dev": true }, "getobject": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", - "integrity": "sha1-BHpEl4n6Fg0Bj1SG7ZEyC27HiFw=", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-1.0.2.tgz", + "integrity": "sha512-2zblDBaFcb3rB4rF77XVnuINOE2h2k/OnqXAiy0IrTxUfV1iFp3la33oAQVY9pCpWU268WFYVt2t71hlMuLsOg==", "dev": true }, "getpass": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "requires": { "assert-plus": "^1.0.0" } }, "glob": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz", - "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=", + "version": "7.1.7", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", + "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", "dev": true, "requires": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", "inherits": "2", - "minimatch": "^3.0.2", + "minimatch": "^3.0.4", "once": "^1.3.0", "path-is-absolute": "^1.0.0" } }, - "globule": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/globule/-/globule-1.2.1.tgz", - "integrity": "sha512-g7QtgWF4uYSL5/dn71WxubOrS7JVGCnFPEnoeChJmBnyR9Mw8nGoEwOgJL/RC2Te0WhbsEUCejfH8SZNJ+adYQ==", + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", "dev": true, "requires": { - "glob": "~7.1.1", - "lodash": "~4.17.10", - "minimatch": "~3.0.2" + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" }, "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "isexe": "^2.0.0" } } } }, + "globule": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.4.tgz", + "integrity": "sha512-OPTIfhMBh7JbBYDpa5b+Q5ptmMWKwcNcFSR/0c6t8V4f3ZAVBEsKNY37QdVqmLRYSMhOUGYrY0QhSoEpzGr/Eg==", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "^4.17.21", + "minimatch": "~3.0.2" + } + }, "graceful-fs": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.0.tgz", - "integrity": "sha512-jpSvDPV4Cq/bgtpndIWbI5hmYxhQGHPC4d4cqBPb4DLniCfhJokdXhwhaDuLBGLQdvvRum/UiX6ECVIPvDXqdg==", + "version": "4.2.10", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.10.tgz", + "integrity": "sha512-9ByhssR2fPVsNZj478qUUbKfmL0+t5BDVyjShtyZZLiK7ZDAArFFfopyOTj0M05wE2tJPisA4iTnnXl2YoPvOA==", "dev": true }, "grunt": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.0.4.tgz", - "integrity": "sha512-PYsMOrOC+MsdGEkFVwMaMyc6Ob7pKmq+deg1Sjr+vvMWp35sztfwKE7qoN51V+UEtHsyNuMcGdgMLFkBHvMxHQ==", + "version": "1.5.3", + "resolved": "https://registry.npmjs.org/grunt/-/grunt-1.5.3.tgz", + "integrity": "sha512-mKwmo4X2d8/4c/BmcOETHek675uOqw0RuA/zy12jaspWqvTp4+ZeQF1W+OTpcbncnaBsfbQJ6l0l4j+Sn/GmaQ==", "dev": true, "requires": { - "coffeescript": "~1.10.0", - "dateformat": "~1.0.12", + "dateformat": "~3.0.3", "eventemitter2": "~0.4.13", - "exit": "~0.1.1", + "exit": "~0.1.2", "findup-sync": "~0.3.0", - "glob": "~7.0.0", - "grunt-cli": "~1.2.0", - "grunt-known-options": "~1.1.0", - "grunt-legacy-log": "~2.0.0", - "grunt-legacy-util": "~1.1.1", + "glob": "~7.1.6", + "grunt-cli": "~1.4.3", + "grunt-known-options": "~2.0.0", + "grunt-legacy-log": "~3.0.0", + "grunt-legacy-util": "~2.0.1", "iconv-lite": "~0.4.13", - "js-yaml": "~3.13.0", - "minimatch": "~3.0.2", - "mkdirp": "~0.5.1", + "js-yaml": "~3.14.0", + "minimatch": "~3.0.4", + "mkdirp": "~1.0.4", "nopt": "~3.0.6", - "path-is-absolute": "~1.0.0", - "rimraf": "~2.6.2" + "rimraf": "~3.0.2" + } + }, + "grunt-cli": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.4.3.tgz", + "integrity": "sha512-9Dtx/AhVeB4LYzsViCjUQkd0Kw0McN2gYpdmGYKtE2a5Yt7v1Q+HYZVWhqXc/kGnxlMtqKDxSwotiGeFmkrCoQ==", + "dev": true, + "requires": { + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~4.0.1", + "v8flags": "~3.2.0" }, "dependencies": { - "grunt-cli": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/grunt-cli/-/grunt-cli-1.2.0.tgz", - "integrity": "sha1-VisRnrsGndtGSs4oRVAb6Xs1tqg=", + "nopt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz", + "integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==", "dev": true, "requires": { - "findup-sync": "~0.3.0", - "grunt-known-options": "~1.1.0", - "nopt": "~3.0.6", - "resolve": "~1.1.0" + "abbrev": "1", + "osenv": "^0.1.4" } - }, - "resolve": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.1.7.tgz", - "integrity": "sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=", - "dev": true } } }, "grunt-contrib-jshint": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-2.1.0.tgz", - "integrity": "sha512-65S2/C/6RfjY/umTxfwXXn+wVvaYmykHkHSsW6Q6rhkbv3oudTEgqnFFZvWzWCoHUb+3GMZLbP3oSrNyvshmIQ==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/grunt-contrib-jshint/-/grunt-contrib-jshint-3.2.0.tgz", + "integrity": "sha512-pcXWCSZWfoMSvcV4BwH21TUtLtcX0Ms8IGuOPIcLeXK3fud9KclY7iqMKY94jFx8TxZzh028YYtpR+io8DiEaQ==", "dev": true, "requires": { - "chalk": "^2.4.2", + "chalk": "~4.1.2", "hooker": "^0.2.3", - "jshint": "~2.10.2" + "jshint": "~2.13.4" } }, "grunt-contrib-uglify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-4.0.1.tgz", - "integrity": "sha512-dwf8/+4uW1+7pH72WButOEnzErPGmtUvc8p08B0eQS/6ON0WdeQu0+WFeafaPTbbY1GqtS25lsHWaDeiTQNWPg==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/grunt-contrib-uglify/-/grunt-contrib-uglify-5.2.2.tgz", + "integrity": "sha512-ITxiWxrjjP+RZu/aJ5GLvdele+sxlznh+6fK9Qckio5ma8f7Iv8woZjRkGfafvpuygxNefOJNc+hfjjBayRn2Q==", "dev": true, "requires": { - "chalk": "^2.4.1", - "maxmin": "^2.1.0", - "uglify-js": "^3.5.0", + "chalk": "^4.1.2", + "maxmin": "^3.0.0", + "uglify-js": "^3.16.1", "uri-path": "^1.0.0" } }, @@ -905,66 +6013,63 @@ "gaze": "^1.1.0", "lodash": "^4.17.10", "tiny-lr": "^1.1.1" - }, - "dependencies": { - "async": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.3.tgz", - "integrity": "sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg==", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } - } } }, "grunt-known-options": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-1.1.1.tgz", - "integrity": "sha512-cHwsLqoighpu7TuYj5RonnEuxGVFnztcUqTqp5rXFGYL4OuPFofwC4Ycg7n9fYwvK6F5WbYgeVOwph9Crs2fsQ==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/grunt-known-options/-/grunt-known-options-2.0.0.tgz", + "integrity": "sha512-GD7cTz0I4SAede1/+pAbmJRG44zFLPipVtdL9o3vqx9IEyb7b4/Y3s7r6ofI3CchR5GvYJ+8buCSioDv5dQLiA==", "dev": true }, "grunt-legacy-log": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-2.0.0.tgz", - "integrity": "sha512-1m3+5QvDYfR1ltr8hjiaiNjddxGdQWcH0rw1iKKiQnF0+xtgTazirSTGu68RchPyh1OBng1bBUjLmX8q9NpoCw==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-3.0.0.tgz", + "integrity": "sha512-GHZQzZmhyq0u3hr7aHW4qUH0xDzwp2YXldLPZTCjlOeGscAOWWPftZG3XioW8MasGp+OBRIu39LFx14SLjXRcA==", "dev": true, "requires": { "colors": "~1.1.2", - "grunt-legacy-log-utils": "~2.0.0", + "grunt-legacy-log-utils": "~2.1.0", "hooker": "~0.2.3", - "lodash": "~4.17.5" + "lodash": "~4.17.19" } }, "grunt-legacy-log-utils": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.0.1.tgz", - "integrity": "sha512-o7uHyO/J+i2tXG8r2bZNlVk20vlIFJ9IEYyHMCQGfWYru8Jv3wTqKZzvV30YW9rWEjq0eP3cflQ1qWojIe9VFA==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-2.1.0.tgz", + "integrity": "sha512-lwquaPXJtKQk0rUM1IQAop5noEpwFqOXasVoedLeNzaibf/OPWjKYvvdqnEHNmU+0T0CaReAXIbGo747ZD+Aaw==", "dev": true, "requires": { - "chalk": "~2.4.1", - "lodash": "~4.17.10" + "chalk": "~4.1.0", + "lodash": "~4.17.19" } }, "grunt-legacy-util": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-1.1.1.tgz", - "integrity": "sha512-9zyA29w/fBe6BIfjGENndwoe1Uy31BIXxTH3s8mga0Z5Bz2Sp4UCjkeyv2tI449ymkx3x26B+46FV4fXEddl5A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-2.0.1.tgz", + "integrity": "sha512-2bQiD4fzXqX8rhNdXkAywCadeqiPiay0oQny77wA2F3WF4grPJXCvAcyoWUJV+po/b15glGkxuSiQCK299UC2w==", "dev": true, "requires": { - "async": "~1.5.2", - "exit": "~0.1.1", - "getobject": "~0.1.0", + "async": "~3.2.0", + "exit": "~0.1.2", + "getobject": "~1.0.0", "hooker": "~0.2.3", - "lodash": "~4.17.10", - "underscore.string": "~3.3.4", - "which": "~1.3.0" + "lodash": "~4.17.21", + "underscore.string": "~3.3.5", + "which": "~2.0.2" + }, + "dependencies": { + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "dev": true + } } }, "grunt-phplint": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/grunt-phplint/-/grunt-phplint-0.1.0.tgz", - "integrity": "sha1-bb4uauxTqiKc+sCtmnyZ4kGEhI0=", + "integrity": "sha512-Fac/6pP1VEZhTNSN5kMc341yxyLVr7uvSChzBmAV4XOANH2MTf1eIeY7cTRER+PyY054dkdN/Eh6z2CG1nuaYw==", "dev": true, "requires": { "cache-swap": "~0.3.0", @@ -974,7 +6079,7 @@ "argparse": { "version": "0.1.16", "resolved": "https://registry.npmjs.org/argparse/-/argparse-0.1.16.tgz", - "integrity": "sha1-z9AeD7uj1srtBJ+9dY1A9lGW9Xw=", + "integrity": "sha512-LjmC2dNpdn2L4UzyoaIr11ELYoLn37ZFy9zObrQFHsSuOepeUEMKnM8w5KL4Tnrp2gy88rRuQt6Ky8Bjml+Baw==", "dev": true, "requires": { "underscore": "~1.7.0", @@ -984,7 +6089,7 @@ "underscore.string": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.4.0.tgz", - "integrity": "sha1-jN2PusTi0uoefi6Al8QvRCKA+Fs=", + "integrity": "sha512-yxkabuCaIBnzfIvX3kBxQqCs0ar/bfJwDnFEHJUm/ZrRVhT3IItdRF5cZjARLzEnyQYtIUhsZ2LG2j3HidFOFQ==", "dev": true } } @@ -992,37 +6097,31 @@ "async": { "version": "0.1.22", "resolved": "https://registry.npmjs.org/async/-/async-0.1.22.tgz", - "integrity": "sha1-D8GqoIig4+8Ovi2IMbqw3PiEUGE=", - "dev": true - }, - "coffee-script": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/coffee-script/-/coffee-script-1.3.3.tgz", - "integrity": "sha1-FQ1rTLUiiUNp7+1qIQHCC8f0pPQ=", + "integrity": "sha512-2tEzliJmf5fHNafNwQLJXUasGzQCVctvsNkXmnlELHwypU0p08/rHohYvkqKIjyXpx+0rkrYv6QbhJ+UF4QkBg==", "dev": true }, "colors": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/colors/-/colors-0.6.2.tgz", - "integrity": "sha1-JCP+ZnisDF2uiFLl0OW+CMmXq8w=", + "integrity": "sha512-OsSVtHK8Ir8r3+Fxw/b4jS1ZLPXkV6ZxDRJQzeD7qo0SqMXWrHDM71DgYzPMHY8SFJ0Ao+nNU2p1MmwdzKqPrw==", "dev": true }, "dateformat": { "version": "1.0.2-1.2.3", "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-1.0.2-1.2.3.tgz", - "integrity": "sha1-sCIMAt6YYXQztyhRz0fePfLNvuk=", + "integrity": "sha512-AXvW8g7tO4ilk5HgOWeDmPi/ZPaCnMJ+9Cg1I3p19w6mcvAAXBuuGEXAxybC+Djj1PSZUiHUcyoYu7WneCX8gQ==", "dev": true }, "esprima": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/esprima/-/esprima-1.0.4.tgz", - "integrity": "sha1-n1V+CPw7TSbs6d00+Pv0drYlha0=", + "integrity": "sha512-rp5dMKN8zEs9dfi9g0X1ClLmV//WRyk/R15mppFNICIFRG5P92VP7Z04p8pk++gABo9W2tY+kHyu6P1mEHgmTA==", "dev": true }, "findup-sync": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-0.1.3.tgz", - "integrity": "sha1-fz56l7gjksZTvwZYm9hRkOk8NoM=", + "integrity": "sha512-yjftfYnF4ThYEvKEV/kEFR15dmtyXTAh3vQnzpJUoc7Naj5y1P0Ck7Zs1+Vroa00E3KT3IYsk756S+8WA5dNLw==", "dev": true, "requires": { "glob": "~3.2.9", @@ -1032,7 +6131,7 @@ "glob": { "version": "3.2.11", "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.11.tgz", - "integrity": "sha1-Spc/Y1uRkPcV0QmH1cAP0oFevj0=", + "integrity": "sha512-hVb0zwEZwC1FXSKRPFTeOtN7AArJcJlI6ULGLtrstaswKNlrTJqAA+1lYlSUop4vjA423xlBzqfVS3iWGlqJ+g==", "dev": true, "requires": { "inherits": "2", @@ -1042,13 +6141,13 @@ "lodash": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", "dev": true }, "minimatch": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.3.0.tgz", - "integrity": "sha1-J12O2qxPG7MyZHIInnlJyDlGmd0=", + "integrity": "sha512-WFX1jI1AaxNTZVOHLBVazwTWKaQjoykSzCBNXB72vDTCzopQGtyP91tKdFK5cv1+qMwPyiTu1HqUriqplI8pcA==", "dev": true, "requires": { "lru-cache": "2", @@ -1057,10 +6156,16 @@ } } }, + "getobject": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/getobject/-/getobject-0.1.0.tgz", + "integrity": "sha512-hIGEBfnHcZpWkXPsAVeVmpYDvfy/matVl03yOY91FPmnpCC12Lm5izNxCjO3lHAeO6uaTwMxu7g450Siknlhig==", + "dev": true + }, "glob": { "version": "3.1.21", "resolved": "https://registry.npmjs.org/glob/-/glob-3.1.21.tgz", - "integrity": "sha1-0p4KBV3qUTj00H7UDomC6DwgZs0=", + "integrity": "sha512-ANhy2V2+tFpRajE3wN4DhkNQ08KDr0Ir1qL12/cUe5+a7STEK8jkW4onUYuY8/06qAFuT5je7mjAqzx0eKI2tQ==", "dev": true, "requires": { "graceful-fs": "~1.2.0", @@ -1071,7 +6176,7 @@ "inherits": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/inherits/-/inherits-1.0.2.tgz", - "integrity": "sha1-ykMJ2t7mtUzAuNJH6NfHoJdb3Js=", + "integrity": "sha512-Al67oatbRSo3RV5hRqIoln6Y5yMVbJSIn4jEJNL7VCImzq/kLr7vvb6sFRJXqr8rpHc/2kJOM+y0sPKN47VdzA==", "dev": true } } @@ -1079,13 +6184,13 @@ "graceful-fs": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-1.2.3.tgz", - "integrity": "sha1-FaSAaldUfLLS2/J/QuiajDRRs2Q=", + "integrity": "sha512-iiTUZ5vZ+2ZV+h71XAgwCSu6+NAizhFU3Yw8aC/hH5SQ3SnISqEqAek40imAFGtDcwJKNhXvSY+hzIolnLwcdQ==", "dev": true }, "grunt": { "version": "0.4.5", "resolved": "https://registry.npmjs.org/grunt/-/grunt-0.4.5.tgz", - "integrity": "sha1-VpN81RlDJK3/bSB2MYMqnWuk5/A=", + "integrity": "sha512-1iq3ylLjzXqz/KSq1OAE2qhnpcbkF2WyhsQcavZt+YmgvHu0EbPMEhGhy2gr0FP67isHpRdfwjB5WVeXXcJemQ==", "dev": true, "requires": { "async": "~0.1.22", @@ -1113,7 +6218,7 @@ "grunt-legacy-log": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/grunt-legacy-log/-/grunt-legacy-log-0.1.3.tgz", - "integrity": "sha1-7ClCboAwIa9ZAp+H0vnNczWgVTE=", + "integrity": "sha512-qYs/uM0ImdzwIXLhS4O5WLV5soAM+PEqqHI/hzSxlo450ERSccEhnXqoeDA9ZozOdaWuYnzTOTwRcVRogleMxg==", "dev": true, "requires": { "colors": "~0.6.2", @@ -1126,13 +6231,13 @@ "lodash": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", "dev": true }, "underscore.string": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", + "integrity": "sha512-hbD5MibthuDAu4yA5wxes5bzFgqd3PpBJuClbRxaNddxfdsz+qf+1kHwrGQFrmchmDHb9iNU+6EHDn8uj0xDJg==", "dev": true } } @@ -1140,7 +6245,7 @@ "grunt-legacy-log-utils": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/grunt-legacy-log-utils/-/grunt-legacy-log-utils-0.1.1.tgz", - "integrity": "sha1-wHBrndkGThFvNvI/5OawSGcsD34=", + "integrity": "sha512-D0vbUX00TFYCKNZtcZzemMpwT8TR/FdRs1pmfiBw6qnUw80PfsjV+lhIozY/3eJ3PSG2zj89wd2mH/7f4tNAlw==", "dev": true, "requires": { "colors": "~0.6.2", @@ -1151,13 +6256,13 @@ "lodash": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/lodash/-/lodash-2.4.2.tgz", - "integrity": "sha1-+t2DS5aDBz2hebPq5tnA0VBT9z4=", + "integrity": "sha512-Kak1hi6/hYHGVPmdyiZijoQyz5x2iGVzs6w9GYB/HiXEtylY7tIoYEROMjvM1d9nXJqPOrG2MNPMn01bJ+S0Rw==", "dev": true }, "underscore.string": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", - "integrity": "sha1-ccCL9rQosRM/N+ePo6Icgvcymw0=", + "integrity": "sha512-hbD5MibthuDAu4yA5wxes5bzFgqd3PpBJuClbRxaNddxfdsz+qf+1kHwrGQFrmchmDHb9iNU+6EHDn8uj0xDJg==", "dev": true } } @@ -1165,7 +6270,7 @@ "grunt-legacy-util": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/grunt-legacy-util/-/grunt-legacy-util-0.2.0.tgz", - "integrity": "sha1-kzJIhNv343qf98Am3/RR2UqeVUs=", + "integrity": "sha512-cXPbfF8aM+pvveQeN1K872D5fRm30xfJWZiS63Y8W8oyIPLClCsmI8bW96Txqzac9cyL4lRqEBhbhJ3n5EzUUQ==", "dev": true, "requires": { "async": "~0.1.22", @@ -1180,13 +6285,13 @@ "iconv-lite": { "version": "0.2.11", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.2.11.tgz", - "integrity": "sha1-HOYKOleGSiktEyH/RgnKS7llrcg=", + "integrity": "sha512-KhmFWgaQZY83Cbhi+ADInoUQ8Etn6BG5fikM9syeOjQltvR45h7cRKJ/9uvQEuD61I3Uju77yYce0/LhKVClQw==", "dev": true }, "js-yaml": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-2.0.5.tgz", - "integrity": "sha1-olrmUJmZ6X3yeMZxnaEb0Gh3Q6g=", + "integrity": "sha512-VEKcIksckDBUhg2JS874xVouiPkywVUh4yyUmLCDe1Zg3bCd6M+F1eGPenPeHLc2XC8pp9G8bsuofK0NeEqRkA==", "dev": true, "requires": { "argparse": "~ 0.1.11", @@ -1196,13 +6301,19 @@ "lodash": { "version": "0.9.2", "resolved": "https://registry.npmjs.org/lodash/-/lodash-0.9.2.tgz", - "integrity": "sha1-jzSZxSRdNG1oLlsNO0B2fgnxqSw=", + "integrity": "sha512-LVbt/rjK62gSbhehDVKL0vlaime4Y1IBixL+bKeNfoY4L2zab/jGrxU6Ka05tMA/zBxkTk5t3ivtphdyYupczw==", + "dev": true + }, + "lru-cache": { + "version": "2.7.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", + "integrity": "sha512-WpibWJ60c3AgAz8a2iYErDrcT2C7OmKnsWhIcHOjkUHFjkXncJhtLxNSqUmxRxRunpb5I8Vprd7aNSd2NtksJQ==", "dev": true }, "minimatch": { "version": "0.2.14", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", - "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", + "integrity": "sha512-zZ+Jy8lVWlvqqeM8iZB7w7KmQkoJn8djM585z88rywrEbzoqawVa9FR5p2hwD+y74nfuKOjmNvi9gtWJNLqHvA==", "dev": true, "requires": { "lru-cache": "2", @@ -1212,7 +6323,7 @@ "nopt": { "version": "1.0.10", "resolved": "https://registry.npmjs.org/nopt/-/nopt-1.0.10.tgz", - "integrity": "sha1-bd0hvSoxQXuScn3Vhfim83YI6+4=", + "integrity": "sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==", "dev": true, "requires": { "abbrev": "1" @@ -1221,91 +6332,128 @@ "rimraf": { "version": "2.2.8", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.2.8.tgz", - "integrity": "sha1-5Dm+Kq7jJzIZUnMPmaiSnk/FBYI=", + "integrity": "sha512-R5KMKHnPAQaZMqLOsyuyUmcIjSeDm+73eoqQpaXA7AZ22BL+6C+1mcUscgOsNd8WVlJuvlgAPsegcx7pjlV0Dg==", "dev": true }, "underscore.string": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.2.1.tgz", - "integrity": "sha1-18D6KvXVoaZ/QlPa7pgTLnM/Dxk=", + "integrity": "sha512-3FVmhXqelrj6gfgp3Bn6tOavJvW0dNH2T+heTD38JRxIrAbiuzbqjknszoOYj3DyFB1nWiLj208Qt2no/L4cIA==", "dev": true }, "which": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/which/-/which-1.0.9.tgz", - "integrity": "sha1-RgwdoPgQED0DIam2M6+eV15kSG8=", + "integrity": "sha512-E87fdQ/eRJr9W1X4wTPejNy9zTW3FI2vpCZSJ/HAY+TkjKVC0TUm1jk6vn2Z7qay0DQy0+RBGdXxj+RmmiGZKQ==", "dev": true } } }, "grunt-sass": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/grunt-sass/-/grunt-sass-3.0.2.tgz", - "integrity": "sha512-Ogq4cWqBre71gZIkgxIxevgzZHSIIsrKu/5yvPDl4Mvib0A4TRTJEQUdpQ0YV1iai0DPjayz02vDJE6KUVHQ2w==", - "dev": true + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/grunt-sass/-/grunt-sass-3.1.0.tgz", + "integrity": "sha512-90s27H7FoCDcA8C8+R0GwC+ntYD3lG6S/jqcavWm3bn9RiJTmSfOvfbFa1PXx4NbBWuiGQMLfQTj/JvvqT5w6A==", + "dev": true, + "requires": {} }, "gzip-size": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-3.0.0.tgz", - "integrity": "sha1-VGGI6b3DN/Zzdy+BZgRks4nc5SA=", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/gzip-size/-/gzip-size-5.1.1.tgz", + "integrity": "sha512-FNHi6mmoHvs1mxZAds4PpdCS6QG8B4C1krxJsMutgxl5t3+GlRTzzI3NEkifXx2pVsOvJdOGSmIgDhQ55FwdPA==", "dev": true, "requires": { - "duplexer": "^0.1.1" + "duplexer": "^0.1.1", + "pify": "^4.0.1" } }, "har-schema": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true }, "har-validator": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", - "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "dev": true, "requires": { - "ajv": "^6.5.5", + "ajv": "^6.12.3", "har-schema": "^2.0.0" } }, + "hard-rejection": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/hard-rejection/-/hard-rejection-2.1.0.tgz", + "integrity": "sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, "has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", - "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "dev": true, "requires": { "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + } } }, "has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true }, "has-unicode": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", "dev": true }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, "hooker": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/hooker/-/hooker-0.2.3.tgz", - "integrity": "sha1-uDT3I8xKJCqmWWNFnfbZhMXT2Vk=", + "integrity": "sha512-t+UerCsQviSymAInD01Pw+Dn/usmz1sRO+3Zk1+lx8eg+WKpD2ulcwWqHHL0+aseRBr+3+vIhiG1K1JTwaIcTA==", "dev": true }, "hosted-git-info": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", - "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", - "dev": true + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.1.0.tgz", + "integrity": "sha512-kyCuEOWjJqZuDbRHzL8V93NzQhwIB71oFWSyzVo+KPZI+pnQPPxucdkrOZvkLRnrf5URsQM+IJ09Dw29cRALIA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "htmlparser2": { "version": "3.8.3", "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz", - "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=", + "integrity": "sha512-hBxEg3CYXe+rPIua8ETe7tmG3XDn9B0edOE/e9wH2nLczxzgdu0m0aNHY+5wFZiviLWLdANPJTssa92dMcXQ5Q==", "dev": true, "requires": { "domelementtype": "1", @@ -1315,16 +6463,33 @@ "readable-stream": "1.1" } }, + "http-cache-semantics": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz", + "integrity": "sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ==", + "dev": true + }, "http-parser-js": { - "version": "0.4.10", - "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.4.10.tgz", - "integrity": "sha1-ksnBN0w1CF912zWexWzCV8u5P6Q=", + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==", "dev": true }, + "http-proxy-agent": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz", + "integrity": "sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg==", + "dev": true, + "requires": { + "@tootallnate/once": "1", + "agent-base": "6", + "debug": "4" + } + }, "http-signature": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "requires": { "assert-plus": "^1.0.0", @@ -1332,6 +6497,25 @@ "sshpk": "^1.7.0" } }, + "https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "requires": { + "agent-base": "6", + "debug": "4" + } + }, + "humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dev": true, + "requires": { + "ms": "^2.0.0" + } + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -1341,25 +6525,28 @@ "safer-buffer": ">= 2.1.2 < 3" } }, - "in-publish": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", - "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "dev": true }, "indent-string": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", - "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", - "dev": true, - "requires": { - "repeating": "^2.0.0" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "dev": true, "requires": { "once": "^1.3.0", @@ -1372,82 +6559,179 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "dev": true }, - "invert-kv": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", - "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true + }, + "interpret": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.1.0.tgz", + "integrity": "sha512-CLM8SNMDu7C5psFCn6Wg/tgpj/bKAg7hc2gWqcuR9OD5Ft9PhBpIu8PLicPeis+xDd6YX2ncI8MCA64I9tftIA==", + "dev": true + }, + "ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==", "dev": true }, "irregular-plurals": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-1.4.0.tgz", - "integrity": "sha1-LKmwM2UREYVUEvFr5dd8YqRYp2Y=", + "integrity": "sha512-kniTIJmaZYiwa17eTtWIfm0K342seyugl6vuC8DiiyiRAJWAVlLkqGCI0Im0neo0TkXw+pRcKaBPRdcKHnQJ6Q==", "dev": true }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, "is-arrayish": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true }, - "is-finite": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz", - "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=", + "is-core-module": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.10.0.tgz", + "integrity": "sha512-Erxj2n/LDAZ7H8WNJXd9tw38GYM3dv8rk8Zcs+jJuxYTW7sozH+SS8NtrSjVL1/vpLvWi1hxy96IzjJ3EHTJJg==", "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "has": "^1.0.3" } }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true + }, "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==", + "dev": true + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-1.1.0.tgz", + "integrity": "sha512-yvkRyxmFKEOQ4pNXCmJG5AEQNlXJS5LaONXo5/cLdTZdWvsZ1ioJEonLGAosKlMWE8lwUy/bJzMjcw8az73+Fg==", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-relative": { "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", - "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", "dev": true, "requires": { - "number-is-nan": "^1.0.0" + "is-unc-path": "^1.0.0" } }, "is-typedarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true }, - "is-utf8": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", - "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", "dev": true }, "isarray": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", - "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8=", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", "dev": true }, "isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", "dev": true }, "isstream": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true }, "js-base64": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.1.tgz", - "integrity": "sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==", + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, "js-yaml": { - "version": "3.13.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.13.1.tgz", - "integrity": "sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw==", + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", "dev": true, "requires": { "argparse": "^1.0.7", @@ -1457,29 +6741,28 @@ "jsbn": { "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true }, "jshint": { - "version": "2.10.2", - "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.10.2.tgz", - "integrity": "sha512-e7KZgCSXMJxznE/4WULzybCMNXNAd/bf5TSrvVEq78Q/K8ZwFpmBqQeDtNiHc3l49nV4E/+YeHU/JZjSUIrLAA==", + "version": "2.13.5", + "resolved": "https://registry.npmjs.org/jshint/-/jshint-2.13.5.tgz", + "integrity": "sha512-dB2n1w3OaQ35PLcBGIWXlszjbPZwsgZoxsg6G8PtNf2cFMC1l0fObkYLUuXqTTdi6tKw4sAjfUseTdmDMHQRcg==", "dev": true, "requires": { "cli": "~1.0.0", "console-browserify": "1.1.x", "exit": "0.1.x", "htmlparser2": "3.8.x", - "lodash": "~4.17.11", + "lodash": "~4.17.21", "minimatch": "~3.0.2", - "shelljs": "0.3.x", "strip-json-comments": "1.0.x" } }, "jshint-stylish": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/jshint-stylish/-/jshint-stylish-2.2.1.tgz", - "integrity": "sha1-JCCCosA1rgP9gQROBXDMQgjPbmE=", + "integrity": "sha512-7ySPIM1/gONcJ1isbd1IPKuBzQ/iDTvofILFSsIaMrWZUO7OJkV9kdU0O6O1pxM+bNj/9mbJ31LyXgQgOhIa0A==", "dev": true, "requires": { "beeper": "^1.1.0", @@ -1490,16 +6773,22 @@ "text-table": "^0.2.0" }, "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -1509,18 +6798,33 @@ "supports-color": "^2.0.0" } }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true } } }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, "json-schema": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", - "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "dev": true }, "json-schema-traverse": { @@ -1532,30 +6836,63 @@ "json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true }, "jsprim": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", - "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, "requires": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", - "json-schema": "0.2.3", + "json-schema": "0.4.0", "verror": "1.10.0" } }, - "lcid": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", - "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", - "dev": true, - "requires": { - "invert-kv": "^1.0.0" + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "liftup": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/liftup/-/liftup-3.0.1.tgz", + "integrity": "sha512-yRHaiQDizWSzoXk3APcA71eOI/UuhEkNN9DiW2Tt44mhYzX4joFoCZlxsSOF7RyeLlfqzFLQI1ngFq3ggMPhOw==", + "dev": true, + "requires": { + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" + }, + "dependencies": { + "findup-sync": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-4.0.0.tgz", + "integrity": "sha512-6jvvn/12IC4quLBL1KNokxC7wWTvYncaVUYSoxWw7YykPLuRrnv4qdHcSOywOI5RpkOVGeQRtWM8/q+G6W6qfQ==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + } + } } }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, "livereload-js": { "version": "2.4.0", "resolved": "https://registry.npmjs.org/livereload-js/-/livereload-js-2.4.0.tgz", @@ -1571,20 +6908,7 @@ "arrify": "^2.0.1", "multimatch": "^4.0.0", "pkg-up": "^3.1.0", - "resolve-pkg": "^2.0.0" - } - }, - "load-json-file": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", - "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", - "dev": true, - "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^2.2.0", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "strip-bom": "^2.0.0" + "resolve-pkg": "^2.0.0" } }, "locate-path": { @@ -1595,41 +6919,39 @@ "requires": { "p-locate": "^3.0.0", "path-exists": "^3.0.0" - }, - "dependencies": { - "path-exists": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", - "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", - "dev": true - } } }, "lodash": { - "version": "4.17.15", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", - "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", "dev": true }, "log-symbols": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-1.0.2.tgz", - "integrity": "sha1-N2/3tY6jCGoPCfrMdGF+ylAeGhg=", + "integrity": "sha512-mmPrW0Fh2fxOzdBbFv4g1m6pR72haFLPJ2G5SJEELf1y+iaQrDG6cWCPjy54RHYbZAt7X+ls690Kw62AdWXBzQ==", "dev": true, "requires": { "chalk": "^1.0.0" }, "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -1639,140 +6961,247 @@ "supports-color": "^2.0.0" } }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true } } }, - "loud-rejection": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", - "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", "dev": true, "requires": { - "currently-unhandled": "^0.4.1", - "signal-exit": "^3.0.0" + "yallist": "^4.0.0" } }, - "lru-cache": { - "version": "2.7.3", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", - "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", + "make-fetch-happen": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz", + "integrity": "sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg==", + "dev": true, + "requires": { + "agentkeepalive": "^4.1.3", + "cacache": "^15.2.0", + "http-cache-semantics": "^4.1.0", + "http-proxy-agent": "^4.0.1", + "https-proxy-agent": "^5.0.0", + "is-lambda": "^1.0.1", + "lru-cache": "^6.0.0", + "minipass": "^3.1.3", + "minipass-collect": "^1.0.2", + "minipass-fetch": "^1.3.2", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.2", + "promise-retry": "^2.0.1", + "socks-proxy-agent": "^6.0.0", + "ssri": "^8.0.0" + } + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==", "dev": true }, "map-obj": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", - "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", "dev": true }, "maxmin": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-2.1.0.tgz", - "integrity": "sha1-TTsiCQPZXu5+t6x/qGTnLcCaMWY=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/maxmin/-/maxmin-3.0.0.tgz", + "integrity": "sha512-wcahMInmGtg/7c6a75fr21Ch/Ks1Tb+Jtoan5Ft4bAI0ZvJqyOw8kkM7e7p8hDSzY805vmxwHT50KcjGwKyJ0g==", "dev": true, "requires": { - "chalk": "^1.0.0", - "figures": "^1.0.1", - "gzip-size": "^3.0.0", - "pretty-bytes": "^3.0.0" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } + "chalk": "^4.1.0", + "figures": "^3.2.0", + "gzip-size": "^5.1.1", + "pretty-bytes": "^5.3.0" } }, "meow": { - "version": "3.7.0", - "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", - "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-9.0.0.tgz", + "integrity": "sha512-+obSblOQmRhcyBt62furQqRAQpNyWXo8BuQ5bN7dG8wmwQ+vwHKp/rCFD4CrTP8CsDQD1sjoZ94K417XEUk8IQ==", "dev": true, "requires": { - "camelcase-keys": "^2.0.0", - "decamelize": "^1.1.2", - "loud-rejection": "^1.0.0", - "map-obj": "^1.0.1", - "minimist": "^1.1.3", - "normalize-package-data": "^2.3.4", - "object-assign": "^4.0.1", - "read-pkg-up": "^1.0.1", - "redent": "^1.0.0", - "trim-newlines": "^1.0.0" + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize": "^1.2.0", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" + } + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, "mime-db": { - "version": "1.40.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.40.0.tgz", - "integrity": "sha512-jYdeOMPy9vnxEqFRRo6ZvTZ8d9oPb+k18PKoYNYUe2stVEBPPwsln/qWzdbmaIvnhZ9v2P+CuecK+fpUfsV2mA==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true }, "mime-types": { - "version": "2.1.24", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.24.tgz", - "integrity": "sha512-WaFHS3MCl5fapm3oLxU4eYDw77IQM2ACcxQ9RIxfaC3ooc6PFuBMGZZsYpvoXS5D5QTWPieo1jjLdAm3TBP3cQ==", + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "requires": { - "mime-db": "1.40.0" + "mime-db": "1.52.0" } }, + "min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true + }, "minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.8.tgz", + "integrity": "sha512-6FsRAQsxQ61mw+qP1ZzbL9Bc78x2p5OqNgNpnoAFLTrX8n5Kxph0CsnhmKKNXTWjXqU5L0pGPR7hYk+XWZr60Q==", "dev": true, "requires": { "brace-expansion": "^1.1.7" } }, "minimist": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", - "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.6.tgz", + "integrity": "sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q==", "dev": true }, - "mkdirp": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", - "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "minimist-options": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/minimist-options/-/minimist-options-4.1.0.tgz", + "integrity": "sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A==", "dev": true, "requires": { - "minimist": "0.0.8" + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" }, "dependencies": { - "minimist": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", - "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true } } }, + "minipass": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.4.tgz", + "integrity": "sha512-I9WPbWHCGu8W+6k1ZiGpPu0GkoKBeorkfKNuAFBNS1HNFJvke82sxvI5bzcCNpWPorkOO5QQ+zomzzwRxejXiw==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-fetch": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz", + "integrity": "sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw==", + "dev": true, + "requires": { + "encoding": "^0.1.12", + "minipass": "^3.1.0", + "minipass-sized": "^1.0.3", + "minizlib": "^2.0.0" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dev": true, + "requires": { + "minipass": "^3.0.0" + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dev": true, + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + } + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "dev": true + }, "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", @@ -1793,128 +7222,164 @@ } }, "nan": { - "version": "2.14.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", - "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "version": "2.16.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.16.0.tgz", + "integrity": "sha512-UdAqHyFngu7TfQKsCBgAA6pWDkT8MAO7d0jyOecVhN5354xbLqdn8mV9Tat9gepAupm0bt2DbeaSC8vS52MuFA==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true }, "node-gyp": { - "version": "3.8.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", - "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", - "dev": true, - "requires": { - "fstream": "^1.0.0", - "glob": "^7.0.3", - "graceful-fs": "^4.1.2", - "mkdirp": "^0.5.0", - "nopt": "2 || 3", - "npmlog": "0 || 1 || 2 || 3 || 4", - "osenv": "0", - "request": "^2.87.0", - "rimraf": "2", - "semver": "~5.3.0", - "tar": "^2.0.0", - "which": "1" + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-8.4.1.tgz", + "integrity": "sha512-olTJRgUtAb/hOXG0E93wZDs5YiJlgbXxTwQAFHyNlRsXQnYzUaF2aGgujZbw+hR8aF4ZG/rST57bWMWD16jr9w==", + "dev": true, + "requires": { + "env-paths": "^2.2.0", + "glob": "^7.1.4", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^9.1.0", + "nopt": "^5.0.0", + "npmlog": "^6.0.0", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^2.0.2" }, "dependencies": { - "semver": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", - "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", - "dev": true + "are-we-there-yet": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-3.0.1.tgz", + "integrity": "sha512-QZW4EDmGwlYur0Yyf/b2uGucHQMa8aFUP7eu9ddR73vvhFyt4V0Vl3QHPcTNJ8l6qYOBdxgXdnBXQrHilfRQBg==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + } + }, + "gauge": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-4.0.4.tgz", + "integrity": "sha512-f9m+BEN5jkg6a0fZjleidjN51VE1X+mPFQ2DJ0uv1V39oCLCbsGe6yjbBnp7eK7z/+GAon99a3nHuqbuuthyPg==", + "dev": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^3.0.7", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "npmlog": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-6.0.2.tgz", + "integrity": "sha512-/vBvz5Jfr9dT/aFWd0FIRf+T/Q2WBsLENygUaFUqstqsycmZAP/t5BvFJTK0viFmSUxiUKTUplWy5vt+rvKIxg==", + "dev": true, + "requires": { + "are-we-there-yet": "^3.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^4.0.3", + "set-blocking": "^2.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "requires": { + "safe-buffer": "~5.2.0" + } } } }, "node-sass": { - "version": "4.12.0", - "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.12.0.tgz", - "integrity": "sha512-A1Iv4oN+Iel6EPv77/HddXErL2a+gZ4uBeZUy+a8O35CFYTXhgA8MgLCWBtwpGZdCvTvQ9d+bQxX/QC36GDPpQ==", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-7.0.1.tgz", + "integrity": "sha512-uMy+Xt29NlqKCFdFRZyXKOTqGt+QaKHexv9STj2WeLottnlqZEEWx6Bj0MXNthmFRRdM/YwyNo/8Tr46TOM0jQ==", "dev": true, "requires": { "async-foreach": "^0.1.3", - "chalk": "^1.1.1", - "cross-spawn": "^3.0.0", + "chalk": "^4.1.2", + "cross-spawn": "^7.0.3", "gaze": "^1.0.0", "get-stdin": "^4.0.1", "glob": "^7.0.3", - "in-publish": "^2.0.0", - "lodash": "^4.17.11", - "meow": "^3.7.0", - "mkdirp": "^0.5.1", + "lodash": "^4.17.15", + "meow": "^9.0.0", "nan": "^2.13.2", - "node-gyp": "^3.8.0", - "npmlog": "^4.0.0", + "node-gyp": "^8.4.1", + "npmlog": "^5.0.0", "request": "^2.88.0", - "sass-graph": "^2.2.4", + "sass-graph": "4.0.0", "stdout-stream": "^1.4.0", "true-case-path": "^1.0.2" - }, - "dependencies": { - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", - "dev": true - } } }, "nopt": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", - "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "integrity": "sha512-4GUt3kSEYmk4ITxzB/b9vaIDfUVWN/Ml1Fwl11IlnIG2iaJ9O6WXZ9SrYM9NLI8OCBieN2Y8SWC2oJV0RQ7qYg==", "dev": true, "requires": { "abbrev": "1" } }, "normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-3.0.3.tgz", + "integrity": "sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA==", "dev": true, "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", "validate-npm-package-license": "^3.0.1" } }, "npmlog": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", - "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", "dev": true, "requires": { - "are-we-there-yet": "~1.1.2", - "console-control-strings": "~1.1.0", - "gauge": "~2.7.3", - "set-blocking": "~2.0.0" + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" } }, "number-is-nan": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", - "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "integrity": "sha512-4jbtZXNAsfZbAHiiqjLPBiCl16dES1zI4Hpzzxw61Tk+loF+sBDBKx1ICKKKwIqQ7M0mFn1TmkN7euSncWgHiQ==", "dev": true }, "oauth-sign": { @@ -1926,13 +7391,44 @@ "object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", "dev": true }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==", + "dev": true, + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha512-3+mAJu2PLfnSVGHwIWubpOFLscJANBKuB/6A4CxBstc4aqwQY0FWcsppuy4jU5GSB95yES5JHSI+33AWuS4k6w==", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, "once": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", "dev": true, "requires": { "wrappy": "1" @@ -1941,22 +7437,13 @@ "os-homedir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", - "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "integrity": "sha512-B5JU3cabzk8c67mRRd3ECmROafjYMXbuzlwtqdM8IbS8ktlTix8aFGb2bAGKrSRIlnfKwovGUUr72JUPyOb6kQ==", "dev": true }, - "os-locale": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", - "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", - "dev": true, - "requires": { - "lcid": "^1.0.0" - } - }, "os-tmpdir": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true }, "osenv": { @@ -1970,9 +7457,9 @@ } }, "p-limit": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.0.tgz", - "integrity": "sha512-pZbTJpoUsCzV48Mc9Nh51VbwO0X9cuPFE8gYwx9BTCt9SF8/b7Zljd2fVgOxhIF/HDTKgpVzs+GPhyKfjLLFRQ==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "requires": { "p-try": "^2.0.0" @@ -1987,86 +7474,113 @@ "p-limit": "^2.0.0" } }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dev": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, "p-try": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "dev": true }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, "parse-json": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", - "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "requires": { - "error-ex": "^1.2.0" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" } }, "parse-ms": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-1.0.1.tgz", - "integrity": "sha1-VjRtR0nXjyNDDKDHE4UK75GqNh0=", + "integrity": "sha512-LpH1Cf5EYuVjkBvCDBYvkUPh+iv2bk3FHflxHkpCYT0/FZ1d3N3uJaLiHr4yGuMcFUhv6eAivitTvWZI4B/chg==", + "dev": true + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==", "dev": true }, "path-exists": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", - "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", - "dev": true, - "requires": { - "pinkie-promise": "^2.0.0" - } + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true }, "path-is-absolute": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "dev": true }, "path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true }, - "path-type": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", - "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" + "path-root-regex": "^0.1.0" } }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==", + "dev": true + }, "performance-now": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true }, - "pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", "dev": true }, - "pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true }, - "pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", - "dev": true, - "requires": { - "pinkie": "^2.0.0" - } - }, "pkg-up": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz", @@ -2074,41 +7588,27 @@ "dev": true, "requires": { "find-up": "^3.0.0" - }, - "dependencies": { - "find-up": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", - "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", - "dev": true, - "requires": { - "locate-path": "^3.0.0" - } - } } }, "plur": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/plur/-/plur-2.1.2.tgz", - "integrity": "sha1-dIJFLBoPUI4+NE6uwxLJHCncZVo=", + "integrity": "sha512-WhcHk576xg9y/iv6RWOuroZgsqvCbJN+XGvAypCJwLAYs2iWDp5LUmvaCdV6JR2O0SMBf8l6p7A94AyLCFVMlQ==", "dev": true, "requires": { "irregular-plurals": "^1.0.0" } }, "pretty-bytes": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-3.0.1.tgz", - "integrity": "sha1-J9AAjXeAY6C0gRuzXHnxvV1fvM8=", - "dev": true, - "requires": { - "number-is-nan": "^1.0.0" - } + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "dev": true }, "pretty-ms": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-2.1.0.tgz", - "integrity": "sha1-QlfCVt8/sLRR1q/6qwIYhBJpgdw=", + "integrity": "sha512-H2enpsxzDhuzRl3zeSQpQMirn8dB0Z/gxW96j06tMfTviUWvX14gjKb7qd1gtkUyYhDPuoNe00K5PqNvy2oQNg==", "dev": true, "requires": { "is-finite": "^1.0.1", @@ -2119,7 +7619,7 @@ "plur": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/plur/-/plur-1.0.0.tgz", - "integrity": "sha1-24XGgU9eXlo7Se/CjWBP7GKXUVY=", + "integrity": "sha512-qSnKBSZeDY8ApxwhfVIwKwF36KVJqb1/9nzYYq3j3vdwocULCXT8f8fQGkiw1Nk9BGfxiDagEe/pwakA+bOBqw==", "dev": true } } @@ -2130,16 +7630,26 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "dev": true }, - "pseudomap": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", - "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==", "dev": true }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dev": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, "psl": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.3.0.tgz", - "integrity": "sha512-avHdspHO+9rQTLbv1RO+MPYeP/SzsCoxofjVnHanETfQhTJrmB0HlDoW+EiN/R+C0BZ+gERab9NY0lPN2TxNag==", + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", "dev": true }, "punycode": { @@ -2149,15 +7659,21 @@ "dev": true }, "qs": { - "version": "6.7.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.7.0.tgz", - "integrity": "sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==", + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", + "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", + "dev": true + }, + "quick-lru": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-4.0.1.tgz", + "integrity": "sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==", "dev": true }, "raw-body": { "version": "1.1.7", "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-1.1.7.tgz", - "integrity": "sha1-HQJ8K/oRasxmI7yo8AAWVyqH1CU=", + "integrity": "sha512-WmJJU2e9Y6M5UzTOkHaM7xJGAPQD8PNzx3bAd2+uhZAim6wDk6dAZxPVYLF67XhbR4hmKGh33Lpmh4XWrCH5Mg==", "dev": true, "requires": { "bytes": "1", @@ -2165,30 +7681,106 @@ } }, "read-pkg": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", - "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz", + "integrity": "sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==", "dev": true, "requires": { - "load-json-file": "^1.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^1.0.0" + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", + "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", + "dev": true + }, + "type-fest": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz", + "integrity": "sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==", + "dev": true + } } }, "read-pkg-up": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", - "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz", + "integrity": "sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==", "dev": true, "requires": { - "find-up": "^1.0.0", - "read-pkg": "^1.0.0" + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "type-fest": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz", + "integrity": "sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==", + "dev": true + } } }, "readable-stream": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz", - "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=", + "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -2197,29 +7789,29 @@ "string_decoder": "~0.10.x" } }, - "redent": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", - "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "rechoir": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz", + "integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==", "dev": true, "requires": { - "indent-string": "^2.1.0", - "strip-indent": "^1.0.1" + "resolve": "^1.9.0" } }, - "repeating": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", - "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", "dev": true, "requires": { - "is-finite": "^1.0.0" + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" } }, "request": { - "version": "2.88.0", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.0.tgz", - "integrity": "sha512-NAqBSrijGLZdM0WZNsInLJpkJokL72XYjUpnB0iwsRgxh7dB6COrHnTBNwN0E+lHDAJzu7kLAkDeY08z2/A0hg==", + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "dev": true, "requires": { "aws-sign2": "~0.7.0", @@ -2229,7 +7821,7 @@ "extend": "~3.0.2", "forever-agent": "~0.6.1", "form-data": "~2.3.2", - "har-validator": "~5.1.0", + "har-validator": "~5.1.3", "http-signature": "~1.2.0", "is-typedarray": "~1.0.0", "isstream": "~0.1.2", @@ -2239,38 +7831,36 @@ "performance-now": "^2.1.0", "qs": "~6.5.2", "safe-buffer": "^5.1.2", - "tough-cookie": "~2.4.3", + "tough-cookie": "~2.5.0", "tunnel-agent": "^0.6.0", "uuid": "^3.3.2" - }, - "dependencies": { - "qs": { - "version": "6.5.2", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", - "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", - "dev": true - } } }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "dev": true - }, - "require-main-filename": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", - "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "dev": true }, "resolve": { - "version": "1.12.0", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.12.0.tgz", - "integrity": "sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==", + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==", "dev": true, "requires": { - "path-parse": "^1.0.6" + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" } }, "resolve-from": { @@ -2288,41 +7878,31 @@ "resolve-from": "^5.0.0" } }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "dev": true + }, "rimraf": { - "version": "2.6.3", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", - "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "dev": true, "requires": { "glob": "^7.1.3" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } } }, "safe-buffer": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.0.tgz", - "integrity": "sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", "dev": true }, "safe-json-parse": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/safe-json-parse/-/safe-json-parse-1.0.1.tgz", - "integrity": "sha1-PnZyPjjf3aE8mx0poeB//uSzC1c=", + "integrity": "sha512-o0JmTu17WGUaUOHa1l0FPGXKBfijbxK6qoHzlkihsDXxzBHvJcA7zgviKR92Xs841rX9pK16unfphLq0/KqX7A==", "dev": true }, "safer-buffer": { @@ -2332,78 +7912,106 @@ "dev": true }, "sass-graph": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", - "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-4.0.0.tgz", + "integrity": "sha512-WSO/MfXqKH7/TS8RdkCX3lVkPFQzCgbqdGsmSKq6tlPU+GpGEsa/5aW18JqItnqh+lPtcjifqdZ/VmiILkKckQ==", "dev": true, "requires": { "glob": "^7.0.0", - "lodash": "^4.0.0", - "scss-tokenizer": "^0.2.3", - "yargs": "^7.0.0" + "lodash": "^4.17.11", + "scss-tokenizer": "^0.3.0", + "yargs": "^17.2.1" } }, "scss-tokenizer": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", - "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.3.0.tgz", + "integrity": "sha512-14Zl9GcbBvOT9057ZKjpz5yPOyUWG2ojd9D5io28wHRYsOrs7U95Q+KNL87+32p8rc+LvDpbu/i9ZYjM9Q+FsQ==", "dev": true, "requires": { - "js-base64": "^2.1.8", - "source-map": "^0.4.2" - }, - "dependencies": { - "source-map": { - "version": "0.4.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", - "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", - "dev": true, - "requires": { - "amdefine": ">=0.0.4" - } - } + "js-base64": "^2.4.3", + "source-map": "^0.7.1" } }, "semver": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.0.tgz", - "integrity": "sha512-Ya52jSX2u7QKghxeoFGpLwCtGlt7j0oY9DYb5apt9nPlJ42ID+ulTXESnt/qAQcoSERyZ5sl3LDIOw0nAn/5DA==", - "dev": true + "version": "7.3.7", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.7.tgz", + "integrity": "sha512-QlYTucUYOews+WeEujDoEGziz4K6c47V/Bd+LjSSYcA94p+DmINdf7ncaUinThfvZyu13lN9OY1XDxt8C0Tw0g==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } }, "set-blocking": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "dev": true }, - "shelljs": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.3.0.tgz", - "integrity": "sha1-NZbmMHp4FUT1kfN9phg2DzHbV7E=", + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "dev": true }, "sigmund": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", - "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", + "integrity": "sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==", "dev": true }, "signal-exit": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", - "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", "dev": true }, + "socks": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.0.tgz", + "integrity": "sha512-scnOe9y4VuiNUULJN72GrM26BNOjVsfPXI+j+98PkyEfsIXroa5ofyjT+FzGvn/xHs73U2JtoBYAVx9Hl4quSA==", + "dev": true, + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.2.1.tgz", + "integrity": "sha512-a6KW9G+6B3nWZ1yB8G7pJwL3ggLy1uTzKAgCb7ttblwqdz9fMGJUuTy3uFzEP48FAs9FLILlmzDlE2JJhVQaXQ==", + "dev": true, + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, "source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", "dev": true }, "spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz", + "integrity": "sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w==", "dev": true, "requires": { "spdx-expression-parse": "^3.0.0", @@ -2411,15 +8019,15 @@ } }, "spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz", + "integrity": "sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A==", "dev": true }, "spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", "dev": true, "requires": { "spdx-exceptions": "^2.1.0", @@ -2427,21 +8035,21 @@ } }, "spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", + "version": "3.0.12", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.12.tgz", + "integrity": "sha512-rr+VVSXtRhO4OHbXUiAF7xW3Bo9DuuF6C5jH+q/x15j2jniycgKbxU09Hr0WqlSLUs4i4ltHGXqTe7VHclYWyA==", "dev": true }, "sprintf-js": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", - "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", "dev": true }, "sshpk": { - "version": "1.16.1", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", - "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", "dev": true, "requires": { "asn1": "~0.2.3", @@ -2455,6 +8063,15 @@ "tweetnacl": "~0.14.0" } }, + "ssri": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz", + "integrity": "sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ==", + "dev": true, + "requires": { + "minipass": "^3.1.1" + } + }, "stdout-stream": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", @@ -2467,13 +8084,13 @@ "isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", - "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", "dev": true }, "readable-stream": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", - "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", "dev": true, "requires": { "core-util-is": "~1.0.0", @@ -2502,95 +8119,112 @@ } } }, + "string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "dev": true + }, "string-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/string-length/-/string-length-1.0.1.tgz", - "integrity": "sha1-VpcPscOFWOnnC3KL894mmsRa36w=", + "integrity": "sha512-MNCACnufWUf3pQ57O5WTBMkKhzYIaKEcUioO0XHrTMafrbBaNk4IyDOLHBv5xbXO0jLLdsYWeFjpjG2hVHRDtw==", "dev": true, "requires": { "strip-ansi": "^3.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + } } }, "string-template": { "version": "0.2.1", "resolved": "https://registry.npmjs.org/string-template/-/string-template-0.2.1.tgz", - "integrity": "sha1-QpMuWYo1LQH8IuwzZ9nYTuxsmt0=", + "integrity": "sha512-Yptehjogou2xm4UJbxJ4CxgZx12HBfeystp0y3x7s4Dj32ltVVG1Gg8YhKjHZkHicuKpZX/ffilA8505VbUbpw==", "dev": true }, "string-width": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", - "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "requires": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, - "string_decoder": { - "version": "0.10.31", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", - "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ=", - "dev": true - }, "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "strip-bom": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", - "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "requires": { - "is-utf8": "^0.2.0" + "ansi-regex": "^5.0.1" } }, "strip-indent": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", - "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", "dev": true, "requires": { - "get-stdin": "^4.0.1" + "min-indent": "^1.0.0" } }, "strip-json-comments": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-1.0.4.tgz", - "integrity": "sha1-HhX7ysl9Pumb8tc7TGVrCCu6+5E=", + "integrity": "sha512-AOPG8EBc5wAikaG1/7uFCNFJwnKOuQwFTpYBdTW6OvWHeZBQBrAA/amefHGrEiOnCPcLFZK6FUPtWVKpQVIRgg==", "dev": true }, "supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, "requires": { - "has-flag": "^3.0.0" + "has-flag": "^4.0.0" } }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, "tar": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", - "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "version": "6.1.11", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz", + "integrity": "sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA==", "dev": true, "requires": { - "block-stream": "*", - "fstream": "^1.0.12", - "inherits": "2" + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^3.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" } }, "text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", "dev": true }, "time-grunt": { @@ -2608,16 +8242,22 @@ "text-table": "^0.2.0" }, "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", + "dev": true + }, "ansi-styles": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, "chalk": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { "ansi-styles": "^2.2.1", @@ -2627,10 +8267,29 @@ "supports-color": "^2.0.0" } }, + "figures": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-1.7.0.tgz", + "integrity": "sha512-UxKlfCRuCBxSXU4C6t9scbDyWZ4VlaFFdojKtzJuSkuOBQ5CNFum+zZXFwHjo+CxBC1t6zlYPgHIgFjL8ggoEQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "object-assign": "^4.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, "supports-color": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true } } @@ -2638,7 +8297,7 @@ "time-zone": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/time-zone/-/time-zone-0.1.0.tgz", - "integrity": "sha1-Sncotqwo2w4Aj1FAQ/1VW9VXO0Y=", + "integrity": "sha512-S5CjtVIkeBTnlsaZP3gjsTb78ClBe74sEcgEoBwAVUKnTRDAGqUtLLIZHMsIyqOWjt9DGQpLMMoD8ZKIfP2ddQ==", "dev": true }, "tiny-lr": { @@ -2653,30 +8312,42 @@ "livereload-js": "^2.3.0", "object-assign": "^4.1.0", "qs": "^6.4.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" } }, "tough-cookie": { - "version": "2.4.3", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.4.3.tgz", - "integrity": "sha512-Q5srk/4vDM54WJsJio3XNn6K2sCG+CQ8G5Wz6bZhRZoAe/+TxjWB/GlFAnYEbkYVlON9FMk/fE3h2RLpPXo4lQ==", + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, "requires": { - "psl": "^1.1.24", - "punycode": "^1.4.1" - }, - "dependencies": { - "punycode": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", - "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", - "dev": true - } + "psl": "^1.1.28", + "punycode": "^2.1.1" } }, "trim-newlines": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", - "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-3.0.1.tgz", + "integrity": "sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw==", "dev": true }, "true-case-path": { @@ -2686,28 +8357,12 @@ "dev": true, "requires": { "glob": "^7.1.2" - }, - "dependencies": { - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - } } }, "tunnel-agent": { "version": "0.6.0", "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", - "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "requires": { "safe-buffer": "^5.0.1" @@ -2716,39 +8371,73 @@ "tweetnacl": { "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "dev": true + }, + "type-fest": { + "version": "0.18.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.18.1.tgz", + "integrity": "sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw==", "dev": true }, "uglify-js": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.0.tgz", - "integrity": "sha512-W+jrUHJr3DXKhrsS7NUVxn3zqMOFn0hL/Ei6v0anCIMoKC93TjcflTagwIHLW7SfMFfiQuktQyFVCFHGUE0+yg==", - "dev": true, - "requires": { - "commander": "~2.20.0", - "source-map": "~0.6.1" - } + "version": "3.17.0", + "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.0.tgz", + "integrity": "sha512-aTeNPVmgIMPpm1cxXr2Q/nEbvkmV8yq66F3om7X3P/cvOXQ0TMQ64Wk63iyT1gPlmdmGzjGpyLh1f3y8MZWXGg==", + "dev": true + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==", + "dev": true }, "underscore": { "version": "1.7.0", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.7.0.tgz", - "integrity": "sha1-a7rwh3UA02vjTsqlhODbn+8DUgk=", + "integrity": "sha512-cp0oQQyZhUM1kpJDLdGO1jPZHgS/MpzoWYfe9+CM2h/QGDZlqwT2T3YGukuBdaNJ/CAPoeyAZRRHz8JFo176vA==", "dev": true }, "underscore.string": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.5.tgz", - "integrity": "sha512-g+dpmgn+XBneLmXXo+sGlW5xQEt4ErkS3mgeN2GFbremYeMBSJKr9Wf2KJplQVaiPY/f7FN6atosWYNm9ovrYg==", + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-3.3.6.tgz", + "integrity": "sha512-VoC83HWXmCrF6rgkyxS9GHv8W9Q5nhMKho+OadDJGzL2oDYbYEppBaCMH6pFlwLeqj2QS+hhkw2kpXkSdD1JxQ==", "dev": true, "requires": { - "sprintf-js": "^1.0.3", + "sprintf-js": "^1.1.1", "util-deprecate": "^1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.2.tgz", + "integrity": "sha512-VE0SOVEHCk7Qc8ulkWw3ntAzXuqf7S2lvwQaDLRnUeIEaKNQJzV6BwmLKhOqT61aGhfUMrXeaBk+oDGCzvhcug==", + "dev": true + } + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" } }, "uri-js": { - "version": "4.2.2", - "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", - "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "dev": true, "requires": { "punycode": "^2.1.0" @@ -2757,21 +8446,30 @@ "uri-path": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/uri-path/-/uri-path-1.0.0.tgz", - "integrity": "sha1-l0fwGDWJM8Md4PzP2C0TjmcmLjI=", + "integrity": "sha512-8pMuAn4KacYdGMkFaoQARicp4HSw24/DHOVKWqVRJ8LhhAwPPFpdGvdL9184JVmUwe7vz7Z9n6IqI6t5n2ELdg==", "dev": true }, "util-deprecate": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "dev": true }, "uuid": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.3.2.tgz", - "integrity": "sha512-yXJmeNaw3DnnKAOKJE51sL/ZaYfWJRl1pK9dr19YFCu0ObS231AB1/LbqTKRAQ5kw8A90rA6fr4riOUpTZvQZA==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "dev": true }, + "v8flags": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", + "integrity": "sha512-mH8etigqMfiGWdeXpaaqGfs6BndypxusHHcv2qSHyZkGEznCd/qAXCWWRzeowtL54147cktFOC4P5y+kl8d8Jg==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, "validate-npm-package-license": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", @@ -2785,134 +8483,114 @@ "verror": { "version": "1.10.0", "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "requires": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", "extsprintf": "^1.2.0" + }, + "dependencies": { + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true + } } }, "websocket-driver": { - "version": "0.7.3", - "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.3.tgz", - "integrity": "sha512-bpxWlvbbB459Mlipc5GBzzZwhoZgGEZLuqPaR0INBGnPAY1vdBX6hPnoFXiw+3yWxDuHyQjO2oXTMyS8A5haFg==", + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", "dev": true, "requires": { - "http-parser-js": ">=0.4.0 <0.4.11", + "http-parser-js": ">=0.5.1", "safe-buffer": ">=5.1.0", "websocket-extensions": ">=0.1.1" } }, "websocket-extensions": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.3.tgz", - "integrity": "sha512-nqHUnMXmBzT0w570r2JpJxfiSD1IzoI+HGVdd3aZ0yNi3ngvQ4jv1dtHt5VGxfI2yj5yqImPhOK4vmIh2xMbGg==", + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", "dev": true }, "which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "dev": true, "requires": { "isexe": "^2.0.0" } }, - "which-module": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", - "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", - "dev": true - }, "wide-align": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", - "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", "dev": true, "requires": { - "string-width": "^1.0.2 || 2" + "string-width": "^1.0.2 || 2 || 3 || 4" } }, "wrap-ansi": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", - "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "requires": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, "y18n": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", - "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true }, "yallist": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", - "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, "yargs": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", - "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "version": "17.5.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.5.1.tgz", + "integrity": "sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA==", "dev": true, "requires": { - "camelcase": "^3.0.0", - "cliui": "^3.2.0", - "decamelize": "^1.1.1", - "get-caller-file": "^1.0.1", - "os-locale": "^1.4.0", - "read-pkg-up": "^1.0.1", + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", "require-directory": "^2.1.1", - "require-main-filename": "^1.0.1", - "set-blocking": "^2.0.0", - "string-width": "^1.0.2", - "which-module": "^1.0.0", - "y18n": "^3.2.1", - "yargs-parser": "^5.0.0" + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" }, "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true } } }, "yargs-parser": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", - "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", - "dev": true, - "requires": { - "camelcase": "^3.0.0" - }, - "dependencies": { - "camelcase": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", - "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", - "dev": true - } - } + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true } } } diff --git a/package.json b/package.json index e81a074..eb05f0c 100644 --- a/package.json +++ b/package.json @@ -1,21 +1,21 @@ { "name": "simple-lightbox", - "version": "2.8.1", + "version": "2.9.0", "title": "Simple Lightbox", "description": "The highly-customizable lightbox for WordPress", "author": "Archetyped ", "license": "GPLv2", "private": true, "devDependencies": { - "grunt": "^1.0.1", - "grunt-contrib-jshint": "^2.1.0", - "grunt-contrib-uglify": "^4.0.1", - "grunt-contrib-watch": "^1.0.0", + "grunt": "^1.5.3", + "grunt-contrib-jshint": "^3.2.0", + "grunt-contrib-uglify": "^5.2.2", + "grunt-contrib-watch": "^1.1.0", "grunt-phplint": "0.1.0", - "grunt-sass": "^3.0.2", + "grunt-sass": "^3.1.0", "jshint-stylish": "^2.2.1", "load-grunt-tasks": "^5.1.0", - "node-sass": "^4.12.0", + "node-sass": "^7.0.1", "time-grunt": "^2.0.0" } } diff --git a/phpcs.xml.dist b/phpcs.xml.dist index 667db28..669fd22 100644 --- a/phpcs.xml.dist +++ b/phpcs.xml.dist @@ -30,94 +30,24 @@ + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/readme.txt b/readme.txt index 439b766..9b4abea 100644 --- a/readme.txt +++ b/readme.txt @@ -4,7 +4,7 @@ Donate link: http://gum.co/slb-donate License: GPLv2 Tags: lightbox, gallery, photography, images, theme, template, style Requires at least: 5.3 -Tested up to: 5.3 +Tested up to: 6.0 Requires PHP: 5.6.20 Stable tag: trunk @@ -38,11 +38,12 @@ Options for customizing the lightbox behavior are located in the **Appearance > **That's it! The image will be displayed in a lightbox automatically.** * For more usage tips, go to [Simple Lightbox's official page](http://archetyped.com/tools/simple-lightbox/) +* See [Simple Lightbox's documentation](https://github.com/archetyped/simple-lightbox/wiki) for in-depth information on using and customizing SLB. == Installation == 1. Install and activate SLB -1. Verify that your site's theme uses the `wp_head()`, `wp_footer()`, & `the_content()` template tags (standard in any professional theme) +2. Verify that your site's theme uses the `wp_head()`, `wp_footer()`, & `the_content()` template tags (standard in any professional theme) == Upgrade Notice == @@ -64,6 +65,19 @@ Get more information on [Simple Lightbox's official page](http://archetyped.com/ == Changelog == += 2.9.0 = + +* Add: Support WebP image format +* Add: Support AVIF image format +* Add: Documentation link to readme file +* Optimize: Code cleanup/refactoring +* Optimize: WPCS validation (Phase 1) +* Optimize: Activate links after all other filters +* Optimize: Plugin metadata retrieval +* Update: Confirm WordPress 6.0 compatibility +* Update: Build dependencies +* Update: GitHub issue templates + = 2.8.1 = * Update: PHP 5.6 Compatibility diff --git a/template-tags/item/js/prod/tag.item.js b/template-tags/item/js/prod/tag.item.js index 955f9e1..2273cf7 100644 --- a/template-tags/item/js/prod/tag.item.js +++ b/template-tags/item/js/prod/tag.item.js @@ -1 +1 @@ -window.SLB&&SLB.has_child("View.extend_template_tag_handler")&&SLB.View.extend_template_tag_handler("item",{render:function(item,tag,dfr){var m="get_"+tag.get_prop(),ret=this.util.is_method(item,m)?item[m]():item.get_attribute(tag.get_prop(),"");return this.util.is_promise(ret)?ret.done(function(output){dfr.resolve(output)}):dfr.resolve(ret),dfr.promise()}}); \ No newline at end of file +window.SLB&&SLB.has_child("View.extend_template_tag_handler")&&SLB.View.extend_template_tag_handler("item",{render:function(item,tag,dfr){var m="get_"+tag.get_prop(),m=this.util.is_method(item,m)?item[m]():item.get_attribute(tag.get_prop(),"");return this.util.is_promise(m)?m.done(function(output){dfr.resolve(output)}):dfr.resolve(m),dfr.promise()}}); \ No newline at end of file diff --git a/template-tags/ui/js/prod/tag.ui.js b/template-tags/ui/js/prod/tag.ui.js index b1f25ce..301d8a6 100644 --- a/template-tags/ui/js/prod/tag.ui.js +++ b/template-tags/ui/js/prod/tag.ui.js @@ -1 +1 @@ -window.SLB&&SLB.has_child("View.extend_template_tag_handler")&&SLB.View.extend_template_tag_handler("ui",{_hooks:function(){this.on("dom_init",function(ev){this.call_attribute("events_init",ev)})},events_init:function(ev){var v=ev.data.template.get_theme().get_viewer(),thm=v.get_theme();v.on("events-complete",function(ev,v){thm.dom_get_tag("ui","close").click(function(){return v.close()}),thm.dom_get_tag("ui","nav_next").click(function(){v.item_next()}),thm.dom_get_tag("ui","nav_prev").click(function(){v.item_prev()}),thm.dom_get_tag("ui","slideshow_control").click(function(){v.slideshow_toggle()})}),v.on("slideshow-toggle",function(ev,v){var tags=thm.get_tags("ui","slideshow_control");if(tags.length)for(var x=0;xthis.get_breakpoint("small")?{width:32,height:55}:{width:0,height:0}},margin:function(){return document.documentElement.clientWidth>this.get_breakpoint("small")?{height:50,width:20}:{height:0,width:0}}}); \ No newline at end of file +window.SLB&&SLB.has_child("View.extend_theme")&&SLB.View.extend_theme("slb_baseline",{breakpoints:{small:480,large:1024},offset:function(){var o=document.documentElement.clientWidth>this.get_breakpoint("small")?{width:32,height:55}:{width:0,height:0};return o},margin:function(){var m=document.documentElement.clientWidth>this.get_breakpoint("small")?{height:50,width:20}:{height:0,width:0};return m}}); \ No newline at end of file diff --git a/themes/default/js/prod/client.js b/themes/default/js/prod/client.js index 1400f45..e6eebc3 100644 --- a/themes/default/js/prod/client.js +++ b/themes/default/js/prod/client.js @@ -1 +1 @@ -window.SLB&&SLB.has_child("View.extend_theme")&&function($){SLB.View.extend_theme("slb_default",{transition:{open:function(v,dfr){var l=v.get_layout().hide(),o=v.get_overlay().hide(),thm=this,d=v.dom_get();return d.find(".slb_content").css({width:"",height:""}).find(this.get_tag_selector()).hide(),d.find(".slb_details").height(0),d.show({always:function(){var pos={top_base:$(document).scrollTop()};document.documentElement.clientWidth>thm.get_breakpoint("small")?(pos.top=pos.top_base+$(window).height()/2-l.height()/2,pos.topthis.get_breakpoint("small")){var anims={layout:{opacity:0,top:$(document).scrollTop()+$(window).height()/2},content:{width:0,height:0},speed:"fast"},pos=l.animate(anims.layout,anims.speed).promise(),size=c.animate(anims.content,anims.speed).promise();$.when(pos,size).done(function(){v.get_overlay().fadeOut({always:function(){reset()}})})}else l.css("opacity",0),reset();return dfr.promise()},load:function(v){return v.get_layout().find(".slb_loading").show(),document.documentElement.clientWidth>this.get_breakpoint("small")?v.get_layout().fadeIn().promise():v.get_layout().show().promise()},unload:function(v,dfr){var l=v.get_layout(),det=l.find(".slb_details"),cont=l.find(".slb_content "+this.get_tag_selector());return det.css({height:0}),cont.hide(),$.when(det.promise(),cont.promise()).done(function(){dfr.resolve()}),dfr.promise()},complete:function(v,dfr){var l=v.get_layout(),loader=l.find(".slb_loading"),det=l.find(".slb_details"),det_data=det.find(".slb_data"),c=l.find(".slb_content"),c_tag=c.find(this.get_tag_selector());if(document.documentElement.clientWidth>this.get_breakpoint("small")){var dims_item=this.get_item_dimensions();det.width(dims_item.width);var dims_det_height=det_data.outerHeight();det.width("");var pos={top_base:$(document).scrollTop()};pos.top=pos.top_base+$(window).height()/2-(dims_det_height+dims_item.height)/2,pos.topthm.get_breakpoint("small")&&(pos.top=pos.top_base+$(window).height()/2-l.height()/2,!(pos.topthis.get_breakpoint("small")?(anims={layout:{opacity:0,top:$(document).scrollTop()+$(window).height()/2},content:{width:0,height:0},speed:"fast"},pos=l.animate(anims.layout,anims.speed).promise(),anims=c.animate(anims.content,anims.speed).promise(),$.when(pos,anims).done(function(){v.get_overlay().fadeOut({always:function(){reset()}})})):(l.css("opacity",0),reset()),dfr.promise()},load:function(v){return v.get_layout().find(".slb_loading").show(),(document.documentElement.clientWidth>this.get_breakpoint("small")?v.get_layout().fadeIn():v.get_layout().show()).promise()},unload:function(v,dfr){var v=v.get_layout(),det=v.find(".slb_details"),v=v.find(".slb_content "+this.get_tag_selector());return det.css({height:0}),v.hide(),$.when(det.promise(),v.promise()).done(function(){dfr.resolve()}),dfr.promise()},complete:function(v,dfr){var dims_item,dims_det_height,pos,thm,v=v.get_layout(),loader=v.find(".slb_loading"),det=v.find(".slb_details"),det_data=det.find(".slb_data"),c=v.find(".slb_content"),c_tag=c.find(this.get_tag_selector());return document.documentElement.clientWidth>this.get_breakpoint("small")?(dims_item=this.get_item_dimensions(),det.width(dims_item.width),dims_det_height=det_data.outerHeight(),det.width(""),(pos={top_base:$(document).scrollTop()}).top=pos.top_base+$(window).height()/2-(dims_det_height+dims_item.height)/2,pos.top