Saturday, April 22, 2023

Overlaying text over video.

Video Player with Text Overlay
Ready to place your bets

Wednesday, December 18, 2019

Java-8 Currency.getSymbol(Locale.ENGLISH) works differently as compared to Java-11

Java-8 Currency.getSymbol(Locale.ENGLISH) works differently as compared to Java-11

Take the sample code
import java.util.*;
public class CurrencyClass
{
        public static void main(String[] args)
        {
                // Use of getInstance() method to 'AUD' instance
                Currency c1 = Currency.getInstance("AUD"); //Australian Dollar
                Currency c2 = Currency.getInstance("JPY"); //Japan Yen
                Currency c3 = Currency.getInstance("USD"); //Japan Yen
               
                System.out.println("getSymbol(Locale.ENGLISH");
		System.out.println("AUD Symbol for English locale: "+c1.getSymbol(Locale.ENGLISH));
		System.out.println("JPY Symbol for English locale: "+c2.getSymbol(Locale.ENGLISH));
                System.out.println("USD Symbol for English locale: "+c3.getSymbol(Locale.ENGLISH));
        }
}
      
and Java-8 will print
getSymbol(Locale.ENGLISH
AUD Symbol for English locale: AUD
JPY Symbol for English locale: JPY
USD Symbol for English locale: USD
      
and Java-11 will print
getSymbol(Locale.ENGLISH
AUD Symbol for English locale: A$
JPY Symbol for English locale: ¥
USD Symbol for English locale: $
      

Monday, October 26, 2015

Hacking Eclipse tutorial - creating RSE property page

Eclipse has a useful plugin/extension called Remote Systems Explorer (RSE) and can be used to browse files, folders, processes and start a shell for a remote server right within Eclipse IDE. They have tutorials to show how it can be extended further and one of them is to add a property page for local folders showing the no of files and the total size.

But the tutorial does not work for Mars version of Eclipse and spent several hours trying to figure out on how to fix it. 

One of the first error I encountered was ResourceBundle not found. That was easy one and moved the rseSamplesMessages.xml and rseSamplesResources.properties into src/ folder.

Second error was the missing message Id 1002. Figured out that 1002 needs to be added to the xml file having the message Processing as shown below.

<message id="1002" indicator="E">
    <levelone>Sample message</levelone>
    <leveltwo>Processing...</leveltwo>
</message>

Third error was to extend new class called FolderInfoPropertyPage from com.ibm.etools.systems.core.ui.propertypages.SystemAbstractRemoteFilePropertyPageExtensionAction but that class was not present in the Mars plugins. Figured out that I can extend FolderInfoPropertyPage from
org.eclipse.rse.ui.propertypages.SystemBasePropertyPage and copy the getRemoteFile() from the class org.eclipse.rse.internal.files.ui.propertypages.SystemFilePropertyPage. Had to do some trivial code changes but seems to be working.

package samples.ui.propertypages;

import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;

import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.rse.core.filters.ISystemFilter;
import org.eclipse.rse.core.filters.ISystemFilterPool;
import org.eclipse.rse.core.filters.ISystemFilterPoolReference;
import org.eclipse.rse.core.filters.ISystemFilterPoolReferenceManager;
import org.eclipse.rse.core.filters.ISystemFilterReference;
import org.eclipse.rse.core.filters.ISystemFilterString;
import org.eclipse.rse.core.model.IHost;
import org.eclipse.rse.core.model.IPropertySet;
import org.eclipse.rse.core.model.IPropertySetContainer;
import org.eclipse.rse.core.model.IRSECallback;
import org.eclipse.rse.core.model.IRSEPersistableContainer;
import org.eclipse.rse.core.model.ISystemProfile;
import org.eclipse.rse.core.subsystems.ICacheManager;
import org.eclipse.rse.core.subsystems.IConnectorService;
import org.eclipse.rse.core.subsystems.ISubSystem;
import org.eclipse.rse.core.subsystems.ISubSystemConfiguration;
import org.eclipse.rse.internal.files.ui.propertypages.*;
import org.eclipse.rse.services.clientserver.messages.SystemMessageException;
import org.eclipse.rse.services.search.IHostSearchResultConfiguration;
import org.eclipse.rse.subsystems.files.core.ILanguageUtilityFactory;
import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFile;
import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileContext;
import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileSubSystem;
import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteFileSubSystemConfiguration;
import org.eclipse.rse.subsystems.files.core.subsystems.IRemoteSearchResult;
import org.eclipse.rse.ui.SystemBasePlugin;
import org.eclipse.rse.ui.SystemWidgetHelpers;
import org.eclipse.rse.ui.propertypages.SystemBasePropertyPage;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Label;
import org.eclipse.ui.dialogs.PropertyPage;

import rsesamples.RSESamplesPlugin;

/**
 * A sample property page for a remote object, which in this case is scoped via the
 *  extension point xml to only apply to folder objects.
 *  
 *  com.ibm.etools.systems.core.ui.propertypages.SystemAbstractRemoteFilePropertyPageExtensionAction
 */
public class FolderInfoPropertyPage
 //extends SystemFilePropertyPage
extends SystemBasePropertyPage
 implements SelectionListener, IRemoteFileSubSystem
{
 // gui widgets...
 private Label sizeLabel, filesLabel, foldersLabel;
 private Button stopButton;
 // state...
 private int totalSize = 0;
 private int totalFolders = 0;
 private int totalFiles = 0;
 private boolean stopped = false;
 private Thread workerThread;
 private Runnable guiUpdater;

 /**
  * Constructor for FolderInfoPropertyPage.
  */
 public FolderInfoPropertyPage()
 {
  super();
 }

 // --------------------------
 // Parent method overrides...
 // --------------------------
 

 /* (non-Javadoc)
  * @see org.eclipse.rse.files.ui.propertypages.SystemAbstractRemoteFilePropertyPageExtensionAction#createContentArea(org.eclipse.swt.widgets.Composite)
  */
 protected Control createContentArea(Composite parent)
 {
  Composite composite = SystemWidgetHelpers.createComposite(parent, 2);
  // draw the gui  
  sizeLabel = SystemWidgetHelpers.createLabeledLabel(composite, 
    RSESamplesPlugin.getResourceString("pp.size.label"), //$NON-NLS-1$
    RSESamplesPlugin.getResourceString("pp.size.tooltip"), //$NON-NLS-1$
    false);
  filesLabel = SystemWidgetHelpers.createLabeledLabel(composite, 
    RSESamplesPlugin.getResourceString("pp.files.label"), //$NON-NLS-1$
    RSESamplesPlugin.getResourceString("pp.files.tooltip"), //$NON-NLS-1$
    false);
  foldersLabel = SystemWidgetHelpers.createLabeledLabel(composite, 
    RSESamplesPlugin.getResourceString("pp.folders.label"), //$NON-NLS-1$
    RSESamplesPlugin.getResourceString("pp.folders.tooltip"), //$NON-NLS-1$
    false);
  stopButton = SystemWidgetHelpers.createPushButton(composite, null, 
    RSESamplesPlugin.getResourceString("pp.stopButton.label"), //$NON-NLS-1$
    RSESamplesPlugin.getResourceString("pp.stopButton.tooltip") //$NON-NLS-1$
    );
  stopButton.addSelectionListener(this);
  
  setValid(false); // Disable OK button until thread is done
  
  // show "Processing..." message
  setMessage(RSESamplesPlugin.getPluginMessage("RSSG1002")); //$NON-NLS-1$
  
  // create instance of Runnable to allow asynchronous GUI updates from background thread    
  guiUpdater = new RunnableGUIClass();
  // spawn a thread to calculate the information
  workerThread = new RunnableClass(getRemoteFile());
  workerThread.start();
  
  return composite;
 }

 /**
  * Get the input remote file object. Copied from org.eclipse.rse.internal.files.ui.propertypages.SystemFilePropertyPage 
  */
 protected IRemoteFile getRemoteFile()
 {
  Object element = getElement();
  IRemoteFile file = (IRemoteFile)element;

  return file;
 }

 
 /**
  * Intercept from PreferencePage. Called when user presses Cancel button.
  * We stop the background thread.
  * @see org.eclipse.jface.preference.PreferencePage#performCancel()
  */
 public boolean performCancel() 
 {
  killThread();
  return true;
 }   
 
 /**
  * Intercept from DialogPage. Called when dialog going away.
  * If the user presses the X to close this dialog, we 
  *  need to stop that background thread.
  */
 public void dispose()
 {
  killThread();
  super.dispose();
 }
 
 /**
  * Private method to kill our background thread.
  * Control doesn't return until it ends.
  */
 private void killThread()
 {
  if (!stopped && workerThread.isAlive())
  {
      stopped = true;
      try {
        workerThread.join(); // wait for thread to end
      } catch (InterruptedException exc) {}
  }  
 }

 // -------------------------------------------
 // Methods from SelectionListener interface...
 // -------------------------------------------
 
 /**
  * From SelectionListener
  * @see SelectionListener#widgetSelected(SelectionEvent)
  */
 public void widgetSelected(SelectionEvent event) 
 {
  if (event.getSource() == stopButton)
  {
   stopped = true;
   stopButton.setEnabled(false);
  }
 }
 /**
  * From SelectionListener
  * @see SelectionListener#widgetDefaultSelected(SelectionEvent)
  */
 public void widgetDefaultSelected(SelectionEvent event)
 {
 }

 // ----------------
 // Inner classes...
 // ----------------
 /**
  * Inner class encapsulating the background work to be done, so it may be executed
  *  in background thread.
  */
 private class RunnableClass extends Thread
 {
  IRemoteFile inputFolder;
  
  RunnableClass(IRemoteFile inputFolder)
  {
   this.inputFolder = inputFolder;
  }
  
  public void run()
  {
   if (stopped)
     return;
   walkFolder(inputFolder);      
   updateGUI();
   if (!stopped)
   {
    stopped = true;
    updateGUI();
   }
  }
  
  /**
   * Recursively walk a folder, updating the running tallies. 
   * Update the GUI after processing each subfolder.
   */
  private void walkFolder(IRemoteFile currFolder)
  {
   SystemBasePlugin.logInfo("walkFolder() currFolder="+currFolder.getName());
   try
   {
   IRemoteFile[] folders = currFolder.getParentRemoteFileSubSystem().list( currFolder, null);
   if ((folders != null) && (folders.length>0))
   {
    for (int idx=0; !stopped && (idx<folders .length="" a="" catch="" e="" else="" exception="+e);
    
   }
  } // end of walkFolder method

 } // end of inner class
 
 /**
  * Inner class encapsulating the GUI work to be done from the
  *  background thread.
  */
 private class RunnableGUIClass implements Runnable
 {
  public void run()
  {
   if (stopButton.isDisposed())
     return;

   sizeLabel.setText(Integer.toString(totalSize));  
   filesLabel.setText(Integer.toString(totalFiles));
   foldersLabel.setText(Integer.toString(totalFolders));

   if (!stopped)
   {
   }
   else if (stopped)
   {    
    setValid(true); // re-enable OK button        
    stopButton.setEnabled(false); // disable Stop button    
                                //clearMessage(); // clear "Processing..." message
   }     
  }
 }

Rest of the file was generated by Eclipse to implement the abstract methods. Hope it works for you too.

Thursday, May 22, 2014

Error running "npm install" in angular-phonecat

I got angular-phonecat using git and when I ran "npm install" to get the node components, I got the following error. It took me a long time to resolve this but I had to update npm.

npm http GET https://registry.npmjs.org/shelljs
npm http GET https://registry.npmjs.org/bower
npm http GET https://registry.npmjs.org/http-server
npm http GET https://registry.npmjs.org/protractor
npm http 304 https://registry.npmjs.org/bower
npm ERR! Error: No compatible version found: bower@'^1.3.1'
npm ERR! Valid install targets:
npm ERR! ["0.1.0","0.1.2","0.1.3","0.2.0","0.3.0","0.3.1","0.3.2","0.4.0","0.5.0","0.5.1","0.6.0","0.6.1","0.6.2","0.6.3","0.6.4","0.6.5","0.6.6","0.6.7","0.6.8","0.7.0","0.7.1","0.8.0","0.8.1","0.8.2","0.8.3","0.8.4","0.8.5","0.8.6","0.9.0","0.9.1","0.9.2","0.10.0","1.0.0","1.0.1","1.0.2","1.0.3","1.1.0","1.1.1","1.1.2","1.2.0","1.2.1","1.2.2","1.2.3","1.2.4","1.2.5","1.2.6","1.2.7","1.2.8","1.3.0","1.3.1","1.3.2","1.3.3"]
npm ERR!     at installTargetsError (/usr/local/lib/node_modules/npm/lib/cache.js:709:10)
npm ERR!     at /usr/local/lib/node_modules/npm/lib/cache.js:631:10
npm ERR!     at saved (/usr/local/lib/node_modules/npm/node_modules/npm-registry-client/lib/get.js:138:7)
npm ERR!     at Object.oncomplete (fs.js:107:15)
npm ERR! If you need help, you may report this log at:
npm ERR!     
npm ERR! or email it to:
npm ERR!     

sudo npm update npm -g

That solved that issue. It took me a long time to figure this out and found it in IRC chat logs.

So this blog is to help other users of angular mitigate the issue.


Friday, March 8, 2013

Second factor authentication

Second factor Authentication at Bank of America

Introduction

BAC online banking (OLB) application has username and password for authentication. If OLB does not recognize the browser, it presents a challenge question to the user.

SafePass

Second factor authentication is called SafePass by BAC. It provides another layer of security in case the username, password are compromised. SafePass sends a SMS to your registered cell phone with a six digit code and prompts to enter it on the OLB website. If it matches, user is allowed to login.
If you watch the traffic between the browser and OLB, you will notice that the SafePass widget is hosted on a different server and if you dissect it more, you will find that it uses JSONP.

Sample SafePass code.

If you have logged in to the BAC site in another tab, SafePass should come initialized.

JSONP

JSON with padding is used to provide html widget like solution for mashups. Instead of having different web pages have the same html, JavaScript, stylesheets and images, the widget is created as an application and is embedded on the different web pages. To allow for cross domain JavaScript access, JSONP is used.
To read more about JSONP please use the following links.
http://api.jquery.com/jQuery.ajax/
http://en.wikipedia.org/wiki/JSONP
Let us first see how it is implemented and we will then figure out how it works.

BAC Implementation

Pages like "Add a Payee" in BillPay or "Outside the Bank Transfer" in Transfer application load the following JavaScript files.
First it loads JQuery core and UI libraries.
https://safe.bankofamerica.com/pa/global-assets/1.0/script/jquery-core.js
https://safe.bankofamerica.com/pa/global-assets/1.0/script/jquery-ui.js 
The third is BAC code for JSONP
https://safe.bankofamerica.com/pa/components/utilities/vipaa-safepass-client-util/1.2/script/safepass-nonflash-widget.js
Looking at the safepass-nonflash-widget.js, we find that it uses JQuery ajax call.

$skwjq.ajax({ // skwjq is JQuery. Instead of $, it is using skwjq
   async: (typeof(spwAsynchAll) !== "undefined"? spwsynchAll : false), // looks like spwsyncAll is undefined
   url: safePassInitUrl, // points to the widget self
   type:'GET',
   dataType: 'jsonp', // As per JQuery docs, Adds an extra "?callback=?" to the end of your URL 
   crossDomain: true,
   cache: false,
   timeout: 20000,
   beforeSend:function(){   
   },        
 error: function(XMLHTTPRequest,textStatus,errorThrown) { 
   $skwjq(spwDivId).html(XMLHttpRequest.responseText + "
   TextStatus: " + textStatus + "
   ErrorThrown: " + errorThrown);
 },        
 success: function(data){
   $skwjq(spwDivId).html(""); //spwDivId: "#safepassNonFlashwidget"
   $skwjq(spwDivId).append(data.htmlSource); // appends the widget to the div
   if ($skwjq('#spw-progress-bar').length > 0) {
     spwProgressBar.setPercent(50);
   }
 },
 complete: function(XMLHTTPRequest,textStatus){ 
   if($('ul.safepass-tab li.sp-mobile').length > 0 && $('ul.safepass-tab li.sp-card').length > 0) {
     if($('ul.safepass-tab li.sp-card:hidden').length > 0) {
       $('ul.safepass-tab li.sp-mobile a').removeAttr('href');
     } else if($('ul.safepass-tab li.sp-mobile:hidden').length > 0) {
       $('ul.safepass-tab li.sp-card a').removeAttr('href');
     }    
   }
 }
});

How it works

The hosting webpage defines a div tag with id=safepassNonFlashwidget. This id is used to attach the widget to the DOM. It will help you to understand better if you put a breakpoint in safepass-nonflash-widget.js.showNonFlashWidget()
The variables of interest have the following values
  1. spwDivId: "#safepassNonFlashwidget"
  2. safePassInitUrl: https://secure.bankofamerica.com/login/sign-in/incoming/safepassInitScreen.go

The JQuery.ajax call invokes URL https://secure.bankofamerica.com/login/sign-in/incoming/safepassInitScreen.go?callback=jsonp1362762508183&_=1362762519426. The callback is the success part of the ajax call. JQuery appends the timestamp to the callback to make each callback unique.
Actually there are multiple JSONP calls occuring.
  1. The first JSONP loads following script files from https://secure.bankofamerica.com/pa/components/utilities/safepass-widget-html-util/1.1/script/. It is a loader for SafePass.
    safepass-widget-html-util.js
    crypto-sha1-hmac-pbkdf2-blockmodes-aes.js
    safepass-widget-layout.js
    
  2. The second JSONP call occurs in safepass-widget-html-util.js. The function is spwGetSafepass(). This actually gets the html to display the widget.
  3. The third JSONP call gets the user specific mobile data.

SAML

When you enter the code sent to your mobile, and click on "Send" button within the widget, two things happen.
  1. SAML assertion is generated on the secure.bankofamerica.com and since that is few kbytes in size, a corresponding artifact is generated.
  2. the method sendToJavaScript() is invoked in the browser and that copies the SAML artifact to the hidden input field.

The SAML artifact is submitted along with the html form. The OLB, or BillPay or Transfer application takes that artifact, makes a webservice call to secure.bankofamerica.com and retrieves the SAML assertion. That assertion is parsed and validated.

Disclaimer

This blog describes working of SafePass, Second factor authentication on BAC website. The code keeps on changing and evolving. So what is observed today may not be seen tomorrow, making this blog inaccurate or pointless.

Saturday, April 28, 2012

Read about immediately invoked function expression IIFE in JavaScript and found it interesting. http://tech.myemma.com/iifes-javascript-control-variable-scope/

http://toddmotto.com/minimal-angular-module-syntax-approach-using-an-iife/ talks about using IIFE for defining Angular controllers and directives.