|
Thursday, April 30, 2026
Welcome to Uber [Do not share: 3658]
Friday, May 9, 2014
How to set the cursor caret at the end of an input text field
I tried dozens of ways involving .select(), .setSelectionRange(0,999), etc, etc. but what works is to simply remove the value from the input box and replace it in a few milliseconds.
So something like this:
/////////////////////////////////////////////////////////////////////////////////////////
// moveCaretToEndOfInputField - ensures that the cursor (caret) is at the end of the
// ====================== text input field.
/////////////////////////////////////////////////////////////////////////////////////////
function moveCaretToEndOfInputField(oInputBox) {
var tempValue = oInputBox.value;
oInputBox.value = "";
setTimeout(function() {
oInputBox.value = tempValue;
},1);
}
moveCaretToEndOfInputField(this)">
Wednesday, July 4, 2012
animateObjectFromTo
var myDiv = document.getElementById('myDiv),
currentPosition = window.getComputedStyle(myDiv,null),
currentLeft = parseFloat(currentPosition["left"]),
currentTop = parseFloat(currentPosition["top"]);
animateObjectFromTo(
myDiv,
{ top:currentTop, left:currentLeft },
{ top:0, left:currentLeft },
250
);
/////////////////////////////////////////////////////////////////////////////////////////
// animateObjectFromTo([object|string] oHTMLElement, json From, json To, int totalTimeInMilliseconds, OPTIONAL int framesPerSecond)
// Sets up an animation that interpolates frame animation from a beginning top, left coordinate
// to an ending top, left coordinate over a number of milliseconds at a specified frame rate
// totalTimeInMilliseconds - default is 1 second
// framesPerSecond - default is 30
/////////////////////////////////////////////////////////////////////////////////////////
animateObjectFromTo : function(oHTMLElement, from, to, totalTimeInMilliseconds, framesPerSecond) {
if (typeof(oHTMLElement)=="string") { oHTMLElement = document.getElementById(oHTMLElement); }
totalTimeInMilliseconds = totalTimeInMilliseconds || 1000;
framesPerSecond = framesPerSecond || 30;
var currentFrame = 0,
numberOfFrames = parseInt(totalTimeInMilliseconds / framesPerSecond),
deltaTimePerFrame = totalTimeInMilliseconds/numberOfFrames,
deltaXPerFrame = (to.left - from.left)/numberOfFrames || 0,
deltaYPerFrame = (to.top - from.top)/numberOfFrames || 0;
animate();
function animate() {
if (currentFrame<numberOfFrames) {
var oCurrentStyle = document.defaultView.getComputedStyle(oHTMLElement, null);
oHTMLElement.style.left = parseFloat(oCurrentStyle["left"]) + deltaXPerFrame + "px";
oHTMLElement.style.top = parseFloat(oCurrentStyle["top"]) + deltaYPerFrame + "px";
currentFrame += 1;
console.log('top is now: ' + parseFloat(oCurrentStyle["top"]) + deltaYPerFrame + "px")
setTimeout( function() { animate(); }, deltaTimePerFrame );
}
}
Friday, June 22, 2012
Javascript String Length
////////////////////////////////////////////////////////////////////////////////
//
// String.width(OPTIONAL string fontSize, OPTIONAL string fontFamily)
// ==================================================================
// Measures the length of a string, in pixels, using CANVAS's measureText method
// By passing in fontSize and FontFamily, you will get accurate measurements
// eg: x.width('22px','HelveticaNeueLTStdTh')
////////////////////////////////////////////////////////////////////////////////
String.prototype.width = function(fontSize, fontFamily) {
var ctx = document.createElement('canvas').getContext('2d'),
retVal = 0,
theString = this.toString();
fontSize = (typeof fontSize==="undefined") ? "12pt" : fontSize;
fontFamily = (typeof fontFamily==="undefined") ? "Arial" : fontFamily;
ctx.font = fontSize + " " + fontFamily;
return (ctx.measureText(theString).width);
}
Shannon Norrell
Thursday, August 18, 2011
Javascript Reliable Detect Internet Connection
Here is an alternative I wrote that seems to work flawlessly.
<script type="text/javascript">
var bIsOnline = false;
(function() {
var anImage = document.createElement("img");
anImage.onerror = function() { bIsOnline=false; }
anImage.onload = function() { bIsOnline=true; }
anImage.src="http://www.quirksmode.org/pix/logo_quirksmode.gif?" + (Math.random()*100000 << 0);
})();
function test() {
alert("You " + ((bIsOnline) ? "ARE" : "ARE NOT") + " online")
}
</script>
<body onload="test();"></body>
Shannon Norrell
Thursday, March 3, 2011
CSS3 Tooltip Trick using CSS3 :before psuedo element, content attribute and custom data attributes
Turns out there is a way to capture the "title" attribute of an element using the :before pseudo element and content property, store that value in a div that only appears onhover over the original element. The problem with this technique was that the actual "title" attribute would eventually display.
Therefore, I made use of another CSS3 feature called "custom data attributes" and, rather than storing the title of the element in the "title" attribute, I used "data-title" instead.
Here is a quick example:
<!DOCTYPE html>
<head>
<style type="text/css">
.sprocket { position:relative;width:50px;height:50px;background-color:red; }
.sprocket:before { content:attr(data-title); display:none; }
.sprocket:hover::before{ width:160px; display:block; border-radius:3px; background-color:#fffdc7; padding:5px; color:black; margin-top:40px; margin-left:20px; -webkit-box-shadow: 3px 3px 3px rgba(193,193,193,.5);}
.sprocket:hover{ z-index:10; position:absolute; }
</style>
</head>
<body>
<div class="sprocket" data-title="Fancy Title Text">
</body>
</html>
Click here for an ExampleShannon Norrell
Saturday, January 1, 2011
Array.remove method (also Array,indexOf
////////////////////////////////////////////////////////////////////////////////
//
// Array.remove( object|string item) - removes an item from an array
// Example x = ["abc","xyz",1,4] x.remove("xyz") returns ["abc",1,4]
//
////////////////////////////////////////////////////////////////////////////////
if (Array.prototype.remove===undefined) { // Presumably this will eventually be added to Javascript
Array.prototype.remove = function( item ) {
var itemLocation = this.indexOf(item);
if (itemLocation > -1) {
this.splice(itemLocation,1);
}
}
}
////////////////////////////////////////////////////////////////////////////////
//
// Array.indexOf() - returns integer index where valueToSearchFor is in an Array
// (believe it or not, not all browsers have this yet ... and it's 2010!
////////////////////////////////////////////////////////////////////////////////
if (Array.prototype.indexOf===undefined) {
Array.prototype.indexOf = function( valueToSearchFor ) {
var iEnd = this.length;
var retVal = -1;
for (var i=0;i<iEnd; i++) {
if (this[i] == valueToSearchFor) {
retVal = i;
break;
}
}
return retVal;
};
}
Shannon Norrell
Wednesday, October 6, 2010
Javascript Array Detection
function isArray(anArray) {
return Object.prototype.toString.apply(anArray) === "[object Array]";
}
Wednesday, September 8, 2010
Flatten Array
Extremely simple solution, but kind of fun because it's a chance to use recursion:
<script type=text/javascript>
var a = [1,2,[5,6,7], 8, [9,10,[11,12],13], 14];
function flatten( oArray ) {
var retVal = [];
for (var i=0;i<oArray.length;i++) {
if (!isArray( oArray[i]) ) {
retVal.push( oArray[i] );
} else {
var tempFlatt = flatten(oArray[i]);
for (var j=0;j<tempFlatt.length;j++) {
retVal.push( tempFlatt[j] );
}
}
}
return retVal;
}
function isArray( anElement ) {
return (typeof anElement=="object" && anElement.constructor == Array);
}
alert(flatten(a));
</script>
Thursday, August 26, 2010
Javascript Detect for Safari 3
Thought it might be helpful to someone else.
<script type="text/javascript">
var isSafari3 = (function() {
var retval = false;
if (navigator.vendor && navigator.vendor.indexOf('Apple') > -1) {
var index=navigator.appVersion.indexOf('Version');
if (index > -1) {
retval = (parseInt(navigator.appVersion.substring(index+8))==3);
}
}
return retval;
})();
alert(isSafari3);
</script>
Shannon Norrell
Monday, August 23, 2010
IE CSS Hack
However, there are two other varieties of IE-only hacks that are perhaps a bit more useful.
All of these work, in some form or another for IE. I tested them all in various flavors to arrive at my favorite (sic).
You can set up a test harness yourself using this code to see for yourself.
<style type=text/css>
body {
background-color:red;
_background-color:blue;
*background-color:green;
background-color:yellow\9;
}
</style>
- _ hack WORKS for: IE8 Quirks, IE7 Quirks, IE6
- _ hack DOES NOT WORK for: IE8 IE8 Standards, IE8 IE7 Standards, IE7 IE7 Standards
- * hack works for: IE8 Quirks, IE8 IE7 Standards, IE7 Quirks, IE7 IE7 Standards, IE6
- * hack DOES NOT WORK for: IE8 IE8 Standards
- \9 hack WORKS for: IE8 IE8 Standards, IE8 IE7 Standards, IE8 Quirks mode, IE7 Quirks, IE7 Standards (all varieties of IE8), IE6
So, in short, if you want an IE CSS hack that works in all flavors of IE, use the backslash-nine hack. That is, just put a \9 after *whatever* css value you are assigning.
Examples
width: 9px\9;
background-color:yellow\9;
etc.
Good luck.
Shannon Norrell
Friday, June 4, 2010
HTML5 Demos on Apple.com
http://www.apple.com/html5/
http://developer.apple.com/safaridemos/
Most of the demos use my DHTML slider and all use my library.js file
Shannon Norrell
Tuesday, April 20, 2010
EnsureMinimumNumberOfRows
This function operates on a table and effectively clones the last row in the table a given number of times to ensure that a minimum number of rows exist within the table. it does not clone the contetns of the cells, but rather the nodes themselves and their classnames (by way of cloneNode(false).
////////////////////////////////////////////////////////////////////////////////
// EnsureMinimumNumberOfRows(element, params) - ensures a table will have a minimum
// ========================================== number of visible rows.
// Supported params are:
// numberOfRows - gives the minimum number of rows that will appear
// rowHeight - height, in pixels for added rows
// *NOTE: Does not support empty tables
////////////////////////////////////////////////////////////////////////////////
function EnsureMinimumNumberOfRows(element, params) {
var minimumNumberOfRows = params.numberOfRows || 10, // default minimumNumberOfRows is 10
rowHeight = params.rowHeight || 30, // default rowHeight (for new rows) is 30px
oTable = $(element).select('div.resultList table')[0], // Get the first element as $(element).select returns an array
numberOfRowsToInsert = minimumNumberOfRows - oTable.rows.length + 1;
if (numberOfRowsToInsert > 0) {
var clonedRow = oTable.rows[ oTable.rows.length - 1 ]
clonedCells = clonedRow.getElementsByTagName('td');
for (var i=0;i<numberOfRowsToInsert;i++) {
var oRow = document.createElement("TR");
for (j=0;j<clonedCells.length;j++) {
var oCell = clonedCells[j].cloneNode(false);
oCell.style.height = rowHeight + "px";
oCell.appendChild( document.createTextNode("\u00a0") );
oRow.appendChild(oCell);
}
oTable.appendChild( oRow );
}
}
}
Shannon Norrell
Now posted on GitHub
Wednesday, April 7, 2010
addClassName and removeClassName
Here I present addClassName, hasClass and removeClassName and also my old implementation of Array.indexOf. Since this is built into JS these days, you probably won't need it.
addClassName and removeClassName are useful functions because you can pass in space separated classNames and it will add/remove them all.
////////////////////////////////////////////////////////////////////////////////
//
// addClassName([object|string] oHTMLElement, string classNameToAdd)
// Adds classNameToAdd to an HTMLElement. Guaranteed not to add the same className twice.
// classNameToAdd can be a space separated list of classNames.
// You can pass in the id to an object or the actual object
//
////////////////////////////////////////////////////////////////////////////////
function addClassName(oHTMLElement, classNameToAdd) {
if (typeof(oHTMLElement)=="string") { oHTMLElement = document.getElementById(oHTMLElement); }
if (oHTMLElement) {
var theClassName = oHTMLElement.className;
if (theClassName && (theClassName.length > 0)) { // If oHTMLElement already has a class name, some more work is needed
var classNamesToAdd = classNameToAdd.split(" ");
if (classNamesToAdd.length===1 && ((" " + theClassName + " ").lastIndexOf(" " + classNameToAdd + " ") === -1) ) { // If we only have one className to potentially add, take the "less work" approach
oHTMLElement.className = oHTMLElement.className + " " + classNameToAdd;
} else {
var theClassNames = theClassName.split(" "),
iEnd = classNamesToAdd.length,
aClassName,
theClassNamesToAddArray = [];
for (var i=0;i<iEnd;i++) {
aClassName = classNamesToAdd[i];
if (theClassNames.indexOf(aClassName)===-1) {
theClassNamesToAddArray.push( aClassName );
}
}
oHTMLElement.className = oHTMLElement.className + " " + ((theClassNamesToAddArray.length > 1) ? theClassNamesToAddArray.join(" ") : theClassNamesToAddArray[0]);
}
} else {
oHTMLElement.className = classNameToAdd; // If oHTMLElement did not already have a class name, just add it
}
}
}
////////////////////////////////////////////////////////////////////////////////
//
// hasClassName([object|string] oHTMLElement, string classNameOfInterest)
// Returns a boolean value of if an HTMLElement has the className of interest
// You can pass in the id to an object or the actual object
//
////////////////////////////////////////////////////////////////////////////////
function hasClassName(oHTMLElement, classNameOfInterest) {
return ((" " + oHTMLElement.className + " ").lastIndexOf(" " + classNameOfInterest + " ") > -1);
}
////////////////////////////////////////////////////////////////////////////////
//
// removeClassName([object|string] oHTMLElement, string classNameToRemove)
// Removes classNameToRemove from an HTMLElement, if it exists.
// classNameToRemove can be a space separated list of classNames.
// You can pass in the id to oHTMLElement or the actual object
//
////////////////////////////////////////////////////////////////////////////////
function removeClassName(oHTMLElement, classNameToRemove) {
if (typeof(oHTMLElement)=="string") { oHTMLElement = document.getElementById(oHTMLElement); }
if (oHTMLElement) {
var theClassName = oHTMLElement.className;
if (theClassName && (theClassName.length > 0)) {
var theClassNameArray = theClassName.split(" "),
classNamesToRemove = classNameToRemove.split(" "),
iEnd = theClassNameArray.length,
aClassName,
theNewClassNameArray = [];
for (var i=0;i<iEnd;i++) {
aClassName = theClassNameArray[i];
if (classNamesToRemove.indexOf(aClassName)===-1) {
theNewClassNameArray.push( aClassName );
}
}
switch (true) {
case (theNewClassNameArray.length>1) :
oHTMLElement.className = theNewClassNameArray.join(" ");
break;
case (theNewClassNameArray.length==1) :
oHTMLElement.className = theNewClassNameArray[0];
break;
case (theNewClassNameArray.length==0) :
oHTMLElement.className = "";
break;
}
}
}
}
////////////////////////////////////////////////////////////////////////////////
//
// Array.indexOf() - returns integer index where valueToSearchFor is in an Array
//
////////////////////////////////////////////////////////////////////////////////
if (Array.prototype.indexOf===undefined) {
Array.prototype.indexOf = function( valueToSearchFor ) {
var iEnd = this.length;
var retVal = -1;
for (var i=0;i<iEnd; i++) {
if (this[i] == valueToSearchFor) {
retVal = i;
break;
}
}
return retVal;
};
}
by Shannon Norrell
Monday, March 1, 2010
showOrHide algorithm
////////////////////////////////////////////////////////////////////////////////
//
// showOrHide([object|string] oHTMLElement, boolean bShowOrHide)
// Shows or Hides an HTMLElement.
// You can pass in the id to an object or the actual object
//
////////////////////////////////////////////////////////////////////////////////
function showOrHide(oHTMLElement, bShowOrHide) {
try {
if (typeof(oHTMLElement)=="string") {
oHTMLElement = document.getElementById(oHTMLElement);
}
if (oHTMLElement && oHTMLElement.style) {
if (bShowOrHide == 'inherit') {
oHTMLElement.style.visibility = 'inherit';
} else {
if (bShowOrHide) {
if (oHTMLElement.nodeName == 'TR') {
oHTMLElement.style.visibility = 'inline-table';
} else {
oHTMLElement.style.visibility = 'visible';
}
} else {
oHTMLElement.style.visibility = 'hidden';
}
try {
if (bShowOrHide) {
oHTMLElement.style.display = 'block';
} else {
oHTMLElement.style.display = 'none';
}
}
catch (ex) {
}
}
}
}
catch (ex) {
}
}
Shannon Norrell
Now on GitHub
Tuesday, December 8, 2009
Unified Javascript disableTextSelection | enableTextSelection
Unified Text Selection Disable/Enable Routine
If you're doing any kind of drag and drop operation in Javascript/DHTML, you will need to temporarily disable and re-enable text selection in your document while the drag operation is going on.
I wrote this block of code today and it was such a tedious hassle, I thought it worth blogging so others wouldn't have to endure my pain :{.
This works in all browsers except PC Opera.
It DOES work in Mac OSX Safari, Firefox, Chrome and on PC Internet Explorer, Safari, Firefox and Chrome.
////////////////////////////////////////////////////////////////////////////
// UTILITIES - Section contains general-purpose utilties //
// ========= //
////////////////////////////////////////////////////////////////////////////
utilities : {
savedValueOf : new Object(), // savedValueOf will hold "original" values that we override/restore as needed
disableTextSelection : function() {
switch (true) {
case ( typeof document.onselectstart!="undefined" ) : // IE
this.savedValueOf["onselectstart"] = document.onselectstart;
document.onselectstart=function() { return false; };
break;
case ( typeof document.body.style.MozUserSelect != "undefined" ) : // Firefox
this.savedValueOf["-moz-user-select"] = document.body.style.MozUserSelect || "text";
document.body.style.MozUserSelect="none";
break;
case ( document.body.style["-khtml-user-select"] != "undefined" ) : // Safari
this.savedValueOf["-khtml-user-select"] = document.body.style["-khtml-user-select"];
document.body.style["-khtml-user-select"] = 'none';
break;
}
},
enableTextSelection : function() {
switch (true) {
case ( typeof document.onselectstart!="undefined" ) : // IE
document.onselectstart = this.savedValueOf["onselectstart"]
break;
case (typeof document.body.style.MozUserSelect != "undefined") : // Firefox
document.body.style.MozUserSelect = this.savedValueOf["-moz-user-select"]
break;
case ( document.body.style["-khtml-user-select"]!="undefined" ) : // Safari
document.body.style["-khtml-user-select"] = this.savedValueOf["-khtml-user-select"];
break;
}
}
}
Shannon Norrell
This posting now also on GitHub
Tuesday, October 20, 2009
How to do LDAP authentication using Ruby, How to Run Ruby as a Windows Service and to Write Events into the EventLog (Event Viewer) Service
We needed a way to authenticate users against LDAP and required that the ruby processing running the Authentication code (in a file we called "ad_login_verify.rb") appear as a Windows Service that can be started from services.msc by our networking guys. For *whatever* reasons, when running as a service, it was found that writing to a log file did not work properly.
Anyway, the more network-operations-friendly approach was for me to figure out a way to write into the Windows EventLog Service so that events could be viewed using Event Viewer.
Once everything is set up properly, the objective is to be able to send a query to a url (like http://server:4243/ldap?username=ausername;password=apassword) and to get "AUTH" or "NON-AUTH" back
So the setup is a windows box running Windows Server 2003, with the following base software installed:
Windows 2003 Resource Kit Tools (available here)
ruby (mine is ruby 1.8.6 (2007-09-24 patchlevel 111) [i386-mswin32])
win32-eventlog gem (mine is win32-eventlog (0.4.6) )
ruby-net-ldap gem (min is ruby-net-ldap (0.0.4) )
The contents of ad_login_verify.rb are as follows: (note, sensitive areas surrounded by ** **)
#!C:\ruby\bin ruby
require "rubygems"
require "webrick"
require "net/ldap"
require 'win32/eventlog'
include Win32
include WEBrick
# Write to EventViewer that Service Started
EventLog.open('Application') do |log|
log.report_event(
:source => "CrewResAuthEventSvc",
:event_type => EventLog::WARN,
:category => "0x00000002L".hex,
:event_id => "0x00000003L".hex,
:data => "CrewResAuth Service successfully started"
)
end
class LDAPServlet < HTTPServlet::AbstractServlet
def do_GET( request, response )
username = request.query['username']
password = request.query['password']
ldap_con = initialize_ldap_con("**DOMAIN**\\**USER**","**PASSWORD**")
treebase = "DC= **DOMAIN** , DC =LOCAL"
user_filter = Net::LDAP::Filter.eq( "sAMAccountName", username )
op_filter = Net::LDAP::Filter.eq( "objectClass", "organizationalPerson" )
dn = String.new
ldap_con.search( :base => treebase, :filter => op_filter & user_filter, :attributes=> 'dn') do |entry|
dn = entry.dn
end
login_succeeded = false
unless dn.empty?
ldap_con = initialize_ldap_con(dn,password)
login_succeeded = true if ldap_con.bind
end
response.status = 200
response.body = login_succeeded ? 'AUTH' : 'NON_AUTH'
# Write to Windows Event Log
EventLog.open('Application') do |log|
log.report_event(
:source => "CrewResAuthEventSvc",
:event_type => EventLog::WARN,
:category => "0x00000002L".hex,
:event_id => "0x000003E9L".hex,
:data => "#{username}/#{password} LOGIN #{login_succeeded ? 'SUCEEDED' : '**FAILED**' }"
)
end
end
alias do_POST :do_GET
def initialize_ldap_con(username, password)
Net::LDAP.new( {:host => '**LDAP FQDN**', :port => 389, :auth => { :method => :simple, :username => username, :password => password }} )
end
end
server = HTTPServer.new(:Port => 4243)
server.mount('/ldap', LDAPServlet)
%w(INT TERM).each do |signal|
trap(signal) {server.shutdown}
end
server.start
The event_id values are generated when we build the .dll that will be used to propogate messages from Ruby into the Event Viewer.
STEP 1 Copy Files
On the box that will be running the authentication service, create the following folder: c:\crewres\services
br/>
Copy the following three files into c:\crewres\services:
- ad_login_verify.rb
- crewResAuthStart.bat
- CrewResAuthEventSvc.dll
The contents of crewResAuthStart.bat is simply the following command:
c:\ruby\bin\ruby.exe c:\crewres\services\ad_login_verify.rb
The reason this is done will become apparent as we set things up to run as a windows service.
STEP 2 Create a Service
This is a two-step process. NOTE – for this section, I essentially followed the instructionshere
2.1) First we create a “stub” Windows Service using SRVANY.
From a command prompt, type:
INSTSRV "CrewResAuthSvc" "C:\Program Files\Windows Resource Kits\Tools\srvany.exe"
This will create a service in Service Manager called “CrewResAuthSvc”. Note the path to srvany may differ.
2.2) Second, you need to edit the registry, telling it what command to run when the service is started.
Navigate to the registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\CrewResAuthSvc
Add a key called Parameters
Underneath Parameters, add a Value called Application with a value being C:\crewres\services\CrewResAuthStart.bat
Now, you should be able to start the service using services.msc
NOTE ON STOPPING THE SERVICE - Please note that a SRVANY solution does not have a way to actually stop a service. You can click on “Stop Service” in services.msc and you will see that it indicates that the service has stopped.
HOWEVER, SRVANY does not have a way to stop ruby (or *whatever* it had launched originally).
Therefore, you have to go to the Windows Task Manager and kill the ruby.exe Process manually.
Note – a tricky way to determine the PID of the process (assuming you have MKS toolkit installed) is to do the following:
ps -a | grep "ruby.exe" | head -1 | awk '{print $1}'
this will print out the PID, after which you can do kill -9 *PID*
STEP 3 Register the .dll as an Event Source for Event Viewer
There is a list of Services that are allowed to send messages to the EventLog Service.
This list may be found under the following registry key: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\Sources
Now, since this is weird registry type that you cannot directly edit (it’s a bunch of null-terminated strings), you have to run some code that will insert CrewResAuthEventSvc into the list of “approved” event sources.
Do this by running the following command from the command prompt (this file is also in .svn)
ruby registerEventSource.rb
The contents of registerEventSource.rb are as follows:
require 'win32/eventlog'
include Win32
dll_file = 'C:\crewres\services\CrewResAuthEventSvc.dll'
EventLog.add_event_source(
"source" => "Application",
"key_name" => "CrewResAuthEventSvc",
"category_count" => 2,
"event_message_file" => dll_file,
"category_message_file" => dll_file
)
After running this, the service "CrewResAuthEventSvc" is on the list of allowed services who can write events into the event log.
How to Create/Build the .DLL
http://rubyforge.org/docman/view.php/85/1734/mc_tutorial.html
CrewResAuthEventSvc.dll is a .dll that marshals event messages into the Windows EventLog. ("marshal" may not be the right word, but that's what I'm calling it)
I essentially followed the instructions found at
To build the .dll, you need to first create an .mc file and then compile that into a .dll
The .dll really does nothing other than to accept messages from Ruby and posts them to the event viewer.
You will need Visual Studio installed and a program called mc.exe that creates header (.h) files and .RES files, which are used by the linker to create a .dll.
I created a file, “CrewResAuthEventSvc.mc” to this end.
The contents of CrewResAuthEventSvc.mc are as follows:
LanguageNames =
(
English = 0x0409:Messages_ENU
)
;////////////////////////////////////////
;// Eventlog categories
;//
;// These always have to be the first entries in a message file
;//
MessageId = 1
SymbolicName = CATEGORY_ONE
Severity = Success
Language = English
First category event
.
MessageId = +1
SymbolicName = CATEGORY_TWO
Severity = Success
Language = English
LDAP Authentication Event
.
;////////////////////////////////////////
;// Events
;//
MessageId = +1
SymbolicName = EVENT_STARTED
Language = English
CrewResAuth Service successfully started
.
;////////////////////////////////////////
;// Additional messages
;//
MessageId = +1
SymbolicName = CREWRES_AUTH
Language = English
XFO AUTH: %1
.
Note that there must be an extra CRLF at the end of the file.
To build the .mc file into a .dll, you must execute the following three commands, which I put into a batch file for convenience:
Contents of buildDll.bat
@ECHO OFF
call "C:\Program Files\Microsoft Visual Studio 8\VC\bin\vcvars32.bat"
mc CrewResAuthEventSvc.mc
rc -r CrewResAuthEventSvc.rc
link -dll -noentry -machine:x86 -out:CrewResAuthEventSvc.dll CrewResAuthEventSvc.RES
Once the .dll is built, copy it into c:\crewres\services folder and do the above voodoo to register CrewResAuthEventSvc as a Registered Event Source.
Here is the contents of the generated .h file:
////////////////////////////////////////
// Eventlog categories
//
// These always have to be the first entries in a message file
//
//
// Values are 32 bit values layed out as follows:
//
// 3 3 2 2 2 2 2 2 2 2 2 2 1 1 1 1 1 1 1 1 1 1
// 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0 9 8 7 6 5 4 3 2 1 0
// +---+-+-+-----------------------+-------------------------------+
// |Sev|C|R| Facility | Code |
// +---+-+-+-----------------------+-------------------------------+
//
// where
//
// Sev - is the severity code
//
// 00 - Success
// 01 - Informational
// 10 - Warning
// 11 - Error
//
// C - is the Customer code flag
//
// R - is a reserved bit
//
// Facility - is the facility code
//
// Code - is the facility's status code
//
//
// Define the facility codes
//
//
// Define the severity codes
//
//
// MessageId: CATEGORY_ONE
//
// MessageText:
//
// First category event
//
#define CATEGORY_ONE 0x00000001L
//
// MessageId: CATEGORY_TWO
//
// MessageText:
//
// LDAP Authentication Event
//
#define CATEGORY_TWO 0x00000002L
////////////////////////////////////////
// Events
//
//
// MessageId: EVENT_STARTED
//
// MessageText:
//
// CrewResAuth Service successfully started
//
#define EVENT_STARTED 0x00000003L
////////////////////////////////////////
// Additional messages
//
//
// MessageId: CREWRES_AUTH
//
// MessageText:
//
// XFO AUTH: %1
//
#define CREWRES_AUTH 0x000003E9L
Do you see the two id's I used in my Ruby code? CREWRES_AUTH is id 0x000003E9L and the one I use to tell event viewer that the service has started is id of 0x00000002L
Anyway, the ids you will use will be generated by mc.exe from the .mc file and will appear in your header file.
That's it!
Lots of steps. Somewhat complicated. But the good news is that it works!
Good luck,
Shannon Norrell
Thursday, September 10, 2009
Command Prompt Here Registry Hack
Copy/paste the below code segment. Save it as CmdPromptHere.reg somewhere, right click on it and choose "Merge" and OK the changes it will make to your registry.
-- CUT ----------------------------------------------
Windows Registry Editor Version 5.00
[HKEY_CLASSES_ROOT\Directory\shell\Command]
@="Command &Prompt Here"
[HKEY_CLASSES_ROOT\Directory\shell\Command\command]
@="cmd.exe"
-- CUT ---------------------------------------------
This is a simple operation that I end up doing to every machine I have and use.
-shannon norrell
Wednesday, September 9, 2009
Pervasive SQL PSQL v10 Custom Functions
The first, "PadWithZeroes" answers a question posed by many users
----------------------------------------------------------------------------------------------
-- PadWithZeroes(:N Integer, :NZ Integer) - Pad with Zeroes
-- Takes integer :N and returns a string padded with integer :NZ number of zeroes
----------------------------------------------------------------------------------------------
DROP FUNCTION PadWithZeroes;
CREATE FUNCTION PadWithZeroes(:N Integer, :NZ Integer)
RETURNS VARCHAR(25)
AS
BEGIN
DECLARE :retVal VARCHAR(25)
DECLARE :nString VARCHAR(25)
SET :nString = CONVERT(:N,SQL_CHAR)
IF LENGTH(:nString)>:NZ THEN
SET :retVal = :nString;
ELSE
SET :retVal = CONCAT(
RIGHT('0000000000000',:NZ - LENGTH(:nString)),
:nString
);
END IF
RETURN :retVal;
END;
The second ConvertToFOSDate, takes a date stored a long integer which is, in fact the number of days offset from January 1st, 1900 (aka a Julian Date) and converts it into a usable Date object:
----------------------------------------------------------------------------------------------
-- ConvertToFOSDate(:D integer) - converts a date stored like 40026 and converts it to a date
-- Takes NumberOfDays :D since 1900 to get the Date
----------------------------------------------------------------------------------------------
DROP FUNCTION ConvertToFOSDate;
CREATE FUNCTION ConvertToFOSDate(:D integer)
RETURNS DATE
AS
BEGIN
DECLARE :theDate DATE;
SET :theDate = DATEADD(DAY,:D,CONVERT('1899-12-31', SQL_DATE));
RETURN :theDate;
END;
The third takes a number of minutes and returns a string formatted as HH:MM
----------------------------------------------------------------------------------------------
-- ConvertToHHMM(:T integer)
-- Takes NumberOfMinutes :T and returns a string formatted as HH:MM
----------------------------------------------------------------------------------------------
DROP FUNCTION ConvertToHHMM;
CREATE FUNCTION ConvertToHHMM(:T integer)
RETURNS VARCHAR(5)
AS
BEGIN
DECLARE :theTime VARCHAR(5)
IF (:T = 0) THEN
SET :theTime = '00:00';
ELSE
SET :theTime = CONCAT(
CONCAT(PadWithZeroes(CONVERT(FLOOR(:T/60),SQL_INTEGER),2), ':'),
PadWithZeroes(CONVERT(ROUND(MOD(:T,60)/60,1)*60,SQL_INTEGER),2)
);
END IF;
RETURN :theTime;
END;
Here are a couple more. They are not world changing, but may be of help to someone:
----------------------------------------------------------------------------------------------
-- GetTimeInHundredths(:A integer)
-- Returns Minutes as a percentage of a day
----------------------------------------------------------------------------------------------
DROP FUNCTION GetTimeInHundredths;
CREATE FUNCTION GetTimeInHundredths(:A integer)
RETURNS VARCHAR(10)
AS
BEGIN
DECLARE :theTime VARCHAR(10)
IF (:A = 0 ) THEN
SET :theTime = '0';
ELSE
SET :theTime =
CONCAT(
CONCAT( CONVERT( FLOOR(:A/60), SQL_CHAR), '.'),
CONVERT( ROUND(MOD(:A,60)/60,1)*10, SQL_CHAR)
);
END IF;
RETURN :theTime;
END;
----------------------------------------------------------------------------------------------
-- MinutesBetween(:D1 DateTime, :D2 DateTime)
-- Computes the integer numberOfMinutes between Date1 :D1 and Date2 :D2
----------------------------------------------------------------------------------------------
DROP FUNCTION MinutesBetween;
CREATE FUNCTION MinutesBetween(:D1 DateTime, :D2 DateTime)
RETURNS INTEGER
AS
BEGIN
DECLARE :minutesBetween INTEGER;
SET :minutesBetween = CONVERT( DATEDIFF(MINUTE, :D1, :D2), SQL_INTEGER);
RETURN :minutesBetween;
END;
-shannon norrell
Saturday, July 4, 2009
Changing Default Download Folder for Internet Explorer 6
I just had the pleaser to use a computer that had IE6 still installed on it. I needed to change the default download directory, which ended up being a "home-made hack" I figured out on my own.
I know this information is a bit useless/out of date inasmuch ad Microsoft is about to release IE8, but there may be someone out there who needs this information.
So here is how to change the default downosd folder for IE6.
1. START/Run/Regedit
2. Navigate to this key: HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer
3. Right click on the right pane.
4. Choose New / String Value (REG_SZ)
5. Name the new key "Download Directory"
6. For the string value, enter the folder you want, in my case "C:\Dropzone"
Make sure to close all instances of IE that may be running for the change to take effect.
Shannon Norrell