diff --git a/.gitignore b/.gitignore index 8f025dc9..0b38f535 100644 --- a/.gitignore +++ b/.gitignore @@ -3,13 +3,3 @@ node_modules/ dist/ .vite/ coverage/ - -# Build artifacts -dev/ -min/ - -# Generated test files -test/extracted/ - -# Temporary test files -test-build.html diff --git a/min/Ox.js b/min/Ox.js index 6e827102..99bb5379 100644 --- a/min/Ox.js +++ b/min/Ox.js @@ -1,2 +1,310 @@ -/* OxJS v0.2.0 | (c) 2024 0x2620 | MIT License | oxjs.org */ -!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).Ox={})}(this,function(exports){"use strict";function typeOf(e){const t=Object.prototype.toString.call(e).slice(8,-1).toLowerCase();if("object"===t){if(null===e)return"null";if(e instanceof Array)return"array";if(e instanceof Date)return"date";if(e instanceof RegExp)return"regexp"}return"number"===t&&isNaN$1(e)?"nan":t}function isArray(e){return Array.isArray(e)}function isBoolean(e){return"boolean"==typeof e}function isDate(e){return e instanceof Date&&!isNaN$1(e)}function isDefined(e){return void 0!==e}function isElement(e){return!(!e||1!==e.nodeType)}function isEmpty$1(e){return null==e||(isArray(e)||isString(e)?0===e.length:!!isObject(e)&&0===Object.keys(e).length)}function isEqual(e,t){if(e===t)return!0;const n=typeOf(e);if(n!==typeOf(t))return!1;if("array"===n){if(e.length!==t.length)return!1;for(let n=0;nt):[]}function values$1(e){return isObject(e)?Object.values(e):isArray(e)?[...e]:isString(e)?e.split(""):[]}const STACK_LENGTH=5e4;function slice(e,t,n){try{const r=Array.prototype.slice.call(e,t,n);if(0===r.length&&e.length>0)throw new Error("Broken slice implementation");return r}catch(r){const a=void 0===n?[t]:[t,n],o=[];let i,s;for("string"===typeOf(e)&&(e=e.split("")),s=e.length,i=0;i{"string"==typeof e?r.appendChild(document.createTextNode(e)):e&&r.appendChild(e)}),r}var DOM={documentReady:documentReady,$:$,createElement:createElement},DOMUtils=Object.freeze({__proto__:null,$:$,createElement:createElement,default:DOM,documentReady:documentReady});async function getFile(e,t){try{const n=await fetch(e),r=await n.text();return t&&t(r),r}catch(n){return console.error("Failed to get file:",e,n),t&&t(null),null}}async function getJSON(e,t){try{const n=await fetch(e),r=await n.json();return t&&t(r),r}catch(n){return console.error("Failed to get JSON:",e,n),t&&t(null),null}}async function post(e,t,n){try{const r=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(t)}),a=await r.json();return n&&n(a),a}catch(t){return console.error("Failed to post:",e,t),n&&n(null),null}}var Request={getFile:getFile,getJSON:getJSON,post:post},RequestUtils=Object.freeze({__proto__:null,default:Request,getFile:getFile,getJSON:getJSON,post:post});let LOCALE="en";const LOCALES={};async function setLocale(e,t){LOCALE=e,t&&t()}function _(e,t={}){return e}var Locale={LOCALE:LOCALE,LOCALES:LOCALES,setLocale:setLocale,_:_},LocaleUtils=Object.freeze({__proto__:null,get LOCALE(){return LOCALE},LOCALES:LOCALES,_:_,default:Locale,setLocale:setLocale});function wrap(e){return{value:e,_wrapped:!0}}const Core={wrap:wrap};function localStorage(e){let t;try{t=window.localStorage||{},t.setItem("OxJS.test",""),t.removeItem("OxJS.test")}catch(e){t={}}function n(r,a){let o;if(0===arguments.length){o={};for(const n in t)n.startsWith(e+".")&&(o[n.slice(e.length+1)]=JSON.parse(t[n]))}else if(1===arguments.length&&"string"==typeof r){const n=t[e+"."+r];o=void 0===n?void 0:JSON.parse(n)}else{const i="object"==typeof r?r:{[r]:a};for(const[n,r]of Object.entries(i))t[e+"."+n]=JSON.stringify(r);o=n}return o}return n.delete=function(...r){return(0===r.length?Object.keys(n()):r).forEach(n=>{delete t[e+"."+n]}),n},n}function loop(...e){const t=e.length,n=t>2?e[0]:0,r=e[t>2?1:0],a=4===t?e[2]:n<=r?1:-1,o=e[t-1];let i;for(i=n;(a>0?ir)&&!1!==o(i);i+=a);return i}function cache(e,t){var n={},r=(t=t||{}).async,a=t.key||JSON.stringify;return function(){var t=Array.prototype.slice.call(arguments),o=r?t.pop():null,i=a(t);if(i in n){if(!r)return n[i];setTimeout(function(){o(n[i])},0)}else{if(!r)return n[i]=e.apply(this,t);e.apply(this,t.concat(function(e){n[i]=e,o(e)}))}}}function debounce(e,t,n){var r;return function(){var a=this,o=arguments,i=n&&!r;clearTimeout(r),r=setTimeout(function(){r=null,n||e.apply(a,o)},t),i&&e.apply(a,o)}}function sequence(){var e=Array.prototype.slice.call(arguments);return function(){var t=Array.prototype.slice.call(arguments),n=this;e.forEach(function(e){e.apply(n,t)})}}function throttle(e,t){var n,r,a,o,i=0,s=function(){i=Date.now(),n=null,o=e.apply(r,a),n||(r=a=null)};return function(){var u=Date.now(),c=t-(u-i);return r=this,a=arguments,c<=0||c>t?(n&&(clearTimeout(n),n=null),i=u,o=e.apply(r,a),n||(r=a=null)):n||(n=setTimeout(s,c)),o}}function bind(e,t){var n=Array.prototype.slice.call(arguments,2);return function(){return e.apply(t,n.concat(Array.prototype.slice.call(arguments)))}}function identity(e){return e}function noop(){}function once(e){var t,n=!1;return function(){return n||(n=!0,t=e.apply(this,arguments)),t}}function constant(e){return function(){return e}}function compose(){var e=Array.prototype.slice.call(arguments);return function(){for(var t=Array.prototype.slice.call(arguments),n=e.length-1;n>=0;n--)t=[e[n].apply(this,t)];return t[0]}}function pipe(){var e=Array.prototype.slice.call(arguments);return function(){for(var t=Array.prototype.slice.call(arguments),n=0;n!r.includes(e)))},n.log=function(...e){if(!t.filterEnabled||t.filter.includes(e[0])){const t=new Date,n=`${t.toTimeString().split(" ")[0]}.${t.getMilliseconds().toString().padStart(3,"0")}`;return e.unshift(n),window.console&&window.console.log&&window.console.log(...e),e.join(" ")}}}();var Function={cache:cache,debounce:debounce,sequence:sequence,throttle:throttle,bind:bind,identity:identity,noop:noop,once:once,constant:constant,compose:compose,pipe:pipe,memoize:memoize,partial:partial},FunctionUtils=Object.freeze({__proto__:null,bind:bind,cache:cache,compose:compose,constant:constant,debounce:debounce,default:Function,identity:identity,memoize:memoize,noop:noop,once:once,partial:partial,pipe:pipe,sequence:sequence,throttle:throttle});function applyPolyfills(){Array.isArray||(Array.isArray=function(e){return"[object Array]"===Object.prototype.toString.call(e)}),Array.prototype.forEach||(Array.prototype.forEach=function(e,t){var n,r;if(null==this)throw new TypeError("this is null or not defined");var a=Object(this),o=a.length>>>0;if("function"!=typeof e)throw new TypeError(e+" is not a function");for(arguments.length>1&&(n=t),r=0;r>>0;if("function"!=typeof e)throw new TypeError(e+" is not a function");for(arguments.length>1&&(n=t),r=new Array(i),a=0;a>>0;if("function"!=typeof e)throw new TypeError;for(var r=[],a=arguments.length>=2?arguments[1]:void 0,o=0;o>>0;if(0===a)return-1;var o=+t||0;if(Math.abs(o)===1/0&&(o=0),o>=a)return-1;for(n=Math.max(o>=0?o:a-Math.abs(o),0);n=0?n:n+t}function rad(e){return e*Math.PI/180}function random(e,t){return 0===arguments.length?Math.random():1===arguments.length?Math.floor(Math.random()*e):e+Math.floor(Math.random()*(t-e))}function round(e,t){var n=Math.pow(10,t||0);return Math.round(e*n)/n}function sign(e){return e>0?1:e<0?-1:0}function sinh(e){return(Math.exp(e)-Math.exp(-e))/2}function sum$1(e){return e.reduce(function(e,t){return e+(isNumber(t)?t:0)},0)}function tanh(e){return sinh(e)/cosh(e)}function getBearing(e,t){var n=rad(e.lat),r=rad(t.lat),a=rad(e.lng),o=rad(t.lng),i=Math.sin(o-a)*Math.cos(r),s=Math.cos(n)*Math.sin(r)-Math.sin(n)*Math.cos(r)*Math.cos(o-a);return(deg(Math.atan2(i,s))+360)%360}function getCenter(e){var t=0,n=0;return e.forEach(function(e){t+=e.lat,n+=e.lng}),{lat:t/e.length,lng:n/e.length}}function getCircle(e,t,n){var r=360/(n=n||36);return Array.from({length:n},function(n,a){return getPoint(e,r*a,t)})}function getDistance(e,t){var n=rad(e.lat),r=rad(t.lat),a=rad(t.lat-e.lat),o=rad(t.lng-e.lng),i=Math.sin(a/2)*Math.sin(a/2)+Math.cos(n)*Math.cos(r)*Math.sin(o/2)*Math.sin(o/2);return 6371e3*(2*Math.atan2(Math.sqrt(i),Math.sqrt(1-i)))}function getPoint(e,t,n){var r=rad(e.lat),a=rad(e.lng);t=rad(t),n/=6371e3;var o=Math.asin(Math.sin(r)*Math.cos(n)+Math.cos(r)*Math.sin(n)*Math.cos(t)),i=a+Math.atan2(Math.sin(t)*Math.sin(n)*Math.cos(r),Math.cos(n)-Math.sin(r)*Math.sin(o));return{lat:deg(o),lng:deg(i)}}var Math$1={acosh:acosh,asinh:asinh,atanh:atanh,cosh:cosh,deg:deg,divmod:divmod,limit:limit,log:log,mod:mod,rad:rad,random:random,round:round,sign:sign,sinh:sinh,sum:sum$1,tanh:tanh,getBearing:getBearing,getCenter:getCenter,getCircle:getCircle,getDistance:getDistance,getPoint:getPoint},MathUtils=Object.freeze({__proto__:null,acosh:acosh,asinh:asinh,atanh:atanh,cosh:cosh,default:Math$1,deg:deg,divmod:divmod,getBearing:getBearing,getCenter:getCenter,getCircle:getCircle,getDistance:getDistance,getPoint:getPoint,limit:limit,log:log,mod:mod,rad:rad,random:random,round:round,sign:sign,sinh:sinh,sum:sum$1,tanh:tanh});function capitalize(e){return e.charAt(0).toUpperCase()+e.slice(1)}function clean(e){return e.replace(/\s+/g," ").replace(/^\s+|\s+$/g,"")}function endsWith$1(e,t){return e.slice(-t.length)===t}function format(e,...t){return e.replace(/\{(\d+)\}/g,function(e,n){return isUndefined(t[n])?e:t[n]})}function isValidEmail(e){return/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}$/i.test(e)}function lowercase(e){return e.toLowerCase()}function pad$1(e,t,n,r){e=String(e),n=n||" ",r=r||"left";var a=Math.max(0,t-e.length),o=repeat(n,Math.ceil(a/n.length)).slice(0,a);return"left"===r||"both"===r?o+e:e+o}function parsePath$1(e){var t=/^(.+\/)?(.+?)(\.[^.]+)?$/.exec(e)||[];return{pathname:e,dirname:t[1]||"",filename:t[2]||"",extension:t[3]?t[3].slice(1):""}}function parseURL(e){var t=/^(?:(https?:)\/\/)?([\w.-]+)(:\d+)?(\/[^?#]*)?(\?[^#]*)?(#.*)?$/.exec(e)||[];return{protocol:t[1]||"",hostname:t[2]||"",port:t[3]?t[3].slice(1):"",pathname:t[4]||"/",search:t[5]||"",hash:t[6]||""}}function removeHTML(e){return e.replace(/<[^>]*>/g,"")}function repeat(e,t){return new Array(t+1).join(e)}function reverse(e){return e.split("").reverse().join("")}function startsWith$1(e,t){return e.slice(0,t.length)===t}function stripTags$1(e){return e.replace(/<[^>]+>/g,"")}function toCamelCase(e){return e.replace(/-(.)/g,function(e,t){return t.toUpperCase()})}function toDashes(e){return e.replace(/[A-Z]/g,function(e){return"-"+e.toLowerCase()})}function toNumber(e){return+e}function toTitleCase(e){return e.replace(/\w\S*/g,function(e){return e.charAt(0).toUpperCase()+e.slice(1).toLowerCase()})}function toUnderscores(e){return e.replace(/[A-Z]/g,function(e){return"_"+e.toLowerCase()})}function truncate(e,t,n,r){if(n=n||"...",r=r||"right",e.length<=t)return e;if(t=Math.max(t-n.length,0),"left"===r)return n+e.slice(-t);if("center"===r){var a=Math.ceil(t/2),o=Math.floor(t/2);return e.slice(0,a)+n+e.slice(-o)}return e.slice(0,t)+n}function uppercase(e){return e.toUpperCase()}function words(e){return e.split(/\s+/).filter(function(e){return e.length>0})}function wordwrap(e,t,n,r){t=t||80,n=n||"\n";var a=[],o=e.split(" "),i="";return o.forEach(function(e){i&&(i+" "+e).length>t?(a.push(i),i=e):i=i?i+" "+e:e}),i&&a.push(i),a.join(n)}const char=String.fromCharCode;function splice(e,t,n){const r=e.split("");return Array.prototype.splice.apply(r,slice(arguments,1)),r.join("")}var String$1={capitalize:capitalize,clean:clean,endsWith:endsWith$1,format:format,isValidEmail:isValidEmail,lowercase:lowercase,pad:pad$1,parsePath:parsePath$1,parseURL:parseURL,removeHTML:removeHTML,repeat:repeat,reverse:reverse,startsWith:startsWith$1,stripTags:stripTags$1,toCamelCase:toCamelCase,toDashes:toDashes,toNumber:toNumber,toTitleCase:toTitleCase,toUnderscores:toUnderscores,truncate:truncate,uppercase:uppercase,words:words,wordwrap:wordwrap,char:char,splice:splice},StringUtils=Object.freeze({__proto__:null,capitalize:capitalize,char:char,clean:clean,default:String$1,endsWith:endsWith$1,format:format,isValidEmail:isValidEmail,lowercase:lowercase,pad:pad$1,parsePath:parsePath$1,parseURL:parseURL,removeHTML:removeHTML,repeat:repeat,reverse:reverse,splice:splice,startsWith:startsWith$1,stripTags:stripTags$1,toCamelCase:toCamelCase,toDashes:toDashes,toNumber:toNumber,toTitleCase:toTitleCase,toUnderscores:toUnderscores,truncate:truncate,uppercase:uppercase,words:words,wordwrap:wordwrap});function api(e,t){var n,r,a={cache:(t=t||{}).cache,enums:t.enums?(n=t.enums,r={},forEach(n,function(e,t){r[t]=e}),r):{},geo:t.geo,map:t.map||{},sort:t.sort||[],sums:t.sums||[],unique:t.unique||"id"},o=function(t,n){var r,o,s,c={},l={data:{},status:{code:200,text:"ok"}};return(t=t||{}).query?(t.query.conditions=i(t.query.conditions),l.data.items=e.filter(function(e){return u(e,t.query)})):l.data.items=clone(e),t.sort&&l.data.items.length>1&&(o=[],t.sort=(s=t.sort.concat(a.sort),s.map(function(e){return isString(e)?{key:e.slice(1),operator:"+"==e[0]?"+":"-"}:e})).filter(function(e){var t=-1==o.indexOf(e.key);return t&&o.push(e.key),t}),t.sort.forEach(function(e){var t=e.key;a.enums[t]?c[t]=function(e){return a.enums[t].indexOf(e)}:a.map[t]&&(c[t]=a.map[t])}),l.data.items=sortBy$1(l.data.items,t.sort,c)),t.positions?(r={},t.positions.forEach(function(e){r[e]=getIndex(l.data.items,a.unique,e)}),l.data={positions:r}):t.keys?(isUndefined(t.range)||(l.data.items=l.data.items.slice(t.range[0],t.range[1])),t.keys&&(l.data.items=l.data.items.map(function(e){var n={};return t.keys.forEach(function(t){n[t]=e[t]}),n})),l.data={items:l.data.items}):(r={},a.sums.forEach(function(e){r[e]=sum(l.data.items,e)}),l.data=extend(r,{items:l.data.items.length})),n&&n(l),l};function i(e){return e.map(function(e){var t=extend({},e);return t.conditions?t.conditions=i(t.conditions):t.value=isArray(t.value)?t.value.map(s):s(t.value),t})}function s(e){return isString(e)?e.toLowerCase():e}function u(e,t){var n="&"==t.operator;return forEach(t.conditions,function(r){var a=r.conditions?u(e,r):function(e,t){var n=t.key,r=t.operator.replace(/^!/,""),a=t.value,o=map[n]?map[n](e[n],e):e[n],i={"=":function(e,t){return isArray(t)?t.indexOf(e)>-1:isString(e)?e.toLowerCase().indexOf(t)>-1:e===t},"==":function(e,t){return isArray(t)?t.indexOf(e)>-1:e===t},"<":function(e,t){return isString(e)?-1==e.toLowerCase().localeCompare(t):e":function(e,t){return isString(e)?1==e.toLowerCase().localeCompare(t):e>t},">=":function(e,t){return isString(e)?e.toLowerCase().localeCompare(t)>-1:e>=t},"^":function(e,t){return isArray(t)?t.some(function(t){return startsWith(e,t)}):startsWith(e,t)},$:function(e,t){return isArray(t)?t.some(function(t){return endsWith(e,t)}):endsWith(e,t)}}[r](o,a);return"!"==t.operator[0]?!i:i}(e,r);return a&&"|"==t.operator?(n=!0,!1):a||"&"!=t.operator?void 0:(n=!1,!1)}),n}return o.enums=a.enums,o.map=a.map,o.sort=a.sort,o.sums=a.sums,a.cache&&(o=cache(o,{async:!0})),o}function compact(e){return filter(e,function(e){return null!=e})}function count(e,t){return filter(e,t||identity).length}function sort(e,t){var n=getSortValues(t?e.map(t):e);return e.sort(function(e,r){return e=t?t(e):e,r=t?t(r):r,n[e]n[r]?1:0})}function unique(e,t){var n=[];return e.length&&(t?e.forEach(function(e){var r=t(e);n.some(function(e){return t(e)===r})||n.push(e)}):n=e.filter(function(t,n){return e.indexOf(t)==n})),n}function zip(){var e=Array.prototype.slice.call(arguments);return e[0].map(function(t,n){return e.map(function(e){return e[n]})})}function startsWith(e,t){return isString(e)&&0===e.toLowerCase().indexOf(t)}function endsWith(e,t){return isString(e)&&e.toLowerCase().indexOf(t)===e.length-t.length}function getIndex(e,t,n){var r=-1;return e.some(function(e,a){if(e[t]===n)return r=a,!0}),r}function sum(e,t){return e.reduce(function(e,n){return e+(n[t]||0)},0)}function sortBy$1(e,t,n){var r={};return(t=t||[]).forEach(function(t){var a=t.key,o=n&&n[a]?n[a]:identity;r[a]={},e.forEach(function(e){var t=o(e[a],e);r[a][t]||(r[a][t]=getSortValue(isString(t)?t.toLowerCase():t))})}),e.sort(function(e,a){var o=0;return t.some(function(t){var i=t.key,s=n&&n[i]?n[i]:identity,u=s(e[i],e),c=s(a[i],a),l=r[i][u],f=r[i][c];return lf&&(o="+"==t.operator?1:-1),0!==o}),o})}function getSortValue(e){var t=e;return isString(e)&&(t=e.toLowerCase().replace(/^\W+/,"").replace(/\d+/g,function(e){return e.padStart(16,"0")})),t}function getSortValues(e){var t={};return e.forEach(function(e){t[e]||(t[e]=getSortValue(e))}),t}function last$1(e,t){var n;return 1==arguments.length?n=e[e.length-1]:(e[e.length-1]=t,n=e),n}function makeArray(e){var t=typeOf(e);return"arguments"==t||"nodelist"==t?slice(e):"array"==t?e:[e]}function range(){var e=[];return loop.apply(null,slice(arguments).concat(function(t){e.push(t)})),e}var Array$1={api:api,compact:compact,count:count,sort:sort,unique:unique,zip:zip,last:last$1,makeArray:makeArray,range:range,slice:slice,max:max,min:min,forEach:forEach,len:len,map:map,filter:filter,values:values,keyOf:keyOf,isEmpty:isEmpty,contains:contains,random:random,char:char,splice:splice,clean:clean,repeat:repeat,loop:loop},ArrayUtils=Object.freeze({__proto__:null,api:api,char:char,clean:clean,compact:compact,contains:contains,count:count,default:Array$1,filter:filter,forEach:forEach,isEmpty:isEmpty,keyOf:keyOf,last:last$1,len:len,loop:loop,makeArray:makeArray,map:map,max:max,min:min,random:random,range:range,repeat:repeat,slice:slice,sort:sort,splice:splice,unique:unique,values:values,zip:zip});function getDayName(e,t){return["Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"][getDayOfWeek(e,t)]}function getDayOfWeek(e,t){return e=makeDate(e),t?e.getUTCDay():e.getDay()}function getDayOfYear(e,t){const n=(e=makeDate(e))-new Date(Date.UTC(getFullYear(e,t),0,1));return Math.floor(n/864e5)+1}function getDaysInMonth(e,t){return new Date(e,t+1,0).getDate()}function getDaysInYear(e){return isLeapYear(e)?366:365}function getFirstDayOfWeek(e,t){const n=getDayOfWeek(e=makeDate(e),t);return new Date(e.getTime()-864e5*n)}function getFullYear(e,t){return e=makeDate(e),t?e.getUTCFullYear():e.getFullYear()}function getHours(e,t){return e=makeDate(e),t?e.getUTCHours():e.getHours()}function getISODate(e,t){return formatDate$1(e,"%Y-%m-%d",t)}function getISOWeek(e,t){const n=getFullYear(e=makeDate(e),t),r=getFirstThursday(n,t),a=Math.floor((e-r)/6048e5)+1;if(a<1)return getISOWeek(new Date(n-1,11,31),t);if(a>52){if(e>=getFirstThursday(n+1,t))return 1}return a}function getISOYear(e,t){const n=getFullYear(e=makeDate(e),t),r=getISOWeek(e,t);return 1===r&&11===getMonth(e,t)?n+1:r>=52&&0===getMonth(e,t)?n-1:n}function getMinutes(e,t){return e=makeDate(e),t?e.getUTCMinutes():e.getMinutes()}function getMonth(e,t){return e=makeDate(e),t?e.getUTCMonth():e.getMonth()}function getMonthName(e,t){return["January","February","March","April","May","June","July","August","September","October","November","December"][getMonth(e,t)]}function getSeconds(e,t){return e=makeDate(e),t?e.getUTCSeconds():e.getSeconds()}function getMilliseconds(e,t){return e=makeDate(e),t?e.getUTCMilliseconds():e.getMilliseconds()}function getTimezoneOffset(e){return makeDate(e).getTimezoneOffset()}function getTimezoneOffsetString(e){const t=getTimezoneOffset(e),n=t<=0?"+":"-",r=Math.floor(Math.abs(t)/60),a=Math.abs(t)%60;return n+pad(r,2)+":"+pad(a,2)}function getUnixTime(e){return Math.floor(makeDate(e).getTime()/1e3)}function getWeek(e,t){e=makeDate(e);const n=new Date(Date.UTC(getFullYear(e,t),0,1)),r=Math.floor((e-n)/864e5);return Math.ceil((r+getDayOfWeek(n,t)+1)/7)}function isLeapYear(e){return e%4==0&&(e%100!=0||e%400==0)}function isValidDate(e){return e=makeDate(e),!isNaN(e.getTime())}function makeDate(e){return isDate(e)?e:isString(e)||isNumber(e)?new Date(e):isUndefined(e)?new Date:new Date(e)}function formatDate$1(e,t,n){e=makeDate(e);const r={"%a":()=>getDayName(e,n).substr(0,3),"%A":()=>getDayName(e,n),"%b":()=>getMonthName(e,n).substr(0,3),"%B":()=>getMonthName(e,n),"%c":()=>e.toLocaleString(),"%d":()=>pad(getDate(e,n),2),"%e":()=>pad(getDate(e,n),2," "),"%H":()=>pad(getHours(e,n),2),"%I":()=>pad((getHours(e,n)+11)%12+1,2),"%j":()=>pad(getDayOfYear(e,n),3),"%k":()=>pad(getHours(e,n),2," "),"%l":()=>pad((getHours(e,n)+11)%12+1,2," "),"%m":()=>pad(getMonth(e,n)+1,2),"%M":()=>pad(getMinutes(e,n),2),"%p":()=>getHours(e,n)<12?"AM":"PM","%S":()=>pad(getSeconds(e,n),2),"%u":()=>getDayOfWeek(e,n)||7,"%U":()=>pad(getWeek(e,n),2),"%V":()=>pad(getISOWeek(e,n),2),"%w":()=>getDayOfWeek(e,n),"%W":()=>pad(getWeek(e,n),2),"%x":()=>e.toLocaleDateString(),"%X":()=>e.toLocaleTimeString(),"%y":()=>pad(getFullYear(e,n)%100,2),"%Y":()=>getFullYear(e,n),"%z":()=>getTimezoneOffsetString(e),"%Z":()=>"","%%":()=>"%"};return(t=t||"%Y-%m-%d %H:%M:%S").replace(/%[a-zA-Z%]/g,e=>r[e]?r[e]():e)}function parseDate$1(e,t,n){return new Date(e)}function getDate(e,t){return e=makeDate(e),t?e.getUTCDate():e.getDate()}function getDay(e,t){return getDayOfWeek(e,t)}function getISODay(e,t){const n=getDayOfWeek(e,t);return 0===n?7:n}function getDayOfTheYear(e,t){return getDayOfYear(e,t)}function getFirstDayOfTheYear(e,t){const n=getFullYear(e=makeDate(e),t);return new Date(Date.UTC(n,0,1))}function setDate(e,t,n){return e=makeDate(e),n?e.setUTCDate(t):e.setDate(t),e}function setFullYear(e,t,n){return e=makeDate(e),n?e.setUTCFullYear(t):e.setFullYear(t),e}function setMonth(e,t,n){return e=makeDate(e),n?e.setUTCMonth(t):e.setMonth(t),e}function setHours(e,t,n){return e=makeDate(e),n?e.setUTCHours(t):e.setHours(t),e}function setMinutes(e,t,n){return e=makeDate(e),n?e.setUTCMinutes(t):e.setMinutes(t),e}function setSeconds(e,t,n){return e=makeDate(e),n?e.setUTCSeconds(t):e.setSeconds(t),e}function getFirstThursday(e,t){const n=new Date(Date.UTC(e,0,1)),r=(11-getDayOfWeek(n,t))%7;return new Date(n.getTime()+864e5*r)}function pad(e,t,n){n=n||"0";const r=String(e);return n.repeat(Math.max(0,t-r.length))+r}var Date$1={getDayName:getDayName,getDayOfWeek:getDayOfWeek,getDayOfYear:getDayOfYear,getDaysInMonth:getDaysInMonth,getDaysInYear:getDaysInYear,getFirstDayOfWeek:getFirstDayOfWeek,getFullYear:getFullYear,getHours:getHours,getISODate:getISODate,getISOWeek:getISOWeek,getISOYear:getISOYear,getMinutes:getMinutes,getMonth:getMonth,getMonthName:getMonthName,getSeconds:getSeconds,getMilliseconds:getMilliseconds,getTimezoneOffset:getTimezoneOffset,getTimezoneOffsetString:getTimezoneOffsetString,getUnixTime:getUnixTime,getWeek:getWeek,isLeapYear:isLeapYear,isValidDate:isValidDate,makeDate:makeDate,formatDate:formatDate$1,parseDate:parseDate$1,getDate:getDate,getDay:getDay,getISODay:getISODay,getDayOfTheYear:getDayOfTheYear,getFirstDayOfTheYear:getFirstDayOfTheYear,setDate:setDate,setFullYear:setFullYear,setMonth:setMonth,setHours:setHours,setMinutes:setMinutes,setSeconds:setSeconds},DateUtils=Object.freeze({__proto__:null,default:Date$1,formatDate:formatDate$1,getDate:getDate,getDay:getDay,getDayName:getDayName,getDayOfTheYear:getDayOfTheYear,getDayOfWeek:getDayOfWeek,getDayOfYear:getDayOfYear,getDaysInMonth:getDaysInMonth,getDaysInYear:getDaysInYear,getFirstDayOfTheYear:getFirstDayOfTheYear,getFirstDayOfWeek:getFirstDayOfWeek,getFullYear:getFullYear,getHours:getHours,getISODate:getISODate,getISODay:getISODay,getISOWeek:getISOWeek,getISOYear:getISOYear,getMilliseconds:getMilliseconds,getMinutes:getMinutes,getMonth:getMonth,getMonthName:getMonthName,getSeconds:getSeconds,getTimezoneOffset:getTimezoneOffset,getTimezoneOffsetString:getTimezoneOffsetString,getUnixTime:getUnixTime,getWeek:getWeek,isLeapYear:isLeapYear,isValidDate:isValidDate,makeDate:makeDate,parseDate:parseDate$1,setDate:setDate,setFullYear:setFullYear,setHours:setHours,setMinutes:setMinutes,setMonth:setMonth,setSeconds:setSeconds});function last(e){return e[e.length-1]}function sortBy(e,t){return e.slice().sort(function(e,n){var r=Array.isArray(t)?t.map(t=>e[t]):e[t],a=Array.isArray(t)?t.map(e=>n[e]):n[t];return r>a?1:r=1e6?"k":"";return t=isUndefined(t)?8:t,formatNumber((n?e/1e6:e).toPrecision(t))+" "+n+"m²"}function formatCount(e,t,n){return n=(n||t+"s")+(2===e?"{2}":""),(0===e?_("no"):formatNumber(e))+" "+_(1===e?t:n)}function formatCurrency(e,t,n){return t+formatNumber(e,n)}var formatPatterns=[["%",function(){return"%{%}"}],["c",function(){return"%D %r"}],["D",function(){return"%m/%d/%y"}],["ED",function(){return"%ES %T"}],["Ed",function(){return"%ES %R"}],["EL",function(){return _("%A, %B %e, %Y")}],["El",function(){return _("%B %e, %Y")}],["EM",function(){return _("%a, %b %e, %Y")}],["Em",function(){return _("%b %e, %Y")}],["ES",function(){return _("%m/%d/%Y")}],["Es",function(){return _("%m/%d/%y")}],["ET",function(){return _("%I:%M:%S %p")}],["Et",function(){return _("%I:%M %p")}],["F",function(){return"%Y-%m-%d"}],["h",function(){return"%b"}],["R",function(){return"%H:%M"}],["r",function(){return"%I:%M:%S %p"}],["T",function(){return"%H:%M:%S"}],["v",function(){return"%e-%b-%Y"}],["\\+",function(){return"%a %b %e %H:%M:%S %Z %Y"}],["A",function(e,t){return _(WEEKDAYS[(getDay(e,t)+6)%7])}],["a",function(e,t){return _(SHORT_WEEKDAYS[(getDay(e,t)+6)%7])}],["B",function(e,t){return _(MONTHS[getMonth(e,t)])}],["b",function(e,t){return _(SHORT_MONTHS[getMonth(e,t)])}],["C",function(e,t){return Math.floor(getFullYear(e,t)/100).toString()}],["d",function(e,t){return pad$1(getDate(e,t),2)}],["e",function(e,t){return pad$1(getDate(e,t),2," ")}],["G",function(e,t){return getISOYear(e,t)}],["g",function(e,t){return getISOYear(e,t).toString().slice(-2)}],["H",function(e,t){return pad$1(getHours(e,t),2)}],["I",function(e,t){return pad$1((getHours(e,t)+11)%12+1,2)}],["j",function(e,t){return pad$1(getDayOfTheYear(e,t),3)}],["k",function(e,t){return pad$1(getHours(e,t),2," ")}],["l",function(e,t){return pad$1((getHours(e,t)+11)%12+1,2," ")}],["M",function(e,t){return pad$1(getMinutes(e,t),2)}],["m",function(e,t){return pad$1(getMonth(e,t)+1,2)}],["p",function(e,t){return _(AMPM[Math.floor(getHours(e,t)/12)])}],["Q",function(e,t){return Math.floor(getMonth(e,t)/4)+1}],["S",function(e,t){return pad$1(getSeconds(e,t),2)}],["s",function(e,t){return Math.floor((+e-(t?getTimezoneOffset(e):0))/1e3)}],["U",function(e,t){return pad$1(getWeek(e,t),2)}],["u",function(e,t){return getISODay(e,t)}],["V",function(e,t){return pad$1(getISOWeek(e,t),2)}],["W",function(e,t){return pad$1(Math.floor((getDayOfTheYear(e,t)+(getFirstDayOfTheYear(e,t)||7)-2)/7),2)}],["w",function(e,t){return getDay(e,t)}],["X",function(e,t){var n=getFullYear(e,t);return Math.abs(n)+" "+_(BCAD[n<0?0:1])}],["x",function(e,t){var n=getFullYear(e,t);return Math.abs(n)+(n<1e3?" "+_(BCAD[n<0?0:1]):"")}],["Y",function(e,t){return getFullYear(e,t)}],["y",function(e,t){return getFullYear(e,t).toString().slice(-2)}],["Z",function(e,t){return t?"UTC":(e.toString().split("(")[1]||"").replace(")","")}],["z",function(e,t){return t?"+0000":getTimezoneOffsetString(e)}],["n",function(){return"\n"}],["t",function(){return"\t"}],["\\{%\\}",function(){return"%"}]].map(function(e){return[new RegExp("%"+e[0],"g"),e[1]]});function formatDate(e,t,n){return""===e?"":(e=makeDate(e),formatPatterns.forEach(function(r){t=t.replace(r[0],function(){return r[1](e,n)})}),t)}function formatDateRange(e,t,n){t=t||formatDate(new Date,"%Y-%m-%d");var r,a=!1,o=[e,t],i=o.map(function(e){return parseDate(e)}),s=o.map(function(e){var t=compact(/(-?\d+)-?(\d+)?-?(\d+)? ?(\d+)?:?(\d+)?:?(\d+)?/.exec(e));return t.shift(),t.map(function(e){return parseInt(e,10)})}),u=s.map(function(e){return e.length}),c=s[0][0]<0?"%X":"%Y",l=[c,"%B "+c,"%a, %b %e, "+c,"%a, %b %e, "+c+", %H:%M","%a, %b %e, "+c+", %H:%M","%a, %b %e, "+c+", %H:%M:%S"];return u[0]==u[1]&&(a=!0,loop(u[0],function(e){if(e1?"s":""):""})).join(" ")}function formatDegrees(e,t){var n=0,r=e<0?"-":"",a=formatDuration(Math.round(3600*Math.abs(e))).split(":");return 4==a.length&&(n=parseInt(a.shift(),10)),a[0]=24*n+parseInt(a[0],10),(t?"":r)+a[0]+"°"+a[1]+"'"+a[2]+'"'+("lat"==t?e<0?"S":"N":"lng"==t?e<0?"W":"E":"")}function formatDimensions(e,t){return e.map(function(e){return formatNumber(e)}).join(" × ")+(t?" "+t:"")}const formatResolution=formatDimensions;function formatDuration(e){for(var t=last(arguments),n="short"==t||"long"==t?t:"none",r=isNumber(arguments[1])?arguments[1]:0,a=(e=round(Math.abs(e),r),[Math.floor(e/31536e3),Math.floor(e%31536e3/86400),Math.floor(e%86400/3600),Math.floor(e%3600/60),formatNumber(e%60,r)]),o="short"==n?["y","d","h","m","s"]:"long"==n?["year","day","hour","minute","second"]:[],i=[a[0].toString().length,a[0]?3:a[1].toString().length,2,2,r?r+3:2];!a[0]&&a.length>("none"==n?3:1);)a.shift(),o.shift(),i.shift();return filter(map(a,function(e,t){return"none"==n?pad$1(e,"left",i[t],"0"):(isNumber(e)?e:parseFloat(e))?e+("long"==n?" ":"")+_(o[t]+("long"==n?1==e?"":2==e?"s{2}":"s":"")):""})).join("none"==n?":":" ")}function formatISBN(e,t,n){var r="";function a(e){var t=10==e.length?11:10;return(mod(t-sum$1(e.slice(0,-1).split("").map(function(t,n){return 10==e.length?parseInt(t)*(10-n):parseInt(t)*(n%2==0?1:3)})),t)+"").replace("10","X")}return 10==(e=e.toUpperCase().replace(/[^\dX]/g,"")).length&&(e=e.slice(0,-1).replace(/\D/g,"")+e.slice(-1)),10!=e.length&&13!=e.length||e.slice(-1)!=a(e)||(e.length==t?r=e:10!=e.length&&"978"!=e.slice(0,3)||(r=(e=10==e.length?"978"+e:e.slice(3)).slice(0,-1)+a(e))),n?[r.slice(-13,-10),r.slice(-10,-9),r.slice(-9,-6),r.slice(-6,-1),r.slice(-1)].join("-").replace(/^-+/,""):r}function formatNumber(e,t){for(var n=[],r=Math.abs(e).toFixed(t).split(".");r[0];)n.unshift(r[0].slice(-3)),r[0]=r[0].slice(0,-3);return r[0]=n.join(_(",")),(e<0?"-":"")+r.join(_("."))}function formatOrdinal(e){var t=formatNumber(e),n=t.length,r=t[n-1],a=n>1&&"1"==t[n-2],o=n>1&&!a;return t+=_("1"!=r||a?"2"!=r||a?"3"!=r||a?"th"+(contains("123",r)&&a?"{1"+r+"}":""):"rd"+(o?"{23}":""):"nd"+(o?"{22}":""):"st"+(o?"{21}":""))}function formatPercent(e,t,n){return formatNumber(e/t*100,n)+_("%")}function formatRoman(e){var t="";return forEach({M:1e3,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1},function(n,r){for(;e>=n;)t+=r,e-=n}),t}function formatSRT(e){return"\ufeff"+sortBy(e,["in","out"]).map(function(e,t){return[t+1,["in","out"].map(function(t){return formatDuration(e[t],3).replace(".",",")}).join(" --\x3e "),e.text].join("\r\n")}).join("\r\n\r\n")+"\r\n\r\n"}function formatString(e,t,n){return e.replace(/\{([^}]+)\}/g,function(e,r){for(var a,o=r.replace(/\\\./g,"\n").split(".").map(function(e){return e.replace(/\n/g,".")}),i=t||{};o.length;){if(!i[a=o.shift()]){i=null;break}i=i[a]}return null!==i?i:n?"{"+r+"}":""})}function formatUnit(e,t,n){return formatNumber(e,n)+(/^[:%]/.test(t)?"":" ")+t}function formatValue(e,t,n){var r,a=n?1024:1e3,o=PREFIXES.length;return forEach(PREFIXES,function(i,s){if(e1&&r--,a[i]=r<1/6?t+6*(n-t)*r:r<.5?n:r<2/3?t+6*(n-t)*(2/3-r):t})),a.map(function(e){return Math.round(255*e)})}function toHex(e){return e.map(function(e){return pad$1(e.toString(16).toUpperCase(),"left",2,"0")}).join("")}function toRGB(e){return range(3).map(function(t){return parseInt(e.substr(2*t,2),16)})}var ColorUtils=Object.freeze({__proto__:null,hsl:hsl,rgb:rgb,toHex:toHex,toRGB:toRGB});function encodeBase26(e){for(var t="";e;)t=String.fromCharCode(65+(e-1)%26)+t,e=Math.floor((e-1)/26);return t}function decodeBase26(e){return e.toUpperCase().split("").reverse().reduce(function(e,t,n){return e+(t.charCodeAt(0)-64)*Math.pow(26,n)},0)}function encodeBase32(e){return map(e.toString(32),function(e){return BASE_32_DIGITS[parseInt(e,32)]})}function decodeBase32(e){return parseInt(map(e.toUpperCase(),function(e){var t=BASE_32_DIGITS.indexOf(BASE_32_ALIASES[e]||e);return-1==t?" ":t.toString(32)}),32)}function encodeBase64(e){return btoa(encodeBase256(e)).replace(/=/g,"")}function decodeBase64(e){return decodeBase256(atob(e))}function encodeBase128(e){for(var t="";e;)t=char(127&e)+t,e>>=7;return t}function decodeBase128(e){return e.split("").reverse().reduce(function(e,t,n){return e+(t.charCodeAt(0)<<7*n)},0)}function encodeBase256(e){for(var t="";e;)t=char(255&e)+t,e>>=8;return t}function decodeBase256(e){return e.split("").reverse().reduce(function(e,t,n){return e+(t.charCodeAt(0)<<8*n)},0)}function encodeDeflate(e,t){var n,r,a=1+(e=encodeUTF8(e)).length,o=canvas(Math.ceil(a/3),1),i=(3-a%3)%3;for(e=char(i)+e+repeat("ÿ",i),loop(o.data.length,function(t){o.data[t]=t%4<3?e.charCodeAt(t-parseInt(t/4)):255}),o.context.putImageData(o.imageData,0,0),n=(e=atob(o.canvas.toDataURL().split(",")[1])).slice(16,20)+e.slice(29,33),r=e.slice(33,-12);r;)n+=(a=r.slice(0,4))+r.slice(8,12+(a=decodeBase256(a))),r=r.slice(12+a);return t&&t(n),n}function decodeDeflate(e,t){var n,r=new Image,a="‰PNG\r\n\n\0\0\0\rIHDR"+e.slice(0,4)+"\0\0\0\b\0\0\0"+e.slice(4,8),o=e.slice(8);function i(){throw new RangeError("Deflate codec can't decode data.")}for(;o;)a+=(n=o.slice(0,4))+"IDAT"+o.slice(4,8+(n=decodeBase256(n))),o=o.slice(8+n);a+="\0\0\0\0IEND®B`‚",r.onload=function(){e=slice(canvas(r).data).map(function(e,t){return t%4<3?char(e):""}).join("");try{e=decodeUTF8(e.slice(1,-e.charCodeAt(0)||void 0))}catch(e){i()}t(e)},r.onerror=i,r.src="data:image/png;base64,"+btoa(a)}function decodeURICompat(e){return decodeURI(function e(t){return t.toString().replace(/%(?![0-9A-Fa-f]{2})/g,"%25").replace(/(%[0-9A-Fa-f]{2})+/g,function(t){var n,r=t.split("%").slice(1);try{n=decodeURI("%"+r.join("%"))}catch(e){}return n||"%25"+r[0]+e(t.slice(3))})}(e))}function decodeURIComponentCompat(e){return decodeURIComponent(function e(t){return t.toString().replace(/%(?![0-9A-Fa-f]{2})/g,"%25").replace(/(%[0-9A-Fa-f]{2})+/g,function(t){var n,r=t.split("%").slice(1);try{n=decodeURIComponent("%"+r.join("%"))}catch(e){}return n||"%25"+r[0]+e(t.slice(3))})}(e))}function encodeUTF8(e){return map(e,function(e){var t=e.charCodeAt(0);return t<128?e:t<2048?String.fromCharCode(t>>6|192)+String.fromCharCode(63&t|128):String.fromCharCode(t>>12|224)+String.fromCharCode(t>>6&63|128)+String.fromCharCode(63&t|128)})}function decodeUTF8(e){var t,n=0,r=e.length,a="";function o(e,t){throw new RangeError("UTF-8 codec can't decode byte 0x"+e.toString(16).toUpperCase()+" at position "+t)}for(;n=192&&t[0]<240&&n=128&&t[1]<192?t[0]<224?(a+=String.fromCharCode((31&t[0])<<6|63&t[1]),n+=2):t[2]>=128&&t[2]<192?(a+=String.fromCharCode((15&t[0])<<12|(63&t[1])<<6|63&t[2]),n+=3):o(t[2],n+2):o(t[1],n+1):o(t[0],n);return a}function encodeEmailAddress$1(e,t){var n=["mailto:"+e,t||e].map(function(e){return map(e,function(e){var t=e.charCodeAt(0);return":"==e?":":"&#"+(Math.random()<.5?t:"x"+t.toString(16))+";"})});return''+n[1]+""}!function(){function e(t){return t.toString().replace(/%(?![0-9A-Fa-f]{2})/g,"%25").replace(/(%[0-9A-Fa-f]{2})+/g,function(t){var n,r=t.split("%").slice(1);return forEach(range(1,r.length+1),function(a){var o=range(a).map(function(e){return char(parseInt(r[e],16))}).join("");try{return decodeUTF8(o),n=t.slice(0,3*a)+e(t.slice(3*a)),!1}catch(e){}}),n||"%25"+r[0]+e(t.slice(3))})}decodeURIFn=function(t){return decodeURI(e(t))},decodeURIComponentFn=function(t){return decodeURIComponent(e(t))}}();var EncodingUtils=Object.freeze({__proto__:null,decodeBase128:decodeBase128,decodeBase256:decodeBase256,decodeBase26:decodeBase26,decodeBase32:decodeBase32,decodeBase64:decodeBase64,decodeDeflate:decodeDeflate,decodeURI:decodeURICompat,decodeURICompat:decodeURICompat,decodeURIComponent:decodeURIComponentCompat,decodeURIComponentCompat:decodeURIComponentCompat,decodeUTF8:decodeUTF8,encodeBase128:encodeBase128,encodeBase256:encodeBase256,encodeBase26:encodeBase26,encodeBase32:encodeBase32,encodeBase64:encodeBase64,encodeDeflate:encodeDeflate,encodeEmailAddress:encodeEmailAddress$1,encodeUTF8:encodeUTF8});function escapeRegExp(e){return(e+"").replace(/([\/\\^$*+?.\-|(){}[\]])/g,"\\$1")}var RegExpUtils=Object.freeze({__proto__:null,escapeRegExp:escapeRegExp}),defaultTags=[{name:"b"},{name:"bdi"},{name:"code"},{name:"em"},{name:"i"},{name:"q"},{name:"s"},{name:"span"},{name:"strong"},{name:"sub"},{name:"sup"},{name:"u"},{name:"blockquote"},{name:"cite"},{name:"div",optional:["style"],validate:{style:/^direction: rtl$/}},{name:"h1"},{name:"h2"},{name:"h3"},{name:"h4"},{name:"h5"},{name:"h6"},{name:"p"},{name:"pre"},{name:"li"},{name:"ol"},{name:"ul"},{name:"dl"},{name:"dt"},{name:"dd"},{name:"table"},{name:"tbody"},{name:"td"},{name:"tfoot"},{name:"th"},{name:"thead"},{name:"tr"},{name:"[]"},{name:"a",required:["href"],optional:["target"],validate:{href:/^((https?:\/\/|\/|mailto:).*?)/,target:/^_blank$/}},{name:"br"},{name:"iframe",optional:["width","height"],required:["src"],validate:{width:/^\d+$/,height:/^\d+$/,src:/^((https?:\/\/|\/).*?)/}},{name:"img",optional:["width","height"],required:["src"],validate:{width:/^\d+$/,height:/^\d+$/,src:/^((https?:\/\/|\/).*?)/}},{name:"figure"},{name:"figcaption"}],htmlEntities={'"':""","&":"&","'":"'","<":"<",">":">"},regexp={entity:/&[^\s]+?;/g,html:/[<&]/,tag:new RegExp("<\\/?("+["a","b","br","code","i","s","span","u"].join("|")+")\\/?>","gi")},salt=range(2).map(function(){return range(16).map(function(){return char(65+random(26))}).join("")});function addLinksInternal(e,t){return e.replace(/\b((https?:\/\/|www\.).+?)([.,:;!?)\]]*?(\s|$))/gi,function(e,t,n,r){return formatString('{url}{end}',{end:r,prefix:n="www."==n.toLowerCase()?"http://":"",url:t})}).replace(/\b([0-9A-Z.+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,6})\b/gi,'$1')}function decodeHTMLEntitiesInternal(e){return e.replace(new RegExp("("+values(htmlEntities).join("|")+")","g"),function(e){return keyOf(htmlEntities,e)}).replace(/&#([0-9A-FX]+);/gi,function(e,t){return char(/^X/i.test(t)?parseInt(t.slice(1),16):parseInt(t,10))})}function splitHTMLTags(e,t){var n=!1,r=[""];return t=t||[],forEach(e,function(e,a){n||"<"!=e||-1!=t.indexOf(a)||(n=!0,r.push("")),r[r.length-1]+=e,n&&">"==e&&(n=!1,r.push(""))}),r}function addLinks(e,t){var n=!1;return t?splitHTMLTags(e).map(function(e,t){var r=t%2;return r&&(/^'+n[1]+""}function encodeHTMLEntities(e,t){return map(String(e),function(e){var n=e.charCodeAt(0);return n<128?e=e in htmlEntities?htmlEntities[e]:e:t&&(e="&#x"+pad$1(n.toString(16).toUpperCase(),"left",4,"0")+";"),e})}function decodeHTMLEntities(e,t){return t?decodeHTMLEntities(normalizeHTML(e)):decodeHTMLEntitiesInternal(e)}function highlight(e,t,n,r){if(!t)return e;var a=0,o=[],i=[],s=0,u=isRegExp(t)?t:new RegExp(escapeRegExp(t),"gi"),c=['',""],l=[];function f(t){t.forEach(function(t){e=splice(e,t.position,t.length,t.value),i.forEach(function(e){t.position"+r.trim().replace(/"),salt.join(t.length-1)}).replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(e,n,r,a,o){return t.push(n+""+a.trim().replace(/"),salt.join(t.length-1)}).replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,"$2").replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,"$2").replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,function(e,t,n,r,a,o,i,s){return'"+n+""}).replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,'$1').replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,function(e,t){return encodeEmailAddress(t)}).replace(/\n\n/g,"

").replace(new RegExp(salt.join("(\\d+)"),"g"),function(e,n){return t[parseInt(n)]})}function sanitizeHTML(e,t,n){n=n||[];var r={},a=0,o=["img","br"],i={},s={},u={},c=(t=t||defaultTags).map(function(e){return i[e.name]=n.concat(e.required||[]).concat(e.optional||[]),s[e.name]=e.required||[],u[e.name]=e.validate||{},e.name});return contains(c,"[]")&&(e=e.replace(/\[((\/|https?:\/\/|mailto:).+?) (.+?)\]/gi,'$3'),c=c.filter(function(e){return"[]"!=e})),normalizeHTML(e=(e=addLinks(e=splitHTMLTags(e).map(function(e,t){var n,l,f,p,d,g={},m=/([^=\ ]+)="([^"]+)"/g,h=!0;if(t%2&&(d=/<(\/)?([^\ \/]+)(.*?)(\/)?>/g.exec(e))){for(f=!isUndefined(d[1]),p=d[2],l=d[3].trim();n=m.exec(l);)i[p]&&contains(i[p],n[1])&&(g[n[1]]=n[2]);if(f||contains(o,p)||a++,!contains(c,p)||l.length&&isEmpty(g)?h=!1:!f&&s[p]&&s[p].forEach(function(e){isUndefined(g[e])&&(h=!1)}),h&&!isEmpty(g)&&forEach(g,function(e,t){if(!isUndefined(u[p][t])&&!u[p][t].exec(e))return h=!1,!1}),h&&f?h=!r[a]:r[a]=!h,f&&a--,h)return"<"+(f?"/":"")+p+(f||isEmpty(g)?"":" "+values(map(g,function(e,t){return t+'="'+e+'"'})).join(" "))+">"}return encodeHTMLEntities(decodeHTMLEntitiesInternal(e))}).join(""),!0)).replace(/\n\n/g,"

"))}function stripTags(e){return e.replace(/<.*?>/g,"")}var HTMLUtils=Object.freeze({__proto__:null,addLinks:addLinks,decodeHTMLEntities:decodeHTMLEntities,encodeEmailAddress:encodeEmailAddress,encodeHTMLEntities:encodeHTMLEntities,highlight:highlight,normalizeHTML:normalizeHTML,parseMarkdown:parseMarkdown,sanitizeHTML:sanitizeHTML,stripTags:stripTags});function asyncMap(e,t,n,r,a){var o=typeOf(t),i="object"==o?{}:[];a=last$1(arguments),e(t,function(e,t,r,a){n(e,t,r,function(e){i[t]=e,a()})},r=5==arguments.length?r:null,function(){a("string"==o?i.join(""):i)})}function asyncMapFn(e,t,n,r){e=makeArray(e),r=last$1(arguments),n=4==arguments.length?n:null,e.some(Array.isArray)?serialMap(e,function(e,n,r,a){parallelMap(makeArray(e),t,a)},r):parallelMap(e,t,r)}function nonblockingForEach(e,t,n,r,a){var o,i,s,u=0,c=last$1(arguments),l=typeOf(e);r=isFunction(c)?c:arguments[arguments.length-2],e="array"==l||"object"==l?e:slice(e),o="object"==l?Object.keys(e):range(e.length),a=a||1e3,i=len(e),n=5==arguments.length||4==arguments.length&&isFunction(c)?n:null,s=+new Date,function c(){forEach(o.slice(u),function(r){return r in e&&!1===t.call(n,e[r],r,e)?(u=i,!1):(u++,!(+new Date>=s+a)&&void 0)}),u>>=16;n&&a++}while(n)}return o}(e.size.toString());function r(e,t){var n,r,a,o;return o=e[3]+t[3],a=e[2]+t[2]+(o>>16),o&=65535,r=e[1]+t[1]+(a>>16),a&=65535,n=e[0]+t[0]+(r>>16),[n&=65535,r&=65535,a,o]}function a(e,t){return t=t||0,[e.charCodeAt(t+6)+(e.charCodeAt(t+7)<<8),e.charCodeAt(t+4)+(e.charCodeAt(t+5)<<8),e.charCodeAt(t+2)+(e.charCodeAt(t+3)<<8),e.charCodeAt(t+0)+(e.charCodeAt(t+1)<<8)]}!function o(i,s){var u,c=65536,l=new FileReader;l.onload=function(i){var u,l,f=i.target.result,p=f.length-8;for(u=0;u<=p;u+=8)n=r(n,a(f,u));e.size>>32-t}function n(e){var t,n="";for(t=7;t>=0;t--)n+=(e>>>4*t&15).toString(16);return n}var r,a,o,i,s,u,c,l,f,p=new Array(80),d=1732584193,g=4023233417,m=2562383102,h=271733878,y=3285377520,S=(e=encodeUTF8(e)).length,E=new Array;for(a=0;a>>29),E.push(S<<3&4294967295),r=0;r-1){date=new Date();args.unshift(Ox.formatDate(date,'%H:%M:%S.')+(+date).toString().slice(-3));window.console&&window.console.log&&window.console.log.apply(window.console,args);ret=args.join(' ');} +return ret;};return that;}());Ox.loop=function(){var length=arguments.length,start=length>2?arguments[0]:0,stop=arguments[length>2?1:0],step=length==4?arguments[2]:(start<=stop?1:-1),iterator=arguments[length-1],i;for(i=start;step>0?istop;i+=step){if(iterator(i)===false){break;}} +return i;};Ox.print=function(){var args=Ox.slice(arguments),date=new Date();args.unshift(date.toString().split(' ')[4]+'.'+(+date).toString().slice(-3));window.console&&window.console.log.apply(window.console,args);return args.join(' ');};Ox.trace=function(){var args=Ox.slice(arguments);try{throw new Error();}catch(e){if(e.stack){args.push('\n'+Ox.clean(e.stack.split('\n').slice(2).join('\n')));}} +return Ox.print.apply(null,args);};Ox.uid=(function(){var uid=0;return function(){return++uid;};}());Ox.wrap=function(value,chained){var wrapper={chain:function(){wrapper.chained=true;return wrapper;},chained:chained||false,value:function(){return value;}};Ox.methods(Ox).filter(function(method){return method[0]==method[0].toLowerCase();}).forEach(function(method){wrapper[method]=function(){var args=Array.prototype.slice.call(arguments),ret;args.unshift(value);ret=Ox[method].apply(Ox,args);return wrapper.chained?Ox.wrap(ret,true):ret;};});return wrapper;};'use strict';Ox.cache=function(fn,options){var cache={},ret;options=options||{};options.async=options.async||false;options.key=options.key||JSON.stringify;ret=function(){var args=Ox.slice(arguments),key=options.key(args);function callback(){cache[key]=Ox.slice(arguments);Ox.last(args).apply(this,arguments);} +if(options.async){if(!(key in cache)){fn.apply(this,args.slice(0,-1).concat(callback));}else{setTimeout(function(){callback.apply(this,cache[key]);});}}else{if(!(key in cache)){cache[key]=fn.apply(this,args);} +return cache[key];}};ret.clear=function(){if(arguments.length==0){cache={};}else{Ox.makeArray(arguments).forEach(function(key){delete cache[key];});} +return ret;};return ret;};Ox.debounce=function(fn){var args,immediate=Ox.last(arguments)===true,ms=Ox.isNumber(arguments[1])?arguments[1]:250,timeout;return function(){args=arguments;if(!timeout){if(immediate){fn.apply(null,args);args=null;}}else{clearTimeout(timeout);} +timeout=setTimeout(function(){if(args!==null){fn.apply(null,args);} +timeout=null;},ms);};};Ox.identity=function(value){return value;};Ox.noop=function(){var callback=Ox.last(arguments);Ox.isFunction(callback)&&callback();};Ox.once=function(fn){var once=false;return function(){if(!once){once=true;fn.apply(null,arguments);}};};Ox.queue=function(fn,maxThreads){maxThreads=maxThreads||10;var processing=[],queued=[],ret=Ox.cache(function(){var args=Ox.slice(arguments);queued.push({args:args,key:getKey(args)});process();},{async:true,key:getKey}),threads=0;ret.cancel=function(){threads-=processing.length;processing=[];return ret;};ret.clear=function(){threads=0;queued=[];return ret;};ret.reset=function(){return ret.cancel().clear();};function getKey(args){return JSON.stringify(args.slice(0,-1));} +function process(){var n=Math.min(queued.length,maxThreads-threads);if(n){threads+=n;processing=processing.concat(queued.splice(0,n));Ox.parallelForEach(processing,function(value,index,array,callback){var args=value.args,key=value.key;fn.apply(this,args.slice(0,-1).concat(function(result){var index=Ox.indexOf(processing,function(value){return value.key==key;});if(index>-1){processing.splice(index,1);args.slice(-1)[0](result);threads--;} +callback();}));},process);}} +return ret;};Ox.throttle=function(fn,ms){var args,timeout;ms=arguments.length==1?250:ms;return function(){args=arguments;if(!timeout){fn.apply(null,args);args=null;timeout=setTimeout(function(){if(args!==null){fn.apply(null,args);} +timeout=null;},ms);}};};Ox.time=function(fn){var time=new Date();fn();return new Date()-time;};'use strict';(function(window){var canDefineProperty=!!Object.defineProperty&&(function(){try{Object.defineProperty({},'a',{});return true;}catch(e){}}()),chars='ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/',log;Ox.polyfill={};Ox.polyfill.atob=function(string){var binary='',ret='';String(string).replace(/=/g,'').split('').forEach(function(char){binary+=Ox.pad(chars.indexOf(char).toString(2),'left',6,'0');});while(binary.length>=8){ret+=Ox.char(parseInt(binary.slice(0,8),2));binary=binary.slice(8);} +return ret;};Ox.polyfill.btoa=function(string){var binary='',ret='';String(string).split('').forEach(function(char){binary+=Ox.pad(char.charCodeAt(0).toString(2),'left',8,'0');});binary=Ox.pad(binary,Math.ceil(binary.length/6)*6,'0');while(binary){ret+=chars[parseInt(binary.slice(0,6),2)];binary=binary.slice(6);} +return Ox.pad(ret,Math.ceil(ret.length/4)*4,'=');};Ox.polyfill.bind=function(that){if(typeof this!=='function'){throw new TypeError();} +var args=Array.prototype.slice.call(arguments,1),fn=function(){},this_=this,ret=function(){return this_.apply(this instanceof fn?this:that||window,args.concat(Array.prototype.slice.call(arguments)));};fn.prototype=this.prototype;ret.prototype=new fn();return ret;};Ox.polyfill.every=function(iterator,that){if(this===void 0||this===null||typeof iterator!=='function'){throw new TypeError();} +var array=Object(this),i,length=array.length>>>0,ret=true;for(i=0;i>>0,ret=[],value;for(i=0;i>>0;for(i=0;i>>0,ret=-1;for(i=0;i>>0,ret=-1;for(i=length-1;i>=0;i--){if(i in array&&array[i]===value){ret=i;break;}} +return ret;};Ox.polyfill.map=function(iterator,that){if(this===void 0||this===null||typeof iterator!=='function'){throw new TypeError();} +var array=Object(this),i,length=array.length>>>0,ret=new Array(length);for(i=0;i=0;i--){if(i in array){ret=iterator.call(void 0,ret,array[i],i,array);}} +return ret;};Ox.polyfill.some=function(iterator,that){if(this===void 0||this===null||typeof iterator!=='function'){throw new TypeError();} +var array=Object(this),i,length=array.length>>>0,ret=false;for(i=0;i1){keys=[];options.sort=parseSort(options.sort.concat(api.sort)).filter(function(v){var ret=keys.indexOf(v.key)==-1;keys.push(v.key);return ret;});options.sort.forEach(function(v){var key=v.key;if(api.enums[key]){map[key]=function(value){return api.enums[key].indexOf(value.toLowerCase());};}else if(api.map[key]){map[key]=api.map[key];}});if(options.keys||options.positions){result.data.items=sortBy(result.data.items,options.sort,map,options.query);}} +if(options.positions){data={positions:{}};options.positions.forEach(function(id){data.positions[id]=Ox.indexOf(result.data.items,function(item){return item[api.unique]==id;});});result.data=data;}else if(!options.keys){data={};api.sums.forEach(function(key){data[key]=result.data.items.map(function(item){return item[key];});data[key]=Ox.isString(data[key][0])?Ox.unique(data[key]).length:Ox.sum(data[key]);});data.items=result.data.items.length;if(api.geo){data.area=data.items==0?{south:-Ox.MAX_LATITUDE,west:-179,north:Ox.MAX_LATITUDE,east:179}:result.data.items.reduce(function(prev,curr){return{south:Math.min(prev.south,curr.south),west:Math.min(prev.west,curr.west),north:Math.max(prev.north,curr.north),east:Math.max(prev.east,curr.east)};},{south:Ox.MAX_LATITUDE,west:180,north:-Ox.MAX_LATITUDE,east:-180});} +result.data=data;}else{if(!Ox.isEmpty(options.keys)){if(options.keys.indexOf(api.unique)==-1){options.keys.push(api.unique);} +result.data.items=result.data.items.map(function(item){var ret={};options.keys.forEach(function(key){ret[key]=item[key];});return ret;});} +if(options.range){result.data.items=result.data.items.slice(options.range[0],options.range[1]);}} +callback&&callback(result);return result;},ret=Ox.extend(api.cache?Ox.cache(fn,{async:true}):fn,{update:function(updatedItems){items=updatedItems;api.cache&&ret.clear();sortBy.clear();return ret;}}),sortBy=Ox.cache(function sortBy(array,by,map,query){return Ox.sortBy(array,by,map);},{key:function(args){return JSON.stringify([args[1],args[3]]);}});function parseEnums(enums){return Ox.map(enums,function(values){return values.map(function(value){return value.toLowerCase();});});} +function parseConditions(conditions){return conditions.map(function(condition){var key=condition.key,operator=condition.operator,values=Ox.makeArray(condition.value);if(condition.conditions){condition.conditions=parseConditions(condition.conditions);}else{values=values.map(function(value){if(Ox.isString(value)){value=value.toLowerCase();} +if(api.enums[key]&&(operator.indexOf('<')>-1||operator.indexOf('>')>-1)){value=api.enums[key].indexOf(value);} +return value;});condition.value=Ox.isArray(condition.value)?values:values[0];} +return condition;});} +function parseSort(sort){return sort.map(function(sort){return Ox.isString(sort)?{key:sort.replace(/^[\+\-]/,''),operator:sort[0]=='-'?'-':'+'}:sort;});} +function testCondition(item,condition){var key=condition.key,operator=condition.operator.replace('!',''),value=condition.value,not=condition.operator[0]=='!',itemValue=item[key],test={'=':function(a,b){return Ox.isArray(b)?a>=b[0]&&a-1;}):Ox.isString(a)?a.indexOf(b)>-1:a===b;},'==':function(a,b){return Ox.isArray(a)?a.some(function(value){return value===b;}):a===b;},'<':function(a,b){return a':function(a,b){return a>b;},'>=':function(a,b){return a>=b;},'^':function(a,b){return Ox.startsWith(a,b);},'$':function(a,b){return Ox.endsWith(a,b);}};if(Ox.isString(itemValue)){itemValue=itemValue.toLowerCase();}else if(Ox.isArray(itemValue)&&Ox.isString(itemValue[0])){itemValue=itemValue.map(function(value){return value.toLowerCase();});} +if(api.enums[key]&&(operator.indexOf('<')>-1||operator.indexOf('>')>-1)){itemValue=api.enums[key].indexOf(itemValue);} +return test[operator](itemValue,value)==!not;} +function testQuery(item,query){var match=true;Ox.forEach(query.conditions,function(condition){match=(condition.conditions?testQuery:testCondition)(item,condition);if((query.operator=='&'&&!match)||(query.operator=='|'&&match)){return false;}});return match;} +return ret;};Ox.compact=function(array){return array.filter(function(value){return value!=null;});};Ox.find=function(array,string,leading){var matches=[[],[]];string=string.toLowerCase();array.forEach(function(value){var lowerCase=value.toLowerCase(),index=lowerCase.indexOf(string);index>-1&&matches[index==0?0:1][lowerCase==string?'unshift':'push'](value);});return leading?matches[0]:matches[0].concat(matches[1]);};Ox.flatten=function(array){var ret=[];array.forEach(function(value){if(Ox.isArray(value)){ret=ret.concat(Ox.flatten(value));}else{ret.push(value);}});return ret;};Ox.getIndex=function(array,key,value){return Ox.indexOf(array,function(obj){return obj[key]===value;});};Ox.getIndexById=function(array,id){return Ox.getIndex(array,'id',id);};Ox.getObject=function(array,key,value){var index=Ox.getIndex(array,key,value);return index>-1?array[index]:null;};Ox.getObjectById=function(array,id){return Ox.getObject(array,'id',id);};Ox.last=function(array,value){var ret;if(arguments.length==1){ret=array[array.length-1];}else{array[array.length-1]=value;ret=array;} +return ret;};Ox.makeArray=function(value){var ret,type=Ox.typeOf(value);if(type=='arguments'||type=='nodelist'){ret=Ox.slice(value);}else if(type=='array'){ret=value;}else{ret=[value];} +return ret;};Ox.nextValue=function(array,value,direction){var found=false,nextValue;direction=direction||1;direction==-1&&array.reverse();Ox.forEach(array,function(v){if(direction==1?v>value:vb?1:0;});};Ox.sortBy=function(array,by,map){var sortValues={};by=Ox.makeArray(by).map(function(value){return Ox.isString(value)?{key:value.replace(/^[\+\-]/,''),operator:value[0]=='-'?'-':'+'}:value;});map=map||{};return array.sort(function(a,b){var aValue,bValue,index=0,key,ret=0;while(ret==0&&indexbValue){ret=by[index].operator=='+'?1:-1;}else{index++;}} +return ret;});};}());Ox.unique=function(array){return Ox.filter(array,function(value,index){return array.indexOf(value)==index;});};Ox.zip=function(){var args=arguments.length==1?arguments[0]:Ox.slice(arguments),array=[];args[0].forEach(function(value,index){array[index]=[];args.forEach(function(value){array[index].push(value[index]);});});return array;};'use strict';Ox.char=String.fromCharCode;Ox.clean=function(string){return Ox.filter(Ox.map(string.split('\n'),function(string){return string.replace(/\s+/g,' ').trim()||'';})).join('\n');};Ox.codePointAt=function(string,index){var first,length=string.length,ret,second;if(index>=0&&index0xDBFF||index==length-1){ret=first;}else{second=string.charCodeAt(index+1);ret=second<0xDC00||second>0xDFFF?first:((first-0xD800)*0x400)+(second-0xDC00)+0x10000;}} +return ret;};Ox.endsWith=function(string,substring){string=string.toString();substring=substring.toString();return string.slice(string.length-substring.length)==substring;};Ox.fromCodePoint=function(){var ret='';Ox.forEach(arguments,function(number){if(number<0||number>0x10FFFF||!Ox.isInt(number)){throw new RangeError();} +if(number<0x10000){ret+=String.fromCharCode(number);}else{number-=0x10000;ret+=String.fromCharCode((number>>10)+0xD800) ++String.fromCharCode((number%0x400)+0xDC00);}});return ret;};Ox.isValidEmail=function(string){return!!/^[0-9A-Z\.\+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,64}$/i.test(string);};Ox.pad=function(string,position,length,padding){var hasPosition=Ox.isString(arguments[1]),isNumber=Ox.isNumber(arguments[0]),last=Ox.last(arguments);position=hasPosition?arguments[1]:isNumber?'left':'right';length=Math.max(hasPosition?arguments[2]:arguments[1],0);padding=Ox.isString(last)?last:isNumber&&position=='left'?'0':' ';string=string.toString();padding=Ox.repeat(padding,length-string.length);return position=='left'?(padding+string).slice(-length):(string+padding).slice(0,length);};Ox.parseDuration=function(string){return string.split(':').reverse().slice(0,4).reduce(function(p,c,i){return p+(parseFloat(c)||0)*(i==3?86400:Math.pow(60,i));},0);};Ox.parsePath=function(string){var matches=/^(.+\/)?(.+?(\..+)?)?$/.exec(string);return{pathname:matches[1]||'',filename:matches[2]||'',extension:matches[3]?matches[3].slice(1):''};};Ox.parseSRT=function(string,fps){return string.replace(/\r\n/g,'\n').trim().split('\n\n').map(function(block){var lines=block.split('\n'),points;if(lines.length<3){Ox.Log('Core','skip invalid srt block',lines);return{};} +lines.shift();points=lines.shift().split(' --> ').map(function(point){return point.replace(',',':').split(':').reduce(function(previous,current,index){return previous+parseInt(current,10)*[3600,60,1,0.001][index];},0);});if(fps){points=points.map(function(point){return Math.round(point*fps)/fps;});} +return{'in':points[0],out:points[1],text:lines.join('\n')};}).filter(function(block){return!Ox.isEmpty(block);});};Ox.parseURL=(function(){var a=document.createElement('a'),keys=['hash','host','hostname','origin','pathname','port','protocol','search'];return function(string){var ret={};a.href=string;keys.forEach(function(key){ret[key]=a[key];});return ret;};}());Ox.parseUserAgent=function(userAgent){var aliases={browser:{'Firefox':/(Fennec|Firebird|Iceweasel|Minefield|Namoroka|Phoenix|SeaMonkey|Shiretoko)/},system:{'BSD':/(FreeBSD|NetBSD|OpenBSD)/,'Linux':/(CrOS|MeeGo|webOS)/,'Unix':/(AIX|HP-UX|IRIX|SunOS)/}},names={browser:{'chromeframe':'Chrome Frame','MSIE':'Internet Explorer'},system:{'CPU OS':'iOS','iPhone OS':'iOS','Macintosh':'Mac OS X'}},regexps={browser:[/(Camino)\/(\d+)/,/(chromeframe)\/(\d+)/,/(Edge)\/(\d+)/,/(Chrome)\/(\d+)/,/(Epiphany)\/(\d+)/,/(Firefox)\/(\d+)/,/(Galeon)\/(\d+)/,/(Googlebot)\/(\d+)/,/(Konqueror)\/(\d+)/,/(MSIE) (\d+)/,/(Netscape)\d?\/(\d+)/,/(NokiaBrowser)\/(\d+)/,/(Opera) (\d+)/,/(Opera)\/.+Version\/(\d+)/,/(YandexBot)\/(\d+)/,/(YandexMobileBot)\/(\d+)/,/Version\/(\d+).+(Safari)/],system:[/(Android) (\d+)/,/(BeOS)/,/(BlackBerry) (\d+)/,/(Darwin)/,/(BSD) (FreeBSD|NetBSD|OpenBSD)/,/(CPU OS) (\d+)/,/(iPhone OS) (\d+)/,/(Linux).+(CentOS|CrOS|Debian|Fedora|Gentoo|Mandriva|MeeGo|Mint|Red Hat|SUSE|Ubuntu|webOS)/,/(CentOS|CrOS|Debian|Fedora|Gentoo|Mandriva|MeeGo|Mint|Red Hat|SUSE|Ubuntu|webOS).+(Linux)/,/(Linux)/,/(Mac OS X) (10.\d+)/,/(Mac OS X)/,/(Macintosh)/,/(SymbianOS)\/(\d+)/,/(SymbOS)/,/(OS\/2)/,/(Unix) (AIX|HP-UX|IRIX|SunOS)/,/(Unix)/,/(Windows) (NT \d\.\d)/,/(Windows) (95|98|2000|2003|ME|NT|XP)/,/(Windows).+(Win 9x 4\.90)/,/(Windows).+(Win9\d)/,/(Windows).+(WinNT4.0)/]},versions={browser:{},system:{'10.0':'10.0 (Cheetah)','10.1':'10.1 (Puma)','10.2':'10.2 (Jaguar)','10.3':'10.3 (Panther)','10.4':'10.4 (Tiger)','10.5':'10.5 (Leopard)','10.6':'10.6 (Snow Leopard)','10.7':'10.7 (Lion)','10.8':'10.8 (Mountain Lion)','10.9':'10.9 (Mavericks)','10.10':'10.10 (Yosemite)','10.11':'10.11 (El Capitan)','10.12':'10.12 (Sierra)','10.13':'10.13 (High Sierra)','CrOS':'Chrome OS','NT 4.0':'NT 4.0 (Windows NT)','NT 4.1':'NT 4.1 (Windows 98)','Win 9x 4.90':'NT 4.9 (Windows ME)','NT 5.0':'NT 5.0 (Windows 2000)','NT 5.1':'NT 5.1 (Windows XP)','NT 5.2':'NT 5.2 (Windows 2003)','NT 6.0':'NT 6.0 (Windows Vista)','NT 6.1':'NT 6.1 (Windows 7)','NT 6.2':'NT 6.2 (Windows 8)','NT 6.3':'NT 6.3 (Windows 8.1)','NT 6.4':'NT 6.4 (Windows 10)','95':'NT 4.0 (Windows 95)','NT':'NT 4.0 (Windows NT)','98':'NT 4.1 (Windows 98)','ME':'NT 4.9 (Windows ME)','2000':'NT 5.0 (Windows 2000)','2003':'NT 5.2 (Windows 2003)','XP':'NT 5.1 (Windows XP)','Win95':'NT 4.0 (Windows 95)','WinNT4.0':'NT 4.0 (Windows NT)','Win98':'NT 4.1 (Windows 98)'}},userAgentData={};Ox.forEach(regexps,function(regexps,key){userAgentData[key]={name:'',string:'',version:''};Ox.forEach(aliases[key],function(regexp,alias){userAgent=userAgent.replace(regexp,key=='browser'?alias:alias+' $1');});Ox.forEach(regexps,function(regexp){var matches=userAgent.match(regexp),name,string,swap,version;if(matches){matches[2]=matches[2]||'';swap=matches[1].match(/^\d/)||matches[2]=='Linux';name=matches[swap?2:1];version=matches[swap?1:2].replace('_','.');name=names[key][name]||name,version=versions[key][version]||version;string=name;if(version){string+=' '+(['BSD','Linux','Unix'].indexOf(name)>-1?'('+version+')':version);} +userAgentData[key]={name:names[name]||name,string:string,version:versions[version]||version};return false;}});});return userAgentData;};Ox.repeat=function(value,times){var ret;if(Ox.isArray(value)){ret=[];Ox.loop(times,function(){ret=ret.concat(value);});}else{ret=times>=1?new Array(times+1).join(value.toString()):'';} +return ret;};Ox.splice=function(string,index,remove){var array=string.split('');Array.prototype.splice.apply(array,Ox.slice(arguments,1));return array.join('');};Ox.startsWith=function(string,substring){string=string.toString();substring=substring.toString();return string.slice(0,substring.length)==substring;};Ox.toCamelCase=function(string){return string.replace(/[\-\/_][a-z]/g,function(string){return string[1].toUpperCase();});};Ox.toDashes=function(string){return string.replace(/[A-Z]/g,function(string){return'-'+string.toLowerCase();});};Ox.toSlashes=function(string){return string.replace(/[A-Z]/g,function(string){return'/'+string.toLowerCase();});};Ox.toTitleCase=function(string){return string.split(' ').map(function(value){var substring=value.slice(1),lowercase=substring.toLowerCase();if(substring==lowercase){value=value.slice(0,1).toUpperCase()+lowercase;} +return value;}).join(' ');};Ox.toUnderscores=function(string){return string.replace(/[A-Z]/g,function(string){return'_'+string.toLowerCase();});};Ox.truncate=function(string,position,length,padding){var hasPosition=Ox.isString(arguments[1]),last=Ox.last(arguments);position=hasPosition?arguments[1]:'right';length=hasPosition?arguments[2]:arguments[1];padding=Ox.isString(last)?last:'…';if(string.length>length){if(position=='left'){string=padding ++string.slice(padding.length+string.length-length);}else if(position=='center'){string=string.slice(0,Math.ceil((length-padding.length)/2)) ++padding ++string.slice(-Math.floor((length-padding.length)/2));}else if(position=='right'){string=string.slice(0,length-padding.length)+padding;}} +return string;};Ox.words=function(string){var array=string.toLowerCase().split(/\b/),length=array.length,startsWithWord=/\w/.test(array[0]);array.forEach(function(v,i){if(i>0&&i1){max=Ox.max(words.map(function(word){return word.length;}));while(length>max){if(Ox.wordwrap(string,--length,newline).split(newline).length>lines.length){length++;break;}}}} +lines=[''];words.forEach(function(word){var index;if((lines[lines.length-1]+word).length<=length){lines[lines.length-1]+=word+' ';}else{if(word.length<=length){lines.push(word+' ');}else{index=length-lines[lines.length-1].length;lines[lines.length-1]+=word.slice(0,index);while(index-1;};Ox.count=function(collection,value){var count={};Ox.forEach(collection,function(value){count[value]=(count[value]||0)+1;});return value?count[value]||0:count;};Ox.every=function(collection,iterator,that){iterator=iterator||Ox.identity;return Ox.forEach(collection,function(value,key,collection){return!!iterator.call(that,value,key,collection);})==Ox.len(collection);};Ox.filter=function(collection,iterator,that){var ret,type=Ox.typeOf(collection);iterator=iterator||Ox.identity;if(type=='object'||type=='storage'){ret={};Ox.forEach(collection,function(value,key){if(iterator.call(that,value,key,collection)){ret[key]=value;}});}else{ret=Ox.slice(collection).filter(iterator,that);if(type=='string'){ret=ret.join('');}} +return ret;};Ox.forEach=function(collection,iterator,that){var i=0,key,type=Ox.typeOf(collection);if(type=='object'||type=='storage'){for(key in collection){if(Ox.hasOwn(collection,key)&&iterator.call(that,collection[key],key,collection)===false){break;} +i++;}}else{collection=Ox.slice(collection);for(i=0;i-1){ret=collection.splice(key,1)[0];}}else{key=Ox.keyOf(collection,element);if(key){ret=collection[key];delete collection[key];}} +return ret;};Ox.reverse=function(collection){return Ox.isArray(collection)?Ox.clone(collection).reverse():collection.toString().split('').reverse().join('');};Ox.shuffle=function(collection){var keys,ret,type=Ox.typeOf(collection),values;if(type=='object'||type=='storage'){keys=Object.keys(collection);values=Ox.shuffle(Ox.values(collection));ret={};keys.forEach(function(key,index){ret[key]=values[index];});}else{ret=[];Ox.slice(collection).forEach(function(value,index){var random=Math.floor(Math.random()*(index+1));ret[index]=ret[random];ret[random]=value;});if(type=='string'){ret=ret.join('');}} +return ret;};Ox.slice=Ox.toArray=function(collection,start,stop){return Array.prototype.slice.call(collection,start,stop);};if(Ox.slice([0]).length==0||Ox.slice('0')[0]===null||Ox.slice('0')[0]===void 0||!(function(){try{return Ox.slice(document.getElementsByTagName('a'));}catch(error){}}())){Ox.slice=Ox.toArray=function(collection,start,stop){var args=stop===void 0?[start]:[start,stop],array=[],index,length,ret;if(Ox.typeOf(collection)=='string'){collection=collection.split('');} +try{ret=Array.prototype.slice.apply(collection,args);}catch(error){length=collection.length;for(index=0;index1?Ox.slice(arguments):collection;Ox.forEach(collection,function(value){value=+value;ret+=isFinite(value)?value:0;});return ret;};Ox.values=function(collection){var ret,type=Ox.typeOf(collection);if(type=='array'||type=='nodelist'){ret=Ox.slice(collection);}else if(type=='object'||type=='storage'){ret=[];Ox.forEach(collection,function(value){ret.push(value);});}else if(type=='string'){ret=collection.split('');} +return ret;};Ox.walk=function(collection,iterator,that,keys){keys=keys||[];Ox.forEach(collection,function(value,key){var keys_=keys.concat(key);iterator.call(that,value,keys_,collection);Ox.walk(collection[key],iterator,that,keys_);});};'use strict';Ox.acosh=function(x){return Math.log(x+Math.sqrt(x*x-1));};Ox.asinh=function(x){return Math.log(x+Math.sqrt(x*x+1));};Ox.atanh=function(x){return 0.5*Math.log((1+x)/(1-x));};Ox.cosh=function(x){return(Math.exp(x)+Math.exp(-x))/2;};Ox.deg=function(rad){return rad*180/Math.PI;};Ox.hypot=function(){return Math.sqrt(Ox.slice(arguments).reduce(function(sum,number){return sum+number*number;},0));};Ox.limit=function(){var number=arguments[0],min=arguments.length==3?arguments[1]:-Infinity,max=arguments[arguments.length-1];return Math.min(Math.max(number,min),max);};Ox.log=function(number,base){return Math.log(number)/Math.log(base||Math.E);};Ox.mod=function(number,by){return(number%by+by)%by;};Ox.rad=function(deg){return deg*Math.PI/180;};Ox.random=function(){var min=arguments.length==2?arguments[0]:0,max=arguments.length?Ox.last(arguments):2;return min+Math.floor(Math.random()*(max-min));};Ox.round=function(number,decimals){var pow=Math.pow(10,decimals||0);return Math.round(number*pow)/pow;};Ox.sign=function(x){x=+x;return x!==x||x===0?x:x<0?-1:1;};Ox.sinh=function(x){return(Math.exp(x)-Math.exp(-x))/2;};Ox.splitInt=function(number,by){var div=Math.floor(number/by),mod=number%by;return Ox.range(by).map(function(i){return div+(i>by-1-mod);});};Ox.tanh=function(x){return(Math.exp(x)-Math.exp(-x))/(Math.exp(x)+Math.exp(-x));};Ox.trunc=function(x){return~~x;};'use strict';(function(){function asyncMap(forEach,collection,iterator,that,callback){var type=Ox.typeOf(collection),results=type=='object'?{}:[];callback=Ox.last(arguments);that=arguments.length==5?that:null;forEach(collection,function(value,key,collection,callback){iterator(value,key,collection,function(value){results[key]=value;callback();});},that,function(){callback(type=='string'?results.join(''):results);});} +Ox.asyncMap=function(array,iterator,that,callback){array=Ox.makeArray(array);callback=Ox.last(arguments);that=arguments.length==4?that:null;if(array.some(Ox.isArray)){Ox.serialMap(array,function(value,key,array,callback){Ox.parallelMap(Ox.makeArray(value),iterator,callback);},callback);}else{Ox.parallelMap(array,iterator,callback);}};Ox.nonblockingForEach=function(collection,iterator,that,callback,ms){var i=0,keys,last=Ox.last(arguments),n,time,type=Ox.typeOf(collection);callback=Ox.isFunction(last)?last:arguments[arguments.length-2];collection=type=='array'||type=='object'?collection:Ox.slice(collection);keys=type=='object'?Object.keys(collection):Ox.range(collection.length);ms=ms||1000;n=Ox.len(collection);that=arguments.length==5||(arguments.length==4&&Ox.isFunction(last))?that:null;time=+new Date();iterate();function iterate(){Ox.forEach(keys.slice(i),function(key){if(key in collection){if(iterator.call(that,collection[key],key,collection)===false){i=n;return false;}} +i++;if(+new Date()>=time+ms){return false;}});if(i1){v3--;} +if(v3<1/6){rgb[i]=v1+((v2-v1)*6*v3);}else if(v3<0.5){rgb[i]=v2;}else if(v3<2/3){rgb[i]=v1+((v2-v1)*6*(2/3-v3));}else{rgb[i]=v1;}});} +return rgb.map(function(value){return Math.round(value*255);});};Ox.toHex=function(rgb){return rgb.map(function(value){return Ox.pad(value.toString(16).toUpperCase(),'left',2,'0');}).join('');};Ox.toRGB=function(hex){return Ox.range(3).map(function(index){return parseInt(hex.substr(index*2,2),16);});};'use strict';Ox.AMPM=['AM','PM'];Ox.BASE_32_ALIASES={'I':'1','L':'1','O':'0','U':'V'},Ox.BASE_32_DIGITS='0123456789ABCDEFGHJKMNPQRSTVWXYZ';Ox.BCAD=['BC','AD'];Ox.EARTH_RADIUS=6378137;Ox.EARTH_CIRCUMFERENCE=2*Math.PI*Ox.EARTH_RADIUS;Ox.EARTH_SURFACE=4*Math.PI*Math.pow(Ox.EARTH_RADIUS,2);Ox.HTML_ENTITIES={'"':'"','&':'&',"'":''','<':'<','>':'>'};Ox.KEYS={0:'section',8:'backspace',9:'tab',12:'clear',13:'enter',16:'shift',17:'control',18:'alt',20:'capslock',27:'escape',32:'space',33:'pageup',34:'pagedown',35:'end',36:'home',37:'left',38:'up',39:'right',40:'down',45:'insert',46:'delete',47:'help',48:'0',49:'1',50:'2',51:'3',52:'4',53:'5',54:'6',55:'7',56:'8',57:'9',65:'a',66:'b',67:'c',68:'d',69:'e',70:'f',71:'g',72:'h',73:'i',74:'j',75:'k',76:'l',77:'m',78:'n',79:'o',80:'p',81:'q',82:'r',83:'s',84:'t',85:'u',86:'v',87:'w',88:'x',89:'y',90:'z',91:'meta.left',92:'meta.right',93:'meta.right',96:'0.numpad',97:'1.numpad',98:'2.numpad',99:'3.numpad',100:'4.numpad',101:'5.numpad',102:'6.numpad',103:'7.numpad',104:'8.numpad',105:'9.numpad',106:'asterisk.numpad',107:'plus.numpad',109:'minus.numpad',108:'enter.numpad',110:'dot.numpad',111:'slash.numpad',112:'f1',113:'f2',114:'f3',115:'f4',116:'f5',117:'f6',118:'f7',119:'f8',120:'f9',121:'f10',122:'f11',123:'f12',124:'f13',125:'f14',126:'f15',127:'f16',128:'f17',129:'f18',130:'f19',131:'f20',144:'numlock',145:'scrolllock',186:'semicolon',187:'equal',188:'comma',189:'minus',190:'dot',191:'slash',192:'backtick',219:'openbracket',220:'backslash',221:'closebracket',222:'quote',224:'meta'};Ox.LOCALE='en';Ox.LOCALE_NAMES={'ar':'العربية','de':'Deutsch','el':'Ελληνικά','en':'English','fr':'Français','hi':'हिन्दी'};Ox.LOCALES={"Geo":["de","ar"],"Ox":["de","el","hi","ar"],"UI":["de","el","hi","ar"]};Ox.MAX_LATITUDE=Ox.deg(Math.atan(Ox.sinh(Math.PI)));Ox.MIN_LATITUDE=-Ox.MAX_LATITUDE;Ox.MODIFIER_KEYS={altKey:'alt',ctrlKey:'control',shiftKey:'shift',metaKey:'meta'};Ox.MONTHS=['January','February','March','April','May','June','July','August','September','October','November','December'];Ox.SHORT_MONTHS=Ox.MONTHS.map(function(val){return val.slice(0,3);});Ox.PATH=(function(){var index,regexp=/Ox\.js(\?.+|)$/,scripts=document.getElementsByTagName('script'),src;for(index=scripts.length-1;index>=0;index--){src=scripts[index].src;if(regexp.test(src)){return src.replace(regexp,'');}}}());Ox.MODE=Ox.PATH.slice(0,-1).split('/').pop();Ox.PREFIXES=['','K','M','G','T','P'];Ox.SEASONS=['Winter','Spring','Summer','Fall'];Ox.STACK_SIZE=65536;Ox.SYMBOLS={dollar:'\u0024',cent:'\u00A2',pound:'\u00A3',currency:'\u00A4',yen:'\u00A5',bullet:'\u2022',ellipsis:'\u2026',permille:'\u2030',colon:'\u20A1',cruzeiro:'\u20A2',franc:'\u20A3',lira:'\u20A4',naira:'\u20A6',peseta:'\u20A7',won:'\u20A9',sheqel:'\u20AA',dong:'\u20AB',euro:'\u20AC',kip:'\u20AD',tugrik:'\u20AE',drachma:'\u20AF',peso:'\u20B1',guarani:'\u20B2',austral:'\u20B3',hryvnia:'\u20B4',cedi:'\u20B5',tenge:'\u20B8',rupee:'\u20B9',celsius:'\u2103',fahrenheit:'\u2109',pounds:'\u2114',ounce:'\u2125',ohm:'\u2126',kelvin:'\u212A',angstrom:'\u212B',info:'\u2139',arrow_left:'\u2190',arrow_up:'\u2191',arrow_right:'\u2192',arrow_down:'\u2193',home:'\u2196',end:'\u2198','return':'\u21A9',redo:'\u21BA',undo:'\u21BB',page_up:'\u21DE',page_down:'\u21DF',tab:'\u21E5',shift:'\u21E7',capslock:'\u21EA',infinity:'\u221E',control:'\u2303',command:'\u2318',enter:'\u2324',alt:'\u2325','delete':'\u2326',clear:'\u2327',backspace:'\u232B',option:'\u2387',navigate:'\u2388',escape:'\u238B',eject:'\u23CF',space:'\u2423',triangle_up:'\u25B2',triangle_right:'\u25BA',triangle_down:'\u25BC',select:'\u25BE',triangle_left:'\u25C0',diamond:'\u25C6',black_star:'\u2605',white_star:'\u2606',burn:'\u2622',sound:'\u266B',trash:'\u267A',flag:'\u2691',anchor:'\u2693',gear:'\u2699',atom:'\u269B',warning:'\u26A0',voltage:'\u26A1',cut:'\u2702',backup:'\u2707',fly:'\u2708',check:'\u2713',close:'\u2715',ballot:'\u2717',windows:'\u2756',edit:'\uF802',click:'\uF803',apple:'\uF8FF'};Ox.VERSION='0.1.3905';Ox.WEEKDAYS=['Monday','Tuesday','Wednesday','Thursday','Friday','Saturday','Sunday'];Ox.SHORT_WEEKDAYS=Ox.WEEKDAYS.map(function(val){return val.slice(0,3);});'use strict';Ox.$=Ox.element=function $(value){var elements=Ox.isArray(value)?value:Ox.isNodeList(value)?Ox.slice(value):!Ox.isString(value)?[value]:value[0]=='<'?[document.createElement(value.slice(1,-1))]:Ox.slice(document.querySelectorAll(value)),mousewheelEvents=['wheel','mousewheel'],originalMousewheelEvents='onwheel'in document?['wheel']:['mousewheel','DOMMouseScroll','MozMousePixelScroll'],previousDisplay;function getElements($other){return $other.forEach?$other:Ox.range($other.length).map(function(index){return $other[index];});} +function normalizeEvents(args){var ret={};Ox.forEach(Ox.makeObject(args),function(callback,event){if(Ox.contains(mousewheelEvents,event)){originalMousewheelEvents.forEach(function(event){ret[event]=callback;});}else{ret[event]=callback;}});return ret;} +return elements.length?Ox.extend(Ox.zipObject(Ox.range(elements.length),elements),{add:function add($other){elements=Ox.unique(elements.concat($other.elements()));this.length=elements.length;return this;},addClass:function addClass(string){string=Ox.clean(string);elements.forEach(function(element){element.className=Ox.unique(((element.className?element.className+' ':'')+string).split(' ')).join(' ');});return this;},append:function append(){var $others=Ox.slice(arguments);elements.forEach(function(element){$others.forEach(function($other){getElements($other).forEach(function(otherElement){element.appendChild(otherElement);});});});return this;},appendTo:function appendTo($other){getElements($other).forEach(function(otherElement){elements.forEach(function(element){otherElement.appendChild(element);});});return this;},attr:function attr(){var args=arguments,ret;if(args.length==1&&Ox.isString(args[0])){ret=this[0].getAttribute?this[0].getAttribute(args[0]):void 0;return ret===null?void 0:ret;}else{args=Ox.makeObject(args);elements.forEach(function(element){Ox.forEach(args,function(value,key){if(element.setAttribute&&!Ox.contains([false,null,void 0],value)){element.setAttribute(key,value);}});});return this;}},children:function children(selector){var children=Ox.unique(Ox.flatten(elements.map(function(element){return Ox.slice(element.childNodes);})));return Ox.$(selector?children.filter(function(child){return Ox.$(child).is(selector);}):children);},css:function css(){var args=arguments;if(args.length==1&&Ox.isString(args[0])){return elements[0].style[args[0]];}else{elements.forEach(function(element){Ox.forEach(Ox.makeObject(args),function(value,key){element.style[key]=value;});});return this;}},data:function data(){var args;if(arguments.length==1&&Ox.isString(arguments[0])){return element.getAttribute('data-'+arguments[0]);}else{args=Ox.makeObject(arguments);elements.forEach(function(element){Ox.forEach(args,function(value,key){element.setAttribute('data-'+key,value);});});return this;}},elements:elements,eq:function eq(){var that=this;Ox.loop(1,this.length,function(index){delete that[index];});this.elements=[this.elements[index]];this.length=1;return this;},empty:function empty(){return this.html('');},every:function every(){return Array.prototype.every.apply(elements,arguments);},filter:function filter(){return Array.prototype.filter.apply(elements,arguments);},find:function find(selector){return Ox.$(Ox.unique(Ox.flatten(elements.map(function(element){return Ox.slice(element.querySelectorAll(selector||'*'));}))));},forEach:function forEach(){Array.prototype.forEach.apply(elements,arguments);return this;},hasClass:function hasClass(string){return elements.some(function(element){return Ox.contains(element.className.split(' '),string);});},height:function height(){return elements[0][elements[0]==document?'height':elements[0]==window?'innerHeight':'offsetHeight'];},hide:function hide(){previousDisplay=this.css('display');return this.css({display:'none'});},html:function html(string){var html='';if(arguments.length==0){elements.forEach(function(element){html+=element.innerHTML;}) +return html;}else{elements.forEach(function(element){element.innerHTML=string;});return this;}},insertAfter:function insertAfter($other){var nextSibling=$other[0].nextSibling;elements.forEach(function(element){$other[0].parentNode.insertBefore(element,nextSibling);}) +return this;},insertBefore:function insertBefore($other){elements.forEach(function(element){$other[0].parentNode.insertBefore(element,$other[0]);});return this;},is:function is(selector){return elements.some(function(element){var parent=element.parentNode;if(!parent){parent=document.createElement('div');parent.appendChild(element);} +return Ox.contains(parent.querySelectorAll(selector),element);});},length:elements.length,map:function map(){return Array.prototype.map.apply(elements,arguments);},next:function next(){return Ox.$(Ox.unique(Ox.filter(elements.map(function(element){return element.nextSibling;}))));},nextAll:function nextAll(){var siblings=[];elements.forEach(function(element){var sibling=element;while(true){sibling=sibling.nextSibling;if(!sibling){break;} +siblings.push(sibling);}});return Ox.$(Ox.unique(siblings));},off:function off(event,callback){var args=normalizeEvents(arguments);elements.forEach(function(element){Ox.forEach(args,function(callback,event){if(callback){element.removeEventListener(event,callback,false);}else{element['on'+event]=null;}});});return this;},on:function on(){var args=normalizeEvents(arguments);elements.forEach(function(element){Ox.forEach(args,function(callback,event){element.addEventListener(event,callback,false);});});return this;},one:function one(events){var args=Ox.slice(arguments),that=this;Ox.forEach(normalizeEvents(arguments),function(callback,event){that.on(event,function fn(){that.off(event,fn);return callback.apply(that,args);});});return this;},parent:function parent(){return Ox.$(Ox.unique(Ox.compact(elements.map(function(element){return element.parentNode;}))));},parents:function parents(selector){var parents=[];Ox.reverse(elements).forEach(function(element){var parent=element;while(true){parent=parent.parentNode;if(!parent||parent==document){break;} +parents.unshift(parent);}});parents=Ox.unique(parents);return Ox.$(selector?parents.filter(function(parent){return Ox.$(parent).is(selector);}):parents);},prepend:function prepend(){var $others=Ox.slice(arguments).reverse();elements.forEach(function(element){var parent=element.parentNode;$others.forEach(function($other){getElements($other).forEach(function(otherElement){parent.insertBefore(otherElement,parent.firstChild);});});});return this;},prependTo:function prependTo($other){getElements($other).forEach(function(otherElement){var firstChild=otherElement.firstChild +elements.forEach(function(element){otherElement.insertBefore(element,firstChild);});});return this;},prev:function prev(){return Ox.$(Ox.unique(Ox.filter(elements.map(function(element){return element.previousSibling;}))));},prevAll:function prevAll(){var siblings=[];Ox.reverse(elements).forEach(function(element){var sibling=element;while(true){sibling=sibling.previousSibling;if(!sibling){break;} +siblings.unshift(sibling);}});return Ox.$(Ox.unique(siblings));},reduce:function reduce(){return Array.prototype.reduce.apply(elements,arguments);},remove:function remove(){elements.forEach(function(element){if(element.parentNode){element.parentNode.removeChild(element);}});return this;},removeAttr:function removeAttr(){var keys=Ox.makeArray(arguments);elements.forEach(function(element){keys.forEach(function(key){element.removeAttribute(key);});});return this;},removeClass:function removeClass(string){var classNames=Ox.clean(string).split(' ');elements.forEach(function(element){element.className=element.className.split(' ').filter(function(className){return!Ox.contains(classNames,className)}).join(' ');});return this;},replace:function replace($other){getElements($other).forEach(function(otherElement){var parent=otherElement.parentNode,sibling=otherElement.nextSibling;if(parent){parent.removeChild(otherElement);elements.forEach(function(element){parent.insertBefore(element,sibling)});}});return this;},replaceWith:function replaceWith($other){elements.forEach(function(element){var parent=element.parentNode,sibling=element.nextSibling;if(parent){parent.removeChild(element);getElements($other).forEach(function(otherElement){parent.insertBefore(otherElement,sibling);});}});return this;},show:function show(){return this.css({display:previousDisplay||'block'});},siblings:function siblings(selector){var siblings=Ox.unique(elements.map(function(element){return Ox.filter(element.parentNode.childNodes,function(sibling){return sibling!==element;});}));return Ox.$(selector?siblings.filter(function(sibling){return Ox.$(sibling).is(selector);}):siblings);},some:function some(){return Array.prototype.some.apply(elements,arguments);},text:function text(string){var text='';if(arguments.length==0){elements.forEach(function(element){text+=Ox.isString(element.textContent)?element.textContent:element.innerText;});return text;}else{elements.forEach(function(element){element.empty();element.appendChild(document.createTextNode(string));});return this;}},toggle:function toggle(){return this[Ox.$(element).css('display')=='none'?'show':'hide']();},toggleClass:function toggleClass(string){elements.forEach(function(element){var $element=Ox.$(element);$element[$element.hasClass(string)?'removeClass':'addClass'](string);}) +return this;},trigger:function trigger(event){elements.forEach(function(element){var e=document.createEvent('MouseEvents');e.initEvent(event,true,true);element.dispatchEvent(e);});return this;},val:function val(value){var ret;if(arguments.length==0){return elements[0].value;}else{elements.forEach(function(element){element.value=value;});return this;}},width:function width(){return elements[0][elements[0]==document?'width':elements[0]==window?'innerWidth':'offsetWidth'];}}):null;};Ox.canvas=function(){var c={},isImage=arguments.length==1,image=isImage?arguments[0]:{width:arguments[0],height:arguments[1]};c.context=(c.canvas=Ox.$('').attr({width:image.width,height:image.height})[0]).getContext('2d');isImage&&c.context.drawImage(image,0,0);c.data=(c.imageData=c.context.getImageData(0,0,image.width,image.height)).data;return c;};Ox.documentReady=(function(){var callbacks=[];document.onreadystatechange=window.onload=function(){if(document.readyState=='complete'){callbacks.forEach(function(callback){callback();});document.onreadystatechange=window.onload=null;}};return function(callback){if(document.readyState=='complete'){callback();return true;}else{callbacks.push(callback);return false;}};}());'use strict';Ox.getDateInWeek=function(date,weekday,utc){date=Ox.makeDate(date);var sourceWeekday=Ox.getISODay(date,utc),targetWeekday=Ox.isNumber(weekday)?weekday:Ox.indexOf(Ox.WEEKDAYS,function(v){return v.slice(0,3)==weekday.slice(0,3);})+1;return Ox.setDate(date,Ox.getDate(date,utc)-sourceWeekday+targetWeekday,utc);};Ox.getDayOfTheYear=function(date,utc){date=Ox.makeDate(date);var month=Ox.getMonth(date,utc),year=Ox.getFullYear(date,utc);return Ox.sum(Ox.range(month).map(function(i){return Ox.getDaysInMonth(year,i+1);}))+Ox.getDate(date,utc);};Ox.getDaysInMonth=function(year,month){year=Ox.makeYear(year);month=Ox.isNumber(month)?month:Ox.indexOf(Ox.MONTHS,function(v){return v.slice(0,3)==month.slice(0,3);})+1;return new Date(year,month,0,1).getDate();};Ox.getDaysInYear=function(year,utc){return 365+Ox.isLeapYear(Ox.makeYear(year,utc));};Ox.getFirstDayOfTheYear=function(date,utc){date=Ox.makeDate(date);date=Ox.setMonth(date,0,utc);date=Ox.setDate(date,1,utc);return Ox.getDay(date,utc);};Ox.getISODate=function(date,utc){return Ox.formatDate(Ox.makeDate(date),'%FT%TZ',utc);};Ox.getISODay=function(date,utc){return Ox.getDay(Ox.makeDate(date),utc)||7;};Ox.getISOWeek=function(date,utc){date=Ox.makeDate(date);return Math.floor((Ox.getDayOfTheYear(Ox.setDate(date,Ox.getDate(date,utc)-Ox.getISODay(date,utc)+4,utc),utc)-1)/7)+1;};Ox.getISOYear=function(date,utc){date=Ox.makeDate(date);return Ox.getFullYear(Ox.setDate(date,Ox.getDate(date,utc)-Ox.getISODay(date,utc)+4,utc));};Ox.getTime=function(utc){return+new Date()-(utc?Ox.getTimezoneOffset():0);};Ox.getTimezoneOffset=function(date){return Ox.makeDate(date).getTimezoneOffset()*60000;};Ox.getTimezoneOffsetString=function(date){var offset=Ox.makeDate(date).getTimezoneOffset();return(offset<=0?'+':'-') ++Ox.pad(Math.floor(Math.abs(offset)/60),2) ++Ox.pad(Math.abs(offset)%60,2);};Ox.getWeek=function(date,utc){date=Ox.makeDate(date);return Math.floor((Ox.getDayOfTheYear(date,utc) ++Ox.getFirstDayOfTheYear(date,utc)-1)/7);};Ox.isLeapYear=function(year,utc){year=Ox.makeYear(year,utc);return year%4==0&&(year%100!=0||year%400==0);};Ox.makeDate=function(date){if(Ox.isString(date)&&Ox.isInvalidDate(new Date(date))){if(/^\d{4}$/.test(date)){date+='-01-01';}else if(/^\d{4}-\d{2}$/.test(date)){date+='-01';}else if(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/.test(date)){date=date.replace(/T/,' ').replace(/Z/,'');} +date=date.replace(/-/g,'/');} +return Ox.isUndefined(date)?new Date():new Date(date);};Ox.makeYear=function(date,utc){return Ox.isDate(date)?Ox.getFullYear(date,utc):parseInt(date,10);};Ox.parseDate=function(string,utc){var date,defaults=[,1,1,0,0,0,0],values=/(-?\d+)-?(\d+)?-?(\d+)? ?(\d+)?:?(\d+)?:?(\d+)?\.?(\d+)?/.exec(string);if(values){values.shift();date=new Date();values=values.map(function(v,i){return v?(i==6?Ox.pad(v,3,'0'):v):defaults[i];});values[1]--;['FullYear','Month','Date','Hours','Minutes','Seconds','Milliseconds'].forEach(function(part,i){Ox['set'+part](date,values[i],utc);});}else{date=null;} +return date;};['FullYear','Month','Date','Day','Hours','Minutes','Seconds','Milliseconds'].forEach(function(part){Ox['get'+part]=function(date,utc){return Ox.makeDate(date)['get'+(utc?'UTC':'')+part]();};Ox['set'+part]=function(date,num,utc){return(Ox.isDate(date)?date:new Date(date))['set'+(utc?'UTC':'')+part](num);};});'use strict';Ox.encodeBase26=function(number){var string='';while(number){string=String.fromCharCode(65+(number-1)%26)+string;number=Math.floor((number-1)/26);} +return string;};Ox.decodeBase26=function(string){return string.toUpperCase().split('').reverse().reduce(function(p,c,i){return p+(c.charCodeAt(0)-64)*Math.pow(26,i);},0);};Ox.encodeBase32=function(number){return Ox.map(number.toString(32),function(char){return Ox.BASE_32_DIGITS[parseInt(char,32)];});};Ox.decodeBase32=function(string){return parseInt(Ox.map(string.toUpperCase(),function(char){var index=Ox.BASE_32_DIGITS.indexOf(Ox.BASE_32_ALIASES[char]||char);return index==-1?' ':index.toString(32);}),32);};Ox.encodeBase64=function(number){return btoa(Ox.encodeBase256(number)).replace(/=/g,'');};Ox.decodeBase64=function(string){return Ox.decodeBase256(atob(string));};Ox.encodeBase128=function(number){var string='';while(number){string=Ox.char(number&127)+string;number>>=7;} +return string;};Ox.decodeBase128=function(string){return string.split('').reverse().reduce(function(p,c,i){return p+(c.charCodeAt(0)<>=8;} +return string;};Ox.decodeBase256=function(string){return string.split('').reverse().reduce(function(p,c,i){return p+(c.charCodeAt(0)<>6|192) ++String.fromCharCode(code&63|128);}else{string=String.fromCharCode(code>>12|224) ++String.fromCharCode(code>>6&63|128) ++String.fromCharCode(code&63|128);} +return string;});};Ox.decodeUTF8=function(string){var code,i=0,length=string.length,ret='';function error(byte,position){throw new RangeError('UTF-8 codec can\'t decode byte 0x'+byte.toString(16).toUpperCase()+' at position '+position);} +while(i=192&&code[0]<240&&i=128&&code[1]<192){if(code[0]<224){ret+=String.fromCharCode((code[0]&31)<<6|code[1]&63);i+=2;}else if(code[2]>=128&&code[2]<192){ret+=String.fromCharCode((code[0]&15)<<12|(code[1]&63)<<6|code[2]&63);i+=3;}else{error(code[2],i+2);}}else{error(code[1],i+1);}}else{error(code[0],i);}} +return ret;};'use strict';Ox.formatArea=function(number,decimals){var k=number>=1000000?'k':'';decimals=Ox.isUndefined(decimals)?8:decimals;return Ox.formatNumber((k?number/1000000:number).toPrecision(decimals))+' '+k+'m\u00B2';};Ox.formatCount=function(number,singular,plural){plural=(plural||singular+'s')+(number===2?'{2}':'');return(number===0?Ox._('no'):Ox.formatNumber(number)) ++' '+Ox._(number===1?singular:plural);};Ox.formatCurrency=function(number,string,decimals){return string+Ox.formatNumber(number,decimals);};(function(){var format=[['%',function(){return'%{%}';}],['c',function(){return'%D %r';}],['D',function(){return'%m/%d/%y';}],['ED',function(){return'%ES %T';}],['Ed',function(){return'%ES %R';}],['EL',function(){return Ox._('%A, %B %e, %Y');}],['El',function(){return Ox._('%B %e, %Y');}],['EM',function(){return Ox._('%a, %b %e, %Y');}],['Em',function(){return Ox._('%b %e, %Y');}],['ES',function(){return Ox._('%m/%d/%Y');}],['Es',function(){return Ox._('%m/%d/%y');}],['ET',function(){return Ox._('%I:%M:%S %p');}],['Et',function(){return Ox._('%I:%M %p');}],['F',function(){return'%Y-%m-%d';}],['h',function(){return'%b';}],['R',function(){return'%H:%M';}],['r',function(){return'%I:%M:%S %p';}],['T',function(){return'%H:%M:%S';}],['v',function(){return'%e-%b-%Y';}],['\\+',function(){return'%a %b %e %H:%M:%S %Z %Y';}],['A',function(date,utc){return Ox._(Ox.WEEKDAYS[(Ox.getDay(date,utc)+6)%7]);}],['a',function(date,utc){return Ox._(Ox.SHORT_WEEKDAYS[(Ox.getDay(date,utc)+6)%7]);}],['B',function(date,utc){return Ox._(Ox.MONTHS[Ox.getMonth(date,utc)]);}],['b',function(date,utc){return Ox._(Ox.SHORT_MONTHS[Ox.getMonth(date,utc)]);}],['C',function(date,utc){return Math.floor(Ox.getFullYear(date,utc)/100).toString();}],['d',function(date,utc){return Ox.pad(Ox.getDate(date,utc),2);}],['e',function(date,utc){return Ox.pad(Ox.getDate(date,utc),2,' ');}],['G',function(date,utc){return Ox.getISOYear(date,utc);}],['g',function(date,utc){return Ox.getISOYear(date,utc).toString().slice(-2);}],['H',function(date,utc){return Ox.pad(Ox.getHours(date,utc),2);}],['I',function(date,utc){return Ox.pad((Ox.getHours(date,utc)+11)%12+1,2);}],['j',function(date,utc){return Ox.pad(Ox.getDayOfTheYear(date,utc),3);}],['k',function(date,utc){return Ox.pad(Ox.getHours(date,utc),2,' ');}],['l',function(date,utc){return Ox.pad(((Ox.getHours(date,utc)+11)%12+1),2,' ');}],['M',function(date,utc){return Ox.pad(Ox.getMinutes(date,utc),2);}],['m',function(date,utc){return Ox.pad((Ox.getMonth(date,utc)+1),2);}],['p',function(date,utc){return Ox._(Ox.AMPM[Math.floor(Ox.getHours(date,utc)/12)]);}],['Q',function(date,utc){return Math.floor(Ox.getMonth(date,utc)/4)+1;}],['S',function(date,utc){return Ox.pad(Ox.getSeconds(date,utc),2);}],['s',function(date,utc){return Math.floor((+date-(utc?Ox.getTimezoneOffset(date):0))/1000);}],['U',function(date,utc){return Ox.pad(Ox.getWeek(date,utc),2);}],['u',function(date,utc){return Ox.getISODay(date,utc);}],['V',function(date,utc){return Ox.pad(Ox.getISOWeek(date,utc),2);}],['W',function(date,utc){return Ox.pad(Math.floor((Ox.getDayOfTheYear(date,utc) ++(Ox.getFirstDayOfTheYear(date,utc)||7)-2)/7),2);}],['w',function(date,utc){return Ox.getDay(date,utc);}],['X',function(date,utc){var y=Ox.getFullYear(date,utc);return Math.abs(y)+' '+Ox._(Ox.BCAD[y<0?0:1]);}],['x',function(date,utc){var y=Ox.getFullYear(date,utc);return Math.abs(y)+(y<1000?' '+Ox._(Ox.BCAD[y<0?0:1]):'');}],['Y',function(date,utc){return Ox.getFullYear(date,utc);}],['y',function(date,utc){return Ox.getFullYear(date,utc).toString().slice(-2);}],['Z',function(date,utc){return utc?'UTC':(date.toString().split('(')[1]||'').replace(')','');}],['z',function(date,utc){return utc?'+0000':Ox.getTimezoneOffsetString(date);}],['n',function(){return'\n';}],['t',function(){return'\t';}],['\\{%\\}',function(){return'%';}]].map(function(value){return[new RegExp('%'+value[0],'g'),value[1]];});Ox.formatDate=function(date,string,utc){if(date===''){return'';} +date=Ox.makeDate(date);format.forEach(function(value){string=string.replace(value[0],function(){return value[1](date,utc);});});return string;};}());Ox.formatDateRange=function(start,end,utc){end=end||Ox.formatDate(new Date(),'%Y-%m-%d');var isOneUnit=false,range=[start,end],strings,dates=range.map(function(str){return Ox.parseDate(str,utc);}),parts=range.map(function(str){var parts=Ox.compact(/(-?\d+)-?(\d+)?-?(\d+)? ?(\d+)?:?(\d+)?:?(\d+)?/.exec(str));parts.shift();return parts.map(function(part){return parseInt(part,10);});}),precision=parts.map(function(parts){return parts.length;}),y=parts[0][0]<0?'%X':'%Y',formats=[y,'%B '+y,'%a, %b %e, '+y,'%a, %b %e, '+y+', %H:%M','%a, %b %e, '+y+', %H:%M','%a, %b %e, '+y+', %H:%M:%S',];if(precision[0]==precision[1]){isOneUnit=true;Ox.loop(precision[0],function(i){if((i1?'s':''):'';})).join(' ');};Ox.formatDegrees=function(degrees,mode){var days=0,seconds=Math.round(Math.abs(degrees)*3600),sign=degrees<0?'-':'',array=Ox.formatDuration(seconds).split(':');if(array.length==4){days=parseInt(array.shift(),10);} +array[0]=days*24+parseInt(array[0],10);return(!mode?sign:'') ++array[0]+'°'+array[1]+"'"+array[2]+'"' ++(mode=='lat'?(degrees<0?'S':'N'):mode=='lng'?(degrees<0?'W':'E'):'');};Ox.formatDimensions=Ox.formatResolution=function(array,string){return array.map(function(value){return Ox.formatNumber(value);}).join(' × ')+(string?' '+string:'');};Ox.formatDuration=function(seconds){var last=Ox.last(arguments),format=last=='short'||last=='long'?last:'none',decimals=Ox.isNumber(arguments[1])?arguments[1]:0,seconds=Ox.round(Math.abs(seconds),decimals),values=[Math.floor(seconds/31536000),Math.floor(seconds%31536000/86400),Math.floor(seconds%86400/3600),Math.floor(seconds%3600/60),Ox.formatNumber(seconds%60,decimals)],string=format=='short'?['y','d','h','m','s']:format=='long'?['year','day','hour','minute','second']:[],pad=[values[0].toString().length,values[0]?3:values[1].toString().length,2,2,decimals?decimals+3:2];while(!values[0]&&values.length>(format=='none'?3:1)){values.shift();string.shift();pad.shift();} +return Ox.filter(Ox.map(values,function(value,index){var ret;if(format=='none'){ret=Ox.pad(value,'left',pad[index],'0');}else if(Ox.isNumber(value)?value:parseFloat(value)){ret=value+(format=='long'?' ':'')+Ox._(string[index]+(format=='long'?(value==1?'':value==2?'s{2}':'s'):''));}else{ret='';} +return ret;})).join(format=='none'?':':' ');};Ox.formatISBN=function(isbn,length,dashes){var ret='';function getCheckDigit(isbn){var mod=isbn.length==10?11:10 +return(Ox.mod(mod-Ox.sum(isbn.slice(0,-1).split('').map(function(digit,index){return isbn.length==10?parseInt(digit)*(10-index):parseInt(digit)*(index%2==0?1:3);})),mod)+'').replace('10','X');} +isbn=isbn.toUpperCase().replace(/[^\dX]/g,'');if(isbn.length==10){isbn=isbn.slice(0,-1).replace(/\D/g,'')+isbn.slice(-1);} +if((isbn.length==10||isbn.length==13)&&isbn.slice(-1)==getCheckDigit(isbn)){if(isbn.length==length){ret=isbn}else if(isbn.length==10||isbn.slice(0,3)=='978'){isbn=isbn.length==10?'978'+isbn:isbn.slice(3);ret=isbn.slice(0,-1)+getCheckDigit(isbn);}} +return dashes?[ret.slice(-13,-10),ret.slice(-10,-9),ret.slice(-9,-6),ret.slice(-6,-1),ret.slice(-1)].join('-').replace(/^-+/,''):ret;};Ox.formatNumber=function(number,decimals){var array=[],abs=Math.abs(number),split=abs.toFixed(decimals).split('.');while(split[0]){array.unshift(split[0].slice(-3));split[0]=split[0].slice(0,-3);} +split[0]=array.join(Ox._(','));return(number<0?'-':'')+split.join(Ox._('.'));};Ox.formatOrdinal=function(number){var string=Ox.formatNumber(number),length=string.length,last=string[length-1],ten=length>1&&string[length-2]=='1',twenty=length>1&&!ten;if(last=='1'&&!ten){string+=Ox._('st'+(twenty?'{21}':''));}else if(last=='2'&&!ten){string+=Ox._('nd'+(twenty?'{22}':''));}else if(last=='3'&&!ten){string+=Ox._('rd'+(twenty?'{23}':''));}else{string+=Ox._('th'+(Ox.contains('123',last)&&ten?'{1'+last+'}':''));} +return string;};Ox.formatPercent=function(number,total,decimals){return Ox.formatNumber(number/total*100,decimals)+Ox._('%');};Ox.formatRoman=function(number){var string='';Ox.forEach({M:1000,CM:900,D:500,CD:400,C:100,XC:90,L:50,XL:40,X:10,IX:9,V:5,IV:4,I:1},function(value,roman){while(number>=value){string+=roman;number-=value;}});return string;};Ox.formatSRT=function(subtitles){return'\ufeff'+Ox.sortBy(subtitles,['in','out']).map(function(subtitle,index){return[index+1,['in','out'].map(function(key){return Ox.formatDuration(subtitle[key],3).replace('.',',');}).join(' --> '),subtitle['text']].join('\r\n')}).join('\r\n\r\n')+'\r\n\r\n';};Ox.formatString=function(string,collection,keepUnmatched){return string.replace(/\{([^}]+)\}/g,function(string,match){var key,keys=match.replace(/\\\./g,'\n').split('.').map(function(key){return key.replace(/\n/g,'.');}),value=collection||{};while(keys.length){key=keys.shift();if(value[key]){value=value[key];}else{value=null;break;}} +return value!==null?value:keepUnmatched?'{'+match+'}':'';});};Ox.formatUnit=function(number,string,decimals){return Ox.formatNumber(number,decimals) ++(/^[:%]/.test(string)?'':' ')+string;};Ox.formatValue=function(number,string,bin){var base=bin?1024:1000,length=Ox.PREFIXES.length,ret;Ox.forEach(Ox.PREFIXES,function(prefix,index){if(numberpointB.lng;};Ox.getArea=function(pointA,pointB){if(Ox.crossesDateline(pointA,pointB)){pointB.lng+=360;} +pointA=rad(pointA);pointB=rad(pointB);return Math.pow(Ox.EARTH_RADIUS,2)*Math.abs(Math.sin(pointA.lat)-Math.sin(pointB.lat))*Math.abs(pointA.lng-pointB.lng);};Ox.getAverageBearing=function(bearingA,bearingB){return Ox.mod((bearingA+bearingB)/2+(Math.abs(bearingA-bearingB)>180?180:0),360);};Ox.getBearing=function(pointA,pointB){pointA=rad(pointA);pointB=rad(pointB);var x=Math.cos(pointA.lat)*Math.sin(pointB.lat) +-Math.sin(pointA.lat)*Math.cos(pointB.lat)*Math.cos(pointB.lng-pointA.lng),y=Math.sin(pointB.lng-pointA.lng)*Math.cos(pointB.lat);return(Ox.deg(Math.atan2(y,x))+360)%360;};Ox.getBearingDifference=function(bearingA,bearingB){var difference=Math.abs(bearingA-bearingB);return difference>180?360-difference:difference;};Ox.getCenter=function(pointA,pointB){pointA=rad(pointA);pointB=rad(pointB);var x=Math.cos(pointB.lat)*Math.cos(pointB.lng-pointA.lng),y=Math.cos(pointB.lat)*Math.sin(pointB.lng-pointA.lng),d=Math.sqrt(Math.pow(Math.cos(pointA.lat)+x,2)+Math.pow(y,2)),lat=Math.atan2(Math.sin(pointA.lat)+Math.sin(pointB.lat),d),lng=pointA.lng+Math.atan2(y,Math.cos(pointA.lat)+x);return deg({lat:lat,lng:lng});};Ox.getCircle=function(center,radius,precision){return Ox.range(0,360,360/Math.pow(2,precision)).map(function(bearing){return Ox.getPoint(center,radius,bearing);});};Ox.getClosestBearing=function(bearing,bearings){var differences=bearings.map(function(bearing_){return getBearingDifference(bearing,bearing_);});return bearings[differences.indexOf(Ox.min(differences))];};Ox.getDegreesPerMeter=function(lat){return 360/Ox.EARTH_CIRCUMFERENCE/Math.cos(lat*Math.PI/180);};Ox.getDistance=function(pointA,pointB){pointA=rad(pointA);pointB=rad(pointB);return Math.acos(Math.sin(pointA.lat)*Math.sin(pointB.lat) ++Math.cos(pointA.lat)*Math.cos(pointB.lat)*Math.cos(pointB.lng-pointA.lng))*Ox.EARTH_RADIUS;};Ox.getLatLngByXY=function(xy){function getValue(value){return(value-0.5)*2*Math.PI;} +return{lat:-Ox.deg(Math.atan(Ox.sinh(getValue(xy.y)))),lng:Ox.deg(getValue(xy.x))};};Ox.getLine=function(pointA,pointB,precision){var line=[pointA,pointB],points;while(precision>0){points=[line[0]];Ox.loop(line.length-1,function(i){points.push(Ox.getCenter(line[i],line[i+1]),line[i+1]);});line=points;precision--;} +return line;};Ox.getMetersPerDegree=function(lat){return Math.cos(lat*Math.PI/180)*Ox.EARTH_CIRCUMFERENCE/360;};Ox.getPoint=function(point,distance,bearing){var pointB={};point=rad(point);distance/=Ox.EARTH_RADIUS;bearing=Ox.rad(bearing);pointB.lat=Math.asin(Math.sin(point.lat)*Math.cos(distance) ++Math.cos(point.lat)*Math.sin(distance)*Math.cos(bearing));pointB.lng=point.lng+Math.atan2(Math.sin(bearing)*Math.sin(distance)*Math.cos(point.lat),Math.cos(distance)-Math.sin(point.lat)*Math.sin(pointB.lat));return deg(pointB);};Ox.getXYByLatLng=function(latlng){function getValue(value){return value/(2*Math.PI)+0.5;} +return{x:getValue(Ox.rad(latlng.lng)),y:getValue(Ox.asinh(Math.tan(Ox.rad(-latlng.lat))))};};Ox.isPolar=function(point){return point.latOx.MAX_LATITUDE;};Ox.containsArea=function(areaA,areaB){var areas=[areaA,areaB].map(splitArea),ret;function contains(areaA,areaB){return areaA.sw.lat<=areaB.sw.lat&&areaA.sw.lng<=areaB.sw.lng&&areaA.ne.lat>=areaB.ne.lat&&areaA.ne.lng>=areaB.ne.lng;} +Ox.forEach(areas[1],function(area1){Ox.forEach(areas[0],function(area0){ret=contains(area0,area1);return!ret;});return ret;});return ret;};Ox.intersectAreas=function(areas){var intersections,ret;areas=areas.map(splitArea);ret=areas[0];function intersect(areaA,areaB){return areaA.sw.lat>areaB.ne.lat||areaA.sw.lng>areaB.ne.lng||areaA.ne.latret.ne.lat){ret.ne.lat=area.ne.lat;} +index=isContainedInGap(area);if(index>-1){gaps.push({sw:gaps[index].sw,ne:{lat:90,lng:area.sw.lng}});gaps.push({sw:{lat:-90,lng:area.ne.lng},ne:gaps[index].ne});gaps.splice(index,1);}else{indices=containsGaps(area);Ox.reverse(indices).forEach(function(index){gaps.splice(index,1);});intersections=intersectsWithGaps(area);Ox.forEach(intersections,function(intersection,index){gaps[index]={sw:{lat:-90,lng:gaps[index].sw.lng==intersection.sw.lng?intersection.ne.lng:gaps[index].sw.lng},ne:{lat:90,lng:gaps[index].ne.lng==intersection.ne.lng?intersection.sw.lng:gaps[index].ne.lng}};});}});if(gaps.length==0){ret.sw.lng=-180;ret.ne.lng=180;}else{gaps.sort(function(a,b){return(b.ne.lng ++(Ox.crossesDateline(b.sw,b.ne)?360:0) +-b.sw.lng)-(a.ne.lng ++(Ox.crossesDateline(a.sw,a.ne)?360:0) +-a.sw.lng);});ret.sw.lng=gaps[0].ne.lng;ret.ne.lng=gaps[0].sw.lng;} +return ret;};}());'use strict';(function(){var defaultTags=[{'name':'b'},{'name':'bdi'},{'name':'code'},{'name':'em'},{'name':'i'},{'name':'q'},{'name':'s'},{'name':'span'},{'name':'strong'},{'name':'sub'},{'name':'sup'},{'name':'u'},{'name':'blockquote'},{'name':'cite'},{'name':'div','optional':['style'],'validate':{'style':/^direction: rtl$/}},{'name':'h1'},{'name':'h2'},{'name':'h3'},{'name':'h4'},{'name':'h5'},{'name':'h6'},{'name':'p'},{'name':'pre'},{'name':'li'},{'name':'ol'},{'name':'ul'},{'name':'dl'},{'name':'dt'},{'name':'dd'},{'name':'table'},{'name':'tbody'},{'name':'td'},{'name':'tfoot'},{'name':'th'},{'name':'thead'},{'name':'tr'},{'name':'[]'},{'name':'a','required':['href'],'optional':['target'],'validate':{'href':/^((https?:\/\/|\/|mailto:).*?)/,'target':/^_blank$/}},{'name':'br'},{'name':'iframe','optional':['width','height'],'required':['src'],'validate':{'width':/^\d+$/,'height':/^\d+$/,'src':/^((https?:\/\/|\/).*?)/}},{'name':'img','optional':['width','height'],'required':['src'],'validate':{'width':/^\d+$/,'height':/^\d+$/,'src':/^((https?:\/\/|\/).*?)/},},{'name':'figure'},{'name':'figcaption'}],htmlEntities={'"':'"','&':'&',"'":''','<':'<','>':'>'},regexp={entity:/&[^\s]+?;/g,html:/[<&]/,tag:new RegExp('<\\/?('+['a','b','br','code','i','s','span','u'].join('|')+')\\/?>','gi')},salt=Ox.range(2).map(function(){return Ox.range(16).map(function(){return Ox.char(65+Ox.random(26));}).join('');});function addLinks(string,obfuscate){return string.replace(/\b((https?:\/\/|www\.).+?)([.,:;!?)\]]*?(\s|$))/gi,function(match,url,prefix,end){prefix=prefix.toLowerCase()=='www.'?'http://':'';return Ox.formatString('{url}{end}',{end:end,prefix:prefix,url:url});}).replace(/\b([0-9A-Z.+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,6})\b/gi,obfuscate?function(match,mail){return Ox.encodeEmailAddress(mail);}:'$1');} +function decodeHTMLEntities(string){return string.replace(new RegExp('('+Ox.values(htmlEntities).join('|')+')','g'),function(match){return Ox.keyOf(htmlEntities,match);}).replace(/&#([0-9A-FX]+);/gi,function(match,code){return Ox.char(/^X/i.test(code)?parseInt(code.slice(1),16):parseInt(code,10));});}function splitHTMLTags(string,ignore){var isTag=false,ret=[''];ignore=ignore||[];Ox.forEach(string,function(char,i){if(!isTag&&char=='<'&&ignore.indexOf(i)==-1){isTag=true;ret.push('');} +ret[ret.length-1]+=char;if(isTag&&char=='>'){isTag=false;ret.push('');}});return ret;} +Ox.addLinks=function(string,isHTML){var isLink=false;return isHTML?splitHTMLTags(string).map(function(string,i){var isTag=i%2;if(isTag){if(/^'+parts[1]+'';};Ox.encodeHTMLEntities=function(string,encodeAll){return Ox.map(String(string),function(char){var code=char.charCodeAt(0);if(code<128){char=char in htmlEntities?htmlEntities[char]:char;}else if(encodeAll){char='&#x' ++Ox.pad(code.toString(16).toUpperCase(),'left',4,'0') ++';';} +return char;});};Ox.decodeHTMLEntities=function(string,decodeAll){return decodeAll?Ox.decodeHTMLEntities(Ox.normalizeHTML(string)):decodeHTMLEntities(string);};Ox.highlight=function(string,query,classname,isHTML){if(!query){return string;} +var cursor=0,entities=[],matches=[],offset=0,re=Ox.isRegExp(query)?query:new RegExp(Ox.escapeRegExp(query),'gi'),span=['',''],tags=[];function insert(array){array.forEach(function(v){string=Ox.splice(string,v.position,v.length,v.value);matches.forEach(function(match){if(v.position').html(html).html():html;};Ox.parseMarkdown=function(string){var array=[];return string.replace(/\r\n/g,'\n').replace(/\r/g,'\n').replace(/(?:^|\n)```(.*)\n([^`]+)\n```/g,function(match,classname,code){array.push('
'
++code.trim().replace(/
');return salt.join(array.length-1);}).replace(/(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm,function(match,prev,backticks,code,next){array.push(prev+'' ++code.trim().replace(/');return salt.join(array.length-1);}).replace(/(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g,'$2').replace(/(\*|_)(?=\S)([^\r]*?\S)\1/g,'$2').replace(/(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g,function(match,all,text,id,url,rest,quote,title){return''+text+'';}).replace(/<((https?|ftp|dict):[^'">\s]+)>/gi,'$1').replace(/<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi,function(match,mail){return Ox.encodeEmailAddress(mail);}).replace(/\n\n/g,'

').replace(new RegExp(salt.join('(\\d+)'),'g'),function(match,index){return array[parseInt(index)];});};Ox.sanitizeHTML=function(html,tags,globalAttributes){tags=tags||defaultTags;globalAttributes=globalAttributes||[];var escaped={},level=0,matches=[],selfClosingTags=['img','br'],validAttributes={},requiredAttributes={},validate={},validTags=tags.map(function(tag){validAttributes[tag.name]=globalAttributes.concat(tag.required||[]).concat(tag.optional||[]);requiredAttributes[tag.name]=tag.required||[];validate[tag.name]=tag.validate||{};return tag.name;});if(Ox.contains(validTags,'[]')){html=html.replace(/\[((\/|https?:\/\/|mailto:).+?) (.+?)\]/gi,'$3');validTags=validTags.filter(function(tag){return tag!='[]';});} +html=splitHTMLTags(html).map(function(string,i){var attrs={},attrMatch,attrRegexp=/([^=\ ]+)="([^"]+)"/g,attrString,isClosing,isTag=i%2,isValid=true,tag,tagMatch,tagRegexp=/<(\/)?([^\ \/]+)(.*?)(\/)?>/g;if(isTag){tagMatch=tagRegexp.exec(string);if(tagMatch){isClosing=!Ox.isUndefined(tagMatch[1]);tag=tagMatch[2];attrString=tagMatch[3].trim();while(attrMatch=attrRegexp.exec(attrString)){if(validAttributes[tag]&&Ox.contains(validAttributes[tag],attrMatch[1])){attrs[attrMatch[1]]=attrMatch[2];}} +if(!isClosing&&!Ox.contains(selfClosingTags,tag)){level++;} +if(!Ox.contains(validTags,tag)||(attrString.length&&Ox.isEmpty(attrs))){isValid=false;}else if(!isClosing&&requiredAttributes[tag]){requiredAttributes[tag].forEach(function(attr){if(Ox.isUndefined(attrs[attr])){isValid=false;}});} +if(isValid&&!Ox.isEmpty(attrs)){Ox.forEach(attrs,function(value,key){if(!Ox.isUndefined(validate[tag][key])&&!validate[tag][key].exec(value)){isValid=false;return false;}});} +if(isValid&&isClosing){isValid=!escaped[level];}else{escaped[level]=!isValid;} +if(isClosing){level--;} +if(isValid){return'<' ++(isClosing?'/':'') ++tag ++(!isClosing&&!Ox.isEmpty(attrs)?' '+Ox.values(Ox.map(attrs,function(value,key){return key+'="'+value+'"';})).join(' '):'') ++'>';}}} +return Ox.encodeHTMLEntities(Ox.decodeHTMLEntities(string));}).join('');html=Ox.addLinks(html,true);html=html.replace(/\n\n/g,'

');return Ox.normalizeHTML(html);};Ox.stripTags=function(string){return string.replace(/<.*?>/g,'');};}());'use strict';Ox.oshash=function(file,callback){var hash=fromString(file.size.toString());read(0);function add(A,B){var a,b,c,d;d=A[3]+B[3];c=A[2]+B[2]+(d>>16);d&=0xffff;b=A[1]+B[1]+(c>>16);c&=0xffff;a=A[0]+B[0]+(b>>16);b&=0xffff;a&=0xffff;return[a,b,c,d];} +function fromData(s,offset){offset=offset||0;return[s.charCodeAt(offset+6)+(s.charCodeAt(offset+7)<<8),s.charCodeAt(offset+4)+(s.charCodeAt(offset+5)<<8),s.charCodeAt(offset+2)+(s.charCodeAt(offset+3)<<8),s.charCodeAt(offset+0)+(s.charCodeAt(offset+1)<<8)];} +function fromString(str){var base=10,blen=1,i,num,pos,r=[0,0,0,0];for(pos=0;pos>>=16;} +if(num){blen++;}}while(num);} +return r;} +function hex(h){return(Ox.pad(h[0].toString(16),'left',4,'0') ++Ox.pad(h[1].toString(16),'left',4,'0') ++Ox.pad(h[2].toString(16),'left',4,'0') ++Ox.pad(h[3].toString(16),'left',4,'0')).toLowerCase();} +function read(offset,last){var blob,block=65536,length=8,reader=new FileReader();reader.onload=function(data){var s=data.target.result,s_length=s.length-length,i;for(i=0;i<=s_length;i+=length){hash=add(hash,fromData(s,i));} +if(file.size>>(32-s));return t4;};function cvt_hex(val){var str="";var i;var v;for(i=7;i>=0;i--){v=(val>>>(i*4))&0x0f;str+=v.toString(16);} +return str;};var blockstart;var i,j;var W=new Array(80);var H0=0x67452301;var H1=0xEFCDAB89;var H2=0x98BADCFE;var H3=0x10325476;var H4=0xC3D2E1F0;var A,B,C,D,E;var temp;msg=Ox.encodeUTF8(msg);var msg_len=msg.length;var word_array=new Array();for(i=0;i>>29);word_array.push((msg_len<<3)&0x0ffffffff);for(blockstart=0;blockstart\s+(.+?)$/,multiline:/^\/\*\@.*?\n([\w\W]+)\n.*?\@?\*\/$/,script:/\n(\s* - > Ox.last(Ox.test.array) - 3 - > Ox.last(Ox.test.array, 4) - [1, 2, 4] - > Ox.test.array - [1, 2, 4] - > Ox.last('123') - '3' -@*/ -export function last(array, value) { - var ret; - if (arguments.length == 1) { - ret = array[array.length - 1]; - } else { - array[array.length - 1] = value; - ret = array; - } - return ret; -} - -/*@ -Ox.makeArray Wraps any non-array in an array. - (value) -> Array - value <*> Any value - > Ox.makeArray('foo') - ['foo'] - > Ox.makeArray(['foo']) - ['foo'] -@*/ -// FIXME: rename to toArray -export function makeArray(value) { - var ret, type = typeOf(value); - if (type == 'arguments' || type == 'nodelist') { - ret = slice(value); - } else if (type == 'array') { - ret = value; - } else { - ret = [value]; - } - return ret; -} - -/*@ -Ox.range Python-style range - (stop) -> <[n]> range - Returns an array of integers from `0` (inclusive) to `stop` (exclusive). - (start, stop) -> <[n]> range - Returns an array of integers from `start` (inclusive) to `stop` - (exclusive). - (start, stop, step) -> <[n]> range - Returns an array of numbers from `start` (inclusive) to `stop` - (exclusive), incrementing by `step`. - start Start value - stop Stop value - step Step value - > Ox.range(3) - [0, 1, 2] - > Ox.range(1, 4) - [1, 2, 3] - > Ox.range(3, 0) - [3, 2, 1] - > Ox.range(1, 2, 0.5) - [1, 1.5] - > Ox.range(-1, -2, -0.5) - [-1, -1.5] -@*/ -export function range() { - var array = []; - loop.apply(null, slice(arguments).concat(function(index) { - array.push(index); - })); - return array; -} - -// Re-export functions from other modules to maintain original hierarchy -export { slice, max, min, forEach, len, map, filter, values, keyOf, isEmpty, contains, random, char, splice, clean, repeat, loop }; - // Export all functions export default { api, @@ -475,26 +389,5 @@ export default { count, sort, unique, - zip, - last, - makeArray, - range, - // Re-exported functions - slice, - max, - min, - forEach, - len, - map, - filter, - values, - keyOf, - isEmpty, - contains, - random, - char, - splice, - clean, - repeat, - loop + zip }; \ No newline at end of file diff --git a/src/ox/core/Async.js b/src/ox/core/Async.js deleted file mode 100644 index d4c3ceda..00000000 --- a/src/ox/core/Async.js +++ /dev/null @@ -1,284 +0,0 @@ -import { typeOf, isFunction } from './Type.js'; -import { last, makeArray, slice, forEach, len, range } from './Array.js'; - -function asyncMap(forEachFn, collection, iterator, that, callback) { - var type = typeOf(collection), - results = type == 'object' ? {} : []; - callback = last(arguments); - that = arguments.length == 5 ? that : null; - forEachFn(collection, function(value, key, collection, callback) { - iterator(value, key, collection, function(value) { - results[key] = value; - callback(); - }); - }, that, function() { - callback(type == 'string' ? results.join('') : results); - }); -} - -export function asyncMapFn(array, iterator, that, callback) { - array = makeArray(array); - callback = last(arguments); - that = arguments.length == 4 ? that : null; - if (array.some(Array.isArray)) { - serialMap(array, function(value, key, array, callback) { - parallelMap(makeArray(value), iterator, callback); - }, callback); - } else { - parallelMap(array, iterator, callback); - } -} - -/*@ -Ox.nonblockingForEach Non-blocking `forEach` with synchronous iterator - (col, iterator[, that], callback[, ms]) -> undefined - collection Collection - iterator Iterator function - value <*> Value - key Key - collection The collection - that The iterator's `this` binding - callback Callback function - ms Number of milliseconds after which to insert a `setTimeout` call -@*/ -export function nonblockingForEach(collection, iterator, that, callback, ms) { - var i = 0, keys, lastArg = last(arguments), - n, time, type = typeOf(collection); - callback = isFunction(lastArg) ? lastArg : arguments[arguments.length - 2]; - collection = type == 'array' || type == 'object' - ? collection : slice(collection); - keys = type == 'object' - ? Object.keys(collection) : range(collection.length); - ms = ms || 1000; - n = len(collection); - that = arguments.length == 5 || ( - arguments.length == 4 && isFunction(lastArg) - ) ? that : null; - time = +new Date(); - iterate(); - function iterate() { - forEach(keys.slice(i), function(key) { - if (key in collection) { - if (iterator.call( - that, collection[key], key, collection - ) === false) { - i = n; - return false; - } - } - i++; - if (+new Date() >= time + ms) { - return false; // break - } - }); - if (i < n) { - setTimeout(function() { - time = +new Date(); - iterate(); - }, 1); - } else { - callback(); - } - } -} - -/*@ -Ox.nonblockingMap Non-blocking `map` with synchronous iterator - (collection, iterator[, that], callback[, ms]) -> undefined - collection Collection - iterator Iterator function - that The iterator's `this` binding - callback Callback function - ms Number of milliseconds after which to insert a `setTimeout` call - - > Ox.nonblockingMap(Ox.range(100000), Ox.identity, function(r) { Ox.test(r.length, 100000); }) - undefined -@*/ -export function nonblockingMap(collection, iterator, that, callback, ms) { - var lastArg = last(arguments), - type = typeOf(collection), - results = type == 'object' ? {} : []; - callback = isFunction(lastArg) ? lastArg : arguments[arguments.length - 2]; - that = arguments.length == 5 || ( - arguments.length == 4 && isFunction(lastArg) - ) ? that : null; - nonblockingForEach(collection, function(value, key, collection) { - results[key] = iterator.call(that, value, key, collection); - }, function() { - callback(type == 'string' ? results.join('') : results); - }, ms); -} - -/*@ -Ox.parallelForEach `forEach` with asynchronous iterator, running in parallel - (collection, iterator[, that], callback) -> undefined - collection Collection - iterator Iterator function - value <*> Value - key Key - collection The collection - callback Callback function - that The iterator's this binding - callback Callback function - - > Ox.parallelForEach(Ox.range(10), Ox.test.pfeIterator, function() { Ox.test(Ox.test.pfeNumber, 5); }) - undefined -@*/ -export function parallelForEach(collection, iterator, that, callback) { - var i = 0, n, type = typeOf(collection); - callback = callback || (arguments.length == 3 ? arguments[2] : function() {}); - collection = type == 'array' || type == 'object' - ? collection : slice(collection); - n = len(collection); - that = arguments.length == 4 ? that : null; - forEach(collection, function(value, key, collection) { - iterator.call(that, value, key, collection, function() { - ++i == n && callback(); - }); - }); -} - -/*@ -Ox.parallelMap Parallel `map` with asynchronous iterator - (collection, iterator[, that], callback) -> undefined - collection Collection - iterator Iterator function - value <*> Value - key Key - collection The collection - callback Callback function - that The iterator's this binding - callback Callback function - results Results - - > Ox.parallelMap(Ox.range(10), Ox.test.pmIterator, function(r) { Ox.test(Ox.sum(r), 0); }) - undefined -@*/ -export function parallelMap() { - asyncMap.apply(null, [parallelForEach].concat(slice(arguments))); -} - -/*@ -Ox.serialForEach `forEach` with asynchronous iterator, run serially - (collection, iterator[, that], callback) -> undefined - collection Collection - iterator Iterator function - value <*> Value - key Key - collection The collection - callback Callback function - that The iterator's this binding - callback Callback function - - > Ox.serialForEach(Ox.range(10), Ox.test.sfeIterator, function() { Ox.test(Ox.test.sfeNumber, 5); }) - undefined -@*/ -export function serialForEach(collection, iterator, that, callback) { - var i = 0, keys, n, type = typeOf(collection); - callback = callback || (arguments.length == 3 ? arguments[2] : function() {}); - collection = type == 'array' || type == 'object' - ? collection : slice(collection); - keys = type == 'object' - ? Object.keys(collection) : range(collection.length); - n = len(collection); - that = arguments.length == 4 ? that : null; - iterate(); - function iterate(value) { - if (value !== false) { - if (keys[i] in collection) { - iterator.call( - that, - collection[keys[i]], - keys[i], - collection, - ++i < n ? iterate : callback - ); - } else { - ++i < n ? iterate() : callback(); - } - } else { - callback(); - } - } -} - -/*@ -Ox.serialMap Serial `map` with asynchronous iterator - (collection, iterator[, that], callback) -> undefined - collection Collection - iterator Iterator function - value <*> Value - key Key - collection The collection - callback Callback function - that The iterator's this binding - callback Callback function - results Results - - > Ox.serialMap(Ox.range(10), Ox.test.smIterator, function(r) { Ox.test(Ox.sum(r), 0); }) - undefined -@*/ -export function serialMap(collection, iterator, that, callback) { - asyncMap.apply(null, [serialForEach].concat(slice(arguments))); -} -// FIXME: The above test with 10000 iterations blows the stack \ No newline at end of file diff --git a/src/ox/core/Collection.js b/src/ox/core/Collection.js index ee1db133..b56ae13a 100644 --- a/src/ox/core/Collection.js +++ b/src/ox/core/Collection.js @@ -208,104 +208,6 @@ export function values(collection) { return []; } -/** - * Constants - */ -const STACK_LENGTH = 50000; - -/*@ -Ox.slice Alias for `Array.prototype.slice.call` - (collection[, start[, stop]]) -> Array - collection Array-like - start Start position - stop Stop position - > (function() { return Ox.slice(arguments); }(1, 2, 3)) - [1, 2, 3] - > Ox.slice('foo', 0, 1); - ['f'] - > Ox.slice({0: 'f', 1: 'o', 2: 'o', length: 3}, -2) - ['o', 'o'] -@*/ -// FIXME: remove toArray alias -export function slice(collection, start, stop) { - // IE8 can't apply slice to NodeLists, returns an empty array if undefined is - // passed as stop and returns an array of null values if a string is passed as - // value. Firefox 3.6 returns an array of undefined values if a string is passed - // as value. - - // Try the simple approach first - try { - const result = Array.prototype.slice.call(collection, start, stop); - // Test for broken implementations - if (result.length === 0 && collection.length > 0) { - throw new Error('Broken slice implementation'); - } - return result; - } catch (error) { - // Fallback for broken implementations - const args = stop === void 0 ? [start] : [start, stop]; - const array = []; - let index, length; - - if (typeOf(collection) === 'string') { - collection = collection.split(''); - } - - length = collection.length; - for (index = 0; index < length; index++) { - array[index] = collection[index]; - } - - return Array.prototype.slice.apply(array, args); - } -} - -/*@ -Ox.max Returns the maximum value of a collection - > Ox.max([1, 2, 3]) - 3 - > Ox.max({a: 1, b: 2, c: 3}) - 3 - > Ox.max('123') - 3 - > Ox.max([]) - -Infinity -@*/ -export function max(collection) { - var ret, collectionValues = values(collection); - if (collectionValues.length < STACK_LENGTH) { - ret = Math.max.apply(null, collectionValues); - } else { - ret = collectionValues.reduce(function(previousValue, currentValue) { - return Math.max(previousValue, currentValue); - }, -Infinity); - } - return ret; -} - -/*@ -Ox.min Returns the minimum value of a collection - > Ox.min([1, 2, 3]) - 1 - > Ox.min({a: 1, b: 2, c: 3}) - 1 - > Ox.min('123') - 1 - > Ox.min([]) - Infinity -@*/ -export function min(collection) { - var ret, collectionValues = values(collection); - if (collectionValues.length < STACK_LENGTH) { - ret = Math.min.apply(null, collectionValues); - } else { - ret = collectionValues.reduce(function(previousValue, currentValue) { - return Math.min(previousValue, currentValue); - }, Infinity); - } - return ret; -} - // Export all functions export default { forEach, @@ -317,8 +219,5 @@ export default { every, some, keys, - values, - slice, - max, - min + values }; \ No newline at end of file diff --git a/src/ox/core/Color.js b/src/ox/core/Color.js deleted file mode 100644 index ffdfbfab..00000000 --- a/src/ox/core/Color.js +++ /dev/null @@ -1,125 +0,0 @@ -import { slice, max, min, range } from './Array.js'; -import { clone } from './Object.js'; -import { pad } from './String.js'; - -/*@ -Ox.hsl Takes RGB values and returns HSL values - (rgb) <[n]> HSL values - (r, g, b) <[n]> HSL values - rgb <[n]> RGB values - r red - g green - b blue - > Ox.hsl([0, 0, 0]) - [0, 0, 0] - > Ox.hsl([255, 255, 255]) - [0, 0, 1] - > Ox.hsl(0, 255, 0) - [120, 1, 0.5] -@*/ -export function hsl(rgb) { - var hsl = [0, 0, 0], maxVal, minVal; - if (arguments.length == 3) { - rgb = slice(arguments); - } - rgb = clone(rgb).map(function(value) { - return value / 255; - }); - maxVal = max(rgb); - minVal = min(rgb); - hsl[2] = 0.5 * (maxVal + minVal); - if (maxVal == minVal) { - hsl[0] = 0; - hsl[1] = 0; - } else { - if (maxVal == rgb[0]) { - hsl[0] = (60 * (rgb[1] - rgb[2]) / (maxVal - minVal) + 360) % 360; - } else if (maxVal == rgb[1]) { - hsl[0] = 60 * (rgb[2] - rgb[0]) / (maxVal - minVal) + 120; - } else if (maxVal == rgb[2]) { - hsl[0] = 60 * (rgb[0] - rgb[1]) / (maxVal - minVal) + 240; - } - if (hsl[2] <= 0.5) { - hsl[1] = (maxVal - minVal) / (2 * hsl[2]); - } else { - hsl[1] = (maxVal - minVal) / (2 - 2 * hsl[2]); - } - } - return hsl; -} - -/*@ -Ox.rgb Takes HSL values and returns RGB values - (hsl) <[n]> RGB values - (h, s, l) <[n]> RGB values - hsl <[n]> HSL values - h hue - s saturation - l lightness - > Ox.rgb([0, 0, 0]) - [0, 0, 0] - > Ox.rgb([0, 0, 1]) - [255, 255, 255] - > Ox.rgb(120, 1, 0.5) - [0, 255, 0] -@*/ -export function rgb(hsl) { - var rgb = [0, 0, 0], v1, v2, v3; - if (arguments.length == 3) { - hsl = slice(arguments); - } - hsl = clone(hsl); - hsl[0] /= 360; - if (hsl[1] == 0) { - rgb = [hsl[2], hsl[2], hsl[2]]; - } else { - if (hsl[2] < 0.5) { - v2 = hsl[2] * (1 + hsl[1]); - } else { - v2 = hsl[1] + hsl[2] - (hsl[1] * hsl[2]); - } - v1 = 2 * hsl[2] - v2; - rgb.forEach(function(v, i) { - v3 = hsl[0] + (1 - i) * 1/3; - if (v3 < 0) { - v3++; - } else if (v3 > 1) { - v3--; - } - if (v3 < 1/6) { - rgb[i] = v1 + ((v2 - v1) * 6 * v3); - } else if (v3 < 0.5) { - rgb[i] = v2; - } else if (v3 < 2/3) { - rgb[i] = v1 + ((v2 - v1) * 6 * (2/3 - v3)); - } else { - rgb[i] = v1; - } - }); - } - return rgb.map(function(value) { - return Math.round(value * 255); - }); -} - -/*@ -Ox.toHex Format RGB array as hex value - > Ox.toHex([192, 128, 64]) - 'C08040' -@*/ -export function toHex(rgb) { - return rgb.map(function(value) { - return pad(value.toString(16).toUpperCase(), 'left', 2, '0'); - }).join(''); -} - -/*@ -Ox.toRGB Format hex value as RGB array - > Ox.toRGB('C08040') - [192, 128, 64] -@*/ -export function toRGB(hex) { - return range(3).map(function(index) { - return parseInt(hex.substr(index * 2, 2), 16); - }); -} \ No newline at end of file diff --git a/src/ox/core/Constants.js b/src/ox/core/Constants.js index 70e8a19f..b0daa843 100644 --- a/src/ox/core/Constants.js +++ b/src/ox/core/Constants.js @@ -17,10 +17,6 @@ export const EARTH_RADIUS = 6371000; // in meters export const MAX_LATITUDE = 85.05112878; // Web Mercator max latitude export const MIN_LATITUDE = -85.05112878; // Web Mercator min latitude -// Base32 encoding constants -export const BASE_32_ALIASES = {'I': '1', 'L': '1', 'O': '0', 'U': 'V'}; -export const BASE_32_DIGITS = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; - // Time constants export const SECONDS_PER_MINUTE = 60; export const SECONDS_PER_HOUR = 3600; @@ -258,8 +254,6 @@ export default { EARTH_RADIUS, MAX_LATITUDE, MIN_LATITUDE, - BASE_32_ALIASES, - BASE_32_DIGITS, SECONDS_PER_MINUTE, SECONDS_PER_HOUR, SECONDS_PER_DAY, diff --git a/src/ox/core/Date.js b/src/ox/core/Date.js deleted file mode 100644 index d5a2bfaa..00000000 --- a/src/ox/core/Date.js +++ /dev/null @@ -1,452 +0,0 @@ -/** - * Date utilities - ES Module Version - */ - -import { isDate, isNumber, isString, isUndefined } from './Type.js'; -import { mod } from './Math.js'; - -/** - * Get the name of the day of the week for a given date - */ -export function getDayName(date, utc) { - const names = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; - return names[getDayOfWeek(date, utc)]; -} - -/** - * Get the day of the week (0-6) for a given date - */ -export function getDayOfWeek(date, utc) { - date = makeDate(date); - return utc ? date.getUTCDay() : date.getDay(); -} - -/** - * Get the day of the year (1-366) for a given date - */ -export function getDayOfYear(date, utc) { - date = makeDate(date); - const startOfYear = new Date(Date.UTC( - getFullYear(date, utc), - 0, 1 - )); - const diff = date - startOfYear; - return Math.floor(diff / 86400000) + 1; -} - -/** - * Get the number of days in a month - */ -export function getDaysInMonth(year, month) { - return new Date(year, month + 1, 0).getDate(); -} - -/** - * Get the number of days in a year - */ -export function getDaysInYear(year) { - return isLeapYear(year) ? 366 : 365; -} - -/** - * Get the first day of the week for a given date - */ -export function getFirstDayOfWeek(date, utc) { - date = makeDate(date); - const day = getDayOfWeek(date, utc); - return new Date(date.getTime() - day * 86400000); -} - -/** - * Get the full year from a date - */ -export function getFullYear(date, utc) { - date = makeDate(date); - return utc ? date.getUTCFullYear() : date.getFullYear(); -} - -/** - * Get hours from date - */ -export function getHours(date, utc) { - date = makeDate(date); - return utc ? date.getUTCHours() : date.getHours(); -} - -/** - * Get the ISO date string (YYYY-MM-DD) - */ -export function getISODate(date, utc) { - return formatDate(date, '%Y-%m-%d', utc); -} - -/** - * Get the ISO week number - */ -export function getISOWeek(date, utc) { - date = makeDate(date); - const year = getFullYear(date, utc); - const firstThursday = getFirstThursday(year, utc); - const week = Math.floor((date - firstThursday) / 604800000) + 1; - - if (week < 1) { - return getISOWeek(new Date(year - 1, 11, 31), utc); - } else if (week > 52) { - const nextFirstThursday = getFirstThursday(year + 1, utc); - if (date >= nextFirstThursday) { - return 1; - } - } - - return week; -} - -/** - * Get the ISO year - */ -export function getISOYear(date, utc) { - date = makeDate(date); - const year = getFullYear(date, utc); - const week = getISOWeek(date, utc); - - if (week === 1 && getMonth(date, utc) === 11) { - return year + 1; - } else if (week >= 52 && getMonth(date, utc) === 0) { - return year - 1; - } - - return year; -} - -/** - * Get minutes from date - */ -export function getMinutes(date, utc) { - date = makeDate(date); - return utc ? date.getUTCMinutes() : date.getMinutes(); -} - -/** - * Get month from date (0-11) - */ -export function getMonth(date, utc) { - date = makeDate(date); - return utc ? date.getUTCMonth() : date.getMonth(); -} - -/** - * Get month name - */ -export function getMonthName(date, utc) { - const names = [ - 'January', 'February', 'March', 'April', 'May', 'June', - 'July', 'August', 'September', 'October', 'November', 'December' - ]; - return names[getMonth(date, utc)]; -} - -/** - * Get seconds from date - */ -export function getSeconds(date, utc) { - date = makeDate(date); - return utc ? date.getUTCSeconds() : date.getSeconds(); -} - -/** - * Get milliseconds from date - */ -export function getMilliseconds(date, utc) { - date = makeDate(date); - return utc ? date.getUTCMilliseconds() : date.getMilliseconds(); -} - -/** - * Get timezone offset in minutes - */ -export function getTimezoneOffset(date) { - return makeDate(date).getTimezoneOffset(); -} - -/** - * Get timezone offset string (+HH:MM or -HH:MM) - */ -export function getTimezoneOffsetString(date) { - const offset = getTimezoneOffset(date); - const sign = offset <= 0 ? '+' : '-'; - const hours = Math.floor(Math.abs(offset) / 60); - const minutes = Math.abs(offset) % 60; - return sign + pad(hours, 2) + ':' + pad(minutes, 2); -} - -/** - * Get Unix timestamp (seconds since epoch) - */ -export function getUnixTime(date) { - return Math.floor(makeDate(date).getTime() / 1000); -} - -/** - * Get week number (1-53) - */ -export function getWeek(date, utc) { - date = makeDate(date); - const firstDayOfYear = new Date(Date.UTC( - getFullYear(date, utc), 0, 1 - )); - const days = Math.floor((date - firstDayOfYear) / 86400000); - return Math.ceil((days + getDayOfWeek(firstDayOfYear, utc) + 1) / 7); -} - -/** - * Check if a year is a leap year - */ -export function isLeapYear(year) { - return year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0); -} - -/** - * Check if a date is valid - */ -export function isValidDate(date) { - date = makeDate(date); - return !isNaN(date.getTime()); -} - -/** - * Make a date object from various inputs - */ -export function makeDate(date) { - if (isDate(date)) { - return date; - } else if (isString(date)) { - return new Date(date); - } else if (isNumber(date)) { - return new Date(date); - } else if (isUndefined(date)) { - return new Date(); - } - return new Date(date); -} - -/** - * Format a date according to a format string - */ -export function formatDate(date, format, utc) { - date = makeDate(date); - format = format || '%Y-%m-%d %H:%M:%S'; - - const replacements = { - '%a': () => getDayName(date, utc).substr(0, 3), - '%A': () => getDayName(date, utc), - '%b': () => getMonthName(date, utc).substr(0, 3), - '%B': () => getMonthName(date, utc), - '%c': () => date.toLocaleString(), - '%d': () => pad(getDate(date, utc), 2), - '%e': () => pad(getDate(date, utc), 2, ' '), - '%H': () => pad(getHours(date, utc), 2), - '%I': () => pad(((getHours(date, utc) + 11) % 12) + 1, 2), - '%j': () => pad(getDayOfYear(date, utc), 3), - '%k': () => pad(getHours(date, utc), 2, ' '), - '%l': () => pad(((getHours(date, utc) + 11) % 12) + 1, 2, ' '), - '%m': () => pad(getMonth(date, utc) + 1, 2), - '%M': () => pad(getMinutes(date, utc), 2), - '%p': () => getHours(date, utc) < 12 ? 'AM' : 'PM', - '%S': () => pad(getSeconds(date, utc), 2), - '%u': () => getDayOfWeek(date, utc) || 7, - '%U': () => pad(getWeek(date, utc), 2), - '%V': () => pad(getISOWeek(date, utc), 2), - '%w': () => getDayOfWeek(date, utc), - '%W': () => pad(getWeek(date, utc), 2), - '%x': () => date.toLocaleDateString(), - '%X': () => date.toLocaleTimeString(), - '%y': () => pad(getFullYear(date, utc) % 100, 2), - '%Y': () => getFullYear(date, utc), - '%z': () => getTimezoneOffsetString(date), - '%Z': () => '', // Timezone abbreviation not easily available - '%%': () => '%' - }; - - return format.replace(/%[a-zA-Z%]/g, (match) => { - return replacements[match] ? replacements[match]() : match; - }); -} - -/** - * Parse a date string - */ -export function parseDate(string, format, utc) { - // Basic implementation - can be enhanced - return new Date(string); -} - -/** - * Get date (day of month) - */ -export function getDate(date, utc) { - date = makeDate(date); - return utc ? date.getUTCDate() : date.getDate(); -} - -/** - * Get day (alias for getDayOfWeek) - */ -export function getDay(date, utc) { - return getDayOfWeek(date, utc); -} - -/** - * Get ISO day (Monday=1, Sunday=7) - */ -export function getISODay(date, utc) { - const day = getDayOfWeek(date, utc); - return day === 0 ? 7 : day; -} - -/** - * Get day of the year (alias for getDayOfYear) - */ -export function getDayOfTheYear(date, utc) { - return getDayOfYear(date, utc); -} - -/** - * Get first day of the year - */ -export function getFirstDayOfTheYear(date, utc) { - date = makeDate(date); - const year = getFullYear(date, utc); - return new Date(Date.UTC(year, 0, 1)); -} - -/** - * Set date (day of month) - */ -export function setDate(date, day, utc) { - date = makeDate(date); - if (utc) { - date.setUTCDate(day); - } else { - date.setDate(day); - } - return date; -} - -/** - * Set full year - */ -export function setFullYear(date, year, utc) { - date = makeDate(date); - if (utc) { - date.setUTCFullYear(year); - } else { - date.setFullYear(year); - } - return date; -} - -/** - * Set month - */ -export function setMonth(date, month, utc) { - date = makeDate(date); - if (utc) { - date.setUTCMonth(month); - } else { - date.setMonth(month); - } - return date; -} - -/** - * Set hours - */ -export function setHours(date, hours, utc) { - date = makeDate(date); - if (utc) { - date.setUTCHours(hours); - } else { - date.setHours(hours); - } - return date; -} - -/** - * Set minutes - */ -export function setMinutes(date, minutes, utc) { - date = makeDate(date); - if (utc) { - date.setUTCMinutes(minutes); - } else { - date.setMinutes(minutes); - } - return date; -} - -/** - * Set seconds - */ -export function setSeconds(date, seconds, utc) { - date = makeDate(date); - if (utc) { - date.setUTCSeconds(seconds); - } else { - date.setSeconds(seconds); - } - return date; -} - -// Helper functions -function getFirstThursday(year, utc) { - const jan1 = new Date(Date.UTC(year, 0, 1)); - const dayOfWeek = getDayOfWeek(jan1, utc); - const daysToThursday = (11 - dayOfWeek) % 7; - return new Date(jan1.getTime() + daysToThursday * 86400000); -} - -function pad(number, length, padding) { - padding = padding || '0'; - const str = String(number); - return padding.repeat(Math.max(0, length - str.length)) + str; -} - -// Export all functions -export default { - getDayName, - getDayOfWeek, - getDayOfYear, - getDaysInMonth, - getDaysInYear, - getFirstDayOfWeek, - getFullYear, - getHours, - getISODate, - getISOWeek, - getISOYear, - getMinutes, - getMonth, - getMonthName, - getSeconds, - getMilliseconds, - getTimezoneOffset, - getTimezoneOffsetString, - getUnixTime, - getWeek, - isLeapYear, - isValidDate, - makeDate, - formatDate, - parseDate, - getDate, - getDay, - getISODay, - getDayOfTheYear, - getFirstDayOfTheYear, - setDate, - setFullYear, - setMonth, - setHours, - setMinutes, - setSeconds -}; \ No newline at end of file diff --git a/src/ox/core/Encoding.js b/src/ox/core/Encoding.js deleted file mode 100644 index d91e39fd..00000000 --- a/src/ox/core/Encoding.js +++ /dev/null @@ -1,426 +0,0 @@ -import { map, char, forEach, range, slice, repeat, loop } from './Array.js'; -import { BASE_32_DIGITS, BASE_32_ALIASES } from './Constants.js'; - -/*@ -Ox.encodeBase26 Encode a number as bijective base26 - See - Bijective numeration. - > Ox.encodeBase26(0) - '' - > Ox.encodeBase26(1) - 'A' - > Ox.encodeBase26(26) - 'Z' - > Ox.encodeBase26(27) - 'AA' - > Ox.encodeBase26(4461) - 'FOO' -@*/ -export function encodeBase26(number) { - var string = ''; - while (number) { - string = String.fromCharCode(65 + (number - 1) % 26) + string; - number = Math.floor((number - 1) / 26); - } - return string; -} - -/*@ -Ox.decodeBase26 Decodes a bijective base26-encoded number - See - Bijective numeration. - > Ox.decodeBase26('foo') - 4461 -@*/ -export function decodeBase26(string) { - return string.toUpperCase().split('').reverse().reduce(function(p, c, i) { - return p + (c.charCodeAt(0) - 64) * Math.pow(26, i); - }, 0); -} - -/*@ -Ox.encodeBase32 Encode a number as base32 - See Base 32. - > Ox.encodeBase32(15360) - 'F00' - > Ox.encodeBase32(33819) - '110V' -@*/ -export function encodeBase32(number) { - return map(number.toString(32), function(char) { - return BASE_32_DIGITS[parseInt(char, 32)]; - }); -} - -/*@ -Ox.decodeBase32 Decodes a base32-encoded number - See Base 32. - > Ox.decodeBase32('foo') - 15360 - > Ox.decodeBase32('ILOU') - 33819 - > Ox.decodeBase32('?').toString() - 'NaN' -@*/ -export function decodeBase32(string) { - return parseInt(map(string.toUpperCase(), function(char) { - var index = BASE_32_DIGITS.indexOf( - BASE_32_ALIASES[char] || char - ); - return index == -1 ? ' ' : index.toString(32); - }), 32); -} - -/*@ -Ox.encodeBase64 Encode a number as base64 - > Ox.encodeBase64(32394) - 'foo' -@*/ -export function encodeBase64(number) { - return btoa(encodeBase256(number)).replace(/=/g, ''); -} - -/*@ -Ox.decodeBase64 Decodes a base64-encoded number - > Ox.decodeBase64('foo') - 32394 -@*/ -export function decodeBase64(string) { - return decodeBase256(atob(string)); -} - -/*@ -Ox.encodeBase128 Encode a number as base128 - > Ox.encodeBase128(1685487) - 'foo' -@*/ -export function encodeBase128(number) { - var string = ''; - while (number) { - string = char(number & 127) + string; - number >>= 7; - } - return string; -} - -/*@ -Ox.decodeBase128 Decode a base128-encoded number - > Ox.decodeBase128('foo') - 1685487 -@*/ -export function decodeBase128(string) { - return string.split('').reverse().reduce(function(p, c, i) { - return p + (c.charCodeAt(0) << i * 7); - }, 0); -} - -/*@ -Ox.encodeBase256 Encode a number as base256 - > Ox.encodeBase256(6713199) - 'foo' -@*/ -export function encodeBase256(number) { - var string = ''; - while (number) { - string = char(number & 255) + string; - number >>= 8; - } - return string; -} - -/*@ -Ox.decodeBase256 Decode a base256-encoded number - > Ox.decodeBase256('foo') - 6713199 -@*/ -export function decodeBase256(string) { - return string.split('').reverse().reduce(function(p, c, i) { - return p + (c.charCodeAt(0) << i * 8); - }, 0); -} - -/*@ -Ox.encodeDeflate Encodes a string, using deflate - Since PNGs are deflate-encoded, the `canvas` object's `toDataURL` method - provides an efficient implementation. The string is encoded as UTF-8 and - written to the RGB channels of a canvas element, then the PNG dataURL is - decoded from base64, and some head, tail and chunk names are removed. - (str) -> The encoded string - str The string to be encoded - > Ox.decodeDeflate(Ox.encodeDeflate('foo'), function(str) { Ox.test(str, 'foo'); }) - undefined -@*/ -export function encodeDeflate(string, callback) { - // Make sure we can encode the full unicode range of characters. - string = encodeUTF8(string); - // We can only safely write to RGB, so we need 1 pixel for 3 bytes. - // The string length may not be a multiple of 3, so we need to encode - // the number of padding bytes (1 byte), the string, and non-0-bytes - // as padding, so that the combined length becomes a multiple of 3. - var length = 1 + string.length, c = canvas(Math.ceil(length / 3), 1), - data, idat, pad = (3 - length % 3) % 3; - string = char(pad) + string + repeat('\u00FF', pad); - loop(c.data.length, function(i) { - // Write character codes into RGB, and 255 into ALPHA - c.data[i] = i % 4 < 3 ? string.charCodeAt(i - parseInt(i / 4)) : 255; - }); - c.context.putImageData(c.imageData, 0, 0); - // Get the PNG data from the data URL and decode it from base64. - string = atob(c.canvas.toDataURL().split(',')[1]); - // Discard bytes 0 to 15 (8 bytes PNG signature, 4 bytes IHDR length, 4 - // bytes IHDR name), keep bytes 16 to 19 (width), discard bytes 20 to 29 - // (4 bytes height, 5 bytes flags), keep bytes 29 to 32 (IHDR checksum), - // keep the rest (IDAT chunks), discard the last 12 bytes (IEND chunk). - data = string.slice(16, 20) + string.slice(29, 33); - idat = string.slice(33, -12); - while (idat) { - // Each IDAT chunk is 4 bytes length, 4 bytes name, length bytes - // data and 4 bytes checksum. We can discard the name parts. - length = idat.slice(0, 4); - data += length + idat.slice(8, 12 + ( - length = decodeBase256(length) - )); - idat = idat.slice(12 + length); - } - // Allow for async use, symmetrical to Ox.decodeDeflate - callback && callback(data); - return data; -} - -/*@ -Ox.decodeDeflate Decodes an deflate-encoded string - Since PNGs are deflate-encoded, the `canvas` object's `drawImage` method - provides an efficient implementation. The string will be wrapped as a PNG - dataURL, encoded as base64, and drawn onto a canvas element, then the RGB - channels will be read, and the result will be decoded from UTF8. - (str) -> undefined - str The string to be decoded - callback Callback function - str The decoded string -@*/ -export function decodeDeflate(string, callback) { - var image = new Image(), - // PNG file signature and IHDR chunk - data = '\u0089PNG\r\n\u001A\n\u0000\u0000\u0000\u000DIHDR' - + string.slice(0, 4) + '\u0000\u0000\u0000\u0001' - + '\u0008\u0006\u0000\u0000\u0000' + string.slice(4, 8), - // IDAT chunks - idat = string.slice(8), length; - function error() { - throw new RangeError('Deflate codec can\'t decode data.'); - } - while (idat) { - // Reinsert the IDAT chunk names - length = idat.slice(0, 4); - data += length + 'IDAT' + idat.slice(4, 8 + ( - length = decodeBase256(length) - )); - idat = idat.slice(8 + length); - } - // IEND chunk - data += '\u0000\u0000\u0000\u0000IEND\u00AE\u0042\u0060\u0082'; - // Unfortunately, we can't synchronously set the source of an image, - // draw it onto a canvas, and read its data. - image.onload = function() { - string = slice(canvas(image).data).map(function(value, index) { - // Read one character per RGB byte, ignore ALPHA. - return index % 4 < 3 ? char(value) : ''; - }).join(''); - try { - // Parse the first byte as number of bytes to chop at the end, - // and the rest, without these bytes, as an UTF8-encoded string. - string = decodeUTF8( - string.slice(1, -string.charCodeAt(0) || void 0) - ); - } catch (e) { - error(); - } - callback(string); - }; - image.onerror = error; - image.src = 'data:image/png;base64,' + btoa(data); -} - -(function() { - - function replace(string) { - return string.toString().replace(/%(?![0-9A-Fa-f]{2})/g, '%25') - .replace(/(%[0-9A-Fa-f]{2})+/g, function(match) { - var hex = match.split('%').slice(1), ret; - forEach(range(1, hex.length + 1), function(length) { - var string = range(length).map(function(i) { - return char(parseInt(hex[i], 16)); - }).join(''); - try { - decodeUTF8(string); - ret = match.slice(0, length * 3) - + replace(match.slice(length * 3)); - return false; - } catch(e) {} - }); - return ret || '%25' + hex[0] + replace(match.slice(3)); - }); - } - - /*@ - Ox.decodeURI Decodes URI - Unlike window.decodeURI, this doesn't throw on trailing '%'. - (string) -> Decoded string - @*/ - decodeURIFn = function(string) { - return decodeURI(replace(string)); - }; - - /*@ - Ox.decodeURIComponent Decodes URI component - Unlike window.decodeURIComponent, this doesn't throw on trailing '%'. - (string) -> Decoded string - @*/ - decodeURIComponentFn = function(string) { - return decodeURIComponent(replace(string)); - }; - -}()); - -/*@ -Ox.decodeURI Decodes URI - Unlike window.decodeURI, this doesn't throw on trailing '%'. - (string) -> Decoded string -@*/ -export function decodeURICompat(string) { - function replace(str) { - return str.toString().replace(/%(?![0-9A-Fa-f]{2})/g, '%25') - .replace(/(%[0-9A-Fa-f]{2})+/g, function(match) { - var hex = match.split('%').slice(1), ret; - try { - ret = decodeURI('%' + hex.join('%')); - } catch (e) {} - return ret || '%25' + hex[0] + replace(match.slice(3)); - }); - } - return decodeURI(replace(string)); -} - -/*@ -Ox.decodeURIComponent Decodes URI component - Unlike window.decodeURIComponent, this doesn't throw on trailing '%'. - (string) -> Decoded string -@*/ -export function decodeURIComponentCompat(string) { - function replace(str) { - return str.toString().replace(/%(?![0-9A-Fa-f]{2})/g, '%25') - .replace(/(%[0-9A-Fa-f]{2})+/g, function(match) { - var hex = match.split('%').slice(1), ret; - try { - ret = decodeURIComponent('%' + hex.join('%')); - } catch (e) {} - return ret || '%25' + hex[0] + replace(match.slice(3)); - }); - } - return decodeURIComponent(replace(string)); -} - -// Export with proper names -export { decodeURICompat as decodeURI, decodeURIComponentCompat as decodeURIComponent }; - -/*@ -Ox.encodeUTF8 Encodes a string as UTF-8 - see http://en.wikipedia.org/wiki/UTF-8 - (string) -> UTF-8 encoded string - string Any string - > Ox.encodeUTF8("YES") - "YES" - > Ox.encodeUTF8("¥€$") - "\u00C2\u00A5\u00E2\u0082\u00AC\u0024" -@*/ -export function encodeUTF8(string) { - return map(string, function(char) { - var code = char.charCodeAt(0), - string = ''; - if (code < 128) { - string = char; - } else if (code < 2048) { - string = String.fromCharCode(code >> 6 | 192) - + String.fromCharCode(code & 63 | 128); - } else { - string = String.fromCharCode(code >> 12 | 224) - + String.fromCharCode(code >> 6 & 63 | 128) - + String.fromCharCode(code & 63 | 128); - } - return string; - }); -} - -/*@ -Ox.decodeUTF8 Decodes an UTF-8-encoded string - see http://en.wikipedia.org/wiki/UTF-8 - (utf8) -> string - utf8 Any UTF-8-encoded string - > Ox.decodeUTF8('YES') - 'YES' - > Ox.decodeUTF8('\u00C2\u00A5\u00E2\u0082\u00AC\u0024') - '¥€$' -@*/ -export function decodeUTF8(string) { - var code, i = 0, length = string.length, ret = ''; - function error(byte, position) { - throw new RangeError( - 'UTF-8 codec can\'t decode byte 0x' + - byte.toString(16).toUpperCase() + ' at position ' + position - ); - } - while (i < length) { - code = [ - string.charCodeAt(i), - string.charCodeAt(i + 1), - string.charCodeAt(i + 2) - ]; - if (code[0] < 128) { - ret += string[i]; - i++; - } else if ( - code[0] >= 192 && code[0] < 240 - && i < length - (code[0] < 224 ? 1 : 2) - ) { - if (code[1] >= 128 && code[1] < 192) { - if (code[0] < 224) { - ret += String.fromCharCode( - (code[0] & 31) << 6 | code[1] & 63 - ); - i += 2; - } else if (code[2] >= 128 && code[2] < 192) { - ret += String.fromCharCode( - (code[0] & 15) << 12 | (code[1] & 63) << 6 - | code[2] & 63 - ); - i += 3; - } else { - error(code[2], i + 2); - } - } else { - error(code[1], i + 1); - } - } else { - error(code[0], i); - } - } - return ret; -} - -/*@ -Ox.encodeEmailAddress Returns obfuscated mailto: link - > Ox.encodeEmailAddress('mailto:foo@bar.com').indexOf(':') > -1 - true -@*/ -export function encodeEmailAddress(address, text) { - var parts = ['mailto:' + address, text || address].map(function(part) { - return map(part, function(char) { - var code = char.charCodeAt(0); - return char == ':' ? ':' - : '&#' - + (Math.random() < 0.5 ? code : 'x' + code.toString(16)) - + ';'; - }); - }); - return '' + parts[1] + ''; -} \ No newline at end of file diff --git a/src/ox/core/Format.js b/src/ox/core/Format.js deleted file mode 100644 index 7acca383..00000000 --- a/src/ox/core/Format.js +++ /dev/null @@ -1,969 +0,0 @@ -/** - * Format utilities - ES Module Version - * Converted from OxJS Format module while preserving original logic and documentation - */ - -import { isUndefined, isNumber } from './Type.js'; -import { mod, round, sum } from './Math.js'; -import { - getDay, getDayOfTheYear, getDate, getFullYear, getMonth, getHours, - getMinutes, getSeconds, getISOYear, getISOWeek, getISODay, - getWeek, getTimezoneOffset, getTimezoneOffsetString, makeDate, - setDate, setFullYear, setMonth, setHours, setMinutes, setSeconds, - getDaysInMonth, getFirstDayOfTheYear -} from './Date.js'; -import { filter, map, forEach } from './Collection.js'; -import { compact } from './Array.js'; -import { contains } from './Object.js'; -import { loop } from './Core.js'; -import { pad } from './String.js'; -import { _ } from './Locale.js'; - -// Helper functions not yet available in other modules -function last(array) { - return array[array.length - 1]; -} - -function sortBy(array, property) { - return array.slice().sort(function(a, b) { - var aVal = Array.isArray(property) ? property.map(p => a[p]) : a[property]; - var bVal = Array.isArray(property) ? property.map(p => b[p]) : b[property]; - return aVal > bVal ? 1 : aVal < bVal ? -1 : 0; - }); -} - -// Constants that would normally be in Ox object -const WEEKDAYS = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday']; -const SHORT_WEEKDAYS = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']; -const MONTHS = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; -const SHORT_MONTHS = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; -const AMPM = ['AM', 'PM']; -const BCAD = ['BC', 'AD']; -const PREFIXES = ['', 'k', 'M', 'G', 'T', 'P']; - -/*@ -formatArea Formats a number of meters as square meters or kilometers - > formatArea(1000) - '1,000 m²' - > formatArea(1000000) - '1 km²' -@*/ -export function formatArea(number, decimals) { - var k = number >= 1000000 ? 'k' : ''; - decimals = isUndefined(decimals) ? 8 : decimals; - return formatNumber( - (k ? number / 1000000 : number).toPrecision(decimals) - ) + ' ' + k + 'm\u00B2'; -} - -/*@ -formatCount Returns a string like "2 items", "1 item" or "no items". - > formatCount(0, 'item') - 'no items' - > formatCount(1, 'item') - '1 item' - > formatCount(1000, 'city', 'cities') - '1,000 cities' -@*/ -export function formatCount(number, singular, plural) { - plural = (plural || singular + 's') + (number === 2 ? '{2}' : ''); - return (number === 0 ? _('no') : formatNumber(number)) - + ' ' + _(number === 1 ? singular : plural); -} - -/*@ -formatCurrency Formats a number with a currency symbol - > formatCurrency(1000, '$', 2) - '$1,000.00' -@*/ -export function formatCurrency(number, string, decimals) { - return string + formatNumber(number, decimals); -} - -/*@ -formatDate Formats a date according to a format string - See - strftime - and ISO 8601. - 'E*%' (localized date and time), %Q' (quarter) and '%X'/'%x' - (year with 'BC'/'AD') are non-standard. - (string) -> formatted date - (date, string) -> formatted date - (date, string, utc) -> formatted date - string format string - date date - utc date is utc - - > formatDate(test.date, '%A') // Full weekday - 'Sunday' - > formatDate(test.date, '%a') // Abbreviated weekday - 'Sun' - > formatDate(test.date, '%B') // Full month - 'January' - > formatDate(test.date, '%b') // Abbreviated month - 'Jan' - > formatDate(test.date, '%C') // Century - '20' - > formatDate(test.date, '%c') // US time and date - '01/02/05 12:03:04 AM' - > formatDate(test.date, '%D') // US date - '01/02/05' - > formatDate(test.date, '%d') // Zero-padded day of the month - '02' - > formatDate(test.date, '%ED') // Localized date and time with seconds - '01/02/2005 00:03:04' - > formatDate(test.date, '%Ed') // Localized date and time without seconds - '01/02/2005 00:03' - > formatDate(test.date, '%EL') // Long localized date with weekday - 'Sunday, January 2, 2005' - > formatDate(test.date, '%El') // Long localized date without weekday - 'January 2, 2005' - > formatDate(test.date, '%EM') // Medium localized date with weekday - 'Sun, Jan 2, 2005' - > formatDate(test.date, '%Em') // Medium localized date without weekday - 'Jan 2, 2005' - > formatDate(test.date, '%ES') // Short localized date with century - '01/02/2005' - > formatDate(test.date, '%Es') // Short localized date without century - '01/02/05' - > formatDate(test.date, '%ET') // Localized time with seconds - '12:03:04 AM' - > formatDate(test.date, '%Et') // Localized time without seconds - '12:03 AM' - > formatDate(test.date, '%e') // Space-padded day of the month - ' 2' - > formatDate(test.date, '%F') // Date - '2005-01-02' - > formatDate(test.date, '%G') // Full ISO-8601 year - '2004' - > formatDate(test.date, '%g') // Abbreviated ISO-8601 year - '04' - > formatDate(test.date, '%H') // Zero-padded hour (24-hour clock) - '00' - > formatDate(test.date, '%h') // Abbreviated month - 'Jan' - > formatDate(test.date, '%I') // Zero-padded hour (12-hour clock) - '12' - > formatDate(test.date, '%j') // Zero-padded day of the year - '002' - > formatDate(test.date, '%k') // Space-padded hour (24-hour clock) - ' 0' - > formatDate(test.date, '%l') // Space-padded hour (12-hour clock) - '12' - > formatDate(test.date, '%M') // Zero-padded minute - '03' - > formatDate(test.date, '%m') // Zero-padded month - '01' - > formatDate(test.date, '%n') // Newline - '\n' - > formatDate(test.date, '%p') // AM or PM - 'AM' - > formatDate(test.date, '%Q') // Quarter of the year - '1' - > formatDate(test.date, '%R') // Zero-padded hour and minute - '00:03' - > formatDate(test.date, '%r') // US time - '12:03:04 AM' - > formatDate(test.date, '%S') // Zero-padded second - '04' - > formatDate(test.epoch, '%s', true) // Number of seconds since the Epoch - '0' - > formatDate(test.date, '%T') // Time - '00:03:04' - > formatDate(test.date, '%t') // Tab - '\t' - > formatDate(test.date, '%U') // Zero-padded week of the year (00-53, Sunday as first day) - '01' - > formatDate(test.date, '%u') // Decimal weekday (1-7, Monday as first day) - '7' - > formatDate(test.date, '%V') // Zero-padded ISO-8601 week of the year - '53' - > formatDate(test.date, '%v') // Formatted date - ' 2-Jan-2005' - > formatDate(test.date, '%W') // Zero-padded week of the year (00-53, Monday as first day) - '00' - > formatDate(test.date, '%w') // Decimal weekday (0-6, Sunday as first day) - '0' - > formatDate(test.date, '%X') // Full year with BC or AD - '2005 AD' - > formatDate(test.date, '%x') // Full year with BC or AD if year < 1000 - '2005' - > formatDate(test.date, '%Y') // Full year - '2005' - > formatDate(test.date, '%y') // Abbreviated year - '05' - > formatDate(test.date, '%Z', true) // Time zone name - 'UTC' - > formatDate(test.date, '%z', true) // Time zone offset - '+0000' - > formatDate(test.date, '%+').replace(/ [A-Z]+ /, ' XYZ ') // Formatted date and time - 'Sun Jan 2 00:03:04 XYZ 2005' - > formatDate(test.date, '%%') - '%' -@*/ - -// Format patterns for formatDate function -var formatPatterns = [ - ['%', function() { - return '%{%}'; - }], - ['c', function() { - return '%D %r'; - }], - ['D', function() { - return '%m/%d/%y'; - }], - ['ED', function() { - return '%ES %T'; - }], - ['Ed', function() { - return '%ES %R'; - }], - ['EL', function() { - return _('%A, %B %e, %Y'); - }], - ['El', function() { - return _('%B %e, %Y'); - }], - ['EM', function() { - return _('%a, %b %e, %Y'); - }], - ['Em', function() { - return _('%b %e, %Y'); - }], - ['ES', function() { - return _('%m/%d/%Y'); - }], - ['Es', function() { - return _('%m/%d/%y'); - }], - ['ET', function() { - return _('%I:%M:%S %p'); - }], - ['Et', function() { - return _('%I:%M %p'); - }], - ['F', function() { - return '%Y-%m-%d'; - }], - ['h', function() { - return '%b'; - }], - ['R', function() { - return '%H:%M'; - }], - ['r', function() { - return '%I:%M:%S %p'; - }], - ['T', function() { - return '%H:%M:%S'; - }], - ['v', function() { - return '%e-%b-%Y'; - }], - ['\\+', function() { - return '%a %b %e %H:%M:%S %Z %Y'; - }], - ['A', function(date, utc) { - return _(WEEKDAYS[(getDay(date, utc) + 6) % 7]); - }], - ['a', function(date, utc) { - return _(SHORT_WEEKDAYS[(getDay(date, utc) + 6) % 7]); - }], - ['B', function(date, utc) { - return _(MONTHS[getMonth(date, utc)]); - }], - ['b', function(date, utc) { - return _(SHORT_MONTHS[getMonth(date, utc)]); - }], - ['C', function(date, utc) { - return Math.floor(getFullYear(date, utc) / 100).toString(); - }], - ['d', function(date, utc) { - return pad(getDate(date, utc), 2); - }], - ['e', function(date, utc) { - return pad(getDate(date, utc), 2, ' '); - }], - ['G', function(date, utc) { - return getISOYear(date, utc); - }], - ['g', function(date, utc) { - return getISOYear(date, utc).toString().slice(-2); - }], - ['H', function(date, utc) { - return pad(getHours(date, utc), 2); - }], - ['I', function(date, utc) { - return pad((getHours(date, utc) + 11) % 12 + 1, 2); - }], - ['j', function(date, utc) { - return pad(getDayOfTheYear(date, utc), 3); - }], - ['k', function(date, utc) { - return pad(getHours(date, utc), 2, ' '); - }], - ['l', function(date, utc) { - return pad(((getHours(date, utc) + 11) % 12 + 1), 2, ' '); - }], - ['M', function(date, utc) { - return pad(getMinutes(date, utc), 2); - }], - ['m', function(date, utc) { - return pad((getMonth(date, utc) + 1), 2); - }], - ['p', function(date, utc) { - return _(AMPM[Math.floor(getHours(date, utc) / 12)]); - }], - ['Q', function(date, utc) { - return Math.floor(getMonth(date, utc) / 4) + 1; - }], - ['S', function(date, utc) { - return pad(getSeconds(date, utc), 2); - }], - ['s', function(date, utc) { - return Math.floor((+date - ( - utc ? getTimezoneOffset(date) : 0 - )) / 1000); - }], - ['U', function(date, utc) { - return pad(getWeek(date, utc), 2); - }], - ['u', function(date, utc) { - return getISODay(date, utc); - }], - ['V', function(date, utc) { - return pad(getISOWeek(date, utc), 2); - }], - ['W', function(date, utc) { - return pad(Math.floor((getDayOfTheYear(date, utc) - + (getFirstDayOfTheYear(date, utc) || 7) - 2) / 7), 2); - }], - ['w', function(date, utc) { - return getDay(date, utc); - }], - ['X', function(date, utc) { - var y = getFullYear(date, utc); - return Math.abs(y) + ' ' + _(BCAD[y < 0 ? 0 : 1]); - }], - ['x', function(date, utc) { - var y = getFullYear(date, utc); - return Math.abs(y) + ( - y < 1000 ? ' ' + _(BCAD[y < 0 ? 0 : 1]) : '' - ); - }], - ['Y', function(date, utc) { - return getFullYear(date, utc); - }], - ['y', function(date, utc) { - return getFullYear(date, utc).toString().slice(-2); - }], - ['Z', function(date, utc) { - return utc ? 'UTC' - : (date.toString().split('(')[1] || '').replace(')', ''); - }], - ['z', function(date, utc) { - return utc ? '+0000' : getTimezoneOffsetString(date); - }], - ['n', function() { - return '\n'; - }], - ['t', function() { - return '\t'; - }], - ['\\{%\\}', function() { - return '%'; - }] -].map(function(value) { - return [new RegExp('%' + value[0], 'g'), value[1]]; -}); - -export function formatDate(date, string, utc) { - if (date === '') { - return ''; - } - date = makeDate(date); - formatPatterns.forEach(function(value) { - string = string.replace(value[0], function() { - return value[1](date, utc); - }); - }); - return string; -} - -/*@ -formatDateRange Formats a date range as a string - A date range is a pair of arbitrary-presicion date strings - > formatDateRange('2000', '2001') - '2000' - > formatDateRange('2000', '2002') - '2000 - 2002' - > formatDateRange('2000-01', '2000-02') - 'January 2000' - > formatDateRange('2000-01', '2000-03') - 'January - March 2000' - > formatDateRange('2000-01-01', '2000-01-02') - 'Sat, Jan 1, 2000' - > formatDateRange('2000-01-01', '2000-01-03') - 'Sat, Jan 1 - Mon, Jan 3, 2000' - > formatDateRange('2000-01-01 00', '2000-01-01 01') - 'Sat, Jan 1, 2000, 00:00' - > formatDateRange('2000-01-01 00', '2000-01-01 02') - 'Sat, Jan 1, 2000, 00:00 - 02:00' - > formatDateRange('2000-01-01 00:00', '2000-01-01 00:01') - 'Sat, Jan 1, 2000, 00:00' - > formatDateRange('2000-01-01 00:00', '2000-01-01 00:02') - 'Sat, Jan 1, 2000, 00:00 - 00:02' - > formatDateRange('2000-01-01 00:00:00', '2000-01-01 00:00:01') - 'Sat, Jan 1, 2000, 00:00:00' - > formatDateRange('2000-01-01 00:00:00', '2000-01-01 00:00:02') - 'Sat, Jan 1, 2000, 00:00:00 - 00:00:02' - > formatDateRange('1999-12', '2000-01') - 'December 1999' - > formatDateRange('1999-12-31', '2000-01-01') - 'Fri, Dec 31, 1999' - > formatDateRange('1999-12-31 23:59', '2000-01-01 00:00') - 'Fri, Dec 31, 1999, 23:59' - > formatDateRange('-50', '50') - '50 BC - 50 AD' - > formatDateRange('-50-01-01', '-50-12-31') - 'Sun, Jan 1 - Sun, Dec 31, 50 BC' - > formatDateRange('-50-01-01 00:00:00', '-50-01-01 23:59:59') - 'Sun, Jan 1, 50 BC, 00:00:00 - 23:59:59' -@*/ -export function formatDateRange(start, end, utc) { - end = end || formatDate(new Date(), '%Y-%m-%d'); - var isOneUnit = false, - range = [start, end], - strings, - dates = range.map(function(str){ - return parseDate(str, utc); - }), - parts = range.map(function(str) { - var parts = compact( - /(-?\d+)-?(\d+)?-?(\d+)? ?(\d+)?:?(\d+)?:?(\d+)?/.exec(str) - ); - parts.shift(); - return parts.map(function(part) { - return parseInt(part, 10); - }); - }), - precision = parts.map(function(parts) { - return parts.length; - }), - y = parts[0][0] < 0 ? '%X' : '%Y', - formats = [ - y, - '%B ' + y, - '%a, %b %e, ' + y, - '%a, %b %e, ' + y + ', %H:%M', - '%a, %b %e, ' + y + ', %H:%M', - '%a, %b %e, ' + y + ', %H:%M:%S', - ]; - if (precision[0] == precision[1]) { - isOneUnit = true; - loop(precision[0], function(i) { - if ( - (i < precision[0] - 1 && parts[0][i] != parts[1][i]) - || (i == precision[0] - 1 && parts[0][i] != parts[1][i] - 1) - ) { - isOneUnit = false; - return false; // break - } - }); - } - if (isOneUnit) { - strings = [formatDate(dates[0], formats[precision[0] - 1], utc)]; - } else { - strings = [ - formatDate(dates[0], formats[precision[0] - 1], utc), - formatDate(dates[1], formats[precision[1] - 1], utc) - ]; - // if same year, and neither date is more precise than day, - // then omit first year - if ( - parts[0][0] == parts[1][0] - && precision[0] <= 3 - && precision[1] <= 3 - ) { - strings[0] = formatDate( - dates[0], formats[precision[0] - 1].replace( - new RegExp(',? ' + y), '' - ), utc - ); - } - // if same day then omit second day - if ( - parts[0][0] == parts[1][0] - && parts[0][1] == parts[1][1] - && parts[0][2] == parts[1][2] - ) { - strings[1] = strings[1].split(', ').pop(); - } - } - // %e is a space-padded day - return strings.join(' - ').replace(/ /g, ' '); -} - -/*@ -formatDateRangeDuration Formats the duration of a date range as a string - A date range is a pair of arbitrary-presicion date strings - > formatDateRangeDuration('2000-01-01 00:00:00', '2001-03-04 04:05:06') - '1 year 2 months 3 days 4 hours 5 minutes 6 seconds' - > formatDateRangeDuration('2000', '2001-01-01 00:00:01') - '1 year 1 second' - > formatDateRangeDuration('1999', '2000', true) - '1 year' - > formatDateRangeDuration('2000', '2001', true) - '1 year' - > formatDateRangeDuration('1999-02', '1999-03', true) - '1 month' - > formatDateRangeDuration('2000-02', '2000-03', true) - '1 month' -@*/ -export function formatDateRangeDuration(start, end, utc) { - end = end || formatDate(new Date(), '%Y-%m-%d'); - var date = parseDate(start, utc), - dates = [start, end].map(function(string) { - return parseDate(string, utc); - }), - keys = ['year', 'month', 'day', 'hour', 'minute', 'second'], - parts = ['FullYear', 'Month', 'Date', 'Hours', 'Minutes', 'Seconds'], - values = []; - date && keys.forEach(function(key, i) { - while (true) { - if (key == 'month') { - // set the day to the same day in the next month, - // or to its last day if the next month is shorter - var day = getDate(date, utc); - setDate(date, Math.min( - day, - getDaysInMonth( - getFullYear(date, utc), - getMonth(date, utc) + 2, - utc - ) - ), utc); - } - // advance the date by one unit - if (key == 'year') { - setFullYear(date, getFullYear(date, utc) + 1, utc); - } else if (key == 'month') { - setMonth(date, getMonth(date, utc) + 1, utc); - } else if (key == 'day') { - setDate(date, getDate(date, utc) + 1, utc); - } else if (key == 'hour') { - setHours(date, getHours(date, utc) + 1, utc); - } else if (key == 'minute') { - setMinutes(date, getMinutes(date, utc) + 1, utc); - } else if (key == 'second') { - setSeconds(date, getSeconds(date, utc) + 1, utc); - } - if (date <= dates[1]) { - // still within the range, add one unit - values[i] = (values[i] || 0) + 1; - } else { - // outside the range, rewind the date by one unit - if (key == 'year') { - setFullYear(date, getFullYear(date, utc) - 1, utc); - } else if (key == 'month') { - setMonth(date, getMonth(date, utc) - 1, utc); - } else if (key == 'day') { - setDate(date, getDate(date, utc) - 1, utc); - } else if (key == 'hour') { - setHours(date, getHours(date, utc) - 1, utc); - } else if (key == 'minute') { - setMinutes(date, getMinutes(date, utc) - 1, utc); - } else if (key == 'second') { - setSeconds(date, getSeconds(date, utc) - 1, utc); - } - // and revert to original day - key == 'month' && setDate(date, day, utc); - break; - } - } - }); - return filter(map(values, function(value, i) { - return value ? value + ' ' + keys[i] + (value > 1 ? 's' : '') : ''; - })).join(' '); -} - -/*@ -formatDegrees Formats degrees as D°MM'SS" - > formatDegrees(-111.11, 'lng') - "111°06'36\"W" -@*/ -export function formatDegrees(degrees, mode) { - var days = 0, - seconds = Math.round(Math.abs(degrees) * 3600), - sign = degrees < 0 ? '-' : '', - array = formatDuration(seconds).split(':'); - if (array.length == 4) { - days = parseInt(array.shift(), 10); - } - array[0] = days * 24 + parseInt(array[0], 10); - return (!mode ? sign : '') - + array[0] + '°' + array[1] + "'" + array[2] + '"' - + ( - mode == 'lat' ? (degrees < 0 ? 'S' : 'N') - : mode == 'lng' ? (degrees < 0 ? 'W' : 'E') - : '' - ); -} - -/*@ -formatDimensions Formats valus as dimension - > formatDimensions([1920, 1080], 'px') - "1,920 × 1,080 px" -@*/ -export function formatDimensions(array, string) { - return array.map(function(value) { - return formatNumber(value); - }).join(' × ') + (string ? ' ' + string : ''); -} - -export const formatResolution = formatDimensions; - -/*@ -formatDuration Formats a duration as a string - > formatDuration(3599.999) - '01:00:00' - > formatDuration(3599.999, 2) - '01:00:00.00' - > formatDuration(3599.999, 3) - '00:59:59.999' - > formatDuration(3599.999, 'short') - '1h' - > formatDuration(3599.999, 3, 'short') - '59m 59.999s' - > formatDuration(3599.999, 'long') - '1 hour' - > formatDuration(3599.999, 3, 'long') - '59 minutes 59.999 seconds' - > formatDuration(1640673) - '18:23:44:33' - > formatDuration(86520, 2) - '1:00:02:00.00' - > formatDuration(86520, 'long') - '1 day 2 minutes' - > formatDuration(31543203, 2) - '1:000:02:00:03.00' - > formatDuration(31543203, 'long') - '1 year 2 hours 3 seconds' - > formatDuration(0, 2) - '00:00:00.00' - > formatDuration(0, 'long') - '' -@*/ -export function formatDuration(seconds/*, decimals, format*/) { - var lastArg = last(arguments), - format = lastArg == 'short' || lastArg == 'long' ? lastArg : 'none', - decimals = isNumber(arguments[1]) ? arguments[1] : 0, - seconds = round(Math.abs(seconds), decimals), - values = [ - Math.floor(seconds / 31536000), - Math.floor(seconds % 31536000 / 86400), - Math.floor(seconds % 86400 / 3600), - Math.floor(seconds % 3600 / 60), - formatNumber(seconds % 60, decimals) - ], - string = format == 'short' ? ['y', 'd', 'h', 'm', 's'] - : format == 'long' ? ['year', 'day', 'hour', 'minute', 'second'] - : [], - padArray = [ - values[0].toString().length, - values[0] ? 3 : values[1].toString().length, - 2, - 2, - decimals ? decimals + 3 : 2 - ]; - while (!values[0] && values.length > (format == 'none' ? 3 : 1)) { - values.shift(); - string.shift(); - padArray.shift(); - } - return filter(map(values, function(value, index) { - var ret; - if (format == 'none') { - ret = pad(value, 'left', padArray[index], '0'); - } else if (isNumber(value) ? value : parseFloat(value)) { - ret = value + (format == 'long' ? ' ' : '') + _(string[index] + ( - format == 'long' - ? (value == 1 ? '' : value == 2 ? 's{2}' : 's') - : '' - )); - } else { - ret = ''; - } - return ret; - })).join(format == 'none' ? ':' : ' '); -} - -/*@ -formatISBN Formats a string as an ISBN of a given length (10 or 13) - (isbn, length) -> ISBN - isbn ISBN - length length (10 or 13) - > formatISBN('0-306-40615-2', 13, true) - '978-0-306-40615-7' - > formatISBN('978-0-306-40615-7', 10) - '0306406152' -@*/ -export function formatISBN(isbn, length, dashes) { - var ret = ''; - function getCheckDigit(isbn) { - var modValue = isbn.length == 10 ? 11 : 10 - return (mod(modValue - sum( - isbn.slice(0, -1).split('').map(function(digit, index) { - return isbn.length == 10 - ? parseInt(digit) * (10 - index) - : parseInt(digit) * (index % 2 == 0 ? 1 : 3); - }) - ), modValue) + '').replace('10', 'X'); - } - isbn = isbn.toUpperCase().replace(/[^\dX]/g, ''); - if (isbn.length == 10) { - isbn = isbn.slice(0, -1).replace(/\D/g, '') + isbn.slice(-1); - } - if ( - (isbn.length == 10 || isbn.length == 13) - && isbn.slice(-1) == getCheckDigit(isbn) - ) { - if (isbn.length == length) { - ret = isbn - } else if (isbn.length == 10 || isbn.slice(0, 3) == '978') { - isbn = isbn.length == 10 ? '978' + isbn : isbn.slice(3); - ret = isbn.slice(0, -1) + getCheckDigit(isbn); - } - } - return dashes ? [ - ret.slice(-13, -10), - ret.slice(-10, -9), - ret.slice(-9, -6), - ret.slice(-6, -1), - ret.slice(-1) - ].join('-').replace(/^-+/, '') : ret; -} - -/*@ -formatNumber Formats a number with thousands separators - (num, dec) -> format number to string - num number - dec number of decimals - > formatNumber(123456789, 3) - "123,456,789.000" - > formatNumber(-2000000 / 3, 3) - "-666,666.667" - > formatNumber(666666.666) - "666,667" -@*/ -export function formatNumber(number, decimals) { - var array = [], - abs = Math.abs(number), - split = abs.toFixed(decimals).split('.'); - while (split[0]) { - array.unshift(split[0].slice(-3)); - split[0] = split[0].slice(0, -3); - } - split[0] = array.join(_(',')); - return (number < 0 ? '-' : '') + split.join(_('.')); -} - -/*@ -formatOrdinal Formats a number as an ordinal - > formatOrdinal(1) - "1st" - > formatOrdinal(2) - "2nd" - > formatOrdinal(3) - "3rd" - > formatOrdinal(4) - "4th" - > formatOrdinal(11) - "11th" - > formatOrdinal(12) - "12th" - > formatOrdinal(13) - "13th" -@*/ -export function formatOrdinal(number) { - var string = formatNumber(number), - length = string.length, - lastChar = string[length - 1], - ten = length > 1 && string[length - 2] == '1', - twenty = length > 1 && !ten; - if (lastChar == '1' && !ten) { - string += _('st' + (twenty ? '{21}' : '')); - } else if (lastChar == '2' && !ten) { - string += _('nd' + (twenty ? '{22}' : '')); - } else if (lastChar == '3' && !ten) { - string += _('rd' + (twenty ? '{23}' : '')); - } else { - string += _( - 'th' + (contains('123', lastChar) && ten ? '{1' + lastChar + '}' : '') - ); - } - return string; -} - -/*@ -formatPercent Formats the relation of two numbers as a percentage - > formatPercent(1, 1000, 2) - "0.10%" -@*/ -export function formatPercent(number, total, decimals) { - return formatNumber(number / total * 100, decimals) + _('%'); -} - -/*@ -formatRoman Formats a number as a roman numeral - > formatRoman(1888) - 'MDCCCLXXXVIII' - > formatRoman(1999) - 'MCMXCIX' - > formatRoman(2000) - 'MM' - > formatRoman(-1) - '' - > formatRoman(0) - '' - > formatRoman(9.9) - 'IX' - > formatRoman(10000) - 'MMMMMMMMMM' -@*/ -export function formatRoman(number) { - var string = ''; - forEach({ - M: 1000, CM: 900, D: 500, CD: 400, C: 100, XC: 90, - L: 50, XL: 40, X: 10, IX: 9, V: 5, IV: 4, I: 1 - }, function(value, roman) { - while (number >= value) { - string += roman; - number -= value; - } - }); - return string; -} - -/*@ -formatSRT Formats subtitles as SRT -@*/ -export function formatSRT(subtitles) { - return '\ufeff' + sortBy(subtitles, ['in', 'out']).map(function(subtitle, index) { - return [ - index + 1, - ['in', 'out'].map(function(key) { - return formatDuration(subtitle[key], 3).replace('.', ','); - }).join(' --> '), - subtitle['text'] - ].join('\r\n') - }).join('\r\n\r\n') + '\r\n\r\n'; -} - -/*@ -formatString Basic string formatting - > formatString('{0}{1}', ['foo', 'bar']) - 'foobar' - > formatString('{a}{b}', {a: 'foo', b: 'bar'}) - 'foobar' - > formatString('{a.x}{a.y}', {a: {x: 'foo', y: 'bar'}}) - 'foobar' - > formatString('{a\\.b}', {'a.b': 'foobar'}) - 'foobar' - > formatString('{1}', ['foobar']) - '' - > formatString('{b}', {a: 'foobar'}, true) - '{b}' -@*/ -export function formatString(string, collection, keepUnmatched) { - return string.replace(/\{([^}]+)\}/g, function(string, match) { - // make sure to not split at escaped dots ('\.') - var key, - keys = match.replace(/\\\./g, '\n').split('.').map(function(key) { - return key.replace(/\n/g, '.'); - }), - value = collection || {}; - while (keys.length) { - key = keys.shift(); - if (value[key]) { - value = value[key]; - } else { - value = null; - break; - } - } - return value !== null ? value : keepUnmatched ? '{' + match + '}' : ''; - }); -} - -/*@ -formatUnit Formats a number with a unit - > formatUnit(100/3, 'm', 2) - '33.33 m' - > formatUnit(100/3, '%') - '33%' -@*/ -export function formatUnit(number, string, decimals) { - return formatNumber(number, decimals) - + (/^[:%]/.test(string) ? '' : ' ') + string; -} - -/*@ -formatValue Formats a numerical value - > formatValue(0, "B") - "0 B" - > formatValue(123456789, "B") - "123.5 MB" - > formatValue(1234567890, "B", true) - "1.15 GiB" -@*/ -// fixme: is this the best name? -export function formatValue(number, string, bin) { - var base = bin ? 1024 : 1000, - length = PREFIXES.length, - ret; - forEach(PREFIXES, function(prefix, index) { - if (number < Math.pow(base, index + 1) || index == length - 1) { - ret = formatNumber( - number / Math.pow(base, index), index ? index - 1 : 0 - ) + ' ' + prefix + (prefix && bin ? 'i' : '') + string; - return false; // break - } - }); - return ret; -} - -/** - * Parse a date string - simplified implementation for now - */ -export function parseDate(string, utc) { - return new Date(string); -} - -// Export all functions -export default { - formatArea, - formatCount, - formatCurrency, - formatDate, - parseDate, - formatDateRange, - formatDateRangeDuration, - formatDegrees, - formatDimensions, - formatResolution, - formatDuration, - formatISBN, - formatNumber, - formatOrdinal, - formatPercent, - formatRoman, - formatSRT, - formatString, - formatUnit, - formatValue -}; \ No newline at end of file diff --git a/src/ox/core/Geo.js b/src/ox/core/Geo.js deleted file mode 100644 index cff49e0e..00000000 --- a/src/ox/core/Geo.js +++ /dev/null @@ -1,7 +0,0 @@ -// Geo module - geographic utilities -// This will be migrated in a future iteration -// For now, we provide basic stubs - -export function parseGeoname() { - throw new Error('Geo.parseGeoname not yet migrated to ES modules'); -} \ No newline at end of file diff --git a/src/ox/core/HTML.js b/src/ox/core/HTML.js deleted file mode 100644 index cd9eb7e4..00000000 --- a/src/ox/core/HTML.js +++ /dev/null @@ -1,678 +0,0 @@ -import { range, char, random, values, keyOf, forEach, map, splice, contains, isEmpty, clean } from './Array.js'; -import { isRegExp, isUndefined } from './Type.js'; -import { escapeRegExp } from './RegExp.js'; -import { formatString } from './Format.js'; -import { pad } from './String.js'; - -var defaultTags = [ - // inline formatting - {'name': 'b'}, - {'name': 'bdi'}, - {'name': 'code'}, - {'name': 'em'}, - {'name': 'i'}, - {'name': 'q'}, - {'name': 's'}, - {'name': 'span'}, - {'name': 'strong'}, - {'name': 'sub'}, - {'name': 'sup'}, - {'name': 'u'}, - // block formatting - {'name': 'blockquote'}, - {'name': 'cite'}, - { - 'name': 'div', - 'optional': ['style'], - 'validate': { - 'style': /^direction: rtl$/ - } - }, - {'name': 'h1'}, - {'name': 'h2'}, - {'name': 'h3'}, - {'name': 'h4'}, - {'name': 'h5'}, - {'name': 'h6'}, - {'name': 'p'}, - {'name': 'pre'}, - // lists - {'name': 'li'}, - {'name': 'ol'}, - {'name': 'ul'}, - // definition lists - {'name': 'dl'}, - {'name': 'dt'}, - {'name': 'dd'}, - // tables - {'name': 'table'}, - {'name': 'tbody'}, - {'name': 'td'}, - {'name': 'tfoot'}, - {'name': 'th'}, - {'name': 'thead'}, - {'name': 'tr'}, - // other - {'name': '[]'}, - { - 'name': 'a', - 'required': ['href'], - 'optional': ['target'], - 'validate': { - 'href': /^((https?:\/\/|\/|mailto:).*?)/, - 'target': /^_blank$/ - } - }, - {'name': 'br'}, - { - 'name': 'iframe', - 'optional': ['width', 'height'], - 'required': ['src'], - 'validate': { - 'width': /^\d+$/, - 'height': /^\d+$/, - 'src': /^((https?:\/\/|\/).*?)/ - } - }, - { - 'name': 'img', - 'optional': ['width', 'height'], - 'required': ['src'], - 'validate': { - 'width': /^\d+$/, - 'height': /^\d+$/, - 'src': /^((https?:\/\/|\/).*?)/ - }, - }, - {'name': 'figure'}, - {'name': 'figcaption'} - ], - htmlEntities = { - '"': '"', '&': '&', "'": ''', '<': '<', '>': '>' - }, - regexp = { - entity: /&[^\s]+?;/g, - html: /[<&]/, - tag: new RegExp('<\\/?(' + [ - 'a', 'b', 'br', 'code', 'i', 's', 'span', 'u' - ].join('|') + ')\\/?>', 'gi') - }, - salt = range(2).map(function(){ - return range(16).map(function() { - return char(65 + random(26)); - }).join(''); - }); - -function addLinksInternal(string, obfuscate) { - return string - .replace( - /\b((https?:\/\/|www\.).+?)([.,:;!?)\]]*?(\s|$))/gi, - function(match, url, prefix, end) { - prefix = prefix.toLowerCase() == 'www.' ? 'http://' : ''; - return formatString( - '{url}{end}', - {end: end, prefix: prefix, url: url} - ); - } - ) - .replace( - /\b([0-9A-Z.+\-_]+@(?:[0-9A-Z\-]+\.)+[A-Z]{2,6})\b/gi, - obfuscate ? function(match, mail) { - return encodeEmailAddress(mail); - } : '$1' - ); -} - -function decodeHTMLEntitiesInternal(string) { - return string - .replace( - new RegExp('(' + values(htmlEntities).join('|') + ')', 'g'), - function(match) { - return keyOf(htmlEntities, match); - } - ) - .replace( - /&#([0-9A-FX]+);/gi, - function(match, code) { - return char( - /^X/i.test(code) - ? parseInt(code.slice(1), 16) - : parseInt(code, 10) - ); - } - ); -} - -// Splits a string into text (even indices) and tags (odd indices), ignoring -// tags with starting positions that are included in the ignore array -function splitHTMLTags(string, ignore) { - var isTag = false, ret = ['']; - ignore = ignore || []; - forEach(string, function(char, i) { - if (!isTag && char == '<' && ignore.indexOf(i) == -1) { - isTag = true; - ret.push(''); - } - ret[ret.length - 1] += char; - if (isTag && char == '>') { - isTag = false; - ret.push(''); - } - }); - return ret; -} - -/*@ -Ox.addLinks Takes a string and adds links for e-mail addresses and URLs - (string[, isHTML]) -> Formatted string - string String - isHTML If true, ignore matches in tags or enclosed by links - > Ox.addLinks('foo bar ') - 'foo bar <foo@bar.com>' - > Ox.addLinks('www.foo.com/bar#baz, etc.') - 'www.foo.com/bar#baz, etc.' - > Ox.addLinks('www.foo.com', true) - 'www.foo.com' -@*/ -export function addLinks(string, isHTML) { - var isLink = false; - return isHTML - ? splitHTMLTags(string).map(function(string, i) { - var isTag = i % 2; - if (isTag) { - if (/^ Returns obfuscated mailto: link - > Ox.encodeEmailAddress('mailto:foo@bar.com').indexOf(':') > -1 - true -@*/ -export function encodeEmailAddress(address, text) { - var parts = ['mailto:' + address, text || address].map(function(part) { - return map(part, function(char) { - var code = char.charCodeAt(0); - return char == ':' ? ':' - : '&#' - + (Math.random() < 0.5 ? code : 'x' + code.toString(16)) - + ';'; - }); - }); - return '' + parts[1] + ''; -} - -/*@ -Ox.encodeHTMLEntities Encodes HTML entities - (string[, encodeAll]) -> String - string String - encodeAll If true, encode characters > 127 as numeric entities - > Ox.encodeHTMLEntities('<\'&"> äbçdê') - '<'&"> äbçdê' - > Ox.encodeHTMLEntities('<\'&"> äbçdê', true) - '<'&"> äbçdê' -@*/ -export function encodeHTMLEntities(string, encodeAll) { - return map(String(string), function(char) { - var code = char.charCodeAt(0); - if (code < 128) { - char = char in htmlEntities ? htmlEntities[char] : char; - } else if (encodeAll) { - char = '&#x' - + pad(code.toString(16).toUpperCase(), 'left', 4, '0') - + ';'; - } - return char; - }); -} - -/*@ -Ox.decodeHTMLEntities Decodes HTML entities - (string[, decodeAll]) -> String - string String - decodeAll If true, decode named entities for characters > 127 - Note that `decodeAll` relies on `Ox.normalizeHTML`, which uses the - DOM and may transform the string - > Ox.decodeHTMLEntities('<'&">') - '<\'&">' - > Ox.decodeHTMLEntities('<'&">') - '<\'&">' - > Ox.decodeHTMLEntities('äbçdê') - 'äbçdê' - > Ox.decodeHTMLEntities('äbçdê') - 'äbçdê' - > Ox.decodeHTMLEntities('äbçdê', true) - 'äbçdê' - > Ox.decodeHTMLEntities('β') - 'β' - > Ox.decodeHTMLEntities('β', true) - 'β' - > Ox.decodeHTMLEntities('<b>') - '' -@*/ -export function decodeHTMLEntities(string, decodeAll) { - return decodeAll - ? decodeHTMLEntities(normalizeHTML(string)) - : decodeHTMLEntitiesInternal(string); -} - -/*@ -Ox.highlight Highlight matches in string - (string, query, classname[, isHTML]) -> Output string - string Input string - query Case-insentitive query string, or regular expression - classname Class name for matches - isHTML If true, the input string is treated as HTML - > Ox.highlight('', 'foo', 'c') - '<foo><bar>' - > Ox.highlight('&', '&', 'c') - '&amp;' - > Ox.highlight('&', '&', 'c') - '&' - > Ox.highlight('<foo> <foo>', '', 'c', true) - '<foo> <foo>' - > Ox.highlight('name', 'name', 'c', true) - 'name' - > Ox.highlight('amp & amp', 'amp', 'c', true) - 'amp & amp' - > Ox.highlight('amp & amp', 'amp & amp', 'c', true) - 'amp & amp' - > Ox.highlight('<b>', '', 'c', true) - '<b>' - > Ox.highlight('<b>', '<b>', 'c', true) - '<b>' - > Ox.highlight('foobarbaz', 'foobar', 'c', true) - 'foobarbaz' - > Ox.highlight('foo

bar

baz', 'foobar', 'c', true) - 'foo

bar

baz' - > Ox.highlight('foo
bar baz', 'foo bar', 'c', true) - 'foo
bar
baz' -@*/ -export function highlight(string, query, classname, isHTML) { - if (!query) { - return string; - } - var cursor = 0, - entities = [], - matches = [], - offset = 0, - re = isRegExp(query) ? query - : new RegExp(escapeRegExp(query), 'gi'), - span = ['', ''], - tags = []; - function insert(array) { - // for each replacement - array.forEach(function(v) { - // replace the modified value with the original value - string = splice(string, v.position, v.length, v.value); - // for each match - matches.forEach(function(match) { - if (v.position < match.position) { - // replacement is before match, update match position - match.position += v.value.length - v.length; - } else if ( - v.position < match.position + match.value.length - ) { - // replacement is inside match, update match value - match.value = splice( - match.value, v.position - match.position, v.length, - v.value - ); - } - }); - }); - } - if (isHTML && regexp.html.test(string)) { - string = string // Ox.normalizeHTML(string) - // remove inline tags - .replace(regexp.tag, function(value, tag, position) { - tags.push({ - length: 0, position: position, value: value - }); - return ''; - }) - // decode html entities - .replace(regexp.entity, function(value, position) { - var ret = decodeHTMLEntitiesInternal(value, true); - entities.push({ - length: ret.length, position: position, value: value - }); - return ret; - }); - // if decoding entities has created new tags, ignore them - splitHTMLTags(string, entities.map(function(entity) { - var ret = entity.position + offset; - offset += entity.length - entity.value.length; - return ret; - })).forEach(function(v, i) { - if (i % 2 == 0) { - // outside tags, find matches and save position and value - v.replace(re, function(value, position) { - matches.push( - {position: cursor + position, value: value} - ); - }); - } - cursor += v.length; - }); - insert(entities); - insert(tags); - // for each match (in reverse order, so that positions are correct) - matches.reverse().forEach(function(match) { - // wrap it in a span - string = splice( - string, match.position, match.value.length, - span.join(match.value) - ); - }); - // we may have enclosed single opening or closing tags in a span - if (matches.length && tags.length) { - string = normalizeHTML(string); - } - } else { - string = encodeHTMLEntities( - string.replace(re, function(value) { - matches.push(span.join(encodeHTMLEntities(value))); - return salt.join(matches.length - 1); - }) - ); - matches.forEach(function(match, i) { - string = string.replace(new RegExp(salt.join(i)), match); - }); - } - return string; -} - -/*@ -Ox.normalizeHTML Normalize HTML (using the DOM) - > Ox.normalizeHTML('foo') - 'foo' - > Ox.normalizeHTML('foo') - 'foo' - > Ox.normalizeHTML('<'&"> äbçdê') - '<\'&"> äbçdê' -@*/ -export function normalizeHTML(html) { - if (!regexp.html.test(html)) { - return html; - } - // Simple implementation for Node.js environments - // In browser environments, this would use DOM manipulation - if (typeof document !== 'undefined') { - var div = document.createElement('div'); - div.innerHTML = html; - return div.innerHTML; - } - return html; -} - -/*@ -Ox.parseMarkdown Parses (a tiny subset of) Markdown. - Supports `*emphasis*`, `_emphasis_`, `**strong**`, `__strong__`, - `` `code` ``, ``` ``code with backtick (`)`` ```, - ```` ```classname\ngithub-style\ncode blocks\n``` ````, - ``, `` and - `[text](http://example.com "title")`. - > Ox.parseMarkdown('*foo* **bar** `baz` ``back`tick``') - 'foo bar baz back`tick' - > Ox.parseMarkdown('foo\n\nbar\n\nbaz') - 'foo

bar

baz' - > Ox.parseMarkdown('```foo\n\nbar\n\nbaz\n```') - '
bar\n\nbaz\n
' - > Ox.parseMarkdown('') - 'http://example.com' - > Ox.parseMarkdown('``') - '<http://example.com>' - > Ox.parseMarkdown('[example](http://example.com "example.com")') - 'example' - > Ox.parseMarkdown('[example](http://example.com?foo=bar&bar=baz)') - 'example' - > Ox(Ox.parseMarkdown('')).startsWith('mail@example.com' -*/ -export function parseMarkdown(string) { - // see https://github.com/coreyti/showdown/blob/master/src/showdown.js - var array = []; - return string.replace(/\r\n/g, '\n').replace(/\r/g, '\n') - .replace( - /(?:^|\n)```(.*)\n([^`]+)\n```/g, - function(match, classname, code) { - array.push( - '
'
-                    + code.trim().replace(/
' - ); - return salt.join(array.length - 1); - } - ) - .replace( - /(^|[^\\])(`+)([^\r]*?[^`])\2(?!`)/gm, - function(match, prev, backticks, code, next) { - array.push( - prev + '' - + code.trim().replace(/' - ); - return salt.join(array.length - 1); - } - ) - .replace( - /(\*\*|__)(?=\S)([^\r]*?\S[*_]*)\1/g, - '$2' - ) - .replace( - /(\*|_)(?=\S)([^\r]*?\S)\1/g, - '$2' - ) - .replace( - /(\[((?:\[[^\]]*\]|[^\[\]])*)\]\([ \t]*()?[ \t]*((['"])(.*?)\6[ \t]*)?\))/g, - function(match, all, text, id, url, rest, quote, title) { - return '' + text + ''; - } - ) - .replace( - /<((https?|ftp|dict):[^'">\s]+)>/gi, - '$1' - ) - .replace( - /<(?:mailto:)?([-.\w]+\@[-a-z0-9]+(\.[-a-z0-9]+)*\.[a-z]+)>/gi, - function(match, mail) { - return encodeEmailAddress(mail); - } - ) - .replace(/\n\n/g, '

') - .replace( - new RegExp(salt.join('(\\d+)'), 'g'), - function(match, index) { - return array[parseInt(index)]; - } - ); -} - -/*@ -Ox.sanitizeHTML Takes untrusted HTML and returns something trustworthy - > Ox.sanitizeHTML('http://foo.com, ...') - 'http://foo.com, ...' - > Ox.sanitizeHTML('http://foo.com/foo?bar&baz, ...') - 'http://foo.com/foo?bar&baz, ...' - > Ox.sanitizeHTML('(see: www.foo.com)') - '(see: www.foo.com)' - > Ox.sanitizeHTML('foo@bar.com') - 'foo@bar.com' - > Ox.sanitizeHTML('foo') - 'foo' - > Ox.sanitizeHTML('foo') - 'foo' - > Ox.sanitizeHTML('http://www.foo.com/') - 'http://www.foo.com/' - > Ox.sanitizeHTML('foo') - 'foo' - > Ox.sanitizeHTML('foo') - 'foo' - > Ox.sanitizeHTML('foo') - '<a href="javascript:alert()">foo</a>' - > Ox.sanitizeHTML('foo') - '<a href="foo">foo</a>' - > Ox.sanitizeHTML('foo') - 'foo' - > Ox.sanitizeHTML('foo') - 'foo' - > Ox.sanitizeHTML('[http://foo.com foo]') - 'foo' - > Ox.sanitizeHTML('
foo
') - '
foo
' - > Ox.sanitizeHTML('') - '<script>alert()</script>' - > Ox.sanitizeHTML('\'foo\' < \'bar\' && "foo" > "bar"') - '\'foo\' < \'bar\' && "foo" > "bar"' - > Ox.sanitizeHTML('foo') - 'foo' - > Ox.sanitizeHTML('foo') - 'foo' - > Ox.sanitizeHTML('&&') - '&&' - > Ox.sanitizeHTML('') - '<http://foo.com>' - > Ox.sanitizeHTML('') - '"<foo value="http://foo.com"></foo>"' -@*/ -export function sanitizeHTML(html, tags, globalAttributes) { - - tags = tags || defaultTags; - globalAttributes = globalAttributes || []; - - var escaped = {}, - level = 0, - matches = [], - selfClosingTags = ['img', 'br'], - validAttributes = {}, requiredAttributes = {}, validate = {}, - validTags = tags.map(function(tag) { - validAttributes[tag.name] = globalAttributes - .concat(tag.required || []) - .concat(tag.optional || []); - requiredAttributes[tag.name] = tag.required || []; - validate[tag.name] = tag.validate || {}; - return tag.name; - }); - - // html = clean(html); fixme: can this be a parameter? - if (contains(validTags, '[]')) { - html = html.replace( - /\[((\/|https?:\/\/|mailto:).+?) (.+?)\]/gi, - '$3' - ); - validTags = validTags.filter(function(tag) { - return tag != '[]'; - }); - } - - html = splitHTMLTags(html).map(function(string, i) { - - var attrs = {}, - attrMatch, - attrRegexp = /([^=\ ]+)="([^"]+)"/g, - attrString, - isClosing, - isTag = i % 2, - isValid = true, - tag, - tagMatch, - tagRegexp = /<(\/)?([^\ \/]+)(.*?)(\/)?>/g; - - if (isTag) { - tagMatch = tagRegexp.exec(string); - if (tagMatch) { - isClosing = !isUndefined(tagMatch[1]); - tag = tagMatch[2]; - attrString = tagMatch[3].trim(); - while (attrMatch = attrRegexp.exec(attrString)) { - if ( - validAttributes[tag] - && contains(validAttributes[tag], attrMatch[1]) - ) { - attrs[attrMatch[1]] = attrMatch[2]; - } - } - if (!isClosing && !contains(selfClosingTags, tag)) { - level++; - } - if ( - !contains(validTags, tag) - || (attrString.length && isEmpty(attrs)) - ) { - isValid = false; - } else if (!isClosing && requiredAttributes[tag]) { - requiredAttributes[tag].forEach(function(attr) { - if (isUndefined(attrs[attr])) { - isValid = false; - } - }); - } - if (isValid && !isEmpty(attrs)) { - forEach(attrs, function(value, key) { - if ( - !isUndefined(validate[tag][key]) - && !validate[tag][key].exec(value) - ) { - isValid = false; - return false; // break - } - }); - } - if (isValid && isClosing) { - isValid = !escaped[level]; - } else { - escaped[level] = !isValid; - } - if (isClosing) { - level--; - } - if (isValid) { - return '<' - + (isClosing ? '/' : '') - + tag - + (!isClosing && !isEmpty(attrs) - ? ' ' + values(map(attrs, function(value, key) { - return key + '="' + value + '"'; - })).join(' ') - : '') - + '>'; - } - } - } - - return encodeHTMLEntities(decodeHTMLEntitiesInternal(string)); - - }).join(''); - - //FIXME: dont add links to urls inside of escaped tags - html = addLinks(html, true); - html = html.replace(/\n\n/g, '

'); - // Close extra opening and remove extra closing tags. - // Note: this converts ''' to "'" and '"' to '"' - return normalizeHTML(html); - -} - -/*@ -Ox.stripTags Strips HTML tags from a string - > Ox.stripTags('foo') - 'foo' -@*/ -export function stripTags(string) { - return string.replace(/<.*?>/g, ''); -} \ No newline at end of file diff --git a/src/ox/core/Hash.js b/src/ox/core/Hash.js deleted file mode 100644 index 3a3c2ab8..00000000 --- a/src/ox/core/Hash.js +++ /dev/null @@ -1,229 +0,0 @@ -import { pad } from './String.js'; -import { encodeUTF8 } from './Encoding.js'; - -/*@ -Ox.oshash Calculates oshash for a given file or blob object. Async. -@*/ -export function oshash(file, callback) { - - // Needs to go via string to work for files > 2GB - var hash = fromString(file.size.toString()); - - read(0); - - function add(A, B) { - var a, b, c, d; - d = A[3] + B[3]; - c = A[2] + B[2] + (d >> 16); - d &= 0xffff; - b = A[1] + B[1] + (c >> 16); - c &= 0xffff; - a = A[0] + B[0] + (b >> 16); - b &= 0xffff; - // Cut off overflow - a &= 0xffff; - return [a, b, c, d]; - } - - function fromData(s, offset) { - offset = offset || 0; - return [ - s.charCodeAt(offset + 6) + (s.charCodeAt(offset + 7) << 8), - s.charCodeAt(offset + 4) + (s.charCodeAt(offset + 5) << 8), - s.charCodeAt(offset + 2) + (s.charCodeAt(offset + 3) << 8), - s.charCodeAt(offset + 0) + (s.charCodeAt(offset + 1) << 8) - ]; - } - - function fromString(str) { - var base = 10, - blen = 1, - i, - num, - pos, - r = [0, 0, 0, 0]; - for (pos = 0; pos < str.length; pos++) { - num = parseInt(str.charAt(pos), base); - i = 0; - do { - while (i < blen) { - num += r[3 - i] * base; - r[3 - i++] = (num & 0xFFFF); - num >>>= 16; - } - if (num) { - blen++; - } - } while (num); - } - return r; - } - - function hex(h) { - return ( - pad(h[0].toString(16), 'left', 4, '0') - + pad(h[1].toString(16), 'left', 4, '0') - + pad(h[2].toString(16), 'left', 4, '0') - + pad(h[3].toString(16), 'left', 4, '0') - ).toLowerCase(); - } - - function read(offset, last) { - var blob, - block = 65536, - length = 8, - reader = new FileReader(); - reader.onload = function(data) { - var s = data.target.result, - s_length = s.length - length, - i; - for (i = 0; i <= s_length; i += length) { - hash = add(hash, fromData(s, i)); - } - if (file.size < block || last) { - callback(hex(hash)); - } else { - read(file.size - block, true); - } - }; - if (file.mozSlice) { - blob = file.mozSlice(offset, offset + block); - } else if (file.webkitSlice) { - blob = file.webkitSlice(offset, offset + block); - } else { - blob = file.slice(offset, offset + block); - } - reader.readAsBinaryString(blob); - } - -} - -/*@ -Ox.SHA1 Calculates SHA1 hash of the given string -@*/ -export function SHA1(msg) { - - function rotate_left(n,s) { - var t4 = ( n<>>(32-s)); - return t4; - }; - - function cvt_hex(val) { - var str=""; - var i; - var v; - for ( i=7; i>=0; i-- ) { - v = (val>>>(i*4))&0x0f; - str += v.toString(16); - } - return str; - }; - - var blockstart; - var i, j; - var W = new Array(80); - var H0 = 0x67452301; - var H1 = 0xEFCDAB89; - var H2 = 0x98BADCFE; - var H3 = 0x10325476; - var H4 = 0xC3D2E1F0; - var A, B, C, D, E; - var temp; - - msg = encodeUTF8(msg); - - var msg_len = msg.length; - - var word_array = new Array(); - for ( i=0; i>>29 ); - word_array.push( (msg_len<<3)&0x0ffffffff ); - - - for ( blockstart=0; blockstart Escapes a string for use in a regular expression - (str) -> Escaped string - str String - > Ox.escapeRegExp('foo.com/bar?baz') - 'foo\\.com\\/bar\\?baz' - > new RegExp(Ox.escapeRegExp('/\\^$*+?.-|(){}[]')).test('/\\^$*+?.-|(){}[]') - true -@*/ -// see https://developer.mozilla.org/en/JavaScript/Guide/Regular_Expressions -export function escapeRegExp(string) { - return (string + '').replace(/([\/\\^$*+?.\-|(){}[\]])/g, '\\$1'); -} \ No newline at end of file diff --git a/src/ox/core/String.js b/src/ox/core/String.js index 711bb21f..a6b55674 100644 --- a/src/ox/core/String.js +++ b/src/ox/core/String.js @@ -3,7 +3,7 @@ */ import { isArray, isNumber, isString, isUndefined } from './Type.js'; -import { map, slice } from './Collection.js'; +import { map } from './Collection.js'; /** * Returns a string with the first letter capitalized @@ -242,22 +242,6 @@ export function wordwrap(string, length, newline, balanced) { return lines.join(newline); } -/*@ -Ox.char Alias for String.fromCharCode -@*/ -export const char = String.fromCharCode; - -/*@ -Ox.splice `[].splice` for strings, returns a new string - > Ox.splice('12xxxxx89', 2, 5, 3, 4, 5, 6, 7) - '123456789' -@*/ -export function splice(string, index, remove) { - const array = string.split(''); - Array.prototype.splice.apply(array, slice(arguments, 1)); - return array.join(''); -} - // Export all functions export default { capitalize, @@ -282,7 +266,5 @@ export default { truncate, uppercase, words, - wordwrap, - char, - splice + wordwrap }; \ No newline at end of file diff --git a/src/ox/core/Video.js b/src/ox/core/Video.js deleted file mode 100644 index e3191567..00000000 --- a/src/ox/core/Video.js +++ /dev/null @@ -1,7 +0,0 @@ -// Video module - video manipulation utilities -// This will be migrated in a future iteration -// For now, we provide basic stubs - -export function parsePath() { - throw new Error('Video.parsePath not yet migrated to ES modules'); -} \ No newline at end of file diff --git a/src/ox/core/stubs.js b/src/ox/core/stubs.js deleted file mode 100644 index 2c8abee1..00000000 --- a/src/ox/core/stubs.js +++ /dev/null @@ -1,57 +0,0 @@ -/** - * Stub implementations for modules not yet converted - * These will be replaced with full implementations - */ - -// Format utilities stub -export const FormatUtils = { - formatNumber: (n) => n.toString(), - formatDuration: (ms) => `${ms}ms`, - formatBytes: (b) => `${b}B` -}; - -// Color utilities stub -export const ColorUtils = { - rgb: (r, g, b) => `rgb(${r}, ${g}, ${b})`, - hex: (color) => color -}; - -// Encoding utilities stub -export const EncodingUtils = { - encodeBase64: (str) => btoa(str), - decodeBase64: (str) => atob(str) -}; - -// RegExp utilities stub -export const RegExpUtils = { - escape: (str) => str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&') -}; - -// HTML utilities stub -export const HTMLUtils = { - encode: (str) => str.replace(/[<>&"']/g, (c) => `&#${c.charCodeAt(0)};`), - decode: (str) => str -}; - -// Async utilities stub -export const AsyncUtils = { - sleep: (ms) => new Promise(resolve => setTimeout(resolve, ms)), - series: async (tasks) => { - const results = []; - for (const task of tasks) { - results.push(await task()); - } - return results; - } -}; - -// Geo utilities stub (enhance existing) -export const GeoUtils = { - getDistance: (a, b) => Math.sqrt(Math.pow(b.lat - a.lat, 2) + Math.pow(b.lng - a.lng, 2)) -}; - -// JavaScript utilities stub -export const JavaScriptUtils = { - minify: (code) => code, - tokenize: (code) => [] -}; \ No newline at end of file diff --git a/src/ox/index.js b/src/ox/index.js index ceb7ef47..34c747f8 100644 --- a/src/ox/index.js +++ b/src/ox/index.js @@ -16,22 +16,18 @@ import * as CollectionUtils from './core/Collection.js'; import * as MathUtils from './core/Math.js'; import * as ObjectUtils from './core/Object.js'; import * as DateUtils from './core/Date.js'; -import * as DOMUtils from './core/DOM.js'; -import * as RequestUtils from './core/Request.js'; -import * as LocaleUtils from './core/Locale.js'; -import * as Constants from './core/Constants.js'; - -// Import newly converted modules import * as FormatUtils from './core/Format.js'; import * as ColorUtils from './core/Color.js'; import * as EncodingUtils from './core/Encoding.js'; import * as RegExpUtils from './core/RegExp.js'; import * as HTMLUtils from './core/HTML.js'; +import * as DOMUtils from './core/DOM.js'; +import * as RequestUtils from './core/Request.js'; import * as AsyncUtils from './core/Async.js'; -import * as HashUtils from './core/Hash.js'; import * as GeoUtils from './core/Geo.js'; import * as JavaScriptUtils from './core/JavaScript.js'; -import * as VideoUtils from './core/Video.js'; +import * as LocaleUtils from './core/Locale.js'; +import * as Constants from './core/Constants.js'; // Create the main Ox object const Ox = function(value) { @@ -54,13 +50,11 @@ Object.assign(Ox, EncodingUtils, RegExpUtils, HTMLUtils, - HashUtils, DOMUtils, RequestUtils, AsyncUtils, GeoUtils, JavaScriptUtils, - VideoUtils, LocaleUtils, Constants ); @@ -91,13 +85,11 @@ export { EncodingUtils, RegExpUtils, HTMLUtils, - HashUtils, DOMUtils, RequestUtils, AsyncUtils, GeoUtils, JavaScriptUtils, - VideoUtils, LocaleUtils, Constants }; diff --git a/test/test-setup.js b/test/test-setup.js deleted file mode 100644 index e71fa6c8..00000000 --- a/test/test-setup.js +++ /dev/null @@ -1,22 +0,0 @@ -/** - * Test setup for running extracted OxJS inline tests - */ - -// Load OxJS ES modules -import Ox from '../src/ox/index.js'; - -// Helper function to evaluate test statements in context -global.evaluateInContext = async function(statement) { - try { - // This will need to be enhanced to handle async tests - // For now, we'll use eval which isn't ideal but matches the original test system - return eval(statement); - } catch (error) { - console.error('Error evaluating:', statement, error); - throw error; - } -}; - -// Make Ox available globally for tests -global.Ox = Ox; -console.log('Test environment setup complete'); diff --git a/vite.config.build.js b/vite.config.build.js deleted file mode 100644 index 5f002005..00000000 --- a/vite.config.build.js +++ /dev/null @@ -1,41 +0,0 @@ -import { defineConfig } from 'vite'; -import { resolve } from 'path'; -import fs from 'fs'; -import path from 'path'; - -export default defineConfig({ - build: { - lib: { - entry: resolve(__dirname, 'src/ox/index.js'), - name: 'Ox', - formats: ['es', 'umd'], - fileName: (format) => { - if (format === 'es') return 'ox.esm.js'; - if (format === 'umd') return 'ox.umd.js'; - return `ox.${format}.js`; - } - }, - rollupOptions: { - output: { - globals: { - // Any external dependencies would go here - }, - // Keep all exports at top level - preserveModules: false, - // Ensure compatibility with older environments - generatedCode: { - constBindings: false - } - } - }, - sourcemap: true, - minify: false, // We'll minify separately for min/Ox.js - outDir: 'dist', - emptyOutDir: false - }, - resolve: { - alias: { - '@': resolve(__dirname, './src'), - } - } -}); \ No newline at end of file diff --git a/vitest.config.js b/vitest.config.js index 22c95bab..8ebfc305 100644 --- a/vitest.config.js +++ b/vitest.config.js @@ -5,7 +5,7 @@ export default defineConfig({ test: { globals: true, environment: 'node', // Use node for now to avoid jsdom issues - setupFiles: './test/test-setup.js' + setupFiles: './test/setup.js' }, resolve: { alias: {