Ich kann Git eigentlich nur empfehlen. (wobei Mercurial auch gut funktioniert)
Beides kann man gratis, auch in Teams, für private Projekte auf Bitbucket hosten.
Als hilfreiches GUI-Tool hat sich bei mir SourceTree bewährt.
Wie bereits beschrieben, ist Git ein sehr mächtiges System, aber man muss ja nicht alles nutzen ;) Für manche Mini-Projekte nutze ich auch keinerlei Branches und arbeite nur allein daran.
Dennoch ist es hilfreicht, nicht einen Stand zippen zu müssen um ihn zu archivieren. Auch kann ich jederzeit von überall wo ich Interesse daran hab, kurz in meinen Repos browsen. Ich muss nicht über Sicherungskopien nachdenken. Ich kann in den Commit-Messages bestimmte wichtige Dinge für mich selbst hinterlegen. Auch hilfreich ist, dass klar ist, welche Dinge *wichtig* in einem Projekt sind (die sind nämlich im Versionsverwaltungssystem verfügbar) und was nur Test/Example/QuickHack/Temp-Files sind, die man auch einfacher und ohne Angst entfernen lassen kann.
So oder so, klare Empfehlung: Git. Falls es kompliziert aussieht, sieh es als Weiterbildung ;-)
Hilfreich: Git Book
Um weitere Neuankömmlinge zusätzlich off-topic zu verwirren: Nonzero-Based Arrays sind auch in .NET spezifiziert und in C# erlaubt. Sie sind nur nicht CLS-konform, da nicht alle .NET Sprachen mit ihnen umgehen können. Zudem bietet C# selbst keine eigene Syntax dafür, aber über Array.CreateInstance ist so einiges möglich ;-)
Eigentlich sollte so etwas einwandfrei funktionieren.
Allerdings matchen .NET Regexe direkt Unicode Codepoints und ignorieren alternative Darstellungen. Das Problem ist beispielsweise, dass sich das deutsche Ä als zwei Varianten kodieren lässt:
Ä (U+00C4) (Latin capital letter A with diaeresis)
A (U+0041,U+0308 ) (Latin capital letter A + Combining Diaresis)
Die sehen zwar gleich aus, aber ein Regex mit dem einen findet den anderen nicht - und umgekehrt.
CreateFile "ist" kein Sector-Copy sondern ein File-Copy; jedenfalls in dem Sinne, was ich unter einem Sector verstehe.
Die WinAPI möchte aber den Begriff "File" allgemeiner verstanden wissen, bisweilen so allgemein, dass er meines Erachtens auch "Sector" in deinem Sinne umfassen sollte.
CreateFile was originally developed specifically for file interaction but has since been expanded and enhanced to include most other types of I/O devices and mechanisms available to Windows developers. [...] However, some uses of file may be referring more generally to an I/O object that supports file-like mechanisms. This liberal use of the term file is particularly prevalent in constant names and parameter names because of the previously mentioned historical reasons.
Gibt es denn eine andere API für sector-access in deinem Sinne?
du musst unterscheiden zwischen "E:\" und "\\.\E:".
Das eine ist das Root-Verzeichnis auf der Partition E:, das andere ist die physische Diskpartition E: selbst.
Generell wenn du ein Verzeichnis mit CreateFile öffnen möchtest, musst du FILE_FLAG_BACKUP_SEMANTICS setzen, wofür du zusätzlich noch ein zwei Privilegien (SE_BACKUP_NAME + SE_RESTORE_NAME) benötigst.
Aber eigentlich willst du das ja garnicht, also kommentier dein "\\.\"-Präfix wieder ein, und beachte die Hinweise zu CreateFile:
Zitat
The dwCreationDisposition parameter must have the OPEN_EXISTINGflag.
When opening a volume or floppy disk, the dwShareMode parameter must have the FILE_SHARE_WRITEflag.
Beachte zusätzlich, dass eventuell ein Stream.Seek nur mit festen Sektoren-Größen funktioniert.
Das CharSet sollte egal sein, solange du nicht ExactSpelling bewusst auf die falsche Version von CreateFileA/W setzt. Es wird automatisch die richtige Methode aufgerufen.
Und nach meinen Tests (Win7) unterstützten CreateFileA und CreateFileW beide UNC-Pfade, auch wenn die Ansi-Variante noch immer auf MAX_PATH begrenzt ist.
Zitat von Abt
PS: CreateFile ist nicht für Sector-Copy geeignet, falls das Dein eigentliches Ziel ist.
Meiner Meinung nach ist bei dir (wie bei vielerlei Verschlüsselungstechniken) das Hauptproblem der Schlüsselaustausch.
Wenn du öffentliche Schlüssel austauschen möchtest, brauchst du eine Public-Key-Infrastruktur, oder kurz: irgendeine Trusted Party.
Ich sehe bei deinem Konzept für einen Chatteilnehmer niemanden, der trusted wäre.
Weder das Gegenüber kenne ich vorher, noch bietet dein Server eine authentifizierte Kommunikation. Du nutzt überall nur selbst-signierte Zertifikate, mit all offenen Problemen für beliebige Man-in-the-Middle Angriffe.
Das kannst du nur verhindern, indem du bestehende PKIs nutzt, sei es SSL-CAs oder Alternativen.
Aber so kann ich einfach jeglichen Verkehr vom Client zu deinem Chatserver über mich leiten, MITM spielen und jegliche Verschlüsselung untergraben.
Mit der einfachste Weg aus HTML Seiten gezielt etwas rauszufummeln ist sicherlich über CSS-Selektoren. XPATH kann manchmal etwas klobig sein.
Zudem ist nicht jedes HTML hunderprozentig ein wohlgeformtes XML, was die Verwendung von XML-Technologien manchmal schwierig macht.
Ein Tipp: CsQuery.
Hey,
ich habe mal ein echtes, funktionsfähiges Beispiel formuliert.
Ich habe 25 Studenten, 5 Kurse und Erst- sowie Zweitwünsche mit Strafpunkten (1, 10, 100).
Die Datei course.lp beschreibt das Problem nach oben erklärter Weise im LP-Format.
Hat man nun beispielsweise GLPK installiert, kann man wie folgt das Problem lösen lassen:
[pre]glpsol --lp course.lp -o course.sol[/pre]
Heraus kommt dann die course.sol, in der man die Belegung der Variablen, also die Zuweisung der Studenten zu den Kursen, ablesen kann. Beispielsweise sieht man, dass es keine Lösung gibt, die alle Studenten zufrieden stellt, zwei bekommen nur ihren Zweitwunsch.
Um zu zeigen, dass man auch programmatisch mit den Solvern sprechen kann, habe ich noch ein Programm geschreiben, was selbes Problem löst. Da ich das noch nie mit C# versucht habe, anbei nur ein Python-Programm, welches das PuLP-Framework als Frontend zu den Solvern nutzt: course.py.
Bestenfalls sollte sich etwas Vergleichbares mit C# genauso umsetzen lassen.
beste Grüße
zommi
Die kommerziellen Tools kosten zumeist einige Tausend Euros, sind dafür aber noch flotter, Aber dir reicht sicherlich eine freie Variante. Es gibt auch noch die Microsoft Solver Foundation, habe aber gelesen, dass es wohl nicht mehr weiterentwickelt wird. Aber auch lp_solve hat C#-Wrapper und Google's or-tools bringen auch C# Schnittstellen zu GLPK und CBC mit.
Kommen wir nun mal zum Inhaltlichen, anhand eines Beispiels mit 4 Kursen, 20 Leuten, Erst- und Zweitwünschen.
Wir definieren hierfür 80 (20*4) binäre Variablen bA,Xdie jeweils mit 0/1 dafür stehen, ob nun Person A dem Kurs X zugewiesen wurde.
Wenn also "Klaus" dem Kurs "Optimierung" zugewiesen würde, wäre
Und als Zielfunktion definieren wir eine lineare Größe, die es zu minimieren gilt. Und zwar so, dass es umso kleiner wird, je öfter der Erstwunsch oder Zweitwunsch zugewiesen wird. Wir vergeben also "Strafpunkte". Für einen erfüllten Erstwunsch gibt es einen Strafpunkt, für einen erfüllten Zweitwunsch gibt es 10 Strafpunkte und wenn etwas anderes zugewiesen werden muss, gibt es 100 Strafpunkte.
Im Beispiel hat Klaus als Erst- und Zweitwunsch (Optimierung, Grundlagen), Alice hat (C#, Optimierung), Bernd hat (Algorithmen, Grundlagen).
Das ergibt nun folgende Zielfunktion, die alle 80 Variablen umfasst:
Insgesamt hast du also 80 Variablen, eine Zielfunktion und 28 (Un-)Gleichungen. Das steckst du in einen Solver und heraus kommt eine Belegung deiner Variablen, bei der das Ziel möglichst minimal ist.
Natürlich kannst du noch weitere Bedingungen einbauen, die Strafpunkte anders bemessen, Dritt- und Viertwünschen einführen, etc... Das Modell ist wunderbar erweiterbar.
Das Prinzip konnte ich aber hoffentlich rüberbringen.
Das schöne an ILP (Integer Linear Programming), wenn man einmal das Grundlegende Konzept verstanden hat, kann man irrsinnig viele Optimierungs-Probleme mit geringem Aufwand so darstellen und vor allem Lösen lassen!
Als Schnittstelle zu den Solvern bietet sich an:
Das Problem als Datei generieren in einem der Formate LP, AMPL, ... und den Solver als Unterprozess starten.
Das Problem über einen Wrapper direkt an den Solver als Komponente übergeben.
Vielleicht sieht das jetzt kompliziert aus, aber glaub mir, es ist eigentlich total einfach :)
^ Zeilenanfang
(.*ToLower\(\).*) Irgendwas wo "ToLower()" drin vorkommt
(==|!=) == oder !=
\WTables Whitespace + "Tables"
(.(?!ToLower\(\)))* Irgendein Zeichen, das nicht direkt von "ToLower()" gefolgt wird - beliebig oft
(aka Irgendwas wo "ToLower()" nicht drin vorkommt)
$ Zeilenende
Wobei ab irgendwann ein einfaches String.Split bei == bzw. != mit anschließendem Contains(...) für "ToLower()" und "Tables" auf beiden Seiten sicherlich lesbarer ist.
dein Datenformat sieht doch halbwegs strukturiert aus.
Ich glaube, dass es besser wäre, es direkt zu parsen. Hier im Forum findest du auch einige Beiträge zu Parsern.
Das Format selbst kenne ich nicht, aber vielleicht gibt es sogar schon etwas fertiges?!
Was mir neben einem eigenen Parser oder mühsamen Regexes noch einfallen würde, wäre ein generischer Konverter, der das Format in beispielsweise JSON umwandelnt und es dann parsed. Da sich die Formate etwas ähneln, kann man mit einfachen Ersetzungen ans Ziel kommen.
Da ich momentan kein C# zur Hand habe, skizziere ich das mal kurz mit einem Python Programm.
import re
import json
text = open("stuff.txt").read()
# convert to uppercase
text = text.upper()
# wrap entire blocks into parenthesis
# wrap doc in paranthesis
text = "(" + text + ")"
# put in empty, separating lines )(
text = re.sub(r"$[\t ]*^", ")(", text, flags=re.MULTILINE)
# replace = with :
text = re.sub(r"\s*=", ":", text)
# enquote identifiers
text = re.sub(r"([\w\-_\.]+)", '"\\1"', text)
# replace close-open )( by comma
text = re.sub(r"\)\s*\(", ", ", text)
# replace ( by {
text = re.sub(r"\(", "{", text)
# replace ) by }
text = re.sub(r"\)", "}", text)
data = json.loads(text)
for interface, settings in data.items():
address = settings['DESCRIPTION']['ADDRESS_LIST']['ADDRESS']
host, port = address['HOST'], address['PORT']
print "{0} ({1}:{2})".format(interface, host, port)
static int RomToInt(char[] x) {
int last=0, result=0;
for (int i=x.Length-1; i≥0; i--) {
if (!"IVXLCDM".Contains(x[i].ToString()))
throw new System.ArgumentException();
int current = (int)((x[i]*(x[i]*(x[i]*(x[i]*(x[i]*(134149L*x[i]-61251763)+11624806957)-1173838830541)+66515437336342)-2005476756276328)+25136183219933184)/5896800);
last = System.Math.Abs(-result + (result += current*(current<last?-1:+1)));
}
return result;
}
//Edit: hier noch eine etwas weniger obfuskierte Variante:
static int RomToInt(char[] x) {
int last=0, result=0;
for (int i=x.Length-1; i≥0; i--) {
char c = x[i];
if (!"IVXLCDM".Contains(c.ToString()))
throw new System.ArgumentException();
int current = (c=='M'?1000:c=='D'?500:c=='C'?100:c=='L'?50:c=='X'?10:c=='V'?5:1);
result += current * (current<last ? -1 : +1);
last = current;
}
return result;
}
also willst du in gerichteten Graphen nach Zyklen suchen? Dann mach das doch :) Geht im Grunde so ähnlich wie die topologische Sortierung, die du ja bereits erwähnt hast.
Wenn ja, dann sollte dein einziges Problem am Ende nur noch sein, dass die Bibliotheken vom Dateinamen her gleich heißen ("wasAuchImmer.dll"), du aber hiervon zwei Versionen mitliefern willst.
Du kann abhängig von der Version über die app.config auf verschiedene Pfade verweisen: Multiple Assemblies with the Same Name
In wie fern wäre in dem simplem Fall minimalcode notwendig?
Um zu verstehen, was passiert. Wie du selbst siehst, passiert etwas unerwartetes. So simpel ist es also nicht.
Daher wäre ein minimales, vollständiges, kompilierbares Beispiel super hilfreich.
Ich habe versucht, selbst eins zu erstellen, schaffe es aber nicht dein Problem zu reproduzieren:
using System;
using System.Collections.Generic;
namespace Rextester {
class Tree
{
private Node _tree;
public Tree(Node tree)
{
this._tree = tree;
}
public void PrintNextIndex()
{
var nextIndex = this.GetNextIndex(this._tree) + 1;
Console.WriteLine(nextIndex);
}
private int GetNextIndex(Node node, Int32 iCurrentMax = -1)
{
int iIndex = iCurrentMax ≥ 0 ? iCurrentMax : 0;
if (node.Index > iIndex)
iIndex = node.Index;
if (node.Nodes.Count > 0)
{
foreach (Node child in node.Nodes)
{
iIndex = this.GetNextIndex(child, iIndex);
}
}
return iIndex;
}
}
class Node
{
public int Index {get; set;}
public List<Node> Nodes {get; set;}
}
public class Program
{
static Node N(int index, params Node[] nodes)
{
return new Node{Index=index, Nodes=new List<Node>(nodes)};
}
public static void Main(System.String[] args)
{
var tree = new Tree(N(1,
N(2,
N(3),
N(4),
N(6),
N(9)),
N(5,
N(8)),
N(7)));
tree.PrintNextIndex();
}
}
}
Kannst du das Problem in einem solch minimalen Snippet reproduzierbar machen?
Zudem verwürfelst du oft "GetNextIndex" mit "GetMaxIndex" in deinen Beschreibungen. Rufen sich diese beiden Methoden eventuell gegenseitig rekursiv auf? Das würde irgendwie erklären, warum ein +1 in der einen auch ein +1 in der anderen entspricht - jedoch nicht das unterschiedliche Klammerverhalten.
Für das Umdrehen gibt es Array.Reverse. Es gibt sogar eine Variante, wo man inline nur einen Teil eines Array umdrehen kann. Das wäre für dich perfekt. Für strings direkt gibt es keine solche Hilfsmethoden. Daher am besten zu Beginn einmal in ein Char-Array umwandeln, alles umdrehen in den Blöcken und am Ende wieder zu einem String umwandeln:
string text = "123456";
int chunkSize = 2;
char[] chars = text.ToCharArray();
for (int i=0; i<chars.Length; i+=chunkSize)
{
Array.Reverse(chars, i, Math.Min(chunkSize, chars.Length - i));
}
string result = new String(chars);
System.Console.WriteLine(result);
Raspberry Pi ist super. 35€ für das Gerät. 10-20€ für die SD Karte, 10€ für ein Gehäuse, dazu ein WLAN-Mini-Stick für 5-10€ oder ein Surfstick und du bist im Netz.
Für schlechte Tonqualität findest du externe USB-Soundkarten für 5-10€ auf Amazon und dazu noch ein mieses Mikro für weitere 5-10€ und du kannst schonmal loswerkeln.
Wenn das dann alles funktioniert, holst du dir ne gescheihte externe Soundkarte, nen Vorverstärker und n gutes Mikro, oder vielleicht auch direkt ein USB-Mikrophone mit integrierten AD-Wandler. (Nur so als Beispiel: AT2020 USB)
Mono auf dem Raspberry zum laufen zu bekommen ist nicht ganz trivial.
Echte Unterstützung der Mono-Runtime für die spezielle ARM-Hardware gibts erst seit Mono 3.2.irgendwas und momentan ist 3.10.0 aktuell. Allerdings haben die gängigen RapsberryPi-Distros nicht die passende Version im Paket-Repo. Daher heißt es höchst wahrscheinlich: Mono-Quellen auschecken und selber kompilieren.
Du kannst aber auch auf Python aufbauen. Könnte sogar noch einfacher sein, fluppt auf dem Raspberry und hat auch gute Libs zur Audio Recording, Processing und natürlich alles andere auch.
beste Grüße
zommi
//Edit:
Oder du schnappst dir n altes rumliegenden Android Smartphone (oder ersteigerst eins), kaufst dir so ein externes Mikrophon wie iRig Mic, und schreibst ne App für Android, entweder nativ oder mit Xamarin in C#.
Wie gut da die Audo Bindings sind, keine Ahnung.
Aber du hast natürlich alle Möglichkeiten der Konnektivität (und Akku und Kamera und Display und und und) gleich eingebaut