I breathe in heavily, huuuuuuughhhh, and wake up covered in sweat.  There’s no way in hell I could sleep or even lie in bed for another second, I HAVE to go. I throw on some clothes, my stomach hurts and my skin screams. I look over to my roommate, fast asleep with a smile on his face, he looks so peaceful; oh how I wish I could just rid my brain of these fake endorphins without withdrawal, back to reality.
 I end up at my bank and for the second time I game the ATM machine. The bank I use allows for deposits in ATM’s but the deposits are in envelopes meaning they don’t get checked until a couple days later and can only make $100 available today, fine with me. I grab an envelope, insert a blank check and tell the ATM it’s for $100. I learned this trick the other day and like any junkie, I won’t stop until this well is tapped out. In goes the blank check, out comes the $100, and down the drain goes my credit and bank account.  I sure don’t. Grabbing the 5 20’s I frantically make my way to my car and start the long hour and a half drive to San Francisco.
I swerve and veer around morning rush hour traffic, withdrawing I become frantic and drive like a maniac. An hour goes by, I pass familiar street signs and watch as the San Francisco sign goes from 76 miles to 43 to 22 to 13 and soon I see the big white letters on a hillside east of the 101 North that read “South San Francisco, The Industrial City”. Yes, I think to myself, only 10 more minutes. I get off, make a left, a right and another left. I park in an alley, get out of my car and quickly start walking. The familiar piss smell of the ghetto fills my nostrils as I pass lifeless bodies huddled and shaking on the ground, the collateral damage of the drug problems here. The sickness subsides a bit now knowing I’ll be well soon.
Since discovering this place I haven’t had to play the waiting game that every junkie hates. You know, waiting for your connect to call back who’s waiting on his connect who’s waiting on his guy as you spin yourself into withdrawal hell. Here you show up any time (though I would never come at night) and you’ll get served up anything you wish. Right now it’s almost 8am and I’m confident I’ll score. Lately I’ve been going for the 80mg Oxy’s which go for $30 a pop (sometimes $20 if you find the right person) and grams of tar for $20-$30 each. The tar is cheap, but not pure enough to effectively smoke; still a bargain though.
Copping is an ordeal in itself. If you’re white and you walk to the right block, men pass you by shouting “OC, OC?” and “cheeva, cheeva here” all you have to do is make the right eye contact and the deal goes down right there. I stopped at a 7 11 and got change, 10 $10 bills divided into $60 in one pocket and $40 in another (you can’t trust these guys to give you change, I’ve lost a bunch of money getting ripped off and by now after dozens of trips here, I’ve honed my skills at copping heroin and oxy. A man passes me by, “whatchya need buddy?” Nothing, I’m good I say; avoid the middle men who say they can get you anything you need as they always take a cut. I’m looking for the dealers. Soon I see one with a familiar look on his face.
“Cheeva?” he asks, “yes” I reply.
“How much you need?”
“Gimmie 3g’s for $60 straight up” I say.
“Man these g’s are $40 each” he thinks I am a new face, a white kid who doesn’t know the prices around here. If you walk up to a heroin dealer and ASK them how much a g is they’ll tell you $50. If you say nothing, the price is $40, but if you know how to play them, it drops fast.
“Fuck that man I know I can get g’s for $20, quit wasting my time” I say.
  He puts the 2gs in my hand and before handing him the $40 I put one of the cellophane wrapped grams in my mouth looking for that vinegar taste (another mistake I made, not checking the heroin before buying as many people will sell you fake tar). He stands there, accepting what is going on, now knowing I’m not a newcomer. I nod to him, hand him the $40 and am off.
I walk back to my car, but not before passing “pill hill” and scoping out an oxy dealer. I nod, he sees me and runs across the street to walk with me.
 At this point I’m done fussing around, it isn’t worth the hassle to find $20 80’s as it is with heroin since the 80 dealers are rarer and work together. He hands me the two pills, I check both sides looking for OC and 80 to be sure and hand him my money.
At this point the sickness is in the back of my head as I walk with $100 worth of opiates in my pocket. I get back to my car, slam the door and begin cooking up. I prefer heroin over oxy for the first shot, I don’t know why but I just do. I grab my end of an aluminum can, place 1/2 of a gram of tar in there and 100 units of water, then another 40 units.   Flicking the syringe and plunging all the air out I laugh as the plunger stops at 75 units.
I glace down at my right arm, my favorite, and happily find that my master vein is showing nicely (digging for a vein while withdrawing is no fun). But since my master vein is presenting itself, I wait a second. I wait and just concentrate solely on my sickness causing it to radiate and grow in intensity. The sick junkie in me finds that by focusing on the sickness, the shot that’s about to come tastes all the sweeter. I close my eyes and focus all my energy on how I feel, pretending I’m back in bed; hundreds of miles and hundreds of dollars away from a good day. If I didn’t have a shot cooked up right now I would be in big trouble. It’s only 8:20 AM, about 8 hours since my last shot and already my soul aches and cries from the core to the tips of my hair. My skin looks like a cold turkey and my clothes feel like sandpaper against my flesh. My stomach is in knots and the thought of food almost makes me vomit. Okay, I think to myself, I’m ready.
I stick the half inch needle in, popping my vein. The solution is too dark to see any blood so I plunge just a little into my arm (if it burns you missed the vein, but if you feel nothing you’re golden). Nothing, I take a breath and plunge the remaining 70 units. I pull out the needle, cap it, recline my seat and close my eyes. A tear rolls down my face, of joy and of sadness.
Of joy as the sickness leaves me and is replaced with overwhelming pleasure and warmth in less than 10 seconds. It’s this rush that I chase.  As those fake endorphins latch on to my receptors I almost forget where I am. My eyes roll back deep into my skull and I find the golden nod.
Of sadness because I know reality will hit soon. This gear will only last me through tomorrow morning and then what? ATM trick again, pshh my bank account will be -$200 by then.  But this thought only lasts for a moment and then is gone as euphoria overwhelms worry.  I shake my head, rub my hands in my face, and make the long drive back arriving at home before my roommate even wakes up.
Morning comes again and I’m sick, but I wake up with a smile knowing I have 2 80’s to get me over the hump. It’s only 7am but I’m able to roll around in bed for another hour before cooking up. Again I focus on the sickness as I roll around, pretending to myself that I have no Oxy and that there’s no way I can get well right now. After an hour of this I’m ready. I roll out of bed, roommate fast asleep. I make my way to the living room with one of my 80’s and get ready to prep a shot.
Preparing Oxy for injection can be tricky. It’s not as easy as tar.   I place this crushed pill on a plate and finish the preparation with a couple cards. The white powder slides from the plate to the spoon where it meets about 100-150 units of water. The solution is milky and inconsistent. I mix it up a little and turn the TV on while I give the solution 10 minutes to soak everything in. Oxycontin, though technically only contains oxycodone, has hundreds of binders and fillers in the pill causing it to become milky. After 10 minutes I begin to cook the solution up watching as the fillers and binders cling together leaving a clear watery solution, this clear water contains the oxycodone. I drop a cotton ball in, say to myself “70 units” and draw back my solution. Damn, 60 units.
Now I sit, watching TV, trying to make myself sick but it doesn’t work.  My right master is tapped out thanks to a blown shot from the night before. I look, the big vein in the crock of my left elbow. Fuck, this one always hurts. I dig the needle in biting my lip.
The one sick joy I like shooting Oxy over heroin is getting to see the plume of blood acknowledging you’ve hit a vein. I pull back on the syringe with my index and middle finger, nothing only a small bubble of air. FUCK. I stab again, taking the pain, draw back, nothing… My heart begins to race, I jab one more time and pull back…
A dark cloud of crimson overwhelms the clear solution and my panic immediately dissipates. I drive the plunger home and cap the needle. Oxy shots, compared to heroin, is a purer high but lasts much shorter. Now for my favorite part of the day, the 20 or so minutes to enjoy the nod before the amazing journey back to my bed as I catch up on some zzz’s. I lie in bed, on a cloud of fake heaven and my eyes roll back into my skull and stay there for about 3 hours before waking up to the first signs of sickness again. I open my eyes, my roommate is in the living room. I reach under the bed and grab a piece of foil. I smoke some crumbs to help me get through normal tasks like putting on semi-clean clothes, showering and tying my shoes; tasks that otherwise would be the last thing on my mind if I were withdrawing. I grab the remaining half of my 80 and head for my car where I can cook in peace.
I look, my right master is ready, well sort of but it better get ready. Solution prepped, missing the guess by only a couple units I jam the needle home. No time to bother about the sickness as that only works for the first shot of the day.
This was 4 weeks ago. I am 4 weeks clean and plan on staying at least 6 months clean. I would like to be clean for the rest of my life but I now know reality. Opiates can creep up on anyone. Ever since my obsession-like curiosity with Oxy fist took me down this road I now know addiction is blind. Promising myself before snorting my first ever line of 10mg Oxy that I would never make the mistake of smoking it like the poor saps I’ve heard about. Then before taking my first hoot off the foil I promised myself I’d never try heroin. After a dry spell of oxy and finding myself with a ball of tar and aluminum foil I promised myself I’d never touch the needle. I went from 0-60 in about 6 months, from snorting Oxy to shooting heroin.
If you’ve never tried opiates, or better yet if you’ve never shot opiates you’re ahead of the game. Get out now. All roads lead to the same dead end.
I’m lucky, knock on wood. No permanent repercussions. No diseases, no run ins with the law or any dark clouds looming overhead. Now I work out, I’m building my bank account up again and living life. I wake up at 7am sometimes, go take a piss and go back to bed for a couple hours, peaceful. I’ll tell you this…
The feeling you get waking up and not having to face any sickness whatsoever is better than any rush.
Experience Reports are the writings and opinions of the individual authors who submit them.
Some of the activities described are dangerous and/or illegal and none are recommended by Erowid.


Class UnconditionalSuppressMessageAttribute
Suppresses reporting of a specific rule violation, allowing multiple suppressions on a single code artifact.
Namespace: System.Diagnostics.CodeAnalysis
Assembly: Philosoft.CodeAnalysisAttributes.dll
Syntax
public sealed class UnconditionalSuppressMessageAttribute : Attribute
Remarks
UnconditionalSuppressMessageAttribute is different than
Constructors
| Improve this Doc View SourceUnconditionalSuppressMessageAttribute(String, String)
Initializes a new instance of the UnconditionalSuppressMessageAttribute class, specifying the category of the tool and the identifier for an analysis rule.
Declaration
public UnconditionalSuppressMessageAttribute(string category, string checkId)
Parameters
| Type | Name | Description |
|---|---|---|
| String | category | The category for the attribute. |
| String | checkId | The identifier of the analysis rule the attribute applies to. |
Properties
| Improve this Doc View SourceCategory
Gets the category identifying the classification of the attribute.
Declaration
public String Category { get; }
Property Value
| Type | Description |
|---|---|
| String |
Remarks
The Category property describes the tool or tool analysis category for which a message suppression attribute applies.
CheckId
Gets the identifier of the analysis tool rule to be suppressed.
Declaration
public String CheckId { get; }
Property Value
| Type | Description |
|---|---|
| String |
Remarks
| Improve this Doc View SourceJustification
Gets or sets the justification for suppressing the code analysis message.
Declaration
public String? Justification { get; set; }
Property Value
| Type | Description |
|---|---|
| Nullable<String> |
MessageId
Gets or sets an optional argument expanding on exclusion criteria.
Declaration
public String? MessageId { get; set; }
Property Value
| Type | Description |
|---|---|
| Nullable<String> |
Remarks
The MessageId property is an optional argument that specifies additional exclusion where the literal metadata target is not sufficiently precise. For example, the UnconditionalSuppressMessageAttribute cannot be applied within a method, and it may be desirable to suppress a violation against a statement in the method that will give a rule violation, but not against all statements in the method.
Scope
Gets or sets the scope of the code that is relevant for the attribute.
Declaration
public String? Scope { get; set; }
Property Value
| Type | Description |
|---|---|
| Nullable<String> |
Remarks
The Scope property is an optional argument that specifies the metadata scope for which the attribute is relevant.
Target
Gets or sets a fully qualified path that represents the target of the attribute.
Declaration
public String? Target { get; set; }
Property Value
| Type | Description |
|---|---|
| Nullable<String> |
Remarks
The Target property is an optional argument identifying the analysis target of the attribute. An example value is "System.IO.Stream.ctor():System.Void". Because it is fully qualified, it can be long, particularly for targets such as parameters. The analysis tool user interface should be capable of automatically formatting the parameter.


Damage of
The damage calculation took
seconds.
Info
This is an archived damage calculation done
ago. Click
here
for fresh calculation
Actual Damage
Actual Damage =
Images =
Stylesheets =
Multimedia =
Javascript =
IFrames =
Text =
Potential Damage
Potential Damage =
Images =
Stylesheets =
Multimedia =
Javascript =
IFrames =
Text =


--- layout: post title: 'OAuth: A Tale of Two Servers' date: '2012-05-16T09:55:17-05:00' tags: - oauth - oauth 2 - client - provider permalink: /post/23164666348/oauth-a-tale-of-two-servers ---
What exactly is OAuth, and how can you use it to access data on sites like Facebook? This introductory video explains the basic flow behind OAuth 2 and how OAuth Clients are implemented.
If you’re using OAuth, you’ll likely want to use a pre-built client library to help with the process. For Ruby you’ll likely want to use Omniauth or Koala, though understanding the process is still important.
This is being posted from Singapore, where I’m about to give a talk at Red Dot Ruby Conf. Have fun learning about OAuth, i’ll post slides from my talk as soon as they’re ready. Wish me luck!


@article{zheng2018phase, title={Phase Collaborative Network for Two-Phase Medical Image Segmentation}, author={Zheng, Huangjie and Xie, Lingxi and Ni, Tianwei and Zhang, Ya and Wang, Yan-Feng and Tian, Qi and Fishman, Elliot K and Yuille, Alan L}, journal={arXiv preprint arXiv:1811.11814}, year={2018} }


Welcome to CaT
You can find multiple Rest services for codes and texts for:
Applications
Domains
Code Types
Code Values
Texts
You can find an extensive documentation
here
.


Pelizaeus-Merzbacher disease: three novel mutations and implication for locus heterogeneity.
Abstract
We report a mutational and polymorphic analysis of the proteolipid protein gene in members of 27 Japanese families with Pelizaeus-Merzbacher disease. We found causative mutations in 6 members of 27 families (22.2%); 5 of the 6 mutations, including two novel mutations, Leu45Arg and 231 + 2T --> G, resulted in the typically severe clinical symptoms. Paradoxically, the Cys219Tyr mutation, presumed to disrupt the tertiary structure of proteolipid protein by removing the disulfide bond between Cys200 and Cys219, was associated with a mild clinical presentation wherein the patient could walk with assistance and speak. It was inferred that the structural change prevented the toxicity associated with a gain of function mutation. Moreover, in one family 3 patients exhibited a intragenic polymorphism that did not segregate with the disease, suggesting a locus heterogeneity for Pelizaeus-Merzbacher disease.


I found it really interesting that Emotional intelligence isn't innate and can be trained. I've always been an observer from a young age and as a mum feel like I've gained a better understanding of reading other peoples emotions. I learned that one of the outcomes of those with high emotional intelligence is the ability to create conditions for happiness. Who doesn't want to be happy? Initally when deciding to enrol in Dev academy I knew my technical skills would be lacking. After doing this assignment it has highlighted to me that even though I lack the technical skills I feel through my own personal and life experience that I have developed some of the soft skills required to be successful. It gives me hope also that of the 6 competencies required to be successful only 2 were related to intelligence and the other 4 were related to emotional intelligence.
Initially I found it difficult. It's the school holidays and my kids are loud and busy! I've been through phases of trying to meditate and in the past have tried waking up an hour before the kids to get some quiet time before I start the day. I've worked this into my schedule again while studying at Dev academy and so far it's going good.


First ‘MoRuns’ set to be held in Blackpool tomorrow
Three runs in aid of testicular cancer, prostrate cancer and mental health charities will take place at Herons Reach on Saturday.
by James SpencerThree runs in aid of testicular cancer, prostrate cancer and mental health charities will take place at Herons Reach on Saturday.
Now in its 10th year, the MoRun event also aims to raise awareness. There are 5k and 10k runs starting at 9.30am with entry prices ranging from £12-22.
Commentator Chris Benson is encouraging people of all ages to take part and to dress as silly as possible.
He said: “It’s a fantastic event for all abilities and ages and good fun for kids too as they can enter the [1.5k] MiniMoRun. It’s timed but not as serious as other events I’ve commentated at.
“I’ve commentated at these events for years now but they’ve added Blackpool for the first time, which is nice.”
Online entries are now closed, though places will be sold on a first come, first served basis on the day.
Those taking part will get a medal and headband, with awards also handed out for the best fancy dress.
For more, see mo-running,com/blackpool


More Recipes
Home
Sign Up
Sign In
John
Profile
Add Recipe
Category
Favorite Recipes
My Recipes
Edit Recipe
Add Ingredients
Select quantity
1
2
3


1 // Copyright 2008, Google Inc. 2 // All rights reserved. 3 // 4 // Redistribution and use in source and binary forms, with or without 5 // modification, are permitted provided that the following conditions are 6 // met: 7 // 8 // * Redistributions of source code must retain the above copyright 9 // notice, this list of conditions and the following disclaimer. 10 // * Redistributions in binary form must reproduce the above 11 // copyright notice, this list of conditions and the following disclaimer 12 // in the documentation and/or other materials provided with the 13 // distribution. 14 // * Neither the name of Google Inc. nor the names of its 15 // contributors may be used to endorse or promote products derived from 16 // this software without specific prior written permission. 17 // 18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 // 30 // Google Test filepath utilities 31 // 32 // This header file declares classes and functions used internally by 33 // Google Test. They are subject to change without notice. 34 // 35 // This file is #included in gtest/internal/gtest-internal.h. 36 // Do not include this header file separately! 37 38 // GOOGLETEST_CM0001 DO NOT DELETE 39 40 #ifndef GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ 41 #define GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_ 42 43 #include "gtest/internal/gtest-string.h" 44 45 GTEST_DISABLE_MSC_WARNINGS_PUSH_(4251 \ 46 /* class A needs to have dll-interface to be used by clients of class B */) 47 48 namespace testing { 49 namespace internal { 50 51 // FilePath - a class for file and directory pathname manipulation which 52 // handles platform-specific conventions (like the pathname separator). 53 // Used for helper functions for naming files in a directory for xml output. 54 // Except for Set methods, all methods are const or static, which provides an 55 // "immutable value object" -- useful for peace of mind. 56 // A FilePath with a value ending in a path separator ("like/this/") represents 57 // a directory, otherwise it is assumed to represent a file. In either case, 58 // it may or may not represent an actual file or directory in the file system. 59 // Names are NOT checked for syntax correctness -- no checking for illegal 60 // characters, malformed paths, etc. 61 62 class GTEST_API_ FilePath { 63 public: 64 FilePath() : pathname_("") { } 65 FilePath(const FilePath& rhs) : pathname_(rhs.pathname_) { } 66 67 explicit FilePath(const std::string& pathname) : pathname_(pathname) { 68 Normalize(); 69 } 70 71 FilePath& operator=(const FilePath& rhs) { 72 Set(rhs); 73 return *this; 74 } 75 76 void Set(const FilePath& rhs) { 77 pathname_ = rhs.pathname_; 78 } 79 80 const std::string& string() const { return pathname_; } 81 const char* c_str() const { return pathname_.c_str(); } 82 83 // Returns the current working directory, or "" if unsuccessful. 84 static FilePath GetCurrentDir(); 85 86 // Given directory = "dir", base_name = "test", number = 0, 87 // extension = "xml", returns "dir/test.xml". If number is greater 88 // than zero (e.g., 12), returns "dir/test_12.xml". 89 // On Windows platform, uses \ as the separator rather than /. 90 static FilePath MakeFileName(const FilePath& directory, 91 const FilePath& base_name, 92 int number, 93 const char* extension); 94 95 // Given directory = "dir", relative_path = "test.xml", 96 // returns "dir/test.xml". 97 // On Windows, uses \ as the separator rather than /. 98 static FilePath ConcatPaths(const FilePath& directory, 99 const FilePath& relative_path); 100 101 // Returns a pathname for a file that does not currently exist. The pathname 102 // will be directory/base_name.extension or 103 // directory/base_name_<number>.extension if directory/base_name.extension 104 // already exists. The number will be incremented until a pathname is found 105 // that does not already exist. 106 // Examples: 'dir/foo_test.xml' or 'dir/foo_test_1.xml'. 107 // There could be a race condition if two or more processes are calling this 108 // function at the same time -- they could both pick the same filename. 109 static FilePath GenerateUniqueFileName(const FilePath& directory, 110 const FilePath& base_name, 111 const char* extension); 112 113 // Returns true iff the path is "". 114 bool IsEmpty() const { return pathname_.empty(); } 115 116 // If input name has a trailing separator character, removes it and returns 117 // the name, otherwise return the name string unmodified. 118 // On Windows platform, uses \ as the separator, other platforms use /. 119 FilePath RemoveTrailingPathSeparator() const; 120 121 // Returns a copy of the FilePath with the directory part removed. 122 // Example: FilePath("path/to/file").RemoveDirectoryName() returns 123 // FilePath("file"). If there is no directory part ("just_a_file"), it returns 124 // the FilePath unmodified. If there is no file part ("just_a_dir/") it 125 // returns an empty FilePath (""). 126 // On Windows platform, '\' is the path separator, otherwise it is '/'. 127 FilePath RemoveDirectoryName() const; 128 129 // RemoveFileName returns the directory path with the filename removed. 130 // Example: FilePath("path/to/file").RemoveFileName() returns "path/to/". 131 // If the FilePath is "a_file" or "/a_file", RemoveFileName returns 132 // FilePath("./") or, on Windows, FilePath(".\\"). If the filepath does 133 // not have a file, like "just/a/dir/", it returns the FilePath unmodified. 134 // On Windows platform, '\' is the path separator, otherwise it is '/'. 135 FilePath RemoveFileName() const; 136 137 // Returns a copy of the FilePath with the case-insensitive extension removed. 138 // Example: FilePath("dir/file.exe").RemoveExtension("EXE") returns 139 // FilePath("dir/file"). If a case-insensitive extension is not 140 // found, returns a copy of the original FilePath. 141 FilePath RemoveExtension(const char* extension) const; 142 143 // Creates directories so that path exists. Returns true if successful or if 144 // the directories already exist; returns false if unable to create 145 // directories for any reason. Will also return false if the FilePath does 146 // not represent a directory (that is, it doesn't end with a path separator). 147 bool CreateDirectoriesRecursively() const; 148 149 // Create the directory so that path exists. Returns true if successful or 150 // if the directory already exists; returns false if unable to create the 151 // directory for any reason, including if the parent directory does not 152 // exist. Not named "CreateDirectory" because that's a macro on Windows. 153 bool CreateFolder() const; 154 155 // Returns true if FilePath describes something in the file-system, 156 // either a file, directory, or whatever, and that something exists. 157 bool FileOrDirectoryExists() const; 158 159 // Returns true if pathname describes a directory in the file-system 160 // that exists. 161 bool DirectoryExists() const; 162 163 // Returns true if FilePath ends with a path separator, which indicates that 164 // it is intended to represent a directory. Returns false otherwise. 165 // This does NOT check that a directory (or file) actually exists. 166 bool IsDirectory() const; 167 168 // Returns true if pathname describes a root directory. (Windows has one 169 // root directory per disk drive.) 170 bool IsRootDirectory() const; 171 172 // Returns true if pathname describes an absolute path. 173 bool IsAbsolutePath() const; 174 175 private: 176 // Replaces multiple consecutive separators with a single separator. 177 // For example, "bar///foo" becomes "bar/foo". Does not eliminate other 178 // redundancies that might be in a pathname involving "." or "..". 179 // 180 // A pathname with multiple consecutive separators may occur either through 181 // user error or as a result of some scripts or APIs that generate a pathname 182 // with a trailing separator. On other platforms the same API or script 183 // may NOT generate a pathname with a trailing "/". Then elsewhere that 184 // pathname may have another "/" and pathname components added to it, 185 // without checking for the separator already being there. 186 // The script language and operating system may allow paths like "foo//bar" 187 // but some of the functions in FilePath will not handle that correctly. In 188 // particular, RemoveTrailingPathSeparator() only removes one separator, and 189 // it is called in CreateDirectoriesRecursively() assuming that it will change 190 // a pathname from directory syntax (trailing separator) to filename syntax. 191 // 192 // On Windows this method also replaces the alternate path separator '/' with 193 // the primary path separator '\\', so that for example "bar\\/\\foo" becomes 194 // "bar\\foo". 195 196 void Normalize(); 197 198 // Returns a pointer to the last occurence of a valid path separator in 199 // the FilePath. On Windows, for example, both '/' and '\' are valid path 200 // separators. Returns NULL if no path separator was found. 201 const char* FindLastPathSeparator() const; 202 203 std::string pathname_; 204 }; // class FilePath 205 206 } // namespace internal 207 } // namespace testing 208 209 GTEST_DISABLE_MSC_WARNINGS_POP_() // 4251 210 211 #endif // GTEST_INCLUDE_GTEST_INTERNAL_GTEST_FILEPATH_H_


- gas(double) - Method in class model.Car
-
Applies the throttle between 0-1
- gas(double) - Method in class model.Scania
-
Applies the gas if the board is in it's upright position.
- gas(double) - Method in class model.Vehicle
-
Increases the current speed, must be called from overridden subclasses
- gasVehicles(double) - Method in class model.World
-
Pushed the "throttle" of all the vehicles
- getAngle() - Method in class model.Board
-
Returns the current angle of the board.
- getAngle() - Method in class model.Ramp
-
- getBoardAngle() - Method in class model.Scania
-
Returns the angle of the board
- getColor() - Method in class model.Vehicle
-
Returns the colour of the vehicle
- getEngineOn() - Method in class model.Car
-
Returns the state of the engine, either on or off.
- getHeight() - Method in class model.Vehicle
-
Return the height of the vehicle
- getModelName() - Method in class model.Vehicle
-
Return the model name of the vehicle
- getNrDoors() - Method in class model.Car
-
Returns how many doors the car has
- getNumberOfCars() - Method in class model.CarCarrier
-
Returns number of loaded cars.
- getNumberOfCars() - Method in class model.CarFerry
-
- getNumberOfCars() - Method in class model.CarTransporter
-
- getRotation() - Method in class model.Vehicle
-
Get rotation of the vehicle
- getSpeed() - Method in class model.Vehicle
-
Returns the current speed of the vehicle
- getVehicles() - Method in class model.World
-
Returns the list of vehicles contained within the world
- getWeight() - Method in class model.Vehicle
-
Returns the weight of the vehicle
- getWidth() - Method in class model.Vehicle
-
Return the width of the vehicle
- getX() - Method in class model.Vehicle
-
- getY() - Method in class model.Vehicle
-
- gui - package gui
-


NiMet predicts sunny, thundery activities for Saturday, November 23
- NiMet has predicted sunny and thundery activities for Saturday
- The agency predicted a stable atmosphere over the Northern region down to Central cities
- However, NiMet predicted chances of thunderstorms over the inland and coastal region of the country
The Nigerian Meteorological Agency (NiMet) has predicted sunny and thundery activities for Saturday, November 23.
NiMet’s weather outlook on Friday in Abuja predicted a stable atmosphere over the Northern region down to Central cities with chances of thunderstorms over the inland and coastal region of the country.
It forecast sunny and dry conditions over the extreme Northern region throughout the forecast period with day and night temperatures of 35 to 38 degree celsius and 15 to 20 degree celsius respectively.
“For central states, partly cloudy to sunny conditions would prevail throughout the forecast period with day and night temperature of 29 to 38 degree celsius and 21 to 23 degree celsius.
NiMet releases weather condition for Thursday, November 21
“For Southern states, partly cloudy to cloudy morning is anticipated over the region with chances of thunderstorms over Akure, Oshogbo, Ibadan and the coastal region in the afternoon/evening period."
PAY ATTENTION: Get the Latest Nigerian News Anywhere 24/7. Spend less on the Internet!
“Day and night temperatures are expected to be 31 to 33 degree celsius and 21 to 22 degree celsius,” it said.
NAIJ.com (naija.ng) -> Legit.ng: Same great journalism, upgraded for better service!
I almost took my own life - Pastor involved in s*x tape scandal reveals | Legit TV


|
|
|
|
|
|
|
Welcome, IGAOMD.
You last visited: Today at 08:14 AM
Private Messages: Unread 0, Total 0.
|
| Ongoing Battle |
| Welcome to the Battle between IGAOMD and Coeurl! Two of the finest warriors in all the land square it off in this exciting display of skill and bravery. But who will emerge victorious...? |
| IGAOMD |
Monster Arena |
Coeurl |
HP: 300/300
MP: 60/60
PP: 60/60
Limit Break: 0%
EXP: 79% Total: 28151
Level: 20 |
|
HP: 10737/12000
MP: 150/150
PP: 120/120
Limit Break: 0%
EXP: 77% Total: 915
Level: 9 |
| Battle Actions |
Quote:
|
IGAOMD pulled out Masamune and rushed towards Coeurl, swinging the mighty weapon with ease. IGAOMD's attack ends up inflicting 646 points of damage upon Coeurl.
|
|
Quote:
|
Coeurl tried to fight IGAOMD using bare fists. However, IGAOMD was able to counter the onslaught. No harm came to either combatant.
|
|
Quote:
|
IGAOMD pulled out Masamune and rushed towards Coeurl, swinging the mighty weapon with ease. IGAOMD's attack ends up inflicting 617 points of damage upon Coeurl.
|
|
Quote:
|
Coeurl tried to fight IGAOMD using bare fists. However, IGAOMD was able to counter the onslaught. No harm came to either combatant.
|
|
All times are GMT -4. The time now is 06:58 PM.
|
|
|
|
|
|
|


Using roll() in Your Own Code¶
For Simple Die Rolls¶
Sample Outputting of Die Rolls:
# import the roll() module
from PyDiceroll import roll
# enter the roll type to be made
number_of_dice = input('Number of dice to roll? ')
dice_type = input('Dice type? ')
dice_roll_modifier = input('DM? ')
# make sure that there is a plus or minus sign in the DM string
if dice_roll_modifier[0] != '-' and dice_roll_modifier[0] != '+':
dice_roll_modifier = '+' + dice_roll_modifier
# concatenate the values for the dice string
dice = number_of_dice + dice_type + dice_roll_modifier
print()
print('Rolling', dice)
# do 20 rolls
for i in range(20):
print('You rolled a %d' % roll(dice))
For Probabilites¶
Sample Task Resolution:
# import the roll() module
from PyDiceroll import roll
# Enter your character's chances to succeed at a task
skilled = input('Is your character trained for the task ([y]/n)? ')
if skilled == 'n':
die_mod = -3
else:
print("Enter your character's skill level")
die_mod = int(input('(0 to 4)? '))
print('Enter the difficulty of the task')
difficulty = int(input('(Simple: +2 to Impossible: +16)? '))
# The player must roll the difficulty or higher for their character to succeed
dice_roll = roll('2D6') + die_mod
print()
print('You rolled:', dice_roll)
if dice_roll >= difficulty:
print('Your character succeeds with the task.')
if dice_roll - difficulty >= 6:
print('Your character saved everyone.')
else:
print('Your character fails at the task.')
if dice_roll - difficulty < -3:
print('Your character becomes injured.')
if dice_roll - difficulty < -6:
print('Your character died from injuries!')
For Repairing Game Code¶
Often times, game code will be downloaded or found that contains
incorrect randint()
calls for rolling two 6-sided dice. A line such as:
world_size = randint(2, 12) - 2
Easily becomes:
world_size = roll('2d6') - 2
Encountering Errors¶
Entering an invalid string for roll()
will return an error message, as well as a value of -9999 from the function:
print(roll('3d1'))
Error
** DICE ERROR! ‘3D1’ is unknown **
-9999


Coverage report for
Generated at 30.11.2022 22:06:19 by DelphiCodeCoverage - an open source tool for Delphi Code Coverage.
Statistics for ..\..\Source\DECCipherBase.pas
| Number of lines covered | 133 | |
| Number of lines with code gen | 177 | |
| Line coverage | 75.1 % |
| 1 | {***************************************************************************** |
| 2 | The DEC team (see file NOTICE.txt) licenses this file |
| 3 | to you under the Apache License, Version 2.0 (the |
| 4 | "License"); you may not use this file except in compliance |
| 5 | with the License. A copy of this licence is found in the root directory |
| 6 | of this project in the file LICENCE.txt or alternatively at |
| 7 | |
| 8 | http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | |
| 10 | Unless required by applicable law or agreed to in writing, |
| 11 | software distributed under the License is distributed on an |
| 12 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| 13 | KIND, either express or implied. See the License for the |
| 14 | specific language governing permissions and limitations |
| 15 | under the License. |
| 16 | *****************************************************************************} |
| 17 | unit DECCipherBase; |
| 18 | |
| 19 | interface |
| 20 | |
| 21 | {$INCLUDE DECOptions.inc} |
| 22 | |
| 23 | uses |
| 24 | {$IFDEF FPC} |
| 25 | SysUtils, Classes, |
| 26 | {$ELSE} |
| 27 | System.SysUtils, System.Classes, Generics.Collections, |
| 28 | {$ENDIF} |
| 29 | DECBaseClass, DECFormatBase; |
| 30 | |
| 31 | type |
| 32 | /// <summary> |
| 33 | /// Possible kindes of cipher algorithms independent of any block |
| 34 | /// concatenation mode etc. |
| 35 | /// <para> |
| 36 | /// ctNull = special "do nothing cipher" |
| 37 | /// </para> |
| 38 | /// <para> |
| 39 | /// ctStream = cipher operating on a stream of bytes instead of blocks |
| 40 | /// </para> |
| 41 | /// <para> |
| 42 | /// ctBlock = cipher operating on blocks of bytes with a fixed size |
| 43 | /// </para> |
| 44 | /// <para> |
| 45 | /// ctSymmetric = cipher where the same key encrypts and decrypts |
| 46 | /// </para> |
| 47 | /// <para> |
| 48 | /// ctAsymetric = cipher where encryption and decryption requires |
| 49 | /// different keys |
| 50 | /// </para> |
| 51 | /// </summary> |
| 52 | TCipherTypes = (ctNull, ctStream, ctBlock, ctSymmetric, ctAsymmetric); |
| 53 | |
| 54 | /// <summary> |
| 55 | /// Actual kind of cipher algorithm |
| 56 | /// </summary> |
| 57 | TCipherType = set of TCipherTypes; |
| 58 | |
| 59 | /// <summary> |
| 60 | /// Padding used to fill the last incomplete block of a block encryption |
| 61 | /// algorithm. To be expanded in a future version |
| 62 | /// </summary> |
| 63 | TBlockFillMode = (fmByte); |
| 64 | |
| 65 | /// <summary> |
| 66 | /// Record containing meta data about a certain cipher |
| 67 | /// </summary> |
| 68 | TCipherContext = packed record |
| 69 | /// <summary> |
| 70 | /// maximal key size in bytes |
| 71 | /// </summary> |
| 72 | KeySize : Integer; |
| 73 | /// <summary> |
| 74 | /// mininmal block size in bytes, e.g. 1 = Streamcipher |
| 75 | /// </summary> |
| 76 | BlockSize : Integer; |
| 77 | /// <summary> |
| 78 | /// internal buffersize in bytes |
| 79 | /// </summary> |
| 80 | BufferSize : Integer; |
| 81 | /// <summary> |
| 82 | /// Size in bytes of the FAdditionalBuffer used by some of the cipher algorithms |
| 83 | /// </summary> |
| 84 | AdditionalBufferSize : Integer; |
| 85 | /// <summary> |
| 86 | /// When true the memory a certain internal pointer (FAdditionalBuffer) |
| 87 | /// points to needs to be backuped during key initialization if no init |
| 88 | /// vector is specified and restored at the end of that init method. |
| 89 | /// Same in Done method as well. |
| 90 | /// </summary> |
| 91 | NeedsAdditionalBufferBackup : Boolean; |
| 92 | /// <summary> |
| 93 | /// Minimum number of rounds allowed for any block cipher having a rounds |
| 94 | /// property. In all other cases it will be set to 1. |
| 95 | /// </summary> |
| 96 | MinRounds : UInt16; |
| 97 | /// <summary> |
| 98 | /// Maximum number of rounds allowed for any block cipher having a rounds |
| 99 | /// property. In all other cases it will be set to 1. |
| 100 | /// </summary> |
| 101 | MaxRounds : UInt16; |
| 102 | |
| 103 | /// <summary> |
| 104 | /// Specifies the kind of cipher |
| 105 | /// </summary> |
| 106 | CipherType : TCipherType; |
| 107 | end; |
| 108 | |
| 109 | /// <summary> |
| 110 | /// TCipher.State represents the internal state of processing |
| 111 | /// <para> |
| 112 | /// csNew : cipher isn't initialized, .Init() must be called before en/decode |
| 113 | /// </para> |
| 114 | /// <para> |
| 115 | /// csNew : cipher isn't initialized, .Init() must be called before en/decode |
| 116 | /// </para> |
| 117 | /// <para> |
| 118 | /// csInitialized : cipher is initialized by .Init(), i.e. Keysetup was processed |
| 119 | /// </para> |
| 120 | /// <para> |
| 121 | /// csEncode : Encoding was started, and more chunks can be encoded, but not decoded |
| 122 | /// </para> |
| 123 | /// <para> |
| 124 | /// csDecode : Decoding was started, and more chunks can be decoded, but not encoded |
| 125 | /// </para> |
| 126 | /// <para> |
| 127 | /// csPadded : trough En/Decoding the messagechunks are padded, no more chunks can |
| 128 | /// be processed, the cipher is blocked |
| 129 | /// </para> |
| 130 | /// <para> |
| 131 | /// csDone : Processing is finished and Cipher.Done was called. Now new En/Decoding |
| 132 | /// can be started without calling .Init() before. csDone is basically |
| 133 | /// identical to csInitialized, except Cipher.Buffer holds the encrypted |
| 134 | /// last state of Cipher.Feedback, thus Cipher.Buffer can be used as C-MAC. |
| 135 | /// </para> |
| 136 | /// </summary> |
| 137 | TCipherState = (csNew, csInitialized, csEncode, csDecode, csPadded, csDone); |
| 138 | /// <summary> |
| 139 | /// Set of cipher states, representing the internal state of processing |
| 140 | /// </summary> |
| 141 | TCipherStates = set of TCipherState; |
| 142 | |
| 143 | /// <summary> |
| 144 | /// This defines how the individual blocks of the data to be processed are |
| 145 | /// linked with each other. |
| 146 | /// |
| 147 | /// Modes cmCBCx, cmCTSx, cmCTSxx, cmCFBx, cmOFBx, cmCFSx, cmECBx are working |
| 148 | /// on Blocks of Cipher.BufferSize bytes, when using a Blockcipher that's equal |
| 149 | /// to Cipher.BlockSize. |
| 150 | /// |
| 151 | /// Modes cmCFB8, cmOFB8, cmCFS8 work on 8 bit Feedback Shift Registers. |
| 152 | /// |
| 153 | /// Modes cmCTSx, cmCFSx, cmCFS8 are proprietary modes developed by Hagen |
| 154 | /// Reddmann. These modes work like cmCBCx, cmCFBx, cmCFB8 but with double |
| 155 | /// XOR'ing of the inputstream into the feedback register. |
| 156 | /// |
| 157 | /// Mode cmECBx needs message padding to be a multiple of Cipher.BlockSize and |
| 158 | /// should be used only in 1-byte Streamciphers. |
| 159 | /// |
| 160 | /// Modes cmCFB8, cmCFBx, cmOFB8, cmOFBx, cmCFS8 and cmCFSx need no padding. |
| 161 | /// |
| 162 | /// Modes cmCTSx, cmCBCx need no external padding, because internally the last |
| 163 | /// truncated block is padded by cmCFS8 or cmCFB8. After padding these Modes |
| 164 | /// cannot be used to process any more data. If needed to process chunks of |
| 165 | /// data then each chunk must be algined to Cipher.BufferSize bytes. |
| 166 | /// |
| 167 | /// Mode cmCTS3 is a proprietary mode developed by Frederik Winkelsdorf. It |
| 168 | /// replaces the CFS8 padding of the truncated final block with a CFSx padding. |
| 169 | /// Useful when converting projects that previously used the old DEC v3.0. It |
| 170 | /// has the same restrictions for external padding and chunk processing as |
| 171 | /// cmCTSx has. |
| 172 | /// </summary> |
| 173 | TCipherMode = ( |
| 174 | cmCTSx, // double CBC, with CFS8 padding of truncated final block |
| 175 | cmCBCx, // Cipher Block Chaining, with CFB8 padding of truncated final block |
| 176 | cmCFB8, // 8bit Cipher Feedback mode |
| 177 | cmCFBx, // CFB on Blocksize of Cipher |
| 178 | cmOFB8, // 8bit Output Feedback mode |
| 179 | cmOFBx, // OFB on Blocksize bytes |
| 180 | cmCFS8, // 8Bit CFS, double CFB |
| 181 | cmCFSx, // CFS on Blocksize bytes |
| 182 | cmECBx, // Electronic Code Book |
| 183 | cmGCM // Galois Counter Mode |
| 184 | {$IFDEF DEC3_CMCTS} |
| 185 | ,cmCTS3 // double CBC, with less secure padding of truncated final block |
| 186 | // for DEC 3.0 compatibility only (see DECOptions.inc) |
| 187 | {$ENDIF DEC3_CMCTS} |
| 188 | ); |
| 189 | |
| 190 | /// <summary> |
| 191 | /// Each cipher algorithm has to implement a Encode and a Decode method which |
| 192 | /// has the same signature as this type. The CipherFormats get these |
| 193 | /// encode/decode methods passed to do their work. |
| 194 | /// </summary> |
| 195 | /// <param name="Source"> |
| 196 | /// Contains the data to be encoded or decoded |
| 197 | /// </param> |
| 198 | /// <param name="Dest"> |
| 199 | /// Contains the data after encoding or decoding |
| 200 | /// </param> |
| 201 | /// <param name="DataSize"> |
| 202 | /// Number of bytes to encode or decode |
| 203 | /// </param> |
| 204 | TDECCipherCodeEvent = procedure(const Source; var Dest; DataSize: Integer) of object; |
| 205 | |
| 206 | /// <summary> |
| 207 | /// Class type of the cipher base class, relevant for the class registration |
| 208 | /// </summary> |
| 209 | TDECCipherClass = class of TDECCipher; |
| 210 | |
| 211 | /// <summary> |
| 212 | /// Base class for all implemented cipher algorithms |
| 213 | /// </summary> |
| 214 | /// <remarks> |
| 215 | /// When adding new block ciphers do never directly inherit from this class! |
| 216 | /// Inherit from TDECCipherFormats. |
| 217 | /// </remarks> |
| 218 | TDECCipher = class(TDECObject) |
| 219 | strict private |
| 220 | /// <summary> |
| 221 | /// This is the complete memory block containing FInitializationVector, |
| 222 | /// FFeedback, FBuffer and FAdditionalBuffer |
| 223 | /// </summary> |
| 224 | FData : PByteArray; |
| 225 | /// <summary> |
| 226 | /// This is the size of FData in byte |
| 227 | /// </summary> |
| 228 | FDataSize : Integer; |
| 229 | strict protected |
| 230 | /// <summary> |
| 231 | /// Padding mode used to concatenate/connect blocks in a block cipher |
| 232 | /// </summary> |
| 233 | FMode : TCipherMode; |
| 234 | /// <summary> |
| 235 | /// Mode used for filling up an incomplete last block in a block cipher |
| 236 | /// </summary> |
| 237 | FFillMode : TBlockFillMode; |
| 238 | /// <summary> |
| 239 | /// Current processing state |
| 240 | /// </summary> |
| 241 | FState: TCipherState; |
| 242 | /// <summary> |
| 243 | /// Size of the internally used processing buffer in byte |
| 244 | /// </summary> |
| 245 | FBufferSize: Integer; |
| 246 | /// <summary> |
| 247 | /// At which position of the buffer are we currently operating? |
| 248 | /// </summary> |
| 249 | FBufferIndex: Integer; |
| 250 | |
| 251 | /// <summary> |
| 252 | /// Some algorithms, mostly the cipher mode ones, need a temporary buffer |
| 253 | /// to work with. Some other methods like Done or Valid cipher need to pass |
| 254 | /// a buffer as parameter as that is ecpected by the called method. |
| 255 | /// </summary> |
| 256 | FBuffer: PByteArray; |
| 257 | |
| 258 | /// <summary> |
| 259 | /// Initialization vector. When using cipher modes to derive a stream |
| 260 | /// cipher from a block cipher algorithm some data from each encrypted block |
| 261 | /// is fed into the encryption of the next block. For the first block there |
| 262 | /// is no such encrypted data yet, so this initialization vector fills this |
| 263 | /// "gap". |
| 264 | /// </summary> |
| 265 | FInitializationVector: PByteArray; |
| 266 | |
| 267 | /// <summary> |
| 268 | /// Size of the initialization vector in byte. Required for algorithms |
| 269 | /// like GCM. |
| 270 | /// </summary> |
| 271 | FInitVectorSize: Integer; |
| 272 | |
| 273 | /// <summary> |
| 274 | /// Cipher modes are used to derive a stream cipher from block cipher |
| 275 | /// algorithms. For this something from the last entrypted block (or for |
| 276 | /// the first block from the vector) is used in the encryption of the next |
| 277 | /// block. It may be XORed with the next block cipher text for isntance. |
| 278 | /// That data "going into the next block encryption" is this feedback array |
| 279 | /// </summary> |
| 280 | FFeedback: PByteArray; |
| 281 | |
| 282 | /// <summary> |
| 283 | /// Size of FAdditionalBuffer in Byte |
| 284 | /// </summary> |
| 285 | FAdditionalBufferSize: Integer; |
| 286 | /// <summary> |
| 287 | /// A buffer some of the cipher algorithms need to operate on. It is |
| 288 | /// some part of FBuffer like FInitializationVector and FFeedback as well. |
| 289 | /// </summary> |
| 290 | FAdditionalBuffer: Pointer; |
| 291 | |
| 292 | /// <summary> |
| 293 | /// If a user does not specify an init vector (IV) during key setup |
| 294 | /// (IV length = 0) the init method generates an IV by encrypting the |
| 295 | /// complete memory reserved for IV. Within this memory block is the memory |
| 296 | /// FAdditionalBuffer points to as well, and for some algorithms this part |
| 297 | /// of the memory may not be altered during initialization so it is |
| 298 | /// backupped to this memory location and restored after the IV got encrypted. |
| 299 | /// In DoDone it needs to be restored as well to prevent any unwanted |
| 300 | /// leftovers which might pose a security issue. |
| 301 | /// </summary> |
| 302 | FAdditionalBufferBackup: Pointer; |
| 303 | |
| 304 | /// <summary> |
| 305 | /// Checks whether the state machine is in one of the states specified as |
| 306 | /// parameter. If not a EDECCipherException will be raised. |
| 307 | /// </summary> |
| 308 | /// <param name="States"> |
| 309 | /// List of states the state machine should be at currently |
| 310 | /// </param> |
| 311 | /// <exception cref="EDECCipherException"> |
| 312 | /// Exception raised if the state machine is not in one of the states |
| 313 | /// specified by the <c>States</c> parameter. |
| 314 | /// </exception> |
| 315 | procedure CheckState(States: TCipherStates); |
| 316 | |
| 317 | /// <summary> |
| 318 | /// Initialize the key, based on the key passed in. This is called before |
| 319 | /// OnAfterInitVectorInitialization is called. |
| 320 | /// </summary> |
| 321 | /// <param name="Key"> |
| 322 | /// Encryption/Decryption key to be used |
| 323 | /// </param> |
| 324 | /// <param name="Size"> |
| 325 | /// Size of the key passed in bytes. |
| 326 | /// </param> |
| 327 | procedure DoInit(const Key; Size: Integer); virtual; abstract; |
| 328 | /// <summary> |
| 329 | /// Allows to run code after the initialization vector has been initialized |
| 330 | /// inside the Init call, which is after DoInit has been called. |
| 331 | /// </summary> |
| 332 | /// <param name="OriginalInitVector"> |
| 333 | /// Value of the init vector as originally passed to the Init call without |
| 334 | /// any initialization steps done to/on it |
| 335 | /// </param> |
| 336 | procedure OnAfterInitVectorInitialization(const OriginalInitVector: TBytes); virtual; abstract; |
| 337 | |
| 338 | /// <summary> |
| 339 | /// This abstract method needs to be overwritten by each concrete encryption |
| 340 | /// algorithm as this is the routine used internally to encrypt a single |
| 341 | /// block of data. |
| 342 | /// </summary> |
| 343 | /// <param name="Source"> |
| 344 | /// Data to be encrypted |
| 345 | /// </param> |
| 346 | /// <param name="Dest"> |
| 347 | /// In this memory the encrypted result will be written |
| 348 | /// </param> |
| 349 | /// <param name="Size"> |
| 350 | /// Size of source in byte |
| 351 | /// </param> |
| 352 | procedure DoEncode(Source, Dest: Pointer; Size: Integer); virtual; abstract; |
| 353 | /// <summary> |
| 354 | /// This abstract method needs to be overwritten by each concrete encryption |
| 355 | /// algorithm as this is the routine used internally to decrypt a single |
| 356 | /// block of data. |
| 357 | /// </summary> |
| 358 | /// <param name="Source"> |
| 359 | /// Data to be decrypted |
| 360 | /// </param> |
| 361 | /// <param name="Dest"> |
| 362 | /// In this memory the decrypted result will be written |
| 363 | /// </param> |
| 364 | /// <param name="Size"> |
| 365 | /// Size of source in byte |
| 366 | /// </param> |
| 367 | procedure DoDecode(Source, Dest: Pointer; Size: Integer); virtual; abstract; |
| 368 | /// <summary> |
| 369 | /// Securely fills the processing buffer with zeroes to make stealing data |
| 370 | /// from memory harder. |
| 371 | /// </summary> |
| 372 | procedure SecureErase; virtual; |
| 373 | |
| 374 | /// <summary> |
| 375 | /// Returns the currently set cipher block mode, means how blocks are |
| 376 | /// linked to each other in order to avoid certain attacks. |
| 377 | /// </summary> |
| 378 | function GetMode: TCipherMode; |
| 379 | |
| 380 | /// <summary> |
| 381 | /// Sets the cipher mode, means how each block is being linked with his |
| 382 | /// predecessor to avoid certain attacks |
| 383 | /// </summary> |
| 384 | procedure SetMode(Value: TCipherMode); |
| 385 | /// <summary> |
| 386 | /// When setting a mode it might need to be initialized and that can |
| 387 | /// usually only be done in a child class. |
| 388 | /// </summary> |
| 389 | procedure InitMode; virtual; abstract; |
| 390 | public |
| 391 | /// <summary> |
| 392 | /// List of registered DEC classes. Key is the Identity of the class. |
| 393 | /// </summary> |
| 394 | class var ClassList : TDECClassList; |
| 395 | |
| 396 | /// <summary> |
| 397 | /// Tries to find a class type by its name |
| 398 | /// </summary> |
| 399 | /// <param name="Name"> |
| 400 | /// Name to look for in the list |
| 401 | /// </param> |
| 402 | /// <returns> |
| 403 | /// Returns the class type if found. if it could not be found a |
| 404 | /// EDECClassNotRegisteredException will be thrown |
| 405 | /// </returns> |
| 406 | /// <exception cref="EDECClassNotRegisteredException"> |
| 407 | /// Exception raised if the class specified by <c>Name</c> is not found |
| 408 | /// </exception> |
| 409 | class function ClassByName(const Name: string): TDECCipherClass; |
| 410 | |
| 411 | /// <summary> |
| 412 | /// Tries to find a class type by its numeric identity DEC assigned to it. |
| 413 | /// Useful for file headers, so they can easily encode numerically which |
| 414 | /// cipher class was being used. |
| 415 | /// </summary> |
| 416 | /// <param name="Identity"> |
| 417 | /// Identity to look for |
| 418 | /// </param> |
| 419 | /// <returns> |
| 420 | /// Returns the class type of the class with the specified identity value |
| 421 | /// or throws an EDECClassNotRegisteredException exception if no class |
| 422 | /// with the given identity has been found |
| 423 | /// </returns> |
| 424 | /// <exception cref="EDECClassNotRegisteredException"> |
| 425 | /// Exception raised if the class specified by <c>Identity</c> is not found |
| 426 | /// </exception> |
| 427 | class function ClassByIdentity(Identity: Int64): TDECCipherClass; |
| 428 | |
| 429 | /// <summary> |
| 430 | /// Provides meta data about the cipher algorithm used like key size. |
| 431 | /// To be overidden in the concrete cipher classes. |
| 432 | /// </summary> |
| 433 | /// <remarks> |
| 434 | /// C++ does not support virtual static functions thus the base cannot be |
| 435 | /// marked 'abstract'. Calling this version of the method will lead to an |
| 436 | /// EDECAbstractError |
| 437 | /// </remarks> |
| 438 | class function Context: TCipherContext; virtual; |
| 439 | |
| 440 | /// <summary> |
| 441 | /// Initializes the instance. Relies in parts on information given by the |
| 442 | /// Context class function. |
| 443 | /// </summary> |
| 444 | constructor Create; override; |
| 445 | /// <summary> |
| 446 | /// Frees internal structures and where necessary does so in a save way so |
| 447 | /// that data in those structures cannot be "stolen". |
| 448 | /// </summary> |
| 449 | destructor Destroy; override; |
| 450 | |
| 451 | /// <summary> |
| 452 | /// Provides information whether the selected block concatenation mode |
| 453 | /// provides authentication functionality or not. |
| 454 | /// </summary> |
| 455 | /// <returns> |
| 456 | /// true if the selected block mode is one providing authentication features |
| 457 | /// as well |
| 458 | /// </returns> |
| 459 | function IsAuthenticated: Boolean; |
| 460 | |
| 461 | /// <summary> |
| 462 | /// Initializes the cipher with the necessary encryption/decryption key |
| 463 | /// </summary> |
| 464 | /// <param name="Key"> |
| 465 | /// Encryption/decryption key. Recommended/required key length is dependant |
| 466 | /// on the concrete algorithm. |
| 467 | /// </param> |
| 468 | /// <param name="Size"> |
| 469 | /// Size of the key in bytes |
| 470 | /// </param> |
| 471 | /// <param name="IVector"> |
| 472 | /// Initialization vector. This contains the values the first block of |
| 473 | /// data to be processed is linked with. This is being done the same way |
| 474 | /// as the 2nd block of the data to be processed will be linked with the |
| 475 | /// first block and so on and this is dependant on the cypher mode set via |
| 476 | /// Mode property |
| 477 | /// </param> |
| 478 | /// <param name="IVectorSize"> |
| 479 | /// Size of the initialization vector in bytes |
| 480 | /// </param> |
| 481 | /// <param name="IFiller"> |
| 482 | /// optional parameter defining the value with which the last block will |
| 483 | /// be filled up if the size of the data to be processed cannot be divided |
| 484 | /// by block size without reminder. Means: if the last block is not |
| 485 | /// completely filled with data. |
| 486 | /// </param> |
| 487 | procedure Init(const Key; Size: Integer; const IVector; IVectorSize: Integer; IFiller: Byte = $FF); overload; |
| 488 | /// <summary> |
| 489 | /// Initializes the cipher with the necessary encryption/decryption key |
| 490 | /// </summary> |
| 491 | /// <param name="Key"> |
| 492 | /// Encryption/decryption key. Recommended/required key length is dependant |
| 493 | /// on the concrete algorithm. |
| 494 | /// </param> |
| 495 | /// <param name="IVector"> |
| 496 | /// Initialization vector. This contains the values the first block of |
| 497 | /// data to be processed is linked with. This is being done the same way |
| 498 | /// as the 2nd block of the data to be processed will be linked with the |
| 499 | /// first block and so on and this is dependant on the cypher mode set via |
| 500 | /// Mode property |
| 501 | /// </param> |
| 502 | /// <param name="IFiller"> |
| 503 | /// optional parameter defining the value with which the last block will |
| 504 | /// be filled up if the size of the data to be processed cannot be divided |
| 505 | /// by block size without reminder. Means: if the last block is not |
| 506 | /// completely filled with data. |
| 507 | /// </param> |
| 508 | procedure Init(const Key: TBytes; const IVector: TBytes; IFiller: Byte = $FF); overload; |
| 509 | /// <summary> |
| 510 | /// Initializes the cipher with the necessary encryption/decryption key |
| 511 | /// </summary> |
| 512 | /// <param name="Key"> |
| 513 | /// Encryption/decryption key. Recommended/required key length is dependant |
| 514 | /// on the concrete algorithm. |
| 515 | /// </param> |
| 516 | /// <param name="IVector"> |
| 517 | /// Initialization vector. This contains the values the first block of |
| 518 | /// data to be processed is linked with. This is being done the same way |
| 519 | /// as the 2nd block of the data to be processed will be linked with the |
| 520 | /// first block and so on and this is dependant on the cypher mode set via |
| 521 | /// Mode property |
| 522 | /// </param> |
| 523 | /// <param name="IFiller"> |
| 524 | /// optional parameter defining the value with which the last block will |
| 525 | /// be filled up if the size of the data to be processed cannot be divided |
| 526 | /// by block size without reminder. Means: if the last block is not |
| 527 | /// completely filled with data. |
| 528 | /// </param> |
| 529 | procedure Init(const Key: RawByteString; const IVector: RawByteString = ''; IFiller: Byte = $FF); overload; |
| 530 | {$IFDEF ANSISTRINGSUPPORTED} |
| 531 | /// <summary> |
| 532 | /// Initializes the cipher with the necessary encryption/decryption key. |
| 533 | /// Only for use with the classic desktop compilers. |
| 534 | /// </summary> |
| 535 | /// <param name="Key"> |
| 536 | /// Encryption/decryption key. Recommended/required key length is dependant |
| 537 | /// on the concrete algorithm. |
| 538 | /// </param> |
| 539 | /// <param name="IVector"> |
| 540 | /// Initialization vector. This contains the values the first block of |
| 541 | /// data to be processed is linked with. This is being done the same way |
| 542 | /// as the 2nd block of the data to be processed will be linked with the |
| 543 | /// first block and so on and this is dependant on the cypher mode set via |
| 544 | /// Mode property |
| 545 | /// </param> |
| 546 | /// <param name="IFiller"> |
| 547 | /// optional parameter defining the value with which the last block will |
| 548 | /// be filled up if the size of the data to be processed cannot be divided |
| 549 | /// by block size without reminder. Means: if the last block is not |
| 550 | /// completely filled with data. |
| 551 | /// </param> |
| 552 | procedure Init(const Key: AnsiString; const IVector: AnsiString = ''; IFiller: Byte = $FF); overload; |
| 553 | {$ENDIF} |
| 554 | {$IFNDEF NEXTGEN} |
| 555 | /// <summary> |
| 556 | /// Initializes the cipher with the necessary encryption/decryption key. |
| 557 | /// Only for use with the classic desktop compilers. |
| 558 | /// </summary> |
| 559 | /// <param name="Key"> |
| 560 | /// Encryption/decryption key. Recommended/required key length is dependant |
| 561 | /// on the concrete algorithm. |
| 562 | /// </param> |
| 563 | /// <param name="IVector"> |
| 564 | /// Initialization vector. This contains the values the first block of |
| 565 | /// data to be processed is linked with. This is being done the same way |
| 566 | /// as the 2nd block of the data to be processed will be linked with the |
| 567 | /// first block and so on and this is dependant on the cypher mode set via |
| 568 | /// Mode property |
| 569 | /// </param> |
| 570 | /// <param name="IFiller"> |
| 571 | /// optional parameter defining the value with which the last block will |
| 572 | /// be filled up if the size of the data to be processed cannot be divided |
| 573 | /// by block size without reminder. Means: if the last block is not |
| 574 | /// completely filled with data. |
| 575 | /// </param> |
| 576 | procedure Init(const Key: WideString; const IVector: WideString = ''; IFiller: Byte = $FF); overload; |
| 577 | {$ENDIF} |
| 578 | |
| 579 | /// <summary> |
| 580 | /// Properly finishes the cryptographic operation. It needs to be called |
| 581 | /// at the end of encrypting or decrypting data, otherwise the last block |
| 582 | /// or last byte of the data will not be properly processed. |
| 583 | /// </summary> |
| 584 | procedure Done; virtual; |
| 585 | |
| 586 | // Encoding / Decoding Routines |
| 587 | // Do not add further methods of that kind here! If needed add them to |
| 588 | // TDECFormattedCipher in DECCipherFormats or inherit from that one. |
| 589 | |
| 590 | /// <summary> |
| 591 | /// Encrypts the contents of a RawByteString. This method is deprecated |
| 592 | /// and should be replaced by a variant expecting TBytes as source in |
| 593 | /// order to not support mistreating strings as binary buffers. |
| 594 | /// </summary> |
| 595 | /// <remarks> |
| 596 | /// This is the direct successor of the EncodeBinary method from DEC 5.2. |
| 597 | /// When block chaining mode ECBx is used |
| 598 | /// (not recommended!), the size of the data passed via this parameter |
| 599 | /// needs to be a multiple of the block size of the algorithm used, |
| 600 | /// otherwise a EDECCipherException exception will be raised! |
| 601 | /// </remarks> |
| 602 | /// <param name="Source"> |
| 603 | /// The data to be encrypted |
| 604 | /// </param> |
| 605 | /// <param name="Format"> |
| 606 | /// Optional parameter. Here a formatting method can be passed. The |
| 607 | /// resulting encrypted data will be formatted with this function, if one |
| 608 | /// has been passed. Examples are hex or base 64 formatting. |
| 609 | /// </param> |
| 610 | /// <returns> |
| 611 | /// Encrypted data. Init must have been called previously. |
| 612 | /// </returns> |
| 613 | /// <exception cref="EDECCipherException"> |
| 614 | /// Exception raised if the length of the data passed as <c>Source</c> |
| 615 | /// is not a multiple of the algorithm's block size. |
| 616 | /// </exception> |
| 617 | function EncodeRawByteString(const Source: RawByteString; |
| 618 | Format: TDECFormatClass = nil): RawByteString; |
| 619 | deprecated; // please use EncodeBytes functions now |
| 620 | // or TCipherFormats.EncodeStringToString |
| 621 | /// <summary> |
| 622 | /// Decrypts the contents of a RawByteString. This method is deprecated |
| 623 | /// and should be replaced by a variant expecting TBytes as source in |
| 624 | /// order to not support mistreating strings as binary buffers. |
| 625 | /// </summary> |
| 626 | /// <remarks> |
| 627 | /// This is the direct successor of the DecodeBinary method from DEC 5.2 |
| 628 | /// When block chaining mode ECBx is used |
| 629 | /// (not recommended!), the size of the data passed via this parameter |
| 630 | /// needs to be a multiple of the block size of the algorithm used, |
| 631 | /// otherwise a EDECCipherException exception will be raised! |
| 632 | /// </remarks> |
| 633 | /// <param name="Source"> |
| 634 | /// The data to be decrypted |
| 635 | /// </param> |
| 636 | /// <param name="Format"> |
| 637 | /// Optional parameter. Here a formatting method can be passed. The |
| 638 | /// data to be decrypted will be formatted with this function, if one |
| 639 | /// has been passed. Examples are hex or base 64 formatting. |
| 640 | /// This is used for removing a formatting applied by the EncodeRawByteString |
| 641 | /// method. |
| 642 | /// </param> |
| 643 | /// <returns> |
| 644 | /// Decrypted data. Init must have been called previously. |
| 645 | /// </returns> |
| 646 | /// <exception cref="EDECCipherException"> |
| 647 | /// Exception raised if the length of the data passed as <c>Source</c> |
| 648 | /// is not a multiple of the algorithm's block size. |
| 649 | /// </exception> |
| 650 | function DecodeRawByteString(const Source: RawByteString; |
| 651 | Format: TDECFormatClass = nil): RawByteString; deprecated; // please use DecodeBytes functions now |
| 652 | |
| 653 | /// <summary> |
| 654 | /// Encrypts the contents of a ByteArray. |
| 655 | /// </summary> |
| 656 | /// <param name="Source"> |
| 657 | /// The data to be encrypted. When block chaining mode ECBx is used |
| 658 | /// (not recommended!), the size of the data passed via this parameter |
| 659 | /// needs to be a multiple of the block size of the algorithm used, |
| 660 | /// otherwise a EDECCipherException exception will be raised! |
| 661 | /// </param> |
| 662 | /// <param name="Format"> |
| 663 | /// Optional parameter. Here a formatting method can be passed. The |
| 664 | /// resulting encrypted data will be formatted with this function, if one |
| 665 | /// has been passed. Examples are hex or base 64 formatting. |
| 666 | /// </param> |
| 667 | /// <returns> |
| 668 | /// Encrypted data. Init must have been called previously. |
| 669 | /// </returns> |
| 670 | /// <exception cref="EDECCipherException"> |
| 671 | /// Exception raised if the length of the data passed as <c>Source</c> |
| 672 | /// is not a multiple of the algorithm's block size. |
| 673 | /// </exception> |
| 674 | function EncodeBytes(const Source: TBytes; Format: TDECFormatClass = nil): TBytes; |
| 675 | /// <summary> |
| 676 | /// Decrypts the contents of a ByteArray. |
| 677 | /// </summary> |
| 678 | /// <param name="Source"> |
| 679 | /// The data to be decrypted. When block chaining mode ECBx is used |
| 680 | /// (not recommended!), the size of the data passed via this parameter |
| 681 | /// needs to be a multiple of the block size of the algorithm used, |
| 682 | /// otherwise a EDECCipherException exception will be raised! |
| 683 | /// </param> |
| 684 | /// <param name="Format"> |
| 685 | /// Optional parameter. Here a formatting method can be passed. The |
| 686 | /// data to be decrypted will be formatted with this function, if one |
| 687 | /// has been passed. Examples are hex or base 64 formatting. |
| 688 | /// This is used for removing a formatting applied by the EncodeRawByteString |
| 689 | /// method. |
| 690 | /// </param> |
| 691 | /// <returns> |
| 692 | /// Decrypted data. Init must have been called previously. |
| 693 | /// </returns> |
| 694 | /// <exception cref="EDECCipherException"> |
| 695 | /// Exception raised if the length of the data passed as <c>Source</c> |
| 696 | /// is not a multiple of the algorithm's block size. |
| 697 | /// </exception> |
| 698 | function DecodeBytes(const Source: TBytes; Format: TDECFormatClass): TBytes; |
| 699 | |
| 700 | // CalcMACBytes deferred since the current implementation would neither be |
| 701 | // performant (that would require another TFormatBase.Encode variant from |
| 702 | // pointer to TBytes and that would require a new method name as overloads |
| 703 | // may not differ in return values only and it would require a lot of unit |
| 704 | // tests to get implemented. Deferred in particular also due to not yet |
| 705 | // really understanding the purpose of CalcMAC |
| 706 | // function CalcMACByte(Format: TDECFormatClass = nil): TBytes; overload; |
| 707 | |
| 708 | // Deprecated directive commented out, as replacement CalcMACByte has not |
| 709 | // been implemented yet, see remark above. Use case for CalcMAC is not clear |
| 710 | // yet either. |
| 711 | function CalcMAC(Format: TDECFormatClass = nil): RawByteString; overload; //deprecated; // please use the TBytes based overload; |
| 712 | |
| 713 | // properties |
| 714 | |
| 715 | /// <summary> |
| 716 | /// Provides the size of the initialization vector in bytes. |
| 717 | /// </summary> |
| 718 | property InitVectorSize: Integer |
| 719 | read FBufferSize; |
| 720 | /// <summary> |
| 721 | /// Provides access to the contents of the initialization vector |
| 722 | /// </summary> |
| 723 | property InitVector: PByteArray |
| 724 | read FInitializationVector; |
| 725 | |
| 726 | /// <summary> |
| 727 | /// Cipher modes are used to derive a stream cipher from block cipher |
| 728 | /// algorithms. For this something from the last entrypted block (or for |
| 729 | /// the first block from the vector) is used in the encryption of the next |
| 730 | /// block. It may be XORed with the next block cipher text for instance. |
| 731 | /// That data "going into the next block encryption" is stored in this |
| 732 | /// feedback array. The size usually depends on the block size of the |
| 733 | /// cipher algorithm. |
| 734 | /// </summary> |
| 735 | property Feedback: PByteArray |
| 736 | read FFeedback; |
| 737 | /// <summary> |
| 738 | /// Allows to query the current internal processing state |
| 739 | /// </summary> |
| 740 | property State: TCipherState |
| 741 | read FState; |
| 742 | /// <summary> |
| 743 | /// Mode used for padding data to be encrypted/decrypted. See TCipherMode. |
| 744 | /// </summary> |
| 745 | property Mode: TCipherMode |
| 746 | read GetMode |
| 747 | write SetMode; |
| 748 | |
| 749 | /// <summary> |
| 750 | /// Mode used for filling up an incomplete last block in a block cipher |
| 751 | /// </summary> |
| 752 | property FillMode: TBlockFillMode |
| 753 | read FFillMode |
| 754 | write FFillMode; |
| 755 | end; |
| 756 | |
| 757 | /// <summary> |
| 758 | /// Returns the passed cipher class type if it is not nil. Otherwise the |
| 759 | /// class type class set per SetDefaultCipherClass is being returned. If using |
| 760 | /// the DECCiphers unit that one registers TCipher_Null in the initialization |
| 761 | /// </summary> |
| 762 | /// <param name="CipherClass"> |
| 763 | /// Class type of a cipher class like TCipher_Blowfish or nil, if no |
| 764 | /// encryption/decryption is desired. |
| 765 | /// </param> |
| 766 | /// <returns> |
| 767 | /// Passed class type or defined default cipher class type, depending on |
| 768 | /// CipherClass parameter value. |
| 769 | /// </returns> |
| 770 | function ValidCipher(CipherClass: TDECCipherClass = nil): TDECCipherClass; |
| 771 | |
| 772 | /// <summary> |
| 773 | /// Defines which cipher class to return by ValidCipher if passing nil to that |
| 774 | /// </summary> |
| 775 | /// <param name="CipherClass"> |
| 776 | /// Class type of a cipher class to return by ValidCipher if passing nil to |
| 777 | /// that one. This parameter should not be nil! |
| 778 | /// </param> |
| 779 | procedure SetDefaultCipherClass(CipherClass: TDECCipherClass); |
| 780 | |
| 781 | /// <summary> |
| 782 | /// Provides information whether a certain block concatenation mode |
| 783 | /// provides authentication functionality or not. |
| 784 | /// </summary> |
| 785 | /// <param name="BlockMode"> |
| 786 | /// Block mode to check fo authentication features |
| 787 | /// </param> |
| 788 | /// <returns> |
| 789 | /// true if the selected block mode is one providing authentication features |
| 790 | /// as well |
| 791 | /// </returns> |
| 792 | function IsAuthenticatedBlockMode(BlockMode: TCipherMode): Boolean; |
| 793 | |
| 794 | implementation |
| 795 | |
| 796 | uses |
| 797 | {$IFDEF FPC} |
| 798 | TypInfo, |
| 799 | {$ELSE} |
| 800 | System.TypInfo, |
| 801 | {$ENDIF} |
| 802 | DECTypes, DECUtil; |
| 803 | |
| 804 | {$IFOPT Q+}{$DEFINE RESTORE_OVERFLOWCHECKS}{$Q-}{$ENDIF} |
| 805 | {$IFOPT R+}{$DEFINE RESTORE_RANGECHECKS}{$R-}{$ENDIF} |
| 806 | |
| 807 | resourcestring |
| 808 | sAlreadyPadded = 'Cipher has already been padded, cannot process message'; |
| 809 | sInvalidState = 'Cipher is not in valid state for this action'; |
| 810 | sNoKeyMaterialGiven = 'No Keymaterial given (Security Issue)'; |
| 811 | sKeyMaterialTooLarge = 'Keymaterial is too large for use (Security Issue)'; |
| 812 | sIVMaterialTooLarge = 'Initvector is too large for use (Security Issue)'; |
| 813 | sInvalidMACMode = 'Invalid Cipher mode to compute MAC'; |
| 814 | sCipherNoDefault = 'No default cipher has been registered'; |
| 815 | |
| 816 | var |
| 817 | /// <summary> |
| 818 | /// Cipher class returned by ValidCipher if nil is passed as parameter to it |
| 819 | /// </summary> |
| 820 | FDefaultCipherClass: TDECCipherClass = nil; |
| 821 | |
| 822 | function ValidCipher(CipherClass: TDECCipherClass): TDECCipherClass; |
| 823 | begin |
| 824 | if CipherClass <> nil then |
| 825 | Result := CipherClass |
| 826 | else |
| 827 | Result := FDefaultCipherClass; |
| 828 | |
| 829 | if Result = nil then |
| 830 | raise EDECCipherException.CreateRes(@sCipherNoDefault); |
| 831 | end; |
| 832 | |
| 833 | procedure SetDefaultCipherClass(CipherClass: TDECCipherClass); |
| 834 | begin |
| 835 | Assert(Assigned(CipherClass), 'Do not set a nil default cipher class!'); |
| 836 | |
| 837 | FDefaultCipherClass := CipherClass; |
| 838 | end; |
| 839 | |
| 840 | function IsAuthenticatedBlockMode(BlockMode: TCipherMode): Boolean; |
| 841 | begin |
| 842 | Result := BlockMode = cmGCM; |
| 843 | end; |
| 844 | |
| 845 | { TDECCipher } |
| 846 | |
| 847 | constructor TDECCipher.Create; |
| 848 | var |
| 849 | MustAdditionalBufferSave: Boolean; |
| 850 | begin |
| 851 | inherited Create; |
| 852 | |
| 853 | FBufferSize := Context.BufferSize; |
| 854 | FAdditionalBufferSize := Context.AdditionalBufferSize; |
| 855 | MustAdditionalBufferSave := Context.NeedsAdditionalBufferBackup; |
| 856 | |
| 857 | // Initialization vector, feedback, buffer, additional buffer |
| 858 | FDataSize := FBufferSize * 3 + FAdditionalBufferSize; |
| 859 | |
| 860 | if MustAdditionalBufferSave then |
| 861 | // if contents of the FAdditionalBuffer needs to be saved increase buffer size |
| 862 | // by FAdditionalBufferSize so FAdditionalBuffer and then FAdditionalBufferBackup |
| 863 | // fit in the buffer |
| 864 | Inc(FDataSize, FAdditionalBufferSize); |
| 865 | |
| 866 | // ReallocMemory instead of ReallocMem due to C++ compatibility as per 10.1 help |
| 867 | FData := ReallocMemory(FData, FDataSize); |
| 868 | FInitializationVector := @FData[0]; |
| 869 | FInitVectorSize := 0; |
| 870 | FFeedback := @FInitializationVector[FBufferSize]; |
| 871 | FBuffer := @FFeedback[FBufferSize]; |
| 872 | FAdditionalBuffer := @FBuffer[FBufferSize]; |
| 873 | |
| 874 | if MustAdditionalBufferSave then |
| 875 | // buffer contents: FData, then FFeedback, then FBuffer then FAdditionalBuffer |
| 876 | FAdditionalBufferBackup := @PByteArray(FAdditionalBuffer)[FAdditionalBufferSize] |
| 877 | else |
| 878 | FAdditionalBufferBackup := nil; |
| 879 | |
| 880 | FFillMode := fmByte; |
| 881 | FState := csNew; |
| 882 | |
| 883 | SecureErase; |
| 884 | end; |
| 885 | |
| 886 | destructor TDECCipher.Destroy; |
| 887 | begin |
| 888 | SecureErase; |
| 889 | // FreeMem instead of ReallocMemory which produced a memory leak. ReallocMemory |
| 890 | // was used instead of ReallocMem due to C++ compatibility as per 10.1 help |
| 891 | FreeMem(FData, FDataSize); |
| 892 | FInitializationVector := nil; |
| 893 | FFeedback := nil; |
| 894 | FBuffer := nil; |
| 895 | FAdditionalBuffer := nil; |
| 896 | FAdditionalBufferBackup := nil; |
| 897 | inherited Destroy; |
| 898 | end; |
| 899 | |
| 900 | procedure TDECCipher.SetMode(Value: TCipherMode); |
| 901 | begin |
| 902 | if Value <> FMode then |
| 903 | begin |
| 904 | if not (FState in [csNew, csInitialized, csDone]) then |
| 905 | Done; |
| 906 | |
| 907 | FMode := Value; |
| 908 | InitMode; |
| 909 | end; |
| 910 | end; |
| 911 | |
| 912 | procedure TDECCipher.CheckState(States: TCipherStates); |
| 913 | begin |
| 914 | if not (FState in States) then |
| 915 | begin |
| 916 | if FState = csPadded then |
| 917 | raise EDECCipherException.CreateRes(@sAlreadyPadded) |
| 918 | else |
| 919 | raise EDECCipherException.CreateRes(@sInvalidState); |
| 920 | end; |
| 921 | end; |
| 922 | |
| 923 | class function TDECCipher.ClassByIdentity(Identity: Int64): TDECCipherClass; |
| 924 | begin |
| 925 | result := TDECCipherClass(ClassList.ClassByIdentity(Identity)); |
| 926 | end; |
| 927 | |
| 928 | class function TDECCipher.ClassByName(const Name: string): TDECCipherClass; |
| 929 | begin |
| 930 | result := TDECCipherClass(ClassList.ClassByName(Name)); |
| 931 | end; |
| 932 | |
| 933 | class function TDECCipher.Context: TCipherContext; |
| 934 | begin |
| 935 | // C++ does not support virtual static functions thus the base cannot be |
| 936 | // marked 'abstract'. This is our workaround: |
| 937 | raise EDECAbstractError.Create(GetShortClassName); |
| 938 | end; |
| 939 | |
| 940 | procedure TDECCipher.Init(const Key; Size: Integer; const IVector; IVectorSize: Integer; IFiller: Byte); |
| 941 | var |
| 942 | OriginalInitVector : TBytes; |
| 943 | begin |
| 944 | FState := csNew; |
| 945 | FInitVectorSize := IVectorSize; |
| 946 | SecureErase; |
| 947 | |
| 948 | if (Size > Context.KeySize) and (not (ctNull in Context.CipherType)) then |
| 949 | raise EDECCipherException.CreateRes(@sKeyMaterialTooLarge); |
| 950 | |
| 951 | if (FInitVectorSize > FBufferSize) and (not (FMode = cmGCM)) then |
| 952 | raise EDECCipherException.CreateRes(@sIVMaterialTooLarge); |
| 953 | |
| 954 | DoInit(Key, Size); |
| 955 | if FAdditionalBufferBackup <> nil then |
| 956 | // create backup of FBuffer |
| 957 | Move(FAdditionalBuffer^, FAdditionalBufferBackup^, FAdditionalBufferSize); |
| 958 | |
| 959 | FillChar(FInitializationVector^, FBufferSize, IFiller); |
| 960 | |
| 961 | SetLength(OriginalInitVector, IVectorSize); |
| 962 | if (IVectorSize > 0) then |
| 963 | Move(IVector, OriginalInitVector[0], IVectorSize); |
| 964 | |
| 965 | // GCM needs same treatment as empty IV even if IV specified |
| 966 | if (IVectorSize = 0) or (FMode = cmGCM) then |
| 967 | begin |
| 968 | DoEncode(FInitializationVector, FInitializationVector, FBufferSize); |
| 969 | if FAdditionalBufferBackup <> nil then |
| 970 | // Restore backup fo FBuffer |
| 971 | Move(FAdditionalBufferBackup^, FAdditionalBuffer^, FAdditionalBufferSize); |
| 972 | end |
| 973 | else |
| 974 | Move(IVector, FInitializationVector^, IVectorSize); |
| 975 | |
| 976 | OnAfterInitVectorInitialization(OriginalInitVector); |
| 977 | |
| 978 | Move(FInitializationVector^, FFeedback^, FBufferSize); |
| 979 | |
| 980 | FState := csInitialized; |
| 981 | end; |
| 982 | |
| 983 | procedure TDECCipher.Init(const Key: TBytes; const IVector: TBytes; IFiller: Byte = $FF); |
| 984 | begin |
| 985 | // GCM allows empty key as the authentication still works |
| 986 | if (Length(Key) = 0) and (not (ctNull in Context.CipherType)) and |
| 987 | (not (FMode = cmGCM)) then |
| 988 | raise EDECCipherException.CreateRes(@sNoKeyMaterialGiven); |
| 989 | |
| 990 | if IVector <> nil then |
| 991 | Init(Key[0], Length(Key), IVector[0], Length(IVector), IFiller) |
| 992 | else |
| 993 | Init(Key[0], Length(Key), NullStr, 0, IFiller); |
| 994 | end; |
| 995 | |
| 996 | procedure TDECCipher.Init(const Key : RawByteString; |
| 997 | const IVector : RawByteString = ''; |
| 998 | IFiller : Byte = $FF); |
| 999 | begin |
| 1000 | // GCM allows empty key as the authentication still works |
| 1001 | if (Length(Key) = 0) and (not (ctNull in Context.CipherType)) and |
| 1002 | (not (FMode = cmGCM)) then |
| 1003 | raise EDECCipherException.CreateRes(@sNoKeyMaterialGiven); |
| 1004 | |
| 1005 | if Length(IVector) > 0 then |
| 1006 | {$IF CompilerVersion >= 24.0} |
| 1007 | Init(Key[Low(Key)], Length(Key) * SizeOf(Key[Low(Key)]), |
| 1008 | IVector[Low(IVector)], Length(IVector) * SizeOf(IVector[Low(IVector)]), IFiller) |
| 1009 | {$ELSE} |
| 1010 | Init(Key[1], Length(Key) * SizeOf(Key[1]), |
| 1011 | IVector[1], Length(IVector) * SizeOf(IVector[1]), IFiller) |
| 1012 | {$IFEND} |
| 1013 | else |
| 1014 | {$IF CompilerVersion >= 24.0} |
| 1015 | Init(Key[Low(Key)], Length(Key) * SizeOf(Key[Low(Key)]), NullStr, 0, IFiller); |
| 1016 | {$ELSE} |
| 1017 | Init(Key[1], Length(Key) * SizeOf(Key[1]), NullStr, 0, IFiller); |
| 1018 | {$IFEND} |
| 1019 | end; |
| 1020 | |
| 1021 | |
| 1022 | {$IFDEF ANSISTRINGSUPPORTED} |
| 1023 | procedure TDECCipher.Init(const Key, IVector: AnsiString; IFiller: Byte); |
| 1024 | begin |
| 1025 | if (Length(Key) = 0) and (not (ctNull in Context.CipherType)) then |
| 1026 | raise EDECCipherException.Create(sNoKeyMaterialGiven); |
| 1027 | |
| 1028 | if Length(IVector) > 0 then |
| 1029 | {$IF CompilerVersion >= 24.0} |
| 1030 | Init(Key[Low(Key)], Length(Key) * SizeOf(Key[Low(Key)]), |
| 1031 | IVector[Low(IVector)], Length(IVector) * SizeOf(Low(IVector)), IFiller) |
| 1032 | {$ELSE} |
| 1033 | Init(Key[1], Length(Key) * SizeOf(Key[Low(Key)]), |
| 1034 | IVector[IVector[1]], Length(IVector) * SizeOf(IVector[1]), IFiller) |
| 1035 | {$IFEND} |
| 1036 | else |
| 1037 | {$IF CompilerVersion >= 24.0} |
| 1038 | Init(Key[Low(Key)], Length(Key) * SizeOf(Key[Low(Key)]), NullStr, 0, IFiller); |
| 1039 | {$ELSE} |
| 1040 | Init(Key[1], Length(Key) * SizeOf(Key[1]), NullStr, 0, IFiller); |
| 1041 | {$IFEND} |
| 1042 | end; |
| 1043 | {$ENDIF} |
| 1044 | |
| 1045 | |
| 1046 | {$IFNDEF NEXTGEN} |
| 1047 | procedure TDECCipher.Init(const Key, IVector: WideString; IFiller: Byte); |
| 1048 | begin |
| 1049 | // GCM allows empty key as the authentication still works |
| 1050 | if (Length(Key) = 0) and (not (ctNull in Context.CipherType)) and |
| 1051 | (not (FMode = cmGCM)) then |
| 1052 | raise EDECCipherException.CreateRes(@sNoKeyMaterialGiven); |
| 1053 | |
| 1054 | if Length(IVector) > 0 then |
| 1055 | {$IF CompilerVersion >= 24.0} |
| 1056 | Init(Key[Low(Key)], Length(Key) * SizeOf(Key[Low(Key)]), |
| 1057 | IVector[Low(IVector)], Length(IVector) * SizeOf(IVector[Low(IVector)]), IFiller) |
| 1058 | {$ELSE} |
| 1059 | Init(Key[1], Length(Key) * SizeOf(Key[1]), |
| 1060 | IVector[1], Length(IVector) * SizeOf(IVector[1]), IFiller) |
| 1061 | {$IFEND} |
| 1062 | else |
| 1063 | {$IF CompilerVersion >= 24.0} |
| 1064 | Init(Key[Low(Key)], Length(Key) * SizeOf(Key[Low(Key)]), NullStr, 0, IFiller); |
| 1065 | {$ELSE} |
| 1066 | Init(Key[1], Length(Key) * SizeOf(Key[1]), NullStr, 0, IFiller); |
| 1067 | {$IFEND} |
| 1068 | end; |
| 1069 | {$ENDIF} |
| 1070 | |
| 1071 | function TDECCipher.IsAuthenticated: Boolean; |
| 1072 | begin |
| 1073 | Result := IsAuthenticatedBlockMode(FMode); |
| 1074 | end; |
| 1075 | |
| 1076 | procedure TDECCipher.Done; |
| 1077 | begin |
| 1078 | if FState <> csDone then |
| 1079 | begin |
| 1080 | FState := csDone; |
| 1081 | FBufferIndex := 0; |
| 1082 | DoEncode(FFeedback, FBuffer, FBufferSize); |
| 1083 | Move(FInitializationVector^, FFeedback^, FBufferSize); |
| 1084 | if FAdditionalBufferBackup <> nil then |
| 1085 | Move(FAdditionalBufferBackup^, FAdditionalBuffer^, FAdditionalBufferSize); |
| 1086 | end; |
| 1087 | end; |
| 1088 | |
| 1089 | procedure TDECCipher.SecureErase; |
| 1090 | begin |
| 1091 | ProtectBuffer(FData[0], FDataSize); |
| 1092 | end; |
| 1093 | |
| 1094 | function TDECCipher.EncodeRawByteString(const Source: RawByteString; Format: TDECFormatClass): RawByteString; |
| 1095 | var |
| 1096 | b : TBytes; |
| 1097 | begin |
| 1098 | SetLength(b, 0); |
| 1099 | if Length(Source) > 0 then |
| 1100 | begin |
| 1101 | {$IF CompilerVersion >= 24.0} |
| 1102 | SetLength(b, Length(Source) * SizeOf(Source[Low(Source)])); |
| 1103 | DoEncode(@Source[low(Source)], @b[0], Length(Source) * SizeOf(Source[low(Source)])); |
| 1104 | {$ELSE} |
| 1105 | SetLength(b, Length(Source) * SizeOf(Source[1])); |
| 1106 | DoEncode(@Source[1], @b[0], Length(Source) * SizeOf(Source[1])); |
| 1107 | {$IFEND} |
| 1108 | Result := BytesToRawString(ValidFormat(Format).Encode(b)); |
| 1109 | end; |
| 1110 | end; |
| 1111 | |
| 1112 | function TDECCipher.GetMode: TCipherMode; |
| 1113 | begin |
| 1114 | Result := FMode; |
| 1115 | end; |
| 1116 | |
| 1117 | function TDECCipher.EncodeBytes(const Source: TBytes; Format: TDECFormatClass = nil): TBytes; |
| 1118 | begin |
| 1119 | SetLength(Result, 0); |
| 1120 | if Length(Source) > 0 then |
| 1121 | begin |
| 1122 | SetLength(Result, Length(Source) * SizeOf(Source[0])); |
| 1123 | DoEncode(@Source[0], @Result[0], Length(Source) * SizeOf(Source[0])); |
| 1124 | Result := ValidFormat(Format).Encode(Result); |
| 1125 | end; |
| 1126 | end; |
| 1127 | |
| 1128 | function TDECCipher.DecodeRawByteString(const Source: RawByteString; Format: TDECFormatClass): RawByteString; |
| 1129 | var |
| 1130 | b : TBytes; |
| 1131 | begin |
| 1132 | SetLength(Result, 0); |
| 1133 | if Length(Source) > 0 then |
| 1134 | begin |
| 1135 | // Delphi 10.1 Berlin and 10.2 Tokyo will issue a W1057 implicit string |
| 1136 | // conversion warning here because the RawByteString BytesOf function is by |
| 1137 | // mistake in a $IFNDEF NEXTGEN block. See QP report: |
| 1138 | // https://quality.embarcadero.com/browse/RSP-20574 |
| 1139 | // This has been fixed in 10.3.0 Rio |
| 1140 | b := ValidFormat(Format).Decode(BytesOf(Source)); |
| 1141 | |
| 1142 | {$IF CompilerVersion >= 24.0} |
| 1143 | DoDecode(@b[0], @Result[Low(Result)], Length(Result) * SizeOf(Result[Low(Result)])); |
| 1144 | {$ELSE} |
| 1145 | DoDecode(@b[0], @Result[1], Length(Result) * SizeOf(Result[1])); |
| 1146 | {$IFEND} |
| 1147 | end; |
| 1148 | end; |
| 1149 | |
| 1150 | function TDECCipher.DecodeBytes(const Source: TBytes; Format: TDECFormatClass): TBytes; |
| 1151 | begin |
| 1152 | SetLength(Result, 0); |
| 1153 | if Length(Source) > 0 then |
| 1154 | begin |
| 1155 | Result := ValidFormat(Format).Decode(Source); |
| 1156 | DoDecode(@Result[0], @Result[0], Length(Result) * SizeOf(Result[0])); |
| 1157 | end; |
| 1158 | end; |
| 1159 | |
| 1160 | |
| 1161 | function TDECCipher.CalcMAC(Format: TDECFormatClass): RawByteString; |
| 1162 | begin |
| 1163 | Done; |
| 1164 | if FMode in [cmECBx] then |
| 1165 | raise EDECException.CreateRes(@sInvalidMACMode) |
| 1166 | else |
| 1167 | Result := ValidFormat(Format).Encode(FBuffer^, FBufferSize); |
| 1168 | { TODO : How to rewrite? EncodeBytes cannot be called directly like that } |
| 1169 | end; |
| 1170 | |
| 1171 | //function TDECCipher.CalcMACByte(Format: TDECFormatClass): TBytes; |
| 1172 | //begin |
| 1173 | // Done; |
| 1174 | // if FMode in [cmECBx] then |
| 1175 | // raise EDECCipherException.Create(sInvalidMACMode) |
| 1176 | // else |
| 1177 | // begin |
| 1178 | // Result := System.SysUtils.BytesOf(ValidFormat(Format).Encode(FBuffer^, FBufferSize)); |
| 1179 | // end; |
| 1180 | //end; |
| 1181 | |
| 1182 | {$IFDEF RESTORE_RANGECHECKS}{$R+}{$ENDIF} |
| 1183 | {$IFDEF RESTORE_OVERFLOWCHECKS}{$Q+}{$ENDIF} |
| 1184 | |
| 1185 | {$IFDEF DELPHIORBCB} |
| 1186 | procedure ModuleUnload(Instance: NativeUInt); |
| 1187 | var // automaticaly deregistration/releasing |
| 1188 | i: Integer; |
| 1189 | Items: TArray<TPair<Int64, TDECCLass>>; |
| 1190 | begin |
| 1191 | // C++Builder calls this function for our own module, but we destroy the ClassList |
| 1192 | // in that case in the finalization section anyway. |
| 1193 | if (Instance <> HInstance) and |
| 1194 | (TDECCipher.ClassList <> nil) and (TDECCipher.ClassList.Count > 0) then |
| 1195 | begin |
| 1196 | Items := TDECCipher.ClassList.ToArray; |
| 1197 | for i := Length(Items) - 1 downto 0 do |
| 1198 | begin |
| 1199 | if FindClassHInstance(Items[i].Value) = HINST(HInstance) then |
| 1200 | TDECCipher.ClassList.Remove(Items[i].Key); |
| 1201 | end; |
| 1202 | end; |
| 1203 | end; |
| 1204 | {$ENDIF DELPHIORBCB} |
| 1205 | |
| 1206 | initialization |
| 1207 | // Code for packages and dynamic extension of the class registration list |
| 1208 | {$IFDEF DELPHIORBCB} |
| 1209 | AddModuleUnloadProc(ModuleUnload); |
| 1210 | {$ENDIF DELPHIORBCB} |
| 1211 | |
| 1212 | TDECCipher.ClassList := TDECClassList.Create; |
| 1213 | |
| 1214 | finalization |
| 1215 | // Ensure no further instances of classes registered in the registraiotn list |
| 1216 | // are possible through the list after this unit has been unloaded by unloding |
| 1217 | // the package this unit is in |
| 1218 | {$IFDEF DELPHIORBCB} |
| 1219 | RemoveModuleUnloadProc(ModuleUnload); |
| 1220 | {$ENDIF DELPHIORBCB} |
| 1221 | |
| 1222 | TDECCipher.ClassList.Free; |
| 1223 | end. |


Welcome to SematAcc, the Essence Accelerator system!
This tool is designed to speed up the learning of Essence Theory in Software Engineering (see Semat website) and to easily test it with any software project in your company.
The tool is implemented by S4FS at the Free University of Bozen-Bolzano in Italy and it is free for everyone to use.
We are seeking for Essence enthusiasts to join in to the development of the SematAcc.
If you became interested, please contact professor Pekka Abrahamsson at firstname.lastname(at)unibz.it.
A demo project is available at /demo. It does not require user
registration.
For project management, please create an account and login.
See the About page of this website for more information.


Note: Body Mass Index (BMI) is a measure of body fat based on height and weight. Body Mass Index is a simple calculation using a person’s height and weight. The formula is BMI = kg/m2 where kg is a person’s weight in kilograms and m2 is their height in metres squared. A BMI of 25.0 or more is overweight, while the healthy range is 18.5 to 24.9. BMI applies to most adults 18-65 years.


| Prev | Next | _reference |
| A | |
|
add | Elementwise Addition |
| C | |
|
cholesky | Cholesky Factor a Matrix Division |
|
cholesky.cpp | Cholesky Factor a Matrix Source Code |
| D | |
|
diag_prod | Diagonal Matrix Product with General Matrix |
|
diag_prod.cpp | Diagonal Matrix Product with General Matrix Source Code |
| E | |
|
element_div | Elementwise Division |
|
element_prod | Elementwise Product |
|
element_unary | Matlab or Octave Elementwise Unary Functions |
|
element_unary.cpp | Elementwise Unary Functions Source Code |
|
elementwise | Elementwise Operations |
|
extend | Extending a Vector |
| G | |
|
getstarted | Getting Started |
| L | |
|
library | Adding a New Routine to the Mat2cpp Library |
|
License | The mat2cpp Software License |
| M | |
|
mat2cpp | Example Conversion of Matlab or Octave to C++ using Ublas |
|
mat2cpp.hpp | The Matlab or Octave to C++ Using Ublas Include File |
|
mat2cpp_ok.cpp | Run C++ Version of Examples |
|
mat2cpp_ok.m | Run Matlab or Octave Version of Examples |
|
matrix_div | Matrix Division |
|
matrix_div.cpp | Matrix Division Source Code |
|
matrix_prod | Matrix Product |
|
matrixwise | Matrixwise Operations |
|
max | Maximum Element of a Matrix |
|
max.cpp | Maximum Element of a Matrix Source code |
|
min | Minimum Element of a Matrix |
|
min.cpp | Minimum Element of a Matrix Source Code |
|
mztuni | C++ Marsaglia Zaman Tsang Uniform Random Number Generator |
|
mztuni.cpp | C++ Marsaglia Zaman Tsang Uniform Random Number Source Code |
|
mztuni_ok.cpp | mztuni: Example and Test |
| N | |
|
News | The mat2cpp News file |
| O | |
|
ones | Matrix of Ones |
|
operation | Operations That Have Conversions |
|
other | Other Operations |
| R | |
|
rand | Uniform Random Matrix |
|
rand.cpp | Uniform Random Matrix Source Code |
|
randn | Normal Random Matrix |
|
randn.cpp | Normal Random Matrix Source Code |
| S | |
|
scalar | Convert Matrix to Scalar |
|
scalar.cpp | Convert Matrix to Scalar Source Code |
|
scalar_div | Scalar Division |
|
scalar_prod | Scalar Product |
|
scalar_valued | Scalar Valued Operations |
|
size | Matrix Size |
|
slice | Matrix Slices |
|
sub | Elementwise Subtraction |
|
sum | Sum The Elements of a Matlab |
|
sum.cpp | Sum The Elements of a Matlab Source Code |
| T | |
|
transpose | Matrix Transpose |
| Z | |
|
zeros | Matrix of Zeros |


Our group uses Slack as a means to communicate and collaborate.
If you would like access, please come to a meeting or fill out the form below.
--- layout: default title: Chat ---
Our group uses Slack as a means to communicate and collaborate.
If you would like access, please come to a meeting or fill out the form below.