|
|
Context
Imagine that you have few lookup tables[^]. Each one can have its own lookup method; e.g.,
string LookupCountryCodes(string query);
string LookupStateCodes(string query);
string LookupCardTypes(string query)
Likely, these methods differ only in the table /entity name that they apply to. Every time a new lookup table / entity is added, the lookup method has to be copied. Readability, extensibility, and maintainability of the code suffers.
Idea
Instead, we can define the lookup as a generic method[^]; e.g.,
string Lookup<T>(string query) where T: class, ILookupEntity, new();
Then, given a table / entity name, we can find the associated:
table / entity type
var t = Type.GetType(typeName);
if (t == null)
{
var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies()
from assemblyType in assembly.GetTypes()
where assemblyType.Name == typeName
select assemblyType;
t = types.FirstOrDefault();
}
Lookup method
var method = <owner_of_Lookup_method>.GetType()
.GetMethod("Lookup", new Type[] {typeof (string)})
.MakeGenericMethod(entityType);
where the <owner_of_Lookup_method> is either a static class or an instance of an object with a Lookup method definition.
Implementation
Putting it all together:
private Dictionary<string, Type> typeCache = new Dictionary<string, Type>();
public bool TryFindType(string typeName, out Type t)
{
lock (typeCache)
{
if (!typeCache.TryGetValue(typeName, out t))
{
t = Type.GetType(typeName);
if (t == null)
{
var types = from assembly in System.AppDomain.CurrentDomain.GetAssemblies()
from assemblyType in assembly.GetTypes()
where assemblyType.Name == typeName
select assemblyType;
t = types.FirstOrDefault();
}
typeCache[typeName] = t;
}
}
return t != null;
}
public string Get(string entityTypeName, string query)
{
Type entityType;
if (TryFindType(entityTypeName, out entityType))
{
var method = <owner_of_Lookup_method>.GetType()
.GetMethod("Lookup", new Type[] {typeof (string)})
.MakeGenericMethod(entityType);
return Convert.ToString(method.Invoke(<owner_of_Lookup_method>, new[] { query }));
}
return string.Empty;
}
See also:
How to use reflection to call generic method[^]
GetType returns null[^]
GetType returns null (2)[^]
How to invoke method with parameters[^]
Object does not match target type+Reflection[^]
Overcoming problems with MethodInfo.Invoke of methods with by-reference value type arguments[^]
modified on Wednesday, August 31, 2011 12:20 AM
|
|
|
|
|
|
|
|
|
|
Display your notes as a collapsible outline to help you keep your thoughts organized.
I like to take notes as I read (or otherwise gather) information to highlight any points of interest that I find in the subject at hand. I find that these notes are most useful when they are focused and compact. An outline lets me organize the information in layers of increasing detail and, in this context, the ability to choose which details are visible becomes important to me.
I wanted an easy/automated access to a collapsible outline layout given any layered/indented text.
The solution comprises:
Model an html <pre> tag that contains the notes as raw text
View a stylesheet for customizing the look and feel
Controller a javascript parser that creates html tags based on the notes
The outline layers are defined by the indentation. The indentation is defined by white space or tab characters. That's it.
How to use it:
1. Open the Outline.html file in a text editor, such as Notepad.
2. Paste your notes in the <pre id='rawcontent'> tag.
3. Open the Outline.html file in a browse, such as Firefox.
4. (Optional) Use Save As..Web Page, Complete to export your outline
How it works:
1. We use regular expressions and recursion to parse the notes into a nested array of details:
content: function(text){
var parse = function(arr){
var newarr = [];
for(var i = 0, len = arr.length; i < len; i++){
if (/[\S]+/.test(arr[i])){
var subarr = arr[i].replace(/([ ]{2,4}(?=[\S])|\t(?=[\S]))/gm, "").split(/[\n](?=[\S])/m);
if (subarr.length > 1){
newarr.push([subarr[0], parse(subarr.slice(1))]);
} else {
newarr.push(subarr[0]);
}
}
}
return newarr;
};
return parse(text.split(/[\n](?=[\S])/m));
}
2. We spin through the array and create the detail html tags
See the attached OutlineParser.js (https://github.com/iguigova/snippets_js/tree/master/outline[^])
Q&A:
1. Can the solution be deployed as a single file?
Yes. Modify the html file to include the contents of the css file in a <style> tag and the contents of the js files in a <script> tag. Please let me know if you need help with that and I will be happy to assist.
2. Do I need to format the notes with any special attributes?
No. As long as you have used white spaces (2, 3, or 4) or a tab for the notes hierarchy, you are ready to paste the text in the html file and view it in your browser.
3. Can I use and/or modify the files freely?
Yes. The files are provided as-is and there is no warranty but you are welcomed to use them as you wish. Please note that some of the code has been borrowed from other people as indicated in the comments; do leave the references to their work.
Your feedback is greatly appreciated.
Thank you.
|
|
|
|
|
Crack-free walls (Project Euler):
Consider the problem of building a wall out of 2 x 1 and 3 x 1 bricks (horizontal x vertical dimensions) such that, for extra strength, the gaps between horizontally-adjacent bricks never line up in consecutive layers, i.e. never form a "running crack".
There are eight ways of forming a crack-free 9 x 3 wall, written W(9,3) = 8.
Calculate W(32,10).
Let
L = length of the row
k = the number of 2 x 1 blocks in a row
l = the number of 3 x 1 blocks in a row
A(k, l) = (k + l)! / k!l! = the number of arrangements of k 2 x 1 blocks and l 3 x 1 blocks
Then
(1) The number of rows of length L is:
R = \forall (k, l) \sum A(k, l)\mid 2*k + 3*l = L
(2) Cracks can occur at positions p in [2, L - 2]. The number of cracks between two rows of length L is:
C = \forall (k, l) \forall p \forall (m, n) \sum (A(k, l)*A(k-m, l-n) \mid 2*k + 3*l = L, p\in [2, L - 2], 2*m + 3*n = p, k - m >= 0, l - n >= 0
(3) The number of ways of forming a crack-free L x 2 wall is:
W(L, 2) = R*R - R - C = R*(R - 1) - C, (i.e., there are R*R walls, R walls with duplicate rows, C walls with cracks)
(4) In order to calculate the number of walls of any height it is enough to know the pattern of increase of cracks with the increase of height.
Observations (in progress):
Let
Wi = the number of walls of height i
Si = the number of splits at height i
s = the number of splits of a row
Then
Wi+1 = Wi + Si
Rows with s = 0 do not contribute to the pattern and can be ignored
Rows with s = 1 do not contribute to the pattern and their count can be carried as a constant
L = 9, W(9, 1) = {333, 3222, 2322, 2232, 2223} = 5
| 2 | 3 | 4 | 5 | 6 | 7 position
------------------------------------------------------
333 | | x | | | x | | 2
3222 | | x | | x | | x | 1
2322 | x | | | x | | x | 1
2232 | x | | x | | | x | 1
2223 | x | | x | | x | | 1
-------------------------------------------------------
| 3 | 2 | 2 | 2 | 2 | 3 number of cracks
1 | 2 | 3 | 4 | 5 | 6 | 7 wall height
-------------------------------------------------------
5 | 6 | 8 | 10 | 14 | 18 | 24 number of crack-free walls, W
| 1 | 2 | 2 | 4 | 4 | 8 number of splits, S
| 0 | 1 | 1 | 2 | 2 | 4 number of splits / 2
Graph of row relationships:
| 2322 |(1) -- | 333 |(2) -- | 2232 | (1)
| 3222 |(1) -- | 2223 |(1)
Graph of significant row relationships:
| 333 |
L = 10, W(10, 1) = {2332, 22222, 2233, 2323, 3223, 3232, 3322} = 7
| 2 | 3 | 4 | 5 | 6 | 7 | 8 position
------------------------------------------------------
2332 | x | | | x | | | x | 0
22222 | x | | x | | x | | x | 1
2233 | x | | x | | | x | | 2
2323 | x | | | x | | x | | 1
3223 | | x | | x | | x | | 1
3232 | | x | | x | | | x | 1
3322 | | x | | | x | | x | 2
-------------------------------------------------------
| 4 | 3 | 2 | 4 | 2 | 3 | 4 number of cracks
1 | 2 | 3 | 4 | 5 | 6 wall height
-------------------------------------------------------
7 | 8 | 12 | 18 | 28 | 44 number of crack-free walls, W
| 2 | 4 | 6 | 10 | 16 number of splits, S
| 1 | 2 | 3 | 5 | 8 number of splits / 2
Graph of row relationships:
| 2332 |(0)
| 3223 |(1) -- | 22222 |(1)
| 3322 |(2) -- | 2233 |(2)
| |
| 2323 |(1) | 3232 |(1)
Graph of significant row relationships:
| 3322 | -- | 2233 |
L = 11, W(11, 1) = {22223, 22232, 22322, 23222, 32222, 2333, 3233, 3323, 3332} = 9
| 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 position
------------------------------------------------------
22223 | x | | x | | x | | x | | 1
22232 | x | | x | | x | | | x | 1
22322 | x | | x | | | x | | x | 2
23222 | x | | | x | | x | | x | 1
32222 | | x | | x | | x | | x | 1
2333 | x | | | x | | | x | | 1
3233 | | x | | x | | | x | | 2
3323 | | x | | | x | | x | | 2
3332 | | x | | | x | | | x | 1
-------------------------------------------------------
| 5 | 4 | 3 | 4 | 4 | 3 | 4 | 5 number of cracks
1 | 2 | 3 | 4 | 5 | 6 wall height
-------------------------------------------------------
9 | 12 | 18 | 28 | | number of crack-free walls, W
| 3 | 6 | 10 | | number of splits, S
| 1 | 3 | 5 | | number of splits / 2
Graph of row relationships:
| 22223 |(1) -- | 32222 |(1)
| 2333 |(1) -- | 3332 |(1)
| 3323 |(2) -- | 22322 |(2) -- | 3233 |(2)
| |
| 23222 |(1) | 22232 |(1)
Graph of significant row relationships:
| 3323 | -- | 22322 | -- | 3233 |
Calculations:
1 import math
2
3 def get_factors(length):
4
5 factors = [(length/2 - length%2, length%2)]
6 while factors[0][0] >= 3:
7 factors[0:0] = (factors[0][0] - 3, factors[0][1] + 2),
8 return factors
9
10 def count_arrangements(x, y):
11 return math.factorial(x + y) / (math.factorial(x) * math.factorial(y))
12
13 def count_rows(rows):
14
15 return sum([count_arrangements(row[0], row[1]) for row in rows])
16
17 def count_cracks(length, rows):
18 return sum([count_arrangements(cracks[0], cracks[1])*count_arrangements(row[0]-cracks[0], row[1]-cracks[1]) for row in rows for c in range(2, length - 1) for cracks in get_factors(c) if row[0] - cracks[0] >= 0 if row[1] - cracks[1] >= 0])
19
20
21
22 def get_rows(length, rows = [[0]]):
23 if (length > 1):
24 if (len(rows[0]) < length):
25 r = [row + [1] for row in rows if ((row[-2:] == [0, 0]) or (row[-2:] == [1, 0]) or (row[-2:] == [0]))]
26
27 if (len(rows[0]) < length - 1):
28 r.extend([row + [0] for row in rows if ((row[-1:] == [1]) or (row[-2:] == [1, 0]) or (row[-2:] == [0]))])
29
30 return get_rows(length, r)
31 else:
32 return rows
33 return []
34
35
36 def count_splits(rows):
37 return sum([len(filter(lambda z: z == 1, [count_cracked(row1, row2) for row2 in rows])) - 1 for row1 in rows])
38
39 def count_cracked(row1, row2):
40 if len(row1) == len(row2):
41 return len(filter(lambda z: z > 1, map(lambda x, y: x + y, row1, row2)))
42
43
44 def count_walls(length, height):
45 pass
46
47
48 def get_time(fcall, i):
49 import timeit
50 t = timeit.Timer("e205_07.%s" % fcall, "import e205_07")
51 print "%s, %d calls/batch" % (t.repeat(3, i), i)
52
53
54 if __name__=='__main__':
55
56
modified on Tuesday, August 31, 2010 3:35 PM
|
|
|
|
|
(originally posted on July 17, 2009)
I thought that this may be useful to somebody…
My Visual Studio 2005 was getting slower and slower. Today it was freezing for 1-2 minutes every time I saved. So I searched the internet and eventually ran FileMon.
It turns out that each time I save, the IDE queries WebsiteCache folder in C:\Documents and Settings\iguigova\Local Settings\Application Data\Microsoft\WebsiteCache.
Then I spent at least an hour to delete its contents of about 80 000 folders being accumulated since December (I even took a snapshot of it and had to use the DOS Prompt to get rid of all the files).
The issue has been raised with Microsoft: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=347228[^]
Because I could not find a setting on the IDE that controls this behavior, I created a batch file to run every night to clean WebsiteCache:
rmdir /s /q "C:\Documents and Settings\<your username>\Local Settings\Application Data\Microsoft\WebsiteCache"
mkdir "C:\Documents and Settings\<your username>\Local Settings\Application Data\Microsoft\WebsiteCache"
I also cleaned some temp files and the RecycleBin and everything runs smoother now.
|
|
|
|
|
MSSQL Server 2005 provides native support for the XML data type, and new methods to directly parse and read the data.
The following two articles discuss the MSSQL Server 2005 XML capabilities:
http://www.setfocus.com/TechnicalArticles/Articles/sql-server-2005-xml.aspx[^]http://www.15seconds.com/Issue/050803.htm[^]
And here is a basic example:
DECLARE @XMLText XML
SET @XMLText = '
<Customers>
<Customer>
<FirstName>Kevin</FirstName>
</Customer>
<Customer>
<FirstName>Steve</FirstName>
</Customer>
</Customers>'
SELECT @XMLText.query('/Customers/Customer/FirstName')
Now let's assume that we have a table (#MAP ) that contains a xml mapping to another table (#NODE ). In order to validate the mappings, we need to check if a node referenced in a xml map exists in the #NODE table.
A solution is to use a cursor.
And here is a basic example of a cursor:
DECLARE @tablename sysname
DECLARE tables_cursor CURSOR FOR
SELECT name
FROM sys.objects
WHERE type = 'U' AND UPPER(NAME) LIKE UPPER('%%')
OPEN tables_cursor
FETCH NEXT FROM tables_cursor INTO @tablename
WHILE @@FETCH_STATUS = 0
BEGIN
EXEC ('SELECT Top 1 * FROM ' + @tablename)
FETCH NEXT FROM tables_cursor INTO @tablename
END
CLOSE tables_cursor
DEALLOCATE tables_cursor
However, since cursors are the slowest way to access data inside MSSQL Server (http://www.sqlteam.com/article/cursors-an-overview[^]), the following snippet includes both the cursor and the set-based way to scroll through and validate the mappings:
CREATE TABLE #NODE
(
ID INT IDENTITY,
NAME NVARCHAR(MAX)
)
INSERT INTO #NODE VALUES ('TESTNODE')
CREATE TABLE #MAP
(
ID INT IDENTITY,
XML_TEXT NVARCHAR(MAX),
IS_ENABLED BIT
)
INSERT INTO #MAP VALUES ('<MAP><INPUT><NODE><ID>1</ID></NODE></INPUT><OUTPUT>1234</OUTPUT></MAP>', 1)
INSERT INTO #MAP VALUES ('<MAP><INPUT><NODE><ID>11</ID></NODE></INPUT><OUTPUT>1234</OUTPUT></MAP>', 1)
UPDATE #MAP SET IS_ENABLED = 0
FROM #MAP M
LEFT JOIN #NODE N ON N.ID = ISNULL((CAST(M.XML_TEXT AS XML)).value('(//NODE/ID)[1]', 'INT'), 0)
WHERE N.ID IS NULL
DROP TABLE #MAP
DROP TABLE #NODE
|
|
|
|
|
On Update
http://haacked.com/archive/2004/02/28/sql-auto-increment.aspx[^]
On Insert
http://social.msdn.microsoft.com/forums/en-US/transactsql/thread/e021ead3-5dd4-4f2b-a79e-a9258384f313[^]
CREATE TABLE #NODE
(
ID INT IDENTITY,
DOMAIN_ID INT,
NAME VARCHAR(32)
)
INSERT INTO #NODE VALUES (100, 'Bloggers')
INSERT INTO #NODE VALUES (100, 'Vloggers')
INSERT INTO #NODE VALUES (500, 'Joe')
INSERT INTO #NODE VALUES (500, 'Jane')
INSERT INTO #NODE VALUES (500, 'Bob')
CREATE TABLE #NODE_LINKS
(
ID INT IDENTITY,
RANK INT,
LEFT_NODE_ID INT,
RIGHT_NODE_ID INT
)
DECLARE @RANK_OFFSET INT
SELECT @RANK_OFFSET = COUNT(ID) FROM #NODE WHERE DOMAIN_ID = 500
INSERT INTO #NODE_LINKS (RANK, LEFT_NODE_ID, RIGHT_NODE_ID)
SELECT (ROW_NUMBER() OVER (ORDER BY Jobs.ID) - 1) % @RANK_OFFSET, Jobs.ID, Personnel.ID
FROM #NODE Jobs
JOIN #NODE Personnel ON Personnel.DOMAIN_ID = 500
WHERE Jobs.DOMAIN_ID = 100
SELECT ROW_NUMBER() OVER (ORDER BY ID) AS COUNTER, * FROM #NODE_LINKS ORDER BY LEFT_NODE_ID
DROP TABLE #NODE_LINKS
DROP TABLE #NODE
Good Luck!
|
|
|
|
|
Setup:
A data from one module is passed into another so that Module 1 takes a (flat) file as input and feeds an xml structure into Module 2. While Module 2 is internal, Module 1 is designed to handle different customer inputs into the system. However, it is not always possible to generate the expected Module 2 xml structure from the flat file in one step.
|Customer| -> file -> |Module 1| -> xml(products-product-detail) -> |Module 2|
There are at least two ways to accomodate the (multi-step) translation process:
- Add re-parsing logic directly in the code - not smart enough as we do not know what input formats will need to be supported by Module 1 in the future
- Apply customizable xsl transformations - providing decoupled solution with a reliable techology
For example:
Given a list of details, we can group them into product(s) in order to conform to the expected Module 2 hierarchy.
List of details:
='1.0'="iso-8859-1"
<PRODUCTS>
<DETAIL>
<DESC>D1</DESC>
<PRODUCT_NAME>APL</PRODUCT_NAME>
</DETAIL>
<DETAIL>
<DESC>D2</DESC>
<PRODUCT_NAME>ANL</PRODUCT_NAME>
</DETAIL>
<DETAIL>
<DESC>D3</DESC>
<PRODUCT_NAME>APL</PRODUCT_NAME>
</DETAIL>
</PRODUCTS>
List of details grouped by product:
='1.0'="iso-8859-1"
<PRODUCTS>
<PRODUCT>
<PRODUCT_NAME>ANL</PRODUCT_NAME>
<DETAIL>
<DESC>D2</DESC>
<PRODUCT_NAME>ANL</PRODUCT_NAME>
</DETAIL>
</PRODUCT>
<PRODUCT>
<PRODUCT_NAME>APL</PRODUCT_NAME>
<DETAIL>
<DESC>D1</DESC>
<PRODUCT_NAME>APL</PRODUCT_NAME>
</DETAIL>
<DETAIL>
<DESC>D3</DESC>
<PRODUCT_NAME>APL</PRODUCT_NAME>
</DETAIL>
</PRODUCT>
</PRODUCTS>
In order to achieve this grouping, we can use the Muenchian method as described here:
http://www.jenitennison.com/xslt/grouping/muenchian.html[^]
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" encoding="iso-8859-1"/>
<xsl:key name="details-by-product" match="DETAIL" use="PRODUCT_NAME" />
<xsl:template match="PRODUCTS">
<PRODUCTS>
<xsl:for-each select="DETAIL[count(. | key('details-by-product', PRODUCT_NAME)[1]) = 1]">
<xsl:sort select="PRODUCT_NAME" />
<PRODUCT>
<PRODUCT_NAME><xsl:value-of select="PRODUCT_NAME"/></PRODUCT_NAME>
<xsl:for-each select="key('details-by-product', PRODUCT_NAME)">
<DETAIL>
<xsl:apply-templates/>
</DETAIL>
</xsl:for-each>
</PRODUCT>
</xsl:for-each>
</PRODUCTS>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
See also:
In order to test the transformation, we can initiate the xslt in a script as described here:
http://msdn.microsoft.com/en-us/library/ms762796(VS.85).aspx[^]
var oArgs = WScript.Arguments;
if (oArgs.length == 0)
{
WScript.Echo ("Usage : cscript xslt.js xml xsl");
WScript.Quit();
}
xmlFile = oArgs(0) + ".xml";
xslFile = oArgs(1) + ".xsl";
var xsl = new ActiveXObject("MSXML2.DOMDOCUMENT.6.0");
var xml = new ActiveXObject("MSXML2.DOMDocument.6.0");
xml.validateOnParse = false;
xml.async = false;
xml.load(xmlFile);
if (xml.parseError.errorCode != 0)
WScript.Echo ("XML Parse Error : " + xml.parseError.reason);
xsl.async = false;
xsl.load(xslFile);
if (xsl.parseError.errorCode != 0)
WScript.Echo ("XSL Parse Error : " + xsl.parseError.reason);
try
{
WScript.Echo (xml.transformNode(xsl.documentElement));
}
catch(err)
{
WScript.Echo ("Transformation Error : " + err.number + "*" + err.description);
}
In order to apply the transformation at run-time, we can use the XslCompiledTransform as described here:
http://msdn.microsoft.com/en-us/library/system.xml.xsl.xslcompiledtransform_members.aspx[^]
private string ApplyStylesheet(string xml, string stylesheet)
{
if (!string.IsNullOrEmpty(stylesheet))
{
XmlReaderSettings settingsReader = new XmlReaderSettings();
settingsReader.ValidationType = ValidationType.None;
settingsReader.ProhibitDtd = false;
settingsReader.XmlResolver = null;
StringReader strReader = new StringReader(xml);
XmlReader xmlReader = XmlReader.Create(strReader, settingsReader);
StringWriter stringWriter = new StringWriter();
XmlTextWriter xmlWriter = new XmlTextWriter(stringWriter);
XslCompiledTransform xslt = new XslCompiledTransform();
xslt.Load(stylesheet);
xslt.Transform(xmlReader, xmlWriter);
xmlWriter.Close();
xmlReader.Close();
return stringWriter.ToString();
}
return xml;
}
Good luck!
|
|
|
|
|
|
In dealing with durations in MSSQL server, I have found the following three resources helpful:
If you need to report a duration in a certain granularity such as "Task runs for ## minutes ## seconds" , then refer to this[^] post:
SELECT *,
(TOTAL_SS) / 31536000 AS YY,
DATEDIFF(MONTH, 0, END_TIME - START_TIME) % 12 AS MM,
(TOTAL_SS % 31536000) / 604800 AS WW,
(TOTAL_SS % 31536000) / 86400 AS DD,
(TOTAL_SS % 86400) / 3600 AS HH,
(TOTAL_SS % 3600)/60 AS MI,
(TOTAL_SS % 60) AS SS
FROM (
SELECT START_TIME,
END_TIME,
END_TIME - START_TIME AS TOTAL,
DATEDIFF(ss, 0, END_TIME - START_TIME) AS TOTAL_SS
FROM Tasks
WHERE END_TIME >= START_TIME
) AS Q1
If you need to report a duration in a certain format such as "## hours 00 minutes 00 seconds", then you may need to pad the number of minutes and seconds to ensure that, for example, 3 minutes is represented as 03. Padding for integers is explained here[^]:
DECLARE @CH CHAR(1) = '0',
@LEN INT = 2,
@N INT = 1
SELECT CASE WHEN @LEN > LEN(@N) THEN REPLICATE(@CH, @LEN - LEN(@N)) ELSE '' END + CAST(@N AS VARCHAR) AS PADDED_NUMBER
If you need to extract the date part of a DATETIME timestamp, you can use the fact that internally dates are treated as FLOAT as described in more detail here[^]:
SELECT CAST (FLOOR(CAST (GETDATE() AS FLOAT)) AS DATETIME) AS DATE_ONLY
|
|
|
|
|
Excellent article, exactly what I need ! Greetings from Varna!
|
|
|
|
|
Hello and thank you for the message! Varna rocks!
|
|
|
|
|
(Originally posted: 2007-09-26)
The __arglist keyword can be very useful. It returns an argument list handle for the current method. By calling __arglist a pointer to the argument list is pushed on the stack.
Application:
In the new OLM Inventory application, the backend interactions are abstracted to a few methods:
. public static void BuildQuery(out string sql_cmd, out OleDbParameter[] sql_params, int mode, string tbl, string input, __arglist)
. public static int ExecNonQuery(string sql_cmd, OleDbParameter[] sql_params)
. public static List<Object> ExecQuery(Type rcrd_type, string sql_cmd, OleDbParameter[] sql_params)
The BuildQuery method has to be flexible enough to work with unknown number of arguments representing the query parameters. Thus we use the __arglist keyword as shown in this excerpt:
public static void BuildQuery(out string sql_cmd, out OleDbParameter[] sql_params, int mode, string tbl, string input, __arglist)
{
sql_params = null;
sql_cmd = String.Empty;
try
{
string[] rcrd_params = input.Split(new Char[] { ',' });
ArgIterator param_iter = new ArgIterator(__arglist);
int param_count = param_iter.GetRemainingCount();
if (param_count != rcrd_params.Length)
{
ErrorLogDataSource.LogError(String.Format(
"Failed to build query with {1}/{2} parameters",
param_count, rcrd_params.Length));
return;
}
sql_params = new OleDbParameter[param_count];
sql_cmd = String.Empty;
for (int i = 0; i < param_count; i++)
{
Object param = TypedReference.ToObject(param_iter.GetNextArg());
sql_params[i] = new OleDbParameter(rcrd_params[i], param);
}
} catch (Exception ex)
{
sql_cmd = String.Empty;
sql_params = null;
ErrorLogDataSource.LogException(new Exception(
String.Format("Failed to build query for {1} with {2} in {3} mode - {0}",
ex.Message, tbl, input, mode),
ex));
}
}
Here is a sample call to BuildQuery:
public static List<Object> GetStatusTypes(int ID, string Name, string Description, bool Reload, int UserID)
{
if ((!isCached) || (Reload))
{
DataSourceAdapter.BuildQuery(out sql_cmd, out sql_params, 3, tbl_name, "Name,Description,ID,ID", __arglist("%", "%", -1, -1));
cache = DataSourceAdapter.ExecQuery(typeof(StatusType), sql_cmd, sql_params);
isCached = true;
listFilter = null;
}
}
Reference:
. Hidden Keywords[^]
. Variable argument list
|
|
|
|
|
(Originally posted: 2007-10-24)
Services running on your machine are defined in the registry at:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services
You can manually edit the registry to change service settings or you can use the SC windows command on the command prompt.
DESCRIPTION:
SC is a command line program used for communicating with the
NT Service Controller and services.
USAGE:
sc <server> [command] [service name] <option1> <option2>...
The option <server> has the form "\\ServerName"
Further help on commands can be obtained by typing: "sc [command]"
Commands:
query-----------Queries the status for a service, or
enumerates the status for types of services.
queryex---------Queries the extended status for a service, or
enumerates the status for types of services.
start-----------Starts a service.
pause-----------Sends a PAUSE control request to a service.
interrogate-----Sends an INTERROGATE control request to a service.
continue--------Sends a CONTINUE control request to a service.
stop------------Sends a STOP request to a service.
config----------Changes the configuration of a service (persistant).
description-----Changes the description of a service.
failure---------Changes the actions taken by a service upon failure.
qc--------------Queries the configuration information for a service.
qdescription----Queries the description for a service.
qfailure--------Queries the actions taken by a service upon failure.
delete----------Deletes a service (from the registry).
create----------Creates a service. (adds it to the registry).
control---------Sends a control to a service.
sdshow----------Displays a service's security descriptor.
sdset-----------Sets a service's security descriptor.
GetDisplayName--Gets the DisplayName for a service.
GetKeyName------Gets the ServiceKeyName for a service.
EnumDepend------Enumerates Service Dependencies.
The following commands do not require a service name:
sc <server> <command> <option>
boot------------(ok | bad) Indicates whether the last boot should
be saved as the last-known-good boot configuration
Lock------------Locks the Service Database
QueryLock-------Queries the LockStatus for the SCManager Database
EXAMPLE:
sc start MyService
|
|
|
|
|
(Originally posted: 2008-02-15)
qwinsta
Display information about Terminal Sessions.
QUERY SESSION [sessionname | username | sessionid]
[/SERVER:servername] [/MODE] [/FLOW] [/CONNECT] [/COUNTER]
sessionname Identifies the session named sessionname.
username Identifies the session with user username.
sessionid Identifies the session with ID sessionid.
/SERVER:servername The server to be queried (default is current).
/MODE Display current line settings.
/FLOW Display current flow control settings.
/CONNECT Display current connect settings.
/COUNTER Display current Terminal Services counters information.
rwinsta
Reset the session subsytem hardware and software to known initial values.
RESET SESSION {sessionname | sessionid} [/SERVER:servername] [/V]
sessionname Identifies the session with name sessionname.
sessionid Identifies the session with ID sessionid.
/SERVER:servername The server containing the session (default is current).
/V Display additional information.
. Managing Terminal Services Sessions Remotely[^]
|
|
|
|
|
(Originally posted: 2007-10-24)
Tip: When you disconnect the adaptor (or most serial port devices like a modem bluetooth IrDA device) the COM port remains allocated but does not show up in Device Manager, however you can re-use that COM port by manually selecting it if you know that it is really free. As far as I know the only way to completely free that COM port so that it is not reported as “In Use” is to plug the device in so that it shows up in device manager, then right click it and choose uninstall (or to go into the registry and manually remove the assignment).
Tools:
. Free Serial Port Monitor[^]
Reference:
. USB to serial adapter review[^]
. A diagnostic procedure[^]
|
|
|
|
|
(Originally posted: 2007-08-24)
A Solution
<style type='text/css'>
.TableContainer div {
width:900px;
padding-bottom: 20px;
overflow-x:auto;
overflow-y:hidden;
}
.locked {
position: relative;
}
</style>
This solution provides only a horizontal scroll bar. In IE, it also freezes the first column, so that the Edit buttons are always visible. The behaviour in Firfox differs.
Note: A bug in IE6.0 places Dropdown lists on top of all other elements independent of their z-index style property. There are few available hacks (using IFrame) to address the problem but they apply better in dealing with page menus rather than controls in the same div element. For more details:
. CSS Positioning[^]
. IE6, SELECT and Z-index Problem Resolution[^]
. Select Element Z-index ignored by IE6 - Workaround[^]
Horizontal And Vertical Scrolling
Ideally, the header, the footer and the first column of the grid view control can be frozen. One clever solution is to apply scrolling at two different levels - the div element containing the table and the tbody element of the table.
<style type='text/css'>
.TableContainer div{
width:800px;
padding-bottom: 20px;
overflow-x:auto;
overflow-y:hidden;
}
.locked {
position: relative;
}
.TableContainer tbody{
height:300px;
overflow-x:hidden;
overflow-y:auto;
padding-right: 20px;
}
.TableContainer tbody tr {
height: auto;
white-space: nowrap;
}
</style>
When we scroll the tbody vertically, the header and the footer of the table are not affected by design (fails not in IE6.0).
When we scroll the div element horizontally, the first column is not affected if its style position is set to relative (fails in Firefox).
. CSS position property[^]
. CSS positioning properties[^]
Note: In order to have access to the thead, tbody, and tfooter sections of the grid view table representation, they have to be programatically added after the grid is data-bound. For example, call the following funciton during the grid's OnPreRender event.
private void MakeAccessible(GridView grid)
{
if (grid.Rows.Count > 0)
{
grid.UseAccessibleHeader = true;
grid.HeaderRow.TableSection = TableRowSection.TableHeader;
grid.FooterRow.TableSection = TableRowSection.TableFooter;
if (grid.TopPagerRow != null)
{
grid.TopPagerRow.TableSection = TableRowSection.TableHeader;
}
if (grid.BottomPagerRow != null)
{
grid.BottomPagerRow.TableSection = TableRowSection.TableFooter;
}
}
}
. Make the GridView control accessible[^]
. Avoid out of order Pager rows: The table must contain row sections in order of header, body, then footer[^]
Explicit Position Calculation
The following javascript functions help setup a listener for the scrolling event and recalculate the positions of the elements on the fly. This approach allows to explicitely set the position style values and avoids the pitfalls of css behaviour interpretations by the different browsers. However, it requires more research and testing before the implementation can be successfully completed...
<script type="text/javascript">
function getElementsByClassName(oElm, strTagName, oClassNames){
var arrElements = (strTagName == "*" && oElm.all)? oElm.all : oElm.getElementsByTagName(strTagName);
var arrReturnElements = new Array();
var arrRegExpClassNames = new Array();
if(typeof oClassNames == "object"){
for(var i=0; i<oClassNames.length; i++){
arrRegExpClassNames.push(new RegExp("(^|\s)" + oClassNames[i].replace(/-/g, "\-") + "(\s|$)"));
}
}
else{
arrRegExpClassNames.push(new RegExp("(^|\s)" + oClassNames.replace(/-/g, "\-") + "(\s|$)"));
}
var oElement;
var bMatchesAll;
for(var j=0; j<arrElements.length; j++){
oElement = arrElements[j];
bMatchesAll = true;
for(var k=0; k<arrRegExpClassNames.length; k++){
if(!arrRegExpClassNames[k].test(oElement.className)){
bMatchesAll = false;
break;
}
}
if(bMatchesAll){
arrReturnElements.push(oElement);
}
}
return (arrReturnElements)
}
function OnScroll(){
var cells = getElementsByClassName(document.getElementByID("div_OLMGridView"), "td", "locked");
for (var i = 0; i < cells.length; i++){
cells[i].style.left = cells[i].offsetParent.scrollLeft;
}
}
function GetScroller(){
var scroller = null;
var divs=document.getElementsByTagName('div');
for (var i = 0; i < divs.length; i++) {
if (divs[i].parentNode.getAttribute('class') == "TableContainer"){
scroller = divs[i];
break;
}
}
return (scroller);
}
function AddScrollListener(){
var scroller = GetScroller();
if (scroller != null){
if (scroller.addEventListener){
scroller.addEventListener('scroll', OnScroll, false);
} else if (scroller.attachEvent){
scroller.attachEvent('scroll', OnScroll);
}
}
}
window.onload = function(){AddScrollListener();}
</script>
In IE, exression() can be used to dynamically set style properties.
. IE Dynamic Properties[^]
For example,
<DIV STYLE="background-color: #CFCFCF; position: absolute;
left:expression(document.body.clientWidth/2-oDiv.offsetWidth/2);
top:expression(document.body.clientHeight/2-oDiv.offsetHeight/2)"></DIV>
However, its use is not recommended:
. CSS expressions in browsers other then IE[^]
. Avoid CSS expressions[^]
References
. ScrollingGrid: A cross-browser freeze-header two-way scrolling DataGrid by Ashley van Gerven[^]
. An ASP.NET DataGrid Custom Control to Freeze Header, Rows, Columns by Tittle Joseph[^]
. Real World GridView: Excel-like Frozen Headers for ASP.NET 2.0[^]
. Lock or Freeze Table Columns plus Non-Scroll Headers - Internet Explorer CSS solution[^]
. Freeze table header in Mozilla[^]
. Implementing a Fixed GridView Header in ASP.NET[^]
|
|
|
|
|
(Originally posted: 2007-09-26)
There are two Delphi functions defined in Classes that are employed in order to allow for a class to be instantiated given its class name:
. function GetClass(const ClassName: string): TPersistentClass;
. procedure RegisterClass(AClass: TPersistentClass);
The Class must be registered before GetClass can find it. Form classes and component classes that are referenced in a form declaration (instance variables) are automatically registered when the form is loaded. Other classes can be registered by calling RegisterClass or RegisterClasses.
Details:
Delphi help files
Application:
The UPOS Specification[^] is followed in an attempt to standardize the implementation of Vivonet POS Devices. Thus each POS device is derived from the TUPOSDeviceControl and TUPOSDeviceService family. A generic interface is provided to create the POS device instances (such as MSR and PinPad) based on their names (supplimented by an ini configuration file that provides the class names for the device in question):
unit uUPOSFactory;
interface
uses
uUPOSDeviceControl,
uUPOSDeviceService;
const
POSDEVICESINIFILE = 'C:\Program Files\Vivonet\iPOS\Client\PosDevices.ini';
function CreateDeviceService(DeviceName: string): TUPOSDeviceService;
function CreateDeviceControl(DeviceName: string): TUPOSDeviceControl;
implementation
uses
IniFiles,
Classes;
function GetClassName(DeviceName: string; DeviceObject: string):string;
var
iniFile: TIniFile;
begin
iniFile := TIniFile.Create(POSDEVICESINIFILE);
Result := iniFile.ReadString(DeviceName, DeviceObject, 'T' + DeviceName + DeviceObject);
iniFile.Free;
end;
function CreateDeviceService(DeviceName: string): TUPOSDeviceService;
var
DeviceClass: TPersistentClass;
begin
try
DeviceClass := GetClass(GetClassName(DeviceName, 'Service'));
Result := TUPOSDeviceService(DeviceClass.Create);
except
Result := nil;
end;
end;
function CreateDeviceControl(DeviceName: string): TUPOSDeviceControl;
var
DeviceClass: TPersistentClass;
begin
try
DeviceClass := GetClass(GetClassName(DeviceName, 'Control'));
Result := TUPOSDeviceControl(DeviceClass.Create);
except
Result := nil;
end;
end;
end.
Inspiration:
Factory Method design pattern
See Also:
Abstract Factory and Builder design patterns
|
|
|
|
|
(Originally posted: 2007-10-03)
. Set Project -> Properties -> Configuration Properties -> Linker -> Debugging -> Generate Debug Info
. Set Tools -> Options -> Debugging -> Native -> Enable RPC Debugging
. Ensure that the user account under which the application will run has enough privileges (e.g., it is part of Debugger Users). Alternatively, set the Component application identity as follows: <Component> Properties -> Identity -> System Account -> Interactive User
References:
. How to: Debug COM+ 1.0 Components[^]
. Debugging an W32 App[^]
|
|
|
|
|
|