FolderMon

20 November 2008 - 1 pv 2 t sitten.

Pieni apuohjelma joka valvoo sopivaa kansiota ja kun sinne tulee sopiva tiedosto niin aukaisee sen kyseisellä ohjelmalla. Tuli sitten väsättyä tämmöinen kun ei flash pelit enään huvittanut.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
/* 
    Need a small utility which chould be started to run in the background and monitors a folder 
    for specific files when it finds a file it should open it with an application. 
 
    I have an application on the server which creates files for users in their
    folder (e.g. "\\server\user"), I need a client side program which should 
    run on the users computer and monitor that folder (local or network share) 
    and open the file when it finds it.
 
    Program should be self contained as a single executable file and should not need 
    an installer or any additional libraries/files.
 
    The program should take command line arguments as described further, when 
    started with no arguments the program should just output a message box with brief 
    usage instructions.
 
    The program should not open the file untill the server finishes writing it.
    Program needs no GUI and needs to be run in the background untill killed or 
    computer is shut down.
 
    Program should use minimum resources (less than 5MB ram and less that 2% CPU).
    Variables need to be expanded in the arguments (e.g. %username%)
    The system should not stop working or give any errors if it can't find the 
    path that it monitors (e.g. a network drive that got disconnected) even for
    extended periods of time, should also not crash for any other errors.
 
    The arguments it needs to take:
    /f:<folder to watch> -  /f:"C:\Temp" or /f:"\\server\user\%username%"
    /e:<file extensions to watch>  -    /e:*.txt
    /x:<application to open file>    -    /x:"C:\WINDOWS\NOTEPAD.EXE" 
      (if "" is used or /X: is omitted use default windows program for this filetype)
    /d - optional, if present delete all files in the watched folder when started
 
    FolderMon.exe /f:"\\server\%username% /e:*.txt /x:"C:\WINDOWS\NOTEPAD.EXE" /d
    Developer should fix any bugs if found in the first 3 months after 
    payment without any charge.
 
    Program should keep a log file (in the same path as the executable file is)
    which should log every action (date-time, filename found whetrher opened  etc.),
    the log file should be deleted when the program starts 
    (to avoid getting large log files).
 
    Program should run with normal "User" rights 
 */
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Collections.Specialized;
using System.Text.RegularExpressions;
using System.IO;
using System.Diagnostics;
using System.Threading;
 
namespace FolderMon
{
    public partial class FolderMon : Form
    {
        String Folder;
        String Extension;
        String Application;
        Boolean Delete;
 
        public FolderMon()
        {
            InitializeComponent();
        }
 
        /// <summary>
        /// Application main logic is here.
        /// </summary>
        private void Form1_Load(object sender, EventArgs e)
        {
            // Hide window
            this.WindowState = FormWindowState.Minimized;
            this.ShowInTaskbar = false;
            this.Visible = false;
 
            // Handle command line switchs.
            HandleCommandLine();
 
            // Delete old log file
            File.Delete(Program.AppPath() + "FolderMon.txt");
 
            // Log parameters file.
            Program.LogMessageToFile("Application started");
            Program.LogMessageToFile("Folder: " + Folder);
            Program.LogMessageToFile("Extension: " + Extension);
            Program.LogMessageToFile("Application:" + Application);
            Program.LogMessageToFile("Delete: " + (Delete ? "True" : "False"));
 
            // Delete all files in Watching folder if /D is used.
            if (Delete)
            {
                string[] List = Directory.GetFiles(Folder);
                foreach (string f in List)
                {
                    FileInfo fi = new FileInfo(f);
                    fi.Delete();
                }
            }
 
            // Create a new FileSystemWatcher and enable it.
            FileSystemWatcher watcher = new FileSystemWatcher();
            watcher.Filter = Extension;
            watcher.Created += new
            FileSystemEventHandler(watcher_FileCreated);
            watcher.Path = Folder;
            watcher.EnableRaisingEvents = true;
        }
 
        /// <summary>
        /// Handle the command line.
        /// </summary>
        void HandleCommandLine()
        {
            //create an instance of the parser
            String[] args = Environment.GetCommandLineArgs();
            CommandLineParser parser = new CommandLineParser(args);
            const string Help = "FolderMon /f:\"C:\\foo\" /e:\"*.txt\"\n\n" +
                                "/f:<folder to watch>\n" +
                                "/e:<file extensions to watch>\n" +
                                "/x:<application to open file> (optional)\n" +
                                "/d delete all files in the watched folder(optional)";
 
            if (parser["f"] != null)
                Folder = Environment.ExpandEnvironmentVariables(parser["f"]); 
            else
            {
                MessageBox.Show(Help,"FolderMon");
                Environment.Exit(0);
            }
            if (parser["e"] != null)
                Extension = parser["e"];
            else
            {
                MessageBox.Show(Help, "FolderMon");
                Environment.Exit(0);
            }
            if (parser["x"] != null)
                Application = Environment.ExpandEnvironmentVariables(parser["x"]);
            if (parser["d"] != null)
                Delete = true;                       
        }
 
        /// <summary>
        /// Run when new file is created to watch folder.
        /// </summary>
        void watcher_FileCreated(object sender, FileSystemEventArgs e)
        {
            String run;
 
            if(Application != null)
                run = Application + e.FullPath;
            else
                run = e.FullPath;
 
            Program.LogMessageToFile("Run: " + run);
            System.Diagnostics.Process.Start(run);
        }
    }
 
    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main()
        {
            Application.ThreadException += new ThreadExceptionEventHandler(
                 Application_ThreadException);
 
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new FolderMon());
        }
 
        /// <summary>
        /// Custom error handler.
        /// </summary>
        private static void Application_ThreadException(object sender, ThreadExceptionEventArgs e)
        {
            string errorMsg = "An error occurred please contact the adminstrator " +
                              "with the following information:\n\n";
            errorMsg = errorMsg + e.Exception.Message + "\n\nStack Trace:\n" + e.Exception.StackTrace;
            LogMessageToFile(errorMsg);
            // Application.ExitThread(); 
        }
 
        /// <summary>
        /// Return application path. 
        /// Hack: Best way?
        /// </summary>        
        internal static string AppPath()
        {
            return Application.StartupPath + "\\";
            //return System.Environment.CurrentDirectory;
        }
 
        /// <summary>
        /// Write simple log file.
        /// </summary>        
        internal static void LogMessageToFile(string msg)
        {
            System.IO.StreamWriter sw = System.IO.File.AppendText(
                AppPath() + "FolderMon.txt");
            try
            {
                string logLine = System.String.Format(
                    "{0:G}: {1}", System.DateTime.Now, msg);
                sw.WriteLine(logLine);
            }
            finally
            {
                sw.Close();
            }
        }
    }
 
 
    public class CommandLineParser
    {
        private StringDictionary parameters;
 
        public CommandLineParser(string[] arguments)
        {
            //create our stringDictionary Object for holding
            //the resulting key/value pairs
            parameters = new StringDictionary();
 
            //create a RegEx Object for splitting the parameters
            Regex paramSplit = new Regex(@"^-{1,2}|^/|=|:", RegexOptions.IgnoreCase | RegexOptions.Compiled);
 
            //create a RegEx Object for removing trailing & 
            //leading single and double quotes
            Regex paramRemover = new Regex(@"^['""]?(.*?)['""]?$", RegexOptions.IgnoreCase | RegexOptions.Compiled);
 
            string param = null;
            string[] paramParts;
            //loop through each item in the arguments array
            foreach (string str in arguments)
            {
                //split the parameter array
                paramParts = paramSplit.Split(str, 3);
                //use a switch statement to tell the parser what
                //to do for each possible length of the array
                switch (paramParts.Length)
                {
                    case 1:
                        if (param != null)
                        {
                            if (!parameters.ContainsKey(param))
                            {
                                paramParts[0] = paramRemover.Replace(paramParts[0], "$1");
                                parameters.Add(param, paramParts[0]);
                            }
                            param = null;
                        }
                        break;
                    //here we found just a parameter
                    case 2:
                        // The last parameter is still waiting. 
                        // With no value, set it to true.
                        if (param != null)
                        {
                            if (!parameters.ContainsKey(param))
                                parameters.Add(param, "true");
                        }
                        param = paramParts[1];
                        break;
                    //here we found a parameter with a value
                    case 3:
                        // The last parameter is still waiting. 
                        // With no value, set it to true.
                        if (param != null)
                        {
                            if (!parameters.ContainsKey(param))
                                parameters.Add(param, "true");
                        }
                        param = paramParts[1];
                        // Remove possible enclosing characters (",')
                        if (!parameters.ContainsKey(param))
                        {
                            paramParts[2] = paramRemover.Replace(paramParts[2], "$1");
                            parameters.Add(param, paramParts[2]);
                        }
                        param = null;
                        break;
                }
            }
            // In case a parameter is still waiting
            if (param != null)
            {
                if (!(parameters.ContainsKey(param)))
                {
                    parameters.Add(param, "true");
                }
            }
        }
 
        /// <summary>
        /// indexer to retrieve the parameters value if it exists
        /// </summary>
        /// <param name="param">parameter we want the value for</param>
        /// <returns></returns>
        public string this[string param]
        {
            get
            {
                return (parameters[param]);
            }
        }
    }
}

Perl linkkejä

2 November 2008 - 18 days ago.

Tässä muutama Perl aiheinen linkki.

Erittäin lyhyt Perl opas.
http://users.tkk.fi/~mtniemi/ohjelmointi/perl.html

Pieni johdanto perliin.
http://www.2kmediat.com/internetohjelmointi/default.asp#perl

Pieni suomenkielinen perl opas.
http://www.sivut.org/perl/

Mureakuhan perl wiki sivu.
http://wiki.mureakuha.com/wiki/Perl

Perlin dogumentointi tapa.
http://perldoc.perl.org/perlpod.html

Perl 6 kehityssivu.
http://dev.perl.org/perl6/

Muistilappu sisään rakennetuinsta muuttujista.
http://www.catonmat.net/blog/perls-special-variable-cheat-sheet/

Perl sivusto, 12 artikkelia ohjelmointiin.
http://sial.org/howto/perl/

Perl keittokirja (aika vanha).
http://www.unix.com.ua/orelly/perl/cookbook/index.htm

Ohjelmointi vinkkejä.
http://www.perlhowto.com

Muovikassit kolmioksi

31 October 2008 - 20 days ago.

Vihdoinkin löysin käytännön ohjeen kuinka muovikassit saa taiteltua vähän tilaa vieviksi kolmioksi. Täytyykin huomioida että nettiin on ilmestynyt huvi videoitten lisäksi oma kategoria tee itse videoille. Ehkä uusavuttomalla nörtillä on sitenkin toivoa.

Flash pelejä

13 October 2008 - 1 kk 8 pv sitten.

Se on taas maanantai, mutta mitään järkevää ei ole tullut saatua aikaiseksi. Oikeastaan koko päivä on mennyt webissä surffatessa ja pelatessa flash pelejä. Oma top 3:

Google - 10 vuotta

4 October 2008 - 1 kk 17 pv sitten.

Google täytti 10 vuotta, pari päivää sitten. Pyöreän juhlan kunniaksi julkaistiin historiallinen google versio vuodelta 2001. Voi hetken aikaa miettiä retro meininkiä ja googlettaa vaikka omia vanhoja webbi sivujaan.

Voisi väittää että webin luonne on kaupunkilaistunut. Keskustelu on muuttunut pienestä kylä yhteisöstä kaupinkimaiseksi omassa piireissä oleviin sosiaalisiin yhteisöihin. Ulkoasu on parantunut ja tarjontaa on tullut lisää.

Death Dice Overdose

30 September 2008 - 1 kk 21 pv sitten.

Tuntuuko että paikka lataamossa on lähellä? Rauhoitu ja vähennä stressiä pelaamalla jotain rauhoittavaa flash peliä.

Death Dice Overdose:ssa väistellään kohtalon heittelemiä noppia! Suuret taivaalta putoilevat nopat aiheuttavat ymmärrettävästi paniikkia sankarissamme, joten kerää lääkkeitä pysyäksesi järjissäsi. Kun popsit tarpeeksi pillereitä niin pääset overdose tilaan jossa rauhallisimmatkin epilepsikot saavat oireita. Tämä kaikki höystettynä tracker musiikin kanssa on oman laatuinen kokemus.

Päivitystä

17 September 2008 - 2 kk 4 pv sitten.

Rauha maassa ja tietokone pari viikkoa pois käytästä. Ensimmäinen käynnistys ja päivitys rulianssi alkaa. Haluatko päivittää ilmoitus x kertaa ja sähköpostilaatikko tupaten täynnä. Hiljainen palaaminen takaisin arkeen ei oikein tunnu onnistuvan.

C# merkkijono suorituskyky testi

13 August 2008 - 3 kk 10 pv sitten.

Tässä on pieni suorituskyky testi C#:llä, joka vertailee merkkijonojenen merkkien käsittelyä eri toimintatavoilla.

Testin tulokset:

28218,75 ns per operation (RegEx)
765,63 ns per operation (StringBuilder)
687,50 ns per operation (char taulukot)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Testi1
{
    class Program
    {
        static void Main(string[] args)
        {
            int loopCount = 1000000;
            long startTime, endTime;
            double nanoseconds;
 
            startTime = DateTime.Now.Ticks * 100;
            for (int x = 0; x &lt; loopCount; x++)
            {
                ExtractNumbers1("Its is only 4 numbers but must be 1337");
            }
            endTime = DateTime.Now.Ticks * 100;
            nanoseconds = ((double)(endTime - startTime)) / ((double)loopCount);
            Console.WriteLine(nanoseconds.ToString("F") + " ns per operation");
 
            startTime = DateTime.Now.Ticks * 100;
            for (int x = 0; x &lt; loopCount; x++)
            {
                ExtractNumbers2("Its is only 4 numbers but must be 1337");
            }
            endTime = DateTime.Now.Ticks * 100;
            nanoseconds = ((double)(endTime - startTime)) / ((double)loopCount);
            Console.WriteLine(nanoseconds.ToString("F") + " ns per operation");
 
            startTime = DateTime.Now.Ticks * 100;
            for (int x = 0; x &lt; loopCount; x++)
            {
                ExtractNumbers3("Its is only 4 numbers but must be 1337");
            }
            endTime = DateTime.Now.Ticks * 100;
            nanoseconds = ((double)(endTime - startTime)) / ((double)loopCount);
            Console.WriteLine(nanoseconds.ToString("F") + " ns per operation");
 
            Console.Read();
        }
 
        static string ExtractNumbers1(string expr)
        {
            return string.Join(null, System.Text.RegularExpressions.Regex.Split(expr, "[^\\d]"));
        }
 
        static string ExtractNumbers2(string expr)
        {
            StringBuilder sb = new StringBuilder(expr.Length);
 
            foreach (char ch in expr)
            {
                if (Char.IsDigit(ch))
                    sb.Append(ch);
            }
 
            return sb.ToString();
        }
 
        static string ExtractNumbers3(string expr)
        {
            char[] nums = new char[expr.Length];
            int pos = 0;
 
            foreach (char ch in expr)
            {
                if( Char.IsDigit( ch ))
                    nums[pos++] = ch;
            }
 
            return new string ( nums, 0, pos );
        }
    }
}

Rinnakkaislaskentaa

4 August 2008 - 3 kk 18 pv sitten.

Intel suosittelee algoritmien suunnittelemisen rinnakkaislaskentaan soveltuvaksi ja AMD työpöydällä on 12 ytiminen prosessori. Siinä missä prosessori valmistajat lisäävät ytimiä prosessoriin niin tavallisen koodaajan päänsärky vain kasvaa.

Tavallisten algoritmien muuttaminen rinnakkaisalgoritmaiksi ei varmaan ole mitään herkkua. Jotta moniydin arkkitehtuurista saataisiin käytännön laskentatehoa irti pitäisi sovelluskirjastot suunnitella uudestaan.

Olen aistivinani tässä ohjelmistokehityksen tulevan virstanpylvään.

C# Laajennetut luokat

24 July 2008 - 3 kk 29 pv sitten.

Tuli luettua C# kielioppia. Mukavana ominaisuutena huomasin että nykyään pystytään (versiosta 3.0 lähtien) laajentamaan valmiita kirjastoluokkia. Tämä avaa mukavia mahdollisuuksia poistaa itseään häiritseviä piirteitä.

Laajennuksen tekeminen onnistuu lisäämällä this sana metodin parametrin määrittelyyn. Alla esimerkki string luokan laajennuksesta.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Globalization;
using System.Text.RegularExpressions;
 
namespace StringExtensions
{
    public static class StringExtensions
    {
        /// <summary>
        /// Remove any non-numeric characters and then return the resultant string.
        /// Useful for parsing phone numbers.
        /// </summary>
        /// <param name="s">The text that is to be evaluated.</param>
        /// <returns>New string</returns>                 
        public static string RemoveNonNumeric(this string s)
        {
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < s.Length; i++)
                if (Char.IsNumber(s[i]))
                    sb.Append(s[i]);
            return sb.ToString();
        }
 
        /// <summary>
        /// Returns the substring of the first argument string that follows the first occurrence 
        /// of the second argument string in the first argument string, or the empty 
        /// string if the first argument string does not contain the second argument string.
        /// </summary>
        /// <param name="source">The text that is to be evaluated.</param>
        /// <param name="value">String to search.</param>
        /// <returns>New string</returns>
        public static string SubstringAfter(this string source, string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return source;
            }
            CompareInfo compareInfo = CultureInfo.InvariantCulture.CompareInfo;
            int index = compareInfo.IndexOf(source, value, CompareOptions.Ordinal);
            if (index < 0)
            {
                //No such substring
                return string.Empty;
            }
            return source.Substring(index + value.Length);
        }
 
        /// <summary>
        /// Returns the substring of the first argument string that precedes the first occurrence of 
        /// the second argument string in the first argument string, or the empty string if 
        /// the first argument string does not contain the second argument string.
        /// </summary>
        /// <param name="source">The text that is to be evaluated.</param>
        /// <param name="value">String to search.</param>
        /// <returns>New string</returns>
        public static string SubstringBefore(this string source, string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                return value;
            }
            CompareInfo compareInfo = CultureInfo.InvariantCulture.CompareInfo;
            int index = compareInfo.IndexOf(source, value, CompareOptions.Ordinal);
            if (index < 0)
            {
                //No such substring
                return string.Empty;
            }
            return source.Substring(0, index);
        }
 
        /// <summary>
        /// Truncate string using dots...
        /// Useful for displaying long filename paths.
        /// </summary>
        /// <param name="s">String to be truncated.</param>
        /// <param name="maxLength">Maximum string size</param>
        /// <returns>New string</returns>
        public static string Truncate(this string s, int maxLength)
        {
            if (string.IsNullOrEmpty(s) || maxLength <= 0)
                return string.Empty;
            else if (s.Length > maxLength)
                return s.Substring(0, maxLength) + "...";
            else
                return s;
        }
 
        /// <summary>
        /// Reverse string.
        /// </summary>
        /// <param name="s">String to be reversed.</param>
        /// <returns>Reversed string.</returns>
        public static string Reverse(this string s)
        {
            char[] c = s.ToCharArray();
            Array.Reverse(c);
            return new string(c);
        }
 
        /// <summary>
        /// Test if string contains only numbers.        
        /// </summary>
        /// <param name="text">The text that is to be evaluated.</param>
        /// <returns>True if text included only letters.</returns>
        public static bool IsAlpha(this string text)  
        {            
            foreach (char c in text.ToLower())  
            {  
                if (!char.IsLetter(c))
                    return false;  
            }  
            return true;  
        }
 
        /// <summary>
        /// Check is string is valid email address.
        /// </summary>
        /// <param name="email">Email to be checked.</param>
        /// <returns>True if email address was ok.</returns>        
        public static bool IsValidEmailAddress(this string email)
         {             
             const string REGEX_VALID_EMAIL =
                 @"^([\w-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|" +
                 @"(([\w-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$";
             bool valid = Regex.IsMatch(email, REGEX_VALID_EMAIL);
             return valid;
         }
 
        /// <summary>
        /// Convert string to integer.
        /// </summary>
        /// <param name="s">String to be processed.</param>
        /// <returns>Integer</returns>
        public static int ToInteger(this string s)
        {
            int integerValue = 0;
            int.TryParse(s, out integerValue);
            return integerValue;
        }
 
        /// <summary>
        /// Compare two strings, ignore case.
        /// </summary>
        /// <param name="s1">String 1</param>
        /// <param name="s2">String 2</param>
        /// <returns>If equal return true.</returns>
        public static bool Comparei(this string s1, string s2)
        {
            CompareInfo Compare = CultureInfo.InvariantCulture.CompareInfo;
            int i = Compare.IndexOf(s1, s2, CompareOptions.IgnoreCase);
            if (i != 0 )
                return true;
            else
                return false;
        }
    }
}