Animation

Latest Prototype
Cash.fn.animate essentials:

[x] Psuedo jQuery-compatible API, not 100% parity but enough to ease migration
[x] Use Element.animate, falling back to a requestAnimationFrame animation engine
[x] $.animate method for animating object properties using the requestAnimationFrame engine.
[x] Group animation calls into one requestAnimationFrame loop for best performance
[x] Support animating multiple transform properties using x, y, z, scale, etc. (we should be able to parse the current element.style.transform to fill in the 'from' values.)
[x] start and complete callbacks (per element)
[ ] progress callbacks (may be problematic with Element.animate, but necessary for Object callbacks)
[x] Stagger feature for offsetting collection animations
[ ] Attempt to convert between % and px where possible ( animating from width: 100% to width: 20px, for example. This is necessary for the requestAnimationFrame fallback, but WAAPI handles it automatically)
[ ] Target weight of 2-4kb minified, 1-2kb gzipped.

Possible features:

[x] CSS Transform Matrix conversion to correctly animate from existing transforms. (needs further testing)
[x] collectionComplete callback (allComplete, animationend?)
[x] Bezier curve conversion ( reference ) for CSS compatible easing (need to compare with standard CSS easings)
[ ] True fill support? Currently applies whatever the end state of animation is (equivalent to fill: both)
[ ] WAAPI Methods ( player.pause(); //"paused", player.play(); //"running", player.cancel(); //"idle"... jump to original state and player.finish(); //"finished"...jump to end state, player.reverse() )
[x] Sequential animations var frames = [ [{ props }, { opts }], [{ props }, { opts }] ]; $(element).animate(frames);
[ ] Sequential animations across multiple elements

Original Issue
I think the future of Cash may need to center around modularity with lightweight extensions/plugins. There are only so many DOM methods we can add that are worthwhile, and performance optimizations will only go so far.
The main Cash package will always have the most useful methods to help beginners get started, but I picture developers being able to select the features/modules they need to get a lightweight package (less than 10-15kb) that gives them exactly what they need for a project without any cruft like we've talked about in #94.
Thinking along those terms, I have a basic animation engine (two files: animateCore.js and canvallax.Animate.js that's quite performant. It could easily be adapted as a cash plugin, minified to about 1kb gzipped, 2kb minified.
Currently it's more along the lines of GSAP TweenMax syntax and designed to animate properties of objects, but it could be adapted to handle CSS properties and more closely match the jQuery syntax for compatibility while introducing some more advanced functions (delay, repeat, animateFrom, animateFromTo, etc).
Like the discussion for AJAX ( #103 ), this wouldn't be an addition to the core, but a separate module for those that want a lightweight but familiar syntax to run simple animations. jQuery with the animation module is at least 50kb, and TweenLite + jQuery support is around 30kb. That's a lot to add for simple effects like spinning an element when clicked or to smoothing a transition from point A to point B.
Any thoughts on animation or the future of Cash?

I think cash is pretty good as is, feature wise. For animation, I wouldn't use anything other than velocity for most implementations. Something like spinning an element when clicked enters the territory of css animation based on class changes.

Yeah, I use CSS animations / class toggles wherever I can but programmatic animations are still a need. Velocity isn't any better in terms of file size ( 30+kb minified ).
When I don't need a boatload of features, I try to find something lightweight & performant. A simple $().animate would be quite useful as an extension for those situations, but I understand if it's not something you think cash should support.

Here's a basic conversion that animates CSS properties on collections in 1.8kb: http://codepen.io/shshaw/pen/WwLKVY?editors=0010
Definitely could be simplified more, especially cutting extra features that jQuery.animate doesn't have ( yoyo, reverse, variable duration, repeat, delay, pause, etc. ).
Adding transform ( x, y, scale, rotate ) support would be pretty easy and would allow animations to be even more performant.

Velocity.js is great for programmatic animation but i do agree with @shshaw in that loading velocity for some basic animations via CSS is nearly always total overkill.
Imagine simple stuff as show/hide or page-object transitions with 'stagger'.

With Custom Builds (issue #94), you could have a cash's core + css + animation in ~4kb, 2kb gzipped for handling all sorts of complex animations. That's would be a lot of functionality in a tiny package.

Basic transform support with prefixed properties support. Compresses to about 2kb, and might be trimmable.
Needs support for reading existing transform properties, potentially building a transform matrix instead of the individual transform functions.

@shshaw So will this happen? Animation or motion in UI really is pretty much now but what technique(s) that are used is in constant flux (latest being the "FLIP" technique by Google) so basic wrappers and some extensions would be a great thing since such base extensions easily can be rewritten or forked to work with A, B or C etc.

@tommiehansen FLIP may be too heavy handed of a technique for a general animation engine. Based on what I've seen, FLIP works well when you're planning & coding every piece of it, but I don't know if it would work well in a general setting. I'll have to look at FlipJS to see how they handle it.
That did make me think: in keeping with Cash's 'mission' of using native browser APIs, we could use Element.animate() if available, and fall back to requestAnimationFrame. Browser support isn't the best, but once Firefox enables it by default in the next version then you're at about 50% coverage. Shouldn't be hard to adapt my implementation to do that.

@shshaw Yes, that's why i wrote about techniques being in 'constant flux' and the anim engine therefor needing to be very generic. It seems i either was not clear or you just didn't read what i wrote. :)
And yes -- using Element.animate() + fallback would be great.

@tommiehansen I just misinterpreted your mention of FLIP as a recommendation.
As for your original question: 'will this happen?': I've gotten to go ahead from @kenwheeler. I'll start a branch for this after I've cleaned up my concept a little bit. Contributions are welcome. Don't know how quickly I'll be able to roll it out, but an alpha should be available soon for testing.

Here's what's on my list for $.fn.animate features. Most are already implemented in the prototype, but need some cleanup and fine tuning.

[ ] Psuedo jQuery-compatible API, not 100% parity but enough to ease migration
[ ] Try to use Element.animate, falling back to a requestAnimationFrame animation engine
[ ] Group animation calls into one requestAnimationFrame loop for best performance
[ ] Support animating multiple transform properties using x, y, z, scale, etc. (we should be able to parse the current element.style.transform to fill in the 'from' values.)
[ ] start, complete and progress callbacks (which may be problematic with Element.animate)
[ ] Small collection of easings (Need to see about compatiblity with Element.animate)
[ ] Attempt to convert between % and px where possible ( animating from width: 100% to width: 20px, for example)
[ ] $.animate method for animating object properties using the requestAnimationFrame engine. Allows for more versatile use than just animating a DOM element.

Any other essentials I seem to be missing?

Regarding missing features:

jQuery does not support repeat, but Element.animate & most other animation libraries will. Is that something to support?
Along those lines, reversing animations & yoyoing ( reverse on repeat ) is not something available in jQuery, but most other libraries do.
delay option before starting animation?

Most of those I have an implementation of, but I've trimmed out. These specfic items wouldn't add much weight.

Reverse is good for playing something in reverse and is helpful. Need options to change duration and easing though since one often want to animate in with A but out with B.

elem.animate({ y: 0, opacity: 1 }, { duration: 500, easing: easeOutQuad })
elem.reverse({ duration: 250, easing: easeInQuad })

Another thing is staggering which is always useful when one animates a group of elements.
Examples
http://codepen.io/tommiehansen/full/ONYyye/
http://codepen.io/tommiehansen/full/ZWNRoY/

Cool demos, @tommiehansen. I think having iterations and direction properties makes sense, and shouldn't add much weight.

Btw -- seeing as the Web Animations API is on the rise an idea would be to use that syntax because that would make it much more easy to transition over in the near future. Chrome and Firefox already have support for it and the MS Edge team has flagged it from 'under consideration' to 'medium priority'.
The syntax is pretty straight forward and it shouldn't be too hard for anyone that have ever used something like jQuery to use WAAP.

I making a cross between the Web Animations API and the jQuery.animate API to allow for complete and start callbacks. I am also not supporting the full keyframes interface like the Web Animations API, but simply animating from the current state to the state provided as the first parameter.
Here's the latest prototype. Still a bit rough at the moment, but it is working with objects and elements (with and without Element.animate) and supports transforms.
// Animate from the current state to these properties
var animateTo = {
        x: '200px', // translateX shortcut
        scale: 0.5
      },

      animationOptions = {
        // jQuery-like animation options
        start: function(){ console.log('Animation has started'); },
        complete: function(){ console.log('Animation is complete!'); },

        // jQuery/Web Animation API equal options
        easing: 'linear',
        duration: 400,

        // Web Animation API style options
        iterations: 2,
        direction: 'alternate',
        delay: 1000
      };

$('#myDiv').animate( animateTo, animationOptions );

The Web Animation API's fill was preventing further transform animations from working, so I have to manually apply the styles after the animation is complete in order to prevent the element from jumping back to the original state.
Feel free to fork & play around with that. Let me know if you catch any oddities. I'm aware of a few issues, but the functionality is about there.

Tested it briefly. The easy stuff, A -> B seems to work as expected.
But something that's immediately noticable is that the complete function is broken since it fires once per item in a collection. So complete: function(){ myComplexFunction(); } would fire once per item in a collection. Need to check length of collection and fire the complete action after the last iteration has completed its animation.
If it fired once per collection it would be easy to write a little function that iterates through frames, like this:
http://codepen.io/tommiehansen/pen/Razoex?editors=0010

For jQuery.animate: "If supplied, the start, step, progress, complete, done, fail, and always callbacks are called on a per-element basis;", which is inline with Web Animation API's individual animations and finish event.
If that's how we proceed, then this for the callbacks should be the element being animated, so as in your example, you could do this:
el.animate(frames[0], {
	easing:		opts.easing,
	duration:		opts.duration,
	complete:		function(){ $(this).animate(frames[1], opts); }
});

Perhaps two separate callbacks are needed: complete for each element and collectionComplete (or allComplete?) run when the collection is finished animating, which would be especially useful if a stagger is implemented.
I have a newer prototype that's trimmed off a full kb from the minified version while retaining the current functionality, and the code should be a little easier to parse.
It's still likely that we'll need to implement a transform matrix conversion, and I'm looking at a Bezier curve convertor that should allow us to have parity with CSS easings.

I've updated the original issue with the essential features list and some possible features. Take a look and let me know if anything we've talked about is missing or any other features you've thought of.

Latest prototype up. 4kb minified, 2kb gzipped with staggering, Bezier conversions and Transform matrix calculations (buh, what a nightmare).
The current CSS bezier conversions for ease, ease-in-out, etc, aren't 100% identical. Need to tweak the curve values.

You work fast, trying it out now. :)

Edit: It seems to work great, the only caveat is of course the lack of being able to easily create more then two frames since multiple complete quickly becomes very messy. See my updated example at http://codepen.io/tommiehansen/pen/Razoex?editors=0010
You said that you'd leave out support for it though so it isn't a bug or fault per say.
Velocity.js does have it in this regard with its sequence, check out a very old example i made:
http://codepen.io/tommiehansen/pen/netCu?editors=0010
Click the Demo loop (infinite) button to play all the sequences. As an example only a single click on the button "popular photos" triggers 4 animations (0: scale down/up button, 1: slide out button, 2: slide in div, 3: fade in images with staggering).

Glad it's working as expected! Feel free to run some performance tests, especially compared to jQuery.animate and Velocity. I'm not very familiar with Velocity.
I haven't ruled out a allComplete callback yet, but I'm trying to figure out the appropriate way to implement it.

Compare against jquery.animate seems redundant. No one really uses jq animate for 'real' animations. Against velocity it would be raw js animations vs css3 animations, there are already stuff on that. The big diff is that css3 animations is native to the browsers which, in my opinion, is always better.
Something that is slighly urgent, for dev-purposes at least, is some sanity check for infinite loops. My browser constatly hangs when trying loops at Codepen.
The complete per element is quite odd. Depends on how one see an animation. I don't really have an answer on that except that it depends on if one see a "frame" or an animation as something that occurs (which it technically do) on multiple items.
Another "problem" with  just A > B animations  is that these can already be done sufficiently in plain CSS and JS just like @kenwheeler said and if one needs simple callbacks one could just include something like ba.js, https://github.com/Arood/bajs
Before you write more code maybe you could/should check out how the WAAPI handles these things, this is a good guide: http://danielcwilson.com/blog/2015/07/animations-intro/

In trying to really test the latest build i began trying to recreate http://codepen.io/tommiehansen/pen/netCu?editors=0010
..here:
http://codepen.io/tommiehansen/pen/yOdEZm?editors=0100
Opacity doesn't seem to work for some elements and the lib quickly becomes annoying due to the lack of any sequencing, que-system or timeline of any sorts. Even the old jquery.animate handles ques (chaining):
element
  .animate(props, opts)
  .animate(props, opts)
  .animate(props, opts);

But chaining in that way isn't really good because that too becomes a bit too much as soon as one reaches over 4 frames, that's why libs like Velocity js got a sequence func:
var frames = [
  [{ props }, { opts }],
  [{ props }, { opts }],
  [{ props }, { opts }],
]

$.runSequence(frames);

A diff in Velocity JS is also that it reads the previous state, something that WAAPI doesn't seem to do at the moment. This makes it easier to create sequences since one doesn't need to write all props for each and every frame within a sequence.

Not sure what the issue with Infinity iterations would be, but I've added a check that may help. It's working as expected for me, so can you send an example of the freezing?
I have been following the WAAPI documentation and implementing everything as close to that as possible.
Regarding callbacks, WAAPI animations are all per element, and the finish and cancel event callbacks are also per element. CSS animations callbacks via animationend events are also per element. Again, I'm not ruling out an allComplete, just explaining why a complete ( or finish ) per element is needed.
The real advantage with $.fn.animate and other animation engines is being able to set up and call animations on the fly. A to B animations in a programmatic way, (not known ahead of time, as a CSS animation could handle that) especially with looping and cross browser support are not exactly simple in plain JavaScript, unless there's a technique I'm unaware of, for a few reasons:

Since only Chrome & Firefox support WAAPI right now, you need a fallback and even simple element animations with Javascript aren't that easy (in that you'd want to set that up yourself in plain JS all the time)
WAAPI also doesn't allow for partial keyframes, you have to explicitly declare the start state and end state, meaning you have to parse the existing styles for animating elements, making it more difficult to just animate on the fly with plain JS.

I do like ba.js's way of creating a CSS animation that's applied to the element. A method like that could potentially save a good bit of code, and would likely be a worthwhile fallback all the way to IE10. However, JS animations would override existing CSS animations and could not be combined, though that may already be the case when animating transforms in particular.
Overall, it sounds like you mainly want a way to set up more complex animations in a CSS keyframes style syntax, which may be too far out of scope for this.

Sorry, was posting that as your latest message came through, so there may be some redundancy.
Sequencing isn't far fetched in the manner which you describe ( array of arrays featuring properties and options ), as it would just be re-calling Animate for the next set of frames at the end.

Ok, then implement an allComplete, allDone, or something that somehow describes that it is something that is triggered after an array of elements has finished animating.

It's on the list. Still figuring out the best way to implement and best naming conventions, so any suggestions are welcome.
I'm also seeing some issues with opacity. Not sure where that's coming from.

What you could do is to try to re-create my re-creation to get a better feel of the general pitfalls:
http://codepen.io/tommiehansen/pen/yOdEZm?editors=0010

Just updated the prototype with an allComplete callback.
Trying to figure out the opacity bug currently, but the overall setup now that allComplete is in place is better for a simple sequencing setup.
The expectation would be that the next sequence event would fire after all staggered elements have finished animating, correct?

Ah! Looks like I was removing some properties from the original end object, so opacity would only apply to one.
The prototype has been updated. 3.83kb minified, 1.98kb gzipped

Tommie, give the latest prototype a try. I think you'll like it ;-)
Probably need to change the callbacks to be frameComplete and allComplete

Yes, that would be the expected behaviour. Has nothing to do with staggering though but rather has to do with collections, collections can be anything like $('h1, p, .box')
Say one would want a startpage where one slides up a bounch of elements and after that has completed show a background image or start a video in the background. That's something that is more common then my box-thing.

Yes, i also saw you added the whole lib as a pen so that it can easily be included -- great. :)

Your changes really brings the code needed to written way down now, but i still hit a speed-bump quite early since there is no simple way to run sequence A on elem 1 and then sequence B on elem 2 without the code starting to get messy. Now it requires one to add "allComplete" to the animation frames themselves or maybe i've misunderstood how it works.
var myFrames = [
  [{ y:0 }, { duration:100 }],
  [{ y:100 }, { duration:100, allComplete: function(){ /*messy */ } }],
];

For ones sanity one really want to separate complete-calls away from any sequencing:
elem1.animate( myFrames, { allComplete: function(){
  elem2.animate( otherFrames );
})

Even that quickly becomes messy though, so:
var myFrames = {
  [{ elem1, prop2, prop3 }, { opts1 } ],
  [{ elem1, prop2, prop3 }, { opts2 }],
  [{ elem2, prop2, prop3 }, { opts3 } ],
};

$.animate( myFrames, { allComplete: function() { console.log('finished sequence'); }})

But the latter would move the entire thing away from the WAAPI which might not be that wise. The WAAPI is hardly the gold standard though, there's tons of stuff that's still missing and the "grouping" and "keyframeEffects" (effects ... ?!) is odd and alien at best; http://danielcwilson.com/blog/2015/09/animations-part-4/

Yes, you can include $.fn.animate using this pen.
To clarify some behavior:
// You can use one keyframe & options object.
$('h1').animate({ x: 200 },{ duration: 1000 });

// Or you can use a keyframes array
$('h1').animate([
  { x: 200 } // keyframe 1 (not the starting state, but the first keyframe to animate to)
  { x: 100 } // keyframe 2
  [{ x: 0, rotate: 360 },{ duration: 500 }] // keyframe 3, with custom options. These options will be merged via `$.extend` with the global options.
],
{ duration: 1000 } // Options for all keyframes
);

Right now, I'm working on the callbacks and this is what I have so far:
        start: noop, // animation start
        complete: noop, // animation complete

        itemStart: noop, // an item's animation has started
        itemProgress: noop, // progress on any item in the animation
        itemComplete: noop, // an item's animation has completed

        frameStart: noop, // a new keyframe has started
        frameComplete: noop, // a keyframe has been completed

With the new stuff a complete' in a sequence seems to act as a allFramesComplete so this sort of works:
$('button').on('click', function(){

	var $t = $(this);

	$.animate($t, buttonFrames, {
		complete: function(){
			$.animate($('.back'), backFrames, {
				complete: function(){
						$.animate($('.backImg'), { opacity: 1 }, { duration: 200, stagger: 60 })
				}
			});
		}
	});
})

But it gets quite messy quite quickly. It does almost work though, the opacity for the images last in the que refuses to animate for some reason.

Yeah, complete means "the entire animation has complete", reference my list above for the callback definitions.
This isn't intended to be TimelineMax or anything. Not sure how that's handled in Velocity (I cannot parse their documentation, what a mess!).
Sequencing multiple animations across different elements is a bit beyond the scope of this, so the 'callback soup' like you have would be how you'd handle that.

The opacity issue may be related to a cash bug I've discovered. You can't set $(el).css({ opacity: 0 }) or any other zero / false-y value. Looks like another version push is coming :-)

It almost is great though, so props for that. :-)
And that it is almost TimelineMax isn't such a bad thing. Even if only using one callback to trigger animation #2 it's still much more then most libs do or can do comfortably.
So now http://codepen.io/tommiehansen/pen/yOdEZm?editors=0010 actually is working even if the callbacks are a bit messy.

Great demo. Love the animations.
If you have any ideas for a simple way cross-element animations could be queued outside of callbacks, please let me know. I can't parse how Velocity does it, and I think GSAP's syntax would be too much for this.

Yes -- no GSAP syntax. :-)
I'll experiment with it more as soon as i got time (which equals the entire weekend since my girl is working). It fits the bill as well since i've been scouring the internet for a decent and non-bloated animation engine so that i don't have to write or include helper1, helper2, helper3 each and every time i want to do more then a simple statechanges aka "A > B animations" (ie the stuff that would end up in a stylesheet anyway).
That's why i began writing small libs such as animation.stagger,
demo: http://codepen.io/tommiehansen/full/ZWNRoY/
full src: https://github.com/tommiehansen/base/blob/master/js/animation.stagger/animation.stagger.js
Which basically just loops through elements and adds animation-delay or transition-delay but also has the option to end staggering after n elements. It leaves all other things to CSS and is great if one just want to add staggering without resorting to :nth-child or some ugly mixin in SASS and LESS.

Any way to reset an element?

A zero duration animation that resets the original state? :-)
No, currently it acts as fill: both, so whatever the end state is
(accounting for direction: alternate), that's applied.
I am looking at implementing a stop method to allow for killing infinite
animations, just haven't integrated that yet.
On Sat, May 21, 2016 at 2:14 AM Tommie Hansen<EMAIL_ADDRESS>wrote:

Any way to reset an element?
—
You are receiving this because you were assigned.
Reply to this email directly or view it on GitHub
https://github.com/kenwheeler/cash/issues/119#issuecomment-220763280

Yes -- i "solved" it that way, but it's not very intuitive though. :)

Looks like the WAAPI equivalents would be:
var player = element.animate(/* ... */);
console.log(player.playState); //"running"

player.pause(); //"paused"
player.play(); //"running"
player.cancel(); //"idle"... jump to original state
player.finish(); //"finished"...jump to end state

The Animator class is being returned by $.fn.animate, so prototype methods
should be able to allow for that. Play/pause may be tricky for the
requestAnimationFrame fallback, but I've done it before.
On Sat, May 21, 2016 at 6:37 AM Tommie Hansen<EMAIL_ADDRESS>wrote:

Yes -- i "solved" it that way, but it's not very intuitive though. :)
—
You are receiving this because you were assigned.
Reply to this email directly or view it on GitHub
https://github.com/kenwheeler/cash/issues/119#issuecomment-220773070

Yeah, i read something about that too.
And actually -- if you want to go the WAAPI way i read ... somewhere that it actually uses the syntax that i nearly proposed before;
var myFrames = [
  [elem1, {  props }, { opts }],
  [elem2, {  props }, { opts }],
  [elem3, {  props }, { opts }],
];

It would seem they've been inspired by Velocity JS or any other that uses the same syntax for sequences.

Trying to create a func for sequencing, but i'm failing, the complete action isn't ran but instead all animations run at the same time.
function stuff(sequence, curNum){

	curNum = curNum || 0;

	for(var key in sequence){

		var cur = sequence[curNum],
				curSel = cur.e,
				curFrame = cur.frame,
				curOpts = cur.opts;

		if(curNum < sequence.length+1){
			var	hasNext = true
			curNum++;
		}
		else { var hasNext = false; }

		if(hasNext) {
			curOpts.complete = function(){ stuff(sequence, curNum); };
		}

		curSel.animate( curFrame, curOpts )

	}

}

var card = $('.card'),
		introElems = $('.popPhoto, .buddy, .head, .sub, .stats');

var sequence = [
	{ e: card, frame: { y: 0, opacity: 1 }, opts: { duration: 1000, easing: 'ease-out' } },
	{ e: introElems, frame: { y: 0, opacity: 1 }, opts: { duration: 1000, easing: 'ease-out', stagger: 90 }  },
];

setTimeout(function(){
	stuff(sequence);
}, 500)

Tried a little and this actually works, it's slighly ugly and i have no idea if it will works with multiple frames within each 'frame' ...
function stuff(sequence, curNum){

	curNum = curNum || 0;

	for(var key in sequence){

		var cur = sequence[curNum],
				curSel = cur.e,
				curFrame = cur.frame,
				curOpts = cur.opts;

		if(curNum < sequence.length+1){
			curOpts.complete = function(){ stuff(sequence, curNum++); };
		}

		curSel.animate( curFrame, curOpts )

	}

}

var card = $('.card'),
		introElems = $('.popPhoto, .buddy, .head, .sub, .stats');

var sequence = [
	{ e: card, frame: { y: 0, opacity: 1 }, opts: { duration: 1000, easing: 'ease-out' } },
	{ e: introElems, frame: { y: 0, opacity: 1 }, opts: { duration: 1000, easing: 'ease-out', stagger: 90 }  },
];

stuff(sequence);

Demo of the func in action and with using lots of sequencing:
http://codepen.io/tommiehansen/full/bpXNPr/
Hit the 'Play all' -button to play all.

Looks like you may be describing the KeyframeEffect class that the Animation class uses, the base of Element.animate.
Good demos. It's not crazy the have sequencing, but the syntax need some work in terms of how it would work in Cash.

Yes.
And yeah, it probably do. See it more as an annoying sample that just shows that it is possible with very little code but still something that cuts down on the codebloat.
Another thing is btw tracking state changes since it quite quickly becomes problematic to reset any changes that has been made. In the demo i needed to check my css to see what my initial states were and reset these with static values which is something that just won't work. Or have i missed something?

Ah, yes. I'd forgotten about Snabbt. 5kb (gzipped) is still over double the target & current weight of this, and we already have a good portion of snabbt's functionality (and a lot of other functionality snabbt doesn't have), so I think we're in a good spot :-)
Regarding state changes, a cancel and finish method like in the WAAPI would allow you to reset to the original state or jump to the final state. Once those methods are implemented, if you save a reference to the first animation (assuming you do multiple animations), you should be able to call cancel to reset to that initial state even though the animation is finished ( var anim = $(el).animate(...); ... anim.cancel() ). Is that what you're referring to?

Yes, it's currently better except for the debugging stuff. :-)
For now i also think it's better to have the WAAPI-syntax (in the cases where it makes sense -- it's hardly perfect) but leave the WAAPI-specific functions out since we're still probably at least a year from WAAPI being a real option on what i would call "real sites". The browsers that has implemented it also have done so in their own specific flavour so even if function A and B works in browser C and D it isn't certain that they work the same.

I haven't forgotten about this, just been slammed at work so haven't been able to dive any deeper into it.
Thanks for the big list, @tommiehansen. I didn't recall reading it before so I'm going over it now.
Regarding 1, Sequencing/Timeline control could be accomplished in this manner, similar to what you'd written before:
$.animate([
  ['#myElement', {  props }, { opts }],
  ['.element2', {  props }, { opts }],
  [document.getElementById('element3'), {  props }, { opts }],
], { animationOpts });

animationOpts would contain callbacks for the full animation. This could be used as default options for the keyframes, for example to set the easing for all keyframes unless overwritten by that keyframe's options.
Number 2 and number 5 are already solved by the current code, though sequencing may provide more opportunities to improve this.
Number 4 'end states' could be done with the supporting fill property. Right now, it's handled the equivalent to fill: both, so that if the animation is reversed, the animation keeps the values of the start state. Are you describing something different than that?
The only time getComputedStyle is called is when the animation starts, so that the animation can be calculated. I don't see a way around that. Same with number 3, the lib will be built to not cause unnecessary paint/reflows, but if you're animating height or other non-'safe' properties you're going to get thrashing.

Stumbled across this today: https://github.com/juliangarnier/anime
Not quite the syntax that we've been discussing and it looks like chaining/keyframing isn't really built-in, but it does have a solid feature set and weighs only 10kb minified.

@shshaw Sorry for the late replies, as you i'm often quite occupied with other things. :)
I've stumbled upon anime.js as well and while it may be good it, just as you say, lacks chaining and keyframing hence it is basically as useful as using raw CSS3-animations (greatly simplified of course) when it comes to the "create a simple animation in a short amount of time". For creating advanced animations one would probably just go with Velocity.js or TweenLite/Max from Greensock.
There's probably a lot one could borrow from anime.js though. :)

I think we shouldn't add support for this if the API would be completely different from jQuery's implementation, in that case just include that other thing into your bundle along with cash.
I'm ok with including support for animation as a plugin, basically included in the repo but disabled by default in our bundles, that's basically a subset of what jQuery implements.

@fabiospampinato is there any update on having animations as a plugin ?

@varunsridharan No.

@fabiospampinato ok cool.
Well i was looking to migrate my WordPress Framework away from jquery and found Cash as a best alternative.
Thanks for making a wonderful library. :-)
and i was creating a custom lib using your code and was able to add a very basic animation system and here the code.
and the code was taken from TinyAnimate with some customization

/**
 * TinyAnimate.easings
 * Adapted from jQuery Easing
 */
const M                  = Math;
const easings            = {};
easings.linear           = ( t, b, c, d ) => c * t / d + b;
easings.easeInQuad       = ( t, b, c, d ) => c * ( t /= d ) * t + b;
easings.easeOutQuad      = ( t, b, c, d ) => -c * ( t /= d ) * ( t - 2 ) + b;
easings.easeInOutQuad    = ( t, b, c, d ) => ( ( t /= d / 2 ) < 1 ) ? c / 2 * t * t + b : -c / 2 * ( ( --t ) * ( t - 2 ) - 1 ) + b;
easings.easeInCubic      = ( t, b, c, d ) => c * ( t /= d ) * t * t + b;
easings.easeOutCubic     = ( t, b, c, d ) => c * ( ( t = t / d - 1 ) * t * t + 1 ) + b;
easings.easeInOutCubic   = ( t, b, c, d ) => ( ( t /= d / 2 ) < 1 ) ? c / 2 * t * t * t + b : c / 2 * ( ( t -= 2 ) * t * t + 2 ) + b;
easings.easeInQuart      = ( t, b, c, d ) => c * ( t /= d ) * t * t * t + b;
easings.easeOutQuart     = ( t, b, c, d ) => -c * ( ( t = t / d - 1 ) * t * t * t - 1 ) + b;
easings.easeInOutQuart   = ( t, b, c, d ) => ( ( t /= d / 2 ) < 1 ) ? c / 2 * t * t * t * t + b : -c / 2 * ( ( t -= 2 ) * t * t * t - 2 ) + b;
easings.easeInQuint      = ( t, b, c, d ) => c * ( t /= d ) * t * t * t * t + b;
easings.easeOutQuint     = ( t, b, c, d ) => c * ( ( t = t / d - 1 ) * t * t * t * t + 1 ) + b;
easings.easeInOutQuint   = ( t, b, c, d ) => ( ( t /= d / 2 ) < 1 ) ? c / 2 * t * t * t * t * t + b : c / 2 * ( ( t -= 2 ) * t * t * t * t + 2 ) + b;
easings.easeInSine       = ( t, b, c, d ) => -c * M.cos( t / d * ( M.PI / 2 ) ) + c + b;
easings.easeOutSine      = ( t, b, c, d ) => c * M.sin( t / d * ( M.PI / 2 ) ) + b;
easings.easeInOutSine    = ( t, b, c, d ) => -c / 2 * ( M.cos( M.PI * t / d ) - 1 ) + b;
easings.easeInExpo       = ( t, b, c, d ) => ( t == 0 ) ? b : c * M.pow( 2, 10 * ( t / d - 1 ) ) + b;
easings.easeOutExpo      = ( t, b, c, d ) => ( t == d ) ? b + c : c * ( -M.pow( 2, -10 * t / d ) + 1 ) + b;
easings.easeInOutExpo    = ( t, b, c, d ) => {
	if( t == 0 ) {
		return b;
	}
	if( t == d ) {
		return b + c;
	}
	return ( ( t /= d / 2 ) < 1 ) ? c / 2 * M.pow( 2, 10 * ( t - 1 ) ) + b : c / 2 * ( -M.pow( 2, -10 * --t ) + 2 ) + b;
};
easings.easeInCirc       = ( t, b, c, d ) => -c * ( M.sqrt( 1 - ( t /= d ) * t ) - 1 ) + b;
easings.easeOutCirc      = ( t, b, c, d ) => c * M.sqrt( 1 - ( t = t / d - 1 ) * t ) + b;
easings.easeInOutCirc    = ( t, b, c, d ) => ( ( t /= d / 2 ) < 1 ) ? -c / 2 * ( M.sqrt( 1 - t * t ) - 1 ) + b : c / 2 * ( M.sqrt( 1 - ( t -= 2 ) * t ) + 1 ) + b;
easings.easeInElastic    = ( t, b, c, d ) => {
	var p = 0;
	var a = c;
	if( t == 0 ) {
		return b;
	}
	if( ( t /= d ) == 1 ) {
		return b + c;
	}
	if( !p ) p = d * .3;
	if( a < M.abs( c ) ) {
		a     = c;
		var s = p / 4;
	} else {
		var s = p / ( 2 * M.PI ) * M.asin( c / a );
	}
	return -( a * M.pow( 2, 10 * ( t -= 1 ) ) * M.sin( ( t * d - s ) * ( 2 * M.PI ) / p ) ) + b;
};
easings.easeOutElastic   = ( t, b, c, d ) => {
	var p = 0;
	var a = c;
	if( t == 0 ) {
		return b;
	}
	if( ( t /= d ) == 1 ) {
		return b + c;
	}
	if( !p ) p = d * .3;
	if( a < M.abs( c ) ) {
		a     = c;
		var s = p / 4;
	} else {
		var s = p / ( 2 * M.PI ) * M.asin( c / a );
	}
	return a * M.pow( 2, -10 * t ) * M.sin( ( t * d - s ) * ( 2 * M.PI ) / p ) + c + b;
};
easings.easeInOutElastic = ( t, b, c, d ) => {
	var p = 0;
	var a = c;
	if( t == 0 ) {
		return b;
	}
	if( ( t /= d / 2 ) == 2 ) {
		return b + c;
	}
	if( !p ) p = d * ( .3 * 1.5 );
	if( a < M.abs( c ) ) {
		a     = c;
		var s = p / 4;
	} else {
		var s = p / ( 2 * M.PI ) * M.asin( c / a );
	}
	if( t < 1 ) {
		return -.5 * ( a * M.pow( 2, 10 * ( t -= 1 ) ) * M.sin( ( t * d - s ) * ( 2 * M.PI ) / p ) ) + b;
	}
	return a * M.pow( 2, -10 * ( t -= 1 ) ) * M.sin( ( t * d - s ) * ( 2 * M.PI ) / p ) * .5 + c + b;
};
easings.easeInBack       = ( t, b, c, d, s ) => {
	if( isUndefined( s ) ) {
		s = 1.70158;
	}
	return c * ( t /= d ) * t * ( ( s + 1 ) * t - s ) + b;
};
easings.easeOutBack      = ( t, b, c, d, s ) => {
	if( isUndefined( s ) ) {
		s = 1.70158;
	}
	return c * ( ( t = t / d - 1 ) * t * ( ( s + 1 ) * t + s ) + 1 ) + b;
};
easings.easeInOutBack    = ( t, b, c, d, s ) => {
	if( isUndefined( s ) ) {
		s = 1.70158;
	}
	return ( ( t /= d / 2 ) < 1 ) ? c / 2 * ( t * t * ( ( ( s *= ( 1.525 ) ) + 1 ) * t - s ) ) + b : c / 2 * ( ( t -= 2 ) * t * ( ( ( s *= ( 1.525 ) ) + 1 ) * t + s ) + 2 ) + b;
};
easings.easeInBounce     = ( t, b, c, d ) => {
	return c - easings.easeOutBounce( d - t, 0, c, d ) + b;
};
easings.easeOutBounce    = ( t, b, c, d ) => {
	if( ( t /= d ) < ( 1 / 2.75 ) ) {
		return c * ( 7.5625 * t * t ) + b;
	} else if( t < ( 2 / 2.75 ) ) {
		return c * ( 7.5625 * ( t -= ( 1.5 / 2.75 ) ) * t + .75 ) + b;
	} else if( t < ( 2.5 / 2.75 ) ) {
		return c * ( 7.5625 * ( t -= ( 2.25 / 2.75 ) ) * t + .9375 ) + b;
	} else {
		return c * ( 7.5625 * ( t -= ( 2.625 / 2.75 ) ) * t + .984375 ) + b;
	}
};
easings.easeInOutBounce  = ( t, b, c, d ) => ( t < d / 2 ) ? easings.easeInBounce( t * 2, 0, c, d ) * .5 + b : easings.easeOutBounce( t * 2 - d, 0, c, d ) * .5 + c * .5 + b;

const animation      = function( from, to, duration, update, easing, done ) {
	if( !isNumber( from ) || !isNumber( to ) || !isNumber( duration ) || !isFunction( update ) ) {
		return 'OOO';
	}

	if( isString( easing ) && easings[ easing ] ) {
		easing = easings[ easing ];
	}

	if( !isFunction( easing ) ) {
		easing = window[ easing ] || null;
	}

	if( !isFunction( easing ) ) {
		easing = easings.linear;
	}

	if( !isFunction( done ) ) {
		done = function() {
		};
	}

	let canceled = false,
		change   = to - from,
		rAF      = v.win.requestAnimationFrame || ( ( callback ) => v.win.setTimeout( callback, 1000 / 60 ) ),
		loop     = function( timestamp ) {
			if( canceled ) {
				return;
			}
			var time = ( timestamp || +new Date() ) - start;
			if( time >= 0 ) {
				update( easing( time, from, change, duration ) );
			}
			if( time >= 0 && time >= duration ) {
				update( to );
				done();
			} else {
				rAF( loop );
			}
		};

	update( from );
	var start = v.win.performance && v.win.performance.now ? v.win.performance.now() : +new Date();
	rAF( loop );

	return { cancel: () => canceled = true, };
};
animation.animateCSS = function( element, property, from, to, duration, easing, done ) {
	let existing  = regex.cssProperty.exec( core( element ).css( property ) ),
		animateTo = regex.cssProperty.exec( to ),
		toNumber  = ( isUndefined( animateTo[ 1 ] ) ) ? to : animateTo[ 1 ],
		toUnit    = ( isUndefined( animateTo[ 2 ] ) ) ? existing[ 2 ] : animateTo[ 2 ];
	from          = ( isNull( from ) ) ? existing[ 1 ] : from;

	let update = function( value ) {
		return element.style[ property ] = value + toUnit;
	};

	from     = parseFloat( from ) || 0;
	toNumber = parseFloat( toNumber ) || 0;
	duration = parseInt( duration ) || 0;

	return animation( from, toNumber, duration, update, easing, done );
};
animation.cancel     = function( instance ) {
	if( !instance ) {
		return;
	}
	instance.cancel();
};

fn.animation = function( property, to, duration, easing, callback ) {
	return this.each( ( i, elem ) => {
		animation.animateCSS( elem, property, null, to, duration, easing, callback );
	} );
};

Closing as an official animation plugin won't be written, use one of the suggested ones. If anybody knows of any plugin that's compatible with Cash and implements the same API as jQuery well I'll link to it in the readme.


Cannot load login page because of rewrite rules

Describe the bug
I've installed BookStack like described in manual part of this guide: https://www.bookstackapp.com/docs/admin/installation/#manual
So problem: I cannot see login page after installation. It tries redirect me to: http://domain.com/login but instead of login page i've got "Your browser sent a request that this server could not understand".
After several hours of debugging i found the problem in this line: "RewriteRule ^ index.php [L]".
When this line is commented i can see some kind of page, but it's corrupted because i have index.php in all url's which points to images, styles and other.

When this line is uncomented(active) then i always got this message "Your browser sent a request that this server could not understand. Tested on Chrome and Firefox.
So at least i know problem in rewrite rules, but i don't know why they come and how to fix them. Also as you can see i have lower version of php, but i think it is not related to current problem.
Your Configuration (please complete the following information):

Exact BookStack Version (Found in settings): from version file v0.25.5
PHP Version: PHP 7.0.33-0ubuntu<IP_ADDRESS> (cli) ( NTS )
Hosting Method: Apache

Hi @altucor,
To be able to help we're going to need a bit more information on your setup.

Where have you placed the rewrite rules? In the virtual host config or have you modified a .htaccess file?
Are you able to supply your apache virtual host configuration?
What is your operating system?
Do you have apache mod_rewrite enabled?

First of all thanks for your help.
Place: I tried both ways, default htaccess and virtual host. Also tried to use other rewrite rules, now all is rolled back to original state.
OS: Ubuntu 16.04.6 LTS (GNU/Linux 4.10.0-42-generic x86_64)
Rewrite module:
sudo a2enmod rewrite
Module rewrite already enabled
`<VirtualHost *:80>
ServerAdmin webmaster@localhost
ServerName domain.com
ServerAlias domain.com
DocumentRoot /var/www/domain.com/public/
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
# Also tried run with this commented block
#<Directory "/var/www/domain.com/public/">
#    AllowOverride All
#</Directory>

Options +FollowSymLinks
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
#RewriteRule ^ index.php [L]
#RewriteRule (.+) index.php?p=$1 [QSA,L] # also tried this line instead of line above

`

@altucor Thanks for the info. It might be a small while before I have a chance to explore this.
Alternatively, Below is the virtualhost configuration from our install script, may provide some hints for you. Is for Ubuntu 18.04 but I don't think apache changed that much since 16.04.
https://github.com/BookStackApp/devops/blob/82b0818eaa4f1b1f79927c3481a145d11ddcb114/scripts/installation-ubuntu-18.04.sh#L75-L111

Ok, thanks, i will try it.

Looks like it works, i just placed config which you shows above. Thank you, solved.


Implementation of Configuration Manager

Unit Stack Configuration Editing Requirements
There is not currently a way to add or end stack/pipe relationships.

Need the ability to add stack/pipe with an active date.
Need the ability to modify stack/pipe active/retire date.
Need the ability to connect units to a stack/pipe with an begin (effective) date.
Need the ability to modify a unit to stack/pipe connection's begin and end dates.
Need the ability to modify a unit to stack/pipe connection's end date, changing a null to an actual date.

After the changes above have been made, display the following and allow the user to accept or reject the changes.

List of locations for the monitoring plan.
Begin and end quarter of the monitoring plan.
Reporting frequency of the monitoring plan.
Begin and end quarter of the reporting frequency.
Indication of whether there are submitted emissions that are no longer covered by the changed configuration.
A single monitoring plan can have multiple reporting frequencies over different quarter periods.

Note: Right now in 2.0, users are unable to delete records and would need to revert to official and start over.
Interface:

The manager should be placed on its own screen, accessed via a button on the sidebar (beneath Monitoring Plans).

This button will not be shown in the public view, i.e. the manager will only be available to logged-in users.

There should be a section for adding/editing stack/pipes and a separate section for adding/editing unit stack configurations.

Other considerations:

Do not require the evaluation and submission of monitoring plans whose begin and end quarters were not affected by the configuration changes. This would include the reporting frequency quarters. Confirm with CAMD that it is okay to require evaluations and submittals for inactive configurations where begin and end quarters were changed.
What to do with configuration changes that involve already submitted emissions data?

Also Read the Following Comments

Configuration Management Principles

Models for Adding to Working Table
Merge Working Table Rows
Updating Reporting Frequencies

Suggested Plants for Testing
Affected and Needed Tables

Need screenshots from 1.0. What are the mechanics for doing the changes. Scott and Dwayne will meet to discuss further.

Configuration Management Principles

Units (affected by a program) should belong in an MP for each quarter from the quarter of its earliest Monitor Method, through the quarter of its retirement based on UNIT_OP_STATUS (if it has retired).
A unit that has never been associated with a stack or pipe in the UNIT_STACK_CONFIGURATION table will only exist in one MP as the sole location.  The begin quarter of the MP will be the quarter of the earliest Monitor Method, and the end quarter will be the quarter of the unit retirement if it has retried, otherwise it will be null.
A unit that has been associated with stacks or pipes will have one or more MP.  These MP will contain at least one unit and one stack or pipe, but at least three locations (see Note 1 below).  A MP's locations are connected to each other through a web of UNIT_STACK_CONFIGURATION rows with an intersection of Begin and End Dates in quarters that match the MP Begin and End Quarters.

Notes:

MP contain at least three locations because information is reported at a unit when it only has one stack that is not connected to other units, and has zero pipes or one pipe that is not connected to other units.  Under these conditions, the source does not include the stack or pipe as separate locations, and reports their data at the unit.

Suggested Plants for Testing

ORIS Code
Facility Name
Facility Id
Notes

3
Barry
1
Variety of MP

641
Gulf Clean Energy Center
126
Complex Changes

708
Hammond
149
Complex Changes

994
IPL - Petersburg Generating Station
191
Complex Changes

1356
Ghent
272
Problematic in ECMPS 1.0

1893
Boswell Energy Center
372
Common Stack Created and Disbanded

2866
W H Sammis
554
Many Changes

2876
Kyger Creek
558
Split Common Stacks

2878
Bay Shore
560
Retire Common Stack and Split Unit

3407
Kingston
650
Complex with CS Combine

10307
Bellingham
1092
Common Pipe

52130
BP Whiting Business Unit
7699
Common Pipe (Inactive)

55284
Big Sandy Peaker Plant
1398
Commom Pipe Change

Models for Adding to Working Table
Note that the queries should run in the following order and for a specific plant (facility) to update the Working Table.
Common Stacks and Pipes
select  fac.Oris_Code,
        fac.Facility_Name,
        extract( year from usc.Begin_Date ) as Begin_Year,
        extract( quarter from usc.Begin_Date ) as Begin_Quarter,
        extract( year from usc.End_Date ) as End_Year,
        extract( quarter from usc.End_Date ) as End_Quarter,
        ( stp.Stack_Name || ', ' || string_agg( unt.Unitid, ', ' order by unt.Unitid ) ) as Location_List
  from  camd.PLANT fac
        join camd.UNIT unt
          on unt.Fac_Id = fac.Fac_Id
        join camdecmpswks.UNIT_STACK_CONFIGURATION usc
          on usc.Unit_Id = unt.Unit_Id
        join camdecmpswks.STACK_PIPE stp
          on stp.Stack_Pipe_Id = usc.Stack_Pipe_Id
         and stp.Stack_Name like 'C%'
 where  fac.Oris_Code in ( 3, 641, 708, 994, 1356, 1893, 2866, 2876, 2878, 3407, 10307, 52130, 55284 )
 group
    by  fac.Oris_Code,
        fac.Facility_Name,
        extract( year from usc.Begin_Date ),
        extract( quarter from usc.Begin_Date ),
        extract( year from usc.End_Date ),
        extract( quarter from usc.End_Date ),
        stp.Stack_Name
 order
    by  Oris_Code,
        Stack_Name,
        Begin_Year,
        Begin_Quarter,
        End_Year,
        End_Quarter;

Multiple Stacks (and Pipes)
select  fac.Oris_Code,
        fac.Facility_Name,
        extract( year from usc.Begin_Date ) as Begin_Year,
        extract( quarter from usc.Begin_Date ) as Begin_Quarter,
        extract( year from usc.End_Date ) as End_Year,
        extract( quarter from usc.End_Date ) as End_Quarter,
        ( string_agg( stp.Stack_Name, ', ' order by stp.Stack_Name ) || unt.Unitid || ', ' ) as Location_List
  from  camd.PLANT fac
        join camd.UNIT unt
          on unt.Fac_Id = fac.Fac_Id
        join camdecmpswks.UNIT_STACK_CONFIGURATION usc
          on usc.Unit_Id = unt.Unit_Id
        join camdecmpswks.STACK_PIPE stp
          on stp.Stack_Pipe_Id = usc.Stack_Pipe_Id
         and stp.Stack_Name like 'M%'
 where  fac.Oris_Code in ( 3, 641, 708, 994, 1356, 1893, 2866, 2876, 2878, 3407, 10307, 52130, 55284 )
 group
    by  fac.Oris_Code,
        fac.Facility_Name,
        extract( year from usc.Begin_Date ),
        extract( quarter from usc.Begin_Date ),
        extract( year from usc.End_Date ),
        extract( quarter from usc.End_Date ),
        unt.Unitid
 order
    by  Oris_Code,
        Unitid,
        Begin_Year,
        Begin_Quarter,
        End_Year,
        End_Quarter;

Units Alone
select  lst.Oris_Code,
        lst.Facility_Name,
        extract( year from lst.Begin_Date ) as Begin_Year,
        extract( quarter from lst.Begin_Date ) as Begin_Quarter,
        extract( year from lst.End_Date ) as End_Year,
        extract( quarter from lst.End_Date ) as End_Quarter,
        lst.Location_List
  from  (
            select  fac.Oris_Code,
                    fac.Facility_Name,
                    (
                        select  max( mth.Begin_Date)
                          from  camdecmpswks.MONITOR_LOCATION loc
                                join camdecmps.MONITOR_METHOD mth
                                  on mth.Mon_Loc_Id = loc.Mon_Loc_Id
                         where  loc.Unit_Id = unt.Unit_Id
                    ) as Begin_Date,
                    (
                        select  min( uos.Begin_Date)
                          from  camd.UNIT_OP_STATUS uos
                         where  uos.Unit_Id = unt.Unit_Id
                           and  uos.Op_Status_Cd = 'RET'
                    ) as End_Date,
                    unt.Unitid as Location_List
              from  camd.PLANT fac
                    join camd.UNIT unt
                      on unt.Fac_Id = fac.Fac_Id
             where  fac.Oris_Code in ( 3, 641, 708, 994, 1356, 1893, 2866, 2876, 2878, 3407, 10307, 52130, 55284 )
        ) lst
 order
    by  Oris_Code,
        Location_List,
        Begin_Year,
        Begin_Quarter,
        End_Year,
        End_Quarter;

Merge Working Table Rows
Main Logic:
/* pseudocode is 1 based, not 0 based. */

currentCursor := workingTable ordered by IdentifierKey
currentRecord := currentCursor.Fetch

while ( currentRecord.Exists )

    compareCursor := workingTable where ( IdentifierKey > currentRecord.IdentifierKey ) ordered by IdentifierKey
    compareRecord := compareCursor.Fetch

    mergeOccurred := false

    while ( compareRecord.Exists ) and ( not mergeOccurred )

        if ( currentRecord.Locations ∩ compareRecord.Locations ≠ Ø ) and ( currentRecord.Period ∩ compareRecord.Period ≠ Ø )

            { Add workingTable rows based on merge logic, which will replace the currentRecord and compareRecord rows with the next IdentifierKeys  }

            workingTable.Delete( compareRecord.IdentifierKey )
            workingTable.Delete( currentRecord.IdentifierKey )

            mergeOccurred := true

        else
            /* Get the next compare row if a merge did not occur. */
            compareRecord := compareCursor.Fetch
        end if

    end while

    if ( not mergeOccurred )
        /* Current was not merged so move to the next row as the current row. */
        currentRecord := currentCursor.Fetch
    else
        /* Recreate the currentCursor to account for deletions and inserts, and start with the first entry */
        currentCursor := workingTable ordered by IdentifierKey
        currentRecord := currentCursor.Fetch
    end if

end while

Updating Reporting Frequencies
Existing "Ending" MP

Note: the End Quarter for the MP must be null before setting an actual End Quarter value.
Delete any Reporting Frequency rows for the MP with a Begin Quarter after the new MP End Quarter.
Set the End Quarter of the latest remaining Reporting Frequency for the MP to the MP End Quarter.

New MP Reporting Frequency Rules

Whether an MP has an annual or OS reporting frequency depends on whether and when annual and OS season programs are active for units in the MP.
The active range from the programs depends on the quarters of the Unit Program Unit Monitor Cert Begin (UMCB) Date and End Date for units in the MP.
When an annual program is active for the quarter span of the MP, create an annual MP Reporting Frequency with the same begin and end quarters as the MP.
When an annual program is not active during the quarter span of the MP, but an OS program is active for the lifespan of the MP, create an OS MP Reporting Frequency with the same begin and end quarters as the MP.

Note: The following logic distinctly differs from ECMPS 1.0.

MP Begin
MP End
U1 UMCB
U1 End
U1 OS Ind
U2 UMCB
U2 End
U2 OS Ind
Freq 1
Freq 2
Freq 3
Notes

2022 Q1

1/1/2022

0
2022-01-01

0
Q: 2022 Q1->

2022 Q1

3/31/2022

0
2022-03-31

0
Q: 2022 Q1->

2022 Q1

1/1/2022

0
2022-04-01

0
Q: 2022 Q1->

2022 Q1

4/1/2022

0
2022-04-01

0
Q: 2022 Q1->

1

2022 Q1

1/1/2022

1
2022-01-01

1
OS: 2022 Q1->

2022 Q1

3/31/2022

1
2022-03-31

1
OS: 2022 Q1->

2022 Q1

1/1/2022

1
2022-05-01

1
OS: 2022 Q1->

2022 Q1

4/1/2022

1
2022-05-01

1
Q: 2022 Q1 - 2022 Q1
OS: 2022 Q2 ->

1

2022 Q2

5/1/2022

1
2022-07-01

1
Q: 2022 Q1 - 2022 Q1
OS: 2022 Q2 ->

2022 Q2

5/1/2022

1
2022-07-01

0
Q: 2022 Q1 - 2022 Q1
OS: 2022 Q2 - 2022 Q2
Q: 2022 Q3 ->

2022 Q2

5/1/2022

0
2022-07-01

1
Q: 2022 Q1 ->

1

2022 Q2

5/1/2022

1
2022-07-01

0
Q: 2022 Q1 - 2022 Q1
OS: 2022 Q2 - 2022 Q3
Q: 2022 Q4 ->

2022 Q1

1/1/2022

1
2022-09-15
2024-05-16
0
OS: 2022 Q1 - 2022 Q2	Q: 2022 Q3 - 2024 Q2
OS: 2024 Q3 ->

2022 Q1

1/1/2022

0
2022-09-15
2024-05-16
1
Q: 2022 Q1 ->

Suggested Plants for Testing

ORIS Code
Facility Name
Facility Id
Notes

3
Barry
1
Variety of MP

641
Gulf Clean Energy Center
126
Complex Changes

708
Hammond
149
Complex Changes

994
IPL - Petersburg Generating Station
191
Complex Changes

1356
Ghent
272
Problematic in ECMPS 1.0

1893
Boswell Energy Center
372
Common Stack Created and Disbanded

2866
W H Sammis
554
Many Changes

2876
Kyger Creek
558
Split Common Stacks

2878
Bay Shore
560
Retire Common Stack and Split Unit

3407
Kingston
650
Complex with CS Combine

6090
Sherburne County
814
Retired Unit

6264
Mountaineer (1301)
860
Annual and OS Only Units

10307
Bellingham
1092
Common Pipe

52130
BP Whiting Business Unit
7699
Common Pipe (Inactive)

55284
Big Sandy Peaker Plant
1398
Commom Pipe Change

Affected and Needed Tables
Affected
The tables exist in both the CAMDECMPS (Official) and CAMDECMPSWKS (Workspace).  The changes occur in the Workspace versions and are submitted to the Official versions.

MONITOR_LOCATION
MONITOR_PLAN
MONITOR_PLAN_LOCATION
STACK_PIPE
UNIT (In CAMD schema and not actually changed)
UNIT_STACK_CONFIGURATION

Needed to determine quarter range for which unit should belong to an MP

MONITOR_METHOD

Used to determine the earliest quarter that a unit should belong to any MP.
Earliest Begin Quarter is based on the quarter of the earliest MONITOR_METHOD BEGIN_DATE.
Exists in both the CAMDECMPS and CAMDECMPSWKS schemas, but should use the CAMDECMPSWKS version.

UNIT_OP_STATUS (CAMD)

Used to determine the latest quarter that a unit should belong to any MP.
Latest Begin Quarter is based is the quarter of the latest day before the UNIT_OP_STATUS BEGIN_DATE where OP_STATUS_CD equals 'RET'.

Needed to determine the latest emission submitted quarter for a unit and stack/pipe

MONITOR_LOCATION (CAMDECMPS): Matched on UNIT_ID or STACK_PIPE_ID
MONITOR_PLAN_LOCATION (CAMDECMPS): Matched on MON_LOC_ID
EMISSION_EVALUATION (CAMDECMPS): Matched on MON_PLAN_ID
REPORTING_PERIOD (CAMDECMPSMD): Matched on RPT_PERIOD_ID and used to determine the latest quarter.

Receiving a forbidden resource error in the Change Summary window when attempting to add an MP for a unit that never submitted an MP (occurs after selecting the "+" icon and Save button).
Issues when ending an existing stack/pipe and USC records:

For annual reporters, the Change Summary window shows Reporting Frequency as Ozone Season for the new and ended plans (MONITOR_PLAN_REPORTING_FREQ is correct though).
Userid and update_date columns in CAMDECMPSWKS.STACK_PIPE not updated when ending a stack/pipe.
Userid and update_date columns in CAMDECMPSWKS.MONITOR_PLAN_REPORTING_FREQ not updated for ended mon_plan_id when ending a stack/pipe.
Ending a stack/pipe configuration will set this MP to Inactive, needs evaluation and submission, but there is no way to select this configuration for evaluation/submission.
Revert to Official issues:

When all changes are completed in the UI, forbidden resource errors are returned for the active and inactive MP's. The new MP is removed from the database on revert though. The forbidden resource issue on the inactive MP appears to leave some changes still active in the MONITOR_PLAN, STACK_PIPE, and MONITOR_PLAN_REPORTING_FREQ tables. I also end up with an active row in the USER_CHECK_OUT table.
When the changes are completed via import from json file, I can revert the inactive MP, but this results in null Configuration rows when viewing the Select Configurations screen. Opening one of these null rows and selecting the tab results in an odd "Cannot read properties of null (reading '1')" error. The new MP's that were created are also not deleted from the MONITOR_PLAN and MONITOR_PLAN_REPORTING_FREQ tables. Also end up with the USER_CHECK_OUT issue.
The revert to official forbidden resource issue also affects other inactive configurations where no changes have been made (stack/pipe configurations and single unit configurations).

Cannot evaluate new MP's that are created either. The needs_eval_flg always remains Y after performing an evaluation. This blocks submission testing.
Cannot update begin dates for existing stack/pipe and USC records logic on import:

The message doesn't make sense and refers to begin dates cannot be on or before end dates of the last Emission Evaluation. They will always be on or before the end date of the last Emission Evaluation. Change it to, "The Begin Date for one or more Stack/Pipe and/or Unit Stack Configuration records does not match the last official submission record for this monitoring plan. Please contact ECMPS Support if you need to correct the Begin Date for any Stack/Pipe and/or Unit Stack Configuration records."
When changing the begin date for an existing stack/pipe record and importing the file, a successful import message is returned (even though the backend data does not change). The should get the message above instead.

There is logic to not allow the end date of an USC record to be before the last day of the quarter for the latest Emission Evaluation, but not for stack/pipe records. I think it would make sense to add the same logic for stack/pipe records. Would need to update this message to also include "Stack/Pipe".

Issues adding new stack/pipe configurations:

ORIS 544, 11 and 12. Attempted to add new CP and associated USC records effective 10/01/2023. Receive odd "Cannot read properties of null (reading 'id')" error in the Change Summary screen. I was able to add a CP configuration for the example below so not really sure what the difference between the two is other than annual vs. ozone season reporters, but it would be good to know in case further targeted testing is needed.
ORIS 542, 10 and 11. I was able to add a new CP configuration effective 10/01/2023.

When the new stack/pipe and USC records are added, update_date was also set in the STACK_PIPE, UNIT_STACK_CONFIGURATION, and MONITOR_PLAN_REPORTING_FREQ tables. This should be null unless another change occurred after the initial save. For MONITOR_PLAN_REPORTING_FREQ, update_date is also not updated for the ended mon_plan_id's.
Same revert issues as documented above.
Same evaluation issues as documented above.

Able to successfully save new stack/pipe and USC records that have end dates before the begin dates.

Able to attempt to create new monitoring plans for retired units. Ex. ORIS 544, 3, 4A, 4B, 5A, 5B, and 6. All these units retired pre-ECMPS 1.0. A user should not be able to add monitoring plans for retired units, regardless if a monitoring plan was never submitted.
#6339 was temporarily merged to dev and this broke the Configuration Manager. Per @maxdiebold-erg, the same endpoint is used. Updates need to be made to handle this. An odd error referencing "Cannot read properties of undefined (reading 'newPlans')" was also returned when this occurred.
Just documenting this here, ticket #xxxx created for future consideration to update the message returned when attempting to import new stack/pipe and USC records from a json file. ECMPS 1.0 does the same thing but a better message could be returned to help avoid ECMPS Support tickets.

The following 4 Pull Requests have been opened to address the changes noted above:

https://github.com/US-EPA-CAMD/easey-monitor-plan-api/pull/586
https://github.com/US-EPA-CAMD/easey-ecmps-ui/pull/1495
https://github.com/US-EPA-CAMD/easey-db-scripts/pull/58
https://github.com/US-EPA-CAMD/easey-facilities-api/pull/193

Per 10/11/2024 standup, hide the Configuration Management module in all environments except dev and tst. New ticket will be created in Sprint 12 to address the remaining issues after the last round of testing.

The above comment has been addressed in https://github.com/US-EPA-CAMD/easey-ecmps-ui/pull/1496.

Confirmed Configuration Management still showing in dev and test, but not perf. Moving this ticket to Sprint 12 to undo these particular changes once #6425 is completed.

These USC existed before ECMPS 1.0 was fully implemented.

Match any Calculated MP that began before 2009 but ended in or after 2009 with an Actual MP that began before 2009 and ended the same quarter as the Calculated MP.

Although it should not happen, this should produce an error if a match on more than one Actual MP occurs.

Match any Calculated MP that began before 2009 but does not have an end quarter with an Actual MP that began before 2009 and does not have an end quarter.

Although it should not happen, this should produce an error if a match on more than one Actual MP occurs.


Can't call PostgreSQL functions with arguments of type "money"

CREATE FUNCTION test (money)
RETURNS integer AS $$
BEGIN
  RETURN 123;
END;
$$ LANGUAGE plpgsql;

SELECT test(1.0); -- Error, can't find function.
SELECT test(1 + 0.0); -- Error, can't find function.
SELECT test(1.0::money); -- works

It looks like the value passed to postgraphql is translated into "($1 + 0.0)" for the SQL used to call the database function. This converts the value to a "numeric" type which isn't specific enough for the function to be found.
Until this is fixed anyone should be able to work around the problem by using the decimal type for their function arguments instead.
Took a long time to figure out what was going on. 😬

I'm a bit lost here but the money type is not an intrinsic number so it cannot be represented without single quotes in PostgreSQL.  select(1.0::money) constructs a numeric (the default non-integer, not-quoted, type) and then casts it to money.  select('1.0'::money') bypasses the numeric altogether and passing the literal '1.0' to money's input function.  I'm not sure how this system handles something like a date literal but the treatment of money probably shouldn't be any different.

I've got a bit of a hack in v4 for dealing with this kind of thing:
https://github.com/postgraphql/graphql-build/blob/7165585cea78c3f1f8192841de4199fdc3db4f2b/packages/graphql-build-pg/src/plugins/PgTypesPlugin.js#L215-L225
Are you saying that casting a float directly to ::money fixes it, or do we need to handle money more carefully? If we need to change it to a string, for instance, then v4 would be the time to do it because it's already going to be a breaking change.

I'd say its reasonable to map the PostgreSQL money type to the GraphQL string type since mapping it to the GraphQL float type is lossy.
In the original example:  select test('1.0'); executes without complaint; as does select test('$1.0').  No explicit casting needed (absent function overloading).
Hope this helps.

According to the PostgreSQL documentation:

The money type stores a currency amount with a fixed fractional precision; see Table 8-3. [...] Input is accepted in a variety of formats, including integer and floating-point literals, as well as typical currency formatting, such as '$1,000.00'. Output is generally in the latter form but depends on the locale.

I then goes on to say how you can cast floats to money via numeric but that you should not do so due to the potential for rounding errors.
I see we have three options:

integer pennies - involves multiplying by 100 which makes values "weird", also does not work for every currency
float units - could have rounding errors
strings - very awkward to deal with (ref: https://github.com/postgraphql/graphql-build/blob/c04b156ef6b041823c19c4175874a2400cec7d40/packages/graphql-build-pg/src/plugins/PgTypesPlugin.js#L315-L325)

v4 is flexible enough that you can override its typing; so I think we'll go with option 2 and trust that anyone using money in the database is aware of the caveats around treating money as a float, and that if it's a problem for them they can use a plugin that replaces the float implementation with string/int depending on their preference.

I suppose, though, that the real question is meeting the GraphQL spec requirement:
All response formats must support string representations, and that representation must be used here.
http://facebook.github.io/graphql/#sec-String
Now, I don't exactly understand how that works here since it implies that all non-string outputs have a secondary string form (which is accessed how?), but practically speaking a user of the money type is likely OK with having it treated as an alias for numeric in most cases - and in theory could request the string representation for situations where that is not the case.
The fact that money type doesn't actually store the reported currency means that practically speaking it is the same as numeric/decimal expect with a bit more liberal/useful input parsing routine.  Thus option 2 indeed seems like an adequate solution.  But I do believe you need to consider the string aspect too, in order to make all this work bi-directionally.  Pretending that money is a float when talking to PostgreSQL isn't going to work since PostgreSQL doesn't agree with that supposition - it wants to see the input data provided as a string (specifically, a quoted literal) - which is what the original complaint message is pointing out.

I'm assuming that refers to the fact you can specify raw values in the GraphQL query string.
We'll follow the docs on casting to money via numeric.


[Event Hubs Client] Storage Implementation Feedback

Summary
The focus of these changes is to consider feedback provided by an internal review of the blob storage manager.  Many of the larger and more critical items have already been used for adjustments; these tweaks address the majority of the remaining minor feedback items.
Last Upstream Rebase
Thursday, February 4, 2021, 1:45pm (EST)

/check-enforcer overrride

/check-enforcer overrride

/check-enforcer override


SIP-15 Add reqs re. representation mets/structMap/div/div/@LABEL='data'

CSIP107
The package’s representation division <div> element @LABEL attribute value must be the path to the representation level METS document starting with the value “Representations” followed by the main folder name for example “Representations/submission” and “Representations/ingest”.

The samples should be updated accordingly to cover all the changes made in 2.0, but I will make a separate epic to track that work.


Deleted CRA folder and Working on Login Page

This first push was just to delete the CRA folder to avoid future mixups, as we will move forward with Vite. I will be pushing login page stuff very soon and will update on the status of that implementation.

This is an extremely basic login page that was added to the website. You can access it now by clicking on the Avatar Icon on the Navbar. The plan was to add the user state information to the website so that when the user is not logged in, the Avatar icon will show a default icon and clicking on this will bring you to a login page. When the user is logged in, the settings menu will appear and the login menu will not show up on click.
The login page template is from react bootstrap https://mdbootstrap.com/docs/react/extended/login-form/ and is the gradient template. There were some formatting issues that need to be fixed on where the gradient text box shows up, and how the interaction with form fields works. These issues can be added over the team meeting this coming week.

This is important work, thank you for your contribution. It is great that you are streamlining and making it easier for the team to integrate their work. I believe that we will be able to start building as a team and assigning pages within the next week or so. Thanks again Alex.


Check Z sign before calling BigFloatPow in CalculateDeSoToReturn

#1223  👈
main

This stack of pull requests is managed by Graphite. Learn more about stacking.

Join @lazynina and the rest of your teammates on  Graphite


pipenv update broken

Upgraded pipenv to the latest release using pipsi and getting an error on trying to upgrade the packages.

Traceback (most recent call last):
File "/home/user/.local/bin/pipenv", line 11, in
sys.exit(cli())
File "/home/user/.local/venvs/pipenv/lib/python2.7/site-packages/pipenv/vendor/click/core.py", line 722, in call
return self.main(*args, **kwargs)
File "/home/user/.local/venvs/pipenv/lib/python2.7/site-packages/pipenv/vendor/click/core.py", line 697, in main
rv = self.invoke(ctx)
File "/home/user/.local/venvs/pipenv/lib/python2.7/site-packages/pipenv/vendor/click/core.py", line 1066, in invoke
return _process_result(sub_ctx.command.invoke(sub_ctx))
File "/home/user/.local/venvs/pipenv/lib/python2.7/site-packages/pipenv/vendor/click/core.py", line 895, in invoke
return ctx.invoke(self.callback, **ctx.params)
File "/home/user/.local/venvs/pipenv/lib/python2.7/site-packages/pipenv/vendor/click/core.py", line 535, in invoke
return callback(*args, **kwargs)
File "/home/user/.local/venvs/pipenv/local/lib/python2.7/site-packages/pipenv/cli.py", line 2094, in update
do_init(dev=dev, verbose=verbose)
File "/home/user/.local/venvs/pipenv/local/lib/python2.7/site-packages/pipenv/cli.py", line 1139, in do_init
do_lock(system=system)
File "/home/user/.local/venvs/pipenv/local/lib/python2.7/site-packages/pipenv/cli.py", line 941, in do_lock
project=project
File "/home/user/.local/venvs/pipenv/local/lib/python2.7/site-packages/pipenv/utils.py", line 409, in resolve_deps
resolved_tree = resolver.resolve()
File "/home/user/.local/venvs/pipenv/local/lib/python2.7/site-packages/piptools/resolver.py", line 107, in resolve
has_changed, best_matches = self._resolve_one_round()
File "/home/user/.local/venvs/pipenv/local/lib/python2.7/site-packages/piptools/resolver.py", line 195, in _resolve_one_round
for dep in self._iter_dependencies(best_match):
File "/home/user/.local/venvs/pipenv/local/lib/python2.7/site-packages/piptools/resolver.py", line 274, in _iter_dependencies
dependencies = self.repository.get_dependencies(ireq)
File "/home/user/.local/venvs/pipenv/local/lib/python2.7/site-packages/piptools/repositories/pypi.py", line 145, in get_dependencies
self._dependencies_cache[ireq] = reqset._prepare_file(self.finder, ireq)
File "/home/user/.local/venvs/pipenv/lib/python2.7/site-packages/pipenv/patched/pip/req/req_set.py", line 634, in _prepare_file
abstract_dist.prep_for_dist()
File "/home/user/.local/venvs/pipenv/lib/python2.7/site-packages/pipenv/patched/pip/req/req_set.py", line 129, in prep_for_dist
self.req_to_install.run_egg_info()
File "/home/user/.local/venvs/pipenv/lib/python2.7/site-packages/pipenv/patched/pip/req/req_install.py", line 439, in run_egg_info
command_desc='python setup.py egg_info')
File "/home/user/.local/venvs/pipenv/lib/python2.7/site-packages/pipenv/patched/pip/utils/init.py", line 707, in call_subprocess
% (command_desc, proc.returncode, cwd))
pip.exceptions.InstallationError: Command "python setup.py egg_info" failed with error code 1 in /tmp/tmpfOJU0Lbuild/ipython/

After reading the previous closed issues it sounds like a ipython problem rather than pipenv. I will remove ipython from the pipfile and reinstall again.

let me know how it goes!


On the Docker Hub page, configure the link to the github repo hosting the Dockerfile

It feels quite empty on the Docker Hub, e.g. here https://hub.docker.com/r/baremaps/baremaps
compared to, e.g. https://hub.docker.com/r/osgeo/gdal
where one can spot the github page hosting the Dockerfile which has been used to build''n'push the image to the hub:

it's a "nice to have" feature, but an immensely useful one, especially for newcomers imho.

#189 should be fixed before this issue.

@nicolas-heigvd I updated the dockerhub page. Let me know if something else is missing.


Feature: AutoIncrement

I can't seem to find a checkbox for autoincrementation, I do believe this is supported, in all of the formats supported so far.
Would be nice :)

There is one -- just inbetween the "Default" and "NULL" fields. Please post a screenshot if you fail to locate it.

Inbetween those are the Primary Key field. As far as i know primary key doesnt have to be incremental? (I only work in mssql though)

Sounds like a localization issue then? Can you switch to English and post a screenshot?

Here you go - Im using FireFox 43.0.4

@VisualBean, you are apparently using some un-official version of the wwwsqldesigner (judging from the screenshot). The official version looks like this: http://ondras.zarovi.cz/sql/demo/?keyword=default


How to use different URLs for testing?

Of the URLs provided, the only one that seems to work is the media_url_dash. The other two URLs do not work. I'm allowing Internet permission and clear text traffic in my manifest. I would like to know how to use this with say, a radio stream url.
Thanks!

The 3 URLs provided are:

media_url_mp3
media_url_mp4
media_url_dash (this last one must be loaded by ExoPlayer directly to work)

All work fine for me inside the app. What URLs are you trying?

Closing due to inactivity. Please reopen if you are still having issues.


User changes + @highlighting

Mentions being highlighted in JS may be temporary.
User changes to be able to associate Message UUID with Users.

LGTM


How to initiate credential verification by scanning a qrcode

Hi,
In Trinsic, it allows to initiate credential verification by scanning a qrcode.
Is this supported by the framework?
Thanks.

duplicated with #492


Adding HTC tracker support

This is a port of the code I've already added in Godot 4 with some changes due to how things work in Godot 3.
Note that we're currently waiting on a fix in SteamVR to be applied and that I'm having a crash issue I'm still investigating.
Other then that this is pretty much finished. One major change that is required for implementing this correctly is that we now create all positional trackers in Godot at startup, this to reserve the needed controller ids and not have them changing as trackers are turned off/on. This may require some more testing to make sure we're correctly reacting to trackers marked as inactive/not tracking.
Also that has had an impact on the implementation of trackers for hand tracking. This may require more testing.

Small update on this, Valve has a fix in beta that resolves the issue with poses not being retrieved correct once the HTC extension is enabled. There are still some issues with detection but will be working on those soon.

I need to do some testing but now that a new SteamVR is out that has a fix we were waiting for, we should be able to merge this soon.


disable auth tests, remove login helper code

Reviewers
Functional: @tihuan
Readability: @Bento007

Changes

add
remove Helper code associated with auth login/logout
modify Skip auth related testing

#900

After our discussion yesterday, I assume we need to udpate the PRs 😄? Thank you!
The other one: https://github.com/chanzuckerberg/cellxgene/pull/2092


[Material-UI] Using custom server in production mode does not attach MUI production classes

Bug report
Describe the bug
when I was working with Material UI. the development build is working good. but when I was running production build with custom server in next js. It is not rendering the jss class correctly in production mode. It is working correctly when I was doing next build and next start(without custom server).
To Reproduce
Clone Material UI with NextJS example from repo:
https://github.com/mui-org/material-ui/tree/master/examples/nextjs
Create custom server.js
const express = require('express');
const next = require('next');
const dev = process.env.NEXT_ENV.trim() !== 'production';
const app = next({ dev });

app
  .prepare()
  .then(() => {
    const server = express();
    const handle = app.getRequestHandler();

    const port = process.env.PORT || 3000;

    server.get('*', (req, res) => handle(req, res));
    server.listen(port, err => {
      if (err) throw err;
      console.log(`Server is running on port ${port}`);
    });
  })
  .catch(ex => {
    console.error(ex.stack);
    process.exit(1);
  });

Run npm script: set NODE_ENV=production && node server.js
Expected behavior
Next js with custom server should load the correct JSS class name in production mode(set NODE_ENV=production && node server.js ).

@CalvinSundar
Next and Material-UI (Branch Next) is tested and working with JSS and custom server.js with NODE_ENV=production and no build.
To Reproduce:

Clone the Next branch version of the Material-UI Next.js example: Here
Add custom server.js
Start with NODE_ENV=production && node server.js script

Outcome:

JSS rendered correctly

@CalvinSundar Please provide a visual screenshot from DevTools showing incorrect JSS classes so we can understand if there's any issues.
@timneutkens The issue seems closable.

Thanks @Yzrsah


Replace var with const

I replaced var with const in the document below.
https://reactjs.org/docs/hooks-state.html#tip-what-do-square-brackets-mean
Reference: https://github.com/reactjs/reactjs.org/blob/master/CONTRIBUTING.md#use-const-where-possible-otherwise-let-dont-use-var

I think this was written this way because people unfamiliar with array destructuring are probably not familiar with the latest JS syntax

Agreed; it was intended to be written this way. Thank you for contributing though!

I understand. Thank you for your feedback!


When checking for existing PRs, the check should ignore PRs from forks

Hi there, thanks for the action, in my testing it has worked OK until I deployed it to a live repo :) There was an old PR from someone's fork on their master branch targeting our devel branch, and that was counted as the PR that was already open.
PR that merged this action into master : https://github.com/pi-hole/AdminLTE/pull/2070
PR that the action decided was an existing one: https://github.com/pi-hole/AdminLTE/pull/1813
Is it possible to add a check to make sure it is not from a fork? Or maybe a check of the title? Not sure what is best...
Anyway, cheers!
logs:

Action Log here
2022-01-11T08:57:40.5335983Z Found online and idle hosted runner in the current repository's organization account that matches the required labels: 'ubuntu-latest'
2022-01-11T08:57:40.5938491Z Waiting for a Hosted runner in the 'organization' to pick this job...
2022-01-11T08:57:40.9443800Z Job is waiting for a hosted runner to come online.
2022-01-11T08:57:46.4672999Z Job is about to start running on the hosted runner: GitHub Actions 4 (hosted)
2022-01-11T08:57:50.4643384Z Current runner version: '2.285.1'
2022-01-11T08:57:50.4675360Z ##[group]Operating System
2022-01-11T08:57:50.4676466Z Ubuntu
2022-01-11T08:57:50.4677069Z 20.04.3
2022-01-11T08:57:50.4677546Z LTS
2022-01-11T08:57:50.4678120Z ##[endgroup]
2022-01-11T08:57:50.4678732Z ##[group]Virtual Environment
2022-01-11T08:57:50.4679495Z Environment: ubuntu-20.04
2022-01-11T08:57:50.4680100Z Version: 20211219.1
2022-01-11T08:57:50.4681294Z Included Software: https://github.com/actions/virtual-environments/blob/ubuntu20/20211219.1/images/linux/Ubuntu2004-README.md
2022-01-11T08:57:50.4682864Z Image Release: https://github.com/actions/virtual-environments/releases/tag/ubuntu20%2F20211219.1
2022-01-11T08:57:50.4683852Z ##[endgroup]
2022-01-11T08:57:50.4684600Z ##[group]Virtual Environment Provisioner
2022-01-11T08:57:50.4685292Z <IP_ADDRESS>-main-20211214-1
2022-01-11T08:57:50.4685927Z ##[endgroup]
2022-01-11T08:57:50.4688179Z ##[group]GITHUB_TOKEN Permissions
2022-01-11T08:57:50.4689580Z Actions: write
2022-01-11T08:57:50.4690379Z Checks: write
2022-01-11T08:57:50.4691005Z Contents: write
2022-01-11T08:57:50.4691609Z Deployments: write
2022-01-11T08:57:50.4692272Z Discussions: write
2022-01-11T08:57:50.4692845Z Issues: write
2022-01-11T08:57:50.4693470Z Metadata: read
2022-01-11T08:57:50.4694038Z Packages: write
2022-01-11T08:57:50.4694666Z Pages: write
2022-01-11T08:57:50.4695300Z PullRequests: write
2022-01-11T08:57:50.4695996Z RepositoryProjects: write
2022-01-11T08:57:50.4696802Z SecurityEvents: write
2022-01-11T08:57:50.4697415Z Statuses: write
2022-01-11T08:57:50.4698143Z ##[endgroup]
2022-01-11T08:57:50.4701251Z Secret source: Actions
2022-01-11T08:57:50.4702364Z Prepare workflow directory
2022-01-11T08:57:50.5551323Z Prepare all required actions
2022-01-11T08:57:50.5563043Z Getting action download info
2022-01-11T08:57:50.8816748Z Download action repository 'actions/checkout@v2' (SHA:ec3a7ce113134d7a93b817d10a8272cb61118579)
2022-01-11T08:57:52.9668041Z Download action repository<EMAIL_ADDRESS>(SHA:ea58ab6e406fd3ad016a064b31270bbb41127f41)
2022-01-11T08:57:53.2582781Z Download action repository 'actions-ecosystem/action-add-labels@v1' (SHA:18f1af5e3544586314bbe15c0273249c770b2daf)
2022-01-11T08:57:53.7109829Z ##[group]Run actions/checkout@v2
2022-01-11T08:57:53.7110614Z with:
2022-01-11T08:57:53.7112592Z   repository: pi-hole/AdminLTE
2022-01-11T08:57:53.7113947Z   token: ***
2022-01-11T08:57:53.7114515Z   ssh-strict: true
2022-01-11T08:57:53.7115429Z   persist-credentials: true
2022-01-11T08:57:53.7116054Z   clean: true
2022-01-11T08:57:53.7116597Z   fetch-depth: 1
2022-01-11T08:57:53.7117106Z   lfs: false
2022-01-11T08:57:53.7117635Z   submodules: false
2022-01-11T08:57:53.7121603Z ##[endgroup]
2022-01-11T08:57:54.4865715Z Syncing repository: pi-hole/AdminLTE
2022-01-11T08:57:54.4867385Z ##[group]Getting Git version info
2022-01-11T08:57:54.4868456Z Working directory is '/home/runner/work/AdminLTE/AdminLTE'
2022-01-11T08:57:54.4870596Z [command]/usr/bin/git version
2022-01-11T08:57:54.4871234Z git version 2.34.1
2022-01-11T08:57:54.4873582Z ##[endgroup]
2022-01-11T08:57:54.4874525Z Deleting the contents of '/home/runner/work/AdminLTE/AdminLTE'
2022-01-11T08:57:54.4877815Z ##[group]Initializing the repository
2022-01-11T08:57:54.4878661Z [command]/usr/bin/git init /home/runner/work/AdminLTE/AdminLTE
2022-01-11T08:57:54.4879851Z hint: Using 'master' as the name for the initial branch. This default branch name
2022-01-11T08:57:54.4880818Z hint: is subject to change. To configure the initial branch name to use in all
2022-01-11T08:57:54.4881785Z hint: of your new repositories, which will suppress this warning, call:
2022-01-11T08:57:54.4882913Z hint:
2022-01-11T08:57:54.4883808Z hint: 	git config --global init.defaultBranch <name>
2022-01-11T08:57:54.4884482Z hint:
2022-01-11T08:57:54.4885351Z hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
2022-01-11T08:57:54.4886521Z hint: 'development'.  Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead.
2022-01-11T08:57:55.5088538Z There is already a pull request (1813) to devel from master. You can view it here: https://api.github.com/repos/pi-hole/AdminLTE/pulls/1813
2022-01-11T08:57:55.5090635Z
2022-01-11T08:57:55.5133388Z
2022-01-11T08:57:55.5279577Z ##[group]Run actions-ecosystem/action-add-labels@v1
2022-01-11T08:57:55.5280397Z with:
2022-01-11T08:57:55.5280860Z   labels: internal
2022-01-11T08:57:55.5281458Z   repo: pi-hole/AdminLTE
2022-01-11T08:57:55.5282023Z   number: 1813
2022-01-11T08:57:55.5283136Z   github_token: ***
2022-01-11T08:57:55.5283689Z ##[endgroup]
2022-01-11T08:57:56.1359895Z Post job cleanup.
2022-01-11T08:57:56.2996579Z [command]/usr/bin/git version
2022-01-11T08:57:56.3051542Z git version 2.34.1
2022-01-11T08:57:56.3092617Z [command]/usr/bin/git config --local --name-only --get-regexp core\.sshCommand
2022-01-11T08:57:56.3137955Z [command]/usr/bin/git submodule foreach --recursive git config --local --name-only --get-regexp 'core\.sshCommand' && git config --local --unset-all 'core.sshCommand' || :
2022-01-11T08:57:56.3458184Z [command]/usr/bin/git config --local --name-only --get-regexp http\.https\:\/\/github\.com\/\.extraheader
2022-01-11T08:57:56.3487921Z http.https://github.com/.extraheader
2022-01-11T08:57:56.3500025Z [command]/usr/bin/git config --local --unset-all http.https://github.com/.extraheader
2022-01-11T08:57:56.3542006Z [command]/usr/bin/git submodule foreach --recursive git config --local --name-only --get-regexp 'http\.https\:\/\/github\.com\/\.extraheader' && git config --local --unset-all 'http.https://github.com/.extraheader' || :
2022-01-11T08:57:56.3920276Z Cleaning up orphan processes

Ohhh, interesting! I'll try to look into this soon.

@TreTuna happened again 😔
Perhaps I should also find an action that autocloses forked PRs from the fork's master branch!


Powershell cannot be found on Ubuntu 18.04

I am still unable to install powershell in Ubuntu 18.04, I get an error Unable to locate package powershell. I have also tried adding sudo add-apt-repository universe, still same.

Can you provide the actual installation cmd line you use to try install PowerShell?
Which version of PowerShell you're trying to install?
Did you follow the installation instructions in Github(https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-linux?view=powershell-6#ubuntu-1804)?
Please provide all steps to reproduce the issue as without it is impossible to see what's wrong.


Add possiblity of use trackers/logs as Application Insights for metrics and historic info

Add the possibility of using Application Insights or other APM to record liveness information events and metrics.
This would allow the possibility of having and history of liveness information, like which are unreliable services, as well as metrics for any pulse milliseconds ellapsed.
This should be added dynamically and support from zero to n trackers.

Hi Luis,
Can you explain more "allow the possibility of having and history of liveness information". This tracker track de "service availability" or metrics like "liveness excution time" etc?
Unai

Sure.
With the Application Insights Tracker, you can check whole history of all BeatPulse calls and it's result, making it so easy to have historical information of it, via Application Insights events information:

Also, adding the milliseconds info taken from BeatPulse, and adding it to the event information, we can have custom metrics on which "pulses" are taking more time, also with history info, via metrics on Application Insights:

The whole point of this also, is to add a new extensibility point, which allows developers to create and add his own trackers for other APM like New Relic, to be able to use this info with the whole monitoring info from their own applications.

Hi @lfraile ,
Sounds good, waiting your PR!

Thanks for this PR, on master with 7140bd4880966f2d41b7dd5364fb4df8119357e1


Calling the actuator bindings endpoint causes infinite recursion

Description
With Spring Cloud Stream 3.2.1 calling the /actuator/bindings endpoint causes an infinite recursion (StackOverflowError):
java.lang.IllegalArgumentException: Infinite recursion (StackOverflowError) (through reference chain: org.springframework.core.convert.support.GenericConversionService$ConvertersForPair["converters"]->java.util.concurrent.ConcurrentLinkedDeque[0]->org.springframework.core.convert.support.ObjectToCollectionConverter["conversionService"]->org.springframework.core.convert.support.DefaultConversionService["converters"]->...)
	at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4394) ~[jackson-databind-2.13.0.jar:2.13.0]
	Suppressed: reactor.core.publisher.FluxOnAssembly$OnAssemblyException:
Error has been observed at the following site(s):
	*__checkpoint ⇢ Handler org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping$ReadOperationHandler#handle(ServerWebExchange) [DispatcherHandler]
	*__checkpoint ⇢ org.springframework.cloud.sleuth.instrument.web.TraceWebFilter [DefaultWebFilterChain]
	*__checkpoint ⇢ org.springframework.boot.actuate.metrics.web.reactive.server.MetricsWebFilter [DefaultWebFilterChain]
	*__checkpoint ⇢ HTTP GET "/actuator/bindings" [ExceptionHandlingWebHandler]
Original Stack Trace:
		at com.fasterxml.jackson.databind.ObjectMapper._convert(ObjectMapper.java:4394) ~[jackson-databind-2.13.0.jar:2.13.0]
		at com.fasterxml.jackson.databind.ObjectMapper.convertValue(ObjectMapper.java:4325) ~[jackson-databind-2.13.0.jar:2.13.0]
		at org.springframework.cloud.stream.binding.BindingsLifecycleController.queryStates(BindingsLifecycleController.java:124) ~[spring-cloud-stream-3.2.1.jar:3.2.1]
		at org.springframework.cloud.stream.endpoint.BindingsEndpoint.queryStates(BindingsEndpoint.java:52) ~[spring-cloud-stream-3.2.1.jar:3.2.1]
		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
		at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
		at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
		at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
		at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:282) ~[spring-core-5.3.13.jar:5.3.13]
		at org.springframework.boot.actuate.endpoint.invoke.reflect.ReflectiveOperationInvoker.invoke(ReflectiveOperationInvoker.java:74) ~[spring-boot-actuator-2.6.1.jar:2.6.1]
		at org.springframework.boot.actuate.endpoint.annotation.AbstractDiscoveredOperation.invoke(AbstractDiscoveredOperation.java:60) ~[spring-boot-actuator-2.6.1.jar:2.6.1]
		at org.springframework.boot.actuate.endpoint.web.reactive.AbstractWebFluxEndpointHandlerMapping$ElasticSchedulerInvoker.lambda$invoke$0(AbstractWebFluxEndpointHandlerMapping.java:239) ~[spring-boot-actuator-2.6.1.jar:2.6.1]
		at reactor.core.publisher.MonoCallable.call(MonoCallable.java:92) ~[reactor-core-3.4.12.jar:3.4.12]
		at reactor.core.publisher.FluxSubscribeOnCallable$CallableSubscribeOnSubscription.run(FluxSubscribeOnCallable.java:227) ~[reactor-core-3.4.12.jar:3.4.12]
		at org.springframework.cloud.sleuth.instrument.reactor.ReactorSleuth.lambda$null$6(ReactorSleuth.java:324) ~[spring-cloud-sleuth-instrumentation-3.1.0.jar:3.1.0]
		at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:68) ~[reactor-core-3.4.12.jar:3.4.12]
		at reactor.core.scheduler.SchedulerTask.call(SchedulerTask.java:28) ~[reactor-core-3.4.12.jar:3.4.12]
		at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264) ~[na:na]
		at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
		at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
		at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
		at java.base/java.lang.Thread.run(Thread.java:829) ~[na:na]
Caused by: com.fasterxml.jackson.databind.JsonMappingException: Infinite recursion (StackOverflowError) ...

Version of the framework

Spring Boot 2.6.1
Spring Cloud 2021.0.0
Spring Cloud Stream 3.2.1
Spring Cloud Stream Binder for Solace PubSub+ 3.2.0

If you disable Sleuth - does the problem persist? Can you create a small maven java sample that replicates the problem?

Disabling Sleuth or removing the Sleuth dependency does not help. I can create a small sample next week.

Yeah, please reproducible sample would help as I can not reproduce it locally.
The part of the stack trace that looks strange is
java.lang.IllegalArgumentException: Infinite recursion (StackOverflowError) (through reference chain: org.springframework.core.convert.support.GenericConversionService$ConvertersForPair["converters"]->java.util.concurrent.ConcurrentLinkedDeque[0]->org.springframework.core.convert.support.ObjectToCollectionConverter["conversionService"]->org.springframework.core.convert.support.DefaultConversionService["converters"]->...)

I can see the recursion, but it appears to be related to the setup of the ConversionService which we don't modify
We simply get ObjectMapper instance from Spring's ApplicationContext and
return this.objectMapper.convertValue(bindings, List.class);

That is the line that causes the exception, so something is up with configuration of ObjectMapper in your environment.

I created a sample project: https://github.com/dbruegger/spring-cloud-stream-actuator-bug
You can run the ActuatorBindingsTest to reproduce the infinite recursion.
While creating the sample project I observed that the infinite recursion only occurs when the following configuration property is enabled:
spring.jackson.visibility.field=ANY

This is quite a common setting in my opinion.
The infinite recursion does not occur with Spring Cloud Streams Version 3.1.3.

@dbruegger thank you. Will look at it shortly

I am not sure how I would fix it as it has nothing to do with stream or our configuration. But let me explain what has changed between 3.1.3 and latest release.
Basically the only difference is that we are now using Spring managed ObjectMapper based on https://github.com/spring-cloud/spring-cloud-stream/issues/2215. Before, we were creating a new instance of it (e.g., new ObjectMapper()). This is why it created an appearance that it was working regardless of spring.jackson.visibility.field=ANY, but in reality this property had absolutely no effect on the ObjectMapper since it only applies on the one managed by Spring.
The only thing I can propose is to go back to a separate/isolated instance of ObjectMapper
Let me know.

Thinking about it some more, I am now inclined bringing isolated ObjectMapper back, given that user has no control over objects (internal list of s-c-stream Binding objects ) that are being serialized

Thanks for fixing the problem!


fix: set focus on password input resolve #124

What:
Fixed set focus on password input while use click on eye button.

Why:
Improving the user experience, Closes #124

How:
Added the focus based on input id.

Checklist:

[x] Ready to be merged

Hey @raoasifraza11, first of all thanks for using Wave and for taking your time contributing to it 🤗
I've gone ahead and changed the title and description to reference #124 instead of #142, I guess it was a typo since #142 is already closed and does not relate to the PR as far as I see, please let me know in case you meant to reference #142

Hey @raoasifraza11, first of all thanks for using Wave and for taking your time contributing to it 🤗
I've gone ahead and changed the title and description to reference #124 instead of #142, I guess it was a typo since #142 is already closed and does not relate to the PR as far as I see, please let me know in case you meant to reference #142

Sorry I meant #124


whitelist

Hello
Firstly many thanks for the plugin is very good
I have a few questions

You can add a whitelist of sites, it's very good, but where can I find the list I've added (in the form of a text file)
It will be good when I want to take my entire whitelist to another computer.

Is it possible to add a white list but for a limited time for example for 5 minutes and after 5 minutes it will disappear from the list.

Thank you

In my question above
I was referring to the possibility of exporting a whitelist
And the option of importing a whitelist