text:
declare let str: string;
declare let strOrNull: string | null;
declare let strOrUndefined: string | undefined;
declare let date: Date;
declare let anyObj: any;
declare let num: number;
declare let error: Error;
declare let bool: boolean;
declare let boolOrUndefined: boolean | undefined;
declare let apiGwEvtReqCtx: AWSLambda.APIGatewayEventRequestContext;
declare let apiGwEvtReqCtxOpt: AWSLambda.APIGatewayEventRequestContext | null | undefined;
declare let apiGwEvt: AWSLambda.APIGatewayEvent;
declare let customAuthorizerEvt: AWSLambda.CustomAuthorizerEvent;
declare let clientCtx: AWSLambda.ClientContext;
declare let clientCtxOrUndefined: AWSLambda.ClientContext | undefined;
declare let clientContextEnv: AWSLambda.ClientContextEnv;
declare let clientContextClient: AWSLambda.ClientContextClient;
declare let context: AWSLambda.Context;
declare let identity: AWSLambda.CognitoIdentity;
declare let identityOrUndefined: AWSLambda.CognitoIdentity | undefined;
declare let proxyResult: AWSLambda.ProxyResult;
declare let authResponse: AWSLambda.AuthResponse;
declare let policyDocument: AWSLambda.PolicyDocument;
declare let statement: AWSLambda.Statement;
declare let authResponseContext: AWSLambda.AuthResponseContext;
declare let authResponseContextOpt: AWSLambda.AuthResponseContext | null | undefined;
declare let snsEvt: AWSLambda.SNSEvent;
declare let snsEvtRecs: AWSLambda.SNSEventRecord[];
declare let snsEvtRec: AWSLambda.SNSEventRecord;
declare let snsMsg: AWSLambda.SNSMessage;
declare let snsMsgAttr: AWSLambda.SNSMessageAttribute;
declare let snsMsgAttrs: AWSLambda.SNSMessageAttributes;
const S3EvtRec: AWSLambda.S3EventRecord = {
    eventVersion: '2.0',
    eventSource: 'aws:s3',
    awsRegion: 'us-east-1',
    eventTime: '1970-01-01T00:00:00.000Z',
    eventName: 'ObjectCreated:Put',
    userIdentity: {
        principalId: 'AIDAJDPLRKLG7UEXAMPLE'
    },
    requestParameters: {
        sourceIPAddress: '127.0.0.1'
    },
    responseElements: {
        'x-amz-request-id': 'C3D13FE58DE4C810',
        'x-amz-id-2': 'FMyUVURIY8/IgAtTv8xRjskZQpcIZ9KG4V5Wp6S7S/JRWeUWerMUE5JgHvANOjpD'
    },
    s3: {
        s3SchemaVersion: '1.0',
        configurationId: 'testConfigRule',
        bucket: {
            name: 'mybucket',
            ownerIdentity: {
                principalId: 'A3NL1KOZZKExample'
            },
            arn: 'arn:aws:s3:::mybucket'
        },
        object: {
            key: 'HappyFace.jpg',
            size: 1024,
            eTag: 'd41d8cd98f00b204e9800998ecf8427e',
            versionId: '096fKKXTRTtl3on89fVO.nfljtsv6qko',
            sequencer: '0055AED6DCD90281E5'
        }
    }
};

const S3CreateEvent: AWSLambda.S3CreateEvent = {
    Records: [S3EvtRec]
};
declare const cognitoUserPoolEvent: AWSLambda.CognitoUserPoolEvent;
declare const cloudformationCustomResourceEvent: AWSLambda.CloudFormationCustomResourceEvent;
declare const cloudformationCustomResourceResponse: AWSLambda.CloudFormationCustomResourceResponse;
declare const cloudwatchLogsEvent: AWSLambda.CloudWatchLogsEvent;
declare const cloudwatchLogsDecodedData: AWSLambda.CloudWatchLogsDecodedData;
declare const scheduledEvent: AWSLambda.ScheduledEvent;

/* API Gateway Event request context */
str = apiGwEvtReqCtx.accountId;
str = apiGwEvtReqCtx.apiId;
authResponseContextOpt = apiGwEvtReqCtx.authorizer;
str = apiGwEvtReqCtx.httpMethod;
strOrNull = apiGwEvtReqCtx.identity.accessKey;
strOrNull = apiGwEvtReqCtx.identity.accountId;
strOrNull = apiGwEvtReqCtx.identity.apiKey;
strOrNull = apiGwEvtReqCtx.identity.apiKeyId;
strOrNull = apiGwEvtReqCtx.identity.caller;
strOrNull = apiGwEvtReqCtx.identity.cognitoAuthenticationProvider;
strOrNull = apiGwEvtReqCtx.identity.cognitoAuthenticationType;
strOrNull = apiGwEvtReqCtx.identity.cognitoIdentityId;
strOrNull = apiGwEvtReqCtx.identity.cognitoIdentityPoolId;
str = apiGwEvtReqCtx.identity.sourceIp;
strOrNull = apiGwEvtReqCtx.identity.user;
strOrNull = apiGwEvtReqCtx.identity.userAgent;
strOrNull = apiGwEvtReqCtx.identity.userArn;
str = apiGwEvtReqCtx.path;
str = apiGwEvtReqCtx.stage;
str = apiGwEvtReqCtx.requestId;
str = apiGwEvtReqCtx.resourceId;
str = apiGwEvtReqCtx.resourcePath;

/* API Gateway Event */
strOrNull = apiGwEvt.body;
str = apiGwEvt.headers["example"];
str = apiGwEvt.multiValueHeaders["example"][0];
str = apiGwEvt.httpMethod;
bool = apiGwEvt.isBase64Encoded;
str = apiGwEvt.path;
str = apiGwEvt.pathParameters!["example"];
str = apiGwEvt.queryStringParameters!["example"];
str = apiGwEvt.multiValueQueryStringParameters!["example"][0];
str = apiGwEvt.stageVariables!["example"];
apiGwEvtReqCtx = apiGwEvt.requestContext;
str = apiGwEvt.resource;

/* API Gateway CustomAuthorizer Event */
str = customAuthorizerEvt.type;
str = customAuthorizerEvt.methodArn;
strOrUndefined = customAuthorizerEvt.authorizationToken;
strOrUndefined = customAuthorizerEvt.resource;
strOrUndefined = customAuthorizerEvt.path;
strOrUndefined = customAuthorizerEvt.httpMethod;
str = customAuthorizerEvt.headers!["example"];
str = customAuthorizerEvt.multiValueHeaders!["example"][0];
str = customAuthorizerEvt.pathParameters!["example"];
str = customAuthorizerEvt.queryStringParameters!["example"];
str = customAuthorizerEvt.multiValueQueryStringParameters!["example"][0];
str = customAuthorizerEvt.stageVariables!["example"];
apiGwEvtReqCtxOpt = customAuthorizerEvt.requestContext;
strOrUndefined = customAuthorizerEvt.domainName;
strOrUndefined = customAuthorizerEvt.apiId;

/* DynamoDB Stream Event */
const dynamoDBStreamEvent: AWSLambda.DynamoDBStreamEvent = {
    Records: [
        {
            eventID: '1',
            eventVersion: '1.0',
            dynamodb: {
                Keys: {
                    Id: {
                        N: '101'
                    }
                },
                NewImage: {
                    Message: {
                        S: 'New item!'
                    },
                    Id: {
                        N: '101'
                    }
                },
                StreamViewType: 'NEW_AND_OLD_IMAGES',
                SequenceNumber: '111',
                SizeBytes: 26
            },
            awsRegion: 'us-west-2',
            eventName: 'INSERT',
            eventSourceARN:
                'arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899',
            eventSource: 'aws:dynamodb'
        },
        {
            eventID: '2',
            eventVersion: '1.0',
            dynamodb: {
                OldImage: {
                    Message: {
                        S: 'New item!'
                    },
                    Id: {
                        N: '101'
                    }
                },
                SequenceNumber: '222',
                Keys: {
                    Id: {
                        N: '101'
                    }
                },
                SizeBytes: 59,
                NewImage: {
                    Message: {
                        S: 'This item has changed'
                    },
                    Id: {
                        N: '101'
                    }
                },
                StreamViewType: 'NEW_AND_OLD_IMAGES'
            },
            awsRegion: 'us-west-2',
            eventName: 'MODIFY',
            eventSourceARN:
                'arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899',
            eventSource: 'aws:dynamodb'
        },
        {
            eventID: '3',
            eventVersion: '1.0',
            dynamodb: {
                Keys: {
                    Id: {
                        N: '101'
                    }
                },
                SizeBytes: 38,
                SequenceNumber: '333',
                OldImage: {
                    Message: {
                        S: 'This item has changed'
                    },
                    Id: {
                        N: '101'
                    }
                },
                StreamViewType: 'NEW_AND_OLD_IMAGES'
            },
            awsRegion: 'us-west-2',
            eventName: 'REMOVE',
            eventSourceARN:
                'arn:aws:dynamodb:us-west-2:account-id:table/ExampleTableWithStream/stream/2015-06-27T00:48:05.899',
            eventSource: 'aws:dynamodb'
        }
    ]
};

/* SNS Event */
snsEvtRecs = snsEvt.Records;

str = snsEvtRec.EventSource;
str = snsEvtRec.EventSubscriptionArn;
str = snsEvtRec.EventVersion;
snsMsg = snsEvtRec.Sns;

str = snsMsg.SignatureVersion;
str = snsMsg.Timestamp;
str = snsMsg.Signature;
str = snsMsg.SigningCertUrl;
str = snsMsg.MessageId;
str = snsMsg.Message;
snsMsgAttrs = snsMsg.MessageAttributes;
str = snsMsg.Type;
str = snsMsg.UnsubscribeUrl;
str = snsMsg.TopicArn;
str = snsMsg.Subject;

snsMsgAttrs["example"] = snsMsgAttr;

str = snsMsgAttr.Type;
str = snsMsgAttr.Value;

/* Lambda Proxy Result */
num = proxyResult.statusCode;
proxyResult.headers!["example"] = str;
proxyResult.headers!["example"] = bool;
proxyResult.headers!["example"] = num;
proxyResult.multiValueHeaders!["example"][0] = str;
proxyResult.multiValueHeaders!["example"][0] = bool;
proxyResult.multiValueHeaders!["example"][0] = num;
boolOrUndefined = proxyResult.isBase64Encoded;
str = proxyResult.body;

/* API Gateway CustomAuthorizer AuthResponse */
authResponseContext = {
    stringKey: str,
    numberKey: num,
    booleanKey: bool
};

statement = {
    Action: str,
    Effect: str,
    Resource: str
};

// $ExpectError
statement = {
    Effect: str,
    Action: str,
    Principal: 123
};

// Bad Resource
// $ExpectError
statement = {
    Effect: str,
    Action: str,
    Resource: 123
};

// Bad Resource with valid Principal
// $ExpectError
statement = {
    Effect: str,
    Action: str,
    Principal: { Service: str},
    Resource: 123
};

// Bad principal with valid Resource
// $ExpectError
statement = {
    Effect: str,
    Action: str,
    Principal: 123,
    Resource: str
};

// No Effect
// $ExpectError
statement = {
    Action: str,
    Principal: str
};

statement = {
    Sid: str,
    Action: [str, str],
    Effect: str,
    Resource: [str, str],
    Condition: {
        condition1: { key: "value" },
        condition2: [{
                key1: "value",
                key2: "value"
        }, {
            key3: "value"
        }]
    },
    Principal: [str, str],
    NotPrincipal: [str, str]
};

statement = {
    Action: str,
    Principal: str,
    Effect: str
};

statement = {
    Action: str,
    NotPrincipal: {
        Service: str
    },
    Effect: str
};

statement = {
    Effect: str,
    NotAction: str,
    NotResource: str
};

policyDocument = {
    Version: str,
    Statement: [statement]
};

policyDocument = {
    Version: str,
    Statement: [statement, statement]
};

authResponse = {
    principalId: str,
    policyDocument,
    context: authResponseContext
};

authResponse = {
    principalId: str,
    policyDocument,
};

// CognitoUserPoolEvent
num = cognitoUserPoolEvent.version;
cognitoUserPoolEvent.triggerSource === "PreSignUp_SignUp";
cognitoUserPoolEvent.triggerSource === "PostConfirmation_ConfirmSignUp";
cognitoUserPoolEvent.triggerSource === "PreAuthentication_Authentication";
cognitoUserPoolEvent.triggerSource === "PostAuthentication_Authentication";
cognitoUserPoolEvent.triggerSource === "CustomMessage_SignUp";
cognitoUserPoolEvent.triggerSource === "CustomMessage_AdminCreateUser";
cognitoUserPoolEvent.triggerSource === "CustomMessage_ResendCode";
cognitoUserPoolEvent.triggerSource === "CustomMessage_ForgotPassword";
cognitoUserPoolEvent.triggerSource === "CustomMessage_UpdateUserAttribute";
cognitoUserPoolEvent.triggerSource === "CustomMessage_VerifyUserAttribute";
cognitoUserPoolEvent.triggerSource === "CustomMessage_Authentication";
cognitoUserPoolEvent.triggerSource === "DefineAuthChallenge_Authentication";
cognitoUserPoolEvent.triggerSource === "CreateAuthChallenge_Authentication";
cognitoUserPoolEvent.triggerSource === "VerifyAuthChallengeResponse_Authentication";
cognitoUserPoolEvent.triggerSource === "PreSignUp_AdminCreateUser";
cognitoUserPoolEvent.triggerSource === "PostConfirmation_ConfirmForgotPassword";
cognitoUserPoolEvent.triggerSource === "TokenGeneration_HostedAuth";
cognitoUserPoolEvent.triggerSource === "TokenGeneration_Authentication";
cognitoUserPoolEvent.triggerSource === "TokenGeneration_NewPasswordChallenge";
cognitoUserPoolEvent.triggerSource === "TokenGeneration_AuthenticateDevice";
cognitoUserPoolEvent.triggerSource === "TokenGeneration_RefreshTokens";
cognitoUserPoolEvent.triggerSource === "UserMigration_Authentication";
cognitoUserPoolEvent.triggerSource === "UserMigration_ForgotPassword";
str = cognitoUserPoolEvent.region;
str = cognitoUserPoolEvent.userPoolId;
strOrUndefined = cognitoUserPoolEvent.userName;
str = cognitoUserPoolEvent.callerContext.awsSdkVersion;
str = cognitoUserPoolEvent.callerContext.clientId;
str = cognitoUserPoolEvent.request.userAttributes["email"];
str = cognitoUserPoolEvent.request.validationData!["k1"];
strOrUndefined = cognitoUserPoolEvent.request.codeParameter;
strOrUndefined = cognitoUserPoolEvent.request.usernameParameter;
boolOrUndefined = cognitoUserPoolEvent.request.newDeviceUsed;
cognitoUserPoolEvent.request.session![0].challengeName === "CUSTOM_CHALLENGE";
cognitoUserPoolEvent.request.session![0].challengeName === "PASSWORD_VERIFIER";
cognitoUserPoolEvent.request.session![0].challengeName === "SMS_MFA";
cognitoUserPoolEvent.request.session![0].challengeName === "DEVICE_SRP_AUTH";
cognitoUserPoolEvent.request.session![0].challengeName === "DEVICE_PASSWORD_VERIFIER";
cognitoUserPoolEvent.request.session![0].challengeName === "ADMIN_NO_SRP_AUTH";
bool = cognitoUserPoolEvent.request.session![0].challengeResult;
strOrUndefined = cognitoUserPoolEvent.request.session![0].challengeMetadata;
strOrUndefined = cognitoUserPoolEvent.request.challengeName;
str = cognitoUserPoolEvent.request.privateChallengeParameters!["answer"];
str = cognitoUserPoolEvent.request.challengeAnswer!;
strOrUndefined = cognitoUserPoolEvent.request.password;
boolOrUndefined = cognitoUserPoolEvent.response.answerCorrect;
strOrUndefined = cognitoUserPoolEvent.response.smsMessage;
strOrUndefined = cognitoUserPoolEvent.response.emailMessage;
strOrUndefined = cognitoUserPoolEvent.response.emailSubject;
strOrUndefined = cognitoUserPoolEvent.response.challengeName;
boolOrUndefined = cognitoUserPoolEvent.response.issueTokens;
boolOrUndefined = cognitoUserPoolEvent.response.failAuthentication;
str = cognitoUserPoolEvent.response.publicChallengeParameters!["captchaUrl"];
str = cognitoUserPoolEvent.response.privateChallengeParameters!["answer"];
strOrUndefined = cognitoUserPoolEvent.response.challengeMetadata;
boolOrUndefined = cognitoUserPoolEvent.response.answerCorrect;
str = cognitoUserPoolEvent.response.userAttributes!["username"];
cognitoUserPoolEvent.response.finalUserStatus === "CONFIRMED";
cognitoUserPoolEvent.response.finalUserStatus === "RESET_REQUIRED";
cognitoUserPoolEvent.response.messageAction === "SUPPRESS";
cognitoUserPoolEvent.response.desiredDeliveryMediums === ["EMAIL"];
cognitoUserPoolEvent.response.desiredDeliveryMediums === ["SMS"];
cognitoUserPoolEvent.response.desiredDeliveryMediums === ["SMS", "EMAIL"];
boolOrUndefined = cognitoUserPoolEvent.response.forceAliasCreation;

// CloudFormation Custom Resource
switch (cloudformationCustomResourceEvent.RequestType) {
    case "Create":
        str = cloudformationCustomResourceEvent.LogicalResourceId;
        str = cloudformationCustomResourceEvent.RequestId;
        anyObj = cloudformationCustomResourceEvent.ResourceProperties;
        str = cloudformationCustomResourceEvent.ResourceProperties.ServiceToken;
        str = cloudformationCustomResourceEvent.ResourceType;
        str = cloudformationCustomResourceEvent.ResponseURL;
        str = cloudformationCustomResourceEvent.ServiceToken;
        str = cloudformationCustomResourceEvent.StackId;
    break;
    case "Update":
        anyObj = cloudformationCustomResourceEvent.OldResourceProperties;
    break;
    case "Delete":
        str = cloudformationCustomResourceEvent.PhysicalResourceId;
    break;
}
anyObj = cloudformationCustomResourceResponse.Data;
str = cloudformationCustomResourceResponse.LogicalResourceId;
str = cloudformationCustomResourceResponse.PhysicalResourceId;
strOrUndefined = cloudformationCustomResourceResponse.Reason;
str = cloudformationCustomResourceResponse.RequestId;
str = cloudformationCustomResourceResponse.StackId;
str = cloudformationCustomResourceResponse.Status;

/* ScheduledEvent */
str = scheduledEvent.account;
anyObj = scheduledEvent.detail;
str = scheduledEvent.id;
str = scheduledEvent.region;
str = scheduledEvent.resources[0];
str = scheduledEvent.source;
str = scheduledEvent.time;

/* Context */
bool = context.callbackWaitsForEmptyEventLoop;
str = context.functionName;
str = context.functionVersion;
str = context.invokedFunctionArn;
num = context.memoryLimitInMB;
str = context.awsRequestId;
str = context.logGroupName;
str = context.logStreamName;
identityOrUndefined = context.identity;
clientCtxOrUndefined = context.clientContext;

/* CognitoIdentity */
str = identity.cognitoIdentityId;
str = identity.cognitoIdentityPoolId;

/* CloudWatch Logs */
str = cloudwatchLogsEvent.awslogs.data;

str = cloudwatchLogsDecodedData.owner;
str = cloudwatchLogsDecodedData.logGroup;
str = cloudwatchLogsDecodedData.logStream;
str = cloudwatchLogsDecodedData.subscriptionFilters[0];
str = cloudwatchLogsDecodedData.messageType;
str = cloudwatchLogsDecodedData.logEvents[0].id;
num = cloudwatchLogsDecodedData.logEvents[0].timestamp;
str = cloudwatchLogsDecodedData.logEvents[0].message;
str = cloudwatchLogsDecodedData.logEvents[0].extractedFields!["example"];

/* ClientContext */
clientContextClient = clientCtx.client;
anyObj = clientCtx.custom;
clientContextEnv = clientCtx.env;

/* ClientContextEnv */
str = clientContextEnv.locale;
str = clientContextEnv.make;
str = clientContextEnv.model;
str = clientContextEnv.platform;
str = clientContextEnv.platformVersion;

/* ClientContextClient */
str = clientContextClient.appPackageName;
str = clientContextClient.appTitle;
str = clientContextClient.appVersionCode;
str = clientContextClient.appVersionName;
str = clientContextClient.installationId;

/* Callback */
function callback(cb: AWSLambda.Callback) {
    cb();
    cb(null);
    cb(error);
    cb(str); // https://docs.aws.amazon.com/apigateway/latest/developerguide/handle-errors-in-lambda-integration.html
    cb(null, anyObj);
    cb(null, bool);
    cb(null, str);
    cb(null, num);
}

/* Proxy Callback */
function proxyCallback(cb: AWSLambda.ProxyCallback) {
    cb();
    cb(null);
    cb(error);
    cb(null, proxyResult);
}

/* CustomAuthorizerCallback */
function customAuthorizerCallback(cb: AWSLambda.CustomAuthorizerCallback) {
    cb();
    cb(null);
    cb(error);
    cb(null, authResponse);
}

/* CodePipeline events https://docs.aws.amazon.com/codepipeline/latest/userguide/actions-invoke-lambda-function.html#actions-invoke-lambda-function-json-event-example */
const CodePipelineEvent: AWSLambda.CodePipelineEvent = {
    "CodePipeline.job": {
        id: "11111111-abcd-1111-abcd-111111abcdef",
        accountId: "111111111111",
        data: {
            actionConfiguration: {
                configuration: {
                    FunctionName: "MyLambdaFunctionForAWSCodePipeline",
                    UserParameters: "some-input-such-as-a-URL"
                }
            },
            inputArtifacts: [
                {
                    location: {
                        s3Location: {
                            bucketName: "the name of the bucket configured as the pipeline artifact store in Amazon S3, for example codepipeline-us-east-2-1234567890",
                            objectKey: "the name of the application, for example CodePipelineDemoApplication.zip"
                        },
                        type: "S3"
                    },
                    revision: null,
                    name: "ArtifactName"
                }
            ],
            outputArtifacts: [],
            artifactCredentials: {
                secretAccessKey: "wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY",
                sessionToken: `MIICiTCCAfICCQD6m7oRw0uXOjANBgkqhkiG9w
 0BAQUFADCBiDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZ
 WF0dGxlMQ8wDQYDVQQKEwZBbWF6b24xFDASBgNVBAsTC0lBTSBDb25zb2xlMRIw
 EAYDVQQDEwlUZXN0Q2lsYWMxHzAdBgkqhkiG9w0BCQEWEG5vb25lQGFtYXpvbi5
 jb20wHhcNMTEwNDI1MjA0NTIxWhcNMTIwNDI0MjA0NTIxWjCBiDELMAkGA1UEBh
 MCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZBb
 WF6b24xFDASBgNVBAsTC0lBTSBDb25zb2xlMRIwEAYDVQQDEwlUZXN0Q2lsYWMx
 HzAdBgkqhkiG9w0BCQEWEG5vb25lQGFtYXpvbi5jb20wgZ8wDQYJKoZIhvcNAQE
 BBQADgY0AMIGJAoGBAMaK0dn+a4GmWIWJ21uUSfwfEvySWtC2XADZ4nB+BLYgVI
 k60CpiwsZ3G93vUEIO3IyNoH/f0wYK8m9TrDHudUZg3qX4waLG5M43q7Wgc/MbQ
 ITxOUSQv7c7ugFFDzQGBzZswY6786m86gpEIbb3OhjZnzcvQAaRHhdlQWIMm2nr
 AgMBAAEwDQYJKoZIhvcNAQEFBQADgYEAtCu4nUhVVxYUntneD9+h8Mg9q6q+auN
 KyExzyLwaxlAoo7TJHidbtS4J5iNmZgXL0FkbFFBjvSfpJIlJ00zbhNYS5f6Guo
 EDmFJl0ZxBHjJnyp378OD8uTs7fLvjx79LjSTbNYiytVbZPQUQ5Yaxu2jXnimvw
 3rrszlaEXAMPLE=`,
                accessKeyId: "AKIAIOSFODNN7EXAMPLE"
            },
            continuationToken: "A continuation token if continuing job"
        }
    }
};

CodePipelineEvent["CodePipeline.job"].data.encryptionKey = { type: 'KMS', id: 'key' };

/* CodePipeline CloudWatch Events
 * see https://docs.aws.amazon.com/codepipeline/latest/userguide/detect-state-changes-cloudwatch-events.html
 * Their documentation says that detail.version is a string, but it is actually an integer
 */
const CodePipelineCloudWatchEvent: AWSLambda.CodePipelineCloudWatchEvent = {
    version: '0',
    id: 'event_Id',
    'detail-type': 'CodePipeline Pipeline Execution State Change',
    source: 'aws.codepipeline',
    account: 'Pipeline_Account',
    time: 'TimeStamp',
    region: 'us-east-1',
    resources: ['arn:aws:codepipeline:us-east-1:account_ID:myPipeline'],
    detail: {
        pipeline: 'myPipeline',
        version: 1,
        state: 'STARTED',
        'execution-id': 'execution_Id',
    },
};

/* CloudFront events, see http://docs.aws.amazon.com/AmazonCloudFront/latest/DeveloperGuide/lambda-event-structure.html */
const CloudFrontRequestWithCustomOriginEvent: AWSLambda.CloudFrontRequestEvent = {
  Records: [
    {
      cf: {
        config: {
          distributionDomainName: "d123.cloudfront.net",
          distributionId: "EDFDVBD6EXAMPLE",
          eventType: "viewer-request",
          requestId: "MRVMF7KydIvxMWfJIglgwHQwZsbG2IhRJ07sn9AkKUFSHS9EXAMPLE=="
        },
        request: {
          clientIp: "2001:0db8:85a3:0:0:8a2e:0370:7334",
          method: "GET",
          uri: "/picture.jpg",
          querystring: "size=large",
          headers: {
            host: [
              {
                key: "Host",
                value: "d111111abcdef8.cloudfront.net"
              }
            ],
            "user-agent": [
              {
                key: "User-Agent",
                value: "curl/7.51.0"
              }
            ]
          },
          origin: {
            custom: {
              customHeaders: {
                "my-origin-custom-header": [
                  {
                    key: "My-Origin-Custom-Header",
                    value: "Test"
                  }
                ]
              },
              domainName: "example.com",
              keepaliveTimeout: 5,
              path: "/custom_path",
              port: 443,
              protocol: "https",
              readTimeout: 5,
              sslProtocols: [
                "TLSv1",
                "TLSv1.1"
              ]
            }
          }
        }
      }
    }
  ]
};

const CloudFrontRequestWithS3OriginEvent: AWSLambda.CloudFrontRequestEvent = {
  Records: [
    {
      cf: {
        config: {
          distributionDomainName: "d123.cloudfront.net",
          distributionId: "EDFDVBD6EXAMPLE",
          eventType: "viewer-request",
          requestId: "MRVMF7KydIvxMWfJIglgwHQwZsbG2IhRJ07sn9AkKUFSHS9EXAMPLE=="
        },
        request: {
          clientIp: "2001:0db8:85a3:0:0:8a2e:0370:7334",
          method: "GET",
          uri: "/picture.jpg",
          querystring: "size=large",
          headers: {
            host: [
              {
                key: "Host",
                value: "d111111abcdef8.cloudfront.net"
              }
            ],
            "user-agent": [
              {
                key: "User-Agent",
                value: "curl/7.51.0"
              }
            ]
          },
          origin: {
            s3: {
              authMethod: "origin-access-identity",
              customHeaders: {
                "my-origin-custom-header": [
                  {
                    key: "My-Origin-Custom-Header",
                    value: "Test"
                  }
                ]
              },
              domainName: "my-bucket.s3.amazonaws.com",
              path: "/s3_path",
              region: "us-east-1"
            }
          }
        }
      }
    }
  ]
};

const CloudFrontResponseEvent: AWSLambda.CloudFrontResponseEvent = {
    Records: [
        {
            cf: {
                config: {
                    distributionDomainName: "d123.cloudfront.net",
                    distributionId: "EDFDVBD6EXAMPLE",
                    eventType: "viewer-response",
                    requestId: "xGN7KWpVEmB9Dp7ctcVFQC4E-nrcOcEKS3QyAez--06dV7TEXAMPLE=="
                },
                request: {
                    clientIp: "2001:0db8:85a3:0:0:8a2e:0370:7334",
                    method: "GET",
                    uri: "/picture.jpg",
                    querystring: "size=large",
                    headers: {
                        host: [
                            {
                                key: "Host",
                                value: "d111111abcdef8.cloudfront.net"
                            }
                        ],
                        "user-agent": [
                            {
                                key: "User-Agent",
                                value: "curl/7.18.1"
                            }
                        ]
                    }
                },
                response: {
                    status: "200",
                    statusDescription: "OK",
                    headers: {
                        server: [
                            {
                                key: "Server",
                                value: "MyCustomOrigin"
                            }
                        ],
                        "set-cookie": [
                            {
                                key: "Set-Cookie",
                                value: "theme=light"
                            },
                            {
                                key: "Set-Cookie",
                                value: "sessionToken=abc123; Expires=Wed, 09 Jun 2021 10:18:14 GMT"
                            }
                        ]
                    }
                }
            }
        }
    ]
};

/* Kinesis Data Stream Events */
declare let kinesisStreamEvent: AWSLambda.KinesisStreamEvent;
declare let kinesisStreamRecord: AWSLambda.KinesisStreamRecord;
declare let kinesisStreamRecordPayload: AWSLambda.KinesisStreamRecordPayload;

kinesisStreamRecord = kinesisStreamEvent.Records[0];

str = kinesisStreamRecord.awsRegion;
str = kinesisStreamRecord.eventID;
str = kinesisStreamRecord.eventName;
str = kinesisStreamRecord.eventSource;
str = kinesisStreamRecord.eventSourceARN;
str = kinesisStreamRecord.eventVersion;
str = kinesisStreamRecord.invokeIdentityArn;
kinesisStreamRecordPayload = kinesisStreamRecord.kinesis;

num = kinesisStreamRecordPayload.approximateArrivalTimestamp;
str = kinesisStreamRecordPayload.data;
str = kinesisStreamRecordPayload.kinesisSchemaVersion;
str = kinesisStreamRecordPayload.partitionKey;
str = kinesisStreamRecordPayload.sequenceNumber;

/* Compatibility functions */
context.done();
context.done(error);
context.done(error, anyObj);
context.succeed(str);
context.succeed(anyObj);
context.succeed(str, anyObj);
context.fail(error);
context.fail(str);

/* Handler */
const handler: AWSLambda.Handler = (event: any, context: AWSLambda.Context, cb: AWSLambda.Callback) => { };

/* In node8.10 runtime, handlers may return a promise for the result value, so existing async
 * handlers that return Promise<void> before calling the callback will now have a `null` result.
 * Be safe and make that badly typed with a major verson bump to 8.10 so users expect the breaking change,
 * since the upgrade effort should be pretty low in most cases, and it points them at a nicer solution.
 */
// $ExpectError
const legacyAsyncHandler: AWSLambda.APIGatewayProxyHandler = async (
    event: AWSLambda.APIGatewayProxyEvent,
    context: AWSLambda.Context,
    cb: AWSLambda.Callback<AWSLambda.APIGatewayProxyResult>,
) => {
    cb(null, { statusCode: 200, body: 'No longer valid' });
};

const node8AsyncHandler: AWSLambda.APIGatewayProxyHandler = async (
    event: AWSLambda.APIGatewayProxyEvent,
    context: AWSLambda.Context,
    cb: AWSLambda.Callback<AWSLambda.APIGatewayProxyResult>,
) => {
    return { statusCode: 200, body: 'Is now valid!' };
};

const inferredHandler: AWSLambda.S3Handler = (event, context, cb) => {
    // $ExpectType S3Event
    event;
    str = event.Records[0].eventName;
    // $ExpectType Context
    context;
    str = context.functionName;
    // $ExpectType Callback<void>
    cb;
    cb();
    cb(null);
    cb(new Error());
    // $ExpectError
    cb(null, { });
};

// Test using default Callback type still works.
const defaultCallbackHandler: AWSLambda.APIGatewayProxyHandler = (event: AWSLambda.APIGatewayEvent, context: AWSLambda.Context, cb: AWSLambda.Callback) => { };

// Specific types
let s3Handler: AWSLambda.S3Handler = (event: AWSLambda.S3Event, context: AWSLambda.Context, cb: AWSLambda.Callback<void>) => {};
// Test old name
const s3CreateHandler: AWSLambda.S3Handler = (event: AWSLambda.S3CreateEvent, context: AWSLambda.Context, cb: AWSLambda.Callback<void>) => {};
s3Handler = s3CreateHandler;

const dynamoDBStreamHandler: AWSLambda.DynamoDBStreamHandler = (event: AWSLambda.DynamoDBStreamEvent, context: AWSLambda.Context, cb: AWSLambda.Callback<void>) => {};

const snsHandler: AWSLambda.SNSHandler = (event: AWSLambda.SNSEvent, context: AWSLambda.Context, cb: AWSLambda.Callback<void>) => {};

const cognitoUserPoolHandler: AWSLambda.CognitoUserPoolTriggerHandler = (event: AWSLambda.CognitoUserPoolEvent, context: AWSLambda.Context, cb: AWSLambda.Callback<void>) => {};

const cloudFormationCustomResourceHandler: AWSLambda.CloudFormationCustomResourceHandler =
    (event: AWSLambda.CloudFormationCustomResourceEvent, context: AWSLambda.Context, cb: AWSLambda.Callback<void>) => {};

const cloudWatchLogsHandler: AWSLambda.CloudWatchLogsHandler = (event: AWSLambda.CloudWatchLogsEvent, context: AWSLambda.Context, cb: AWSLambda.Callback<void>) => {};

const scheduledHandler: AWSLambda.ScheduledHandler = (event: AWSLambda.ScheduledEvent, context: AWSLambda.Context, cb: AWSLambda.Callback<void>) => {};

let apiGtwProxyHandler: AWSLambda.APIGatewayProxyHandler = (event: AWSLambda.APIGatewayProxyEvent, context: AWSLambda.Context, cb: AWSLambda.APIGatewayProxyCallback) => { };
// Test old names
const proxyHandler: AWSLambda.ProxyHandler = (event: AWSLambda.APIGatewayEvent, context: AWSLambda.Context, cb: AWSLambda.ProxyCallback) => { };
apiGtwProxyHandler = proxyHandler;

const codePipelineHandler: AWSLambda.CodePipelineHandler = (event: AWSLambda.CodePipelineEvent, context: AWSLambda.Context, cb: AWSLambda.Callback<void>) => {};

const cloudFrontRequestHandler: AWSLambda.CloudFrontRequestHandler = (event: AWSLambda.CloudFrontRequestEvent, context: AWSLambda.Context, cb: AWSLambda.CloudFrontRequestCallback) => {
    event = CloudFrontRequestWithCustomOriginEvent;
    // $ExpectType CloudFrontRequestEvent
    event;
    let request = event.Records[0].cf.request;

    let s3Origin: AWSLambda.CloudFrontS3Origin = {
        authMethod: 'none',
        customHeaders: {},
        domainName: 'example.com',
        path: '/',
        region: 'us-east-1'
    };

    if (request.origin && request.origin.custom) {
        request.origin.custom.domainName;
        request.origin.custom.domainName = "example2.com";

        // $ExpectError
        s3Origin = request.origin.s3;

        // $ExpectError
        request.origin.s3.path = '/';
    }

    let customOrigin: AWSLambda.CloudFrontCustomOrigin = {
        customHeaders: {},
        domainName: 'example.com',
        keepaliveTimeout: 60,
        path: '/',
        port: 80,
        protocol: 'http',
        readTimeout: 30,
        sslProtocols: []
    };

    event = CloudFrontRequestWithS3OriginEvent;
    // $ExpectType CloudFrontRequestEvent
    event;
    request = event.Records[0].cf.request;
    if (request.origin && request.origin.s3) {
        request.origin.s3.path;
        request.origin.s3.path = "/new_path";

        // $ExpectError
        customOrigin = request.origin.custom;

        // $ExpectError
        request.origin.custom.path = '/';
    }

    cb();
    cb(null);
    cb(new Error(''));
    cb(null, { clientIp: str, method: str, uri: str, querystring: str, headers: { } });
    cb(null, { status: str });
    // $ExpectError
    cb(null, { });
};

const cloudFrontResponseHandler: AWSLambda.CloudFrontResponseHandler = (event: AWSLambda.CloudFrontResponseEvent, context: AWSLambda.Context, cb: AWSLambda.CloudFrontResponseCallback) => { };

const customAuthorizerHandler: AWSLambda.CustomAuthorizerHandler = (event: AWSLambda.CustomAuthorizerEvent, context: AWSLambda.Context, cb: AWSLambda.CustomAuthorizerCallback) => { };

interface CustomEvent { eventString: string; eventBool: boolean; }
interface CustomResult { resultString: string; resultBool?: boolean; }
type CustomCallback = AWSLambda.Callback<CustomResult>;
const customHandler: AWSLambda.Handler<CustomEvent, CustomResult> = (event, context, cb) => {
    // $ExpectType CustomEvent
    event;
    str = event.eventString;
    bool = event.eventBool;
    // $ExpectType Context
    context;
    // $ExpectType Callback<CustomResult>
    cb;
    cb(null, { resultString: str, resultBool: bool });
    // $ExpectError
    cb(null, { resultString: bool });
};

const kinesisStreamHandler: AWSLambda.KinesisStreamHandler = (event: AWSLambda.KinesisStreamEvent, context: AWSLambda.Context, cb: AWSLambda.Callback<void>) => { };

const SQSMessageHandler: AWSLambda.SQSHandler = (event: AWSLambda.SQSEvent, context: AWSLambda.Context, cb: AWSLambda.Callback<void>) => { };

// See https://docs.aws.amazon.com/lambda/latest/dg/eventsources.html#eventsources-sqs
const SQSEvent: AWSLambda.SQSEvent = {
    Records: [
        {
            messageId: "c80e8021-a70a-42c7-a470-796e1186f753",
            receiptHandle: "AQEBJQ+/u6NsnT5t8Q/VbVxgdUl4TMKZ5FqhksRdIQvLBhwNvADoBxYSOVeCBXdnS9P+",
            body: "{\"foo\":\"bar\"}",
            attributes: {
                ApproximateReceiveCount: "3",
                SentTimestamp: "1529104986221",
                SenderId: "594035263019",
                ApproximateFirstReceiveTimestamp: "1529104986230"
            },
            messageAttributes: {},
            md5OfBody: "9bb58f26192e4ba00f01e2e7b136bbd8",
            eventSource: "aws:sqs",
            eventSourceARN: "arn:aws:sqs:us-west-2:594035263019:NOTFIFOQUEUE",
            awsRegion: "us-west-2"
        }
    ]
};

const SQSMessageLegacyAsyncHandler: AWSLambda.SQSHandler = async (
    event: AWSLambda.SQSEvent,
    context: AWSLambda.Context,
    cb: AWSLambda.Callback<void>,
) => {
    // $ExpectType SQSEvent
    event;
    str = event.Records[0].messageId;
    anyObj = event.Records[0].body;
    // $ExpectType Context
    context;
    str = context.functionName;
    // $ExpectType Callback<void>
    cb;
    cb();
    cb(null);
    cb(new Error());
};

const SQSMessageNode8AsyncHandler: AWSLambda.SQSHandler = async (
    event: AWSLambda.SQSEvent,
    context: AWSLambda.Context
) => {
    // $ExpectType SQSEvent
    event;
    str = event.Records[0].messageId;
    anyObj = event.Records[0].body;
    // $ExpectType Context
    context;
    str = context.functionName;
    return;
};

const firehoseEventHandler: AWSLambda.FirehoseTransformationHandler = (
    event: AWSLambda.FirehoseTransformationEvent,
    context: AWSLambda.Context,
    callback: AWSLambda.FirehoseTransformationCallback
) => {
    // $ExpectType FirehoseTransformationEvent
    event;
    str = event.records[0].recordId;

    // $ExpectType Context
    context;
    str = context.functionName;
    callback(null, {
        records: [
            {
                recordId: event.records[0].recordId,
                result: 'Ok' as AWSLambda.FirehoseRecordTransformationStatus,
                data: 'eyJmb28iOiJiYXIifQ==',
            }
        ]
    });
};


text:
/**
  *   Modelizer - by Jonathan Haeberle
  *   https://github.com/dreampulse/modelizer
  *
  *   This it the code, which is being shared between server and client
  *
  */

var assert = require('./microlibs').assert;
var check = require('./microlibs').check;
var isEmptyObject = require('./microlibs').isEmptyObject;

var Q = require('q');
//var _ = require('lodash');

// note: browserify will replace this ObjectId implementation by 'require("objectid-browser")' for the client
var ObjectId = require('./objectid');

//////////////////////////
// The Model implementation

var Model = function(modelName, schema) {
  this.self = this;

  this.modelName = modelName;
  this.schema = schema;

  // im scope der Model-Methode speichere ich alles was ich dem Modell übergeben kann
  // also Attribute, operationen usw..
  // die Funktionen hierfür sehen eigentlich immer gleich auch
  // deswegen sollte das auch in ein meta-modell wandern

  this.attrs = {};

  // a reference to another model
  this.attrRefs = {};

  // a reference to another model
  this.attrObjs = {};

  // an inline object
  this.methods = {};

  this.methodImpls = {};

  this.virtualAttrs = {};

  this.virtualAttrImpls = {};

  this.attrArrays = {};

  this.attrRefArrays = {};

  this.attrLinks = {};  // TODO

  this.operations = {};

  this.operationImpls = {};

  this.factorys = {};

  this.factoryImpls = {};

  // setup filters for using the model
  this.readFilters = [];

  this.afterReadFilters = function() { };  // only one

  // setup write filters for using the model
  this.writeFilters = [];

  /////////////////
  // Constructing

  // 'execute' schema definition
  if (this.schema) { // a schema was provided
    this.processSchema(this.schema);
  }

  // set connection for all models
  if (Model.globalConnection) {
    this.connection(Model.globalConnection);
  }

  // set express for all models
  if (Model.globalExpress) {
    this.express(Model.globalExpress);
    this.serve();
  }

  // init sample Server
  if (Model.simpleServer) {
    console.log("init simple server for", this.modelName);

    // say that our model should use express and the database connector
    this.connection(Model.simpleServer.connector);
    this.express(Model.simpleServer.app);
    this.serve();
  }

  return this;
};

///////
// Der Store

/// Problem: ich will eigentlich Mengen abonieren
// das geht aber nicht so einfach
// couchdb anschauen...

// alle objekte werden hier gecached
// TODO: an remove denken -> geht nicht in js
Model.prototype.store = (function(){
  var store = {};  // private store

  var watchers = {};

  // sets of objects
  var all = [];
  var find = {};  // set of array with this results
  // änderungen können dann per websocket immer rein kommen
  // ist eigentlich ein abo an mengen...

  var updateSets = function() {
    // clean array
    // http://stackoverflow.com/questions/1232040/how-to-empty-an-array-in-javascript
    all.length = 0;

    for (var i in store) {
      all.push(store[i]);
    }
  }

  // todo use getters & setters
  return {
    set : function(obj) {
      assert(typeof obj === 'object', 'obj has to be an object');
      assert(obj.hasOwnProperty("_id"), 'obj has no id');

      // assume ObjectID right now!
      var id = obj._id.toString();
      if (store.hasOwnProperty(id)) {  // this object already exists

        for (var i in obj) {  // copy values
          store[id][i] = obj[i];
        }

        updateSets();  // TODO: performace only do that if object changed (later)

        if (watchers.hasOwnProperty(id)) {  // call watcher
          watchers[id](obj);
        }

      } else {
        assert(false, "actually no problem, but get() should be called before set() - in this case ;-)");
        store[id] = new Object();
      }
    },
    get : function(id) {  // implements a get or create

      //assert(typeof id === 'string', 'id has to be a string');
      id = id.toString();

      if (store.hasOwnProperty(id)) {  // there is that object
        return store[id];
      } else {  // create a new object
        store[id] = new Object();
        return store[id];
      }
    },
    del : function(id) {
      //assert(typeof id === 'string', 'id has to be a string');
      id = id.toString();

      if (store.hasOwnProperty(id)) {  // there is that object
        delete store[id];
      }

      updateSets();

      if (watchers.hasOwnProperty(id)) {  // call watcher
        watchers[id](undefined);
      }
    },
    all : function() {

      return all;
    },
    addWatcher : function(id, callback) {
      //assert(typeof id === 'string', 'id has to be a string');
      id = id.toString();

      watchers[id] = callback;  // todo können auch mehere sein
    },
    removeWatcher : function(id) {
      //assert(typeof id === 'string', 'id has to be a string');
      id = id.toString();

      delete watchers[id];  // todo können auch mehere sein
    }
  }
})();

// "Subclasses"

///////////////////////////
// Methods

Model.prototype.attr = function(attrName) {
  var filters = [];
  for (var i in arguments) {
    if (i != '0')  // except for attrName
      filters.push(arguments[i]);
  }
  this.attrs[attrName] = {name : attrName, filters : filters};

  return this;
};

Model.prototype.attrRef = function(attrName, reference) {
  this.attrRefs[attrName] = reference;

  return this;
};

Model.prototype.attrObj = function(attrName, obj) {
  this.attrObjs[attrName] = obj;

  return this;
};

Model.prototype.method = function(methodName) {
  this.methods[methodName] = methodName;

  return this;
};

Model.prototype.methodImpl = function(methodName, fnImpl) {
  this.methodImpls[methodName] = fnImpl;

  return this;
};

Model.prototype.virtualAttr = function(attrName, attrType) {
  this.virtualAttrs[attrName] = {name : attrName, type : attrType};

  return this;
};

Model.prototype.virtualAttrImpl = function(virtualAttrName, fnImpl) {
  this.virtualAttrImpls[virtualAttrName] = fnImpl;

  return this;
};

Model.prototype.attrArray = function(attrName, obj) {
  this.attrArrays[attrName] = obj;

  return this;
};

Model.prototype.attrLink = function(linkName, model, link) {
  this.attrLinks[linkName] = {
    model : model,
    link : link
  };

  return this;
};

Model.prototype.attrRefArray = function(attrName, obj) {
  this.attrRefArrays[attrName] = obj;

  return this;
};

Model.prototype.operation = function(operationName) {
  this.operations[operationName] = operationName;
  this[operationName] = function(params) {
    assert(this.collection != undefined, "Use a connector!");
    return this.callOpQ(operationName, params, null);
  };

  return this;
};

Model.prototype.operationImpl = function(operationName, fnImpl) {
  this.operationImpls[operationName] = fnImpl;

  return this;
};

Model.prototype.factory = function(factoryName) {
  this.factorys[factoryName] = factoryName;
  this[factoryName] = function(params) {
    return this.callOpQ(factoryName, params, null);
  };

  return this;
};

Model.prototype.factoryImpl = function(factoryName, fnImpl) {
  this.factoryImpls[factoryName] = fnImpl;

  return this;
};

// setup connection stuff
Model.prototype.connection = function(connector) {
  assert(connector !== undefined, "Don't set a undefined connection!");
  this.connector = connector;
  this.collection = connector(this);
};

Model.prototype.link = function(model, linkModel) {
  var object;
  var subObject;

  this.set = function(obj, link) {
    //assert(obj instanceof model, "The object is not a instance of the right model");
    //assert(link instanceof linkModel, "You linked to a model with the wrong type");
    assert(link._id, "the target object has no _id");

    object = obj;
    subObject = link;
    this._link = link._id;
  };

  this.init = function(obj) {
    object = obj;
  };

  this.ref = function() {
    if (object && this._link) {
      var res = object._childObjs[this._link];
      assert(res, "link missing in lookup-table");
      return res;
    } else {
      throw new Error("Link not initialized");
    }
  }
};

// simuliert das verhalten einer referenz auf ein anderes Object
// Zugriff dann mit object.ref().XXX
Model.prototype.reference = function(refModel, parentModel) {

  // das weiterreichn wollte macht irgendwie probleme (sollte eigentlich auch ohne funktionieren) TODO
  //refModel.connection(parentModel.connector);  // mongodb connection an child modell durchreichen

  this.create = function() {
    var refObj = refModel.create();
    this.ref = function() { return refObj; }  // definition von der .ref()-Methode
    return this.ref();
  }

  // load object
  // todo: soll erst verfügbar sein, wenns auch was zum laden gibt
  this.loadQ = function() {
    var loadScope = this;

    var deferred = Q.defer();
    if (this._reference === undefined) {
      deferred.reject(new Error("Reference not set! Don't now what to load!"));
      return deferred.promise;
    }

    return refModel.getQ(this._reference)
      .then(function(obj) {
        var refObj = obj;
        loadScope.ref = function() { return refObj; }  // definition von der .ref()-Methode

        return refObj;
      });
  };

  this.load = this.loadQ;

  // set an existing object to the reference
  // TODO: type check -> geht garnicht so einfach (object müsste wissen zu welchem modell es gehört)
  this.setObject = function(obj) {
    var refObj = obj;

    if (obj._id === undefined) {
      throw new Error("Save object first, then set object reference!");
    }

    this.ref = function() { return refObj; }
    this._reference = obj._id;

  }
};

Model.prototype.arrayReferenceRoot = function(refModel, obj, arrayName) {
  var theArryRef = obj[arrayName];
  assert(Array.isArray(theArryRef));
  var self = this;

  theArryRef.iterate = function(callback) {
    var loadPromises = [];
    for (var i=0; i<theArryRef.length; i++) {
      loadPromises.push(
        theArryRef[i].loadQ()
          .then(function (el) {
            return callback(el);
          })
      )
    }

    return Q.all(loadPromises);
  };

  theArryRef.create = function() {
    return self.createArrayReferenceElement(refModel, obj, arrayName)();
  };
};

// Many-Referenzen (das laden aus der DB)
Model.prototype.arrayReference = function(refModel, parentModel) {
  //refModel.connection(parentModel.connector);  // mongodb connection an child modell durchreichen

  this.loadQ = function() {   //TODO: ist ja genau das selbe Load wie beim reference!!
    var loadScope = this;

    var deferred = Q.defer();
    if (this._reference === undefined) {
      deferred.reject(new Error("Reference not set! Don't now what to load!"));
      return deferred.promise;
    }

    return refModel.getQ(this._reference)
      .then(function(obj) {
        var refObj = obj;
        loadScope.ref = function() { return refObj; }  // definition von der .ref()-Methode
        return refObj;
      });
  };

  this.load = this.loadQ;

};

// verhalten von Many-Referenzen (erstellen eines neuen objects)
Model.prototype.createArrayReferenceElement = function(refModel, obj, arrayName) {
  var self = this;

  // Das hier ist die Funktion die ein neue Array-Reference anlegt
  return function() {
    var refObj = refModel.create();

    // Das Reference Array Element zusammen bauen
    var el = new self.arrayReference(refModel, self);
    el.ref = function() { return refObj; };

    var array = obj[arrayName];
    array.push(el);

    return el.ref();
  }
}

Model.prototype.createArrayElement = function(arrayModel, obj, arrayName, rootObject) {
  // Das hier ist die Funktion um ein neues Array Element anzulegen
  return function() {
    var el = arrayModel._initObject(rootObject); // creates the new element

    // add an unique id for each object in the array,
    // to enable linking to that object
    el._id = ObjectId();

    // add the element to the lookup-table
    rootObject._childObjs[el._id] = el;

    var array = obj[arrayName];
    array.push(el); // add the element to the array
    return el;
  }
}

/// Erstellt alles was für den Datenbankzugriff benötigt wird

// def was ich alles mit dem obj tun kann
Model.prototype._addStore = function(obj) {
  var self = this;

  var prepareSave = function(obj, model) {
    var doc = {};  // the target document to sore

    if (obj.hasOwnProperty("_id")) {
      doc._id = obj._id;  // copy _id
    }

    // copy attrObjs
    for (var i in model.attrObjs) {
      check(typeof obj[i] == 'object', "Object attribute '"+ i +"' not provided in your object (model '"+model.modelName+"')");
      doc[i] = prepareSave(obj[i], model.attrObjs[i]);
    }

    // copy attrArrays
    for (var i in model.attrArrays) {
      check(Array.isArray(obj[i]), "Array '"+ i +"' is not correctly provided in your object (model '"+model.modelName+"')");

      doc[i] = [];
      for (var j in obj[i]) {
        doc[i][j] = prepareSave(obj[i][j], model.attrArrays[i]);
      }
    }

    // apply attribute filters (eg. for type check..)
    for (var i in model.attrs) {

//      if (!obj.hasOwnProperty(model.attrs[i].name)) {  // check for error in usage!
//        console.log("Warning: Attribute '"+ model.attrs[i].name +"' not provided in your object (model '"+model.modelName+"')");
//        console.log("  Attribute will be set to null! Use '"+model.modelName+".create()' to avoid this problem!");
//        obj[model.attrs[i].name] = null;
//      }
      check(obj.hasOwnProperty(model.attrs[i].name), "Attribute '"+ model.attrs[i].name +"' not provided in your object (model '"+model.modelName+"')");

      doc[model.attrs[i].name] = obj[model.attrs[i].name];  // copy attribute

      try {
        for (var j=0; j<model.attrs[i].filters.length; j++) {
          doc[model.attrs[i].name] = model.attrs[i].filters[j](doc[model.attrs[i].name], 'save');  // call filter
        }
      } catch (err) {
        err.message = "Can't save '"+model.attrs[i].name+"' " + err.message;
        throw err;
      };

      obj[model.attrs[i].name] = doc[model.attrs[i].name];  // copy back to obj
    }

    // Speichern (vorbereiten) von Referenz-Attributen
    for (var i in model.attrRefs) {
      check(obj[i] instanceof Object, i + " not correctly provided");

      //doc[i] = obj[i];  // copy ref-attr
      doc[i] = {};

      if (obj[i]._reference) {  // es ist gerade nicht geladen, hat aber eine _reference-id
        doc[i]._reference = obj[i]._reference;
      }

      if (obj[i].ref !== undefined && obj[i].ref()._id !== undefined) {  // wenn das referenzierte Object existiert und bereits gespeichert wurde
        obj[i]._reference = obj[i].ref()._id;  // die reference id an das object geben
        doc[i]._reference = obj[i].ref()._id;  // die reference id mit persisieren
      }

      //obj[i] = doc[i];  // copy back to obj
    }

    // Speichern (vorbereiten) von Link-Attributen
    for (var i in model.attrLinks) {
      doc[i] = {};

      if (obj[i]._link) {
        doc[i]._link = obj[i]._link;
      }
    }

    // Speichern (vorbereiten) von Referenz-Arrays
    for (var i in model.attrRefArrays) {  // über alle Referenz Arrays die in meinem Modell vorkommen
      check(obj[i] instanceof Object, i + " not correctly provided");

      doc[i] = [];  // copy only the references

      var refArray = obj[i];
      for (var j=0; j<refArray.length; j++) {  // über die einzelnen Elemente dieses Arrays
        var ref = refArray[j];

        if (obj[i][j]._reference) {  // es ist gerade nicht geladen, hat aber eine _reference-id
          doc[i][j] = {};
          doc[i][j]._reference = obj[i][j]._reference;
        }

        if (ref !== undefined && ref.ref !== undefined && ref.ref()._id !== undefined) {  // wenn das referenzierte Object existiert und bereits gespeichert wurde
          obj[i][j]._reference = ref.ref()._id;   // die reference id im object speichern
          doc[i][j] = {};
          doc[i][j]._reference = ref.ref()._id;   // die reference id mit persisieren
        }
      }
    }

    return doc;
  }

  // The Save-function for a object instance
  obj.saveQ = function() {
    var deferred = Q.defer();

    try {
      var doc = prepareSave(obj, self);
    } catch (e) {
      deferred.reject(e);
      return deferred.promise;
    }

    // transform the object to a document
    // and apply attribute filters
    return self.saveQ(doc)  // store the document
      .then(function(resDoc) {
        // Achtung: client gibt hier ein string zurück
        if (resDoc != 1) {  // doc is 1 if an insert was performed
          obj._id = resDoc._id;  // store the generated Mongo-ObjectId to the local context
        }

        return obj;
      });
  };

  obj.save = obj.saveQ;  // compatibility

  obj.removeQ = function() {
    var deferred = Q.defer();

    if (obj._id === undefined) {
      deferred.reject(new Error("Object seems not to been saved so far!"));
      return deferred.promise;
    }

    return self.removeQ(obj._id)
      .then(function() {
        delete obj._id;

        deferred.resolve();
        return deferred.promise;
      })
      .fail(function(err) {
        deferred.reject(err);
        return deferred.promise;
      });

  };

  obj.remove = obj.removeQ;  // compatibility

  obj.validate = function(attr) {
    try {
      for (var i=0; i<self.attrs[attr].filters.length; i++) {
        self.attrs[attr].filters[i](obj[attr], 'validate');  // call filter
      }
    } catch (err) {
      return err.message;
    };

    return true;
  };

  return obj;
};

// Erstellt ein neues Object aus dem Modell
Model.prototype.create = function(initValues) {
  var obj = this._initObject();
  obj = this._addStore(obj);

  // lookup table of child objects
  obj._childObjs = {};

  obj.getChild = function(id) {
    return obj._childObjs[id];
  }

  if (initValues) {
    for (var i in initValues) {
      obj[i] = initValues[i];
    }
  }

  return obj;
};

// Create an empty collection of Modelizer Objects
// and add some nice functions
Model.prototype.createCollection = function() {
  var self = this;

  var coll = [];

  coll.create = function() {
    var el = self.create();
    coll.push(el);
  };

  coll.saveQ = function() {
    for (var i=0; i<coll.length; i++) {
      coll[i].saveQ().done();
    }
  }

  return coll;
}

// Diese Funktion fügt alles aus dem Modell in ein neues Object hinzu
Model.prototype._initObject = function(rootObject) {
  var obj = new Object();  // das wird usere Modell-Instanz

  rootObject = rootObject || obj;

  // create the attributes
  for(var i in this.attrs) {
    obj[this.attrs[i].name] = null;
  }

  for (var i in this.virtualAttrs) {
    obj[this.virtualAttrs[i].name] = null;
  }

  // create Attribute Objects (a sub structure)
  for(var i in this.attrObjs) {
    var attrObj = this.attrObjs[i]._initObject(rootObject);
    obj[i] = attrObj;
  }

  // create a reference to another model
  for(var i in this.attrRefs) {
    var modelRef = this.attrRefs[i];
    obj[i] = new this.reference(modelRef, this);
  }

  // create a links to objects
  for(var i in this.attrLinks) {
    var link = this.attrLinks[i];
    obj[i] = new this.link(link.model, link.link);
  }

  // create a reference Array to another model
  for(var i in this.attrRefArrays) {
    var modelRef = this.attrRefArrays[i];  // Das Model auf das referenziert wird
    var arrayName = i;

    obj[i] = [];  // init with empty array
    this.arrayReferenceRoot(modelRef, obj, i);  //init arrayRef helper functions

    arrayName = arrayName[0].toUpperCase() + arrayName.substr(1);
    obj["create" + arrayName] = this.createArrayReferenceElement(modelRef, obj, i);
  }

  // create the methods
  for(var i in this.methods) {
    //  obj[i] = function() {
    //    return this.callMethod(i, arguments);
    //  }
    obj[i] = this.methodImpls[i];
  }

//    // create the virtualAttrs
//    for (var i in this.virtualAttrs) {
//      obj[i] = this.virtualAttrImpls[i](obj);
//    }
  // TODO: es ist unklar wann am besten der Wert für ein virtueles Attribut brechnet wird

  // create stuff for attrArrays
  for (var i in this.attrArrays) {
    obj[i] = [];

    var arrayName = i;
    arrayName = arrayName[0].toUpperCase() + arrayName.substr(1);
    obj["create" + arrayName] = this.createArrayElement(this.attrArrays[i], obj, i, rootObject);

    //obj[i].create = this.createArrayElement(this.attrArrays[i], obj, i);  // add create method directly on the array
  }

  return obj;
};

Model.prototype.readFilter = function(fn) {
  this.readFilters.push(fn);
};

Model.prototype.afterReadFilter = function(fn) {
  this.afterReadFilters = fn;
}

// create the filter hash (mongo search string)
Model.prototype._getReadFilter = function(req) {
  var res = {};
  var bool_res = null;

  var promises = [];

  for (var i=0; i<this.readFilters.length; i++) {  // alle filter
    promises.push(Q(this.readFilters[i](req))
      .then(function(filter) {
        if (filter === false) bool_res = false;
        if (filter === true) bool_res = true;

        // copy content
        for (var j in filter) {
          res[j] = filter[j];
        }

      }))
  }

  return Q.all(promises)
    .then(function() {
      if (bool_res === null)
        return res
      else return bool_res;
    })
}

Model.prototype.writeFilter = function(fn) {
  this.writeFilters.push(fn);
}

// create the filter hash (mongo search string)
Model.prototype._getWriteFilter = function(obj, req) {
  var res = {};
  var bool_res = null;

  var promises = [];

  for (var i=0; i<this.writeFilters.length; i++) {  // alle filter
    promises.push(Q(this.writeFilters[i](obj, req))
      .then(function (filter) {
        if (filter === false) bool_res = false;
        if (filter === true) bool_res = true;

        // copy content
        for (var j in filter) {
          res[j] = filter[j];
        }

      }))
  }

  return Q.all(promises)
    .then(function() {
      if (bool_res === null)
        return res
      else return bool_res;
    })
}

// Using the model (static functions)

Model.prototype.loadFromDoc = function(doc, initObj) {
  var rootObj = initObj || this.create();

  // TODO: das hier überschreibt ja alle Methoden
  // da muss ich mir was besseres überlegen

  var copy = function(obj, doc, model) {
    if (!doc) {  // doc missing
      doc = {};  // use empty one
      if (!obj) {
        obj = {};
      }
    }

    for (var i in doc) {  // kopiere alles was von der Datenquelle kommt
      obj[i] = doc[i];    // todo remove
    }

    for (var i in model.attrs) {
        obj[i] = doc[i];
    }

    // copy Attribute Objects (a sub structure)
    for(var i in model.attrObjs) {
      copy(obj[i], doc[i], model.attrObjs[i]);  // recursive
    }

     // create stuff for attrArrays
    for (var i in model.attrArrays) {

      if (doc[i] === undefined || doc[i] === null) {
        obj[i] = [];
      }

      // jedes element kopieren
      for (var j=0; j<doc[i].length; j++) {
        copy(obj[i][j], doc[i][j], model.attrArrays[i]);
      }

      var arrayName = i;
      arrayName = arrayName[0].toUpperCase() + arrayName.substr(1);
      obj["create" + arrayName] = model.createArrayElement(model.attrArrays[i], obj, i, rootObj);

  //    obj[i].create = this.createArrayElement(this.attrArrays[i], obj, i);  // add create method directly on the array
    }

    // TODO: hier kopierere ich teilweise _initObject verhalten (-> kapseln )
    // TODO: big todo!!

    // hier kümmere ich mich um die Referenzen
    for(var j in model.attrRefs) {
      var modelRef = model.attrRefs[j];
      var ref_id = obj[j]._reference;
      obj[j] = new model.reference(modelRef, model);
      obj[j]._reference = ref_id;
    }

    for(var j in model.attrLinks) {
      var link = model.attrLinks[j];
      var link_id = obj[j]._link;
      obj[j] = new model.link(link.model, link.link);
      if (link_id) {
        obj[j]._link = link_id;
      }
    }

    // hier kümmere ich mich um Referenz-Arrays
    for(var j in model.attrRefArrays) {
      var modelRef = model.attrRefArrays[j];
      var refArray = obj[j];

      assert(typeof refArray.length === 'number');
      for (var k=0; k<refArray.length; k++) {
        var ref = refArray[k];
        var ref_id = ref._reference;   // _reference retten
        obj[j][k] = new model.arrayReference(modelRef, model);
        obj[j][k]._reference = ref_id;       // zurück speichern
      }
      model.arrayReferenceRoot(modelRef, obj, j);
    }

    // TODO: kopieren von anderen Methoden die durch das kopieren oben überschrieben werden

    // store a reference of this object in the lookup-table
    if (doc._id && doc._id != rootObj._id) { // but don't store the rootObj
      rootObj._childObjs[doc._id] = obj;
    }
  };

  copy(rootObj, doc, this);

  return rootObj;
};

// todo: conflict with angular-client
Model.prototype.$get = function(id) {
  var self = this;

  this.getQ(id)
    .then(function(obj) {
      self.store.set(obj);
    })
    .fail(function(err) {
      if (err.message == "Object not found!") {
        self.store.del(id);
      }
    });

  return this.store.get(id);  // todo: was tun wenns id nicht gibt -> fail
};

Model.prototype.getQ = function(id, initObj) {
  var self = this;
  var deferred = Q.defer();

  self.collection.findOne({_id:id}, function(err, doc) {
    if (err) {
      deferred.reject(err);
      return;
    }
    if (doc === null) {
      deferred.reject(new Error("Object not found!"));
      return;
    }

    var obj = self.loadFromDoc(doc, initObj);

    Q(self.afterReadFilters(obj))
      .then(function () {
        deferred.resolve(obj);
      })
  });

  return deferred.promise;
};

Model.prototype.get = Model.prototype.getQ;

Model.prototype.findOneQ = function(search, initObj) {
  var self = this;
  var deferred = Q.defer();

  self.collection.findOne(search, function(err, doc) {
    if (err) {
      deferred.reject(err);
      return;
    }
    if (doc === null) {
      deferred.reject(new Error("Object not found!"));
      return;
    }

    var obj = self.loadFromDoc(doc, initObj);

    Q(self.afterReadFilters(obj))
      .then(function () {
        deferred.resolve(obj);
      });

  });

  return deferred.promise;
};

Model.prototype.findOneQ = Model.prototype.findOne;

Model.prototype.findQ = function(search, initObj) {
  var self = this;
  var deferred = Q.defer();

  self.collection.find(search, function(err, docs) {
    if (err) return deferred.reject(err);
    var objs = initObj || self.createCollection();
    var promises = [];

    // für jedes document in der DB ein object anlegen
    for (var i=0; i<docs.length; i++) {
      (function() {  // extra closure für obj
        var doc = docs[i];
        var obj = self.loadFromDoc(doc);

        promises.push(
          Q(self.afterReadFilters(obj))
            .then(function () {
              objs.push(obj);
            })
        );
      })();
    }

    return Q.all(promises)
      .then(function() {
        deferred.resolve(objs);
      })
  });

  return deferred.promise;
};

Model.prototype.find = Model.prototype.findQ;

Model.prototype.$all = function() {
  return this.store.all();
}

Model.prototype.allQ = function(initObj) {
  return this.findQ({}, initObj);
};

Model.prototype.all = Model.prototype.allQ;

Model.prototype.saveQ = function(obj) {
  var deferred = Q.defer();
  assert(this.collection != undefined, "connection no set for " + this.modelName);

  this.collection.save(obj, function(err, doc) {
    if (err) {
      deferred.reject(err);
      return;
    }
    deferred.resolve(doc);
  });

  return deferred.promise;
};

Model.prototype.save = Model.prototype.saveQ;

Model.prototype.removeQ = function(id) {
  var deferred = Q.defer();
  this.collection.remove({_id:id}, true, function(err, result) {
    if (err) {
      deferred.reject(new Error('Failed to remove document!'));
      return;
    }

    if (result.status == "OK") {  // success from a client call
      deferred.resolve();
      return;
    }

    // TODO: das hat wohl was mit der express send funktion zu tun, wenn parameter fehlen
    // Hinweis: MongoDB unter windows liefert ein anderes 'result'.. unklar warum
    if (result === 1 || (result.hasOwnProperty('n') && result.n == 1)) {  // removed sucessfull
      deferred.resolve();
      return;
    }
    if (result === 0 || ( result.hasOwnProperty('n') && result.n.hasOwnProperty('n') && result.n.n == 0 ) ) {
      deferred.reject(new Error('No document with this id found!'));
      return;
    }

    deferred.reject(new Error("Don't know what was the result of removing the object"));
    return;
  });

  return deferred.promise;
};

Model.prototype.remove = Model.prototype.removeQ;

Model.prototype.callOpQ = function(operationName, params, HTMLrequest) {
  return this.collection.callOperation(operationName, params, HTMLrequest);
};

Model.prototype.callOp = Model.prototype.callOpQ;

// serialize doc
Model.prototype._transform = function(model, doc, method) {

  // handle attributes
  for (var i in model.attrs) {
    for (var j=0; j<model.attrs[i].filters.length; j++) {
      doc[model.attrs[i].name] = model.attrs[i].filters[j](doc[model.attrs[i].name], method);  // call pack/unpack filter
    }
  }

  // pack attrObjs
  for (var i in model.attrObjs) {
    this._transform(model.attrObjs[i], doc[i], method);
  }

  // copy attrArrays
  for (var i in model.attrArrays) {
    for (var j in doc[i]) {
      this._transform(model.attrArrays[i], doc[i][j], method);
    }
  }

  // remove obj lookup-table
  delete doc['_childObjs'];
}

Model.prototype.processSchema = function(schema) {
  assert(typeof schema == 'object', "Error in Schema ("+this.modelName+") definition (has to be a Hash)");

  for (var entry in schema) {
    var value = schema[entry];
    //console.log("value", value);

    // it is a attrArray
    if (Array.isArray(value)) {
      assert(value.length == 1, "Only one element in " + entry + " allowed");
      var attrArrayModel = new Model(entry, value[0]);
      this.attrArray(entry, attrArrayModel);

    } else if (value instanceof Model) {
      this.attrObj(entry, value);

      // it is a attribute
    } else if (value._what == 'attr') {
      this.attr(entry, value.filter);

      // it is a virutal attribute
    } else if (value._what == 'virtualAttr') {
      this.virtualAttr(entry);

      // it is a reference to another model
    } else if (value._what == 'attrRef') {
      this.attrRef(entry, value.ref);

      // it is a link to an object
    } else if (value._what == 'attrLink') {
      this.attrLink(entry, value.model, value.link);

      // it is a many Reference to another model
    } else if (value._what == 'attrRefArray') {
      this.attrRefArray(entry, value.ref);

      // it is an array with objects
    } else if (value._what == 'attrObjArray') {
      this.attrArray(entry, value.ref);

      // it is a operation definition
      // todo parameter validation
    } else if (value._what == 'operation') {
      this.operation(entry);

    } else if (value._what == 'method') {
        this.method(entry);
        this.methodImpl(entry, value.impl);

    } else if (value._what == 'factory') {
      this.factory(entry);

      // i assume in this cases that it is an 'attrObj' (nested object)
    } else {
      var attrObjModel = new Model(entry, value);
      this.attrObj(entry, attrObjModel);
    }
  }
};

///////////////////////////
// Helpers for Schema definition

// Usage eg: Attr(Types.String, Attr.default("foo"), ..)
Model.Attr = function() {
  var filters = arguments;

  return {
    '_what' : 'attr',
    filter: function(value, action) {
      for (var i in filters) {
        value = filters[i](value, action);  // call all filters
      }
      return value;
    }
  };
};

Model.VirtualAttr = function() {
  return {
    '_what' : 'virtualAttr'
  };
};

Model.Ref = function(reference) {
  return {
    '_what' : 'attrRef',
    ref : reference
  };
};

Model.Link = function(model, link) {
  return {
    '_what' : 'attrLink',
    model : model,
    link : link
  };
};

Model.RefArray = function(reference) {
  return {
    '_what' : 'attrRefArray',
    ref : reference
  }
};

Model.ObjArray = function(reference) {
  return {
    '_what' : 'attrObjArray',
    ref : reference
  }
};

Model.Operation = function() {
  return {
    '_what' : 'operation'
  }
};

Model.Factory = function() {
    return {
        '_what' : 'factory'
    }
};

Model.Method = function(impl) {
    return {
        '_what' : 'method',
        impl : impl
    }
};

///////////////////////////

///////////////////////////
// Filters and Type  checks

// define a default value for a attribute
Model.Attr.default = function(def) {
  return function(value, action) {
    if (value == undefined || value == null) {
      value = def;
    }
    return value;
  }
};

Model.Attr.required = function(def) {
  return function (value) {
    if (value === undefined || value === null || value === "") {
      throw new Error("Value has to be not null");
    }
    return value;
  }
};

Model.Attr.Types = {
  // define a string type
  string : function(value, action) {
    if (typeof value != 'string' && value !== undefined && value !== null) {
      throw new Error("'"+value+"' is not a string value");
    }
    return value;
  },
  // define a number type
  number : function(value, action) {
    if (typeof value != 'number' && value !== undefined && value !== null) {
      throw new Error("'"+value+"' is not a number");
    }
    return value;
  },
  boolean : function(value, action) {
    if (typeof value != 'boolean' && value !== undefined && value !== null) {
      throw new Error("'"+value+"' is not a boolean");
    }
    return value;
  },
  date : function(value, action) {
    if (action == 'pack') {
      if (value !== undefined && value !== null && value instanceof Date) {
        return value.toISOString();
      } else {
        return value;
      }
    }

    if (action == 'unpack') {
      if (value !== undefined && value !== null) {
        return new Date(value);
      } else {
        return value;
      }
    }

    if (!(value instanceof Date) && value !== undefined && value !== null) {
      throw new Error("'"+value+"' is not a date");
    }

    return value;
  },
  array : function(value, action) {
    if (!Array.isArray(value) && value !== undefined && value !== null) {
      throw new Error("'"+value+"' is not an array");
    }
    return value;
  },
  ObjectId : function(value, action) {
    return value;
  },
  // define a enumeration type
  enum : function() {

    var enums = {};
    for (var i in arguments) {
      enums[arguments[i]] = true;
    }

    return function(value, action) {
      if (!enums[value] && value !== undefined && value !== null) {
        throw new Error("'"+value+"' is not in the enum");
      }
      return value;
    }
  }
};

///////////////////////////

// all implementieren
// eigentlich ist model-def ein aspekt
// und von den aspekten gibts viele

module.exports = Model;

/*
if (typeof window === 'undefined') {
  module.exports = Model;

} else {
  window.require = function(content) {
    if (content.indexOf('modelizer') != -1) return Model;
  }
}
*/

redpajama_set_name: RedPajamaGithub


text:
package org.apache.olingo.fit.metadata;

import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

public class Schema extends AbstractMetadataElement {

  private final String namespace;

  private final Map<String, Container> containers;

  private final Map<String, Association> associations;

  private final Map<String, EntityType> entityTypes;

  public Schema(final String namespace) {
    this.namespace = namespace;
    entityTypes = new HashMap<String, EntityType>();
    containers = new HashMap<String, Container>();
    associations = new HashMap<String, Association>();
  }

  public String getNamespace() {
    return namespace;
  }

  public Collection<EntityType> getEntityTypes() {
    return entityTypes.values();
  }

  public EntityType getEntityType(final String name) {
    return entityTypes.get(name);
  }

  public Schema addEntityType(final String name, final EntityType entityType) {
    entityTypes.put(name, entityType);
    return this;
  }

  public Collection<Container> getContainers() {
    return containers.values();
  }

  public Container getContainer(final String name) {
    return containers.get(name);
  }

  public Schema addContainer(final String name, final Container container) {
    containers.put(name, container);
    return this;
  }

  public Association getAssociation(final String name) {
    return associations.get(name);
  }

  public Schema addAssociation(final String name, final Association association) {
    associations.put(name, association);
    return this;
  }
}


text:
#ifndef WebDevToolsAgentClient_h
#define WebDevToolsAgentClient_h

#include "../platform/WebCString.h"
#include "../platform/WebCommon.h"

namespace blink {

class WebString;
struct WebDeviceEmulationParams;
struct WebDevToolsMessageData;
struct WebRect;
struct WebSize;

class WebDevToolsAgentClient {
public:
    virtual void sendMessageToInspectorFrontend(const WebString&) { }
    virtual void sendDebuggerOutput(const WebString&) { }

    // Returns process id.
    virtual long processId() { return -1; }

    // Returns unique identifier of the entity within process.
    virtual int debuggerId() { return -1; }

    // Save the agent state in order to pass it later into WebDevToolsAgent::reattach
    // if the same client is reattached to another agent.
    virtual void saveAgentRuntimeState(const WebString&) { }

    // Resume the inspected renderer that is waiting for DevTools front-end to initialize its state.
    virtual void resumeStartup() { }

    class WebKitClientMessageLoop {
    public:
        virtual ~WebKitClientMessageLoop() { }
        virtual void run() = 0;
        virtual void quitNow() = 0;
    };
    virtual WebKitClientMessageLoop* createClientMessageLoop() { return 0; }
    virtual void willEnterDebugLoop() { }
    virtual void didExitDebugLoop() { }

    typedef void (*TraceEventCallback)(char phase, const unsigned char*, const char* name, unsigned long long id,
        int numArgs, const char* const* argNames, const unsigned char* argTypes, const unsigned long long* argValues,
        unsigned char flags, double timestamp);

    virtual void setTraceEventCallback(const WebString& categoryFilter, TraceEventCallback) { }
    virtual void resetTraceEventCallback() { }
    virtual void enableTracing(const WebString& categoryFilter) { }
    virtual void disableTracing() { }

    virtual void startGPUEventsRecording() { }
    virtual void stopGPUEventsRecording() { }

    // Enables device emulation as specified in params.
    virtual void enableDeviceEmulation(const WebDeviceEmulationParams& params) { }

    // Cancel emulation started via |enableDeviceEmulation| call.
    virtual void disableDeviceEmulation() { }

    virtual void setTouchEventEmulationEnabled(bool enabled, bool allowPinch) { }

protected:
    ~WebDevToolsAgentClient() { }
};

} // namespace blink

#endif


text:
Gulp plugin for creating versions of static files.

Examples:
* file.ext => ia-Gd5r_5P3C8IwhDTkpEC7rQI.ext
* file.ext => 54b0c58c7ce9f2a8b551351102ee0938.ext
* file.ext => file-1102ee0938.ext
* something else

[![Standard - JavaScript Style Guide](https://img.shields.io/badge/code_style-standard-brightgreen.svg)](https://standardjs.com)

## Install
```
npm install gulp-vr --save-dev
```
or
```
npm i gulp-vr -D
```

## Usage
```
const gulp = require('gulp')
const vr = require('gulp-vr')

gulp.task('default', () => {
  return gulp.src('src/*.{svg,css,js}')
      .pipe(vr.modifier())
      .pipe(gulp.dest('dest'));
})
```

## API

At the beginning
https://nodejs.org/api/crypto.html#crypto_class_hash

### vr.createHashBase64(algorithm, data)
@param {String} algorithm
@param {String|Buffer} data
@return {String}

Returns a string of the form: ia-Gd5r_5P3C8IwhDTkpEC7rQI
Convert base64 to a valid file name
Valid characters in base64: 'A-Z', 'a-z', '0-9', '+', '/', '='
'+', '/', '=' symbols in file names are forbidden

### vr.createHashHex(algorithm, data)
@param {String} algorithm
@param {String|Buffer} data
@return {String}

Returns a string of the form: 54b0c58c7ce9f2a8b551351102ee0938

### vr.modifier(options)
@param {Object} [options]
@param {Function} [options.modify]
@param {Object} [options.hash]
@param {String} [options.hash.algorithm=sha1]
@param {String} [options.hash.encoding=base64]
@return {Stream}

Modifies vinyl files. By default: file.ext => ia-Gd5r_5P3C8IwhDTkpEC7rQI.ext

#### options.modify(file)
@param {Vinyl} file - This is a proxy object over the current vinyl file.
Available for writing properties: basename, stem, extname.

Example:

```
function modify (file) {
  let mt = file.stat.mtime

  file.stem += `-${mt.getUTCFullYear()}-${mt.getUTCMonth()}-${mt.getUTCDay()}`
}
```

## License

MIT © Platonov Anton


text:
package org.springframework.security.ldap.authentication;

import java.util.Collection;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.context.MessageSource;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.support.MessageSourceAccessor;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.SpringSecurityMessageSource;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.ldap.userdetails.LdapUserDetailsMapper;
import org.springframework.security.ldap.userdetails.UserDetailsContextMapper;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * Base class for the standard {@code LdapAuthenticationProvider} and the
 * {@code ActiveDirectoryLdapAuthenticationProvider}.
 *
 * @author Luke Taylor
 * @since 3.1
 */
public abstract class AbstractLdapAuthenticationProvider
		implements AuthenticationProvider, MessageSourceAware {
	protected final Log logger = LogFactory.getLog(getClass());
	protected MessageSourceAccessor messages = SpringSecurityMessageSource.getAccessor();
	private boolean useAuthenticationRequestCredentials = true;
	private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
	protected UserDetailsContextMapper userDetailsContextMapper = new LdapUserDetailsMapper();

	public Authentication authenticate(Authentication authentication)
			throws AuthenticationException {
		Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication,
				() -> this.messages.getMessage("LdapAuthenticationProvider.onlySupports",
						"Only UsernamePasswordAuthenticationToken is supported"));

		final UsernamePasswordAuthenticationToken userToken = (UsernamePasswordAuthenticationToken) authentication;

		String username = userToken.getName();
		String password = (String) authentication.getCredentials();

		if (this.logger.isDebugEnabled()) {
			this.logger.debug("Processing authentication request for user: " + username);
		}

		if (!StringUtils.hasLength(username)) {
			throw new BadCredentialsException(this.messages.getMessage(
					"LdapAuthenticationProvider.emptyUsername", "Empty Username"));
		}

		if (!StringUtils.hasLength(password)) {
			throw new BadCredentialsException(this.messages.getMessage(
					"AbstractLdapAuthenticationProvider.emptyPassword",
					"Empty Password"));
		}

		Assert.notNull(password, "Null password was supplied in authentication token");

		DirContextOperations userData = doAuthentication(userToken);

		UserDetails user = this.userDetailsContextMapper.mapUserFromContext(userData,
				authentication.getName(),
				loadUserAuthorities(userData, authentication.getName(),
						(String) authentication.getCredentials()));

		return createSuccessfulAuthentication(userToken, user);
	}

	protected abstract DirContextOperations doAuthentication(
			UsernamePasswordAuthenticationToken auth);

	protected abstract Collection<? extends GrantedAuthority> loadUserAuthorities(
			DirContextOperations userData, String username, String password);

	/**
	 * Creates the final {@code Authentication} object which will be returned from the
	 * {@code authenticate} method.
	 *
	 * @param authentication the original authentication request token
	 * @param user the <tt>UserDetails</tt> instance returned by the configured
	 * <tt>UserDetailsContextMapper</tt>.
	 * @return the Authentication object for the fully authenticated user.
	 */
	protected Authentication createSuccessfulAuthentication(
			UsernamePasswordAuthenticationToken authentication, UserDetails user) {
		Object password = this.useAuthenticationRequestCredentials
				? authentication.getCredentials() : user.getPassword();

		UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(
				user, password,
				this.authoritiesMapper.mapAuthorities(user.getAuthorities()));
		result.setDetails(authentication.getDetails());

		return result;
	}

	public boolean supports(Class<?> authentication) {
		return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
	}

	/**
	 * Determines whether the supplied password will be used as the credentials in the
	 * successful authentication token. If set to false, then the password will be
	 * obtained from the UserDetails object created by the configured
	 * {@code UserDetailsContextMapper}. Often it will not be possible to read the
	 * password from the directory, so defaults to true.
	 *
	 * @param useAuthenticationRequestCredentials
	 */
	public void setUseAuthenticationRequestCredentials(
			boolean useAuthenticationRequestCredentials) {
		this.useAuthenticationRequestCredentials = useAuthenticationRequestCredentials;
	}

	public void setMessageSource(MessageSource messageSource) {
		this.messages = new MessageSourceAccessor(messageSource);
	}

	public void setAuthoritiesMapper(GrantedAuthoritiesMapper authoritiesMapper) {
		this.authoritiesMapper = authoritiesMapper;
	}

	/**
	 * Allows a custom strategy to be used for creating the <tt>UserDetails</tt> which
	 * will be stored as the principal in the <tt>Authentication</tt> returned by the
	 * {@link #createSuccessfulAuthentication(org.springframework.security.authentication.UsernamePasswordAuthenticationToken, org.springframework.security.core.userdetails.UserDetails)}
	 * method.
	 *
	 * @param userDetailsContextMapper the strategy instance. If not set, defaults to a
	 * simple <tt>LdapUserDetailsMapper</tt>.
	 */
	public void setUserDetailsContextMapper(
			UserDetailsContextMapper userDetailsContextMapper) {
		Assert.notNull(userDetailsContextMapper,
				"UserDetailsContextMapper must not be null");
		this.userDetailsContextMapper = userDetailsContextMapper;
	}

	/**
	 * Provides access to the injected {@code UserDetailsContextMapper} strategy for use
	 * by subclasses.
	 */
	protected UserDetailsContextMapper getUserDetailsContextMapper() {
		return this.userDetailsContextMapper;
	}
}


text:
const config = require('./app.config');
const passport = require('passport');

const FacebookStrategy = require('passport-facebook').Strategy;
const VKontakteStrategy = require('passport-vkontakte').Strategy;

passport.use(
    new FacebookStrategy({
        clientID: config.facebook.api.appId,
        clientSecret: config.facebook.api.appSecret,
        callbackURL: `http://localhost:${config.app.port}${config.facebook.path}${config.facebook.redirect_url}`
    },
    (accessToken, refreshToken, profile, cb) => {
        return cb(null, {facebook: {accessToken, refreshToken}})
    })
);

passport.use(
    new VKontakteStrategy({
        clientID: config.vkontakte.api.appId,
        clientSecret: config.vkontakte.api.appSecret,
        callbackURL: `http://localhost:${config.app.port}${config.vkontakte.path}${config.vkontakte.redirect_url}`
    },
    (accessToken, refreshToken, profile, cb) => {
        return cb(null, {vkontakte: {accessToken, refreshToken}})
    })
);

passport.serializeUser(function(user, cb) {
    cb(null, user);
});

passport.deserializeUser(function(obj, cb) {
    cb(null, obj);
});

module.exports = passport;


text:
local Threads = require 'threads'

-- This script contains the logic to create K threads for parallel data-loading.
-- For the data-loading details, look at donkey.lua
-------------------------------------------------------------------------------
do -- start K datathreads (donkeys)
   if opt.nDonkeys > 0 then
      local options = opt -- make an upvalue to serialize over to donkey threads
      donkeys = Threads(
         opt.nDonkeys,
         function()
            require 'torch'
         end,
         function(idx)
            opt = options -- pass to all donkeys via upvalue
            tid = idx
            local seed = opt.manualSeed + idx
            torch.manualSeed(seed)
            print(string.format('Starting donkey with id: %d seed: %d', tid, seed))
            paths.dofile('donkey.lua')
         end
      );
   else -- single threaded data loading. useful for debugging
      paths.dofile('donkey.lua')
      donkeys = {}
      function donkeys:addjob(f1, f2) f2(f1()) end
      function donkeys:synchronize() end
   end
end

nClasses = nil
classes = nil
donkeys:addjob(
   function() return trainLoader.classes end,
   function(c) classes = c end)
donkeys:synchronize()
nClasses = #classes
assert(nClasses, "Failed to get nClasses")
print('nClasses: ', nClasses)
torch.save(paths.concat(opt.save, 'classes.t7'), classes)


text:
using System.Collections.Generic;

namespace osu_StreamCompanion.Code.Helpers
{
    public static class ListExtensions
    {

        public static bool StartsAnywhereWith(this List<string> list,string val)
        {
            foreach (var variable in list)
            {
                if (variable.StartsWith(val))
                    return true;
            }
            return false;
        }
        public static int AnyStartsWith(this IReadOnlyList<string> list, string val)
        {
            for (int i = 0; i < list.Count; i++)
            {
                if (list[i].StartsWith(val))
                    return i;
            }
            return -1;
        }
    }
}


text:
const assert = require('assert')

const fetch = require('node-fetch')
const freeport = require('freeport-promise')
const Server = require('../lib/')
const fs = require('fs')
const path = require('path')

describe('Demo plugin ', () => {
  it('works', async () => {
    process.env.SIGNALK_NODE_CONFIG_DIR = require('path').join(
      __dirname,
      'plugin-test-config'
    )
    const pluginConfig = {
      enabled: true,
      configuration: {
        testOption: 'testValue'
      }
    }

    mkDirSync(path.join(`${__dirname}/plugin-test-config/plugin-config-data`))
    writePluginConfig(pluginConfig)

    const port = await freeport()
    const server = new Server({
      config: { settings: { port } }
    })
    await server.start()
    const plugins = await fetch(`http://0.0.0.0:${port}/skServer/plugins`).then(res =>
      res.json()
    )
    assert(plugins.find(plugin => plugin.id === 'testplugin'))

    const plugin = server.app.plugins.find(plugin => plugin.id === 'testplugin')
    assert(plugin)
    assert(plugin.started)

    const optionsTest = plugin.app.readPluginOptions()
    assert(optionsTest.configuration.testOption === 'testValue')

    assert(server.app.signalk.self.some.path.value === 'someValue')

    const outputValues = []
    server.app.signalk.on('delta', msg => {
      outputValues.push(msg.updates[0].values[0].value)
    })
    server.app.handleMessage('foo', {
      updates: [
        {
          values: [
            {
              path: 'navigation.courseOverGroundTrue',
              value: Math.PI
            }
          ]
        }
      ]
    })
    server.app.handleMessage('foo', {
      updates: [
        {
          values: [
            {
              path: 'navigation.courseOverGroundMagnetic',
              value: 2
            }
          ]
        }
      ]
    })

    pluginConfig.enabled = false
    await postPluginConfig(port, pluginConfig)

    server.app.handleMessage('foo', {
      updates: [
        {
          values: [
            {
              path: 'navigation.courseOverGroundTrue',
              value: 3
            }
          ]
        }
      ]
    })
    assert.equal(outputValues[0], -1)
    assert.equal(outputValues[1], 2)
    assert.equal(outputValues[2], 3)

    await server.stop()
  })
})

function mkDirSync (dirPath) {
  try {
    fs.mkdirSync(dirPath)
  } catch (err) {
    if (err.code !== 'EEXIST') {
      throw err
    }
  }
}

function writePluginConfig (config) {
  fs.writeFileSync(
    path.join(
      `${__dirname}/plugin-test-config/plugin-config-data/testplugin.json`
    ),
    JSON.stringify(config)
  )
}

async function postPluginConfig (port, config) {
  await fetch(`http://0.0.0.0:${port}/skServer/plugins/testplugin/config`, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json'
    },
    body: JSON.stringify(config)
  })
}


text:
{% extends "layout.html" %}

{% block page_title %}
  Sprint {{sprint}} - Dashboard
{% endblock %}

{% block inside_header %}

{% endblock %}

{% block after_header %}
{% include "sprint/"+sprint+"/includes/header.html" %}
{% endblock %}

{% block content %}

Levy account created

Red & White Holdings Ltd

Things you can do

                Enable spending

You need to sign a legal agreement before you can spend your levy funds.

                Invite team members

You can invite team members to access this account.

                Forecast your funds

Forecast the funds you'll be able to spend.

                Explore training and find a provider.

Find training courses and training providers.

                Plan your end point assessments

Register of apprentice assessment organisations

Checklist

                              You need to sign 1 agreement.

                              Invite team members.

                                  1 Team member added
                                  2 Team members added

                              Forecast your funds
                                Forecast added on 20 May 2017

                              Explore training and find a provider.

                              Learn more about Endpoint Assesment.

            To enable spending you must sign 1 agreement.

Red & White Holdings Ltd

                        Enable your organisations to spend levy

Add and manage organisations that'll spend levy.

                        Manage PAYE schemes

Add levy funds to your account by adding PAYE schemes.

                     View your finances

View transactions and forecast your levy funds.

                        Spend your levy

Add an apprentice or review and approve apprenticeship starts.

                        Manage your apprentices

View, pause and stop current apprentices.

                        Manage your team

Control what your team can do and invite new team members.

Help us improve this section

Take a 3 minute survey about managing your account or invitations so that we can improve the service.

Take the survey about your experience of managing your own account or being invited to a team

{% endblock %}


text:
A `Tray` represents an icon in operating system's notification area, it is
usually attached with a context menu.

```javascript
var app = require('app');
var Menu = require('menu');
var Tray = require('tray');

var appIcon = null;
app.on('ready', function(){
  appIcon = new Tray('/path/to/my/icon');
  var contextMenu = Menu.buildFromTemplate([
    { label: 'Item1', type: 'radio' },
    { label: 'Item2', type: 'radio' },
    { label: 'Item3', type: 'radio', clicked: true },
    { label: 'Item4', type: 'radio' },
  ]);
  appIcon.setToolTip('This is my application.');
  appIcon.setContextMenu(contextMenu);
});

```

__Platform limitations:__

* On OS X `clicked` event will be ignored if the tray icon has context menu.
* On Linux app indicator will be used if it is supported, otherwise
  `GtkStatusIcon` will be used instead.
* App indicator will only be showed when it has context menu.
* When app indicator is used on Linux, `clicked` event is ignored.

So if you want to keep exact same behaviors on all platforms, you should not
rely on `clicked` event and always attach a context menu to the tray icon.

## Class: Tray

`Tray` is an [EventEmitter](event-emitter).

### new Tray(image)

* `image` [Image](image.md)

Creates a new tray icon associated with the `image`.

### Event: 'clicked'

Emitted when the tray icon is clicked.

### Tray.setImage(image)

* `image` [Image](image.md)

Sets the `image` associated with this tray icon.

### Tray.setPressedImage(image)

* `image` [Image](image.md)

Sets the `image` associated with this tray icon when pressed.

### Tray.setToolTip(toolTip)

* `toolTip` String

### Tray.setContextMenu(menu)

* `menu` Menu

[event-emitter]: http://nodejs.org/api/events.html#events_class_events_eventemitter