diff --git a/.nojekyll b/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/404.html b/404.html new file mode 100644 index 00000000..2d9386ee --- /dev/null +++ b/404.html @@ -0,0 +1,424 @@ + + + + + + + + + + + + + + + + + + Crispy Waffle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ +

404 - Not found

+ +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/assets/images/favicon.png b/assets/images/favicon.png new file mode 100644 index 00000000..1cf13b9f Binary files /dev/null and b/assets/images/favicon.png differ diff --git a/assets/javascripts/bundle.51d95adb.min.js b/assets/javascripts/bundle.51d95adb.min.js new file mode 100644 index 00000000..b20ec683 --- /dev/null +++ b/assets/javascripts/bundle.51d95adb.min.js @@ -0,0 +1,29 @@ +"use strict";(()=>{var Hi=Object.create;var xr=Object.defineProperty;var Pi=Object.getOwnPropertyDescriptor;var $i=Object.getOwnPropertyNames,kt=Object.getOwnPropertySymbols,Ii=Object.getPrototypeOf,Er=Object.prototype.hasOwnProperty,an=Object.prototype.propertyIsEnumerable;var on=(e,t,r)=>t in e?xr(e,t,{enumerable:!0,configurable:!0,writable:!0,value:r}):e[t]=r,P=(e,t)=>{for(var r in t||(t={}))Er.call(t,r)&&on(e,r,t[r]);if(kt)for(var r of kt(t))an.call(t,r)&&on(e,r,t[r]);return e};var sn=(e,t)=>{var r={};for(var n in e)Er.call(e,n)&&t.indexOf(n)<0&&(r[n]=e[n]);if(e!=null&&kt)for(var n of kt(e))t.indexOf(n)<0&&an.call(e,n)&&(r[n]=e[n]);return r};var Ht=(e,t)=>()=>(t||e((t={exports:{}}).exports,t),t.exports);var Fi=(e,t,r,n)=>{if(t&&typeof t=="object"||typeof t=="function")for(let o of $i(t))!Er.call(e,o)&&o!==r&&xr(e,o,{get:()=>t[o],enumerable:!(n=Pi(t,o))||n.enumerable});return e};var yt=(e,t,r)=>(r=e!=null?Hi(Ii(e)):{},Fi(t||!e||!e.__esModule?xr(r,"default",{value:e,enumerable:!0}):r,e));var fn=Ht((wr,cn)=>{(function(e,t){typeof wr=="object"&&typeof cn!="undefined"?t():typeof define=="function"&&define.amd?define(t):t()})(wr,function(){"use strict";function e(r){var n=!0,o=!1,i=null,a={text:!0,search:!0,url:!0,tel:!0,email:!0,password:!0,number:!0,date:!0,month:!0,week:!0,time:!0,datetime:!0,"datetime-local":!0};function s(T){return!!(T&&T!==document&&T.nodeName!=="HTML"&&T.nodeName!=="BODY"&&"classList"in T&&"contains"in T.classList)}function f(T){var Ke=T.type,We=T.tagName;return!!(We==="INPUT"&&a[Ke]&&!T.readOnly||We==="TEXTAREA"&&!T.readOnly||T.isContentEditable)}function c(T){T.classList.contains("focus-visible")||(T.classList.add("focus-visible"),T.setAttribute("data-focus-visible-added",""))}function u(T){T.hasAttribute("data-focus-visible-added")&&(T.classList.remove("focus-visible"),T.removeAttribute("data-focus-visible-added"))}function p(T){T.metaKey||T.altKey||T.ctrlKey||(s(r.activeElement)&&c(r.activeElement),n=!0)}function m(T){n=!1}function d(T){s(T.target)&&(n||f(T.target))&&c(T.target)}function h(T){s(T.target)&&(T.target.classList.contains("focus-visible")||T.target.hasAttribute("data-focus-visible-added"))&&(o=!0,window.clearTimeout(i),i=window.setTimeout(function(){o=!1},100),u(T.target))}function v(T){document.visibilityState==="hidden"&&(o&&(n=!0),B())}function B(){document.addEventListener("mousemove",z),document.addEventListener("mousedown",z),document.addEventListener("mouseup",z),document.addEventListener("pointermove",z),document.addEventListener("pointerdown",z),document.addEventListener("pointerup",z),document.addEventListener("touchmove",z),document.addEventListener("touchstart",z),document.addEventListener("touchend",z)}function re(){document.removeEventListener("mousemove",z),document.removeEventListener("mousedown",z),document.removeEventListener("mouseup",z),document.removeEventListener("pointermove",z),document.removeEventListener("pointerdown",z),document.removeEventListener("pointerup",z),document.removeEventListener("touchmove",z),document.removeEventListener("touchstart",z),document.removeEventListener("touchend",z)}function z(T){T.target.nodeName&&T.target.nodeName.toLowerCase()==="html"||(n=!1,re())}document.addEventListener("keydown",p,!0),document.addEventListener("mousedown",m,!0),document.addEventListener("pointerdown",m,!0),document.addEventListener("touchstart",m,!0),document.addEventListener("visibilitychange",v,!0),B(),r.addEventListener("focus",d,!0),r.addEventListener("blur",h,!0),r.nodeType===Node.DOCUMENT_FRAGMENT_NODE&&r.host?r.host.setAttribute("data-js-focus-visible",""):r.nodeType===Node.DOCUMENT_NODE&&(document.documentElement.classList.add("js-focus-visible"),document.documentElement.setAttribute("data-js-focus-visible",""))}if(typeof window!="undefined"&&typeof document!="undefined"){window.applyFocusVisiblePolyfill=e;var t;try{t=new CustomEvent("focus-visible-polyfill-ready")}catch(r){t=document.createEvent("CustomEvent"),t.initCustomEvent("focus-visible-polyfill-ready",!1,!1,{})}window.dispatchEvent(t)}typeof document!="undefined"&&e(document)})});var un=Ht(Sr=>{(function(e){var t=function(){try{return!!Symbol.iterator}catch(c){return!1}},r=t(),n=function(c){var u={next:function(){var p=c.shift();return{done:p===void 0,value:p}}};return r&&(u[Symbol.iterator]=function(){return u}),u},o=function(c){return encodeURIComponent(c).replace(/%20/g,"+")},i=function(c){return decodeURIComponent(String(c).replace(/\+/g," "))},a=function(){var c=function(p){Object.defineProperty(this,"_entries",{writable:!0,value:{}});var m=typeof p;if(m!=="undefined")if(m==="string")p!==""&&this._fromString(p);else if(p instanceof c){var d=this;p.forEach(function(re,z){d.append(z,re)})}else if(p!==null&&m==="object")if(Object.prototype.toString.call(p)==="[object Array]")for(var h=0;hd[0]?1:0}),c._entries&&(c._entries={});for(var p=0;p1?i(d[1]):"")}})})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr);(function(e){var t=function(){try{var o=new e.URL("b","http://a");return o.pathname="c d",o.href==="http://a/c%20d"&&o.searchParams}catch(i){return!1}},r=function(){var o=e.URL,i=function(f,c){typeof f!="string"&&(f=String(f)),c&&typeof c!="string"&&(c=String(c));var u=document,p;if(c&&(e.location===void 0||c!==e.location.href)){c=c.toLowerCase(),u=document.implementation.createHTMLDocument(""),p=u.createElement("base"),p.href=c,u.head.appendChild(p);try{if(p.href.indexOf(c)!==0)throw new Error(p.href)}catch(T){throw new Error("URL unable to set base "+c+" due to "+T)}}var m=u.createElement("a");m.href=f,p&&(u.body.appendChild(m),m.href=m.href);var d=u.createElement("input");if(d.type="url",d.value=f,m.protocol===":"||!/:/.test(m.href)||!d.checkValidity()&&!c)throw new TypeError("Invalid URL");Object.defineProperty(this,"_anchorElement",{value:m});var h=new e.URLSearchParams(this.search),v=!0,B=!0,re=this;["append","delete","set"].forEach(function(T){var Ke=h[T];h[T]=function(){Ke.apply(h,arguments),v&&(B=!1,re.search=h.toString(),B=!0)}}),Object.defineProperty(this,"searchParams",{value:h,enumerable:!0});var z=void 0;Object.defineProperty(this,"_updateSearchParams",{enumerable:!1,configurable:!1,writable:!1,value:function(){this.search!==z&&(z=this.search,B&&(v=!1,this.searchParams._fromString(this.search),v=!0))}})},a=i.prototype,s=function(f){Object.defineProperty(a,f,{get:function(){return this._anchorElement[f]},set:function(c){this._anchorElement[f]=c},enumerable:!0})};["hash","host","hostname","port","protocol"].forEach(function(f){s(f)}),Object.defineProperty(a,"search",{get:function(){return this._anchorElement.search},set:function(f){this._anchorElement.search=f,this._updateSearchParams()},enumerable:!0}),Object.defineProperties(a,{toString:{get:function(){var f=this;return function(){return f.href}}},href:{get:function(){return this._anchorElement.href.replace(/\?$/,"")},set:function(f){this._anchorElement.href=f,this._updateSearchParams()},enumerable:!0},pathname:{get:function(){return this._anchorElement.pathname.replace(/(^\/?)/,"/")},set:function(f){this._anchorElement.pathname=f},enumerable:!0},origin:{get:function(){var f={"http:":80,"https:":443,"ftp:":21}[this._anchorElement.protocol],c=this._anchorElement.port!=f&&this._anchorElement.port!=="";return this._anchorElement.protocol+"//"+this._anchorElement.hostname+(c?":"+this._anchorElement.port:"")},enumerable:!0},password:{get:function(){return""},set:function(f){},enumerable:!0},username:{get:function(){return""},set:function(f){},enumerable:!0}}),i.createObjectURL=function(f){return o.createObjectURL.apply(o,arguments)},i.revokeObjectURL=function(f){return o.revokeObjectURL.apply(o,arguments)},e.URL=i};if(t()||r(),e.location!==void 0&&!("origin"in e.location)){var n=function(){return e.location.protocol+"//"+e.location.hostname+(e.location.port?":"+e.location.port:"")};try{Object.defineProperty(e.location,"origin",{get:n,enumerable:!0})}catch(o){setInterval(function(){e.location.origin=n()},100)}}})(typeof global!="undefined"?global:typeof window!="undefined"?window:typeof self!="undefined"?self:Sr)});var Qr=Ht((Lt,Kr)=>{/*! + * clipboard.js v2.0.11 + * https://clipboardjs.com/ + * + * Licensed MIT © Zeno Rocha + */(function(t,r){typeof Lt=="object"&&typeof Kr=="object"?Kr.exports=r():typeof define=="function"&&define.amd?define([],r):typeof Lt=="object"?Lt.ClipboardJS=r():t.ClipboardJS=r()})(Lt,function(){return function(){var e={686:function(n,o,i){"use strict";i.d(o,{default:function(){return ki}});var a=i(279),s=i.n(a),f=i(370),c=i.n(f),u=i(817),p=i.n(u);function m(j){try{return document.execCommand(j)}catch(O){return!1}}var d=function(O){var w=p()(O);return m("cut"),w},h=d;function v(j){var O=document.documentElement.getAttribute("dir")==="rtl",w=document.createElement("textarea");w.style.fontSize="12pt",w.style.border="0",w.style.padding="0",w.style.margin="0",w.style.position="absolute",w.style[O?"right":"left"]="-9999px";var k=window.pageYOffset||document.documentElement.scrollTop;return w.style.top="".concat(k,"px"),w.setAttribute("readonly",""),w.value=j,w}var B=function(O,w){var k=v(O);w.container.appendChild(k);var F=p()(k);return m("copy"),k.remove(),F},re=function(O){var w=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body},k="";return typeof O=="string"?k=B(O,w):O instanceof HTMLInputElement&&!["text","search","url","tel","password"].includes(O==null?void 0:O.type)?k=B(O.value,w):(k=p()(O),m("copy")),k},z=re;function T(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?T=function(w){return typeof w}:T=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},T(j)}var Ke=function(){var O=arguments.length>0&&arguments[0]!==void 0?arguments[0]:{},w=O.action,k=w===void 0?"copy":w,F=O.container,q=O.target,Le=O.text;if(k!=="copy"&&k!=="cut")throw new Error('Invalid "action" value, use either "copy" or "cut"');if(q!==void 0)if(q&&T(q)==="object"&&q.nodeType===1){if(k==="copy"&&q.hasAttribute("disabled"))throw new Error('Invalid "target" attribute. Please use "readonly" instead of "disabled" attribute');if(k==="cut"&&(q.hasAttribute("readonly")||q.hasAttribute("disabled")))throw new Error(`Invalid "target" attribute. You can't cut text from elements with "readonly" or "disabled" attributes`)}else throw new Error('Invalid "target" value, use a valid Element');if(Le)return z(Le,{container:F});if(q)return k==="cut"?h(q):z(q,{container:F})},We=Ke;function Ie(j){return typeof Symbol=="function"&&typeof Symbol.iterator=="symbol"?Ie=function(w){return typeof w}:Ie=function(w){return w&&typeof Symbol=="function"&&w.constructor===Symbol&&w!==Symbol.prototype?"symbol":typeof w},Ie(j)}function Ti(j,O){if(!(j instanceof O))throw new TypeError("Cannot call a class as a function")}function nn(j,O){for(var w=0;w0&&arguments[0]!==void 0?arguments[0]:{};this.action=typeof F.action=="function"?F.action:this.defaultAction,this.target=typeof F.target=="function"?F.target:this.defaultTarget,this.text=typeof F.text=="function"?F.text:this.defaultText,this.container=Ie(F.container)==="object"?F.container:document.body}},{key:"listenClick",value:function(F){var q=this;this.listener=c()(F,"click",function(Le){return q.onClick(Le)})}},{key:"onClick",value:function(F){var q=F.delegateTarget||F.currentTarget,Le=this.action(q)||"copy",Rt=We({action:Le,container:this.container,target:this.target(q),text:this.text(q)});this.emit(Rt?"success":"error",{action:Le,text:Rt,trigger:q,clearSelection:function(){q&&q.focus(),window.getSelection().removeAllRanges()}})}},{key:"defaultAction",value:function(F){return yr("action",F)}},{key:"defaultTarget",value:function(F){var q=yr("target",F);if(q)return document.querySelector(q)}},{key:"defaultText",value:function(F){return yr("text",F)}},{key:"destroy",value:function(){this.listener.destroy()}}],[{key:"copy",value:function(F){var q=arguments.length>1&&arguments[1]!==void 0?arguments[1]:{container:document.body};return z(F,q)}},{key:"cut",value:function(F){return h(F)}},{key:"isSupported",value:function(){var F=arguments.length>0&&arguments[0]!==void 0?arguments[0]:["copy","cut"],q=typeof F=="string"?[F]:F,Le=!!document.queryCommandSupported;return q.forEach(function(Rt){Le=Le&&!!document.queryCommandSupported(Rt)}),Le}}]),w}(s()),ki=Ri},828:function(n){var o=9;if(typeof Element!="undefined"&&!Element.prototype.matches){var i=Element.prototype;i.matches=i.matchesSelector||i.mozMatchesSelector||i.msMatchesSelector||i.oMatchesSelector||i.webkitMatchesSelector}function a(s,f){for(;s&&s.nodeType!==o;){if(typeof s.matches=="function"&&s.matches(f))return s;s=s.parentNode}}n.exports=a},438:function(n,o,i){var a=i(828);function s(u,p,m,d,h){var v=c.apply(this,arguments);return u.addEventListener(m,v,h),{destroy:function(){u.removeEventListener(m,v,h)}}}function f(u,p,m,d,h){return typeof u.addEventListener=="function"?s.apply(null,arguments):typeof m=="function"?s.bind(null,document).apply(null,arguments):(typeof u=="string"&&(u=document.querySelectorAll(u)),Array.prototype.map.call(u,function(v){return s(v,p,m,d,h)}))}function c(u,p,m,d){return function(h){h.delegateTarget=a(h.target,p),h.delegateTarget&&d.call(u,h)}}n.exports=f},879:function(n,o){o.node=function(i){return i!==void 0&&i instanceof HTMLElement&&i.nodeType===1},o.nodeList=function(i){var a=Object.prototype.toString.call(i);return i!==void 0&&(a==="[object NodeList]"||a==="[object HTMLCollection]")&&"length"in i&&(i.length===0||o.node(i[0]))},o.string=function(i){return typeof i=="string"||i instanceof String},o.fn=function(i){var a=Object.prototype.toString.call(i);return a==="[object Function]"}},370:function(n,o,i){var a=i(879),s=i(438);function f(m,d,h){if(!m&&!d&&!h)throw new Error("Missing required arguments");if(!a.string(d))throw new TypeError("Second argument must be a String");if(!a.fn(h))throw new TypeError("Third argument must be a Function");if(a.node(m))return c(m,d,h);if(a.nodeList(m))return u(m,d,h);if(a.string(m))return p(m,d,h);throw new TypeError("First argument must be a String, HTMLElement, HTMLCollection, or NodeList")}function c(m,d,h){return m.addEventListener(d,h),{destroy:function(){m.removeEventListener(d,h)}}}function u(m,d,h){return Array.prototype.forEach.call(m,function(v){v.addEventListener(d,h)}),{destroy:function(){Array.prototype.forEach.call(m,function(v){v.removeEventListener(d,h)})}}}function p(m,d,h){return s(document.body,m,d,h)}n.exports=f},817:function(n){function o(i){var a;if(i.nodeName==="SELECT")i.focus(),a=i.value;else if(i.nodeName==="INPUT"||i.nodeName==="TEXTAREA"){var s=i.hasAttribute("readonly");s||i.setAttribute("readonly",""),i.select(),i.setSelectionRange(0,i.value.length),s||i.removeAttribute("readonly"),a=i.value}else{i.hasAttribute("contenteditable")&&i.focus();var f=window.getSelection(),c=document.createRange();c.selectNodeContents(i),f.removeAllRanges(),f.addRange(c),a=f.toString()}return a}n.exports=o},279:function(n){function o(){}o.prototype={on:function(i,a,s){var f=this.e||(this.e={});return(f[i]||(f[i]=[])).push({fn:a,ctx:s}),this},once:function(i,a,s){var f=this;function c(){f.off(i,c),a.apply(s,arguments)}return c._=a,this.on(i,c,s)},emit:function(i){var a=[].slice.call(arguments,1),s=((this.e||(this.e={}))[i]||[]).slice(),f=0,c=s.length;for(f;f{"use strict";/*! + * escape-html + * Copyright(c) 2012-2013 TJ Holowaychuk + * Copyright(c) 2015 Andreas Lubbe + * Copyright(c) 2015 Tiancheng "Timothy" Gu + * MIT Licensed + */var is=/["'&<>]/;Jo.exports=as;function as(e){var t=""+e,r=is.exec(t);if(!r)return t;var n,o="",i=0,a=0;for(i=r.index;i0&&i[i.length-1])&&(c[0]===6||c[0]===2)){r=0;continue}if(c[0]===3&&(!i||c[1]>i[0]&&c[1]=e.length&&(e=void 0),{value:e&&e[n++],done:!e}}};throw new TypeError(t?"Object is not iterable.":"Symbol.iterator is not defined.")}function W(e,t){var r=typeof Symbol=="function"&&e[Symbol.iterator];if(!r)return e;var n=r.call(e),o,i=[],a;try{for(;(t===void 0||t-- >0)&&!(o=n.next()).done;)i.push(o.value)}catch(s){a={error:s}}finally{try{o&&!o.done&&(r=n.return)&&r.call(n)}finally{if(a)throw a.error}}return i}function D(e,t,r){if(r||arguments.length===2)for(var n=0,o=t.length,i;n1||s(m,d)})})}function s(m,d){try{f(n[m](d))}catch(h){p(i[0][3],h)}}function f(m){m.value instanceof Xe?Promise.resolve(m.value.v).then(c,u):p(i[0][2],m)}function c(m){s("next",m)}function u(m){s("throw",m)}function p(m,d){m(d),i.shift(),i.length&&s(i[0][0],i[0][1])}}function mn(e){if(!Symbol.asyncIterator)throw new TypeError("Symbol.asyncIterator is not defined.");var t=e[Symbol.asyncIterator],r;return t?t.call(e):(e=typeof xe=="function"?xe(e):e[Symbol.iterator](),r={},n("next"),n("throw"),n("return"),r[Symbol.asyncIterator]=function(){return this},r);function n(i){r[i]=e[i]&&function(a){return new Promise(function(s,f){a=e[i](a),o(s,f,a.done,a.value)})}}function o(i,a,s,f){Promise.resolve(f).then(function(c){i({value:c,done:s})},a)}}function A(e){return typeof e=="function"}function at(e){var t=function(n){Error.call(n),n.stack=new Error().stack},r=e(t);return r.prototype=Object.create(Error.prototype),r.prototype.constructor=r,r}var $t=at(function(e){return function(r){e(this),this.message=r?r.length+` errors occurred during unsubscription: +`+r.map(function(n,o){return o+1+") "+n.toString()}).join(` + `):"",this.name="UnsubscriptionError",this.errors=r}});function De(e,t){if(e){var r=e.indexOf(t);0<=r&&e.splice(r,1)}}var Fe=function(){function e(t){this.initialTeardown=t,this.closed=!1,this._parentage=null,this._finalizers=null}return e.prototype.unsubscribe=function(){var t,r,n,o,i;if(!this.closed){this.closed=!0;var a=this._parentage;if(a)if(this._parentage=null,Array.isArray(a))try{for(var s=xe(a),f=s.next();!f.done;f=s.next()){var c=f.value;c.remove(this)}}catch(v){t={error:v}}finally{try{f&&!f.done&&(r=s.return)&&r.call(s)}finally{if(t)throw t.error}}else a.remove(this);var u=this.initialTeardown;if(A(u))try{u()}catch(v){i=v instanceof $t?v.errors:[v]}var p=this._finalizers;if(p){this._finalizers=null;try{for(var m=xe(p),d=m.next();!d.done;d=m.next()){var h=d.value;try{dn(h)}catch(v){i=i!=null?i:[],v instanceof $t?i=D(D([],W(i)),W(v.errors)):i.push(v)}}}catch(v){n={error:v}}finally{try{d&&!d.done&&(o=m.return)&&o.call(m)}finally{if(n)throw n.error}}}if(i)throw new $t(i)}},e.prototype.add=function(t){var r;if(t&&t!==this)if(this.closed)dn(t);else{if(t instanceof e){if(t.closed||t._hasParent(this))return;t._addParent(this)}(this._finalizers=(r=this._finalizers)!==null&&r!==void 0?r:[]).push(t)}},e.prototype._hasParent=function(t){var r=this._parentage;return r===t||Array.isArray(r)&&r.includes(t)},e.prototype._addParent=function(t){var r=this._parentage;this._parentage=Array.isArray(r)?(r.push(t),r):r?[r,t]:t},e.prototype._removeParent=function(t){var r=this._parentage;r===t?this._parentage=null:Array.isArray(r)&&De(r,t)},e.prototype.remove=function(t){var r=this._finalizers;r&&De(r,t),t instanceof e&&t._removeParent(this)},e.EMPTY=function(){var t=new e;return t.closed=!0,t}(),e}();var Or=Fe.EMPTY;function It(e){return e instanceof Fe||e&&"closed"in e&&A(e.remove)&&A(e.add)&&A(e.unsubscribe)}function dn(e){A(e)?e():e.unsubscribe()}var Ae={onUnhandledError:null,onStoppedNotification:null,Promise:void 0,useDeprecatedSynchronousErrorHandling:!1,useDeprecatedNextContext:!1};var st={setTimeout:function(e,t){for(var r=[],n=2;n0},enumerable:!1,configurable:!0}),t.prototype._trySubscribe=function(r){return this._throwIfClosed(),e.prototype._trySubscribe.call(this,r)},t.prototype._subscribe=function(r){return this._throwIfClosed(),this._checkFinalizedStatuses(r),this._innerSubscribe(r)},t.prototype._innerSubscribe=function(r){var n=this,o=this,i=o.hasError,a=o.isStopped,s=o.observers;return i||a?Or:(this.currentObservers=null,s.push(r),new Fe(function(){n.currentObservers=null,De(s,r)}))},t.prototype._checkFinalizedStatuses=function(r){var n=this,o=n.hasError,i=n.thrownError,a=n.isStopped;o?r.error(i):a&&r.complete()},t.prototype.asObservable=function(){var r=new U;return r.source=this,r},t.create=function(r,n){return new wn(r,n)},t}(U);var wn=function(e){ne(t,e);function t(r,n){var o=e.call(this)||this;return o.destination=r,o.source=n,o}return t.prototype.next=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.next)===null||o===void 0||o.call(n,r)},t.prototype.error=function(r){var n,o;(o=(n=this.destination)===null||n===void 0?void 0:n.error)===null||o===void 0||o.call(n,r)},t.prototype.complete=function(){var r,n;(n=(r=this.destination)===null||r===void 0?void 0:r.complete)===null||n===void 0||n.call(r)},t.prototype._subscribe=function(r){var n,o;return(o=(n=this.source)===null||n===void 0?void 0:n.subscribe(r))!==null&&o!==void 0?o:Or},t}(E);var Et={now:function(){return(Et.delegate||Date).now()},delegate:void 0};var wt=function(e){ne(t,e);function t(r,n,o){r===void 0&&(r=1/0),n===void 0&&(n=1/0),o===void 0&&(o=Et);var i=e.call(this)||this;return i._bufferSize=r,i._windowTime=n,i._timestampProvider=o,i._buffer=[],i._infiniteTimeWindow=!0,i._infiniteTimeWindow=n===1/0,i._bufferSize=Math.max(1,r),i._windowTime=Math.max(1,n),i}return t.prototype.next=function(r){var n=this,o=n.isStopped,i=n._buffer,a=n._infiniteTimeWindow,s=n._timestampProvider,f=n._windowTime;o||(i.push(r),!a&&i.push(s.now()+f)),this._trimBuffer(),e.prototype.next.call(this,r)},t.prototype._subscribe=function(r){this._throwIfClosed(),this._trimBuffer();for(var n=this._innerSubscribe(r),o=this,i=o._infiniteTimeWindow,a=o._buffer,s=a.slice(),f=0;f0?e.prototype.requestAsyncId.call(this,r,n,o):(r.actions.push(this),r._scheduled||(r._scheduled=ut.requestAnimationFrame(function(){return r.flush(void 0)})))},t.prototype.recycleAsyncId=function(r,n,o){var i;if(o===void 0&&(o=0),o!=null?o>0:this.delay>0)return e.prototype.recycleAsyncId.call(this,r,n,o);var a=r.actions;n!=null&&((i=a[a.length-1])===null||i===void 0?void 0:i.id)!==n&&(ut.cancelAnimationFrame(n),r._scheduled=void 0)},t}(Ut);var On=function(e){ne(t,e);function t(){return e!==null&&e.apply(this,arguments)||this}return t.prototype.flush=function(r){this._active=!0;var n=this._scheduled;this._scheduled=void 0;var o=this.actions,i;r=r||o.shift();do if(i=r.execute(r.state,r.delay))break;while((r=o[0])&&r.id===n&&o.shift());if(this._active=!1,i){for(;(r=o[0])&&r.id===n&&o.shift();)r.unsubscribe();throw i}},t}(Wt);var we=new On(Tn);var R=new U(function(e){return e.complete()});function Dt(e){return e&&A(e.schedule)}function kr(e){return e[e.length-1]}function Qe(e){return A(kr(e))?e.pop():void 0}function Se(e){return Dt(kr(e))?e.pop():void 0}function Vt(e,t){return typeof kr(e)=="number"?e.pop():t}var pt=function(e){return e&&typeof e.length=="number"&&typeof e!="function"};function zt(e){return A(e==null?void 0:e.then)}function Nt(e){return A(e[ft])}function qt(e){return Symbol.asyncIterator&&A(e==null?void 0:e[Symbol.asyncIterator])}function Kt(e){return new TypeError("You provided "+(e!==null&&typeof e=="object"?"an invalid object":"'"+e+"'")+" where a stream was expected. You can provide an Observable, Promise, ReadableStream, Array, AsyncIterable, or Iterable.")}function Ki(){return typeof Symbol!="function"||!Symbol.iterator?"@@iterator":Symbol.iterator}var Qt=Ki();function Yt(e){return A(e==null?void 0:e[Qt])}function Gt(e){return ln(this,arguments,function(){var r,n,o,i;return Pt(this,function(a){switch(a.label){case 0:r=e.getReader(),a.label=1;case 1:a.trys.push([1,,9,10]),a.label=2;case 2:return[4,Xe(r.read())];case 3:return n=a.sent(),o=n.value,i=n.done,i?[4,Xe(void 0)]:[3,5];case 4:return[2,a.sent()];case 5:return[4,Xe(o)];case 6:return[4,a.sent()];case 7:return a.sent(),[3,2];case 8:return[3,10];case 9:return r.releaseLock(),[7];case 10:return[2]}})})}function Bt(e){return A(e==null?void 0:e.getReader)}function $(e){if(e instanceof U)return e;if(e!=null){if(Nt(e))return Qi(e);if(pt(e))return Yi(e);if(zt(e))return Gi(e);if(qt(e))return _n(e);if(Yt(e))return Bi(e);if(Bt(e))return Ji(e)}throw Kt(e)}function Qi(e){return new U(function(t){var r=e[ft]();if(A(r.subscribe))return r.subscribe(t);throw new TypeError("Provided object does not correctly implement Symbol.observable")})}function Yi(e){return new U(function(t){for(var r=0;r=2;return function(n){return n.pipe(e?_(function(o,i){return e(o,i,n)}):me,Oe(1),r?He(t):zn(function(){return new Xt}))}}function Nn(){for(var e=[],t=0;t=2,!0))}function fe(e){e===void 0&&(e={});var t=e.connector,r=t===void 0?function(){return new E}:t,n=e.resetOnError,o=n===void 0?!0:n,i=e.resetOnComplete,a=i===void 0?!0:i,s=e.resetOnRefCountZero,f=s===void 0?!0:s;return function(c){var u,p,m,d=0,h=!1,v=!1,B=function(){p==null||p.unsubscribe(),p=void 0},re=function(){B(),u=m=void 0,h=v=!1},z=function(){var T=u;re(),T==null||T.unsubscribe()};return g(function(T,Ke){d++,!v&&!h&&B();var We=m=m!=null?m:r();Ke.add(function(){d--,d===0&&!v&&!h&&(p=jr(z,f))}),We.subscribe(Ke),!u&&d>0&&(u=new et({next:function(Ie){return We.next(Ie)},error:function(Ie){v=!0,B(),p=jr(re,o,Ie),We.error(Ie)},complete:function(){h=!0,B(),p=jr(re,a),We.complete()}}),$(T).subscribe(u))})(c)}}function jr(e,t){for(var r=[],n=2;ne.next(document)),e}function K(e,t=document){return Array.from(t.querySelectorAll(e))}function V(e,t=document){let r=se(e,t);if(typeof r=="undefined")throw new ReferenceError(`Missing element: expected "${e}" to be present`);return r}function se(e,t=document){return t.querySelector(e)||void 0}function _e(){return document.activeElement instanceof HTMLElement&&document.activeElement||void 0}function tr(e){return L(b(document.body,"focusin"),b(document.body,"focusout")).pipe(ke(1),l(()=>{let t=_e();return typeof t!="undefined"?e.contains(t):!1}),N(e===_e()),Y())}function Be(e){return{x:e.offsetLeft,y:e.offsetTop}}function Yn(e){return L(b(window,"load"),b(window,"resize")).pipe(Ce(0,we),l(()=>Be(e)),N(Be(e)))}function rr(e){return{x:e.scrollLeft,y:e.scrollTop}}function dt(e){return L(b(e,"scroll"),b(window,"resize")).pipe(Ce(0,we),l(()=>rr(e)),N(rr(e)))}var Bn=function(){if(typeof Map!="undefined")return Map;function e(t,r){var n=-1;return t.some(function(o,i){return o[0]===r?(n=i,!0):!1}),n}return function(){function t(){this.__entries__=[]}return Object.defineProperty(t.prototype,"size",{get:function(){return this.__entries__.length},enumerable:!0,configurable:!0}),t.prototype.get=function(r){var n=e(this.__entries__,r),o=this.__entries__[n];return o&&o[1]},t.prototype.set=function(r,n){var o=e(this.__entries__,r);~o?this.__entries__[o][1]=n:this.__entries__.push([r,n])},t.prototype.delete=function(r){var n=this.__entries__,o=e(n,r);~o&&n.splice(o,1)},t.prototype.has=function(r){return!!~e(this.__entries__,r)},t.prototype.clear=function(){this.__entries__.splice(0)},t.prototype.forEach=function(r,n){n===void 0&&(n=null);for(var o=0,i=this.__entries__;o0},e.prototype.connect_=function(){!zr||this.connected_||(document.addEventListener("transitionend",this.onTransitionEnd_),window.addEventListener("resize",this.refresh),xa?(this.mutationsObserver_=new MutationObserver(this.refresh),this.mutationsObserver_.observe(document,{attributes:!0,childList:!0,characterData:!0,subtree:!0})):(document.addEventListener("DOMSubtreeModified",this.refresh),this.mutationEventsAdded_=!0),this.connected_=!0)},e.prototype.disconnect_=function(){!zr||!this.connected_||(document.removeEventListener("transitionend",this.onTransitionEnd_),window.removeEventListener("resize",this.refresh),this.mutationsObserver_&&this.mutationsObserver_.disconnect(),this.mutationEventsAdded_&&document.removeEventListener("DOMSubtreeModified",this.refresh),this.mutationsObserver_=null,this.mutationEventsAdded_=!1,this.connected_=!1)},e.prototype.onTransitionEnd_=function(t){var r=t.propertyName,n=r===void 0?"":r,o=ya.some(function(i){return!!~n.indexOf(i)});o&&this.refresh()},e.getInstance=function(){return this.instance_||(this.instance_=new e),this.instance_},e.instance_=null,e}(),Jn=function(e,t){for(var r=0,n=Object.keys(t);r0},e}(),Zn=typeof WeakMap!="undefined"?new WeakMap:new Bn,eo=function(){function e(t){if(!(this instanceof e))throw new TypeError("Cannot call a class as a function.");if(!arguments.length)throw new TypeError("1 argument required, but only 0 present.");var r=Ea.getInstance(),n=new Ra(t,r,this);Zn.set(this,n)}return e}();["observe","unobserve","disconnect"].forEach(function(e){eo.prototype[e]=function(){var t;return(t=Zn.get(this))[e].apply(t,arguments)}});var ka=function(){return typeof nr.ResizeObserver!="undefined"?nr.ResizeObserver:eo}(),to=ka;var ro=new E,Ha=I(()=>H(new to(e=>{for(let t of e)ro.next(t)}))).pipe(x(e=>L(Te,H(e)).pipe(C(()=>e.disconnect()))),J(1));function de(e){return{width:e.offsetWidth,height:e.offsetHeight}}function ge(e){return Ha.pipe(S(t=>t.observe(e)),x(t=>ro.pipe(_(({target:r})=>r===e),C(()=>t.unobserve(e)),l(()=>de(e)))),N(de(e)))}function bt(e){return{width:e.scrollWidth,height:e.scrollHeight}}function ar(e){let t=e.parentElement;for(;t&&(e.scrollWidth<=t.scrollWidth&&e.scrollHeight<=t.scrollHeight);)t=(e=t).parentElement;return t?e:void 0}var no=new E,Pa=I(()=>H(new IntersectionObserver(e=>{for(let t of e)no.next(t)},{threshold:0}))).pipe(x(e=>L(Te,H(e)).pipe(C(()=>e.disconnect()))),J(1));function sr(e){return Pa.pipe(S(t=>t.observe(e)),x(t=>no.pipe(_(({target:r})=>r===e),C(()=>t.unobserve(e)),l(({isIntersecting:r})=>r))))}function oo(e,t=16){return dt(e).pipe(l(({y:r})=>{let n=de(e),o=bt(e);return r>=o.height-n.height-t}),Y())}var cr={drawer:V("[data-md-toggle=drawer]"),search:V("[data-md-toggle=search]")};function io(e){return cr[e].checked}function qe(e,t){cr[e].checked!==t&&cr[e].click()}function je(e){let t=cr[e];return b(t,"change").pipe(l(()=>t.checked),N(t.checked))}function $a(e,t){switch(e.constructor){case HTMLInputElement:return e.type==="radio"?/^Arrow/.test(t):!0;case HTMLSelectElement:case HTMLTextAreaElement:return!0;default:return e.isContentEditable}}function Ia(){return L(b(window,"compositionstart").pipe(l(()=>!0)),b(window,"compositionend").pipe(l(()=>!1))).pipe(N(!1))}function ao(){let e=b(window,"keydown").pipe(_(t=>!(t.metaKey||t.ctrlKey)),l(t=>({mode:io("search")?"search":"global",type:t.key,claim(){t.preventDefault(),t.stopPropagation()}})),_(({mode:t,type:r})=>{if(t==="global"){let n=_e();if(typeof n!="undefined")return!$a(n,r)}return!0}),fe());return Ia().pipe(x(t=>t?R:e))}function Me(){return new URL(location.href)}function ot(e){location.href=e.href}function so(){return new E}function co(e,t){if(typeof t=="string"||typeof t=="number")e.innerHTML+=t.toString();else if(t instanceof Node)e.appendChild(t);else if(Array.isArray(t))for(let r of t)co(e,r)}function M(e,t,...r){let n=document.createElement(e);if(t)for(let o of Object.keys(t))typeof t[o]!="undefined"&&(typeof t[o]!="boolean"?n.setAttribute(o,t[o]):n.setAttribute(o,""));for(let o of r)co(n,o);return n}function fr(e){if(e>999){let t=+((e-950)%1e3>99);return`${((e+1e-6)/1e3).toFixed(t)}k`}else return e.toString()}function fo(){return location.hash.substring(1)}function uo(e){let t=M("a",{href:e});t.addEventListener("click",r=>r.stopPropagation()),t.click()}function Fa(){return b(window,"hashchange").pipe(l(fo),N(fo()),_(e=>e.length>0),J(1))}function po(){return Fa().pipe(l(e=>se(`[id="${e}"]`)),_(e=>typeof e!="undefined"))}function Nr(e){let t=matchMedia(e);return Zt(r=>t.addListener(()=>r(t.matches))).pipe(N(t.matches))}function lo(){let e=matchMedia("print");return L(b(window,"beforeprint").pipe(l(()=>!0)),b(window,"afterprint").pipe(l(()=>!1))).pipe(N(e.matches))}function qr(e,t){return e.pipe(x(r=>r?t():R))}function ur(e,t={credentials:"same-origin"}){return ve(fetch(`${e}`,t)).pipe(ce(()=>R),x(r=>r.status!==200?Tt(()=>new Error(r.statusText)):H(r)))}function Ue(e,t){return ur(e,t).pipe(x(r=>r.json()),J(1))}function mo(e,t){let r=new DOMParser;return ur(e,t).pipe(x(n=>n.text()),l(n=>r.parseFromString(n,"text/xml")),J(1))}function pr(e){let t=M("script",{src:e});return I(()=>(document.head.appendChild(t),L(b(t,"load"),b(t,"error").pipe(x(()=>Tt(()=>new ReferenceError(`Invalid script: ${e}`))))).pipe(l(()=>{}),C(()=>document.head.removeChild(t)),Oe(1))))}function ho(){return{x:Math.max(0,scrollX),y:Math.max(0,scrollY)}}function bo(){return L(b(window,"scroll",{passive:!0}),b(window,"resize",{passive:!0})).pipe(l(ho),N(ho()))}function vo(){return{width:innerWidth,height:innerHeight}}function go(){return b(window,"resize",{passive:!0}).pipe(l(vo),N(vo()))}function yo(){return Q([bo(),go()]).pipe(l(([e,t])=>({offset:e,size:t})),J(1))}function lr(e,{viewport$:t,header$:r}){let n=t.pipe(X("size")),o=Q([n,r]).pipe(l(()=>Be(e)));return Q([r,t,o]).pipe(l(([{height:i},{offset:a,size:s},{x:f,y:c}])=>({offset:{x:a.x-f,y:a.y-c+i},size:s})))}(()=>{function e(n,o){parent.postMessage(n,o||"*")}function t(...n){return n.reduce((o,i)=>o.then(()=>new Promise(a=>{let s=document.createElement("script");s.src=i,s.onload=a,document.body.appendChild(s)})),Promise.resolve())}var r=class{constructor(n){this.url=n,this.onerror=null,this.onmessage=null,this.onmessageerror=null,this.m=a=>{a.source===this.w&&(a.stopImmediatePropagation(),this.dispatchEvent(new MessageEvent("message",{data:a.data})),this.onmessage&&this.onmessage(a))},this.e=(a,s,f,c,u)=>{if(s===this.url.toString()){let p=new ErrorEvent("error",{message:a,filename:s,lineno:f,colno:c,error:u});this.dispatchEvent(p),this.onerror&&this.onerror(p)}};let o=new EventTarget;this.addEventListener=o.addEventListener.bind(o),this.removeEventListener=o.removeEventListener.bind(o),this.dispatchEvent=o.dispatchEvent.bind(o);let i=document.createElement("iframe");i.width=i.height=i.frameBorder="0",document.body.appendChild(this.iframe=i),this.w.document.open(),this.w.document.write(` + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + + + + + +
+
+ + + + + + + + +

Changelog

+

Version 4.2 [2023-07-24]

+
    +
  • Fix SonarCloud reports - issue #182 by @viktoriussuwandi
  • +
  • Fix security in GitHub Actions and AppVeyor pipeline
  • +
  • Add CSharpier (Linter)
  • +
  • Add DeepSource scanner
  • +
+

Version 4.1 [2023-03-22]

+ +

Version 4.0 [2023-03-22]

+ +

Version 3.1 [2022-09-10]

+
    +
  • Add CrispyWaffle.ElasticSearch project & package - issue #119.
  • +
+

Version 3.0 [2022-09-09]

+
    +
  • Upgrade dependencies and increase unit test coverage.
  • +
+

Version 2.5 [2020-09-07]

+
    +
  • Add CrispyWaffle.RabbitMQ project & package - issue #92.
  • +
+

Version 2.4 [2020-09-06]

+
    +
  • Add CrispyWaffle.Redis project & package.
  • +
  • Add documentation for caching.
  • +
+

Version 2.3 [2020-09-06]

+
    +
  • Add FailoverExceptionHandler class - issue #73.
  • +
  • Add Environment Helper class - issue #75.
  • +
+

Version 2.2 [2020-09-05]

+
    +
  • Add a scheduler feature.
  • +
  • Add documentation using MkDocs.
  • +
+

Version 2.1 [2020-09-04]

+
    +
  • Add the Configuration project and package.
  • +
  • Add Mustache template engine (inspired by Mustache/Handlebars).
  • +
  • Add Resource template repository.
  • +
  • Add Elmah & Log4Net projects (logging).
  • +
  • Basic usage examples.
  • +
+

Version 2.0 [2020-08-03]

+
    +
  • Removed some application-specific patterns from the StringExtensions class
  • +
+

Version 1.3 [2020-07-24]

+
    +
  • Add EvenLogProvider and EventLogAdapter.
  • +
  • Add log Trace methods that support exceptions.
  • +
  • Add Fatal log level.
  • +
+

Version 1.2 [2020-03-28]

+
    +
  • Add some unit tests.
  • +
  • Update appveyor.yml with build enhancements and test coverages.
  • +
  • Update readme template.
  • +
+

Version 1.1 [2019-09-27]

+
    +
  • Add Math Extensions (CrispyWaffle.Extensions.MathExtensions namespace).
  • +
  • Add Personal Data Validations (CrispyWaffle.Validations.PersonalDataValidations).
  • +
  • Rename method FormatDocument to FormatBrazilianDocument (CrispyWaffle.Extensions.ConversionExtensions).
  • +
  • Rename method ParsePhoneNumber to arseBrazilianPhoneNumber (CrispyWaffle.Extensions.ConversionExtensions).
  • +
  • Removed CleanListItems (CrispyWaffle.Extensions.ConversionExtensions).
  • +
  • Rename method TryParsePhoneNumber to TryParseBrazilianPhoneNumber (CrispyWaffle.Extensions.ConversionExtensions).
  • +
  • Removed CleanListItems and ToListString (CrispyWaffle.Extensions.ConversionExtensions) (Specific to application patterns).
  • +
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/extra.css b/extra.css new file mode 100644 index 00000000..295488a1 --- /dev/null +++ b/extra.css @@ -0,0 +1,11 @@ +table { + width: 100%; +} + +table tr td { + text-align: center; +} + +.wy-nav-content { + max-width: 90%; +} \ No newline at end of file diff --git a/images/favicon.png b/images/favicon.png new file mode 100644 index 00000000..e8f6e877 Binary files /dev/null and b/images/favicon.png differ diff --git a/index.html b/index.html new file mode 100644 index 00000000..8dc79834 --- /dev/null +++ b/index.html @@ -0,0 +1,554 @@ + + + + + + + + + + + + + + + + + + + + Crispy Waffle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Welcome to Crispy Waffle

+

A toolkit for .NET projects.

+

Crispy Waffle logo

+

This project is proudly maintained by @guibranco GitHub followers

+

Source code available at: GitHub GitHub stars

+

Currently opened issues: GitHub issues

+

Build status

+ + + + + + + + + + + + + + + +
Build statusLast commitTests
Build statusGitHub last commitAppVeyor tests (branch)
+

Code quality

+ + + + + + + + + + + + + + + +
CoverageCode SmellsLoC
CoverageCode SmellsLines of Code
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/installation/index.html b/installation/index.html new file mode 100644 index 00000000..c476fb0b --- /dev/null +++ b/installation/index.html @@ -0,0 +1,669 @@ + + + + + + + + + + + + + + + + + + + + + + Installation - Crispy Waffle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Installation

+

About

+

The Crispy Waffle project is divided into some packages:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PackageDescription
CrispyWaffleThe core package, with main features.
ConfigurationConfiguration abstractions.
ElasticSearchThe ElasticSearch extension package.
Implements the Elastic Search client and log features.
ELMAHThe ELMAH exception handler.
Redirects the exceptions messages (from LogConsumer.Handle method) to ELMAH.
Log4NetThe Log4Net log provider.
Redirects the log output to Log4Net.
RabbitMQThe RabbitMQ extension package.
Implements the RabbitMQ message broker client and log features.
RedisThe Redis extension package.
Implements the Redis cache, log and telemetry features.
UtilsThe utility extension package.
Implements the utilities classes (communications - FTP client, SMTP mailer).
+

Github Releases

+

GitHub last release Github All Releases

+

Download the latest zip file from the Release page.

+

Nuget package manager

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
PackageVersionDownloads
CrispyWaffleCrispyWaffle NuGet VersionCrispyWaffle NuGet Downloads
CrispyWaffle.ConfigurationCrispyWaffle Configuration NuGet VersionCrispyWaffle Configuration NuGet Downloads
CrispyWaffle.ElasticSearchCrispyWaffle ElasticSearch NuGet VersionCrispyWaffle ElasticSearch NuGet Downloads
CrispyWaffle.ElmahCrispyWaffle ELMAH NuGet VersionCrispyWaffle ELMAH NuGet Downloads
CrispyWaffle.Log4NetCrispyWaffle Log4Net NuGet VersionCrispyWaffle Log4Net NuGet Downloads
CrispyWaffle.RabbitMQCrispyWaffle RabbitMQ NuGet VersionCrispyWaffle RabbitMQ NuGet Downloads
CrispyWaffle.RedisCrispyWaffle Redis NuGet VersionCrispyWaffle Redis NuGet Downloads
CrispyWaffle.UtilsCrispyWaffle Utils NuGet VersionCrispyWaffle Utils NuGet Downloads
+

Package Manager Console (manual):

+

CrispyWaffle

+
Install-Package CrispyWaffle
+
+

Configuration

+
Install-Package CrispyWaffle.Configuration
+
+

ElasticSearch

+
Install-Package CrispyWaffle.ElasticSearch
+
+

ELMAH

+
Install-Package CrispyWaffle.Elmah
+
+

Log4Net

+
Install-Package CrispyWaffle.Log4Net
+
+

RabbitMQ

+
Install-Package CrispyWaffle.RabbitMQ
+
+

Redis

+
Install-Package CrispyWaffle.Redis
+
+

Utils

+
Install-Package CrispyWaffle.Utils
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/license/index.html b/license/index.html new file mode 100644 index 00000000..4d051aa2 --- /dev/null +++ b/license/index.html @@ -0,0 +1,464 @@ + + + + + + + + + + + + + + + + + + + + + + License - Crispy Waffle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

MIT License

+

Copyright (c) 2019-2023 Guilherme Branco Stracini

+

Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions:

+

The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software.

+

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.

+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/logo.png b/logo.png new file mode 100644 index 00000000..e8f6e877 Binary files /dev/null and b/logo.png differ diff --git a/sitemap.xml b/sitemap.xml new file mode 100644 index 00000000..92ec8400 --- /dev/null +++ b/sitemap.xml @@ -0,0 +1,58 @@ + + + + None + 2023-10-08 + daily + + + None + 2023-10-08 + daily + + + None + 2023-10-08 + daily + + + None + 2023-10-08 + daily + + + None + 2023-10-08 + daily + + + None + 2023-10-08 + daily + + + None + 2023-10-08 + daily + + + None + 2023-10-08 + daily + + + None + 2023-10-08 + daily + + + None + 2023-10-08 + daily + + + None + 2023-10-08 + daily + + \ No newline at end of file diff --git a/sitemap.xml.gz b/sitemap.xml.gz new file mode 100644 index 00000000..848dce88 Binary files /dev/null and b/sitemap.xml.gz differ diff --git a/user-guide/basic-usage/index.html b/user-guide/basic-usage/index.html new file mode 100644 index 00000000..54c2165a --- /dev/null +++ b/user-guide/basic-usage/index.html @@ -0,0 +1,524 @@ + + + + + + + + + + + + + + + + + + + + + + Basic Usage - Crispy Waffle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+ +
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user-guide/caching/index.html b/user-guide/caching/index.html new file mode 100644 index 00000000..1a7d883f --- /dev/null +++ b/user-guide/caching/index.html @@ -0,0 +1,593 @@ + + + + + + + + + + + + + + + + + + + + + + Caching - Crispy Waffle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Caching

+

About

+

Cache data is easy with Crispy Waffle, there are available two repositories for cache:

+
    +
  • MemoryCacheRepository: A cache repository that store data in application memory.
  • +
  • RedisCacheRepository: A cache repository that uses Redis as persistence mechanism.
  • +
+

There is also a helper class, CacheManager that make cache usage easy.

+

Examples

+

Single cache repository + CacheManager helper class

+

The following example uses the RedisCacheRepository and the CacheManager helper class:

+

Process #1 (write data to cache):

+
ServiceLocator.Register<ICacheRepository, RedisCacheRepository>(LifeStyle.SINGLETON);
+CacheManager.AddRepository<ICacheRepository>();
+
+CacheManager.Set("some string text", "MyKey");
+
+

Process #2 (read data from cache - Redis):

+
ServiceLocator.Register<ICacheRepository, RedisCacheRepository>(LifeStyle.SINGLETON);
+CacheManager.AddRepository<ICacheRepository>();
+
+var cachedValueFromRedis = CacheManager.Get<string>("MyKey"); //some string text
+
+

Multiple cache repositories (registration precedence)

+

Using multiple cache repositories:

+
ServiceLocator.Register<ICacheRepository, MemoryCacheRepository>(LifeStyle.SINGLETON);
+ServiceLocator.Register<RedisCacheRepository>(LifeStyle.SINGLETON);
+
+CacheManager.AddRepository<ICacheRepository>(); //or directly: CacheManager.AddRepository<MemoryCacheRepository>(); 
+CacheManager.AddRepository<RedisCacheRepository>(); //RedisCacheRepository
+
+var cachedValue = CacheManager.Get<string>("MyKey"); //first will lookup in MemoryCacheRepository then RedisCacheRepository
+
+var cachedValueFromSpecificRepository = CachemManager.GetFrom<RedisCacheRepository, string>("MyKey"); //will get the value only from RedisCacheRepository.
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user-guide/events/index.html b/user-guide/events/index.html new file mode 100644 index 00000000..df31297a --- /dev/null +++ b/user-guide/events/index.html @@ -0,0 +1,633 @@ + + + + + + + + + + + + + + + + + + + + + + Events - Crispy Waffle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Events

+

Definition

+

Events are a way to execute one or more actions based on a class (the event itself). +Events are defined as a simple class, inherited from IEvent interface.

+

Each event can be handled by one, two or infinite number of event handlers.

+

Event handler class inherit from IEventHandler<TEvent> interface and must implement the Handle(TEvent evt) method. +The TEvent generic type is the type of IEvent that will be handled.

+

For example, the HelloWorldEvent class, defined below is a simple class without methods, properties or fields and is used to trigger HelloWorldEventHandler:

+

Event class:

+
public class HelloWorldEvent : IEvent {}
+
+

Event handler class:

+
public class HelloWorldEventHandler : IEventHandler<HelloWorldEvent> 
+{
+    public Handle(HelloWorldEvent evt)
+    {
+        Console.WriteLine("Hello World triggered!");
+    }
+}
+
+

To trigger the event handler just call the EventsConsumer.Raise method from any part of your code:

+
EventsConsumer.Raise(new HelloWorldEvent());
+//do other stuff...
+
+

Each event handler can handle many kinds of events, just need to implement each interface and each method Handle.

+

Event handling is currently done synchronously. There are plans to do async, issue #XX.

+
+

Examples

+

Multiple event handlers for the same event

+

A more complex example using Events & EventsHandlers. +In this example, there are two event handlers and the event class has some properties:

+
//The event class.
+public class SomeEvent : IEvent 
+{
+    public SomeEvent(string data)
+    {
+        Id = Guid.NewGuid();
+        Date = DateTime.Now;
+        Data = data;
+    }
+
+    public Guid Id { get; }
+
+    public string Data { get; }
+
+    public DateTime Date { get; }
+}
+
+//The event handler class. Each event can be handled by N event handlers.
+public class SomeEventHandler : IEventHandler<SomeEvent>
+{
+    //constructor of the class, with dependencies...
+    //dependencies are resolved by ServiceLocator.
+
+    public void Handle(SomeEvent args)
+    {
+        LogConsumer.Warning("Event 'SomeEvent' handled by 'SomeEventHandler'. Event Id: {0}", args.Id);
+        //do any other processing stuff...
+    }
+}
+
+public class AnotherSomeEventHandler : IEventHandler<SomeEvent>
+{
+    //constructor of the class, with dependencies...
+    //dependencies are resolved by ServiceLocator.
+
+    public void Handle(SomeEvent args)
+    {
+        LogConsumer.Warning("Event 'SomeEvent' handled by 'AnotherSomeEventHandler'. Event Id: {0}", args.Id);
+
+        //someOtherDependency.DoSomeStuffWithEvent(args.Id, args.Data);
+        //do any other processing stuff...
+    }
+}
+
+// Program entry point
+public static class Program 
+{    
+    public static void Main(string[] args)
+    {
+        //Initialize the dependencies with ServiceLocator.
+        //Initialize log providers/adapters
+        //...
+
+        var evt = new SomeEvent ("Some text passed to all event handlers");
+        EventsConsumer.Raise(evt);
+    }
+}
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user-guide/logging/index.html b/user-guide/logging/index.html new file mode 100644 index 00000000..14e4b275 --- /dev/null +++ b/user-guide/logging/index.html @@ -0,0 +1,558 @@ + + + + + + + + + + + + + + + + + + + + + + Logging - Crispy Waffle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Logging

+

Definition

+

The Crispy Waffle provides some logs providers/adapters for loggin purproses.

+

Default providers:

+
    +
  • ConsoleLogProvider: Output log to console window.
  • +
  • EventLogProvider: Output log using EventLogAdapter.
  • +
  • TextFileLogProvider: Output log to a text file in the file system.
  • +
  • Log4NetLogProvider: Bridge from CrispyWaffle logging to Log4Net logging.
  • +
  • ...
  • +
+

Default adapters:

+
    +
  • StandardConsoleLogAdapter: Colored console output.
  • +
  • StandardTextFileLogAdapter: Simple text file output.
  • +
  • RollingTextFileLogAdapter: Text file output, rolling to another file every time each reaches defined size.
  • +
  • ...
  • +
+

Examples

+

A simple console application with simple (colored console output) logging example:

+
static void Main(string[] args)
+{
+    //Registering the standard console log adapter to be used by console log provider. 
+    ServiceLocator.Register<IConsoleLogAdapter, StandardConsoleLogAdapter>(LifeStyle.SINGLETON);
+
+    //Registering the null exception handler for the method LogConsumer.Handle, this means that no action will be executed for exceptions handled by LogConsumer.
+    ServiceLocator.Register<IExceptionHandler, NullExceptionHandler>(LifeStyle.SINGLETON);
+
+    //Adding console provider to LogConsumer, the log provider will use the registered IConsoleLogAdapter.
+    LogConsumer.AddProvider<ConsoleLogProvider>();
+
+    LogConsumer.Info("Hello world Crispy Waffle");
+
+    LogConsumer.Debug("Current time: {0:hh:mm:ss}", DateTime.Now);
+
+    LogConsumer.Warning("Press any key to close the program!");
+
+    Console.ReadKey();
+}
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user-guide/messaging/index.html b/user-guide/messaging/index.html new file mode 100644 index 00000000..21134cd2 --- /dev/null +++ b/user-guide/messaging/index.html @@ -0,0 +1,590 @@ + + + + + + + + + + + + + + + + + + + + + + Messaging - Crispy Waffle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Messaging

+

Definition

+

The Crispy Waffle provides a set of helpers to send/receive messaging over RabbitMq broker.

+

Examples

+

Send message to a RabbitMq exchage:

+

+[ExchangeName("rabbitmq-exchange-name")]
+[Serializer(SerializerFormat.JSON)]
+public class SampleItemDto
+{
+    public Guid Id { get; set; }
+
+    public string Text { get; set; }
+
+    public DateTime Date { get; set; }
+}
+
+static void Main(string[] args)
+{
+    //Registering the RabbitMq connector as singleton lifecycle.
+    ServiceLocator.Register<RabbitMQConnector>(LifeStyle.SINGLETON);
+
+    var data = new SampleItemDto 
+    {
+        Id = Guid.NewGuid(),
+        Text = "some random text",
+        Date = DateTime.Now
+    };
+
+    //Gets the wrapper
+    var wrapper = ServiceLocator.Resolve<RabbitMQWrapper>();
+
+    //Send to exchange (the exchange name is set via attributes in the SampleItemDto declaration)
+    wrapper.SendToExchange(data);
+
+    Console.ReadKey();
+}
+
+

Send message to a RabbitMq queue:

+

+[QueueName("rabbitmq-queue-name")]
+[Serializer(SerializerFormat.JSON)]
+public class SampleItemDto
+{
+    public Guid Id { get; set; }
+
+    public string Text { get; set; }
+
+    public DateTime Date { get; set; }
+}
+
+static void Main(string[] args)
+{
+    //Registering the RabbitMq connector as singleton lifecycle.
+    ServiceLocator.Register<RabbitMQConnector>(LifeStyle.SINGLETON);
+
+    var data = new SampleItemDto 
+    {
+        Id = Guid.NewGuid(),
+        Text = "some random text",
+        Date = DateTime.Now
+    };
+
+    //Gets the wrapper
+    var wrapper = ServiceLocator.Resolve<RabbitMQWrapper>();
+
+    //Send to queue (the queue name is set via attributes in the SampleItemDto declaration)
+    wrapper.SendToQueue(data);
+
+    Console.ReadKey();
+}
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user-guide/scheduled-jobs/index.html b/user-guide/scheduled-jobs/index.html new file mode 100644 index 00000000..ebc5fa7f --- /dev/null +++ b/user-guide/scheduled-jobs/index.html @@ -0,0 +1,577 @@ + + + + + + + + + + + + + + + + + + + + + + Scheduled jobs - Crispy Waffle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Scheduled jobs

+

Definition

+

Scheduler jobs allows schedule the execution of some method/action using CRON expressions.

+

CRON expression

+

Currently supports the following formats:

+
    +
  • *: translates to * * * * * (every minute, every day).
  • +
  • 10: translates to 10 * * * * (every 10th minute of every hour on every day).
  • +
  • 10 1 * * 0: runs every 1:10 am of every Sunday
  • +
  • */10: runs at 0, 10, 20, 30, 40 and 50 minute of every hour on every day.
  • +
  • */20 * 10,20,30 * *: runs at 0, 20 and 40 minute of every hour only in days 10, 20 or 30 of each month, independently of the week day.
  • +
+

Check the Wikipedia's CRON page for more examples and details.

+

Examples

+

Using cron expression to schedule tasks/jobs inside a program.

+
public static class Program
+{
+    public static void Main(string[] args)
+    {
+        var exampleObj = new SomeClass();
+        exampleObj.Counter = 10;
+
+        var jobManager = new JobManager();
+        jobManager.AddJob(new JobRunner("* * * * *", () => { exampleObj.Counter++; }));
+        jobManager.Start();
+
+        Thread.Sleep(120 * 1000); //waits 2 minutes
+
+        jobManager.Stop(); //stops the manager, so no more execution runs.
+
+        if(exampleObj.Counter == 12)
+        {
+            LogConsumer.Warning("Example job runned for 2 times!");
+        }
+
+    }
+
+    internal class SomeClass 
+    {
+        public int Counter { get; set; } 
+    }
+
+}
+
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file diff --git a/user-guide/serviceLocator/index.html b/user-guide/serviceLocator/index.html new file mode 100644 index 00000000..a8a87715 --- /dev/null +++ b/user-guide/serviceLocator/index.html @@ -0,0 +1,577 @@ + + + + + + + + + + + + + + + + + + + + Service Locator - Crispy Waffle + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + +
+ + +
+ +
+ + + + + + +
+
+ + + +
+
+
+ + + + +
+
+
+ + + +
+
+
+ + + +
+
+
+ + + +
+
+ + + + + + + + +

Service Locator

+

Definition

+

The service locator class is a helper class that acts like a IoC container. +You can register instances as singleton/transient scope. Register dependencies and request a instance of a interface/class.

+

Examples

+

The following example register a singleton class and then request it multiple times. +In this example, the class is instantiante in the first Resolve call

+
public class SingletonTest 
+{
+    public DateTime Date { get; set; }
+
+    //when creating a instance, set the Date property to DateTime.Now value.
+    public SingletonTest() => Date = DateTime.Now;
+}
+
+static void Main(string[] args)
+{
+    //Registering
+    ServiceLocator.Register<SingletonTest>(LifeStyle.SINGLETON);
+
+    var instanceA = ServiceLocator.Resolve<SingletonTest>();
+
+    Thread.Sleep(1000);
+
+    var instanceB = ServiceLocator.Resolve<SingletonTest>();
+
+    Thread.Sleep(1000);
+
+    var instanceC = ServiceLocator.Resolve<SingletonTest>();
+
+    //check that all 3 instances has the same Date.
+}
+
+

The following create a new instance for every Resolve call

+

+public class TransientTest 
+{
+    public DateTime Date { get; set; }
+
+    //when creating a instance, set the Date property to DateTime.Now value.
+    public TransientTest() => Date = DateTime.Now;
+}
+
+static void Main(string[] args)
+{
+    //Registering
+    ServiceLocator.Register<TransientTest>();
+
+    var instanceA = ServiceLocator.Resolve<TransientTest>();
+
+    Thread.Sleep(1000);
+
+    var instanceB = ServiceLocator.Resolve<TransientTest>();
+
+    Thread.Sleep(1000);
+
+    var instanceC = ServiceLocator.Resolve<TransientTest>();
+
+    //check that all 3 instances has different Date properties value.
+}
+
+ + + + + + +
+
+ + +
+ +
+ + + +
+
+
+
+ + + + + + + + + \ No newline at end of file