Showing posts with label javascript. Show all posts
Showing posts with label javascript. Show all posts

Saturday, January 24, 2015

JavaScript Currying

Generic currying in JavaScript is so great but it takes time to understand the code. Closures!

'use strict';

// subCurry(fn, 1)(2, 3)
var subCurry = function (fn /* Multiple arguments possible */) {
  var args = [].slice.call(arguments, 1); // Dont take the first argument
  return function () {
    var thisArgs = Array.prototype.slice.call(arguments);
    return fn.apply(this, args.concat(thisArgs));
  };
};

// curry(fn)(1)(2)(3)
var curry = function (fn, length) {
  // Length will only be available after the first curry
  length = length || fn.length;
  return function () {
    if (arguments.length < length) {
      var thisArgs = Array.prototype.slice.call(arguments);
      var combined = [fn].concat(thisArgs);

      return curry(subCurry.apply(this, combined), length - arguments.length);
    } else {
      // All arguments ok
      return fn.apply(this, arguments);
    }
  };
};

var fn = function(x, y, z) { return x+y+z; }

var mFn = curry(fn);
console.log(mFn(1)(2)(3));

Wednesday, July 30, 2014

Points and Animation


A simple code pen for travel between points and animation. Works for Firefox atleast!

See the Pen iebuc by Dinesh Vasudevan (@dinks) on CodePen.

Sunday, October 13, 2013

Fibonacci - Golden Ratio

In mathematics, the Fibonacci numbers or Fibonacci series or Fibonacci sequence are the numbers in the following integer sequence: 0, 1, 1,2, 3, 5, 8, 13, 21, 34, 55, 89, 144 ...

I have always done the one with recursion (or iteration). But mathematics says we could do it with the Golden Ratio ..


Tuesday, October 8, 2013

Js for Sublime

Setting up a build system for Sublime Text for js

Let your interpreter be Node. If you don't have Node, I would recommend installing it from here. It uses the Google V8 Engine.

Open Tools -> Build System and select a New Build System
Name it whatever you want it to be (this will show up in the Build Options)
Add the following to it


 "cmd": ["node", "$file", "$file_base_name"], 
 "working_dir": "${project_path:${folder}}", 
 "selector": "*.js
}

The syntax could be understood from this link.

Restart sublime and open the file. Goto Tools -> Build System and set the build system to the name you gave.

Run Command + B and it will work !

All the build files go into /Library/Application Support/Sublime Text 2/Packages/User

:)

Friday, March 15, 2013

Less Caching

We came across this unusual problem when developing. So for starters, there is a Gem that we use and a test application reside in the test folder of the Gem. The Gem uses only Javascript in the app/assets folder and has a minimal Ruby code.

The Gem uses Bootstrap's less version to set the CSS. We use the mixins by Bootstrap and overwrite variables and stuff. The Gem still used SASS and we felt a little odd with writing mixed CSS. Therefore we moved all the stuff to less files and put it all in assets/stylesheets. Nice and organized. 

Now we had the problem. We made a change to the less files and the application did not load them. We had put all our imports in a main file and any change to the main file reflected in the test app. but not if the change were done inside the individual imports.

We wanted to analyze if the problem was with Sprockets or with less-rails. After some probe and hunt we concluded that the problem indeed was with less-rails. The Gem caches the imports which prevent any compilation after the import to the base file (first level).

I tried adding options like

config.consider_all_requests_local = true config.action_controller.perform_caching = false 

inside the environment files, but alas! no change what so ever.

So we had to do the inevitable. Look at files and trigger a restart and cache clear.

The process was to be something like :

if Change? 
  rake tmp:clear 
  powder restart (or touch tmp/restart) [we use pow]

Guard was perfect for this.

2 Guard plugins were used for this :
  guard-process => To run the rake process
  guard-pow => To restart Pow

The file looked something like this

# RUN bundle exec guard -p -i -w ../../ 
guard 'pow' do 
 watch(%r{app/assets/stylesheets/**/.*\.less$}) 
end 

guard 'process', :name => 'ClearCache', :command => 'rake tmp:clear' do
 watch(%r{app/assets/stylesheets/**/.*\.less$}) 
end 

The guard command needed to run with
  -w because we were looking at a change from another directory
  -p for polling
  -i for no interactions

phew..

Friday, October 26, 2012

Semicolons in Javascript

I read this very interesting blog post today and kind of made me thinking .. 

Semicolons in JavaScript are optional - http://mislav.uniqpath.com/2010/05/semicolons/ by Mislav Marohnić (http://mislav.uniqpath.com/) 

Sunday, January 15, 2012

FB Likes

I have been trying to get the Facebook Like to appear on an application. It was getting somewhat stressful because the Like would just not take the whole URL, but would take the base URL.


I started using the XFBML first because the way to integrate it is so nice. 


Add 


<html xmlns:fb="http://ogp.me/ns/fb#"> 


as the namespace and then use 


<fb:like href="http://google.com/" send="false" layout="button_count" width="450" show_faces="false"></fb:like>


Easy enough. The application used a lot of Ajax and therefore the these likes need some refreshing. To do this I used the Javascript method available


fb.xfbml.parse()


Function and it started working. But the likes were happening only for the base URL and not the href in the fb:like. This is when I saw the statement in the documentation which said 'The XFBML version defaults to the current page.' if href is used. 


urghh


I went on to use the iframe way so that I could get likes for the particular URL. It seems its important that the url end with '/' and only then Facebook identifies the absolute URL. 

Wednesday, December 28, 2011

Image Cropping With Rails 3

I was looking at some options for the Image Cropping functionality with Rails 3 and got many great solutions on the net. This Rails Cast is the best place to start if you have the images stored as local. If you have it as s3 storage there are some changes you need to make.

My main haml file has these contents -

#cropperpopup.lpopup.x 
  %a.ccloser 
  %p.large Image Cropper 
  .cropper 
    = image_tag @user.avatar.url(:medium), :id => :cropbox 
  = form_for @user, :html => {:class => 'edit_user_two'} do |f| 
    - for attrbt in [:crop_x, :crop_y, :crop_w, :crop_h] 
      = f.text_field attrbt, :id => attrbt, :class => :coordinate 
    = f.submit 'Crop'

When on calls the popup, one should call the code for the Jcrop method

$('img#cropbox').Jcrop({ 
  onChange: update_crop, 
  onSelect: update_crop, 
  setSelect: [0, 0, 168, 202], 
  aspectRatio: (168/202) });

My aspect ratio setting is with respect to the configurations I did for the has_attached_file :avatar.

The thing you will have to do specifically for s3 is in the avatar_geometry method.


def cropping? 
  !crop_x.blank? && !crop_y.blank? && !crop_w.blank? && !crop_h.blank? 
end 

def avatar_geometry(style = :medium) 
  @geometry ||= {} 
  path = (avatar.options[:storage]==:s3) ? avatar.url(style).split(' ').join('%20') : avatar.path(style) 
  @geometry[style] ||= Paperclip::Geometry.from_file(path) 
end

Inside the model.

I'm having issues with the cropper processor and its not cropping fine. Will have to fix that. This is the Cropper

module Paperclip 
  class Cropper < Thumbnail 
    def transformation_command 
     if crop_command 
       r = super 
       if r.class == Array 
         r = r.join(' ') 
       end 
       crop_command + r.sub(/ -crop \S+/, '').sub(/-resize \S+/, '') 
     else 
       super 
     end 
   end 
   def crop_command 
     target = @attachment.instance 
     if target.cropping? 
       "-resize \"168x202\" -crop #{target.crop_w}x#{target.crop_h}+#{target.crop_x}+#{target.crop_y} " 
     end 
    end 
  end 
end

Tuesday, September 20, 2011

Orientation changes for iPad - Secha & PhoneGap

I was working on a mobile application developed for iPhone. The application was built using Sencha Touch and PhoneGap. Its great what these guys have done to bridge the gap between Objective C and HTML/JavaScript/CSS. The application now wants to be run on iPad.

The orientation was something that caused a problem here. The call back for the orientation, onorientationchange, was not being called for some reason. I went through most of the content in the web which described the problem. Solutions were limited.

I tried putting window.onorientationchange, added event listeners for orientation and even added Objective C code ! Did not work ...

Thats when onWindowResize came into picture. The code started working. But just once. You change orientation and that works just once. The code goes something like :

var or = function(){ 
    // alert( Ext.getOrientation()); 
    var width = (Ext.getOrientation()=="landscape") ? window.innerWidth-1 : window.innerWidth; 
    panel.setOrientation( Ext.getOrientation() , width , window.innerHeight ); 
    panel.el.parent().setSize(width, window.innerHeight); 
    // return 0; 
    panel.doComponentLayout(); 

Ext.EventManager.onWindowResize(or);

The alert function caused a lot of issues for me. Firstly it creates an exception on the Objective C side. Signal Exception of some kind which says arguments are expected of a different kind. The setOrientation call is necessary for the panel to know the orientation. This did not update the width and height of the panel for some odd reason. So I did it manually by calling the setSize and to make sure I called the doComponentLayout.

Well, the code works now. This is for reference for all those people who have not still got the answers for this question.

Kudos !


Tuesday, January 18, 2011

Delegation Drag

Its been some time since I have written something and its simply because there is not much to write about. But now I have something :P

The application that I'm working on currently use a lot of drag and drop features for many objects. The number of these objects in the UI varies from user to user. The code has been written to create a DragDrop object for each of these UI elements. Therefore if you were supposed to have many elements, the page would stall thus making actions damn slow. I was told to improve performance by changing this to a delegation model.

The delegation model would find the event attachments done to the main container and not the individual elements. The event would bubble up to the container which would be handled by the handler written for this. The container would be specified as well as the css selector for the elements which would have the drag and drop feature.

To make this work was pretty easy with YUI3. A delegation class was present which gave me the initial stuff to get started. But then came problems.

The application would have different drop targets at different points of time. An ajax action would change the UI which would then have different drop targets. Now if you were using delegation, you need to specify the drop objects in the constructor. I did not find a way where I could add/remove drop targets dynamically. This is when I saw a post from an author who did a work around for this. He had created the drop targets inside the mouseover action of the drag, thus scoping it :). I put these drop objects inside a scoped variable so that when the UI changed, I reset this variable.


YUI().use('dd-delegate', 'dd-constrain', 'dd-proxy', 'dd-drop', function(Y) {

var del = new Y.DD.Delegate({
container: '#container1',
nodes: '.appt',
target: true,
dragConfig: { groups: ['default']}
});

del.dd.plug(Y.Plugin.DDConstrained, {
constrain2node: '#container1'
});

del.dd.plug(Y.Plugin.DDProxy, {
moveOnEnd: false,
cloneNode: false
});

del.on('drag:mouseDown', function(e){
if(_self.createdDrops.length ==0){
var drops = Y.all('td.day');
Y.each(drops, function(v, k) {
var tar = new Y.DD.Drop({
node: v,
groups: ['default']
});
_self.createdDrops.push(tar);
});
}
});

del.on('drag:start', function(e) {
_self.delDragStart(e, Y);
});

del.on('drag:end', function(e) {
_self.delDragStop(e);
});

del.on('drag:drophit', function(e) {
_self.delDragHit(e,Y);
});

del.on('drag:over', function(e){
_self.delDragOver(e);
});

del.on('drag:exit', function(e){
_self.delDragExit(e);
});

_self.del = del;
});


I also required there be different drag objects. Those which went to specific drop targets. I started specifying the 'container' parameter instead of the 'cont' parameter and that solved some issues. To have another set of delegates, I just took the above code and changed the 'container' parameter to get the correct set of draggables. I also change the groups parameter bit that did not seem to make a difference ...

References
http://yuilibrary.com/forum/viewtopic.php?p=17845
http://developer.yahoo.com/yui/3/dd/
http://developer.yahoo.com/yui/3/examples/dd/

Monday, August 30, 2010

Minimum diff between dates of a week

Problem statement:
The UI contains a set of checkboxes. Each signifies a day. The list starts from a Sunday and goes upto a Saturday. The task is to find out the minimum difference between the selected days.

Eg:
If Mon, Thur and Fri were selected, then the minimum days between the selected days would be 1 (Thu and Fri).

Take into consideration that if Sun and Sat were selected, the difference would be 1. :)

Thursday, June 10, 2010

Javascript Debug

I started working with Javascript some years back and at those times to get hold of a js issue was hard. Then came firebug. The tool analyzed the js stuff, gave a console where we could assign new Javascript variables, call functions etc. The Dom tab gave the variables currently declared in the DOM so that analyzing a variable got easier. The Net tab gave all the access made by the page. This included the images, css, js files and even XHR ! Debugging a script became easier with the Script tab.

But that was not enough, as for all things. YSlow came along which gave you a precise idea of the stuff that made your web page slow. Page Speed from Google also gave a great idea of the same. Cookies was introduced which let you view a cookie and modify it.

The debugging in IE was also some thing that developers looked forward to. Developer Bar gave many of the options that Firebug gave. Companion JS is a great tool that let you debug Javascript. Fiddler let you act as a proxy between IE and the server so that you could change a request to fetch a file (js/css) from the local disk.

Smush.it is something that I got to know recently which gives you a compressed version of images thus increasing the response time for a web site. Javascript compression and obfuscation are techniques that we use every time for the js response time reduction.

Many stuff to keep in mind and many to implement to create a great web app.

Wednesday, March 3, 2010

JS Snippets


function myFunc(param){
if (!myFunc.cache) {
myFunc.cache = {};
}
if (!myFunc.cache[param]) {
var result = {}; // ...
myFunc.cache[param] = result;
}
return myFunc.cache[param];
}



function lazy() {
var result = 2 + 2;
lazy = function() {
return result;
};
return lazy();
}

lazy(); // 4
lazy(); // 4

Thursday, February 18, 2010

Cook me up

This post tries to focus on the topic of Cooking or escaping in Web Applications.

The process of stripping/changing/modifying user input so that it avoids attacks like XSS is cooking. There are many ways to do it. One way is to strip off every input that the user provides. Let it be tags like <script> or <img> . The quotes are also removed so that javascript errors are avoided. 

The other way would be to take in what ever input the user provides and store it as it is in the database. The only place you would cook it would be in the UI. Escape/change what ever stuff you feel would cause your app to succumb to XSS and then display. This, I feel, is the right way to do it. 

Many applications that you see now may also have a JSON part to it. It might also be the case that the application is accessed by many other applications and these apps use the data. Not cooking this data is kinda buggy and cooking it defeats the purpose if this data is shown in a simple textarea. So I would rather let javascript cook this using the functions available.


update: The buzz has a problem with this. My blog title is  << Dinks >> and look how it came up in buzz .. 





Sunday, January 31, 2010

Pre Initialization Technique

An interesting piece of code which does a pre initialization.

XMLHttpRequest = (function () {
try { return new ActiveXObject("Msxml2.XMLHTTP.6.0"); }
catch (e1) {}
try { return new ActiveXObject("Msxml2.XMLHTTP.3.0"); }
catch (e2) {}
try { return new ActiveXObject("Msxml2.XMLHTTP"); }
catch (e3) {}
try { return new ActiveXObject("Microsoft.XMLHTTP"); }
catch (e4) {}
throw new Error("This browser does not support XMLHttpRequest.");
})();

Wednesday, November 4, 2009

Phew - Learning is hard

The last month had a learning curve to it. I had to learn and understand quite a bit of stuff. General http was one. These interview sessions require that you have the basic knowledge of stuff. The web is some thing that I thought I was comfortable with, but the sessions proved me wrong.

Javascript was some thing that I studied. I have used normal Javascript functions but not to the level as Closures. "Everyone uses closures, knowingly and unknowingly" was the statement of a friend of mine. Cross Side Scripting was another thing that I understood.

What are Sessions ? What are Cookies ? What are the different types of Cookies ? What do you do to maintain Sessions if Cookies are not accepted by your browser ? What is the access policy for a Cookie ?

Alternate Ajax techniques was also another topic that I went through. What happens if the Javascript in the browser is deactivated ? What is Accessibility and whats its importance ? What is Reverse Ajax ? Polling and Pushing ? What are iFrames used for and what are its disadvantages ? Whats JSONP ? What are the security issues ?

What are Javascript Events and how do you handle Cross Browser Event Handling problems ? What is Capturing and Bubbling ?

Why are CSS said to be Cascading ? What is the priority set by the CSS selectors ?

How would you improve the performance of a page ? What are Http Caches ? What are the Http Status Codes ? How would I track errors if accessed using Ajax ?

Why do I use Doctypes ? What are Semantic Markups used for ?

What is a Proxy ? What is a Reverse Proxy ?

Theres a vast array of questions but these troubled me a lot lately.

Saturday, May 16, 2009

Jira Again

Its been some time since I have worked on Jira. Creating plugins and modifying Java/Velocity Template/jsp code was what I used to do earlier. It was fun earlier when you start of learning new things and understand the structure of the excellent code written for Jira. But then the work becomes monotonous and you feel that you have more to give. After having finished with Enthiosys but developing some high end stuff based on SVG, javascript and HTML, I was asked to do some work on Jira.

The idea is a simple one. try to build something that would let users chat about some Jira issue and then log the chat into the Jira issue as comments. :) . Simple as it sounds, I had to set up a Jabber server. I used the excellent OpenFire as the server. The LDAP credentials for the company, I managed to obtain and then configured it so that all the users of the company could log in. Jira 3.13.4 was downloaded and I managed to connect to LDAP as well with the help of Indraneel.

Then came the difficult part. The application which was to be in AIR. I first thought to try to build it using flash. Actionscripting is something that I could do. But to have frames build movie clips is something that I could not do. I was good with HTML and Javascript and thought I would do it my way using HTML Ajax. I decided to build the required files to communicate with Jira and Jabber in flash so that I could use them in HTML using the window.runtime object provided by Adobe AIR.

Jira offers 2 ways of external communication. SOAP and XML RPC. I downloaded a bunch of those classes which facilitated the SOAP communication, because SOAP was well documented and XML RPC was crude, but did not have much luck getting information from Jira. The envelope and the structure of the xml was not being detected by the class for some reason. I had success with XML RPC and decided to go on with that.

The communication with Jabber was done with the excellent XIFF library. It is one of the best libraries that I have seen but is a little less in documentation. That is ok as long as it has all the necessary stuff required to develop.

I tried compiling the libraries into swf files, but for some reason they were not included in the file. I had just used an import statement. Ashish suggested to use a function and after using a function which initiated the class, I managed to get all the libraries for access. Event listeners were something that needed to be taken care of. At first the idea was to call Javascript from the Actionscript but the sand box had restrictions. This made me create event handlers in javascript and attach then using javascript. That worked fine.

With all the things setup, the next step was to build the interface. The interface would be simple with a list of contacts, an option to search, find and add contacts and chat with a contact. To create a native window with the chat was the next big step. I managed to populate the list of contacts with online and offline contacts (this list would change as and when the user logs in).

The native window creation according to the chat was tricky. It was tricky because to show the window was not a big deal, but to load chats in it was a pretty big deal. The handle for the window must be maitained by the main window and the chats must be sent as well. As of now I am working on this and I hope Ill make progress.

Tuesday, January 20, 2009

Scalable Vector Graphics - The Next Generation?

I had the opportunity of working in a relatively new (supposedly cutting edge) technology called Scalar Vector Graphics in my new project. IT has been great up until now. SVG is a language for describing two-dimensional graphics and graphical applications in XML. This XML could be either an external file or an inline XML. SVG has some primary inbuilt support in Firefox and for the lousy Internet Explorer there's the Adobe SVG Viewer.

When we started out with the project which was about drawing stuff(shapes and figures) in a canvas collaboratively, we were unsure about what to use. Since we needed the users to draw polygons and drag and drop objects (images that represent objects) to these polygons (and identify this region ), we were looking for some high end stuff. Indraneel suggested the use of SVG and before that I had very little or no knowledge of SVG. Reading about SVG and understanding it took some time but when it was known that the programming would be done in Javascript I was quite comfortable.

Javascript is used to manipulate the drawing of regions and dragging and dropping of items on these regions. The first wrapper Javascript library I saw was based on JQuery. I started out doing some POC using this library, but JQuery is not my style of coding. I like the operator/operand/manipulation style of coding which I think Prototype provides. So I went on to find another library thats based on Prototype called Prototype Graphic. I found this library excellent and fulfilled all of my needs. The sample files helped a lot in understanding the things I could do with this wonderful library.

The server side of the application was done by Dan and the client side (HTML/ Javascript/ CSS) was done by me. I tried to structure the application code in a class style as done with Workstreamer. Base application, managers like Layermanager, Layertreemanager, Usermanager etc. I had to also do a lot of changes in the main Prototype Graphics Javascript files, like adding node elements to the base SVG.

The Application.js file has all the base methods and initialization. This also meant uderstanding the stage of the game (plan, play, postprocessing) and setting up the item necessary for each stage. It also had hooks (event methods) so that all the data structures could be updated. This might be something like when a new object is created what methoids must be called so that the data is updated in the server.

The application dealt with the creation of layers (a collection of regions) and regions (with is a polygon shape). A Layermanager.js file was created with maintains the list of layers which inturn would have a list of regions. Each region would have a shape associated with it so that highlighing ( displaying the border with a different color) is possible. The regions would essentially have a set of co-ordinates (x and y) and this co-ordinates would be feeded to the server when the user is reday to create his game. Methods for hiding a layer(which meant hiding all the regions inside a layer), showing a layer etc were added.

The layers and regions had to presented to the user in some way. I felt a tree would be fit this requirement perfectly. Each layer would/could have regions as children and they could be renamed (labelled). An id (generated from inside the layermanager) would bbe assigned to each layer/region on creation and that would be its base identifier. Now for the tree I started out with the Yahoo! tree, but soon had to change it because of its clash with the JQuery code which was inserted by the server. The clash with Prototype was solved using jQuery's no conflict option. Aditya did his POC and gave me the TafelTree implementation which was based on Prototype. Hooks were added so that on selecting a region, the region would be highlighted on the canvas and on selecting a layer, that layer (ie the regions inside that layer) would show and all the others would be hidden.

The Draggablemanager.js file was the base file used to create the objects on dragging and dropping. The canvas would have a palette (an area which will have objects which could be initialized by dragging and dropping into the droppable area). Dragging from the palette would actually clone the object being dragged, add all the necesaary classes to identify the newly created object and after the drop was done would issue the create object command. To identify the object moved to created a class was added. All the updates to the canvas was done using a full refresh of the canvas. The server implemented using a framework called Lift would facilitate this. The refresh is done by lift comet calling a pre defined Javascript function which would refresh (redraw) the game board. The selection of items (for delete, lock, unlock) was done by drawing a circle around it after the object (which is in the canvas) was clicked. Double clicking on the item would fire a modal window inside the browser where the user could update the label and description for the item.

The regions inside a layer would have a fill ( color inside the polygon) which is the same. ie Different layers would have different fill colors. This color was maintained byt inserting this information in cookies. As the canvas was constantly refreshed, randomizing the color everytime felt odd. Therefore the code was stored inside cookies and therefore cookie,js was used.

A carousel control was used to show the backgrounds/objects available to the user during planning. The coding done for this control was one of the best I have seen. It took me some time to actually understand what Victor had done with this.

A gamecreator was created so that the game definition JSON could be generated and passed to the server during the game plan phase. This also had methods to update the background image, game name and description.

The chat feature was one feature that I felt increased the level of collaboration in this product. The comet from the Lift made this possible. The Usermanager was created to maintain the list of users, identify the current user and his privileges, and populate the chat messages in the necessary container.

Ill be writing more about the coding aspect in the next post !

Friday, September 5, 2008

What a week !

This week was a long one. Lots of work to be done, or atleast was asked from us. Amit and Abhilash had to put in extra hours to get it done and the work still continues as I write this post. My work is some what done so I am calmly sitting at a corner so that no one notices me.

The bugs that I got were all bugs which arose as a result of some miscommunication. Sometimes I understood it wrong, otherwise they interpreted it differently. 'They' are obviously NOT wrong. The major bug that took most my time was the one related to the Sortable list not working in IE7. I tried juggling with those classes but reached no where. At last a simple ' ' solved my problem :). The next major one was that the auto-completer in scriptaculous kept on disappearing when the container div's scroll was clicked. This was obviously because all the browsers except Firefox interpreted this as a valid auto-complete text field blur. The work around done was to entirely take off the onBlur event and be entirely dependent on the keypress(ESC key) and the selection of the element inside the autocomplete list.

Coding for the browser was also something we learned here. Amit had lots of problems uploading flv files via Safari. As I understand Safari gives a String Object instead of a StringIO object and therefore checking the content type becomes impossible. The attachment_fu plug-in therefore bombs and gives errors. Kudos to Amit for solving this bug.

To top it all up, I was to travel home today and my flight got canceled. Can't still believe it. This guy calls me up early in the morning to say that the flight has been canceled. He asks me the mode of refund and pleasantly says thanks. I had to spend a thousand rupees more to get a ticket home and am 'supposed' to go tomorrow. Let's hope that works out.