You have to have some Apple i* products though I think to truly appreciate this…
http://www.4shared.com/file/74031012/a779e2a7/The_Simpsons_-_Mapple.html
Information about joeware mixed with wild and crazy opinions...
You have to have some Apple i* products though I think to truly appreciate this…
http://www.4shared.com/file/74031012/a779e2a7/The_Simpsons_-_Mapple.html
It just rocks… I had to clean up a bunch of photos with red eye reduction etc and it just did it for me…
Good software that just works.™
Have you been around long enough to remember ASCII art… You can generate some with the code at the following link:
http://www.codeproject.com/KB/recipes/ASCII_Imager.aspx
Dear joe,
The next time you get an error 0x8007232B aka DNS name does not exist on Vista or Windows Server 2008 don’t forget to do
slmgr.vbs –ipk “activation key”
slmgr.vbs –ato
thanks, joe
The primary updates I was looking to put into AdFind V01.39.00 are now done. Now I am adding/updating shortcuts. After that, I have to do the part I hate the most, update the usage… Ugh.
As I look at the usage I think, I really need to write a book that goes into depth on all of the switches and variations thereof and what you can do with it because I don’t even recall all of the cute pieces I put into it at this point. I visualized a book on AdFind/AdMod before. It was sort of an AD/LDAP primer with basic ideas explained and then sort of a cookbook / reference for AdFind/Admod. That is a lot of work though and would be something I would write and then use something like cafepress to publish to pay for the labor it would take as I couldn’t get other tool type stuff done while working on it.
Here is the rough listing of what was done so far from V01.37.00 (don’t mind the typos, people don’t usually get to see this…). I will discuss the changes more in depth later, maybe. 😉
//* V01.38.00 2007.0630 o 06/30 Add more longhorn decodes *
//* Changed -noctl to display chars *
//* -csv now sets -noctl *
//* Removed crash bug in -dn / -dsq *
//* Added -sc admincountdmp *
//* **NEVER RELEASED** *
//* V01.39.00 2008.1022 o 10/22 Add more longhorn decodes *
//* Change references to longhorn *
//* o 10/23 added -rootdseanon *
//* BugFix: Transformed filter display *
//* BugFix: Removed extra line with list*
//* BugFix: Misc usage errors *
//* BugFix: Misc shortcut errors *
//* BugFix: replacedn with csv issue *
//* Added check for y for mvfilter x=y *
//* BugFix: removed trailing space from *
//* generic binary output *
//* o 10/27 Added -nirs and -nirsx *
//* Added useraccountcontrol decodes *
//* Added search flags decodes *
//* Decode schemaFlagsEx *
//* o 10/29 More accurate SD Decode *
//* Arbitrary text for csv header:value*
//* o 11/03 BugFix: CSVquote escape *
//* BugFix: CSVMVDelim escape *
//* Resolve msExchAdmins SID *
//* o 11/04 -rawsddl no longer requires -sddl *
//* o 11/06 Ranging disabled by attr if range *
//* Added -writeable *
//* o 11/07 Added -sslignoresrvcert *
//* o 11/11 If no base specified, use default *
//* o 11/13 Decode objecversion of schema *
//* o 11/16 mvfilter will take attrib and clean *
//* off ;extension for match *
//* o 11/17 Decode dsheuristics *
//* Cleanup metadata output *
//* Added -mvsort and -mvrsort *
//* Updated -sc sdump to have -mvsort *
//* o 11/26 Added -filterbreakdown *
//* Allow multiple values for attr for *
//* mvfilter and mvnotfilter *
//* o 11/27 Added -binenc CURRENT option *
//* o 11/28 Added -enccurrent *
//* Added -tdcd *
//* Decode msPKIRoamingTimeStamp *
Anyway, I am still on schedule for a December release of AdFind V01.39.00….
As you all know, I have been working away on AdFind lately. I added the ability to decode msPKIRoamingTimeStamp to its two components (create and update time). I wanted to test it and because I don’t have that attrib set on my test environments I needed to compile AdFind in a non-debug mode… And my excitement commenced…
Right off I knew something was wrong, the compiler normally spits AdFind.exe out in about 15-30 seconds or so, after 2 minutes it was still chewing on it… Uh oh. Finally boom, 2 errors. The linker blew up with some error (IMP327 Access Violation) I can’t find a solution for for my case, it seems it usually is a problem with large projects but in Debug mode, my problem was in Release mode and it works great in debug mode….
So I started thinking, well debug versus release is a compiler thing so I looked at the OBJ (object file to you non-devs) file and saw that it was about 6 times larger than it normally is… That could definitely be a cause for the linker to get antsy. It shouldn’t blow up like that but I am more concerned about the compiler issue than the linker issue at the moment as I don’t want an OBJ that is normally 2MB or smaller in a debug compile to be 12MB in a release compile…
So I jump out of the IDE and start playing with the command line compiler BCC32 and eventually realize that the problem is related to inline function expansion. This is something you do to increase speed in your apps, but it causes them to get bigger for all but the most trivial of applications. Now this is something I already knew about because Borland started automatically selecting inline function expansion as the default in BDS 2006 and I had to learn to turn it off on each project or have horribly bloated executables. So I had ALREADY turned it off in the IDE…
I then look closer at the message output in CodeGear C++ Builder 2009 and see that the IDE was specifying the switches “-vi-” and “-v-“. These should mean
-vi- : Disable inline function expansion (opposite of -vi : this is the default setting if you specify nothing)
-v- : Disable debug (opposite of -v) The default setting if you don’t specify anything should be -v- (i.e. don’t be in debug)
So that looked right but after extensive testing I realized that the BCC32 compiler has a bug in it. If you specify “-vi-” it will happily disable the inline function expansion, but if you specify “-vi- -v-” it won’t… Theoretically “-vi-” and “-vi- -v-” should be functionally the same, but it isn’t being treated that way with my compiler.
The upshot of all of this is that I have to compile and link by hand at the command line instead of using the nice IDE that I paid so much money for whenever I want to produce a release copy of AdFind right now which annoys the heck out of me.
So I found 3 bugs…
1. “-vi- -v-” should be functionally identical with “-vi-“, they aren’t.
2. The IDE uses “-vi- -v-” instead of “-vi-“
3. The linker blows up because the OBJ produced by compiling with “-vi- -v-” is wrong.
After I finally got it compiled and took it to a network that I thought had the msPKIRoamingTimeStamp attribute set I found out it actually didn’t so I can’t even run the test I wanted to run!!!
joe
More Detail:
I logged this all with Code Gear under Code Gear Quality Central Report 69444
Here are the details in the report (doing this so it can be found by anyone searching for any of these terms on the web)
Running on Windows Vista 32 Bit SP1
There appears to be three problems.
1. BCC32 does something different when using “-vi- -v-” than it does if just specifying “-vi-” w/o “-v-“.
When specifying “-vi- -v-” the compile of my project (sorry I cannot provide the project) is extremely slow taking minutes to complete and when it finally completes the OBJ size is 12,437,373 bytes. When I specify “-vi-” without the “-v-” the project compiles within seconds and has an OBJ size of 1,542,100 bytes. If I specify “-vi- -v” the project compiles within seconds and has an OBJ size of 2,890,523.
If I add the -B switch to compile to ASM, I get sizes of
“-vi-” : 10,271,585
“-vi- -v” : 15,991,499
“-vi -v-” : 88,866,898
Obviously “-v-” is doing something different from not specifying it at all which is unexpected to me from what I see in the usage.
2. In the IDE when I specify release with inline functions not expanded it specifies a command line of “-vi- -v-” instead of “-vi-“, with the above information you can see how that impacts me. I do not see how I can modify that behavior.
3. When “-vi- -v-” is used and the OBJ is 12MB, the linker blows up with an access violation and the following:
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: BSS : 0x00000000 / 0x00400000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: CODE : 0x0000033b / 0x00400000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: DATA : 0x000000b5 / 0x00400000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: DEBSYM : 0x0000000e / 0x00400000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Extdef flags : 0x00000021 / 0x00004000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Extdefs : 0x00000084 / 0x00004000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Import symbols : 0x0000030c / 0x00100000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: OBJ symbols : 0x00000b94 / 0x00100000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Public GSX : 0x00000078 / 0x000c0000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Publics : 0x00000438 / 0x000c0000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: SegRelocs : 0x00000820 / 0x00400000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: StringBlock : 0x00000030 / 0x00400000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: UNKNOWN : 0x00000006 / 0x00400000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Virdefs : 0x00000060 / 0x00020000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: BSS : 0x00000000 / 0x00400000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: CODE : 0x003e4089 / 0x00400000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: DATA : 0x0002dac1 / 0x00400000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Extdef flags : 0x00000000 / 0x00004000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Extdefs : 0x00000000 / 0x00004000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: F:/Dev/Current/CPP/AdFind/Release/AdFind.ilc: 0x00010000 / 0x08000000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: F:/Dev/Current/CPP/AdFind/Release/AdFind.ild: 0x00010000 / 0x08000000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: F:/Dev/Current/CPP/AdFind/Release/AdFind.ilf: 0x00016000 / 0x08000000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: F:/Dev/Current/CPP/AdFind/Release/AdFind.ils: 0x0004b000 / 0x03000000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: F:/Dev/Current/CPP/AdFind/Release/AdFind.tds: 0x00010000 / 0x06000000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Import symbols : 0x00000000 / 0x00100000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: OBJ symbols : 0x00000000 / 0x00100000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Public GSX : 0x0000082c / 0x000c0000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Publics : 0x0000498c / 0x000c0000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: StringBlock : 0x0000000b / 0x00400000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: Virdefs : 0x0000082c / 0x00020000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets : warning : Warning: unknown heap name : 0x08000000 / 0x08000000
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets(2089,3): error : Fatal: Error detected (IMP327)
e:\program files\codegear\rad studio\6.0\Bin\CodeGear.Cpp.Targets(2089,3): error : Fatal: Access violation. Link terminated.
I’m on a roll…
This evening while partaking in a little turkey, ham, mashed potatoes, and some sautéed squash fries and visiting with friends and family the code I needed to write to add delta time filter capability popped into my head and this evening I inserted that code so now you can do something like
F:\Dev\Current\CPP\AdFind\Debug>adfind -default -binenc -f "lastlogontimestamp>={{current:-20d}}" lastlogontimestamp -tdcs
AdFind V01.39.00cpp ***BETA*** Joe Richards (joe@joeware.net) November 2008
Transformed Filter: lastlogontimestamp>=128706070664670000
Using server: JOEWARE-DC1.joeware.local:389
Directory: Windows Server 2003
Base DN: DC=joeware,DC=local
dn:CN=$jricha34,CN=Users,DC=joeware,DC=local
>lastLogonTimestamp: 2008/11/18-20:29:00 Eastern Standard Time
dn:CN=DC2,OU=Domain Controllers,DC=joeware,DC=local
>lastLogonTimestamp: 2008/11/24-09:38:47 Eastern Standard Time
dn:CN=JOEWARE-DC1,OU=Domain Controllers,DC=joeware,DC=local
>lastLogonTimestamp: 2008/11/18-15:53:36 Eastern Standard Time
dn:CN=MBX01,CN=Computers,DC=joeware,DC=local
>lastLogonTimestamp: 2008/11/22-23:34:48 Eastern Standard Time
dn:CN=$joe,CN=Users,DC=joeware,DC=local
>lastLogonTimestamp: 2008/11/17-21:42:24 Eastern Standard Time
dn:CN=mvp,OU=Users,OU=joeware.net,OU=Orgs,OU=Mail,DC=joeware,DC=local
>lastLogonTimestamp: 2008/11/18-08:35:01 Eastern Standard Time
dn:CN=joe,OU=Users,OU=joeware.net,OU=Orgs,OU=Mail,DC=joeware,DC=local
>lastLogonTimestamp: 2008/11/18-16:36:13 Eastern Standard Time
dn:CN=listmail1,OU=Users,OU=joeware.net,OU=Orgs,OU=Mail,DC=joeware,DC=local
>lastLogonTimestamp: 2008/11/25-23:37:40 Eastern Standard Time
dn:CN=support,OU=Users,OU=joeware.net,OU=Orgs,OU=Mail,DC=joeware,DC=local
>lastLogonTimestamp: 2008/11/18-22:48:57 Eastern Standard Time
9 Objects returned
Which basically says, show me all objects that have the lastLogonTimeStamp attribute updated with a value from the last 20 days. You could also do –20m for last 20 minutes. Or if you want to be very specific you can specify the days, hours, minutes and seconds with a dd:hh:mm:ss formatted string. The 20 days example would look like –20:00:00:00 or alternately –20:0:0:0.
This will make it even easier for folks to use AdFind for their custom cleanup scripts if OldCmp isn’t doing it for them… Instead of them having to calculate the actual int8 value, they can let AdFind do it for them.
joe
So Happy Thanksgiving to all of my US viewers.
To everyone else, happy last Thursday of November. 🙂
joe
Calmness of the mind is one of the beautiful jewels of wisdom. It is the result of long and patient effort in self control.
…
A man becomes calm in the measure that he understands himself as a thought-evolved being, for such knowledge necessitates the understanding of others as the result of thought, and as he develops a right understanding , and sees more and more clearly the internal relations of things by the action of cause and effect, he ceases to fuss and fume and worry and grieve, and remains poised, steadfast, serene.
…
How many people we know who sour their lives, who ruin all that is sweet and beautiful by explosive tempers, and make bad blood! It is a question whether the great majority of people do not ruin their lives and mar their happiness by lack of self-control.
– James Allen (as a Man Thinketh)
So you have this big nasty LDAP filter and for some reason it isn’t working and by that I mean when you submit the query it comes back and says invalid filter or maybe it doesn’t return what you expect for the data set. You know if you could just see the filter in a “nice” format you could probably figure out what is going on…
Well certainly I have thought that on more than one occasion and usually it was Exchange or sometimes some third party app that generated that nasty LDAP filter that I had to try and figure out what was wrong with…
For example… say you have this lovely filter (some of you may recognize it…)
(& (mailnickname=*) (| (&(objectCategory=person)(objectClass=user)(!(homeMDB=*))(!(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=user)(|(homeMDB=*)(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=contact))(objectCategory=group)(objectCategory=publicFolder)(objectCategory=msExchDynamicDistributionList) ))
Certainly that is easy to read… (reread with sarcastic sneer…)
If you have enough permissions on the Domain Controller you can throw it through AdFind with the -stats+ or -stats+only switches and you get to see something like
Filter Breakdown:
(
(&
(mailNickname=*)
(|
(&
(objectCategory=CN=Person,CN=Schema,CN=Configuration,DC=joeware,DC=local)
(objectClass=user)
(!
(homeMDB=*)
)
(!
(msExchHomeServerName=*)
)
)
(&
(objectCategory=CN=Person,CN=Schema,CN=Configuration,DC=joeware,DC=local)
(objectClass=user)
(|
(homeMDB=*)
(msExchHomeServerName=*)
)
)
(&
(objectCategory=CN=Person,CN=Schema,CN=Configuration,DC=joeware,DC=local)
(objectClass=contact)
)
(objectCategory=CN=Group,CN=Schema,CN=Configuration,DC=joeware,DC=local)
(objectCategory=CN=ms-Exch-Public-Folder,CN=Schema,CN=Configuration,DC=joeware,DC=local)
(objectCategory=CN=ms-Exch-Dynamic-Distribution-List,CN=Schema,CN=Configuration,DC=joeware,DC=local)
)
)
)
which is at least an order of magnitude easier to read.
But what if your filter is…
(& (mailnickname=*) (| (&(objectCategory=person)(objectClass=user)(!(homeMDB=*))((!(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=user)(|(homeMDB=*)(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=contact))(objectCategory=group)(objectCategory=publicFolder)(objectCategory=msExchDynamicDistributionList) ))
and you run that through AdFind…
The filter is syntactically incorrect (can you see the error?) so you will see…
ldap_get_next_page_s: [JOEWARE-DC1.joeware.local] Error 0x57 (87) – Filter Error
Yeah that isn’t so helpful and –stats doesn’t make it any more helpful because there is no stats info coming back from the server. So then you stare at it for a while, curse the LDAP format, maybe twirl your pencil, try to figure out who to send it to to tell you what is wrong with it (and I am not the person despite the hundreds of requests I get to look at LDAP filters…). Etc etc etc ad nauseum… Until finally you paste it into notepad or some other text editor and start manually breaking it up…
I was doing that for like the thousandth time in my career and said, god, someone should write a tool that can parse this out like my AdFind does for the STATS output… and then I sat back, smacked my forehead. Yes, I am not always super bright with things I personally need… So I started looking at the AdFind source to see how easy I could break this little functionality out of that portion of my code. When I did that I also reworked the parsing logic because quite frankly, it did not follow the K.I.S.S philosophy of “Keep It Simple Dumbass”. The new function is cleaner and more stable.
So now you can do something like
F:\Dev\Current\CPP\AdFind\Debug>adfind -filterbreakdown "(& (mailnickname=*) (| (&(objectCategory=person)(objectClass=user)(!(homeMDB=*))((!(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=user)(|(homeMDB=*)(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=contact))(objectCategory=group)(objectCategory=publicFolder)(objectCategory=msExchDynamicDistributionList) ))"
AdFind V01.39.00cpp ***BETA*** Joe Richards (joe@joeware.net) November 2008
Filter Breakdown:
(&
(mailnickname=*)
(|
(&
(objectCategory=person)
(objectClass=user)
(!
(homeMDB=*)
)
(
(!
(msExchHomeServerName=*)
)
)
(&
(objectCategory=person)
(objectClass=user)
(|
(homeMDB=*)
(msExchHomeServerName=*)
)
)
(&
(objectCategory=person)
(objectClass=contact)
)
(objectCategory=group)
(objectCategory=publicFolder)
(objectCategory=msExchDynamicDistributionList)
)
)
WARNING: Parens don’t match up properly, not all open
parens were matched with close parens.
Note: This is not necessarily the filter that the query processor will
process, instead it is a simple text parsing of the supplied filter.
And here is the same filter without the mistake
F:\Dev\Current\CPP\AdFind\Debug>adfind -filterbreakdown "(& (mailnickname=*) (| (&(objectCategory=person)(objectClass=user)(!(homeMDB=*))(!(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=user)(|
(homeMDB=*)(msExchHomeServerName=*)))(&(objectCategory=person)(objectClass=contact))(objectCategory=group)(objectCategory=publicFolder)(objectCategory=msExchDynamicDistributionList) ))"
AdFind V01.39.00cpp ***BETA*** Joe Richards (joe@joeware.net) November 2008
Filter Breakdown:
(&
(mailnickname=*)
(|
(&
(objectCategory=person)
(objectClass=user)
(!
(homeMDB=*)
)
(!
(msExchHomeServerName=*)
)
)
(&
(objectCategory=person)
(objectClass=user)
(|
(homeMDB=*)
(msExchHomeServerName=*)
)
)
(&
(objectCategory=person)
(objectClass=contact)
)
(objectCategory=group)
(objectCategory=publicFolder)
(objectCategory=msExchDynamicDistributionList)
)
)
Note: This is not necessarily the filter that the query processor will
process, instead it is a simple text parsing of the supplied filter.
Still not the EASIEST to see the problem but it is a heck of lot easier to see than it was before.
Here is an example of a non-Exchange related filter
(&(&(objectcategory=person)(objectclass=user)(!(cn=_*))(!(userAccountControl:1.2.840.113556.1.4.803:=65536))(!(isCriticalSystemObject=TRUE)))(&(whenChanged<=20081120000000.0Z)(|(&(whenCreated<=20080926000000.0Z)(|(&(pwdLastSet<=128669508314632476)(lastlogontimestamp<=128669508314632476))(&(pwdLastSet<=128617668314632476)(pwdLastSet>=1))(&(lastlogontimestamp=*)(pwdLastSet=0)(lastlogontimestamp<=128669508314632476))))(&(!(lastlogontimestamp=*))(pwdLastSet=0)(whenCreated<=20081026000000.0Z)))))
and here it is after going through the filter breakdown in AdFind…
(&
(&
(objectcategory=person)
(objectclass=user)
(!
(cn=_*)
)
(!
(userAccountControl:1.2.840.113556.1.4.803:=65536)
)
(!
(isCriticalSystemObject=TRUE)
)
)
(&
(whenChanged<=20081120000000.0Z)
(|
(&
(whenCreated<=20080926000000.0Z)
(|
(&
(pwdLastSet<=128669508314632476)
(lastlogontimestamp<=128669508314632476)
)
(&
(pwdLastSet<=128617668314632476)
(pwdLastSet>=1)
)
(&
(lastlogontimestamp=*)
(pwdLastSet=0)
(lastlogontimestamp<=128669508314632476)
)
)
)
(&
(!
(lastlogontimestamp=*)
)
(pwdLastSet=0)
(whenCreated<=20081026000000.0Z)
)
)
)
)
Its actually sort of readable!!!
This is but one cool change amongst a bunch of changes in the new version of AdFind. As mentioned previously, the goal for the release of AdFind V01.39.00 is sometime towards the end of December.
joe
[joeware – never stop exploring… :) is proudly powered by WordPress.]