diff --git a/code/lab-0/configureCloud9.sh b/code/lab-0/configureCloud9.sh index 3150192..fb5ce96 100755 --- a/code/lab-0/configureCloud9.sh +++ b/code/lab-0/configureCloud9.sh @@ -5,7 +5,6 @@ sudo yum update -y pip install cfn-lint --use-feature=2020-resolver #cleanup -rm -fr ~/environment/wild-rydes-async-messaging/workshop/ rm -fr ~/environment/wild-rydes-async-messaging/.git mv ~/environment/wild-rydes-async-messaging/code/lab-* ~/environment/wild-rydes-async-messaging/ rm -fr ~/environment/wild-rydes-async-messaging/code/ \ No newline at end of file diff --git a/workshop/buildspec.yml b/workshop/buildspec.yml deleted file mode 100644 index 54adf0e..0000000 --- a/workshop/buildspec.yml +++ /dev/null @@ -1,27 +0,0 @@ -version: 0.2 -phases: - install: - runtime-versions: - golang: 1.13 - nodejs: 10 - commands: - - echo Entered the install phase... - - apt-get -qq update && apt-get -qq install curl - - apt-get -qq install asciidoctor - - curl -s -L https://github.com/gohugoio/hugo/releases/download/v0.74.3/hugo_0.74.3_Linux-64bit.deb -o hugo.deb - - dpkg -i hugo.deb - finally: - - echo Installation done - build: - commands: - - echo Entered the build phase ... - - echo Build started on `date` - - cd $CODEBUILD_SRC_DIR/workshop - - hugo --quiet - finally: - - echo Building the HTML files finished -artifacts: - files: - - "**/*" - base-directory: $CODEBUILD_SRC_DIR/workshop/public/ - discard-paths: no diff --git a/workshop/config.toml b/workshop/config.toml deleted file mode 100644 index 0b46ea0..0000000 --- a/workshop/config.toml +++ /dev/null @@ -1,40 +0,0 @@ -RelativeURLs=true -CanonifyURLs=true -languageCode = "en-US" -defaultContentLanguage = "en" - -title = "Wild Rydes Asynchronous Messaging Workshop" -theme = "learn" -metaDataFormat = "yaml" -defaultContentLanguageInSubdir= false - -uglyurls = true -sectionPagesMenu = "main" -pygmentsCodeFences = true -pygmentsStyle = "monokai" - -[params] - editURL = "https://code.amazon.com/packages/AwsSaDeMsgPtnMcrSrv/trees/mainline/--/workshop/content/" - description = "Wild Rydes Asynchronous Messaging Workshop" - author = "Jane Architect" - disableBreadcrumb = false - disableNextPrev = false - themeVariant = "aws" - disableSearch = false - disableAssetsBusting = true - disableLanguageSwitchingButton = false - disableShortcutsTitle = true - disableInlineCopyToClipBoard = true - -[outputs] -home = [ "HTML", "RSS", "JSON"] - -[blackfriday] -plainIDAnchors = true -hrefTargetBlank = true - -[[menu.shortcuts]] -name = " Github repo" -identifier = "ds" -url = "https://github.com/aws-samples/asynchronous-messaging-workshop/" -weight = 10 \ No newline at end of file diff --git a/workshop/content/_index.md b/workshop/content/_index.md deleted file mode 100644 index 4f2e6bb..0000000 --- a/workshop/content/_index.md +++ /dev/null @@ -1,23 +0,0 @@ -+++ -title = "Decoupled Microservices" -weight = 1 -pre = "1. " -+++ - -![Intro](/images/wild-rydes.png) - -# Welcome Builders! - -Extend the existing and successful Wild Rydes service with asynchronous messaging for our microservices to allow us to scale reliable into new dimensions. - -One of the implications of applying the microservices architectural style in Wild Rydes is that a lot of communication between components is done over the network. In order to be able to individually scale, operate, and evolve each service, this communication needs to happen in a loosely coupled manner. One option that our initial architect have in mind here is that all services expose an API following the REST architectural style. - -Using REST APIs for communications between a set of systems can decouple them to a certain degree, but only if applied properly - which is often not the case. Additionally, REST APIs tend to be designed with synchronous communications, which limits the potential for decoupling when you think about request paths through a landscape of microservices. However, there is another option that provides even looser coupling: asynchronous messaging. - -Asynchronous messaging is a fundamental approach for integrating independent systems, or building up a set of loosely coupled systems that can operate, scale, and evolve independently and flexibly. One could also quote our colleague Tim Bray on this: - -> **If your application is cloud-native, or large-scale, or distributed, and doesn’t include a messaging component, that’s probably a bug.** - -Within this workshop, we will introduce asynchronous messaging into Wild Rydes to support the ever growing demand of our business. - -{{< youtube UJxog8pDydU >}} diff --git a/workshop/content/choose-your-own-advanture/_index.md b/workshop/content/choose-your-own-advanture/_index.md deleted file mode 100644 index f4c95b2..0000000 --- a/workshop/content/choose-your-own-advanture/_index.md +++ /dev/null @@ -1,13 +0,0 @@ -+++ -title = "Choose Your Own Adventure" -class = "adventure" -weight = 19 -pre = "" -+++ - -Start with the lab which is most interesting for you and choose how to continue. All labs are independent and you don't have to follow a strict order. - -| | | -|:---------------------------------------------:|:---------------------------------------------:| -| [![Lab 1](choose-your-own-advanture/lab-1.png)](/fan-out-and-message-filtering.html) | [![Lab 2](choose-your-own-advanture/lab-2.png)](/topic-queue-chaining-and-load-balancer.html) | -| [![Lab 3](choose-your-own-advanture/lab-3.png)](/scatter-gather.html) | [![Lab 4](choose-your-own-advanture/lab-4.png)](/orchestration-and-coordination.html) | diff --git a/workshop/content/choose-your-own-advanture/lab-1.png b/workshop/content/choose-your-own-advanture/lab-1.png deleted file mode 100644 index d799d4a..0000000 Binary files a/workshop/content/choose-your-own-advanture/lab-1.png and /dev/null differ diff --git a/workshop/content/choose-your-own-advanture/lab-2.png b/workshop/content/choose-your-own-advanture/lab-2.png deleted file mode 100644 index 5baed36..0000000 Binary files a/workshop/content/choose-your-own-advanture/lab-2.png and /dev/null differ diff --git a/workshop/content/choose-your-own-advanture/lab-3.png b/workshop/content/choose-your-own-advanture/lab-3.png deleted file mode 100644 index 1da6655..0000000 Binary files a/workshop/content/choose-your-own-advanture/lab-3.png and /dev/null differ diff --git a/workshop/content/choose-your-own-advanture/lab-4.png b/workshop/content/choose-your-own-advanture/lab-4.png deleted file mode 100644 index d0b0e2f..0000000 Binary files a/workshop/content/choose-your-own-advanture/lab-4.png and /dev/null differ diff --git a/workshop/content/cleanups/_index.md b/workshop/content/cleanups/_index.md deleted file mode 100644 index 166a9cc..0000000 --- a/workshop/content/cleanups/_index.md +++ /dev/null @@ -1,31 +0,0 @@ -+++ -title = "Clean up" -weight = 60 -pre = "" -+++ - -{{% notice tip %}} -**Running the workshop at an AWS Event** -If you are running this workshop at an AWS hosted event, such as re:Invent, -Loft, Immersion Day, or any other event hosted by an AWS employee, you skip this section, as we will clean up everything for you. -{{% /notice %}} - -In this step, we will clean up the AWS Cloud9 IDE we have created at the very beginning. - -#### 1. Delete the AWS Cloud9 IDE - -Follow **[this deep link](https://console.aws.amazon.com/cloudformation/home?#/stacks?filteringText=wild-rydes-async-msg-0)** to list the **AWS CloudFormation** stack with the name `wild-rydes-async-msg-0`. Select the stack and choose **Delete**. - -{{%expand "Detailed description" %}} -![Step 1](cleanups/step-1.png) -{{% /expand%}} - - -1. Open the [AWS CloudFormation Console](https://console.aws.amazon.com/cloudformation/home) -2. Select `wild-rydes-lab-x` stack from the list of Stacks -3. Click the **Delete** button -4. On the confirmation modal screen that appears, click **Delete Stack** button - -> Note: You will need to delete the S3 bucket you created for this lab manually. - -That's it! All done. diff --git a/workshop/content/cleanups/step-1.png b/workshop/content/cleanups/step-1.png deleted file mode 100644 index 4ae1725..0000000 Binary files a/workshop/content/cleanups/step-1.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/_index.md b/workshop/content/fan-out-and-message-filtering/_index.md deleted file mode 100644 index ca54430..0000000 --- a/workshop/content/fan-out-and-message-filtering/_index.md +++ /dev/null @@ -1,42 +0,0 @@ -+++ -title = "Fan-Out & Message Filtering" -weight = 20 -pre = "Lab-1: " -+++ - -{{% notice info %}} -Make sure you executed the **[Workshop Prerequisites](/prerequisites.html)** first, before you start with this lab! -{{% /notice %}} - -As a registered customer, when you need a ride, you can use the Wild Rydes customer app to request a unicorn and manage everything around it. -As a registered unicorn, you can use the Wild Rydes unicorn app to manage everything around your business. - -In particular, unicorns are interested to use the app to submit a ride completion after they have successfully delivered a customer to their destination. -This is the use case we will now have a closer look at. - -At Wild Rydes, end-user clients typically communicate via REST APIs with the backend services. For our use case, the Wild Rydes unicorn app interacts with the API exposed by the unicorn management service. It uses the submit-ride-completion resource to send the relevant details of the ride to the backend. In response to that, the backend creates a new completed-ride resource and returns the respective status code, the location, and a representation of the new resource to the client. - -It’s probably not a surprise that there are other services in the Wild Rydes microservices landscape, that are also interested in a new completed ride: - -+ **Customer notification service**: Customers should get a notification into their app about their latest completed ride. -+ **Customer accounting service**: After all, Wild Rydes is a business, so this service would be responsible to collect the fare from the customer. -+ **Extraordinary rides service**: This is special service that is interested in rides with fares or distances above certain thresholds - preparing the respective data for marketeers and success managers. - -This use case obviously cries for making use of publish/subscribe messaging, which can comfortably done using Amazon SNS in a serverless and scalable manner. It decouples both sides as much as possible. Services on the right hand side can autonomously subscribe to the topic, transparent to the left hand side. - -![Module 1](fan-out-and-message-filtering/module-1.png) - -## Lab Objectives - -In this lab, you will acquire the following skills: - -+ **How to create an Amazon SNS topic?** -+ **How to add a AWS Lambda subscription to an Amazon SNS topic?** -+ **How to define a subscription filter in an Amazon SNS subscriptions?** -+ **How to call Amazon SNS from AWS Lambda?** - - -{{% notice tip %}} -**Lab source code** -If you are curious and would like to dive into the lab's source code, you are more than welcome to do so. You will find the source code of this lab in our Github repo **[here](https://github.com/aws-samples/asynchronous-messaging-workshop/tree/master/code/lab-1)**. -{{% /notice %}} diff --git a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/bootstrap-initial-state.files/template.yaml b/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/bootstrap-initial-state.files/template.yaml deleted file mode 100644 index 7a64813..0000000 --- a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/bootstrap-initial-state.files/template.yaml +++ /dev/null @@ -1,501 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Transform: AWS::Serverless-2016-10-31 -Description: > - SAM template to bootstrap the Wild Rydes Async Messaging Workshop Lab-1 - -# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst -Globals: - Function: - Timeout: 10 - -Resources: - PythonLayerWithBoto3: - Type: AWS::Serverless::LayerVersion - Properties: - LayerName: PythonLayerWithBoto3 - Description: Lambda Python 3.6 Layer with Boto3 - ContentUri: lambda-layers/ - CompatibleRuntimes: - - python3.6 - LicenseInfo: Apache 2.0 - RetentionPolicy: Retain - - SubmitRideCompletionFunction: - Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction - Properties: - CodeUri: unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.6 - Layers: - - !Ref PythonLayerWithBoto3 - Environment: - Variables: - TABLE_NAME: !Ref RidesTable -# TOPIC_ARN: !Ref RideCompletionTopic - Policies: - - DynamoDBCrudPolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - TableName: !Ref RidesTable -# - SNSPublishMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json -# TopicName: !GetAtt RideCompletionTopic.TopicName - Events: - WildRydes: - Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api - Properties: - Path: /submit-ride-completion - Method: post - - RidesTable: - Type: AWS::Serverless::SimpleTable - Properties: - TableName: Rides - PrimaryKey: - Name: id - Type: String - -# RideCompletionTopic: -# Type: AWS::SNS::Topic -# Properties: -# TopicName: RideCompletionTopic - -# CustomerNotificationServiceSubscription: -# Type: AWS::SNS::Subscription -# Properties: -# TopicArn: !Ref RideCompletionTopic -# Protocol: http -# Endpoint: !Sub "http://${CustomerNotifyLoadBalancer.DNSName}" - -# CustomerAccountingServiceSubscription: -# Type: AWS::SNS::Subscription -# Properties: -# TopicArn: !Ref RideCompletionTopic -# Protocol: http -# Endpoint: !Sub "http://${CustomerAccountingLoadBalancer.DNSName}" - -# ExtraordinaryRidesServiceSubscription: -# Type: AWS::SNS::Subscription -# Properties: -# TopicArn: !Ref RideCompletionTopic -# Protocol: http -# Endpoint: !Sub "http://${ExtraordinaryRidesLoadBalancer.DNSName}" -# FilterPolicy: { "fare": [{"numeric": [">=", 50]}], "distance": [{"numeric": [">=", 20]}] } - - ################################################## - ## BACKEND MICROSERVICES BASED ON AWS FARGATE ## - ################################################## - - VPC: - Type: AWS::EC2::VPC - Properties: - CidrBlock: 10.11.0.0/16 - EnableDnsSupport: true - EnableDnsHostnames: true - Tags: - - Key: Name - Value: !Join [ ':', [ !Ref 'AWS::StackName', 'VPC' ] ] - - InternetGateway: - Type: AWS::EC2::InternetGateway - Properties: - Tags: - - Key: Name - Value: !Join [ ':', [ !Ref 'AWS::StackName', 'InternetGateway' ] ] - - VPCGatewayAttachment: - Type: AWS::EC2::VPCGatewayAttachment - Properties: - VpcId: !Ref VPC - InternetGatewayId: !Ref InternetGateway - - RouteTable: - DependsOn: VPCGatewayAttachment - Type: AWS::EC2::RouteTable - Properties: - VpcId: !Ref VPC - Tags: - - Key: Name - Value: !Join [ ':', [ !Ref 'AWS::StackName', 'RouteTable' ] ] - - Route: - Type: AWS::EC2::Route - Properties: - RouteTableId: !Ref RouteTable - DestinationCidrBlock: 0.0.0.0/0 - GatewayId: !Ref InternetGateway - - PublicSubnet1: - Type: AWS::EC2::Subnet - Properties: - VpcId: !Ref VPC - CidrBlock: 10.11.0.0/24 - AvailabilityZone: !Select [0, !GetAZs ''] - Tags: - - Key: Name - Value: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnet1' ] ] - - PublicSubnet2: - Type: AWS::EC2::Subnet - Properties: - VpcId: !Ref VPC - CidrBlock: 10.11.1.0/24 - AvailabilityZone: !Select [1, !GetAZs ''] - Tags: - - Key: Name - Value: !Join [ ':', [ !Ref 'AWS::StackName', 'PublicSubnet2' ] ] - - PublicSubnet1RouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - SubnetId: !Ref PublicSubnet1 - RouteTableId: !Ref RouteTable - - PublicSubnet2RouteTableAssociation: - Type: AWS::EC2::SubnetRouteTableAssociation - Properties: - SubnetId: !Ref PublicSubnet2 - RouteTableId: !Ref RouteTable - - SecurityGroup: - Type: AWS::EC2::SecurityGroup - Properties: - GroupDescription: Limits security group ingress and egress traffic for the ECS tasks running in AWS Fargate - VpcId: !Ref VPC - SecurityGroupIngress: - - IpProtocol: tcp - FromPort: 80 - ToPort: 80 - CidrIp: 0.0.0.0/0 - - ECSTaskExecutionRole: - Type: AWS::IAM::Role - Properties: - AssumeRolePolicyDocument: - Statement: - - Effect: Allow - Principal: - Service: [ecs-tasks.amazonaws.com] - Action: ['sts:AssumeRole'] - Path: / - ManagedPolicyArns: - - arn:aws:iam::aws:policy/service-role/AmazonECSTaskExecutionRolePolicy - - ECSCluster: - Type: AWS::ECS::Cluster - Properties: - ClusterName: wild-rides-cluster - - CustomerAccountingServiceECSTaskDefinition: - Type: AWS::ECS::TaskDefinition - Properties: - Family: customer-accounting-service-task - Cpu: 512 - Memory: 1024 - NetworkMode: awsvpc - RequiresCompatibilities: - - FARGATE - ExecutionRoleArn: !Ref ECSTaskExecutionRole - ContainerDefinitions: - - Name: customer-accounting-service-task - Cpu: 512 - Memory: 1024 - Image: !Sub '689573718314.dkr.ecr.eu-central-1.amazonaws.com/wild-rydes/generic-backend-microservice:latest' - Environment: - - Name: SERVICE_NAME - Value: customer-accounting-service - PortMappings: - - ContainerPort: 80 - LogConfiguration: - LogDriver: awslogs - Options: - awslogs-group: !Ref WildRidesCloudWatchLogsGroup - awslogs-region: !Ref AWS::Region - awslogs-stream-prefix: customer-accounting-service - - CustomerNotificationServiceECSTaskDefinition: - Type: AWS::ECS::TaskDefinition - Properties: - Family: customer-notification-service-task - Cpu: 512 - Memory: 1024 - NetworkMode: awsvpc - RequiresCompatibilities: - - FARGATE - ExecutionRoleArn: !Ref ECSTaskExecutionRole - ContainerDefinitions: - - Name: customer-notification-service-task - Cpu: 512 - Memory: 1024 - Image: !Sub '689573718314.dkr.ecr.eu-central-1.amazonaws.com/wild-rydes/generic-backend-microservice:latest' - Environment: - - Name: SERVICE_NAME - Value: customer-notification-service - PortMappings: - - ContainerPort: 80 - LogConfiguration: - LogDriver: awslogs - Options: - awslogs-group: !Ref WildRidesCloudWatchLogsGroup - awslogs-region: !Ref AWS::Region - awslogs-stream-prefix: customer-notification-service - - ExtraordinaryRidesServiceECSTaskDefinition: - Type: AWS::ECS::TaskDefinition - Properties: - Family: extraordinary-rides-service-task - Cpu: 512 - Memory: 1024 - NetworkMode: awsvpc - RequiresCompatibilities: - - FARGATE - ExecutionRoleArn: !Ref ECSTaskExecutionRole - ContainerDefinitions: - - Name: extraordinary-rides-service-task - Cpu: 512 - Memory: 1024 - Image: !Sub '689573718314.dkr.ecr.eu-central-1.amazonaws.com/wild-rydes/generic-backend-microservice:latest' - Environment: - - Name: SERVICE_NAME - Value: extraordinary-rides-service - PortMappings: - - ContainerPort: 80 - LogConfiguration: - LogDriver: awslogs - Options: - awslogs-group: !Ref WildRidesCloudWatchLogsGroup - awslogs-region: !Ref AWS::Region - awslogs-stream-prefix: extraordinary-rides-service - - # ALB added to facade the containers for back end services - Customer accounting - CustomerAccountingLoadBalancer: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Name: !Sub "caslb-${AWS::StackName}" - Subnets: - - !Ref PublicSubnet1 - - !Ref PublicSubnet2 - SecurityGroups: - - !Ref SecurityGroup - Tags: - - Key: Name - Value: !Ref AWS::StackName - - CustomerAccountingLoadBalancerListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - LoadBalancerArn: !Ref CustomerAccountingLoadBalancer - Port: 80 - Protocol: HTTP - DefaultActions: - - Type: forward - TargetGroupArn: !Ref CustomerAccountingTargetGroup - - CustomerAccountingTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - VpcId: !Ref VPC - Port: 80 - Protocol: HTTP - Matcher: - HttpCode: 200-299 - HealthCheckIntervalSeconds: 60 - HealthCheckPath: / - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 5 - HealthyThresholdCount: 2 - TargetType: ip - - # ALB added to facade the containers for back end services - Customer notification - CustomerNotifyLoadBalancer: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Name: !Sub "cnslb-${AWS::StackName}" - Subnets: - - !Ref PublicSubnet1 - - !Ref PublicSubnet2 - SecurityGroups: - - !Ref SecurityGroup - Tags: - - Key: Name - Value: !Ref AWS::StackName - - CustomerNotifyLoadBalancerListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - LoadBalancerArn: !Ref CustomerNotifyLoadBalancer - Port: 80 - Protocol: HTTP - DefaultActions: - - Type: forward - TargetGroupArn: !Ref CustomerNotifyTargetGroup - - CustomerNotifyTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - VpcId: !Ref VPC - Port: 80 - Protocol: HTTP - Matcher: - HttpCode: 200-299 - HealthCheckIntervalSeconds: 60 - HealthCheckPath: / - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 5 - HealthyThresholdCount: 2 - TargetType: ip - - # ALB added to facade the containers for back end services - extraordinary rides - ExtraordinaryRidesLoadBalancer: - Type: AWS::ElasticLoadBalancingV2::LoadBalancer - Properties: - Name: !Sub "erslb-${AWS::StackName}" - Subnets: - - !Ref PublicSubnet1 - - !Ref PublicSubnet2 - SecurityGroups: - - !Ref SecurityGroup - Tags: - - Key: Name - Value: !Ref AWS::StackName - - ExtraordinaryRidesLoadBalancerListener: - Type: AWS::ElasticLoadBalancingV2::Listener - Properties: - LoadBalancerArn: !Ref ExtraordinaryRidesLoadBalancer - Port: 80 - Protocol: HTTP - DefaultActions: - - Type: forward - TargetGroupArn: !Ref ExtraordinaryRidesTargetGroup - - ExtraordinaryRidesTargetGroup: - Type: AWS::ElasticLoadBalancingV2::TargetGroup - Properties: - VpcId: !Ref VPC - Port: 80 - Protocol: HTTP - Matcher: - HttpCode: 200-299 - HealthCheckIntervalSeconds: 60 - HealthCheckPath: / - HealthCheckProtocol: HTTP - HealthCheckTimeoutSeconds: 5 - HealthyThresholdCount: 2 - TargetType: ip - - CustomerAccountingServiceECSService: - Type: AWS::ECS::Service - DependsOn: CustomerAccountingLoadBalancerListener - Properties: - ServiceName: customer-accounting-service-service - Cluster: !Ref ECSCluster - LaunchType: FARGATE - DeploymentConfiguration: - MaximumPercent: 200 - MinimumHealthyPercent: 100 - DesiredCount: 1 - NetworkConfiguration: - AwsvpcConfiguration: - AssignPublicIp: ENABLED # to be able to download images from ECR - SecurityGroups: - - !Ref SecurityGroup - Subnets: - - !Ref PublicSubnet1 - - !Ref PublicSubnet2 - TaskDefinition: !Ref CustomerAccountingServiceECSTaskDefinition - LoadBalancers: - - ContainerName: "customer-accounting-service-task" - ContainerPort: 80 - TargetGroupArn: !Ref CustomerAccountingTargetGroup - - CustomerNotificationServiceECSService: - Type: AWS::ECS::Service - DependsOn: CustomerNotifyLoadBalancerListener - Properties: - ServiceName: customer-notification-service-service - Cluster: !Ref ECSCluster - LaunchType: FARGATE - DeploymentConfiguration: - MaximumPercent: 200 - MinimumHealthyPercent: 100 - DesiredCount: 1 - NetworkConfiguration: - AwsvpcConfiguration: - AssignPublicIp: ENABLED # to be able to download images from ECR - SecurityGroups: - - !Ref SecurityGroup - Subnets: - - !Ref PublicSubnet1 - - !Ref PublicSubnet2 - TaskDefinition: !Ref CustomerNotificationServiceECSTaskDefinition - LoadBalancers: - - ContainerName: "customer-notification-service-task" - ContainerPort: 80 - TargetGroupArn: !Ref CustomerNotifyTargetGroup - - ExtraordinaryRidesServiceECSService: - Type: AWS::ECS::Service - DependsOn: ExtraordinaryRidesLoadBalancerListener - Properties: - ServiceName: extraordinary-rides-service-service - Cluster: !Ref ECSCluster - LaunchType: FARGATE - DeploymentConfiguration: - MaximumPercent: 200 - MinimumHealthyPercent: 100 - DesiredCount: 1 - NetworkConfiguration: - AwsvpcConfiguration: - AssignPublicIp: ENABLED # to be able to download images from ECR - SecurityGroups: - - !Ref SecurityGroup - Subnets: - - !Ref PublicSubnet1 - - !Ref PublicSubnet2 - TaskDefinition: !Ref ExtraordinaryRidesServiceECSTaskDefinition - LoadBalancers: - - ContainerName: "extraordinary-rides-service-task" - ContainerPort: 80 - TargetGroupArn: !Ref ExtraordinaryRidesTargetGroup - - WildRidesCloudWatchLogsGroup: - Type: AWS::Logs::LogGroup - Properties: - LogGroupName: ecs/wild-rides/async-msg - RetentionInDays: 30 - -Outputs: - # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function - # Find out more about other implicit resources you can reference within SAM - # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api - UnicornManagementServiceApiSubmitRideCompletionEndpoint: - Description: "API Gateway endpoint URL for Prod stage for SubmitRideCompletion function" - Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/submit-ride-completion/" - - SubmitRideCompletionFunction: - Description: "SubmitRideCompletionFunction Lambda Function ARN" - Value: !GetAtt SubmitRideCompletionFunction.Arn - Export: - Name: 'WILD-RIDES:RIDES-COMPLETION-FUNCTION' - - SubmitRideCompletionFunctionIamRole: - Description: "Implicit IAM Role created for SubmitRideCompletion function" - Value: !GetAtt SubmitRideCompletionFunctionRole.Arn - - RidesTable: - Description: "Amazon DynamoDB table ARN for Rides table" - Value: !Ref RidesTable - -# RideCompletionTopic: -# Description: "Amazon SNS topic ARN for rides completion topic" -# Value: !Ref RideCompletionTopic - - CustomerAccountingServiceLBURL: - Description: "Load balancer URL for customer accounting service" - Value: !Sub "http://${CustomerAccountingLoadBalancer.DNSName}" - - CustomerNotificationServiceLBURL: - Description: "Load balancer URL for customer notify service" - Value: !Sub "http://${CustomerNotifyLoadBalancer.DNSName}" - - ExtraordinaryRidesServiceLBURL: - Description: "Load balancer URL for extraordinary rides service" - Value: !Sub "http://${ExtraordinaryRidesLoadBalancer.DNSName}" \ No newline at end of file diff --git a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/bootstrap-initial-state.md b/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/bootstrap-initial-state.md deleted file mode 100644 index ffb191b..0000000 --- a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/bootstrap-initial-state.md +++ /dev/null @@ -1,61 +0,0 @@ -+++ -title = "Bootstrap the Initial State" -weight = 21 -pre = "1 " -+++ - -First, we will setup the initial state, including the integrating of the **Unicorn Management Service** (leveraging [Amazon API Gateway](https://aws.amazon.com/api-gateway/) and [AWS Lambda](https://aws.amazon.com/lambda/)), the **Rides Store** (leveraging [Amazon DynamoDB](https://aws.amazon.com/dynamodb/)) and three Serverless backend services - **Customer notification**, **Customer accounting**, and the **Extraordinary rides** service. - -![Step 1](step-1.png) - -#### 1. Browse to your AWS Cloud9 IDE - -Browse to your [AWS Cloud9 Console](https://console.aws.amazon.com/cloud9/home) and find the environment called **WildRydesAsyncMessaging**. Click the **Open IDE** button to navigate to your AWS Cloud9 IDE. - -{{%expand "Detailed description" %}} -![Step 2](step-2.png) -{{% /expand%}} - -#### 2. Build the lab artifacts from source - -We provide you with an [AWS SAM](https://aws.amazon.com/serverless/sam/) template which we will use to bootstrap the initial state. In the **bash tab** (at the bottom) in you AWS Cloud9 IDE, run the following commands to build the lab code: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-1 -sam build -{{< /highlight >}} - -{{%expand "Detailed description" %}} -![Step 4](step-4.png) -{{% /expand%}} - -#### 3. Deploy the application - -Now we are ready to deploy the application, by running the following command in the **lab-1** directory: - -{{< highlight bash >}} -export AWS_REGION=$(aws --profile default configure get region) -sam deploy \ - --stack-name wild-rydes-async-msg-1 \ - --capabilities CAPABILITY_IAM \ - --region $AWS_REGION \ - --guided -{{< /highlight >}} - -Confirm the first 4 proposed arguments by hitting **ENTER**. - -When you get asked **SubmitRideCompletionFunction may not have authorization defined, Is this okay? [y/N]:**, enter `y` and hit **ENTER** again 4 times. - -#### 4. Wait until the stack is successfully deployed - -It takes usually 4 minutes until the stack launched. You can monitor the progress of the **wild-rydes-async-msg-1** stack in the SAM CLI or in your [AWS CloudFormation Console](https://console.aws.amazon.com/cloudformation). When the stack is launched, the status will change from **CREATE_IN_PROGRESS** to **CREATE_COMPLETE**. - -{{%expand "Detailed description" %}} -![Step 7](step-7.png) -{{% /expand%}} - - -In the meantime while your waiting, you may want to have a look at the AWS SAM template to make yourself familiar with the stack we launched. Just click on the **template.yaml** attachment below to see the content. - - -{{%attachments title="Related files" pattern="/*.*(yaml)"/%}} diff --git a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-1.png b/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-1.png deleted file mode 100644 index b7804df..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-1.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-2.png b/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-2.png deleted file mode 100644 index f090b9e..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-2.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-3.png b/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-3.png deleted file mode 100644 index 50c016e..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-3.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-4.png b/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-4.png deleted file mode 100644 index ff02511..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-4.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-5.png b/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-5.png deleted file mode 100644 index 168e849..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-5.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-6.png b/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-6.png deleted file mode 100644 index 574c8c9..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-6.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-7.png b/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-7.png deleted file mode 100644 index b262957..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/bootstrap-initial-state/step-7.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/clean-up/clean-up-console.md b/workshop/content/fan-out-and-message-filtering/clean-up/clean-up-console.md deleted file mode 100644 index b20c0ee..0000000 --- a/workshop/content/fan-out-and-message-filtering/clean-up/clean-up-console.md +++ /dev/null @@ -1,25 +0,0 @@ -+++ -title = "Console" - -disableToc = true -hidden = true -+++ - -#### 3. Delete the Amazon S3 bucket - -In your **[Amazon S3 console](https://s3.console.aws.amazon.com/s3/home?#)**, filter for the **bucket** you have created to upload your code artifacts with AWS SAM, select the **bucket** and click the **Delete** button in the top. - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - - -#### 4. Delete the Amazon SNS topic - -In your **[Amazon SNS console](https://console.aws.amazon.com/sns/v3/home?#/topics)**, select **Topic** in the left navigation pane, select the **RideCompletionTopic** and click the **Delete** button in the top right corner. - -{{%expand "Detailed description" %}} -![Step 2](step-2-console.png) -{{% /expand%}} - -You are done! diff --git a/workshop/content/fan-out-and-message-filtering/clean-up/clean-up-sam.md b/workshop/content/fan-out-and-message-filtering/clean-up/clean-up-sam.md deleted file mode 100644 index c6ab588..0000000 --- a/workshop/content/fan-out-and-message-filtering/clean-up/clean-up-sam.md +++ /dev/null @@ -1,8 +0,0 @@ -+++ -title = "SAM" - -disableToc = true -hidden = true -+++ - - diff --git a/workshop/content/fan-out-and-message-filtering/clean-up/clean-up.md b/workshop/content/fan-out-and-message-filtering/clean-up/clean-up.md deleted file mode 100644 index 963f099..0000000 --- a/workshop/content/fan-out-and-message-filtering/clean-up/clean-up.md +++ /dev/null @@ -1,28 +0,0 @@ -+++ -title = "Clean up" -weight = 28 -pre = "8 " -+++ - -In this step, we will clean up all resources, we created during this lab, so that no further cost will occur. - -#### 1. Delete the previously created IAM Inline Policies - -In your Amazon IAM console, select **[Roles](https://console.aws.amazon.com/iamv2/home#/roles)** in the left navigation. In the search field, enter "async-msg". Open all matching roles and delete the previously created inline policies by clicking the "x" right to the policy name. - -#### 2. Delete the AWS SAM template - -In your Cloud9 IDE, run the following command to delete the resources we created with our AWS SAM template: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-1 -aws cloudformation delete-stack \ - --stack-name wild-rydes-async-msg-1 - -{{< /highlight >}} - - -#### 3. Delete the AWS Lambda created Amazon CloudWatch Log Group - -Follow **[this deep link](https://console.aws.amazon.com/cloudwatch/home?#logs:prefix=/aws/lambda/wild-rydes)** to list the **Amazon CloudWatch Log Groups** with the name `/aws/lambda/wild-rydes`, AWS Lambda created during this lab. Select the Amazon CloudWatch Log Group and choose **Delete log group** from the **Actions** menu. - diff --git a/workshop/content/fan-out-and-message-filtering/clean-up/step-1-console.png b/workshop/content/fan-out-and-message-filtering/clean-up/step-1-console.png deleted file mode 100644 index f04b02a..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/clean-up/step-1-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/clean-up/step-1.png b/workshop/content/fan-out-and-message-filtering/clean-up/step-1.png deleted file mode 100644 index d2690fa..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/clean-up/step-1.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/clean-up/step-2-console.png b/workshop/content/fan-out-and-message-filtering/clean-up/step-2-console.png deleted file mode 100644 index 49f409c..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/clean-up/step-2-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-console.md b/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-console.md deleted file mode 100644 index 0498144..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-console.md +++ /dev/null @@ -1,50 +0,0 @@ -+++ -title = "Console" -disableToc = true -hidden = true -+++ - -#### 1. Create a new subscription - -After selecting the topic **RideCompletionTopic**, click the **Create subscription** button in the bottom right corner. - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - -#### 2. Configure the subscription - - -In the next page, select **AWS Lambda** as the subscription protocol. In the **Endpoint** dropdown type **CustomerAccount**, and select the ARN of the Lambda function. - -To look-up the subscription endpoint, navigate back to your CloudFormation console, select the stack **wild-rydes-async-msg-1** and select the **Outputs** tab. Select the value, corresponding to the key **CustomerAccountingFunction**. It should look similar like `arn:aws:lambda...CustomerAccountingFunction-v7rZLcVBqIKT`. - -You can also look-up the value by running the following command: - -```bash -aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-1 \ - --query 'Stacks[].Outputs[?OutputKey==`CustomerAccountingFunction`].OutputValue' \ - --output text -``` - -Click **Create subscription** to create the subscription. - -{{%expand "Detailed description" %}} -![Step 2](step-2-console.png) -{{% /expand%}} - - -#### 3. Confirm the subscription - -Amazon SNS and AWS Lambda are integrated so the subscription is immediately established and the **Status** will change to **Confirmed**. There is nothing to do for you in this step. - -{{%expand "Detailed description" %}} -![Step 3](step-3-console.png) -{{% /expand%}} - -To validate that the trigger was created for the Lambda function, navigate to the [AWS Lambda console](https://console.aws.amazon.com/lambda/home?/functions). Open the **Customer Accounting function**. In the function overview you should see the SNS service icon. Click on the icon and make sure you have the **RideCompletionTopic** trigger listed. - -{{%expand "Detailed description" %}} -![Step 4](step-4-console.png) -{{% /expand%}} \ No newline at end of file diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-sam.md b/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-sam.md deleted file mode 100644 index b253f2c..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-sam.md +++ /dev/null @@ -1,43 +0,0 @@ -+++ -title = "SAM" -disableToc = true -hidden = true -+++ - -#### 1. Update the AWS SAM template - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-1/template.yaml`. In the **Resources** section, uncomment the Amazon SNS event source for the **CustomerAccountingFunction**. You can find the AWS SAM documentation to do so **[here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-sns.html)**. - -{{%expand "Cheat Sheet" %}} -```yaml -Events: - SNSEvent: - Type: SNS - Properties: - Topic: !Ref RideCompletionTopic -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 1](step-1-sam.png) -{{% /expand%}} - - -#### 2. Deploy the updated AWS SAM template - -Run the following command to build the lab again, after we have added the Amazon SNS subscription: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-1 -sam build -{{< /highlight >}} - -Now we are ready to update the application, by running the following command to deploy the change: - -{{< highlight bash >}} -sam deploy -{{< /highlight >}} - -**Note:** you do not need to provide the arguments for the deployment, because AWS SAM saved the parameter values in a configuration file called **samconfig.toml**. See the **[documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html)** more information on the AWS SAM CLI configuration file. - -Because AWS SAM will only deploy/update/delete resources which are changed, it only takes a couple of seconds to deploy the new Amazon SNS topic. diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription.md b/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription.md deleted file mode 100644 index 1588946..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription.md +++ /dev/null @@ -1,12 +0,0 @@ -+++ -title = "Create Customer Accounting Service Subscription" -weight = 24 -pre = "4 " -+++ - -Now we are ready to configure the subscription for the customer accounting service: - -{{< tabs name="Style" >}} -{{< tab name="Console" include="create-customer-accounting-service-subscription-console" />}} -{{< tab name="SAM" include="create-customer-accounting-service-subscription-sam" />}} -{{< /tabs >}} diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-1-console.png b/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-1-console.png deleted file mode 100644 index 151bbeb..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-1-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-1-sam.png b/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-1-sam.png deleted file mode 100644 index 1caba98..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-1-sam.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-2-console.png b/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-2-console.png deleted file mode 100644 index 0b27fdd..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-2-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-3-console.png b/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-3-console.png deleted file mode 100644 index 80c5dd6..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-3-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-4-console.png b/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-4-console.png deleted file mode 100644 index ff209d2..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-customer-accounting-service-subscription/step-4-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/create-customer-notification-service-subscription-console.md b/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/create-customer-notification-service-subscription-console.md deleted file mode 100644 index 1bd9d67..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/create-customer-notification-service-subscription-console.md +++ /dev/null @@ -1,48 +0,0 @@ -+++ -title = "Console" -disableToc = true -hidden = true -+++ - -#### 1. Create a new subscription - -After selecting the topic **RideCompletionTopic**, click the **Create subscription** button in the bottom right corner. - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - -#### 2. Configure the subscription - -In the next page, select **AWS Lambda** as the subscription protocol. In the **Endpoint** dropdown type **CustomerNotification**, and select the ARN of the Lambda function. - -To look-up the subscription endpoint, navigate back to your CloudFormation console, select the stack **wild-rydes-async-msg-1** and select the **Outputs** tab. Select the value, corresponding to the key **CustomerNotificationFunction**. It should look similar like `arn:aws:lambda...CustomerNotificationFunctio-qGy9SKt8mya6`. - -You can also look-up the value by running the following command: - -```bash -aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-1 \ - --query 'Stacks[].Outputs[?OutputKey==`CustomerNotificationFunction`].OutputValue' \ - --output text -``` - -Click **Create subscription** to create the subscription. - -{{%expand "Detailed description" %}} -![Step 2](step-2-console.png) -{{% /expand%}} - -#### 3. Confirm the subscription - -Amazon SNS and AWS Lambda are integrated so the subscription is immediately established and the **Status** will change to **Confirmed**. There is nothing to do for you in this step. - -{{%expand "Detailed description" %}} -![Step 3](step-3-console.png) -{{% /expand%}} - -To validate that the trigger was created for the Lambda function, navigate to the [AWS Lambda console](https://console.aws.amazon.com/lambda/home?/functions). Open the **Customer Notification function**. In the function overview you should see the SNS service icon. Click on the icon and make sure you have the **RideCompletionTopic** trigger listed. - -{{%expand "Detailed description" %}} -![Step 4](step-4-console.png) -{{% /expand%}} \ No newline at end of file diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/create-customer-notification-service-subscription-sam.md b/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/create-customer-notification-service-subscription-sam.md deleted file mode 100644 index 50b41ce..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/create-customer-notification-service-subscription-sam.md +++ /dev/null @@ -1,42 +0,0 @@ -+++ -title = "SAM" -disableToc = true -hidden = true -+++ - -#### 1. Update the AWS SAM template - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-1/template.yaml`. In the **Resources** section, uncomment the Amazon SNS event source for the **CustomerNotificationFunction**. You can find the AWS SAM documentation to do so **[here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/sam-property-function-sns.html)**. - -{{%expand "Cheat Sheet" %}} -```yaml -Events: - SNSEvent: - Type: SNS - Properties: - Topic: !Ref RideCompletionTopic -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 1](step-1-sam.png) -{{% /expand%}} - -#### 2. Deploy the updated AWS SAM template - -Run the following command to build the lab again, after we have added the Amazon SNS subscription: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-1 -sam build -{{< /highlight >}} - -Now we are ready to update the application, by running the following command to deploy the change: - -{{< highlight bash >}} -sam deploy -{{< /highlight >}} - -**Note:** you do not need to provide the arguments for the deployment, because AWS SAM saved the parameter values in a configuration file called **samconfig.toml**. See the **[documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html)** more information on the AWS SAM CLI configuration file. - -Because AWS SAM will only deploy/update/delete resources which are changed, it only takes a couple of seconds to deploy the new Amazon SNS topic. diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/create-customer-notification-service-subscription.md b/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/create-customer-notification-service-subscription.md deleted file mode 100644 index e93eec3..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/create-customer-notification-service-subscription.md +++ /dev/null @@ -1,12 +0,0 @@ -+++ -title = "Create Customer Notification Service Subscription" -weight = 23 -pre = "3 " -+++ - -Now we are ready to configure the subscription for the customer notification service: - -{{< tabs name="Style" >}} -{{< tab name="Console" include="create-customer-notification-service-subscription-console" />}} -{{< tab name="SAM" include="create-customer-notification-service-subscription-sam" />}} -{{< /tabs >}} diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-1-console.png b/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-1-console.png deleted file mode 100644 index b95c83d..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-1-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-1-sam.png b/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-1-sam.png deleted file mode 100644 index db94916..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-1-sam.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-2-console.png b/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-2-console.png deleted file mode 100644 index 5bf7a3e..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-2-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-3-console.png b/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-3-console.png deleted file mode 100644 index fb98eef..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-3-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-4-console.png b/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-4-console.png deleted file mode 100644 index f1aef40..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-customer-notification-service-subscription/step-4-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-console.md b/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-console.md deleted file mode 100644 index 602fb64..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-console.md +++ /dev/null @@ -1,65 +0,0 @@ -+++ -title = "Console" -disableToc = true -hidden = true -+++ - -#### 1. Create a new subscription - -After selecting the topic **RideCompletionTopic**, click the **Create subscription** button in the bottom right corner. - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - -#### 2. Configure the subscription - -In the next page, select **AWS Lambda** as the subscription protocol. In the **Endpoint** dropdown type **CustomerNotification**, and select the ARN of the Lambda function. - -To look-up the subscription endpoint, navigate back to your CloudFormation console, select the stack **wild-rydes-async-msg-1** and select the **Outputs** tab. Select the value, corresponding to the key **ExtraordinaryRidesFunction**. It should look similar like `arn:aws:lambda...ExtraordinaryRidesFunction-3DzmsnujRS2Q`. - -You can also look-up the value by running the following command: - -```bash -aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-1 \ - --query 'Stacks[].Outputs[?OutputKey==`ExtraordinaryRidesFunction`].OutputValue' \ - --output text -``` - -{{% notice tip %}} -Don't overlook to create the subscription filter policy! -{{% /notice %}} - -Expand the section **Subscription filter policy** to create the subscription filter policy to receive notifications only, if the `fare >= 50` and the `distance >= 20`. If you are not familiar with the syntax, you can study it [here](https://docs.aws.amazon.com/sns/latest/dg/sns-subscription-filter-policies.html) - or fall-back to the cheat sheet below. - -{{%expand "cheat sheet" %}} -``` -{ - "fare": [{"numeric": [">=", 50]}], - "distance": [{"numeric": [">=", 20]}] -} -``` -{{% /expand%}} - -Click **Create subscription** to create the subscription. - -{{%expand "Detailed description" %}} -![Step 2](step-2-console.png) -{{% /expand%}} - - -#### 3. Confirm the subscription - -**Amazon SNS** require a confirmation of a subscription, before it publishes messages to that endpoint, as described **[here](https://docs.aws.amazon.com/sns/latest/dg/sns-http-https-endpoint-as-subscriber.html#SendMessageToHttp.confirm)**. -Our provided Customer Notification Service handles this automatically for us. The **Status** will change to **Confirmed** immediately (may refresh the page a couple of times). There is nothing to do for you in this step. - -{{%expand "Detailed description" %}} -![Step 3](step-3-console.png) -{{% /expand%}} - -To validate that the trigger was created for the Lambda function, navigate to the [AWS Lambda console](https://console.aws.amazon.com/lambda/home?/functions). Open the **Extraordinary Rides function**. In the function overview you should see the SNS service icon. Click on the icon and make sure you have the **RideCompletionTopic** trigger listed. - -{{%expand "Detailed description" %}} -![Step 4](step-4-console.png) -{{% /expand%}} \ No newline at end of file diff --git a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-sam.md b/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-sam.md deleted file mode 100644 index 7b1220b..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-sam.md +++ /dev/null @@ -1,56 +0,0 @@ -+++ -title = "SAM" -disableToc = true -hidden = true -+++ - -#### 1. Update the AWS SAM template - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-1/template.yaml`. In the **Resources** section, add the definition for the Amazon SNS subscription for the **ExtraordinaryRidesService**. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sns-subscription.html)**. - -{{% notice tip %}} -Don't overlook to create the subscription filter policy! -{{% /notice %}} - -{{%expand "Cheat Sheet" %}} -```yaml -Events: - SNSEvent: - Type: SNS - Properties: - Topic: !Ref RideCompletionTopic - FilterPolicy: - fare: - - numeric: - - '>=' - - 50 - distance: - - numeric: - - '>=' - - 20 -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 1](step-1-sam.png) -{{% /expand%}} - - -#### 2. Deploy the updated AWS SAM template - -Run the following command to build the lab again, after we have added the Amazon SNS subscription: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-1 -sam build -{{< /highlight >}} - -Now we are ready to update the application, by running the following command to deploy the change: - -{{< highlight bash >}} -sam deploy -{{< /highlight >}} - -**Note:** you do not need to provide the arguments for the deployment, because AWS SAM saved the parameter values in a configuration file called **samconfig.toml**. See the **[documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html)** more information on the AWS SAM CLI configuration file. - -Because AWS SAM will only deploy/update/delete resources which are changed, it only takes a couple of seconds to deploy the new Amazon SNS topic. \ No newline at end of file diff --git a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription.md b/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription.md deleted file mode 100644 index edd5d7b..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription.md +++ /dev/null @@ -1,13 +0,0 @@ -+++ -title = "Create Extraordinary Rides Service Subscription" -weight = 25 -pre = "5 " -+++ - -Now we are ready to configure the subscription for the extraordinary rides service: - -{{< tabs name="Style" >}} -{{< tab name="Console" include="create-extraordinary-rides-service-subscription-console" />}} -{{< tab name="SAM" include="create-extraordinary-rides-service-subscription-sam" />}} -{{< /tabs >}} - diff --git a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-1-console.png b/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-1-console.png deleted file mode 100644 index 5ab6789..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-1-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-1-sam.png b/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-1-sam.png deleted file mode 100644 index 1e69644..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-1-sam.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-2-console.png b/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-2-console.png deleted file mode 100644 index 87a1e58..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-2-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-3-console.png b/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-3-console.png deleted file mode 100644 index 1ff74b5..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-3-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-4-console.png b/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-4-console.png deleted file mode 100644 index cdbb38c..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-extraordinary-rides-service-subscription/step-4-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-sns-topic/create-sns-topic-console.md b/workshop/content/fan-out-and-message-filtering/create-sns-topic/create-sns-topic-console.md deleted file mode 100644 index 3f7cb8a..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-sns-topic/create-sns-topic-console.md +++ /dev/null @@ -1,23 +0,0 @@ -+++ -title = "Console" - -disableToc = true -hidden = true -+++ - -#### 1. Browse to the Amazon SNS console - -In your [Amazon SNS console](https://console.aws.amazon.com/sns/v3/home?#/topics), select **Topic** in the left navigation pane and click the **Create topic** button in the top right corner. - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - - -#### 2. Create the Ride Completion Topic - -Enter the topic name **RideCompletionTopic** and leave the default values. Scroll to the bottom of the page and click **Create topic**. - -{{%expand "Detailed description" %}} -![Step 2](step-2-console.png) -{{% /expand%}} diff --git a/workshop/content/fan-out-and-message-filtering/create-sns-topic/create-sns-topic-sam.md b/workshop/content/fan-out-and-message-filtering/create-sns-topic/create-sns-topic-sam.md deleted file mode 100644 index 416a357..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-sns-topic/create-sns-topic-sam.md +++ /dev/null @@ -1,44 +0,0 @@ -+++ -title = "SAM" - -disableToc = true -hidden = true -+++ - -#### 1. Update the AWS SAM template - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-1/template.yaml`. In the **Resources** section, add the definition for an Amazon SNS topic with the name RideCompletionTopic. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html)**. - -{{%expand "Cheat Sheet" %}} -``` - RideCompletionTopic: - Type: AWS::SNS::Topic - Properties: - TopicName: RideCompletionTopic -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 1](step-1-sam.png) -{{% /expand%}} - - -#### 2. Deploy the updated AWS SAM template - -Run the following command to build the lab again, after we have added the Amazon SNS topic: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-1 -sam build - -{{< /highlight >}} - -Now we are ready to update the application, by running the following command to deploy the change: - -{{< highlight bash >}} -sam deploy -{{< /highlight >}} - -**Note:** you do not need to provide the arguments for the deployment, because AWS SAM saved the parameter values in a configuration file called **samconfig.toml**. See the **[documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html)** more information on the AWS SAM CLI configuration file. - -Because AWS SAM will only deploy/update/delete resources which are changed, it only takes a couple of seconds to deploy the new Amazon SNS topic. diff --git a/workshop/content/fan-out-and-message-filtering/create-sns-topic/create-sns-topic.md b/workshop/content/fan-out-and-message-filtering/create-sns-topic/create-sns-topic.md deleted file mode 100644 index 65fb9ff..0000000 --- a/workshop/content/fan-out-and-message-filtering/create-sns-topic/create-sns-topic.md +++ /dev/null @@ -1,16 +0,0 @@ -+++ -title = "Create the Amazon SNS topic" -weight = 22 -pre = "2 " -+++ - -In this step, you can chose whether you want to create the Amazon SNS topic via the AWS console or AWS SAM. Just select the corresponding tab below and follow the instructions: - -{{% notice info %}} -You can chose, whether you would like to use the **[AWS Console](https://console.aws.amazon.com) or [AWS SAM](https://aws.amazon.com/serverless/sam/)** for this lab. Once you have chosen, **stick to it until the end** of this lab and don't switch in between! -{{% /notice %}} - -{{< tabs name="Style" >}} -{{< tab name="Console" include="create-sns-topic-console" />}} -{{< tab name="SAM" include="create-sns-topic-sam" />}} -{{< /tabs >}} diff --git a/workshop/content/fan-out-and-message-filtering/create-sns-topic/step-1-console.png b/workshop/content/fan-out-and-message-filtering/create-sns-topic/step-1-console.png deleted file mode 100644 index 039b0c6..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-sns-topic/step-1-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-sns-topic/step-1-sam.png b/workshop/content/fan-out-and-message-filtering/create-sns-topic/step-1-sam.png deleted file mode 100644 index 1979b40..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-sns-topic/step-1-sam.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/create-sns-topic/step-2-console.png b/workshop/content/fan-out-and-message-filtering/create-sns-topic/step-2-console.png deleted file mode 100644 index 895ce21..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/create-sns-topic/step-2-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/module-1.png b/workshop/content/fan-out-and-message-filtering/module-1.png deleted file mode 100644 index b7804df..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/module-1.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/step-1.png b/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/step-1.png deleted file mode 100644 index 6d7fea6..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/step-1.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/step-2.png b/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/step-2.png deleted file mode 100644 index 750438f..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/step-2.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/step-3.png b/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/step-3.png deleted file mode 100644 index 6071836..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/step-3.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/test-fan-out-and-message-filtering.md b/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/test-fan-out-and-message-filtering.md deleted file mode 100644 index d6006f3..0000000 --- a/workshop/content/fan-out-and-message-filtering/test-fan-out-and-message-filtering/test-fan-out-and-message-filtering.md +++ /dev/null @@ -1,56 +0,0 @@ -+++ -title = "Test Fan-Out and Message Filtering" - -weight = 27 -pre = "7 " -+++ - -In this step, we will validate that the Amazon SNS topic is publishing all messages to all subscribers. Because a subscriber can also fail processing a message, we also want to validate that Amazon SNS is redelivering the message, so that we will not miss a single message. - -#### 1. Look up the API Gateway endpoint - -To look-up the API Gateway endpoint URL for the submit-ride-completion function, run the following command: - -```bash -aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-1 \ - --query 'Stacks[].Outputs[?OutputKey==`UnicornManagementServiceApiSubmitRideCompletionEndpoint`].OutputValue' \ - --output text -``` - - -#### 2. Send a couple requests to the Unicorn Management Service - -Let's store this API Gateway endpoint URL in an environment variable, so we don't have to repeat it all the time: - -```bash -export ENDPOINT=$(aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-1 \ - --query 'Stacks[].Outputs[?OutputKey==`UnicornManagementServiceApiSubmitRideCompletionEndpoint`].OutputValue' \ - --output text) -``` - -To send a couple requests to the **submit ride completion endpoint**, execute the command below 5 or more times and change the request payload to test the filter criteria for the **Extraordinary Rides Service**: - -```bash -curl -XPOST -i -H "Content-Type:application/json" -d '{ "from": "Berlin", "to": "Frankfurt", "duration": 420, "distance": 600, "customer": "cmr", "fare": 256.50 }' $ENDPOINT -``` - -{{%expand "Detailed description" %}} -![Step 1](step-1.png) -{{% /expand%}} - - -#### 3. Validate the message reception - -Go to your [Amazon CloudWatch Log console](https://console.aws.amazon.com/cloudwatch/home?#logsV2:log-groups) and your **Log Groups** beginning with `/aws/lambda/wild-rydes-async-msg-1-`. Select a Log Group to see all **Log Streams** available for that Log Group. - -{{%expand "Detailed description" %}} -![Step 2](step-2.png) -{{% /expand%}} - -Browse each Log Stream to validate, that each of our 3 backend service could successfully process the message. You should also see some random log entries, indicating a failed message processing. Shortly after, you should see the message redelivery from Amazon SNS and the successful message processing log entry. - -{{%expand "Detailed description" %}} -![Step 3](step-3.png) -{{% /expand%}} diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-1-console.png b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-1-console.png deleted file mode 100644 index 0756e5a..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-1-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-1-sam.png b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-1-sam.png deleted file mode 100644 index 107f6c4..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-1-sam.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-1.png b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-1.png deleted file mode 100644 index b7804df..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-1.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-2-console.png b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-2-console.png deleted file mode 100644 index 3ab02d7..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-2-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-2-sam.png b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-2-sam.png deleted file mode 100644 index cc82149..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-2-sam.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-3-console.png b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-3-console.png deleted file mode 100644 index 5008e7f..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-3-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-3-sam.png b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-3-sam.png deleted file mode 100644 index 8e85dbb..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-3-sam.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-4-console.png b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-4-console.png deleted file mode 100644 index e9260d1..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-4-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-5-console.png b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-5-console.png deleted file mode 100644 index 10bb1ca..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-5-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-6-console.png b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-6-console.png deleted file mode 100644 index ad5b5e8..0000000 Binary files a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/step-6-console.png and /dev/null differ diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/update-unicorn-management-service-console.md b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/update-unicorn-management-service-console.md deleted file mode 100644 index 422ff3a..0000000 --- a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/update-unicorn-management-service-console.md +++ /dev/null @@ -1,98 +0,0 @@ -+++ -title = "Console" - -disableToc = true -hidden = true -+++ - -#### 1. Grant additional IAM permissions to Lambda - -In your **[Amazon IAM console](https://console.aws.amazon.com/iam)**, select **Roles** in the left navigation. Use the filter text box to find the role with the name **wild-rydes-async-msg-1-SubmitRideCompletionFunctio-...** (assuming your have chosen `wild-rydes-async-msg-1` as your stack name). - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - -Click on the role name and click **Add inline policy** to attach another one. - -{{%expand "Detailed description" %}} -![Step 2](step-2-console.png) -{{% /expand%}} - -Select the **JSON** tab and passed the following policy statement into it, after you have substitute <<...>> with the correct values. It will add the permission to your Lambda function to publish messages to this particular Amazon SNS topic: - -{{%expand "policy" %}} -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Action": [ - "sns:Publish" - ], - "Resource": "arn:aws:sns:<>:<>:<>", - "Effect": "Allow" - } - ] -} -``` -{{% /expand%}} - -{{% notice tip %}} -Make sure you provide the AWS ACCOUNT ID in the form of XXXXXXXXXXXX and not XXXX-XXXX-XXXX! -{{% /notice %}} - -Click **Review policy** and enter the **Name** `SubmitRideCompletionFunctionRolePolicy1`. Click **Create policy**. To validate this step, select on the role again and your should see 3 policies attached to your role, including the one you just have created: - -{{%expand "Detailed description" %}} -![Step 3](step-3-console.png) -{{% /expand%}} - -#### 2. Provide the Amazon SNS topic ARN to Lambda - -In your **[AWS Lambda console](https://console.aws.amazon.com/lambda/home?#/functions)**, select **Functions** in the left navigation. Use the filter text box to find the function with the name **wild-rydes-async-msg-1-SubmitRideCompletionFunctio-...** (assuming your have chosen `wild-rydes-async-msg-1` as your stack name). - -{{%expand "Detailed description" %}} -![Step 4](step-4-console.png) -{{% /expand%}} - -Click on the function name and scroll down to the section **Environment variables**. Our Lambda function expects an environment variable with the **Name** `TOPIC_ARN`. It uses this Amazon SNS topic to publish all messages to. Lookup your Amazon SNS topic name in the [Amazon SNS console](https://console.aws.amazon.com/sns) and add this variable. Click the **Save** button in the top right corner to save the change. - -{{%expand "Detailed description" %}} -![Step 5](step-5-console.png) -{{% /expand%}} - -#### 3. Update your Lambda function to call Amazon SNS - -Open your **[AWS Lambda console](https://console.aws.amazon.com/lambda/home?#/functions)** and select **Functions** in the left navigation. Select the function with the name **wild-rydes-async-msg-1-SubmitRideCompletionFunctio-...** (assuming your have chosen `wild-rydes-async-msg-1` as your stack name). Scroll a bit down to the section **Function code**. Add the definition of the sns client directly after the dynamodb client: - -{{%expand "Cheat Sheet" %}} -```Python -sns = boto3.client('sns', config=config) -``` -{{% /expand%}} - -After the put item DynamoDB statement and before we are sending the response back to the caller, add the code to publish a message to Amazon SNS: - -{{%expand "Cheat Sheet" %}} -```Python - response = sns.publish( - TopicArn=TOPIC_ARN, - Message=json.dumps(request), - MessageAttributes = { - 'fare': { - 'DataType': 'Number', - 'StringValue': str(request['fare']) - }, - 'distance': { - 'DataType': 'Number', - 'StringValue': str(request['distance']) - } - } - ) -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 6](step-6-console.png) -{{% /expand%}} diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/update-unicorn-management-service-sam.md b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/update-unicorn-management-service-sam.md deleted file mode 100644 index 942b4cd..0000000 --- a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/update-unicorn-management-service-sam.md +++ /dev/null @@ -1,97 +0,0 @@ -+++ -title = "SAM" - -disableToc = true -hidden = true -+++ - -#### 1. Grant additional IAM permissions to Lambda - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-1/template.yaml`. In the **Resources** section, look for the **SubmitRideCompletionFunction** definition. It already contains one policies entry called **DynamoDBCrudPolicy**. Directly below, add a policy entry which grants Amazon SNS publish message permission. You can look up the supported policies **[here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-templates.html)**. - -{{%expand "Cheat Sheet" %}} - -```yaml -- SNSPublishMessagePolicy: - TopicName: !GetAtt RideCompletionTopic.TopicName -``` - -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 1](step-1-sam.png) -{{% /expand%}} - - -#### 2. Provide the Amazon SNS topic ARN to Lambda - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-1/template.yaml`. In the **Resources** section, look for the **SubmitRideCompletionFunction** definition. It already contains one environment variables entry called **TABLE_NAME**. Directly below, add an additional variable with the key **TOPIC_ARN** and the corresponding value. - -{{%expand "Cheat Sheet" %}} - -```yaml -TOPIC_ARN: !Ref RideCompletionTopic -``` - -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 2](step-2-sam.png) -{{% /expand%}} - - -#### 3. Update your Lambda function to call Amazon SNS - -In your Cloud9 IDE, open the Python based AWS Lambda function `wild-rydes-async-messaging/lab-1/unicorn-management-service/app.py`. -Add the definition of the sns client directly after the dynamodb client: - -{{%expand "Cheat Sheet" %}} -```Python -sns = boto3.client('sns', config=config) -``` -{{% /expand%}} - -After the put item DynamoDB statement and before we are sending the response back to the caller, add the code to publish a message to Amazon SNS: - -{{%expand "Cheat Sheet" %}} -```Python - response = sns.publish( - TopicArn=TOPIC_ARN, - Message=json.dumps(request), - MessageAttributes = { - 'fare': { - 'DataType': 'Number', - 'StringValue': str(request['fare']) - }, - 'distance': { - 'DataType': 'Number', - 'StringValue': str(request['distance']) - } - } - ) -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 3](step-3-sam.png) -{{% /expand%}} - - -#### 4. Deploy the updated AWS SAM template - -Run the following command to build the lab again, after we have added the additional policy: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-1 -sam build -{{< /highlight >}} - -Now we are ready to update the application, by running the following command to deploy the change: - -{{< highlight bash >}} -sam deploy -{{< /highlight >}} - -**Note:** you do not need to provide the arguments for the deployment, because AWS SAM saved the parameter values in a configuration file called **samconfig.toml**. See the **[documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html)** more information on the AWS SAM CLI configuration file. - -Because AWS SAM will only deploy/update/delete resources which are changed, it only takes a couple of seconds to deploy the new Amazon SNS topic. diff --git a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/update-unicorn-management-service.md b/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/update-unicorn-management-service.md deleted file mode 100644 index a844e03..0000000 --- a/workshop/content/fan-out-and-message-filtering/update-unicorn-management-service/update-unicorn-management-service.md +++ /dev/null @@ -1,17 +0,0 @@ -+++ -title = "Update Unicorn Management Service" - -weight = 26 -pre = "6 " -+++ - -After creating the Amazon SNS topic and all the subscriptions, the current architecture looks like the following on: - -![Step 1](step-1.png) - -The last missing part to complete the architecture is calling our **Amazon SNS topic** from our **Unicorn Management Service**. - -{{< tabs name="Style" >}} -{{< tab name="Console" include="update-unicorn-management-service-console" />}} -{{< tab name="SAM" include="update-unicorn-management-service-sam" />}} -{{< /tabs >}} diff --git a/workshop/content/orchestration-and-coordination/_index.md b/workshop/content/orchestration-and-coordination/_index.md deleted file mode 100644 index b59c513..0000000 --- a/workshop/content/orchestration-and-coordination/_index.md +++ /dev/null @@ -1,61 +0,0 @@ -+++ -title = "Orchestration and Coordination" -weight = 50 -pre = "Lab-4: " -+++ - -{{% notice info %}} -Make sure you executed the **[Workshop Prerequisites](/prerequisites.html)** first, before you start with this lab! -{{% /notice %}} - -AWS Step Functions is a fully managed Serverless workflow management service for managing long running processes and coordinating the components of distributed applications and microservices using visual workflows. But did you know it can also help you deal with the complexities of dealing with a long lived transaction across distributed components in your microservices architecture? - -In this Builder session, you will learn how AWS Step Functions can help us to implement the Saga design pattern. - -## What problems are we trying to solve - -When building cloud-based distributed architectures, one of the questions we need to ask ourselves is how do we maintain data consistency across microservices that have their own database / persistence mechanism? We do not have support for Distributed Transaction Coordinators (DTC) or two-phase commit protocols responsible for coordinating transactions across multiple cloud resources. We need a mechanism coordinate multiple local transactions. - -## The Saga Pattern - -A Saga is a design pattern for dealing with “long-lived transactions” (LLT), published by Garcia-Molina and Salem in 1987. Their original paper can be found here [https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf](https://www.cs.cornell.edu/andru/cs711/2002fa/reading/sagas.pdf). - - > “LLT is a saga if it can be written as a sequence of transactions that can be interleaved with other transactions.” (Garcia-Molina, Salem 1987) - -Fundamentally the Saga Pattern is a failure management pattern that provides a mechansim for providing semantic consistency in our distributed applications by providing compensating transactions for every transaction where you have more than one collaborating services or functions. This compensating transactions ensures the system remains in a consistent state by rolling back or compensating for partially completed transactions. - -## Why AWS Step Functions - -AWS Step Functions provide us with a mechanism for dealing with long-lived transactions, by providing us with the ability to build fully managed state machines that: - -* coordinate the components of distributed applications and microservices -* allowing us to build our state machines using visual workflows -* provides us with a way to manage state and deal with failure - -## Lab Objectives - -The core objective for this lab is to **build a state machine** that implements a Saga for the Wild Rydes Fare Collection process. - -![Module 4](orchestration-and-coordination/module-4.png) - -The process consists of three discrete transactions that need to be treated as a single, distributed transaction. - -1. **Register Fare**: register the fare in a DynamoDB table. -1. **Payment Service**: calls a payment gateway for credit card pre-authorisation, and using the pre-authorisation code, completes the payment transaction -1. **Customer Accounting Service**: once the payment has been processed, update the Wild Rydes Customer accounting system with the transaction details. - -In this lab, you will acquire the following skills: - -+ **How to create a Step Functions State Machine** -+ **How to use the Step Functions Workflow Studio** -+ **How to catch exceptions and manage retries in a Step Functions State Machine** -+ **How to manage successful and non-successful execution flows in a Step Functions State machine** - - -Let's get started! - - -{{% notice tip %}} -**Lab source code** -If you are curious and would like to dive into the lab's source code, you are more than welcome to do so. You will find the source code of this lab in our Github repo **[here](https://github.com/aws-samples/asynchronous-messaging-workshop/tree/master/code/lab-4)**. -{{% /notice %}} diff --git a/workshop/content/orchestration-and-coordination/add-exception-handling/add-exception-handling.md b/workshop/content/orchestration-and-coordination/add-exception-handling/add-exception-handling.md deleted file mode 100644 index f282ec6..0000000 --- a/workshop/content/orchestration-and-coordination/add-exception-handling/add-exception-handling.md +++ /dev/null @@ -1,197 +0,0 @@ -+++ -title = "Add Exception Handling" -weight = 53 -pre = "4 " -+++ - -#### 1. Error Handling - -In the last section, we added the transactions required to register and charge a fare and credit a customer account. But what if a problem occurs with any of these transactions? - -Remember that we need to leave the state of the system in a semantically correct state at each stage of the workflow. We wouldn't want to charge a fare via a payment system only for something to go wrong and then incorrectly credit a customer account. Similarly, we wouldn't want to mark a fare as completed without successfully taking payment. Our Unicorns might be magic but our profits are not! - -In this section, we will add logic to catch potential failures at each state in the workflow. This will enable us to rollback the transactions in order to leave the state of the system in a semantically correct state. We will also add termination states for both successful and unsuccessful State machine executions and an additional notification for unsuccessful completions. - -#### 1. Step Functions Error Handling - -Any state in a Step Functions state machine can encounter an error and errors can happen for a variety of reasons: - -* State machine definition issues (e.g. no matching rule in a Choice state) -* Task failures (e.g. an exception in a Lambda function) -* Transient issues (e.g. transient throttling or network issues) - -**By default, when a state reports an error, AWS Step Functions will fail the execution entirely.** - -However in addition to this default error behaviour, the **Task, Map and Parallel** states in a Step Functions State machine allow errors to be caught using the **Catch** field (also referred to as a **Catcher**). This enables conditional logic based on the error and in turn enables customisable error handling within a Step Functions state machine. - -The Catch field enables all or specific errors to be caught by specifying error names in the **errors** field. Error names can be custom errors raised by Lambda functions or errors defined by a particular AWS service. Step Functions provides a number of [default error names](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-error-handling.html#error-handling-error-representation) -, a selection of which are: - -* States.ALL - Acts as a catch all and matches any known error name. -* States.Timeout - Thrown when a Task state runs for longer than the **TimeoutSeconds** value or failed to send a heartbeat for a period longer than the **HeartbeatSeconds** value. -* States.TaskFailed - Acts as a wildcard for any error other than **States.Timeout**. - -In the event an error is caught, a **fallback state** is defined as part of a **Catcher** which determines the next state to transition to, together with a **ResultPath** that enables the error to be appended to the original input to in turn allow down stream systems and processes to take appropriate action. - -{{% notice tip %}} -We use a **Catcher** and add the error name to the **ResultPath** in this lab to send an error SNS failure notification with the details of the specific error that occurred. -{{% /notice %}} - -#### 2. RegisterFare Exception Handling & Failure Notification - -Let's start by adding some error handling to our first state: **RegisterFare**. - -This is a relatively simple state that adds a new Fare item to our DynamoDB table using Step Functions direct integration with DynamoDB. - -Click on the **RegisterFare** state in the graph and select the **Error Handling** table from the **Form** view. Click **Add new catcher**. - -For this state, our behavior is not going to vary by error, we will simply send a failure notification in each case, so let's catch all possible exceptions. We can do this by specifying the **States.ALL** error name in the **Errors** text box. Add **$.registerError** to the **ResultPath** field for the catcher. - -For the **Fallback state** option, choose **Add new state**. This creates an empty state that our catcher will transition to in the event of a failure. In the **Actions** menu in the left-hand pane, select **Amazon SNS Publish** from either the **Most Popular** or **Application Integration** category and drag onto the empty state. - -Set the parameters for the **SNS Publish** state as follows (leave the others with default values): - -* **State Name**: NotifyFailure -* **Topic**: Search for the bootstrapped SNS topic containing the string **FareProcessing**. Copy the Topic ARN and keep to hand. - -Click on **Edit as JSON** under **API Parameters** and copy the following JSON replacing **arn placeholder** with the topic ARN you copied previously: - -{{< highlight json >}} -{ - "Message.$": "$", - "TopicArn": "<>", - "MessageAttributes": { - "IsSuccessful": { - "DataType": "String", - "StringValue": "false" - } - } -}{{< /highlight >}} - - -In the **Output** tab, ensure the **Add original input to output using ResultPath** is ticked and has the following values: - -* Combine original input with result -* $.snsResult - -You should now have two execution flows within your State Machine, the original successful path and an additional path that is followed in the event of a failure when Registering a Fare that leads to an SNS Failure Notification. - -{{%expand "Detailed description" %}} -![Step 2](lab-4-register-fare-catcher.png) -{{% /expand%}} - -{{% notice note %}} -Before you move on to the next step, can you predict a potential issue with the State machine and the two execution flows as it stands? -{{% /notice %}} - -#### 3. Managing Execution State - -Whilst we send SNS notifications to distinguish whether our State machine completed successfully or failed, the Step Functions **execution status** will return successful for both a successful execution and for executions where an error at the **RegisterFare** state is caught (remember we are catching *all* errors). This is undesirable as we may want to track successful vs unsuccessful executions and we may also want to use the State machine execution status to determine follow on actions. - -Let's add a **Succeed and Fail state** to the end of each flow to appropriately denote the execution status. - -In the **Flow** menu in the left-hand pane, drag the **Success** Flow state in between the **NotifySuccess** and **End** states. Set the **StateName** to **FareProcessingSucceeded**. - -Repeat the process for the **Fail** Flow state and drag in between **NotifyFailure** and **End**. Set the **StateName** to **FareProcessingFailed**. - -{{% notice tip %}} -The Success and Fail states are also useful for terminating a flow of execution early, perhaps as part of a **Choice** state branch where no further processing is necessary. -{{% /notice %}} - - -{{%expand "Detailed description" %}} -![Step 3](lab-4-execution-states.png) -{{% /expand%}} - -#### 4. ChargeFare Exception Handling - -Next, let's add a **Catcher** to the **ChargeFare** state. - -It is important to understand the errors that can potentially occur in your Lambda Function when defining a catcher. -For AWS Lambda, there are [two types of error](https://docs.aws.amazon.com/lambda/latest/dg/invocation-retries.html) that can occur: **Invocation errors** and **Function errors**. - -* Invocation errors occur when an invocation request is rejected before your Function receives it. This might occur because of a concurrency limit being reached, lack of permissions, or a malformed request event. - -* Function errors are further sub divided into those that your function code throws and those that can occur at the runtime level. Runtime errors are thrown by the Lambda Service and can occur when your function exceeds the configured timeout, detects a syntax error, fails to marshall a JSON response and so on. - -To determine the Function errors for **ChargeFare** we will look at the underlying Lambda function code. The easiest method is to examine the **ChargeFare** Lambda Function code directly through the Lambda console. Click on the **ChargeFare** state and then **View Function** in the **Configuration** tab. - -Notice in the **PaymentChargeFunction** code that underpins our **ChargeFare** state that we define two exceptions at the top: -* PaymentAuthException - thrown when payment cannot be authorised. -* PaymentChargeException - thrown when the payment cannot be charged. - -We will add a catcher to catch both of these exceptions. Back in the **Step Functions Workflow Studio**, Select the **ChargeFare** state and navigate to the **Error Handling** table and click **Add new Catcher**. Add the following values (add each error as a separate value excluding the commas): - -* **Errors**: PaymentAuthException, PaymentChargeException -* **ResultPath**: $.chargeError - -For the **Fallback State**, let's take the opportunity to leave our system in a semantically correct state and rather than just sending a failure notification, we will add a new state to set the Fare status to failed. Select **Add new state** as the target for our new catcher and drag a **DynamoDB UpdateItem** action onto the new empty state. - -For the new **DynamoDB UpdateItem** action, add the following values: - -* **StateName**: SetFareStatusFailed -* **API Parameters**: - {{< highlight json >}} -{ - "TableName": "FaresTable-wild-rydes-async-msg-4", - "Key": { - "fareId": { - "S.$": "$.fareId" - } - }, - "UpdateExpression": "SET fareStatus = :s", - "ExpressionAttributeValues": { - ":s": { - "S": "failed" - } - } -}{{< /highlight >}} -* **NextState**: **NotifyFailure** - -In the **Output** tab for the new **DynamoDB UpdateItem** action, ensure the **Add original input to output using ResultPath** is ticked and has the following values: - -* Combine original input with result -* $.dynamodbResult - -You should now have a catcher defined for **ChargeFare** which falls back to the newly added **SetFareStatusFailed** state. Refer to the Detailed Description to verify your state machine. - -{{%expand "Detailed description" %}} -![Step 4a](lab-4-chargefare-catcher.png) -![Step 4b](lab-4-set-fare-to-failed.png) -{{% /expand%}} - -#### 5. CreditCustomerAccount Exception Handling - -Next let's add exception handling to the **CreditCustomerAccount** state. - -Take an opportunity to again look at the Lambda function code underpinning this state and the exceptions thrown by this code. You will notice that a single exception is thrown: **AccountCreditException**. - -In the **Step Functions Workflow Studio**, select the **CreditCustomerAccount** state and click on the **Error Handling** tab. Click **Add new catcher** and add the following values: - -* **Errors**: AccountCreditException -* **Fallback state**: SetFareStatusFailed -* **ResultPath**: $.creditError - -{{%expand "Detailed description" %}} -![Step 4a](lab-4-credit-customer-account-catcher.png) -{{% /expand%}} - -#### 6. Refund Customer Account - -After the last step, we are catching the **AccountCreditException** and then setting the fare status to failed followed by a failure notification. However, we have not dealt with the fact that we have charged the customer for the fare prior to this state and therefore in this exceptional execution case, we have potentially left our system in an inconsistent state. - -To resolve this, we need to rollback the ChargeFare transaction and we will do this by refunding the customer in the event of a **AccountCreditException**. - -In the **Step Functions Workflow Studio**, drag the **AWS Lambda Invoke** Action onto the State machine graph inbetween **CreditCustomerAccount** and **SetFareStatusFailed** over the top of the **Catch #1** label. Add the following values: - -* **StateName**: RefundFare -* **Function Name**: Search for **PaymentRefundFunction** -* **Next State**: SetFareStatusFailed (should be implicitly set) - -{{%expand "Detailed description" %}} -![Step 4a](lab-4-refund-fare.png) -{{% /expand%}} - -#### 7. Exception Handling Complete - -This completes this step in the lab. We have added exception handling, ensuring transactions are rolled back, notifications are sent and the status of the State machine execution matches the notification and fare status. Good work! diff --git a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-chargefare-catcher.png b/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-chargefare-catcher.png deleted file mode 100644 index 6cc377d..0000000 Binary files a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-chargefare-catcher.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-credit-customer-account-catcher.png b/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-credit-customer-account-catcher.png deleted file mode 100644 index b634672..0000000 Binary files a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-credit-customer-account-catcher.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-execution-states.png b/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-execution-states.png deleted file mode 100644 index 99aa002..0000000 Binary files a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-execution-states.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-refund-fare.png b/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-refund-fare.png deleted file mode 100644 index cdf880d..0000000 Binary files a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-refund-fare.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-register-fare-catcher.png b/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-register-fare-catcher.png deleted file mode 100644 index 7b90fb0..0000000 Binary files a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-register-fare-catcher.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-set-fare-to-failed.png b/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-set-fare-to-failed.png deleted file mode 100644 index 382a290..0000000 Binary files a/workshop/content/orchestration-and-coordination/add-exception-handling/lab-4-set-fare-to-failed.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/add-retrying/add-retrying.md b/workshop/content/orchestration-and-coordination/add-retrying/add-retrying.md deleted file mode 100644 index 9879e2b..0000000 --- a/workshop/content/orchestration-and-coordination/add-retrying/add-retrying.md +++ /dev/null @@ -1,40 +0,0 @@ -+++ -title = "Add Retrying" -weight = 54 -pre = "5 " -+++ - -#### 1. Step Functions Retry - -In addition to **Catchers**, the **Task and Parallel** states can also define a **Retry** (also referred to as **Retriers**). A Retry can be used to define one or more retriers with each retrier representing a certain number of retries, usually with increasing time intervals. - -A Retrier has the following fields: -* Errors - this determines the error names to match that triggers a retrier. -* Interval - an integer that represents the number of seconds before the first retry attempt (1 by default). -* Max Attempts - the maximum retry attempts (default: 3). -* Backoff Rate - the multiplier by which the retry interval increases during each attempt (default: 2.0). - -### 2. RegisterFare Retry - -Let's add a Retrier to the **RegisterFare** state. - -When we looked at adding Catchers for our States that are backed by Lambda Functions, we examined the code and the Lambda service for potential exceptions that can occur. **RegisterFare** is a state which integrates directly with DynamoDB to add a Fare item. We can look at the errors that [DynamoDB throws](https://docs.aws.amazon.com/amazondynamodb/latest/developerguide/Programming.Errors.html#Programming.Errors.Components) to determine what we need to match and how we should proceed in terms of retries. - -In this step, we will add a Retrier for the transient DynamoDB exceptions that have the potential to be successful when retried. - -Navigate to **Workflow Studio** and click on the **RegisterFare** state. Select the **Error Handling** tab and click on **Add new retrier**. - -Add the following values for the retrier (add each error as a separate value excluding the commas): - -* Errors: ProvisionedThroughputExceededException, RequestLimitExceeded, ServiceUnavailable, ThrottlingException -* Interval: 1 -* Max attempts: 2 -* Backoff rate: 2 - -{{%expand "Detailed description" %}} -![Step 1](lab-4-register-fare-retrier.png) -{{% /expand%}} - -### 3. Repeat for Set Fare Status states - -Repeat the steps above to add retriers for the **SetFareStatusFailed** and **SetFareStatusCompleted** states which are also DynamoDB integrations. \ No newline at end of file diff --git a/workshop/content/orchestration-and-coordination/add-retrying/lab-4-register-fare-retrier.png b/workshop/content/orchestration-and-coordination/add-retrying/lab-4-register-fare-retrier.png deleted file mode 100644 index c98f4dd..0000000 Binary files a/workshop/content/orchestration-and-coordination/add-retrying/lab-4-register-fare-retrier.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/bootstrap-initial-state.md b/workshop/content/orchestration-and-coordination/bootstrap-initial-state/bootstrap-initial-state.md deleted file mode 100644 index a1859d7..0000000 --- a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/bootstrap-initial-state.md +++ /dev/null @@ -1,52 +0,0 @@ -+++ -title = "Bootstrap the Initial State" -weight = 50 -pre = "1 " -+++ - -### 1. Browse to your AWS Cloud9 IDE - -Browse to your [AWS Cloud9 Console](https://console.aws.amazon.com/cloud9/home) and select the environment called **WildRydesAsyncMessaging**. - -{{%expand "Screenshot" %}} -![Step 1](lab-4-step-1.png) -{{% /expand%}} - - -### 2. Build the lab artifacts from source - -We provide you with an [AWS SAM](https://aws.amazon.com/serverless/sam/) template which we will use to bootstrap the initial state. In the **bash tab** (at the bottom) in you AWS Cloud9 IDE, run the following commands to build the lab code: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-4 -sam build -{{< /highlight >}} - -{{%expand "Screenshot" %}} -![Step 3](lab-4-step-3.png) -{{% /expand%}} - - -### 3. Deploy the application - -Now we are ready to deploy the application, by running the following command in the **lab-4** directory: - -{{< highlight bash >}} -export AWS_REGION=$(aws --profile default configure get region) -sam deploy \ - --stack-name wild-rydes-async-msg-4 \ - --capabilities CAPABILITY_IAM \ - --region $AWS_REGION \ - --guided -{{< /highlight >}} - -Confirm all proposed arguments by hitting **ENTER**. - - -### 4. Wait until the stack is successfully deployed - -It takes usually 4 minutes until the stack launched. You can monitor the progress of the **wild-rydes-async-msg-4** stack in your [AWS CloudFormation Console](https://console.aws.amazon.com/cloudformation). When the stack is launched, the status will change from **CREATE_IN_PROGRESS** to **CREATE_COMPLETE**. - -{{%expand "Screenshot" %}} -![Step 7](lab-4-step-6.png) -{{% /expand%}} diff --git a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-1.png b/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-1.png deleted file mode 100644 index 6f50a8e..0000000 Binary files a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-1.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-2.png b/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-2.png deleted file mode 100644 index b8f9dda..0000000 Binary files a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-2.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-3.png b/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-3.png deleted file mode 100644 index cdef6e9..0000000 Binary files a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-3.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-4.png b/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-4.png deleted file mode 100644 index fbee433..0000000 Binary files a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-4.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-5.png b/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-5.png deleted file mode 100644 index 034d67b..0000000 Binary files a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-5.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-6.png b/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-6.png deleted file mode 100644 index 1d207e9..0000000 Binary files a/workshop/content/orchestration-and-coordination/bootstrap-initial-state/lab-4-step-6.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/build-guide/build-guide.md b/workshop/content/orchestration-and-coordination/build-guide/build-guide.md deleted file mode 100644 index 5cf586b..0000000 --- a/workshop/content/orchestration-and-coordination/build-guide/build-guide.md +++ /dev/null @@ -1,57 +0,0 @@ -+++ -title = "Build Guide" -weight = 51 -pre = "2 " -+++ - -The bootstrap script provisions the AWS resources required for the workflow, including the Lambda functions to execute transactions, Amazon DynamoDB table to store Fare items, and an Amazon SNS topic for notifications with Amazon SQS subscriptions for success and failures. - -The bootstrapping process also provisions two Step Functions State Machines: - -* `wild-rydes-async-msg-4-start-here` - A starting point for your state machine. - -* `wild-rydes-async-msg-4-completed` - A completed state machine to use as a reference if you get stuck. - -{{% notice tip %}} -See the Output for the CloudFormation stack for ARN for the bootstrapped AWS resources. Alternatively, you can run the CloudFormation command below. -{{% /notice %}} - -{{< highlight bash >}} -aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-4 \ - --query 'Stacks[].Outputs' -{{< /highlight >}} - -The primary task in this lab is to use **`wild-rydes-async-msg-4-start-here`** as the starting point to create a Saga workflow using **Step Functions Workflow Studio**. - -{{%expand "Completed State Machine Diagram" %}} -The completed state machine should look like the following: -![State Machine](lab-4-statemachine.png) -{{% /expand%}} - -{{% notice note %}} -Your task is to create a state machine that integrates these services and deals with any failures by providing compensating transactions that leave the system, and the simulated customer's bank account, in a semantically consistent state. -{{% /notice %}} - -## AWS Step Functions Workflow Studio - -Workflow Studio for AWS Step Functions is a low-code visual workflow designer that enables you to create serverless workflows by orchestrating AWS services. You can use a drag and drop interface to create and edit workflows, control how input and output is filtered or transformed for each state, and configure error handling. As you create a workflow, Workflow Studio validates your work and auto-generates code. When you are finished, you can save your workflow, run it, then examine the results in the Step Functions console. - -Step Functions has optimized integrations with a number of AWS services and can also directly integrate with the AWS SDK. In addition to service integrations which form the basis for **Action** states, Step Functions supports **Flow** states that enable error handling, conditional branching and parallel operations. - -Here are some of the available flow states: - -* Choice: Adds if-then-else logic. -* Parallel: Adds parallel branches. -* Map: Adds a for-each loop. -* Wait: Delays for a specific time. - - Consult the [Worflow Studio Documentation](https://docs.aws.amazon.com/step-functions/latest/dg/workflow-studio-components.html) for further information and the video below provides a short, high-level overview of the main visual components of Workflow Studio. - -{{< youtube HfTucfkIwhs >}} - -The following sections in this lab provides a step-by-step guide to implementing a complete state machine using Workflow Studio for AWS Step Functions. You can choose to build the Saga state machine using the step-by-step guide or build the state machine yourself and use the guides in this lab to help align your state machine to the completed example. - -{{% notice note %}} -Step Functions supports calling the AWS SDK directly which enables integration in a State Machine to over 200 AWS services. However for the purpose of this lab, we will only use the **optimized** action types. -{{% /notice %}} diff --git a/workshop/content/orchestration-and-coordination/build-guide/choose-workflow-designer.png b/workshop/content/orchestration-and-coordination/build-guide/choose-workflow-designer.png deleted file mode 100644 index 8cc2be6..0000000 Binary files a/workshop/content/orchestration-and-coordination/build-guide/choose-workflow-designer.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/build-guide/lab-4-statemachine-2.png b/workshop/content/orchestration-and-coordination/build-guide/lab-4-statemachine-2.png deleted file mode 100644 index 2a60e5f..0000000 Binary files a/workshop/content/orchestration-and-coordination/build-guide/lab-4-statemachine-2.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/build-guide/lab-4-statemachine.png b/workshop/content/orchestration-and-coordination/build-guide/lab-4-statemachine.png deleted file mode 100644 index 5265539..0000000 Binary files a/workshop/content/orchestration-and-coordination/build-guide/lab-4-statemachine.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/clean-up/clean-up-console.md b/workshop/content/orchestration-and-coordination/clean-up/clean-up-console.md deleted file mode 100644 index 12370bd..0000000 --- a/workshop/content/orchestration-and-coordination/clean-up/clean-up-console.md +++ /dev/null @@ -1,16 +0,0 @@ -+++ -title = "Console" - -disableToc = true -hidden = true -+++ - -#### Delete the Amazon S3 bucket - -In your **[Amazon S3 console](https://s3.console.aws.amazon.com/s3/home?#)**, filter for the **bucket** you have created to upload your code artifacts with AWS SAM, select the **bucket** and click the **Delete** button in the top. - -{{%expand "Detailed description" %}} -![Step 1](lab-4-step-1-console.png) -{{% /expand%}} - -You are done! diff --git a/workshop/content/orchestration-and-coordination/clean-up/clean-up-sam.md b/workshop/content/orchestration-and-coordination/clean-up/clean-up-sam.md deleted file mode 100644 index 60eda30..0000000 --- a/workshop/content/orchestration-and-coordination/clean-up/clean-up-sam.md +++ /dev/null @@ -1,17 +0,0 @@ -+++ -title = "SAM" - -disableToc = true -hidden = true -+++ - - -#### Delete the Amazon S3 bucket - -In your Cloud9 IDE, run the following command to delete the Amazon S3 bucket we created earlier: - -{{< highlight bash >}} -aws s3 rb s3://${BUCKET_NAME} —-force -{{< /highlight >}} - -You are done! diff --git a/workshop/content/orchestration-and-coordination/clean-up/clean-up.md b/workshop/content/orchestration-and-coordination/clean-up/clean-up.md deleted file mode 100644 index 0234c27..0000000 --- a/workshop/content/orchestration-and-coordination/clean-up/clean-up.md +++ /dev/null @@ -1,27 +0,0 @@ -+++ -title = "Clean up" -weight = 56 -pre = "7 " -+++ - -In this step, we will clean up all resources we created during the lab to prevent further cost. - -#### 1. Delete the AWS SAM template - -In your Cloud9 IDE, run the following command to delete the resources we created with our AWS SAM template: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-4 -sam delete --stack-name wild-rydes-async-msg-4 -{{< /highlight >}} - -Enter (Y)es for each confirmation of the resources that SAM will delete. This includes the resources created explicitly by the SAM template as well as the supporting resources that SAM uses, such as the resources S3 bucket. - -#### 2. Delete the AWS Lambda created Amazon CloudWatch Log Group - -Follow **[this deep link](https://console.aws.amazon.com/cloudwatch/home?#logs:prefix=/aws/lambda/wild-rydes)** to list the **Amazon CloudWatch Log Groups** with the name `/aws/lambda/wild-rydes`, AWS Lambda created during this lab. Select the Amazon CloudWatch Log Group and choose **Delete log group** from the **Actions** menu. Repeat for remaining Log Groups. - -{{%expand "Detailed description" %}} -![Step 1](lab-4-step-1.png) - -{{% /expand%}} diff --git a/workshop/content/orchestration-and-coordination/clean-up/lab-4-step-1-console.png b/workshop/content/orchestration-and-coordination/clean-up/lab-4-step-1-console.png deleted file mode 100644 index f04b02a..0000000 Binary files a/workshop/content/orchestration-and-coordination/clean-up/lab-4-step-1-console.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/clean-up/lab-4-step-1.png b/workshop/content/orchestration-and-coordination/clean-up/lab-4-step-1.png deleted file mode 100644 index 6ad2f94..0000000 Binary files a/workshop/content/orchestration-and-coordination/clean-up/lab-4-step-1.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/executing/executing.md b/workshop/content/orchestration-and-coordination/executing/executing.md deleted file mode 100644 index 3b48caf..0000000 --- a/workshop/content/orchestration-and-coordination/executing/executing.md +++ /dev/null @@ -1,62 +0,0 @@ -+++ -title = "Executing and Testing" -weight = 55 -pre = "6 " -+++ - -#### Executing the state machine - -To begin testing your application, open the state machine and click **Start execution** - -![Generate Snippet](lab-4-start-execution.png) - -Copy and paste the fare payload into the Input field and click **Start Execution**. An execution will be successful if you invoke it with the following payload (you are free to update the values): - -{{< highlight json >}} -{ - "customerId": "3", - "fareId": "wr_563", - "fareAmount": "$20.00", - "cc": "2424 2424 2424 2424", - "expiryDate": "12/22", - "cvv": "111" -} -{{< /highlight >}} - -![Generate Snippet](lab-4-new-execution.png) - -#### Testing failures - -You can easily force custom exceptions from the Lambda functions by appending one of the following suffixes to the `customerId`. For example, if you want to test to see if your state machine is handling pre-authentication failures for the ChargeFare state, simply append `_fail_auth` to the `customerId` like so... - -{{< highlight json >}} -{ - "customerId": "3_fail_auth", - "fareId": "wr_563", - "fareAmount": "$20.00", - "cc": "2424 2424 2424 2424", - "expiryDate": "12/22", - "cvv": "111" -} -{{< /highlight >}} - -| State | customerId Suffix | Exception -| ------ | ----------- | ---------- | -| ChargeFare | _fail_auth | PaymentAuthException| -| ChargeFare | _fail_charge | PaymentChargeException | -| CustomerAccountCredit | _fail_credit | AccountCreditException | - - -Here are some examples of the execution path your state machine will have when errors are invoked, and what a successful execution path looks like. - -![Step 3](lab-4-failures.png) - -#### Examining Notifications - -You can examine success and failed notifications that are consumed from the SNS Topic by the respective SQS queues. Navigate to the [SQS Console](https://console.aws.amazon.com/sqs/) and look at **messages available**. - -![Step 4](lab-4-sqs-queues.png) - -You can also click on one the queues and then click on the **Send and Receive messages** to then Receive messages and examine the content and attributes for the notification messages sent by the State machine. Notice that these messages contain the JSON state we propagated from each state. We can easily transform this JSON in Step Functions using JSON Path if needed. - -![Step 4](lab-4-sqs-queue-messages.png) \ No newline at end of file diff --git a/workshop/content/orchestration-and-coordination/executing/lab-4-failures.png b/workshop/content/orchestration-and-coordination/executing/lab-4-failures.png deleted file mode 100644 index bdd89b9..0000000 Binary files a/workshop/content/orchestration-and-coordination/executing/lab-4-failures.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/executing/lab-4-new-execution.png b/workshop/content/orchestration-and-coordination/executing/lab-4-new-execution.png deleted file mode 100644 index d0a6240..0000000 Binary files a/workshop/content/orchestration-and-coordination/executing/lab-4-new-execution.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/executing/lab-4-sqs-queue-messages.png b/workshop/content/orchestration-and-coordination/executing/lab-4-sqs-queue-messages.png deleted file mode 100644 index 1e888de..0000000 Binary files a/workshop/content/orchestration-and-coordination/executing/lab-4-sqs-queue-messages.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/executing/lab-4-sqs-queues.png b/workshop/content/orchestration-and-coordination/executing/lab-4-sqs-queues.png deleted file mode 100644 index 734b6d2..0000000 Binary files a/workshop/content/orchestration-and-coordination/executing/lab-4-sqs-queues.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/executing/lab-4-start-execution.png b/workshop/content/orchestration-and-coordination/executing/lab-4-start-execution.png deleted file mode 100644 index 1d341c9..0000000 Binary files a/workshop/content/orchestration-and-coordination/executing/lab-4-start-execution.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/module-4.png b/workshop/content/orchestration-and-coordination/module-4.png deleted file mode 100644 index 5820fee..0000000 Binary files a/workshop/content/orchestration-and-coordination/module-4.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/choose-workflow-designer.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/choose-workflow-designer.png deleted file mode 100644 index 8cc2be6..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/choose-workflow-designer.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-apply-exit.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-apply-exit.png deleted file mode 100644 index c4c6822..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-apply-exit.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-charge-fare.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-charge-fare.png deleted file mode 100644 index 0f2fac4..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-charge-fare.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-register-fare-output.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-register-fare-output.png deleted file mode 100644 index 7a153a1..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-register-fare-output.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-register-workflow-complete.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-register-workflow-complete.png deleted file mode 100644 index 30b1d82..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-register-workflow-complete.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-registerfare-putitem-dynamodb.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-registerfare-putitem-dynamodb.png deleted file mode 100644 index 1089ebd..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-registerfare-putitem-dynamodb.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-save-definition.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-save-definition.png deleted file mode 100644 index 6198f89..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-save-definition.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-send-success-notification.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-send-success-notification.png deleted file mode 100644 index 48696d9..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-send-success-notification.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-set-fare-status-completed.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-set-fare-status-completed.png deleted file mode 100644 index a4323fc..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-set-fare-status-completed.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-snippet-gen.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-snippet-gen.png deleted file mode 100644 index aec7a49..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-snippet-gen.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-step-functions-edit.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-step-functions-edit.png deleted file mode 100644 index 775ee7d..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-step-functions-edit.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-step-functions-role-and-studio-edit.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-step-functions-role-and-studio-edit.png deleted file mode 100644 index 437c4dc..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/lab-4-step-functions-role-and-studio-edit.png and /dev/null differ diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/register-and-charge-fare.md b/workshop/content/orchestration-and-coordination/register-and-charge-fare/register-and-charge-fare.md deleted file mode 100644 index 315e87b..0000000 --- a/workshop/content/orchestration-and-coordination/register-and-charge-fare/register-and-charge-fare.md +++ /dev/null @@ -1,200 +0,0 @@ -+++ -title = "Register and Charge Fare Workflow" -weight = 52 -pre = "3 " -+++ - -![Step Functions Console](step-functions-console.png) - -In this section of the lab, we will familiarize ourselves with the Step Functions Workflow studio and define the main transactions in our workflow. We will first assume a **'happy path'** through our system and tackle failures and possible exception paths in the next part of the lab. - -#### 1. Browse to the Amazon Step Functions Console - -In the [Amazon Step Functions console](https://console.aws.amazon.com/states/), click on **State machines** in the left navigation pane, select the **`wild-rydes-async-msg-4-start-here`** state machine from the list and then click the **Edit** button. - -{{%expand "Detailed description" %}} -![Step 1](lab-4-step-functions-edit.png) -{{% /expand%}} - - -#### 2. Edit the State machine using Workflow Studio - -In the Step Functions Edit page, you will see the State Machine definition in the left pane and a diagram of the workflow on the right (see detailed description). - -A Step Functions State Machine is defined using the [Amazon States Language specification (ASL)](https://states-language.net/spec.html). You can see the ASL in the **Definition** pane for the State machine. - -{{% notice tip %}} -Try the **Generate code snippet** dropdown in the AWS Step Function Editor in the [AWS Console](https://console.aws.amazon.com/states/home) for examples of how you can implement various states using the ASL. -![Generate Snippet](lab-4-snippet-gen.png) -{{% /notice %}} - -In this lab we will use the Workflow Studio to create our workflow, but is important to remember that Workflow Studio will ultimately generate an underlying ASL specification for our State machine. You can view the complete generated ASL at any time by clicking on **Apply and Save** in Workflow studio and returning to the State machine Edit Definition screen. - -Ensure the bootstrapped IAM role is being used (wild-rydes-msg-4-WildRydesStateMachineStartR) and click on **Workflow Studio** to proceed to the next step (refer to the screenshot in the detailed description). - -{{%expand "Detailed description" %}} -![Step 2](lab-4-step-functions-role-and-studio-edit.png) -{{% /expand%}} - -#### 3. Step Functions Workflow Studio Interface - -The Workflow studio is composed of three main visual components: -* The left menu pane which enables Actions and Flow states to be dragged onto the State machine. -* A graph representation of the state machine in the centre which shows the states inbetween Start and End, and how they are connected. -* A Worflow menu pane on the right-hand side that enables the properties of each state to be edited. - -{{% notice tip %}} -You can toggle between the **Form** and **Definition** views for the pane on the right-hand side of Workflow studio to toggle between a form view of the current selected state and the ASL definition. This is useful if you need to quickly generate an ASL snippet to copy into an existing State machine specification. -{{% /notice %}} - -#### 4. Add RegisterFare state - -Click on the **RegisterFare** which is a Pass state and should be the only state in the starter State machine. A Pass state is a useful state to have in a State machine as a placeholder and for debugging state machines as its simply passes its input to its output. The input can be filtered or transformed or a mock output result can be added as necessary to test your state machine. Step Functions enables data to be transferred and transformed between states using JSON and JSON Path syntax. This is an important and powerful concept when developing State machines, refer to [this page in the Step Functions documentation](https://docs.aws.amazon.com/step-functions/latest/dg/concepts-input-output-filtering.html) for more information. - -In the first state, we will replace the **RegisterFare** Pass State with a DynamoDB Put:Item state to add an item into the Fares Item DynamoDB table to register a new fare. - -{{% notice note %}} -All the steps in this lab will assume that the **Form** menu is active in Workflow Studio when selecting states such that the Configuration, Input and Output submenus can be accessed. -{{% /notice %}} - -In the **Actions** menu in the left-hand pane, select **DynamoDB** from the **Database** category and drag the **PutItem** action onto the workflow graph either before or after the existing Pass State. - -Click on the **RegisterFare** Pass State and click on **Delete state** from the Configuration menu. You can also right-click on the state in the graph to delete or duplicate the state. - -Click on the newly added **PutItem** state and enter the following for the **Configuration**: - -* **State Name**: RegisterFare -* **API Parameters**: - {{< highlight json >}} -{ - "TableName": "FaresTable-wild-rydes-async-msg-4", - "Item.$": "$" -} - {{< /highlight >}} - -This targets the bootstrapped Fares table and adds an item using the entire input JSON payload by referencing $ for the item field. - -We need to make sure that the original JSON input is combined with the output from this state and passed on to the next state. In the **Output** tab, ensure the **Add original input to output using ResultPath** is ticked and has the following values: - -* Combine original input with result -* $.dynamodbResult - -{{%expand "Detailed description" %}} -![Step 4](lab-4-registerfare-putitem-dynamodb.png ) -![Step 4](lab-4-register-fare-output.png ) -{{% /expand%}} - -#### 5. Charge Fare - -Now that we have registered the fare in the system by adding it to the Fares DynamoDB table, we should attempt to charge the fare via a simulated payment system. - -In the **Actions** menu, select **AWS Lambda Invoke** and drag it onto the state machine graph **after RegisterFare**. The **AWS Lambda Invoke** state can be found in the **Actions** menu either in the **Most Popular** section or in the **Compute** section. - -Enter the following **Configuration**: - -* **State Name**: **ChargeFare** -* **Function Name**: search for **ChargeFare** and select the bootstrapped ChargeFare lambda function. - -Leave the other parameters with default values and ensure the Integration type is set to **Optimized** for this and all Lambda invokes in this State machine. - -{{%expand "Detailed description" %}} -![Step 5](lab-4-charge-fare.png) -{{% /expand%}} - -#### 6. Credit Customer Account - -Let's assume for now that payment has been successfully authorised by the payment system and we can move to the next stage, which is to credit the customer's account. - -In the **Actions** menu, select **AWS Lambda Invoke** and drag it onto the state machine graph **after ChargeFare**. - -Set the following **Configuration**: -* **State Name**: **CreditCustomerAccount** -* **Function name**: search for and select the bootstrapped **Account Credit** lambda function - -Leave the other parameters with default values. - -#### 7. Set Fare Status to Completed - -Assuming a successful path through the workflow, we have now completed the fare payment and subsequent credit to the customer account, so let's update the status to completed for the Fare in the DynamoDB table. - -Navigate to the DynamoDB section within the Database of the Actions menu and select **DynamoDB:UpdateItem**. Drag this action **after the CreditCustomerAccount state** and add the following for the Configuration. - -* **State Name**: SetFareStatusCompleted - - {{< highlight json >}} -{ - "TableName": "FaresTable-wild-rydes-async-msg-4", - "Key": { - "fareId": { - "S.$": "$.fareId" - } - }, - "UpdateExpression": "SET fareStatus = :s", - "ExpressionAttributeValues": { - ":s": { - "S": "completed" - } - } -} - {{< /highlight >}} - -Finally, we need to make sure that the original JSON input is combined with the output and passed on to the next state. In the **Output** tab, ensure the **Add original input to output using ResultPath** is ticked and has the following values: - -* Combine original input with result -* $.dynamodbResult - -{{%expand "Detailed description" %}} -![Step 7](lab-4-set-fare-status-completed.png) -{{% /expand%}} - -#### 8. Send Success SNS Notification - -Finally, let's send a successful notification message onto our SNS Topic to mark the completion of this State machine and potentially notify any interested consumers. These consumers could use any notifications from our State to complete appropriate follow on activities. - -In the **Actions** menu, select **Amazon SNS Publish** from either the **Most Popular** or **Application Integration** category and drag in between **SetFareStatusCompleted** and **End**. Set the parameters to the following: - -* **State Name**: NotifySuccess -* **Topic**: Search for and select the bootstrapped **FareProcessing** topic. - -In the **Output** tab, ensure the **Add original input to output using ResultPath** is ticked and has the following values: - -* Combine original input with result -* $.snsResult - -The SNS notifications are sent to a single SNS topic that has two SQS Queue consumers for successful and failed notifications respectively. - -**Before you continue on, can you work out how these notification messages are routed to the appropriate SQS queue? Hint: Start in the [SNS Console](https://console.aws.amazon.com/sns/v3/)**. - -The answer is that we have to add message attributes to our notifications to enable the appropriate SQS queue to consume the message based on the filter policies we have set. - -In the **Configuration** tab for the **NotifySuccess** state, copy the topic ARN and keep to hand. Click on **Edit as JSON** under **API Parameters** and copy the following JSON replacing **arn placeholder** with the topic ARN you copied previously: - -{{< highlight json >}} -{ - "Message.$": "$", - "TopicArn": "<>", - "MessageAttributes": { - "IsSuccessful": { - "DataType": "String", - "StringValue": "true" - } - } -}{{< /highlight >}} - -{{%expand "Detailed description" %}} -![Step 8](lab-4-send-success-notification.png) -{{% /expand%}} -#### 9. Initial Register and Charge Fare Workflow Complete - -This completes our initial workflow and this part of the lab. At this stage, you should have a workflow that registers and charges a fare, credits a customer account and finally sets the fare status to completed. This adds all the transactions from the overview at the start of this lab. - -Refer to the Detailed Description below for a graph of the workflow you should have at this stage. - -{{%expand "Detailed description" %}} -![Step 9](lab-4-register-workflow-complete.png) -{{% /expand%}} - -{{% notice note %}} -Don't forget to click **Apply and exit** in Workflow Studio followed by **Save** on the Edit screen before you leave the console or your changes will be lost. It's a two stage process because we are using Workflow Studio to generate and apply an ASL definition which we then must save for the State Machine. -![Step 4b](lab-4-apply-exit.png )![Step 4b](lab-4-save-definition.png ) -{{% /notice %}} \ No newline at end of file diff --git a/workshop/content/orchestration-and-coordination/register-and-charge-fare/step-functions-console.png b/workshop/content/orchestration-and-coordination/register-and-charge-fare/step-functions-console.png deleted file mode 100644 index ed16fa1..0000000 Binary files a/workshop/content/orchestration-and-coordination/register-and-charge-fare/step-functions-console.png and /dev/null differ diff --git a/workshop/content/prerequisites/_index.md b/workshop/content/prerequisites/_index.md deleted file mode 100644 index 0027797..0000000 --- a/workshop/content/prerequisites/_index.md +++ /dev/null @@ -1,15 +0,0 @@ -+++ -title = "Workshop Prerequisites" -weight = 10 -pre = "" -+++ - -{{% notice info %}} -**Running the workshop in your own AWS account** -If you want to run this workshop in your own AWS account (outside of events such as re:Invent, -Loft, Immersion Day, or any other event hosted by an AWS employee), please start at [Bootstrap AWS Cloud9](prerequisites/prerequisites-1.html). -{{% /notice %}} - -You can use the **orange arrowheads** on the left and right of the main frame to navigate between the chapters, or the navigation bar in the left frame. - -Before we can start, we have to make sure our environment is up and running and current. Just click the **orange arrowheads** on the right to get started. diff --git a/workshop/content/prerequisites/prerequisites-1/_index.md b/workshop/content/prerequisites/prerequisites-1/_index.md deleted file mode 100644 index 07267a0..0000000 --- a/workshop/content/prerequisites/prerequisites-1/_index.md +++ /dev/null @@ -1,50 +0,0 @@ -+++ -title = "Bootstrap AWS Cloud9" -weight = 11 -pre = "" -hidden = false -+++ - - -{{% notice warning %}} -**Running the workshop at an AWS Event** -If you are running this workshop at an AWS hosted event, such as re:Invent, -Loft, Immersion Day, or any other event hosted by an AWS employee, you skip this section, as the AWS Cloud9 IDE is already created for you. You can go straight to the next step and configure AWS Cloud9 by clicking the **orange arrowheads** on the right! -{{% /notice %}} - -We will leverage **[AWS CloudFormation](https://aws.amazon.com/cloudformation/)** which allows us to codify our infrastructure. In addition, we use **[AWS SAM](https://aws.amazon.com/serverless/sam/)** to build serverless applications in simple and clean syntax. - -### 1. Create the AWS CloudFormation stack in your closest region - -{{% notice note %}} -The Cloud9 workspace should be built by an IAM user with Administrator privileges, -not the root account user. Please ensure you are logged in as an IAM user, not the root -account user. -{{% /notice %}} - -{{< tabs name="Region" >}} -{{< tab name="Frankfurt" include="eu-central-1" />}} -{{< tab name="Ireland" include="eu-west-1" />}} -{{< tab name="Oregon" include="us-west-2" />}} -{{< tab name="Ohio" include="us-east-2" />}} -{{< tab name="Singapore" include="ap-southeast-1" />}} -{{< tab name="Sydney" include="ap-southeast-2" />}} -{{< /tabs >}} - - -### 2. Launch the AWS CloudFormation stack - -Just click the **Create Stack** button to launch the template. - -{{%expand "Detailed description" %}} -![Step 1](prerequisites-1/step-1.png) -{{% /expand%}} - - -### 3. Wait until the AWS CloudFormation stack launched - -It takes usually less than 2 minutes until the stack launched. When the stack is launched, the status will change from **CREATE_IN_PROGRESS** to **CREATE_COMPLETE**. - -{{%expand "Detailed description" %}} -![Step 2](prerequisites-1/step-2.png) -{{% /expand%}} diff --git a/workshop/content/prerequisites/prerequisites-1/ap-southeast-1.md b/workshop/content/prerequisites/prerequisites-1/ap-southeast-1.md deleted file mode 100644 index bae6a89..0000000 --- a/workshop/content/prerequisites/prerequisites-1/ap-southeast-1.md +++ /dev/null @@ -1,13 +0,0 @@ -+++ -title = "Singapore" - -disableToc = true -hidden = true -+++ - -Create your AWS Cloud9 Environment by launching this CloudFormation template in Singapore, with clicking on the below **Launch** button. - - -| AWS CloudFormation launch template | Launch in Singapore | -| ------ |:------| -| AWS Cloud9 IDE | {{% cf-launch "wild-rydes-async-msg-0" "ap-southeast-1" "ee-assets-prod-us-east-1/modules/32af13c099e8423b8edb09255cec1b9f/v4/template.yaml" %}} | diff --git a/workshop/content/prerequisites/prerequisites-1/ap-southeast-2.md b/workshop/content/prerequisites/prerequisites-1/ap-southeast-2.md deleted file mode 100644 index 97bc08a..0000000 --- a/workshop/content/prerequisites/prerequisites-1/ap-southeast-2.md +++ /dev/null @@ -1,13 +0,0 @@ -+++ -title = "Sydney" - -disableToc = true -hidden = true -+++ - -Create your AWS Cloud9 Environment by launching this CloudFormation template in Sydney, with clicking on the below **Launch** button. - - -| AWS CloudFormation launch template | Launch in Sydney | -| ------ |:------| -| AWS Cloud9 IDE | {{% cf-launch "wild-rydes-async-msg-0" "ap-southeast-2" "ee-assets-prod-us-east-1/modules/32af13c099e8423b8edb09255cec1b9f/v4/template.yaml" %}} | diff --git a/workshop/content/prerequisites/prerequisites-1/eu-central-1.md b/workshop/content/prerequisites/prerequisites-1/eu-central-1.md deleted file mode 100644 index 5b9f482..0000000 --- a/workshop/content/prerequisites/prerequisites-1/eu-central-1.md +++ /dev/null @@ -1,13 +0,0 @@ -+++ -title = "Ireland" - -disableToc = true -hidden = true -+++ - -Create your AWS Cloud9 Environment by launching this CloudFormation template in Frankfurt, with clicking on the below **Launch** button. - - -| AWS CloudFormation launch template | Launch in Frankfurt | -| ------ |:------| -| AWS Cloud9 IDE | {{% cf-launch "wild-rydes-async-msg-0" "eu-central-1" "ee-assets-prod-us-east-1/modules/32af13c099e8423b8edb09255cec1b9f/v4/template.yaml" %}} | diff --git a/workshop/content/prerequisites/prerequisites-1/eu-west-1.md b/workshop/content/prerequisites/prerequisites-1/eu-west-1.md deleted file mode 100644 index d241a08..0000000 --- a/workshop/content/prerequisites/prerequisites-1/eu-west-1.md +++ /dev/null @@ -1,13 +0,0 @@ -+++ -title = "Ireland" - -disableToc = true -hidden = true -+++ - -Create your AWS Cloud9 Environment by launching this CloudFormation template in Ireland, with clicking on the below **Launch** button. - - -| AWS CloudFormation launch template | Launch in Ireland | -| ------ |:------| -| AWS Cloud9 IDE | {{% cf-launch "wild-rydes-async-msg-0" "eu-west-1" "ee-assets-prod-us-east-1/modules/32af13c099e8423b8edb09255cec1b9f/v4/template.yaml" %}} | diff --git a/workshop/content/prerequisites/prerequisites-1/step-1.png b/workshop/content/prerequisites/prerequisites-1/step-1.png deleted file mode 100644 index 01ed332..0000000 Binary files a/workshop/content/prerequisites/prerequisites-1/step-1.png and /dev/null differ diff --git a/workshop/content/prerequisites/prerequisites-1/step-2.png b/workshop/content/prerequisites/prerequisites-1/step-2.png deleted file mode 100644 index 28466cb..0000000 Binary files a/workshop/content/prerequisites/prerequisites-1/step-2.png and /dev/null differ diff --git a/workshop/content/prerequisites/prerequisites-1/us-east-2.md b/workshop/content/prerequisites/prerequisites-1/us-east-2.md deleted file mode 100644 index 283192e..0000000 --- a/workshop/content/prerequisites/prerequisites-1/us-east-2.md +++ /dev/null @@ -1,13 +0,0 @@ -+++ -title = "Ohio" - -disableToc = true -hidden = true -+++ - -Create your AWS Cloud9 Environment by launching this CloudFormation template in Ohio, with clicking on the below **Launch** button. - - -| AWS CloudFormation launch template | Launch in Ohio | -| ------ |:------| -| AWS Cloud9 IDE | {{% cf-launch "wild-rydes-async-msg-0" "us-east-2" "ee-assets-prod-us-east-1/modules/32af13c099e8423b8edb09255cec1b9f/v4/template.yaml" %}} | diff --git a/workshop/content/prerequisites/prerequisites-1/us-west-2.md b/workshop/content/prerequisites/prerequisites-1/us-west-2.md deleted file mode 100644 index 4458bfb..0000000 --- a/workshop/content/prerequisites/prerequisites-1/us-west-2.md +++ /dev/null @@ -1,13 +0,0 @@ -+++ -title = "Oregon" - -disableToc = true -hidden = true -+++ - -Create your AWS Cloud9 Environment by launching this CloudFormation template in Oregon, with clicking on the below **Launch** button. - - -| AWS CloudFormation launch template | Launch in Oregon | -| ------ |:------| -| AWS Cloud9 IDE | {{% cf-launch "wild-rydes-async-msg-0" "us-west-2" "ee-assets-prod-us-east-1/modules/32af13c099e8423b8edb09255cec1b9f/v4/template.yaml" %}} | diff --git a/workshop/content/prerequisites/prerequisites-2/magic.gif b/workshop/content/prerequisites/prerequisites-2/magic.gif deleted file mode 100644 index 235c4ed..0000000 Binary files a/workshop/content/prerequisites/prerequisites-2/magic.gif and /dev/null differ diff --git a/workshop/content/prerequisites/prerequisites-2/prerequisites-2.md b/workshop/content/prerequisites/prerequisites-2/prerequisites-2.md deleted file mode 100644 index 3edb9e9..0000000 --- a/workshop/content/prerequisites/prerequisites-2/prerequisites-2.md +++ /dev/null @@ -1,39 +0,0 @@ -+++ -title = "Configure AWS Cloud9" -weight = 12 -pre = "" -+++ - -{{% notice note %}} -Ad blockers, javascript disabler, and tracking blockers should be disabled for -the cloud9 domain, or connecting to the workspace might be impacted. -Cloud9 requires third-party-cookies. You can whitelist the [specific domains]( https://docs.aws.amazon.com/cloud9/latest/user-guide/troubleshooting.html#troubleshooting-env-loading). -{{% /notice %}} - -### 1. Browse to your AWS Cloud9 development environment - -Open your [CloudFormation Console](https://console.aws.amazon.com/cloudformation/home?#/stacks) and select the stack with the description ”Wild Rydes Asynchronous Messaging Workshop“ (the name could vary). The `Outputs` tab exposes the `Cloud9DevEnvUrl` parameter. Click at the corresponding URL in the value column and open your AWS Cloud9 development environment in a new tab. - -{{%expand "Detailed description" %}} -![Step 1](step-1.png) -{{% /expand%}} - -### 2. Configure your AWS Cloud9 development environment - -In your AWS Cloud9 IDE, you can close the welcome tab. In the left environment navigation window, you can see the project **wild-rydes-async-messaging** we have already checked out for you from Github. This project also contains a shell script to setup your environment. Run the following command in the **bash** tab (at the bottom of the IDE): - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/code/lab-0 -chmod +x configureCloud9.sh -./configureCloud9.sh -{{< /highlight >}} - -{{%expand "Detailed description" %}} -![Step 2](step-2.png) -{{% /expand%}} - -It takes usually less then 1 minute, until the AWS Cloud9 IDE is updated. In the meantime while your waiting, you may want to have a look at some handy AWS Cloud9 shortcuts, like the **[multiple cursors](https://docs.c9.io/docs/multiple-cursors)** or the AWS Cloud9 **[keybindings](https://docs.c9.io/docs/keybindings)**. - -![Get Started](magic.gif) - -**You are now ready to get started!!!** diff --git a/workshop/content/prerequisites/prerequisites-2/step-1.png b/workshop/content/prerequisites/prerequisites-2/step-1.png deleted file mode 100644 index fffcb38..0000000 Binary files a/workshop/content/prerequisites/prerequisites-2/step-1.png and /dev/null differ diff --git a/workshop/content/prerequisites/prerequisites-2/step-2.png b/workshop/content/prerequisites/prerequisites-2/step-2.png deleted file mode 100644 index e6103cb..0000000 Binary files a/workshop/content/prerequisites/prerequisites-2/step-2.png and /dev/null differ diff --git a/workshop/content/resources/ARC314.decoupled-microservices-building-scalable-applications.srr-final-presentation.pdf b/workshop/content/resources/ARC314.decoupled-microservices-building-scalable-applications.srr-final-presentation.pdf deleted file mode 100644 index 62a3250..0000000 Binary files a/workshop/content/resources/ARC314.decoupled-microservices-building-scalable-applications.srr-final-presentation.pdf and /dev/null differ diff --git a/workshop/content/resources/_index.md b/workshop/content/resources/_index.md deleted file mode 100644 index f6c2101..0000000 --- a/workshop/content/resources/_index.md +++ /dev/null @@ -1,26 +0,0 @@ -+++ -title = "Resources" -weight = 70 -pre = "" -+++ - -## Congratulations! - -You've successfully completed the Decoupled Microservices Workshop! - -### Presentation - -[![presentation](resources/presentation.png)](resources/ARC314.decoupled-microservices-building-scalable-applications.srr-final-presentation.pdf) - -### General Messaging Resources - -* [AWS Messaging Site](https://aws.amazon.com/messaging/) -* [AWS Messaging Related Blog Posts](https://aws.amazon.com/blogs/compute/tag/messaging/) - -#### Orchestration and Coordination - -* [AWS Step Functions](https://aws.amazon.com/step-functions/) -* [AWS Step Functions Developer Guide](https://docs.aws.amazon.com/step-functions/latest/dg/welcome.html) -* [AWS Step Function Tutorials](https://docs.aws.amazon.com/step-functions/latest/dg/tutorials.html) -* [statelint](https://github.com/awslabs/statelint) -* [Amazon States Language](https://states-language.net/spec.html) diff --git a/workshop/content/resources/presentation.png b/workshop/content/resources/presentation.png deleted file mode 100644 index 2b2119f..0000000 Binary files a/workshop/content/resources/presentation.png and /dev/null differ diff --git a/workshop/content/scatter-gather/_index.md b/workshop/content/scatter-gather/_index.md deleted file mode 100644 index 9adfc6a..0000000 --- a/workshop/content/scatter-gather/_index.md +++ /dev/null @@ -1,34 +0,0 @@ -+++ -title = "Scatter-Gather" -weight = 40 -pre = "Lab-3: " -+++ - -{{% notice info %}} -Make sure you executed the **[Workshop Prerequisites](/prerequisites.html)** first, before you start with this lab! -{{% /notice %}} - -As Wild Rydes business has grown in its popularity, it has opened its platform for various unicorn providers to partner with Wild Rydes. Customers of Wild Rydes app will be able to submit a request for a ride from their mobile app. Behind the scenes, Wild Rydes service will talk to multiple service providers who will submit quotes for the customer. The platform will receive all the responses and stage it in a database. The app will then periodically poll for the response quotes using a REST API and present them to the customer. The end user app will keep updating the dashboard of the quotes as new providers keep sending the response. In this architecture queues provide a loose coupling between the producer and consumer systems. In the absence of queues, the client systems would need to know the API endpoints for each of the server systems. It will need to be stored in a central database for any type of changes. It gets further complicated as additional instances are added or removed. In addition to it, client systems will need to implement failure and retry logic in their code. Queues help alleviate lot of such issues by decoupling the systems and providing a store and forward mechanism. -
- -The service can be enhanced further to notify customers once all the service providers have responded or have exceeded the time for them to respond. - -![Module 3](scatter-gather/module-3.png) - -## Lab Objectives - -In this lab, you will acquire the following skills: - -+ **How to implement a scatter pattern by sending messages through multiple channels?** -+ **How to implement a request response flow in asynchronous manner?** -+ **How to stage responses from multiple sources?** -+ **How to create a gather pattern by querying responses based on a request id?** - - -{{% notice tip %}} -**Lab source code** -If you are curious and would like to dive into the lab's source code, you are more than welcome to do so. You will find the source code of this lab in our Github repo **[here](https://github.com/aws-samples/asynchronous-messaging-workshop/tree/master/code/lab-3)**. -{{% /notice %}} - - - diff --git a/workshop/content/scatter-gather/bootstrap-initial-state.files/template.yaml b/workshop/content/scatter-gather/bootstrap-initial-state.files/template.yaml deleted file mode 100644 index 34b26b3..0000000 --- a/workshop/content/scatter-gather/bootstrap-initial-state.files/template.yaml +++ /dev/null @@ -1,321 +0,0 @@ -AWSTemplateFormatVersion: '2010-09-09' -Transform: AWS::Serverless-2016-10-31 -Description: > - re:invent2019 ARC314-R Lab-3 - - Sample SAM Template for re:invent2019 ARC314-R Lab-3 - -# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst -Globals: - Function: - Timeout: 70 - -Resources: - RequestForQuotesService: - Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction - Properties: - CodeUri: request-for-quotes-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - TABLE_NAME: !Ref RidesBookingTable - TOPIC_ARN: !Ref RequestForQuotesTopic - Policies: - - DynamoDBCrudPolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - TableName: - !Ref RidesBookingTable - - SNSPublishMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - TopicName: - !GetAtt RequestForQuotesTopic.TopicName - Events: - RideBooking: - Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api - Properties: - Path: /submit-instant-ride-rfq - Method: post - - QueryForQuotesService: - Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction - Properties: - CodeUri: query-for-quotes-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - TABLE_NAME: !Ref RidesBookingTable - TOPIC_ARN: !Ref RequestForQuotesTopic - Policies: - - DynamoDBCrudPolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - TableName: - !Ref RidesBookingTable - - SNSPublishMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - TopicName: - !GetAtt RequestForQuotesTopic.TopicName - Events: - RideBooking: - Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api - Properties: - Path: /query-instant-ride-rfq/{id} - Method: get - - RidesBookingTable: - Type: AWS::DynamoDB::Table - Properties: - TableName: RidesBookingTable - AttributeDefinitions: - - AttributeName: id - AttributeType: S - - AttributeName: responder - AttributeType: S - KeySchema: - - AttributeName: id - KeyType: HASH - - AttributeName: responder - KeyType: RANGE - BillingMode: PAY_PER_REQUEST - - RequestForQuotesTopic: - Type: AWS::SNS::Topic - Properties: - TopicName: request-for-quotes-topic - - RequestForQuotesResponseQueue: - Type: AWS::SQS::Queue - Properties: - QueueName: RequestForQuotesResponseQueue - VisibilityTimeout: 120 - - UnicornManagementResource1: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - SERVICE_NAME: UnicornManagementResource1 - QUEUE_URL: !Ref RequestForQuotesResponseQueue - Policies: - - SQSSendMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - QueueName: - !GetAtt RequestForQuotesResponseQueue.QueueName - Events: - SqsJobQueue: - Type: SNS - Properties: - Topic: !Ref RequestForQuotesTopic - - UnicornManagementResource2: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - SERVICE_NAME: UnicornManagementResource2 - QUEUE_URL: !Ref RequestForQuotesResponseQueue - Policies: - - SQSSendMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - QueueName: - !GetAtt RequestForQuotesResponseQueue.QueueName - Events: - SqsJobQueue: - Type: SNS - Properties: - Topic: !Ref RequestForQuotesTopic - - UnicornManagementResource3: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - SERVICE_NAME: UnicornManagementResource3 - QUEUE_URL: !Ref RequestForQuotesResponseQueue - Policies: - - SQSSendMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - QueueName: - !GetAtt RequestForQuotesResponseQueue.QueueName - Events: - SqsJobQueue: - Type: SNS - Properties: - Topic: !Ref RequestForQuotesTopic - - UnicornManagementResource4: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - SERVICE_NAME: UnicornManagementResource4 - QUEUE_URL: !Ref RequestForQuotesResponseQueue - Policies: - - SQSSendMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - QueueName: - !GetAtt RequestForQuotesResponseQueue.QueueName - Events: - SqsJobQueue: - Type: SNS - Properties: - Topic: !Ref RequestForQuotesTopic - - UnicornManagementResource5: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - SERVICE_NAME: UnicornManagementResource5 - QUEUE_URL: !Ref RequestForQuotesResponseQueue - Policies: - - SQSSendMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - QueueName: - !GetAtt RequestForQuotesResponseQueue.QueueName - Events: - SqsJobQueue: - Type: SNS - Properties: - Topic: !Ref RequestForQuotesTopic - - UnicornManagementResource6: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - SERVICE_NAME: UnicornManagementResource6 - QUEUE_URL: !Ref RequestForQuotesResponseQueue - Policies: - - SQSSendMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - QueueName: - !GetAtt RequestForQuotesResponseQueue.QueueName - Events: - SqsJobQueue: - Type: SNS - Properties: - Topic: !Ref RequestForQuotesTopic - - UnicornManagementResource7: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - SERVICE_NAME: UnicornManagementResource7 - QUEUE_URL: !Ref RequestForQuotesResponseQueue - Policies: - - SQSSendMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - QueueName: - !GetAtt RequestForQuotesResponseQueue.QueueName - Events: - SqsJobQueue: - Type: SNS - Properties: - Topic: !Ref RequestForQuotesTopic - - UnicornManagementResource8: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - SERVICE_NAME: UnicornManagementResource8 - QUEUE_URL: !Ref RequestForQuotesResponseQueue - Policies: - - SQSSendMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - QueueName: - !GetAtt RequestForQuotesResponseQueue.QueueName - Events: - SqsJobQueue: - Type: SNS - Properties: - Topic: !Ref RequestForQuotesTopic - - UnicornManagementResource9: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - SERVICE_NAME: UnicornManagementResource9 - QUEUE_URL: !Ref RequestForQuotesResponseQueue - Policies: - - SQSSendMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - QueueName: - !GetAtt RequestForQuotesResponseQueue.QueueName - Events: - SqsJobQueue: - Type: SNS - Properties: - Topic: !Ref RequestForQuotesTopic - - UnicornManagementResource10: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - SERVICE_NAME: UnicornManagementResource10 - QUEUE_URL: !Ref RequestForQuotesResponseQueue - Policies: - - SQSSendMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - QueueName: - !GetAtt RequestForQuotesResponseQueue.QueueName - Events: - SqsJobQueue: - Type: SNS - Properties: - Topic: !Ref RequestForQuotesTopic - - QuotesResponseService: - Type: AWS::Serverless::Function - Properties: - CodeUri: quotes-response-service/ - Handler: app.lambda_handler - Runtime: python3.7 - Environment: - Variables: - TABLE_NAME: !Ref RidesBookingTable - Policies: - - DynamoDBCrudPolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - TableName: - !Ref RidesBookingTable - Events: - SQSQueue: - Type: SQS - Properties: - Queue: !GetAtt RequestForQuotesResponseQueue.Arn - BatchSize: 1 - -Outputs: - RideBookingApiSubmitInstantRideRfqEndpoint: - Description: "API Gateway endpoint URL for Prod stage for RideBookingService submit-instant-ride-rfq resource" - Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/submit-instant-ride-rfq/" - RideBookingApiQueryInstantRideRfqEndpoint: - Description: "API Gateway endpoint URL for Prod stage for RideBookingService query-instant-ride-rfq resource" - Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/query-instant-ride-rfq/{id}" -# RideBookingService: -# Description: "RideBookingService Lambda Function ARN" -# Value: !GetAtt RideBookingService.Arn - RequestForQuotesTopic: - Description: "Amazon SNS topic ARN for RequestForQuotes topic" - Value: !Ref RequestForQuotesTopic \ No newline at end of file diff --git a/workshop/content/scatter-gather/bootstrap-initial-state.md b/workshop/content/scatter-gather/bootstrap-initial-state.md deleted file mode 100644 index b69f93c..0000000 --- a/workshop/content/scatter-gather/bootstrap-initial-state.md +++ /dev/null @@ -1,61 +0,0 @@ -+++ -title = "Bootstrap the Initial State" -weight = 41 -pre = "1 " -+++ - -First, we will build the AWS Serverless Application Model (AWS SAM) deployment template to create the deployment package for the Python functions. AWS SAM is an open-source framework that you can use to build serverless applications on AWS. It will also generate deployment artifacts that target AWS Lambda's execution environment. It also helps with creating artifacts needed for running the tests using sam local. - -The inputs and outputs from the service are shown in the picture below. The overall deployment comprises of deploying API endpoints using Amazon API Gateway to send the RFQ (request for quote) and get the response for the RFQ, AWS Lambda functions to process the request for quotes from end user and response for the quotes from service providers, Amazon DynamoDB to stage the response quotes and SQS queues to act as the message destination for request and responses. - -![Step 1](lab-3-step-1.png) - -### 1. Browse to your AWS Cloud9 IDE - -Browse to your [AWS Cloud9 Console](https://console.aws.amazon.com/cloud9/home) and select the environment called **WildRydesAsyncMessaging**. Open the IDE and go to the terminal window in lower right pane. - -{{%expand "Screenshot" %}} -![Step 1](lab-3-step-2.png) -{{% /expand%}} - -### 2. Build the lab artifacts from source - -We provide you with an [AWS SAM](https://aws.amazon.com/serverless/sam/) template which we will use to bootstrap the initial state. In the **bash tab** (at the bottom) in you AWS Cloud9 IDE, run the following commands to build the lab code: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-3 -sam build -{{< /highlight >}} - -{{%expand "Screenshot" %}} -![Step 3](lab-3-step-4.png) -{{% /expand%}} - -### 3. Deploy the application - -Now we are ready to deploy the application, by running the following command in the **lab-3** directory: - -{{< highlight bash >}} -sam deploy --guided --stack-name wild-rydes-async-msg-3 --capabilities CAPABILITY_IAM -{{< /highlight >}} - -Confirm all proposed arguments by hitting **ENTER**. You will be asked to confirm whether or not you want to proceed without authorisation for two services. Enter **y** for these and continue with the default arguments. - -{{< highlight bash >}} -RequestForQuotesService may not have authorization defined, Is this okay? [y/N]: y -QueryForQuotesService may not have authorization defined, Is this okay? [y/N]: y -{{< /highlight >}} - -The application comprises of API Gateway endpoints and lambda functions which provide the ability to send request for quotes and query the responses. Service providers are subscribed to a SNS topic which is used to publish the request for quote. On receiving the RFQ message, service providers send their response for quotes in a queue. The queue triggers a lambda functions which loads the responses in a DynamoDB table. The response for quotes service queries all the responses based on request id. In a real world scenario, the service providers may respond at different times as a result client applications may need to consolidate their responses by polling responses multiple times. - -### 4. Wait until the stack is successfully deployed - -It usually takes less than 5 minutes until the stack launched. You can monitor the progress of the **wild-rydes-async-msg-3** stack in your [AWS CloudFormation Console](https://console.aws.amazon.com/cloudformation). When the stack is launched, the status will change from **CREATE_IN_PROGRESS** to **CREATE_COMPLETE**. - -{{%expand "Screenshot" %}} -![Step 6](lab-3-step-7.png) -{{% /expand%}} - -In the meantime while your waiting, you may want to have a look at the AWS SAM template to make yourself familiar with the stack we launched. Just click on the **template.yaml** attachment below to see the content. Once complete, you can also look at the lambda functions that will request the quotes and process responses. The created queues can also be explored from the console. - -{{%attachments title="Related files" pattern=".*(yaml)"/%}} diff --git a/workshop/content/scatter-gather/cleanup/clean-up-console.md b/workshop/content/scatter-gather/cleanup/clean-up-console.md deleted file mode 100644 index 5b3d7b3..0000000 --- a/workshop/content/scatter-gather/cleanup/clean-up-console.md +++ /dev/null @@ -1,19 +0,0 @@ -+++ -title = "Console" - -disableToc = true -hidden = true -+++ - -#### 3. Delete the Amazon S3 bucket - -In your **[Amazon S3 console](https://s3.console.aws.amazon.com/s3/home?#)**, filter for the **bucket** you have created to upload your code artifacts with AWS SAM, select the **bucket** and click the **Delete** button in the top. - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - - - -You are done! - diff --git a/workshop/content/scatter-gather/cleanup/clean-up-sam.md b/workshop/content/scatter-gather/cleanup/clean-up-sam.md deleted file mode 100644 index 8cd7015..0000000 --- a/workshop/content/scatter-gather/cleanup/clean-up-sam.md +++ /dev/null @@ -1,17 +0,0 @@ -+++ -title = "SAM" - -disableToc = true -hidden = true -+++ - - -#### 3. Delete the Amazon S3 bucket - -In your Cloud9 IDE, run the following command to delete the Amazon S3 bucket we created earlier: - -{{< highlight bash >}} -aws s3 rb s3://${BUCKET_NAME} —-force -{{< /highlight >}} - -You are done! diff --git a/workshop/content/scatter-gather/cleanup/clean-up.md b/workshop/content/scatter-gather/cleanup/clean-up.md deleted file mode 100644 index a16e52d..0000000 --- a/workshop/content/scatter-gather/cleanup/clean-up.md +++ /dev/null @@ -1,41 +0,0 @@ -+++ -title = "Cleanup" -weight = 43 -pre = "3 " -+++ - - -In this step, we will clean up all resources, we created during this lab, so that no further cost will occur. - -#### 1. Delete the AWS SAM template - -In your Cloud9 IDE, run the following command to delete the resources we created with our AWS SAM template: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-3 -aws cloudformation delete-stack \ - --stack-name wild-rydes-async-msg-3 - -{{< /highlight >}} - - -#### 2. Delete the AWS Lambda created Amazon CloudWatch Log Group - -Run the following command to delete all the log groups associated with the labs. - -``` -aws logs describe-log-groups --query 'logGroups[*].logGroupName' --output table | awk '{print $2}' | \ - grep ^/aws/lambda/wild-ryde | while read x; \ - do echo "deleting $x" ; aws logs delete-log-group --log-group-name $x; \ -done -``` - -#### 3. Delete S3 bucket used to upload code package -You can delete the S3 bucket by going to the console or using the CLI. Please follow one of the options below to delete the bucket. - -{{< tabs name="Style" >}} -{{< tab name="Console" include="clean-up-console" />}} -{{< tab name="SAM" include="clean-up-sam" />}} -{{< /tabs >}} - - diff --git a/workshop/content/scatter-gather/cleanup/step-1-console.png b/workshop/content/scatter-gather/cleanup/step-1-console.png deleted file mode 100644 index f04b02a..0000000 Binary files a/workshop/content/scatter-gather/cleanup/step-1-console.png and /dev/null differ diff --git a/workshop/content/scatter-gather/cleanup/step-1.png b/workshop/content/scatter-gather/cleanup/step-1.png deleted file mode 100644 index d2690fa..0000000 Binary files a/workshop/content/scatter-gather/cleanup/step-1.png and /dev/null differ diff --git a/workshop/content/scatter-gather/lab-3-step-1.png b/workshop/content/scatter-gather/lab-3-step-1.png deleted file mode 100644 index 3e662f8..0000000 Binary files a/workshop/content/scatter-gather/lab-3-step-1.png and /dev/null differ diff --git a/workshop/content/scatter-gather/lab-3-step-2.png b/workshop/content/scatter-gather/lab-3-step-2.png deleted file mode 100644 index 6f50a8e..0000000 Binary files a/workshop/content/scatter-gather/lab-3-step-2.png and /dev/null differ diff --git a/workshop/content/scatter-gather/lab-3-step-2a.png b/workshop/content/scatter-gather/lab-3-step-2a.png deleted file mode 100644 index f45535c..0000000 Binary files a/workshop/content/scatter-gather/lab-3-step-2a.png and /dev/null differ diff --git a/workshop/content/scatter-gather/lab-3-step-4.png b/workshop/content/scatter-gather/lab-3-step-4.png deleted file mode 100644 index 8b05a25..0000000 Binary files a/workshop/content/scatter-gather/lab-3-step-4.png and /dev/null differ diff --git a/workshop/content/scatter-gather/lab-3-step-5.png b/workshop/content/scatter-gather/lab-3-step-5.png deleted file mode 100644 index 0b793e6..0000000 Binary files a/workshop/content/scatter-gather/lab-3-step-5.png and /dev/null differ diff --git a/workshop/content/scatter-gather/lab-3-step-6.png b/workshop/content/scatter-gather/lab-3-step-6.png deleted file mode 100644 index f1dffac..0000000 Binary files a/workshop/content/scatter-gather/lab-3-step-6.png and /dev/null differ diff --git a/workshop/content/scatter-gather/lab-3-step-7.png b/workshop/content/scatter-gather/lab-3-step-7.png deleted file mode 100644 index a277694..0000000 Binary files a/workshop/content/scatter-gather/lab-3-step-7.png and /dev/null differ diff --git a/workshop/content/scatter-gather/lab-3-step-8.png b/workshop/content/scatter-gather/lab-3-step-8.png deleted file mode 100644 index c0746ae..0000000 Binary files a/workshop/content/scatter-gather/lab-3-step-8.png and /dev/null differ diff --git a/workshop/content/scatter-gather/lab-3-step-9.png b/workshop/content/scatter-gather/lab-3-step-9.png deleted file mode 100644 index 0e42636..0000000 Binary files a/workshop/content/scatter-gather/lab-3-step-9.png and /dev/null differ diff --git a/workshop/content/scatter-gather/module-3.png b/workshop/content/scatter-gather/module-3.png deleted file mode 100644 index 3e662f8..0000000 Binary files a/workshop/content/scatter-gather/module-3.png and /dev/null differ diff --git a/workshop/content/scatter-gather/test-scatter-and-gather.md b/workshop/content/scatter-gather/test-scatter-and-gather.md deleted file mode 100644 index 7114d59..0000000 --- a/workshop/content/scatter-gather/test-scatter-and-gather.md +++ /dev/null @@ -1,108 +0,0 @@ -+++ -title = "Test Scatter-Gather" -weight = 42 -pre = "2 " -+++ - -### 1. Get API Gateway endpoint to send request for quotes -The lab 3 SAM template created two separate API gateway endpoints. They will be shown under the outputs tab of the cloudformation stack once deployment is completed. **RideBookingApiSubmitInstantRideRfqEndpoint** is the API endpoint to submit request for quotes and **RideBookingApiQueryInstantRideRfqEndpoint** is used to query the response from various ride operators. You can run the following command to retrieve the **RideBookingApiSubmitInstantRideRfqEndpoint** API Gateway Endpoint URL. - -{{< highlight bash >}} -aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-3 \ - --query 'Stacks[].Outputs[?OutputKey==`RideBookingApiSubmitInstantRideRfqEndpoint`][OutputValue]' \ - --output text -{{< /highlight >}} - -Let's store this request API Gateway endpoint URL in an environment variable, so we don't have to repeat it all the time: - -```bash -export REQ_ENDPOINT=$(aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-3 \ - --query 'Stacks[].Outputs[?OutputKey==`RideBookingApiSubmitInstantRideRfqEndpoint`].OutputValue' \ - --output text) -``` -### 2. Send the request for quotes - -The trigger point of the flow is a request message that is sent to get the quote. The following is the structure of the request event message. -{{< highlight bash >}} -{ - "from": "Frankfurt", - "to": "Las Vegas", - "customer": "cmr" -} -{{< /highlight >}} - - -The from tag represents the starting point and to indicates the destination. The customer is an id for the end ussr. -Execute the below commands to send a request for quote. - -{{< highlight bash >}} - -curl -XPOST -i -H "Content-Type:application/json" -d @event.json $REQ_ENDPOINT -{{< /highlight >}} - -The output will have a **rfq-id** parameter. Save the value in a notepad as it will be used later to query the responses. - -{{%expand "Screenshot" %}} -![Step 4](lab-3-step-8.png) -{{% /expand%}} - -### 3. Get API Gateway endpoint to query responses -Before we can query the quotes, we have to lookup the response query endpoint. Execute the following command to query the **RideBookingApiQueryInstantRideRfqEndpoint** output in Amazon CloudFormation stack via the CLI: - -{{< highlight bash >}} -aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-3 \ - --query 'Stacks[].Outputs[?OutputKey==`RideBookingApiQueryInstantRideRfqEndpoint`][OutputValue]' \ - --output text -{{< /highlight >}} - -Let's store this request API Gateway endpoint URL in an environment variable, so we don't have to repeat it all the time: - -```bash -export RES_ENDPOINT=$(aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-3 \ - --query 'Stacks[].Outputs[?OutputKey==`RideBookingApiQueryInstantRideRfqEndpoint`].OutputValue' \ - --output text | cut -d'{' -f 1) -``` - - -### 4. Query the RFQ response endpoint -Replace the **<>** in the below command with the value that was received in step 2. This is the correlation id to get the response quotes for the request that was sent. Execute the following command to query the responses: - -{{< highlight bash >}} - -curl -i -H "Accept:application/json" ${RES_ENDPOINT}<> -{{< /highlight >}} - -The above call invokes a lambda function via API gateway end point. It queries the DynamoDB table to get the responses corresponding to the request id. The response will be a json payload showing the response quotes from different providers. A sample response is shown below: -{{< highlight bash >}} -{ - "quotes": [ - { - "responder": "UnicornManagementResource10", - "quote": "45" - }, - { - "responder": "UnicornManagementResource2", - "quote": "100" - } - ], - "rfq-id": "8b095f9e-cffc-4790-91a6-28353fa30e42", - "from": "Frankfurt", - "to": "Las Vegas", - "customer": "cmr" -} -{{< /highlight >}} -It shows the response quotes from two service providers. The function will need to be called in regular intervals if the service providers send responses at different times. You can also check the responses in the DynamoDB directly by querying based on the request id. -{{% notice tip %}} -**How to verify the data is actually coming from DynamoDB?** -All responses for the quotes are received in a SQS queue. A lambda function receives the messages and stages them in a DynamoDB table. You can verify the response data by accessing the DynamoDB table in your specific region. -**Oregon** | [Click here](https://us-west-2.console.aws.amazon.com/dynamodb/home?region=us-west-2#tables:) | -**Ohio** | [Click here](https://us-east-2.console.aws.amazon.com/dynamodb/home?region=us-east-2#tables:) | -**Singapore** | [Click here](https://ap-southeast-1.console.aws.amazon.com/dynamodb/home?region=ap-southeast-1#tables:) | -**Sydney** | [Click here](https://ap-southeast-2.console.aws.amazon.com/dynamodb/home?region=ap-southeast-2#tables:) | -**Frankfurt** | [Click here](https://eu-central-1.console.aws.amazon.com/dynamodb/home?region=eu-central-1#tables:) | -**Ireland** | [Click here](https://eu-west-1.console.aws.amazon.com/dynamodb/home?region=eu-west-1#tables:) | -{{% /notice %}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/_index.md b/workshop/content/topic-queue-chaining-and-load-balancer/_index.md deleted file mode 100644 index e399bc0..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/_index.md +++ /dev/null @@ -1,36 +0,0 @@ -+++ -title = "Topic-Queue Chaining & Load Balancing" -weight = 30 -pre = "Lab-2: " -+++ - -{{% notice info %}} -Make sure you executed the **[Workshop Prerequisites](/prerequisites.html)** first, before you start with this lab! -{{% /notice %}} - -Let’s look once more at the publish/subscribe channel between the unicorn management service and all 3 backend services on the right hand side that are interested in getting notified about ride completions. - -One of these services could happen to be taken offline for maintenance. Or the code that processes messages coming in from the ride completion topic could run into an exception. These are two examples where a subscriber service could potentially miss topic messages. A good pattern to apply here is **topic-queue-chaining**. That means that you add a queue, in our case an Amazon SQS queue, between the ride completion Amazon SNS topic and each of the subscriber services. -As messages are buffered in a persistent manner in an SQS queue, no message will get lost should a subscriber process run into problems for many hours or days, or has exceptions or crashes. - -But there is even more to it. By having an Amazon SQS queue in front of each subscriber service, we can leverage the fact that a queue can act as a **buffering load-balancer**. Due to nature that every queue message is delivered to one of potentially many consumer processes, you can easily scale your subscriber services out & in and the message load will be distributed over the available consumer processes. Furthermore, since messages are buffered in the queue, also a scaling event, for instance when you need to wait until an additional consumer process becomes operational, will not make you lose messages. - -In this lab, we will develop the architecture below: - -![Module 2](topic-queue-chaining-and-load-balancer/module-2.png) - -## Lab Objectives - -In this lab, you will acquire the following skills: - -+ **How to create an Amazon SQS queue?** -+ **How to leverage Amazon SQS as event source for AWS Lambda?** -+ **How to add an Amazon SQS subscription to an Amazon SNS topic?** -+ **How to define a subscription filter in an Amazon SNS subscriptions?** -+ **How to call Amazon SNS from AWS Lambda?** - - -{{% notice tip %}} -**Lab source code** -If you are curious and would like to dive into the lab's source code, you are more than welcome to do so. You will find the source code of this lab in our Github repo **[here](https://github.com/aws-samples/asynchronous-messaging-workshop/tree/master/code/lab-2)**. -{{% /notice %}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/bootstrap-initial-state.files/template.yaml b/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/bootstrap-initial-state.files/template.yaml deleted file mode 100644 index d6131ae..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/bootstrap-initial-state.files/template.yaml +++ /dev/null @@ -1,236 +0,0 @@ - -AWSTemplateFormatVersion: '2010-09-09' -Transform: AWS::Serverless-2016-10-31 -Description: > - re:invent2019 ARC314-R Lab-2 - - Sample SAM Template for re:invent2019 ARC314-R Lab-2 - -# More info about Globals: https://github.com/awslabs/serverless-application-model/blob/master/docs/globals.rst -Globals: - Function: - Timeout: 10 - -Resources: - PythonLayerWithBoto3: - Type: AWS::Serverless::LayerVersion - Properties: - LayerName: PythonLayerWithBoto3 - Description: Lambda Python 3.6 Layer with Boto3 - ContentUri: lambda-layers/ - CompatibleRuntimes: - - python3.6 - LicenseInfo: Apache 2.0 - RetentionPolicy: Retain - - SubmitRideCompletionFunction: - Type: AWS::Serverless::Function # More info about Function Resource: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#awsserverlessfunction - Properties: - CodeUri: unicorn-management-service/ - Handler: app.lambda_handler - Runtime: python3.6 - Layers: - - !Ref PythonLayerWithBoto3 - Environment: - Variables: - TABLE_NAME: !Ref RidesTable -# TOPIC_ARN: !Ref RideCompletionTopic - Policies: - - DynamoDBCrudPolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json - TableName: !Ref RidesTable -# - SNSPublishMessagePolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json -# TopicName: !GetAtt RideCompletionTopic.TopicName - Events: - WildRydes: - Type: Api # More info about API Event Source: https://github.com/awslabs/serverless-application-model/blob/master/versions/2016-10-31.md#api - Properties: - Path: /submit-ride-completion - Method: post - - RidesTable: - Type: AWS::Serverless::SimpleTable - Properties: - TableName: Rides - PrimaryKey: - Name: id - Type: String - -# RideCompletionTopic: -# Type: AWS::SNS::Topic -# Properties: -# TopicName: RideCompletionTopic - - CustomerAccountingService: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-backend-microservice/ - Handler: app.lambda_handler - Runtime: python3.6 - ReservedConcurrentExecutions: 5 - Environment: - Variables: - SERVICE_NAME: CustomerAccountingService -# Policies: -# - SQSPollerPolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json -# QueueName: !Ref CustomerAccountingServiceQueue -# Events: -# CustomerAccountingServiceJobQueue: -# Type: SQS -# Properties: -# Queue: !GetAtt CustomerAccountingServiceQueue.Arn -# BatchSize: 1 - - CustomerNotificationService: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-backend-microservice/ - Handler: app.lambda_handler - Runtime: python3.6 - ReservedConcurrentExecutions: 5 - Environment: - Variables: - SERVICE_NAME: CustomerNotificationService -# Policies: -# - SQSPollerPolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json -# QueueName: !Ref CustomerNotificationServiceQueue -# Events: -# CustomerNotificationServiceJobQueue: -# Type: SQS -# Properties: -# Queue: !GetAtt CustomerNotificationServiceQueue.Arn -# BatchSize: 1 - - ExtraordinaryRidesService: - Type: AWS::Serverless::Function - Properties: - CodeUri: generic-backend-microservice/ - Handler: app.lambda_handler - Runtime: python3.6 - ReservedConcurrentExecutions: 5 - Environment: - Variables: - SERVICE_NAME: ExtraordinaryRidesService -# Policies: -# - SQSPollerPolicy: # https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json -# QueueName: !Ref ExtraordinaryRidesServiceQueue -# Events: -# ExtraordinaryRidesServiceJobQueue: -# Type: SQS -# Properties: -# Queue: !GetAtt ExtraordinaryRidesServiceQueue.Arn -# BatchSize: 1 - -# CustomerAccountingServiceQueue: -# Type: AWS::SQS::Queue - -# CustomerAccountingServiceQueuePolicy: -# Type: AWS::SQS::QueuePolicy -# Properties: -# Queues: -# - !Ref CustomerAccountingServiceQueue -# PolicyDocument: -# Statement: -# Effect: Allow -# Principal: '*' -# Action: sqs:SendMessage -# Resource: '*' -# Condition: -# ArnEquals: -# aws:SourceArn: !Ref RideCompletionTopic - -# CustomerAccountingServiceQueueToRidesTopicSubscription: -# Type: AWS::SNS::Subscription -# Properties: -# Endpoint: !GetAtt CustomerAccountingServiceQueue.Arn -# Protocol: sqs -# RawMessageDelivery: true -# TopicArn: !Ref RideCompletionTopic - -# CustomerNotificationServiceQueue: -# Type: AWS::SQS::Queue - -# CustomerNotificationServiceQueuePolicy: -# Type: AWS::SQS::QueuePolicy -# Properties: -# Queues: -# - !Ref CustomerNotificationServiceQueue -# PolicyDocument: -# Statement: -# Effect: Allow -# Principal: '*' -# Action: sqs:SendMessage -# Resource: '*' -# Condition: -# ArnEquals: -# aws:SourceArn: !Ref RideCompletionTopic - -# CustomerNotificationServiceQueueToRidesTopicSubscription: -# Type: AWS::SNS::Subscription -# Properties: -# Endpoint: !GetAtt CustomerNotificationServiceQueue.Arn -# Protocol: sqs -# RawMessageDelivery: true -# TopicArn: !Ref RideCompletionTopic - -# ExtraordinaryRidesServiceQueue: -# Type: AWS::SQS::Queue - -# ExtraordinaryRidesServiceQueuePolicy: -# Type: AWS::SQS::QueuePolicy -# Properties: -# Queues: -# - !Ref ExtraordinaryRidesServiceQueue -# PolicyDocument: -# Statement: -# Effect: Allow -# Principal: '*' -# Action: sqs:SendMessage -# Resource: '*' -# Condition: -# ArnEquals: -# aws:SourceArn: !Ref RideCompletionTopic - -# ExtraordinaryRidesServiceQueueToRidesTopicSubscription: -# Type: AWS::SNS::Subscription -# Properties: -# Endpoint: !GetAtt ExtraordinaryRidesServiceQueue.Arn -# Protocol: sqs -# RawMessageDelivery: true -# TopicArn: !Ref RideCompletionTopic -# FilterPolicy: { "fare": [{"numeric": [">=", 50]}], "distance": [{"numeric": [">=", 20]}] } - -Outputs: - # ServerlessRestApi is an implicit API created out of Events key under Serverless::Function - # Find out more about other implicit resources you can reference within SAM - # https://github.com/awslabs/serverless-application-model/blob/master/docs/internals/generated_resources.rst#api - UnicornManagementServiceApiSubmitRideCompletionEndpoint: - Description: "API Gateway endpoint URL for Prod stage for SubmitRideCompletion function" - Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/submit-ride-completion/" - - SubmitRideCompletionFunction: - Description: "SubmitRideCompletionFunction Lambda Function ARN" - Value: !GetAtt SubmitRideCompletionFunction.Arn - - CustomerAccountingService: - Description: "CustomerAccountingService Lambda Function ARN" - Value: !GetAtt CustomerAccountingService.Arn - - CustomerNotificationService: - Description: "CustomerNotificationService Lambda Function ARN" - Value: !GetAtt CustomerNotificationService.Arn - - ExtraordinaryRidesService: - Description: "ExtraordinaryRidesService Lambda Function ARN" - Value: !GetAtt ExtraordinaryRidesService.Arn - -# CustomerAccountingServiceQueue: -# Description: "Amazon SQS queue ARN for the CustomerAccounting service queue" -# Value: !Ref CustomerAccountingServiceQueue - -# CustomerNotificationServiceQueue: -# Description: "Amazon SQS queue ARN for the CustomerNotification service queue" -# Value: !Ref CustomerNotificationServiceQueue - -# ExtraordinaryRidesServiceQueue: -# Description: "Amazon SQS queue ARN for the ExtraordinaryRides service queue" -# Value: !Ref ExtraordinaryRidesServiceQueue \ No newline at end of file diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/bootstrap-initial-state.md b/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/bootstrap-initial-state.md deleted file mode 100644 index 343f716..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/bootstrap-initial-state.md +++ /dev/null @@ -1,59 +0,0 @@ -+++ -title = "Bootstrap the Initial State" -weight = 31 -pre = "1 " -+++ - - -First, we will setup the initial state, including the integrating of the **Unicorn Management Service** (leveraging [Amazon API Gateway](https://aws.amazon.com/api-gateway/) and [AWS Lambda](https://aws.amazon.com/lambda/)), the **Rides Store** (leveraging [Amazon DynamoDB](https://aws.amazon.com/dynamodb/)) and all **3 backend services** (leveraging [AWS Lambda](https://aws.amazon.com/lambda/)). - -![Step 1](step-1.png) - -#### 1. Browse to your AWS Cloud9 IDE - -Browse to your [AWS Cloud9 Console](https://console.aws.amazon.com/cloud9/home) and select the environment called **WildRydesAsyncMessaging**. - -{{%expand "Detailed description" %}} -![Step 2](step-2.png) -{{% /expand%}} - -#### 2. Build the lab artifacts from source - -We provide you with an [AWS SAM](https://aws.amazon.com/serverless/sam/) template which we will use to bootstrap the initial state. In the **bash tab** (at the bottom) in you **AWS Cloud9 IDE**, run the following commands to build the lab code: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-2 -sam build - -{{< /highlight >}} - -{{%expand "Detailed description" %}} -![Step 4](step-4.png) -{{% /expand%}} - -#### 3. Deploy the application - -Now we are ready to deploy the application, by running the following command in the **lab-2** directory: - -{{< highlight bash >}} -export AWS_REGION=$(aws --profile default configure get region) -sam deploy \ - --stack-name wild-rydes-async-msg-2 \ - --capabilities CAPABILITY_IAM \ - --region $AWS_REGION \ - --guided -{{< /highlight >}} - -Confirm the first 4 proposed arguments by hitting **ENTER**. When you get asked **SubmitRideCompletionFunction may not have authorization defined, Is this okay? [y/N]:**, enter `y` and hit **ENTER** again 3 times. - -#### 4. Wait until the stack is successfully deployed - -It takes usually 4 minutes until the stack launched. You can monitor the progress of the **wild-rydes-async-msg-2** stack in your SAM CLI or your [AWS CloudFormation Console](https://console.aws.amazon.com/cloudformation). When the stack is launched, the status will change from **CREATE_IN_PROGRESS** to **CREATE_COMPLETE**. - -{{%expand "Detailed description" %}} -![Step 7](step-7.png) -{{% /expand%}} - -In the meantime while your waiting, you may want to have a look at the AWS SAM template to make yourself familiar with the stack we launched. Just click on the **template.yaml** attachment below to see the content. - -{{%attachments title="Related files" pattern="/*.*(yaml)"/%}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-1.png b/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-1.png deleted file mode 100644 index c419a8a..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-1.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-2.png b/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-2.png deleted file mode 100644 index 558e235..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-2.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-3.png b/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-3.png deleted file mode 100644 index 50c016e..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-3.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-4.png b/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-4.png deleted file mode 100644 index 78ad62b..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-4.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-5.png b/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-5.png deleted file mode 100644 index 930656b..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-5.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-6.png b/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-6.png deleted file mode 100644 index 8b2db5c..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-6.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-7.png b/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-7.png deleted file mode 100644 index 4a8f86e..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/bootstrap-initial-state/step-7.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/clean-up-console.md b/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/clean-up-console.md deleted file mode 100644 index 39f098e..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/clean-up-console.md +++ /dev/null @@ -1,20 +0,0 @@ -+++ -title = "Console" - -disableToc = true -hidden = true -+++ - - - - -#### 4. Delete the Amazon SNS topic - -In your **[Amazon SNS console](https://console.aws.amazon.com/sns/v3/home?#/topics)**, select **Topic** in the left navigation pane, select the **RideCompletionTopic** and click the **Delete** button in the top right corner. - -{{%expand "Detailed description" %}} -![Step 2](step-2-console.png) -{{% /expand%}} - - -You are done! diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/clean-up-sam.md b/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/clean-up-sam.md deleted file mode 100644 index 8cd7015..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/clean-up-sam.md +++ /dev/null @@ -1,17 +0,0 @@ -+++ -title = "SAM" - -disableToc = true -hidden = true -+++ - - -#### 3. Delete the Amazon S3 bucket - -In your Cloud9 IDE, run the following command to delete the Amazon S3 bucket we created earlier: - -{{< highlight bash >}} -aws s3 rb s3://${BUCKET_NAME} —-force -{{< /highlight >}} - -You are done! diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/clean-up.md b/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/clean-up.md deleted file mode 100644 index 2834a47..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/clean-up.md +++ /dev/null @@ -1,28 +0,0 @@ -+++ -title = "Clean up" -weight = 38 -pre = "8 " -+++ - -In this step, we will clean up all resources, we created during this lab, so that no further cost will occur. - -#### 1. Delete the previously created IAM Inline Policies - -In your Amazon IAM console, select **[Roles](https://console.aws.amazon.com/iamv2/home#/roles)** in the left navigation. In the search field, enter "async-msg". Open all matching roles and delete the previously created inline policies by clicking the "x" right to the policy name. - -#### 2. Delete the AWS SAM template - -In your Cloud9 IDE, run the following command to delete the resources we created with our AWS SAM template: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-2 -aws cloudformation delete-stack \ - --stack-name wild-rydes-async-msg-2 - -{{< /highlight >}} - - -#### 3. Delete the AWS Lambda created Amazon CloudWatch Log Group - -Follow **[this deep link](https://console.aws.amazon.com/cloudwatch/home?#logs:prefix=/aws/lambda/wild-rydes-async-msg-2)** to list all **Amazon CloudWatch Log Groups** with the prefix `/aws/lambda/wild-rydes-async-msg-2`, AWS Lambda created during this lab. Select all the Amazon CloudWatch Log Group one after each other and choose **Delete log group** from the **Actions** menu. - diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/step-1-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/step-1-console.png deleted file mode 100644 index f04b02a..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/step-1-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/step-1.png b/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/step-1.png deleted file mode 100644 index d2690fa..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/step-1.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/step-2-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/step-2-console.png deleted file mode 100644 index 49f409c..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/clean-up/step-2-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-console.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-console.md deleted file mode 100644 index f2cdb12..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-console.md +++ /dev/null @@ -1,124 +0,0 @@ -+++ -title = "Console" -disableToc = true -hidden = true -+++ - -#### 1. Create a new Amazon SQS queue - -In your **[Amazon SQS console](https://console.aws.amazon.com/sqs/home?)**, select **Create New Queue** in top left corner or click **Get Started Now** in the center of the page, if it's your first queue in this region. - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - -Enter `CustomerAccountingServiceQueue` as **Queue Name**, make sure **Standard Queue** is highlighted and click **Create Queue**. - -{{%expand "Screenshot" %}} -![Step 2](step-2-console.png) -{{% /expand%}} - -#### 2. Create a new subscription - -After creating the queue **CustomerAccountingServiceQueue**, click the **Subscribe to Amazon SNS Topic** button in the SNS Subscriptions tab. - -{{%expand "Detailed description" %}} -![Step 3](step-3-console.png) -{{% /expand%}} - -In the Subscribe to Amazon SNS topic window, select the **RideCompletionTopic** and click **Save**. - -{{%expand "Detailed description" %}} -![Step 4](step-4-console.png) -{{% /expand%}} - -#### 3. Validate the subscription and add the filter to the subscription - -Select the newly created subscription from the SNS subscriptions list and click the **View in SNS** button (this should open a new tab to the subscription in the **[Amazon SNS console](https://console.aws.amazon.com/sns/v3/home?#/topics)**). - -{{%expand "Detailed description" %}} -![Step 5](step-5-console.png) -{{% /expand%}} - -Confirm that the Status of the subscription is **Confirmed**. - -{{%expand "Detailed description" %}} -![Step 5](step-5-1-console.png) -{{% /expand%}} - -Click **Edit** to modify the subscription. - -In the Edit subscription screen, click **Enable raw message delivery**. Click **Save Changes** - -{{%expand "Detailed description" %}} -![Step 6](step-5-2-console.png) -{{% /expand%}} - -Now that we have updated the subscription, let's set the IAM policy for our Lambda function to access the queue. - -#### 4. Grant permissions to our function to access the Amazon SQS queue - -In your **[Amazon IAM console](https://console.aws.amazon.com/iam)**, select **Roles** in the left navigation. Use the filter text box to find the role with the name **wild-rydes-async-msg-2-CustomerAccountingService-...** (assuming your have chosen `wild-rydes-async-msg-2` as your stack name). - -{{%expand "Detailed description" %}} -![Step 6](step-6-console.png) -{{% /expand%}} - -Click on the role name and click **Add inline policy** to attach another one. - -{{%expand "Detailed description" %}} -![Step 7](step-7-console.png) -{{% /expand%}} - -Select the **JSON** tab and passed the following policy statement into it, after you have substitute <<...>> with the correct values. It will add the permission to your Lambda function to access the Amazon SQS queue: - -{{%expand "policy" %}} -```bash -{ - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "sqs:ChangeMessageVisibility", - "sqs:ChangeMessageVisibilityBatch", - "sqs:DeleteMessage", - "sqs:DeleteMessageBatch", - "sqs:GetQueueAttributes", - "sqs:ReceiveMessage" - ], - "Resource": "arn:aws:sqs:<>:<>:CustomerAccountingServiceQueue" - } - ] -} -``` -{{% /expand%}} - -{{% notice tip %}} -Make sure you provide the AWS ACCOUNT ID in the form of XXXXXXXXXXXX and not XXXX-XXXX-XXXX! -{{% /notice %}} - -Click **Review policy** and enter the **Name** `CustomerAccountingServiceRolePolicy0`. Click **Create policy**. To validate this step, select on the role again and your should see 2 policies attached to your role, including the one you just have created: - -{{%expand "Detailed description" %}} -![Step 8](step-8-console.png) -{{% /expand%}} - -#### 5. Add the Amazon SQS queue as event source for your Customer Accounting Service AWS Lambda function - -Open your **[AWS Lambda console](https://console.aws.amazon.com/lambda/home?#/functions)** and select **Functions** in the left navigation. Click on the function with the name **wild-rydes-async-msg-2-CustomerAccounting...** (assuming your have chosen `wild-rydes-async-msg-2` as your stack name). Click on the **+ Add Trigger** button on the left side of the page: - -{{%expand "Detailed description" %}} -![Step 9](step-9-console.png) -{{% /expand%}} - -On the following page, select `SQS` as the event source for this AWS Lambda function. For the **SQS queue**, select the `CustomerAccountingServiceQueue` and set the **batch size** to `1`. Don't forget to **enable the trigger**, before you click the **Add** button in the lower right corner. - -{{%expand "Detailed description" %}} -![Step 10](step-10-console.png) -{{% /expand%}} - -After some seconds, the trigger will be enabled and and you are ready to go (you may have to refresh the site a few times). - -{{%expand "Detailed description" %}} -![Step 11](step-11-console.png) -{{% /expand%}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-sam.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-sam.md deleted file mode 100644 index 42a9fd8..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription-sam.md +++ /dev/null @@ -1,98 +0,0 @@ -+++ -title = "SAM" -disableToc = true -hidden = true -+++ - -#### 1. Update the AWS SAM template - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-2/template.yaml`. In the **Resources** section, add the definition for an Amazon SQS queue with the name **CustomerAccountingServiceQueue**, the **CustomerAccountingService** will use to consume messages from. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html)**. - -{{%expand "Cheat Sheet" %}} -```yaml - CustomerAccountingServiceQueue: - Type: AWS::SQS::Queue -``` -{{% /expand%}} - -The next step, before we can define the subscription, is granting our Amazon SNS topic the permissions to publish messages into this Amazon SQS queue. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-policy.html)**. - -{{%expand "Cheat Sheet" %}} -```yaml - CustomerAccountingServiceQueuePolicy: - Type: AWS::SQS::QueuePolicy - Properties: - Queues: - - !Ref CustomerAccountingServiceQueue - PolicyDocument: - Statement: - Effect: Allow - Principal: '*' - Action: sqs:SendMessage - Resource: '*' - Condition: - ArnEquals: - aws:SourceArn: !Ref RideCompletionTopic -``` -{{% /expand%}} - -Now we are ready to create the Amazon SNS subscription for the **CustomerAccountingService**. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sns-subscription.html)**. - -{{%expand "Cheat Sheet" %}} -```yaml - CustomerAccountingServiceQueueToRidesTopicSubscription: - Type: AWS::SNS::Subscription - Properties: - Endpoint: !GetAtt CustomerAccountingServiceQueue.Arn - Protocol: sqs - RawMessageDelivery: true - TopicArn: !Ref RideCompletionTopic -``` -{{% /expand%}} - -The next step is to attach an AWS IAM policy tou our **CustomerAccountingService** AWS Lambda function, which grants permission to access our previously created Amazon SQS queue, to consume the messages. You can find the AWS SAM documentation to do so **[here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template.html#serverless-sam-template-function)** and **[here](https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json)**. - -{{%expand "Cheat Sheet" %}} -```yaml - Policies: - - SQSPollerPolicy: - QueueName: !Ref CustomerAccountingServiceQueue -``` -{{% /expand%}} - -Last but not least, we have to declare the **CustomerAccountingServiceQueue** as event source for our **CustomerAccountingService**. You can find the AWS SAM documentation to do so **[here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template.html#serverless-sam-template-function)**. - -{{%expand "Cheat Sheet" %}} -```yaml - Events: - CustomerAccountingServiceJobQueue: - Type: SQS - Properties: - Queue: !GetAtt CustomerAccountingServiceQueue.Arn - BatchSize: 1 -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 1](step-1-sam.png) - -![Step 2](step-2-sam.png) -{{% /expand%}} - -#### 2. Deploy the updated AWS SAM template - -Run the following command to build the lab again, after we have added the Amazon SQS queue and the Amazon SNS subscription: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-2 -sam build - -{{< /highlight >}} - -{{< highlight bash >}} -sam deploy -{{< /highlight >}} - -In the meantime while your waiting, you may want to have a look at the AWS SAM template to make yourself familiar with the stack we launched. Just click on the **template.yaml** attachment below to see the content. - -Because AWS SAM will only deploy/update/delete resources which are changed, it only takes a couple of seconds to deploy the new Amazon SQS queue and the Amazon SNS subscription. diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription.md deleted file mode 100644 index 38ae91a..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/create-customer-accounting-service-subscription.md +++ /dev/null @@ -1,12 +0,0 @@ -+++ -title = "Create Customer Accounting Service Subscription" -weight = 34 -pre = "4 " -+++ - -In this step, we will create an Amazon SQS queue for the **Customer Accounting Service** and add a subscription to the Amazon SNS topic we created before: - -{{< tabs name="Style" >}} -{{< tab name="Console" include="create-customer-accounting-service-subscription-console" />}} -{{< tab name="SAM" include="create-customer-accounting-service-subscription-sam" />}} -{{< /tabs >}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-1-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-1-console.png deleted file mode 100644 index 4bdc249..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-1-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-1-sam.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-1-sam.png deleted file mode 100644 index aa8244d..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-1-sam.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-10-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-10-console.png deleted file mode 100644 index 7be5d7b..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-10-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-11-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-11-console.png deleted file mode 100644 index ad031c8..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-11-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-2-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-2-console.png deleted file mode 100644 index 52bc1be..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-2-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-2-sam.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-2-sam.png deleted file mode 100644 index 4425d24..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-2-sam.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-3-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-3-console.png deleted file mode 100644 index 2147217..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-3-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-4-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-4-console.png deleted file mode 100644 index 5e4204c..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-4-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-5-1-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-5-1-console.png deleted file mode 100644 index c09527d..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-5-1-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-5-2-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-5-2-console.png deleted file mode 100644 index 14d7400..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-5-2-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-5-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-5-console.png deleted file mode 100644 index 35daac4..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-5-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-6-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-6-console.png deleted file mode 100644 index aa4e7e3..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-6-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-7-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-7-console.png deleted file mode 100644 index 3ab02d7..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-7-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-8-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-8-console.png deleted file mode 100644 index 9fe926b..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-8-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-9-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-9-console.png deleted file mode 100644 index 99fb540..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-accounting-service-subscription/step-9-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/create-customer-notification-service-subscription-console.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/create-customer-notification-service-subscription-console.md deleted file mode 100644 index 58f44e1..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/create-customer-notification-service-subscription-console.md +++ /dev/null @@ -1,129 +0,0 @@ -+++ -title = "Console" -disableToc = true -hidden = true -+++ - -#### 1. Create a new Amazon SQS queue - -In your **[Amazon SQS console](https://console.aws.amazon.com/sqs/home?)**, select **Create New Queue** in top left corner or click **Get Started Now** in the center of the page, if it's your first queue in this region. - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - -Enter `CustomerNotificationServiceQueue` as **Queue Name**, make sure **Standard Queue** is highlighted and click **Create Queue**. - -{{%expand "Detailed description" %}} -![Step 2](step-2-console.png) -{{% /expand%}} - -#### 2. Create a new subscription - -After creating the queue **CustomerNotificationServiceQueue**, click the **Subscribe to Amazon SNS Topic** button in the SNS Subscriptions tab. - -{{%expand "Detailed description" %}} -![Step 3](step-3-console.png) -{{% /expand%}} - -In the Subscribe to Amazon SNS topic window, select the **RideCompletionTopic** and click **Save**. - -{{%expand "Detailed description" %}} -![Step 4](step-4-console.png) -{{% /expand%}} - -{{% notice tip %}} -You may wondering why we don't create the subscription from the Amazon SNS console as shown below. If we create a subscription from Amazon SNS to Amazon SQS, Amazon SNS will send a confirmation message first to Amazon SQS. As long as this subscription is not confirmed, Amazon SNS will not start sending messages to Amazon SQS. -By initiating the subscription from the subscriber side, this is not necessary. -{{% /notice %}} - -#### 3. Validate the subscription and add the filter to the subscription - -Select the newly created subscription from the SNS subscriptions list and click the **View in SNS** button (this should open a new tab to the subscription in the **[Amazon SNS console](https://console.aws.amazon.com/sns/v3/home?#/topics)**). - -{{%expand "Detailed description" %}} -![Step 4](step-5-console.png) -{{% /expand%}} - -Confirm that the Status of the subscription is **Confirmed**. - -{{%expand "Detailed description" %}} -![Step 4](step-5-1-console.png) -{{% /expand%}} - -Click **Edit** to modify the subscription. - -In the Edit subscription screen, click **Enable raw message delivery**. Click **Save Changes** - -{{%expand "Detailed description" %}} -![Step 6](step-5-2-console.png) -{{% /expand%}} - -Now that we have updated the subscription, let's set the IAM policy for our Lambda function to access the queue. - -#### 4. Grant permissions to our function to access the Amazon SQS queue - -In your **[Amazon IAM console](https://console.aws.amazon.com/iam)**, select **Roles** in the left navigation. Use the filter text box to find the role with the name **wild-rydes-async-msg-2-CustomerNotificationService-...** (assuming your have chosen `wild-rydes-async-msg-2` as your stack name). - -{{%expand "Detailed description" %}} -![Step 6](step-6-console.png) -{{% /expand%}} - -Click on the role name and click **Add inline policy** to attach another one. - -{{%expand "Detailed description" %}} -![Step 7](step-7-console.png) -{{% /expand%}} - -Select the **JSON** tab and passed the following policy statement into it, after you have substitute <<...>> with the correct values. It will add the permission to your Lambda function to access the Amazon SQS queue: - -{{%expand "policy" %}} -```bash -{ - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "sqs:ChangeMessageVisibility", - "sqs:ChangeMessageVisibilityBatch", - "sqs:DeleteMessage", - "sqs:DeleteMessageBatch", - "sqs:GetQueueAttributes", - "sqs:ReceiveMessage" - ], - "Resource": "arn:aws:sqs:<>:<>:CustomerNotificationServiceQueue" - } - ] -} -``` -{{% /expand%}} - -{{% notice tip %}} -Make sure you provide the AWS ACCOUNT ID in the form of XXXXXXXXXXXX and not XXXX-XXXX-XXXX! -{{% /notice %}} - -Click **Review policy** and enter the **Name** `CustomerNotificationServiceRolePolicy0`. Click **Create policy**. To validate this step, select on the role again and your should see 2 policies attached to your role, including the one you just have created: - -{{%expand "Detailed description" %}} -![Step 8](step-8-console.png) -{{% /expand%}} - -#### 5. Add the Amazon SQS queue as event source for your Customer Notification Service AWS Lambda function - -Open your **[AWS Lambda console](https://console.aws.amazon.com/lambda/home?#/functions)** and select **Functions** in the left navigation. Click on the function with the name **wild-rydes-async-msg-2-CustomerNotification...** (assuming your have chosen `wild-rydes-async-msg-2` as your stack name). Click on the **+ Add Trigger** button on the left side of the page: - -{{%expand "Detailed description" %}} -![Step 9](step-9-console.png) -{{% /expand%}} - -On the following page, select `SQS` as the event source for this AWS Lambda function. For the **SQS queue**, select the `CustomerNotificationServiceQueue` and set the **batch size** to `1`. Don't forget to **enable the trigger**, before you click the **Add** button in the lower right corner. - -{{%expand "Detailed description" %}} -![Step 10](step-10-console.png) -{{% /expand%}} - -After some seconds, the trigger will be enabled and and you are ready to go (you may have to refresh the site a few times). - -{{%expand "Detailed description" %}} -![Step 11](step-11-console.png) -{{% /expand%}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/create-customer-notification-service-subscription-sam.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/create-customer-notification-service-subscription-sam.md deleted file mode 100644 index 9404ef6..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/create-customer-notification-service-subscription-sam.md +++ /dev/null @@ -1,100 +0,0 @@ -+++ -title = "SAM" -disableToc = true -hidden = true -+++ - -#### 1. Update the AWS SAM template - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-2/template.yaml`. In the **Resources** section, add the definition for an Amazon SQS queue with the name **CustomerNotificationServiceQueue**, the **CustomerNotificationService** will use to consume messages from. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html)**. - -{{%expand "Cheat Sheet" %}} -```yaml - CustomerNotificationServiceQueue: - Type: AWS::SQS::Queue -``` -{{% /expand%}} - -The next step, before we can define the subscription, is granting our Amazon SNS topic the permissions to publish messages into this Amazon SQS queue. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-policy.html)**. - -{{%expand "Cheat Sheet" %}} -```yaml - CustomerNotificationServiceQueuePolicy: - Type: AWS::SQS::QueuePolicy - Properties: - Queues: - - !Ref CustomerNotificationServiceQueue - PolicyDocument: - Statement: - Effect: Allow - Principal: '*' - Action: sqs:SendMessage - Resource: '*' - Condition: - ArnEquals: - aws:SourceArn: !Ref RideCompletionTopic -``` -{{% /expand%}} - -Now we are ready to create the Amazon SNS subscription for the **CustomerNotificationService**. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sns-subscription.html)**. - -{{%expand "Cheat Sheet" %}} -```yaml - CustomerNotificationServiceQueueToRidesTopicSubscription: - Type: AWS::SNS::Subscription - Properties: - Endpoint: !GetAtt CustomerNotificationServiceQueue.Arn - Protocol: sqs - RawMessageDelivery: true - TopicArn: !Ref RideCompletionTopic -``` -{{% /expand%}} - -The next step is to attach an AWS IAM policy tou our **CustomerNotificationService** AWS Lambda function, which grants permission to access our previously created Amazon SQS queue, to consume the messages. You can find the AWS SAM documentation to do so **[here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template.html#serverless-sam-template-function)** and **[here](https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json)**. - -{{%expand "Cheat Sheet" %}} -```yaml - Policies: - - SQSPollerPolicy: - QueueName: !Ref CustomerNotificationServiceQueue -``` -{{% /expand%}} - -Last but not least, we have to declare the **CustomerNotificationServiceQueue** as event source for our **CustomerNotificationService**. You can find the AWS SAM documentation to do so **[here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template.html#serverless-sam-template-function)**. - -{{%expand "Cheat Sheet" %}} -```yaml - Events: - CustomerNotificationServiceJobQueue: - Type: SQS - Properties: - Queue: !GetAtt CustomerNotificationServiceQueue.Arn - BatchSize: 1 -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 1](step-1-sam.png) - -![Step 2](step-2-sam.png) -{{% /expand%}} - -#### 2. Deploy the updated AWS SAM template - -Run the following command to build the lab again, after we have added the Amazon SQS queue and the Amazon SNS subscription: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-2 -sam build - -{{< /highlight >}} - -Now we are ready to update the application, by running the following command to deploy the change: - -{{< highlight bash >}} -sam deploy -{{< /highlight >}} - -In the meantime while your waiting, you may want to have a look at the AWS SAM template to make yourself familiar with the stack we launched. Just click on the **template.yaml** attachment below to see the content. - -Because AWS SAM will only deploy/update/delete resources which are changed, it only takes a couple of seconds to deploy the new Amazon SQS queue and the Amazon SNS subscription. diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/create-customer-notification-service-subscription.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/create-customer-notification-service-subscription.md deleted file mode 100644 index 00e70ce..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/create-customer-notification-service-subscription.md +++ /dev/null @@ -1,12 +0,0 @@ -+++ -title = "Create Customer Notification Service Subscription" -weight = 33 -pre = "3 " -+++ - -In this step, we will create an **Amazon SQS** queue for the **Customer Notification Service** and add a subscription to the Amazon SNS topic we created before: - -{{< tabs name="Style" >}} -{{< tab name="Console" include="create-customer-notification-service-subscription-console" />}} -{{< tab name="SAM" include="create-customer-notification-service-subscription-sam" />}} -{{< /tabs >}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-1-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-1-console.png deleted file mode 100644 index 4bdc249..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-1-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-1-sam.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-1-sam.png deleted file mode 100644 index f988d69..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-1-sam.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-10-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-10-console.png deleted file mode 100644 index dc8f048..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-10-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-11-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-11-console.png deleted file mode 100644 index 5f7a208..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-11-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-2-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-2-console.png deleted file mode 100644 index 491351b..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-2-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-2-sam.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-2-sam.png deleted file mode 100644 index 62a6eca..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-2-sam.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-3-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-3-console.png deleted file mode 100644 index ef9feac..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-3-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-4-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-4-console.png deleted file mode 100644 index 3e902bd..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-4-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-5-1-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-5-1-console.png deleted file mode 100644 index 8e0dd8d..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-5-1-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-5-2-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-5-2-console.png deleted file mode 100644 index 4e450ac..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-5-2-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-5-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-5-console.png deleted file mode 100644 index 35daac4..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-5-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-6-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-6-console.png deleted file mode 100644 index 37d1fd5..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-6-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-7-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-7-console.png deleted file mode 100644 index 3ab02d7..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-7-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-8-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-8-console.png deleted file mode 100644 index c0edeea..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-8-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-9-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-9-console.png deleted file mode 100644 index 8a5464a..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/step-9-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/tip.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/tip.png deleted file mode 100644 index 980fabc..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-customer-notification-service-subscription/tip.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-console.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-console.md deleted file mode 100644 index d6c1dd0..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-console.md +++ /dev/null @@ -1,133 +0,0 @@ -+++ -title = "Console" -disableToc = true -hidden = true -+++ - -#### 1. Create a new Amazon SQS queue - -In your **[Amazon SQS console](https://console.aws.amazon.com/sqs/home?)**, select **Create New Queue** in top left corner or click **Get Started Now** in the center of the page, if it's your first queue in this region. - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - -Enter `ExtraordinaryRidesServiceQueue` as **Queue Name**, make sure **Standard Queue** is highlighted and click **Create Queue**. - -{{%expand "Detailed description" %}} -![Step 2](step-2-console.png) -{{% /expand%}} - -#### 2. Create a new subscription - -After creating the queue **ExtraordinaryRidesServiceQueue**, click the **Subscribe to Amazon SNS Topic** button in the SNS Subscriptions tab. - -{{%expand "Detailed description" %}} -![Step 3](step-3-console.png) -{{% /expand%}} - -In the Subscribe to Amazon SNS topic window, select the **RideCompletionTopic** and click **Save**. - -{{%expand "Detailed description" %}} -![Step 4](step-4-console.png) -{{% /expand%}} - -#### 3. Validate the subscription and add the filter to the subscription - -Select the newly created subscription from the SNS subscriptions list and click the **View in SNS** button (this should open a new tab to the subscription in the **[Amazon SNS console](https://console.aws.amazon.com/sns/v3/home?#/topics)**). - -{{%expand "Detailed description" %}} -![Step 4](step-5-console.png) -{{% /expand%}} - -Confirm that the Status of the subscription is **Confirmed**. - -{{%expand "Detailed description" %}} -![Step 4](step-5-1-console.png) -{{% /expand%}} - -Click **Edit** to modify the subscription. - -In the Edit subscription screen, click **Enable raw message delivery**. - -In the subscription filter policy section, add the filter policy. Click **Save changes**. - -{{< highlight json >}} -{ - "fare": [{"numeric": [">=", 50]}], - "distance": [{"numeric": [">=", 20]}] -} -{{< /highlight >}} - -{{%expand "Detailed description" %}} -![Step 6](step-6-console.png) -{{% /expand%}} - -Now that we have updated the subscription, let's set the IAM policy for our Lambda function to access the queue. - -#### 5. Grant permissions to our function to access the Amazon SQS queue - -In your **[Amazon IAM console](https://console.aws.amazon.com/iam)**, select **Roles** in the left navigation. Use the filter text box to find the role with the name **wild-rydes-async-msg-2-ExtraordinaryRidesService-...** (assuming your have chosen `wild-rydes-async-msg-2` as your stack name). - -{{%expand "Detailed description" %}} -![Step 7](step-7-console.png) -{{% /expand%}} - -Click on the role name and click **Add inline policy** to attach another one. - -{{%expand "Detailed description" %}} -![Step 8](step-8-console.png) -{{% /expand%}} - -Select the **JSON** tab and passed the following policy statement into it, after you have substitute <<...>> with the correct values. It will add the permission to your Lambda function to access the Amazon SQS queue: - -{{%expand "policy" %}} -```bash -{ - "Statement": [ - { - "Effect": "Allow", - "Action": [ - "sqs:ChangeMessageVisibility", - "sqs:ChangeMessageVisibilityBatch", - "sqs:DeleteMessage", - "sqs:DeleteMessageBatch", - "sqs:GetQueueAttributes", - "sqs:ReceiveMessage" - ], - "Resource": "arn:aws:sqs:<>:<>:ExtraordinaryRidesServiceQueue" - } - ] -} -``` -{{% /expand%}} - -{{% notice tip %}} -Make sure you provide the AWS ACCOUNT ID in the form of XXXXXXXXXXXX and not XXXX-XXXX-XXXX! -{{% /notice %}} - -Click **Review policy** and enter the **Name** `ExtraordinaryRidesServiceRolePolicy0`. Click **Create policy**. To validate this step, select on the role again and your should see 2 policies attached to your role, including the one you just have created: - -{{%expand "Detailed description" %}} -![Step 9](step-9-console.png) -{{% /expand%}} - -#### 6. Add the Amazon SQS queue as event source for your Extraordinary Rides Service AWS Lambda function - -Open your **[AWS Lambda console](https://console.aws.amazon.com/lambda/home?#/functions)** and select **Functions** in the left navigation. Click on the function with the name **wild-rydes-async-msg-2-ExtraordinaryRides...** (assuming your have chosen `wild-rydes-async-msg-2` as your stack name). Click on the **+ Add Trigger** button on the left side of the page: - -{{%expand "Detailed description" %}} -![Step 10](step-10-console.png) -{{% /expand%}} - -On the following page, select `SQS` as the event source for this AWS Lambda function. For the **SQS queue**, select the `ExtraordinaryRidesServiceQueue` and set the **batch size** to `1`. Don't forget to **enable the trigger**, before you click the **Add** button in the lower right corner. - -{{%expand "Detailed description" %}} -![Step 11](step-11-console.png) -{{% /expand%}} - -After some seconds, the trigger will be enabled and and you are ready to go (you may have to refresh the site a few times). - -{{%expand "Detailed description" %}} -![Step 12](step-12-console.png) -{{% /expand%}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-sam.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-sam.md deleted file mode 100644 index 6c46693..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription-sam.md +++ /dev/null @@ -1,101 +0,0 @@ -+++ -title = "SAM" -disableToc = true -hidden = true -+++ - -#### 1. Update the AWS SAM template - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-2/template.yaml`. In the **Resources** section, add the definition for an Amazon SQS queue with the name **ExtraordinaryRidesServiceQueue**, the **ExtraordinaryRidesService** will use to consume messages from. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-queues.html)**. - -{{%expand "Cheat Sheet" %}} -```yaml - ExtraordinaryRidesServiceQueue: - Type: AWS::SQS::Queue -``` -{{% /expand%}} - -The next step, before we can define the subscription, is granting our Amazon SNS topic the permissions to publish messages into this Amazon SQS queue. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sqs-policy.html)**. - -{{%expand "Cheat Sheet" %}} -```yaml - ExtraordinaryRidesServiceQueuePolicy: - Type: AWS::SQS::QueuePolicy - Properties: - Queues: - - !Ref ExtraordinaryRidesServiceQueue - PolicyDocument: - Statement: - Effect: Allow - Principal: '*' - Action: sqs:SendMessage - Resource: '*' - Condition: - ArnEquals: - aws:SourceArn: !Ref RideCompletionTopic -``` -{{% /expand%}} - -Now we are ready to create the Amazon SNS subscription for the **ExtraordinaryRidesService**. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-sns-subscription.html)**. - -{{%expand "Cheat Sheet" %}} -```yaml - ExtraordinaryRidesServiceQueueToRidesTopicSubscription: - Type: AWS::SNS::Subscription - Properties: - Endpoint: !GetAtt ExtraordinaryRidesServiceQueue.Arn - Protocol: sqs - RawMessageDelivery: true - TopicArn: !Ref RideCompletionTopic - FilterPolicy: { "fare": [{"numeric": [">=", 50]}], "distance": [{"numeric": [">=", 20]}] } -``` -{{% /expand%}} - -The next step is to attach an AWS IAM policy tou our **ExtraordinaryRidesService** AWS Lambda function, which grants permission to access our previously created Amazon SQS queue, to consume the messages. You can find the AWS SAM documentation to do so **[here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template.html#serverless-sam-template-function)** and **[here](https://github.com/awslabs/serverless-application-model/blob/develop/samtranslator/policy_templates_data/policy_templates.json)**. - -{{%expand "Cheat Sheet" %}} -```yaml - Policies: - - SQSPollerPolicy: - QueueName: !Ref ExtraordinaryRidesServiceQueue -``` -{{% /expand%}} - -Last but not least, we have to declare the **ExtraordinaryRidesServiceQueue** as event source for our **ExtraordinaryRidesService**. You can find the AWS SAM documentation to do so **[here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-template.html#serverless-sam-template-function)**. - -{{%expand "Cheat Sheet" %}} -```yaml - Events: - ExtraordinaryRidesServiceJobQueue: - Type: SQS - Properties: - Queue: !GetAtt ExtraordinaryRidesServiceQueue.Arn - BatchSize: 1 -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 1](step-1-sam.png) - -![Step 2](step-2-sam.png) -{{% /expand%}} - -#### 2. Deploy the updated AWS SAM template - -Run the following command to build the lab again, after we have added the Amazon SQS queue and the Amazon SNS subscription: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-2 -sam build - -{{< /highlight >}} - -Now we are ready to update the application, by running the following command to deploy the change: - -{{< highlight bash >}} -sam deploy -{{< /highlight >}} - -In the meantime while your waiting, you may want to have a look at the AWS SAM template to make yourself familiar with the stack we launched. Just click on the **template.yaml** attachment below to see the content. - -Because AWS SAM will only deploy/update/delete resources which are changed, it only takes a couple of seconds to deploy the new Amazon SQS queue and the Amazon SNS subscription. diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription.md deleted file mode 100644 index 524603a..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/create-extraordinary-rides-service-subscription.md +++ /dev/null @@ -1,12 +0,0 @@ -+++ -title = "Create Extraordinary Rides Service Subscription" -weight = 35 -pre = "5 " -+++ - -In this step, we will create an Amazon SQS queue for the **Extraordinary Rides Service** and add a subscription to the Amazon SNS topic we created before: - -{{< tabs name="Style" >}} -{{< tab name="Console" include="create-extraordinary-rides-service-subscription-console" />}} -{{< tab name="SAM" include="create-extraordinary-rides-service-subscription-sam" />}} -{{< /tabs >}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-1-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-1-console.png deleted file mode 100644 index 4bdc249..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-1-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-1-sam.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-1-sam.png deleted file mode 100644 index cea8d5a..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-1-sam.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-10-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-10-console.png deleted file mode 100644 index 4dda4eb..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-10-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-11-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-11-console.png deleted file mode 100644 index ed249b5..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-11-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-12-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-12-console.png deleted file mode 100644 index 5638276..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-12-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-2-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-2-console.png deleted file mode 100644 index 66870e9..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-2-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-2-sam.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-2-sam.png deleted file mode 100644 index b17e533..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-2-sam.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-3-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-3-console.png deleted file mode 100644 index cd74e5d..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-3-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-4-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-4-console.png deleted file mode 100644 index 684b3d7..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-4-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-5-1-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-5-1-console.png deleted file mode 100644 index 65d0bc2..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-5-1-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-5-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-5-console.png deleted file mode 100644 index 35daac4..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-5-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-6-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-6-console.png deleted file mode 100644 index 0988597..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-6-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-7-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-7-console.png deleted file mode 100644 index 6d54d4e..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-7-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-8-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-8-console.png deleted file mode 100644 index 3ab02d7..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-8-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-9-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-9-console.png deleted file mode 100644 index 10599e6..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-extraordinary-rides-service-subscription/step-9-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/create-sns-topic-console.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/create-sns-topic-console.md deleted file mode 100644 index 3f7cb8a..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/create-sns-topic-console.md +++ /dev/null @@ -1,23 +0,0 @@ -+++ -title = "Console" - -disableToc = true -hidden = true -+++ - -#### 1. Browse to the Amazon SNS console - -In your [Amazon SNS console](https://console.aws.amazon.com/sns/v3/home?#/topics), select **Topic** in the left navigation pane and click the **Create topic** button in the top right corner. - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - - -#### 2. Create the Ride Completion Topic - -Enter the topic name **RideCompletionTopic** and leave the default values. Scroll to the bottom of the page and click **Create topic**. - -{{%expand "Detailed description" %}} -![Step 2](step-2-console.png) -{{% /expand%}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/create-sns-topic-sam.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/create-sns-topic-sam.md deleted file mode 100644 index 089e27a..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/create-sns-topic-sam.md +++ /dev/null @@ -1,47 +0,0 @@ -+++ -title = "SAM" - -disableToc = true -hidden = true -+++ - -#### 1. Update the AWS SAM template - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-2/template.yaml`. In the **Resources** section, add the definition for an Amazon SNS topic with the name RideCompletionTopic. You can find the AWS CloudFormation documentation to do so **[here](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-sns-topic.html)**. - -{{%expand "Cheat Sheet" %}} -``` - RideCompletionTopic: - Type: AWS::SNS::Topic - Properties: - TopicName: RideCompletionTopic -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 1](step-1-sam.png) -{{% /expand%}} - - -#### 2. Deploy the updated AWS SAM template - -Run the following command to build the lab again, after we have added the Amazon SNS topic: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-2 -sam build - -{{< /highlight >}} - - -Now we are ready to update the application, by running the following command to deploy the change: - -{{< highlight bash >}} -sam deploy -{{< /highlight >}} - -**Note:** you do not need to provide the arguments for the deployment, because AWS SAM saved the parameter values in a configuration file called **samconfig.toml**. See the **[documentation](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-sam-cli-config.html)** more information on the AWS SAM CLI configuration file. - -In the meantime while your waiting, you may want to have a look at the AWS SAM template to make yourself familiar with the stack we launched. Just click on the **template.yaml** attachment below to see the content. - -Because AWS SAM will only deploy/update/delete resources which are changed, it only takes a couple of seconds to deploy the new Amazon SNS topic. diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/create-sns-topic.md b/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/create-sns-topic.md deleted file mode 100644 index 060eb6c..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/create-sns-topic.md +++ /dev/null @@ -1,16 +0,0 @@ -+++ -title = "Create the Amazon SNS topic" -weight = 32 -pre = "2 " -+++ - -In this step, you can chose whether you want to create the Amazon SNS topic via the AWS console or AWS SAM. Just select the corresponding tab below and follow the instructions: - -{{% notice info %}} -You can chose, whether you would like to use the **[AWS Console](https://console.aws.amazon.com) or [AWS SAM](https://aws.amazon.com/serverless/sam/)** for this lab. Once you have chosen, **stick to it until the end** of this lab and don't switch in between! -{{% /notice %}} - -{{< tabs name="Style" >}} -{{< tab name="Console" include="create-sns-topic-console" />}} -{{< tab name="SAM" include="create-sns-topic-sam" />}} -{{< /tabs >}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/step-1-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/step-1-console.png deleted file mode 100644 index 65cfe34..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/step-1-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/step-1-sam.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/step-1-sam.png deleted file mode 100644 index 01079ea..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/step-1-sam.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/step-2-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/step-2-console.png deleted file mode 100644 index 895ce21..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/create-sns-topic/step-2-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/module-2.png b/workshop/content/topic-queue-chaining-and-load-balancer/module-2.png deleted file mode 100644 index 15a9e76..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/module-2.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-1.png b/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-1.png deleted file mode 100644 index 9a1f480..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-1.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-2.png b/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-2.png deleted file mode 100644 index dcd31c7..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-2.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-3.png b/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-3.png deleted file mode 100644 index 4e226a4..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-3.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-4.png b/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-4.png deleted file mode 100644 index 4529c11..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/step-4.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancing.md b/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancing.md deleted file mode 100644 index 4efe958..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancer/test-topic-queue-chaining-and-load-balancing.md +++ /dev/null @@ -1,64 +0,0 @@ -+++ -title = "Test Topic-Queue Chaining & Load Balancing" - -weight = 37 -pre = "7 " -+++ - -In this step, we will validate that the Amazon SNS topic is publishing all messages to all subscribers. Because a subscriber can also fail processing a message, we also want to validate that Amazon SNS is redelivering the message, so that we will not miss a single message. - -#### 1. Look up the API Gateway endpoint - -To look-up the API Gateway endpoint URL for the submit-ride-completion function, run the following command: - -```bash -aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-2 \ - --query 'Stacks[].Outputs[?OutputKey==`UnicornManagementServiceApiSubmitRideCompletionEndpoint`].OutputValue' \ - --output text -``` - - -#### 2. Send a couple requests to the Unicorn Management Service - -Let's store this API Gateway endpoint URL in an environment variable, so we don't have to repeat it all the time: - -```bash -export ENDPOINT=$(aws cloudformation describe-stacks \ - --stack-name wild-rydes-async-msg-2 \ - --query 'Stacks[].Outputs[?OutputKey==`UnicornManagementServiceApiSubmitRideCompletionEndpoint`].OutputValue' \ - --output text) -``` - -To send a couple requests to the **submit ride completion endpoint**, execute the command below 5 or more times and change the request payload to test the filter criteria for the **Extraordinary Rides Service**: - -```bash -curl -XPOST -i -H "Content-Type:application/json" -d '{ "from": "Berlin", "to": "Frankfurt", "duration": 420, "distance": 600, "customer": "cmr", "fare": 256.50 }' $ENDPOINT -``` - -{{%expand "Detailed description" %}} -![Step 1](step-1.png) -{{% /expand%}} - - -#### 3. Validate the message reception - -Go to your [Amazon CloudWatch Log console](https://console.aws.amazon.com/cloudwatch/home?#logs:prefix=/aws/lambda/wild-rydes-async-msg-2) and lookup all **Log Groups** with the prefix `/aws/lambda/wild-rydes-async-msg-2`. - -{{%expand "Detailed description" %}} -![Step 2](step-2.png) -{{% /expand%}} - -Click one the name of the Log Groups to see all **Log Streams** available for this Log Group. - -{{%expand "Detailed description" %}} -![Step 3](step-3.png) -{{% /expand%}} - -Browse the most recent Log Streams to validate, that it could successfully process the message. You should also see some log entries, indicating a failed message processing. Shortly after, you should see the message redelivery from Amazon SNS and the successful message processing log entry. - -{{%expand "Detailed description" %}} -![Step 4](step-4.png) -{{% /expand%}} - -Browse all Log Groups to validate, that each of our 5 backend service could successfully process the message. diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-1-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-1-console.png deleted file mode 100644 index fee4648..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-1-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-1-sam.png b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-1-sam.png deleted file mode 100644 index 99e9018..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-1-sam.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-1.png b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-1.png deleted file mode 100644 index 15a9e76..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-1.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-2-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-2-console.png deleted file mode 100644 index 3ab02d7..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-2-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-2-sam.png b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-2-sam.png deleted file mode 100644 index 4c9360b..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-2-sam.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-3-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-3-console.png deleted file mode 100644 index 1bfdb19..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-3-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-3-sam.png b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-3-sam.png deleted file mode 100644 index 1c4c798..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-3-sam.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-4-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-4-console.png deleted file mode 100644 index 095aaf8..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-4-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-5-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-5-console.png deleted file mode 100644 index d51932c..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-5-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-6-console.png b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-6-console.png deleted file mode 100644 index 188c790..0000000 Binary files a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/step-6-console.png and /dev/null differ diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/update-unicorn-management-service-console.md b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/update-unicorn-management-service-console.md deleted file mode 100644 index 9b2d37d..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/update-unicorn-management-service-console.md +++ /dev/null @@ -1,98 +0,0 @@ -+++ -title = "Console" - -disableToc = true -hidden = true -+++ - -#### 1. Grant additional IAM permissions to Lambda - -In your **[Amazon IAM console](https://console.aws.amazon.com/iam)**, select **Roles** in the left navigation. Use the filter text box to find the role with the name **wild-rydes-async-msg-2-SubmitRideCompletionFunctio-...** (assuming your have chosen `wild-rydes-async-msg-2` as your stack name). - -{{%expand "Detailed description" %}} -![Step 1](step-1-console.png) -{{% /expand%}} - -Click on the role name and click **Add inline policy** to attach another one. - -{{%expand "Detailed description" %}} -![Step 2](step-2-console.png) -{{% /expand%}} - -Select the **JSON** tab and passed the following policy statement into it, after you have substitute <<...>> with the correct values. It will add the permission to your Lambda function to publish messages to this particular Amazon SNS topic: - -{{%expand "policy" %}} -```json -{ - "Version": "2012-10-17", - "Statement": [ - { - "Action": [ - "sns:Publish" - ], - "Resource": "arn:aws:sns:<>:<>:<>", - "Effect": "Allow" - } - ] -} -``` -{{% /expand%}} - -{{% notice tip %}} -Make sure you provide the AWS ACCOUNT ID in the form of XXXXXXXXXXXX and not XXXX-XXXX-XXXX! -{{% /notice %}} - -Click **Review policy** and enter the **Name** `SubmitRideCompletionFunctionRolePolicy1`. Click **Create policy**. To validate this step, select on the role again and your should see 3 policies attached to your role, including the one you just have created: - -{{%expand "Detailed description" %}} -![Step 3](step-3-console.png) -{{% /expand%}} - -#### 2. Provide the Amazon SNS topic ARN to Lambda - -In your **[AWS Lambda console](https://console.aws.amazon.com/lambda/home?#/functions)**, select **Functions** in the left navigation. Use the filter text box to find the function with the name **wild-rydes-async-msg-2-SubmitRideCompletionFunctio-...** (assuming your have chosen `wild-rydes-async-msg-2` as your stack name). - -{{%expand "Detailed description" %}} -![Step 4](step-4-console.png) -{{% /expand%}} - -Click on the function name and scroll down to the section **Environment variables**. Our Lambda function expects an environment variable with the **Name** `TOPIC_ARN`. It uses this Amazon SNS topic to publish all messages to. Lookup your Amazon SNS topic name in the [Amazon SNS console](https://console.aws.amazon.com/sns) and add this variable. Click the **Save** button in the top right corner to save the change. - -{{%expand "Detailed description" %}} -![Step 5](step-5-console.png) -{{% /expand%}} - -#### 3. Update your Lambda function to call Amazon SNS - -Open your **[AWS Lambda console](https://console.aws.amazon.com/lambda/home?#/functions)** and select **Functions** in the left navigation. Select the function with the name **wild-rydes-async-msg-2-SubmitRideCompletionFunctio-...** (assuming your have chosen `wild-rydes-async-msg-2` as your stack name). Scroll a bit down to the section **Function code**. Add the definition of the sns client directly after the dynamodb client: - -{{%expand "Cheat Sheet" %}} -```Python -sns = boto3.client('sns', config=config) -``` -{{% /expand%}} - -After the put item DynamoDB statement and before we are sending the response back to the caller, add the code to publish a message to Amazon SNS: - -{{%expand "Cheat Sheet" %}} -```Python - response = sns.publish( - TopicArn=TOPIC_ARN, - Message=json.dumps(request), - MessageAttributes = { - 'fare': { - 'DataType': 'Number', - 'StringValue': str(request['fare']) - }, - 'distance': { - 'DataType': 'Number', - 'StringValue': str(request['distance']) - } - } - ) -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 6](step-6-console.png) -{{% /expand%}} diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/update-unicorn-management-service-sam.md b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/update-unicorn-management-service-sam.md deleted file mode 100644 index bce889d..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/update-unicorn-management-service-sam.md +++ /dev/null @@ -1,98 +0,0 @@ -+++ -title = "SAM" - -disableToc = true -hidden = true -+++ - -#### 1. Grant additional IAM permissions to Lambda - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-2/template.yaml`. In the **Resources** section, look for the **SubmitRideCompletionFunction** definition. It already contains one policies entry called **DynamoDBCrudPolicy**. Directly below, add a policy entry which grants Amazon SNS publish message permission. You can look up the supported policies **[here](https://docs.aws.amazon.com/serverless-application-model/latest/developerguide/serverless-policy-templates.html)**. - -{{%expand "Cheat Sheet" %}} - -```yaml - - SNSPublishMessagePolicy: - TopicName: !GetAtt RideCompletionTopic.TopicName -``` - -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 1](step-1-sam.png) -{{% /expand%}} - - -#### 2. Provide the Amazon SNS topic ARN to Lambda - -In your Cloud9 IDE for this workshop, open the SAM template file `wild-rydes-async-messaging/lab-2/template.yaml`. In the **Resources** section, look for the **SubmitRideCompletionFunction** definition. It already contains one environment variables entry called **TABLE_NAME**. Directly below, add an additional variable with the key **TOPIC_ARN** and the corresponding value. - -{{%expand "Cheat Sheet" %}} - -```yaml - TOPIC_ARN: !Ref RideCompletionTopic -``` - -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 2](step-2-sam.png) -{{% /expand%}} - - -#### 3. Update your Lambda function to call Amazon SNS - -In your Cloud9 IDE, open the Python based AWS Lambda function `wild-rydes-async-messaging/lab-2/unicorn-management-service/app.py`. -Add the definition of the sns client directly after the dynamodb client: - -{{%expand "Cheat Sheet" %}} -```Python -sns = boto3.client('sns', config=config) -``` -{{% /expand%}} - -After the put item DynamoDB statement and before we are sending the response back to the caller, add the code to publish a message to Amazon SNS: - -{{%expand "Cheat Sheet" %}} -```Python - response = sns.publish( - TopicArn=TOPIC_ARN, - Message=json.dumps(request), - MessageAttributes = { - 'fare': { - 'DataType': 'Number', - 'StringValue': str(request['fare']) - }, - 'distance': { - 'DataType': 'Number', - 'StringValue': str(request['distance']) - } - } - ) -``` -{{% /expand%}} - -{{%expand "Detailed description" %}} -![Step 3](step-3-sam.png) -{{% /expand%}} - - -#### 4. Deploy the updated AWS SAM template - -Run the following command to build the lab again, after we have added the additional policy: - -{{< highlight bash >}} -cd ~/environment/wild-rydes-async-messaging/lab-2 -sam build - -{{< /highlight >}} - -Now we are ready to update the application, by running the following command to deploy the change: - -{{< highlight bash >}} -sam deploy -{{< /highlight >}} - -In the meantime while your waiting, you may want to have a look at the AWS SAM template to make yourself familiar with the stack we launched. Just click on the **template.yaml** attachment below to see the content. - -Because AWS SAM will only deploy/update/delete resources which are changed, it only takes a couple of seconds to deploy the new version. diff --git a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/update-unicorn-management-service.md b/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/update-unicorn-management-service.md deleted file mode 100644 index dec8177..0000000 --- a/workshop/content/topic-queue-chaining-and-load-balancer/update-unicorn-management-service/update-unicorn-management-service.md +++ /dev/null @@ -1,17 +0,0 @@ -+++ -title = "Update Unicorn Management Service" - -weight = 36 -pre = "6 " -+++ - -After creating the Amazon SNS topic, all the Amazon SQS queues and the subscriptions, the current architecture looks like the following on: - -![Step 1](step-1.png) - -The last missing part to complete the architecture is calling our **Amazon SNS topic** from our **Unicorn Management Service**. - -{{< tabs name="Style" >}} -{{< tab name="Console" include="update-unicorn-management-service-console" />}} -{{< tab name="SAM" include="update-unicorn-management-service-sam" />}} -{{< /tabs >}} diff --git a/workshop/layouts/partials/header.html b/workshop/layouts/partials/header.html deleted file mode 100644 index c1efdfe..0000000 --- a/workshop/layouts/partials/header.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - - - - - - {{ .Hugo.Generator }} - {{ partial "meta.html" . }} - {{ partial "favicon.html" . }} - {{ .Title }} :: {{ .Site.Title }} - - {{ $assetBusting := not .Site.Params.disableAssetsBusting }} - - - - - - - - - - {{with .Site.Params.themeVariant}} - - {{end}} - - - - - - - {{ partial "custom-header.html" . }} - - - - {{ partial "menu.html" . }} -
-
-
- {{if not .IsHome}} -
-
- {{ if and (or .IsPage .IsSection) .Site.Params.editURL }} - {{ $File := .File }} - {{ $Site := .Site }} - {{with $File.Path }} - - {{ end }} - {{ end }} - {{$toc := (and (not .Params.disableToc) (not .Params.chapter))}} - - {{ if $toc }} - {{ partial "toc.html" . }} - {{ end }} -
-
- {{ end }} - - {{ if .Params.chapter }} -
- {{ end }} -
-

{{.Title}}

- - {{define "breadcrumb"}} - {{$parent := .page.Parent }} - {{ if $parent }} - {{ $value := (printf "%s > %s" $parent.Permalink $parent.Title .value) }} - {{ template "breadcrumb" dict "page" $parent "value" $value }} - {{else}} - {{.value|safeHTML}} - {{end}} - {{end}} diff --git a/workshop/layouts/shortcodes/cf-launch.html b/workshop/layouts/shortcodes/cf-launch.html deleted file mode 100644 index 9f201af..0000000 --- a/workshop/layouts/shortcodes/cf-launch.html +++ /dev/null @@ -1,5 +0,0 @@ -{{ $_hugo_config := `{ "version": 1 }` }} - - - Launch - \ No newline at end of file diff --git a/workshop/layouts/shortcodes/codebucket.html b/workshop/layouts/shortcodes/codebucket.html deleted file mode 100644 index c534931..0000000 --- a/workshop/layouts/shortcodes/codebucket.html +++ /dev/null @@ -1,2 +0,0 @@ -{{ getenv "HUGO_S3_CFN_BUCKET" }} - diff --git a/workshop/layouts/shortcodes/tab.html b/workshop/layouts/shortcodes/tab.html deleted file mode 100644 index a169c76..0000000 --- a/workshop/layouts/shortcodes/tab.html +++ /dev/null @@ -1,19 +0,0 @@ -{{ if .Parent }} - {{ $name := trim (.Get "name") " " }} - {{ $include := trim (.Get "include") " "}} - {{ $codelang := .Get "codelang" }} - {{ if not (.Parent.Scratch.Get "tabs") }} - {{ .Parent.Scratch.Set "tabs" slice }} - {{ end }} - {{ with .Inner }} - {{ if $codelang }} - {{ $.Parent.Scratch.Add "tabs" (dict "name" $name "content" (highlight . $codelang "") ) }} - {{ else }} - {{ $.Parent.Scratch.Add "tabs" (dict "name" $name "content" . ) }} - {{ end }} - {{ else }} - {{ $.Parent.Scratch.Add "tabs" (dict "name" $name "include" $include "codelang" $codelang) }} - {{ end }} -{{ else }} - {{- errorf "[%s] %q: tab shortcode missing its parent" .Page.Site.Language.Lang .Page.Path -}} -{{ end}} \ No newline at end of file diff --git a/workshop/layouts/shortcodes/tabs.html b/workshop/layouts/shortcodes/tabs.html deleted file mode 100644 index 521a404..0000000 --- a/workshop/layouts/shortcodes/tabs.html +++ /dev/null @@ -1,43 +0,0 @@ -{{ .Page.Scratch.Add "tabset-counter" 1 }} -{{ $tab_set_id := .Get "name" | default (printf "tabset-%s-%d" (.Page.RelPermalink) (.Page.Scratch.Get "tabset-counter") ) | anchorize }} -{{ $tabs := .Scratch.Get "tabs" }} -{{ if .Inner }}{{/* We don't use the inner content, but Hugo will complain if we don't reference it. */}}{{ end }} -
-
    - {{ range $i, $e := $tabs }} - {{ $id := printf "%s-%d" $tab_set_id $i }} -
  • {{ trim .name " " }}
  • -{{ end }} -
-{{ range $i, $e := $tabs }} -{{ $id := printf "%s-%d" $tab_set_id $i }} -
- {{ with .content }} - {{ . }} - {{ else }} - {{ if eq $.Page.BundleType "leaf" }} - {{/* find the file somewhere inside the bundle. Note the use of double asterisk */}} - {{ with $.Page.Resources.GetMatch (printf "**%s*" .include) }} - {{ if ne .ResourceType "page" }} - {{/* Assume it is a file that needs code highlighting. */}} - {{ $codelang := $e.codelang | default ( path.Ext .Name | strings.TrimPrefix ".") }} - {{ highlight .Content $codelang "" }} - {{ else}} - {{ .Content }} - {{ end }} - {{ end }} - {{ else}} - {{ $path := path.Join $.Page.Dir .include }} - {{ $page := $.Page.Site.GetPage "page" $path }} - {{ with $page }} - {{ .Content }} - {{ else }} - {{ errorf "[%s] tabs include not found for path %q" $.Page.Site.Language.Lang $path}} - {{ end }} - {{ end }} - {{ end }} -
-{{ end }} -
-{{ $elem := $tab_set_id | safeJS }} - diff --git a/workshop/static/css/jquery-ui.min.css b/workshop/static/css/jquery-ui.min.css deleted file mode 100644 index accf0a8..0000000 --- a/workshop/static/css/jquery-ui.min.css +++ /dev/null @@ -1,7 +0,0 @@ -/*! jQuery UI - v1.13.1 - 2022-01-20 -* http://jqueryui.com -* Includes: core.css, accordion.css, autocomplete.css, menu.css, button.css, controlgroup.css, checkboxradio.css, datepicker.css, dialog.css, draggable.css, resizable.css, progressbar.css, selectable.css, selectmenu.css, slider.css, sortable.css, spinner.css, tabs.css, tooltip.css, theme.css -* To view and modify this theme, visit http://jqueryui.com/themeroller/?bgShadowXPos=&bgOverlayXPos=&bgErrorXPos=&bgHighlightXPos=&bgContentXPos=&bgHeaderXPos=&bgActiveXPos=&bgHoverXPos=&bgDefaultXPos=&bgShadowYPos=&bgOverlayYPos=&bgErrorYPos=&bgHighlightYPos=&bgContentYPos=&bgHeaderYPos=&bgActiveYPos=&bgHoverYPos=&bgDefaultYPos=&bgShadowRepeat=&bgOverlayRepeat=&bgErrorRepeat=&bgHighlightRepeat=&bgContentRepeat=&bgHeaderRepeat=&bgActiveRepeat=&bgHoverRepeat=&bgDefaultRepeat=&iconsHover=url(%22images%2Fui-icons_555555_256x240.png%22)&iconsHighlight=url(%22images%2Fui-icons_777620_256x240.png%22)&iconsHeader=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsError=url(%22images%2Fui-icons_cc0000_256x240.png%22)&iconsDefault=url(%22images%2Fui-icons_777777_256x240.png%22)&iconsContent=url(%22images%2Fui-icons_444444_256x240.png%22)&iconsActive=url(%22images%2Fui-icons_ffffff_256x240.png%22)&bgImgUrlShadow=&bgImgUrlOverlay=&bgImgUrlHover=&bgImgUrlHighlight=&bgImgUrlHeader=&bgImgUrlError=&bgImgUrlDefault=&bgImgUrlContent=&bgImgUrlActive=&opacityFilterShadow=Alpha(Opacity%3D30)&opacityFilterOverlay=Alpha(Opacity%3D30)&opacityShadowPerc=30&opacityOverlayPerc=30&iconColorHover=%23555555&iconColorHighlight=%23777620&iconColorHeader=%23444444&iconColorError=%23cc0000&iconColorDefault=%23777777&iconColorContent=%23444444&iconColorActive=%23ffffff&bgImgOpacityShadow=0&bgImgOpacityOverlay=0&bgImgOpacityError=95&bgImgOpacityHighlight=55&bgImgOpacityContent=75&bgImgOpacityHeader=75&bgImgOpacityActive=65&bgImgOpacityHover=75&bgImgOpacityDefault=75&bgTextureShadow=flat&bgTextureOverlay=flat&bgTextureError=flat&bgTextureHighlight=flat&bgTextureContent=flat&bgTextureHeader=flat&bgTextureActive=flat&bgTextureHover=flat&bgTextureDefault=flat&cornerRadius=3px&fwDefault=normal&ffDefault=Arial%2CHelvetica%2Csans-serif&fsDefault=1em&cornerRadiusShadow=8px&thicknessShadow=5px&offsetLeftShadow=0px&offsetTopShadow=0px&opacityShadow=.3&bgColorShadow=%23666666&opacityOverlay=.3&bgColorOverlay=%23aaaaaa&fcError=%235f3f3f&borderColorError=%23f1a899&bgColorError=%23fddfdf&fcHighlight=%23777620&borderColorHighlight=%23dad55e&bgColorHighlight=%23fffa90&fcContent=%23333333&borderColorContent=%23dddddd&bgColorContent=%23ffffff&fcHeader=%23333333&borderColorHeader=%23dddddd&bgColorHeader=%23e9e9e9&fcActive=%23ffffff&borderColorActive=%23003eff&bgColorActive=%23007fff&fcHover=%232b2b2b&borderColorHover=%23cccccc&bgColorHover=%23ededed&fcDefault=%23454545&borderColorDefault=%23c5c5c5&bgColorDefault=%23f6f6f6 -* Copyright jQuery Foundation and other contributors; Licensed MIT */ - -.ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;-ms-filter:"alpha(opacity=0)"}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-accordion .ui-accordion-header{display:block;cursor:pointer;position:relative;margin:2px 0 0 0;padding:.5em .5em .5em .7em;font-size:100%}.ui-accordion .ui-accordion-content{padding:1em 2.2em;border-top:0;overflow:auto}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}.ui-button{padding:.4em 1em;display:inline-block;position:relative;line-height:normal;margin-right:.1em;cursor:pointer;vertical-align:middle;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;overflow:visible}.ui-button,.ui-button:link,.ui-button:visited,.ui-button:hover,.ui-button:active{text-decoration:none}.ui-button-icon-only{width:2em;box-sizing:border-box;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-button-icon-only{text-indent:0}.ui-button-icon-only .ui-icon{position:absolute;top:50%;left:50%;margin-top:-8px;margin-left:-8px}.ui-button.ui-icon-notext .ui-icon{padding:0;width:2.1em;height:2.1em;text-indent:-9999px;white-space:nowrap}input.ui-button.ui-icon-notext .ui-icon{width:auto;height:auto;text-indent:0;white-space:normal;padding:.4em 1em}input.ui-button::-moz-focus-inner,button.ui-button::-moz-focus-inner{border:0;padding:0}.ui-controlgroup{vertical-align:middle;display:inline-block}.ui-controlgroup > .ui-controlgroup-item{float:left;margin-left:0;margin-right:0}.ui-controlgroup > .ui-controlgroup-item:focus,.ui-controlgroup > .ui-controlgroup-item.ui-visual-focus{z-index:9999}.ui-controlgroup-vertical > .ui-controlgroup-item{display:block;float:none;width:100%;margin-top:0;margin-bottom:0;text-align:left}.ui-controlgroup-vertical .ui-controlgroup-item{box-sizing:border-box}.ui-controlgroup .ui-controlgroup-label{padding:.4em 1em}.ui-controlgroup .ui-controlgroup-label span{font-size:80%}.ui-controlgroup-horizontal .ui-controlgroup-label + .ui-controlgroup-item{border-left:none}.ui-controlgroup-vertical .ui-controlgroup-label + .ui-controlgroup-item{border-top:none}.ui-controlgroup-horizontal .ui-controlgroup-label.ui-widget-content{border-right:none}.ui-controlgroup-vertical .ui-controlgroup-label.ui-widget-content{border-bottom:none}.ui-controlgroup-vertical .ui-spinner-input{width:75%;width:calc( 100% - 2.4em )}.ui-controlgroup-vertical .ui-spinner .ui-spinner-up{border-top-style:solid}.ui-checkboxradio-label .ui-icon-background{box-shadow:inset 1px 1px 1px #ccc;border-radius:.12em;border:none}.ui-checkboxradio-radio-label .ui-icon-background{width:16px;height:16px;border-radius:1em;overflow:visible;border:none}.ui-checkboxradio-radio-label.ui-checkboxradio-checked .ui-icon,.ui-checkboxradio-radio-label.ui-checkboxradio-checked:hover .ui-icon{background-image:none;width:8px;height:8px;border-width:4px;border-style:solid}.ui-checkboxradio-disabled{pointer-events:none}.ui-datepicker{width:17em;padding:.2em .2em 0;display:none}.ui-datepicker .ui-datepicker-header{position:relative;padding:.2em 0}.ui-datepicker .ui-datepicker-prev,.ui-datepicker .ui-datepicker-next{position:absolute;top:2px;width:1.8em;height:1.8em}.ui-datepicker .ui-datepicker-prev-hover,.ui-datepicker .ui-datepicker-next-hover{top:1px}.ui-datepicker .ui-datepicker-prev{left:2px}.ui-datepicker .ui-datepicker-next{right:2px}.ui-datepicker .ui-datepicker-prev-hover{left:1px}.ui-datepicker .ui-datepicker-next-hover{right:1px}.ui-datepicker .ui-datepicker-prev span,.ui-datepicker .ui-datepicker-next span{display:block;position:absolute;left:50%;margin-left:-8px;top:50%;margin-top:-8px}.ui-datepicker .ui-datepicker-title{margin:0 2.3em;line-height:1.8em;text-align:center}.ui-datepicker .ui-datepicker-title select{font-size:1em;margin:1px 0}.ui-datepicker select.ui-datepicker-month,.ui-datepicker select.ui-datepicker-year{width:45%}.ui-datepicker table{width:100%;font-size:.9em;border-collapse:collapse;margin:0 0 .4em}.ui-datepicker th{padding:.7em .3em;text-align:center;font-weight:bold;border:0}.ui-datepicker td{border:0;padding:1px}.ui-datepicker td span,.ui-datepicker td a{display:block;padding:.2em;text-align:right;text-decoration:none}.ui-datepicker .ui-datepicker-buttonpane{background-image:none;margin:.7em 0 0 0;padding:0 .2em;border-left:0;border-right:0;border-bottom:0}.ui-datepicker .ui-datepicker-buttonpane button{float:right;margin:.5em .2em .4em;cursor:pointer;padding:.2em .6em .3em .6em;width:auto;overflow:visible}.ui-datepicker .ui-datepicker-buttonpane button.ui-datepicker-current{float:left}.ui-datepicker.ui-datepicker-multi{width:auto}.ui-datepicker-multi .ui-datepicker-group{float:left}.ui-datepicker-multi .ui-datepicker-group table{width:95%;margin:0 auto .4em}.ui-datepicker-multi-2 .ui-datepicker-group{width:50%}.ui-datepicker-multi-3 .ui-datepicker-group{width:33.3%}.ui-datepicker-multi-4 .ui-datepicker-group{width:25%}.ui-datepicker-multi .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-multi .ui-datepicker-group-middle .ui-datepicker-header{border-left-width:0}.ui-datepicker-multi .ui-datepicker-buttonpane{clear:left}.ui-datepicker-row-break{clear:both;width:100%;font-size:0}.ui-datepicker-rtl{direction:rtl}.ui-datepicker-rtl .ui-datepicker-prev{right:2px;left:auto}.ui-datepicker-rtl .ui-datepicker-next{left:2px;right:auto}.ui-datepicker-rtl .ui-datepicker-prev:hover{right:1px;left:auto}.ui-datepicker-rtl .ui-datepicker-next:hover{left:1px;right:auto}.ui-datepicker-rtl .ui-datepicker-buttonpane{clear:right}.ui-datepicker-rtl .ui-datepicker-buttonpane button{float:left}.ui-datepicker-rtl .ui-datepicker-buttonpane button.ui-datepicker-current,.ui-datepicker-rtl .ui-datepicker-group{float:right}.ui-datepicker-rtl .ui-datepicker-group-last .ui-datepicker-header,.ui-datepicker-rtl .ui-datepicker-group-middle .ui-datepicker-header{border-right-width:0;border-left-width:1px}.ui-datepicker .ui-icon{display:block;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat;left:.5em;top:.3em}.ui-dialog{position:absolute;top:0;left:0;padding:.2em;outline:0}.ui-dialog .ui-dialog-titlebar{padding:.4em 1em;position:relative}.ui-dialog .ui-dialog-title{float:left;margin:.1em 0;white-space:nowrap;width:90%;overflow:hidden;text-overflow:ellipsis}.ui-dialog .ui-dialog-titlebar-close{position:absolute;right:.3em;top:50%;width:20px;margin:-10px 0 0 0;padding:1px;height:20px}.ui-dialog .ui-dialog-content{position:relative;border:0;padding:.5em 1em;background:none;overflow:auto}.ui-dialog .ui-dialog-buttonpane{text-align:left;border-width:1px 0 0 0;background-image:none;margin-top:.5em;padding:.3em 1em .5em .4em}.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset{float:right}.ui-dialog .ui-dialog-buttonpane button{margin:.5em .4em .5em 0;cursor:pointer}.ui-dialog .ui-resizable-n{height:2px;top:0}.ui-dialog .ui-resizable-e{width:2px;right:0}.ui-dialog .ui-resizable-s{height:2px;bottom:0}.ui-dialog .ui-resizable-w{width:2px;left:0}.ui-dialog .ui-resizable-se,.ui-dialog .ui-resizable-sw,.ui-dialog .ui-resizable-ne,.ui-dialog .ui-resizable-nw{width:7px;height:7px}.ui-dialog .ui-resizable-se{right:0;bottom:0}.ui-dialog .ui-resizable-sw{left:0;bottom:0}.ui-dialog .ui-resizable-ne{right:0;top:0}.ui-dialog .ui-resizable-nw{left:0;top:0}.ui-draggable .ui-dialog-titlebar{cursor:move}.ui-draggable-handle{-ms-touch-action:none;touch-action:none}.ui-resizable{position:relative}.ui-resizable-handle{position:absolute;font-size:0.1px;display:block;-ms-touch-action:none;touch-action:none}.ui-resizable-disabled .ui-resizable-handle,.ui-resizable-autohide .ui-resizable-handle{display:none}.ui-resizable-n{cursor:n-resize;height:7px;width:100%;top:-5px;left:0}.ui-resizable-s{cursor:s-resize;height:7px;width:100%;bottom:-5px;left:0}.ui-resizable-e{cursor:e-resize;width:7px;right:-5px;top:0;height:100%}.ui-resizable-w{cursor:w-resize;width:7px;left:-5px;top:0;height:100%}.ui-resizable-se{cursor:se-resize;width:12px;height:12px;right:1px;bottom:1px}.ui-resizable-sw{cursor:sw-resize;width:9px;height:9px;left:-5px;bottom:-5px}.ui-resizable-nw{cursor:nw-resize;width:9px;height:9px;left:-5px;top:-5px}.ui-resizable-ne{cursor:ne-resize;width:9px;height:9px;right:-5px;top:-5px}.ui-progressbar{height:2em;text-align:left;overflow:hidden}.ui-progressbar .ui-progressbar-value{margin:-1px;height:100%}.ui-progressbar .ui-progressbar-overlay{background:url("data:image/gif;base64,R0lGODlhKAAoAIABAAAAAP///yH/C05FVFNDQVBFMi4wAwEAAAAh+QQJAQABACwAAAAAKAAoAAACkYwNqXrdC52DS06a7MFZI+4FHBCKoDeWKXqymPqGqxvJrXZbMx7Ttc+w9XgU2FB3lOyQRWET2IFGiU9m1frDVpxZZc6bfHwv4c1YXP6k1Vdy292Fb6UkuvFtXpvWSzA+HycXJHUXiGYIiMg2R6W459gnWGfHNdjIqDWVqemH2ekpObkpOlppWUqZiqr6edqqWQAAIfkECQEAAQAsAAAAACgAKAAAApSMgZnGfaqcg1E2uuzDmmHUBR8Qil95hiPKqWn3aqtLsS18y7G1SzNeowWBENtQd+T1JktP05nzPTdJZlR6vUxNWWjV+vUWhWNkWFwxl9VpZRedYcflIOLafaa28XdsH/ynlcc1uPVDZxQIR0K25+cICCmoqCe5mGhZOfeYSUh5yJcJyrkZWWpaR8doJ2o4NYq62lAAACH5BAkBAAEALAAAAAAoACgAAAKVDI4Yy22ZnINRNqosw0Bv7i1gyHUkFj7oSaWlu3ovC8GxNso5fluz3qLVhBVeT/Lz7ZTHyxL5dDalQWPVOsQWtRnuwXaFTj9jVVh8pma9JjZ4zYSj5ZOyma7uuolffh+IR5aW97cHuBUXKGKXlKjn+DiHWMcYJah4N0lYCMlJOXipGRr5qdgoSTrqWSq6WFl2ypoaUAAAIfkECQEAAQAsAAAAACgAKAAAApaEb6HLgd/iO7FNWtcFWe+ufODGjRfoiJ2akShbueb0wtI50zm02pbvwfWEMWBQ1zKGlLIhskiEPm9R6vRXxV4ZzWT2yHOGpWMyorblKlNp8HmHEb/lCXjcW7bmtXP8Xt229OVWR1fod2eWqNfHuMjXCPkIGNileOiImVmCOEmoSfn3yXlJWmoHGhqp6ilYuWYpmTqKUgAAIfkECQEAAQAsAAAAACgAKAAAApiEH6kb58biQ3FNWtMFWW3eNVcojuFGfqnZqSebuS06w5V80/X02pKe8zFwP6EFWOT1lDFk8rGERh1TTNOocQ61Hm4Xm2VexUHpzjymViHrFbiELsefVrn6XKfnt2Q9G/+Xdie499XHd2g4h7ioOGhXGJboGAnXSBnoBwKYyfioubZJ2Hn0RuRZaflZOil56Zp6iioKSXpUAAAh+QQJAQABACwAAAAAKAAoAAACkoQRqRvnxuI7kU1a1UU5bd5tnSeOZXhmn5lWK3qNTWvRdQxP8qvaC+/yaYQzXO7BMvaUEmJRd3TsiMAgswmNYrSgZdYrTX6tSHGZO73ezuAw2uxuQ+BbeZfMxsexY35+/Qe4J1inV0g4x3WHuMhIl2jXOKT2Q+VU5fgoSUI52VfZyfkJGkha6jmY+aaYdirq+lQAACH5BAkBAAEALAAAAAAoACgAAAKWBIKpYe0L3YNKToqswUlvznigd4wiR4KhZrKt9Upqip61i9E3vMvxRdHlbEFiEXfk9YARYxOZZD6VQ2pUunBmtRXo1Lf8hMVVcNl8JafV38aM2/Fu5V16Bn63r6xt97j09+MXSFi4BniGFae3hzbH9+hYBzkpuUh5aZmHuanZOZgIuvbGiNeomCnaxxap2upaCZsq+1kAACH5BAkBAAEALAAAAAAoACgAAAKXjI8By5zf4kOxTVrXNVlv1X0d8IGZGKLnNpYtm8Lr9cqVeuOSvfOW79D9aDHizNhDJidFZhNydEahOaDH6nomtJjp1tutKoNWkvA6JqfRVLHU/QUfau9l2x7G54d1fl995xcIGAdXqMfBNadoYrhH+Mg2KBlpVpbluCiXmMnZ2Sh4GBqJ+ckIOqqJ6LmKSllZmsoq6wpQAAAh+QQJAQABACwAAAAAKAAoAAAClYx/oLvoxuJDkU1a1YUZbJ59nSd2ZXhWqbRa2/gF8Gu2DY3iqs7yrq+xBYEkYvFSM8aSSObE+ZgRl1BHFZNr7pRCavZ5BW2142hY3AN/zWtsmf12p9XxxFl2lpLn1rseztfXZjdIWIf2s5dItwjYKBgo9yg5pHgzJXTEeGlZuenpyPmpGQoKOWkYmSpaSnqKileI2FAAACH5BAkBAAEALAAAAAAoACgAAAKVjB+gu+jG4kORTVrVhRlsnn2dJ3ZleFaptFrb+CXmO9OozeL5VfP99HvAWhpiUdcwkpBH3825AwYdU8xTqlLGhtCosArKMpvfa1mMRae9VvWZfeB2XfPkeLmm18lUcBj+p5dnN8jXZ3YIGEhYuOUn45aoCDkp16hl5IjYJvjWKcnoGQpqyPlpOhr3aElaqrq56Bq7VAAAOw==");height:100%;-ms-filter:"alpha(opacity=25)";opacity:0.25}.ui-progressbar-indeterminate .ui-progressbar-value{background-image:none}.ui-selectable{-ms-touch-action:none;touch-action:none}.ui-selectable-helper{position:absolute;z-index:100;border:1px dotted black}.ui-selectmenu-menu{padding:0;margin:0;position:absolute;top:0;left:0;display:none}.ui-selectmenu-menu .ui-menu{overflow:auto;overflow-x:hidden;padding-bottom:1px}.ui-selectmenu-menu .ui-menu .ui-selectmenu-optgroup{font-size:1em;font-weight:bold;line-height:1.5;padding:2px 0.4em;margin:0.5em 0 0 0;height:auto;border:0}.ui-selectmenu-open{display:block}.ui-selectmenu-text{display:block;margin-right:20px;overflow:hidden;text-overflow:ellipsis}.ui-selectmenu-button.ui-button{text-align:left;white-space:nowrap;width:14em}.ui-selectmenu-icon.ui-icon{float:right;margin-top:0}.ui-slider{position:relative;text-align:left}.ui-slider .ui-slider-handle{position:absolute;z-index:2;width:1.2em;height:1.2em;cursor:pointer;-ms-touch-action:none;touch-action:none}.ui-slider .ui-slider-range{position:absolute;z-index:1;font-size:.7em;display:block;border:0;background-position:0 0}.ui-slider.ui-state-disabled .ui-slider-handle,.ui-slider.ui-state-disabled .ui-slider-range{filter:inherit}.ui-slider-horizontal{height:.8em}.ui-slider-horizontal .ui-slider-handle{top:-.3em;margin-left:-.6em}.ui-slider-horizontal .ui-slider-range{top:0;height:100%}.ui-slider-horizontal .ui-slider-range-min{left:0}.ui-slider-horizontal .ui-slider-range-max{right:0}.ui-slider-vertical{width:.8em;height:100px}.ui-slider-vertical .ui-slider-handle{left:-.3em;margin-left:0;margin-bottom:-.6em}.ui-slider-vertical .ui-slider-range{left:0;width:100%}.ui-slider-vertical .ui-slider-range-min{bottom:0}.ui-slider-vertical .ui-slider-range-max{top:0}.ui-sortable-handle{-ms-touch-action:none;touch-action:none}.ui-spinner{position:relative;display:inline-block;overflow:hidden;padding:0;vertical-align:middle}.ui-spinner-input{border:none;background:none;color:inherit;padding:.222em 0;margin:.2em 0;vertical-align:middle;margin-left:.4em;margin-right:2em}.ui-spinner-button{width:1.6em;height:50%;font-size:.5em;padding:0;margin:0;text-align:center;position:absolute;cursor:default;display:block;overflow:hidden;right:0}.ui-spinner a.ui-spinner-button{border-top-style:none;border-bottom-style:none;border-right-style:none}.ui-spinner-up{top:0}.ui-spinner-down{bottom:0}.ui-tabs{position:relative;padding:.2em}.ui-tabs .ui-tabs-nav{margin:0;padding:.2em .2em 0}.ui-tabs .ui-tabs-nav li{list-style:none;float:left;position:relative;top:0;margin:1px .2em 0 0;border-bottom-width:0;padding:0;white-space:nowrap}.ui-tabs .ui-tabs-nav .ui-tabs-anchor{float:left;padding:.5em 1em;text-decoration:none}.ui-tabs .ui-tabs-nav li.ui-tabs-active{margin-bottom:-1px;padding-bottom:1px}.ui-tabs .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-state-disabled .ui-tabs-anchor,.ui-tabs .ui-tabs-nav li.ui-tabs-loading .ui-tabs-anchor{cursor:text}.ui-tabs-collapsible .ui-tabs-nav li.ui-tabs-active .ui-tabs-anchor{cursor:pointer}.ui-tabs .ui-tabs-panel{display:block;border-width:0;padding:1em 1.4em;background:none}.ui-tooltip{padding:8px;position:absolute;z-index:9999;max-width:300px}body .ui-tooltip{border-width:2px}.ui-widget{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget .ui-widget{font-size:1em}.ui-widget input,.ui-widget select,.ui-widget textarea,.ui-widget button{font-family:Arial,Helvetica,sans-serif;font-size:1em}.ui-widget.ui-widget-content{border:1px solid #c5c5c5}.ui-widget-content{border:1px solid #ddd;background:#fff;color:#333}.ui-widget-content a{color:#333}.ui-widget-header{border:1px solid #ddd;background:#e9e9e9;color:#333;font-weight:bold}.ui-widget-header a{color:#333}.ui-state-default,.ui-widget-content .ui-state-default,.ui-widget-header .ui-state-default,.ui-button,html .ui-button.ui-state-disabled:hover,html .ui-button.ui-state-disabled:active{border:1px solid #c5c5c5;background:#f6f6f6;font-weight:normal;color:#454545}.ui-state-default a,.ui-state-default a:link,.ui-state-default a:visited,a.ui-button,a:link.ui-button,a:visited.ui-button,.ui-button{color:#454545;text-decoration:none}.ui-state-hover,.ui-widget-content .ui-state-hover,.ui-widget-header .ui-state-hover,.ui-state-focus,.ui-widget-content .ui-state-focus,.ui-widget-header .ui-state-focus,.ui-button:hover,.ui-button:focus{border:1px solid #ccc;background:#ededed;font-weight:normal;color:#2b2b2b}.ui-state-hover a,.ui-state-hover a:hover,.ui-state-hover a:link,.ui-state-hover a:visited,.ui-state-focus a,.ui-state-focus a:hover,.ui-state-focus a:link,.ui-state-focus a:visited,a.ui-button:hover,a.ui-button:focus{color:#2b2b2b;text-decoration:none}.ui-visual-focus{box-shadow:0 0 3px 1px rgb(94,158,214)}.ui-state-active,.ui-widget-content .ui-state-active,.ui-widget-header .ui-state-active,a.ui-button:active,.ui-button:active,.ui-button.ui-state-active:hover{border:1px solid #003eff;background:#007fff;font-weight:normal;color:#fff}.ui-icon-background,.ui-state-active .ui-icon-background{border:#003eff;background-color:#fff}.ui-state-active a,.ui-state-active a:link,.ui-state-active a:visited{color:#fff;text-decoration:none}.ui-state-highlight,.ui-widget-content .ui-state-highlight,.ui-widget-header .ui-state-highlight{border:1px solid #dad55e;background:#fffa90;color:#777620}.ui-state-checked{border:1px solid #dad55e;background:#fffa90}.ui-state-highlight a,.ui-widget-content .ui-state-highlight a,.ui-widget-header .ui-state-highlight a{color:#777620}.ui-state-error,.ui-widget-content .ui-state-error,.ui-widget-header .ui-state-error{border:1px solid #f1a899;background:#fddfdf;color:#5f3f3f}.ui-state-error a,.ui-widget-content .ui-state-error a,.ui-widget-header .ui-state-error a{color:#5f3f3f}.ui-state-error-text,.ui-widget-content .ui-state-error-text,.ui-widget-header .ui-state-error-text{color:#5f3f3f}.ui-priority-primary,.ui-widget-content .ui-priority-primary,.ui-widget-header .ui-priority-primary{font-weight:bold}.ui-priority-secondary,.ui-widget-content .ui-priority-secondary,.ui-widget-header .ui-priority-secondary{opacity:.7;-ms-filter:"alpha(opacity=70)";font-weight:normal}.ui-state-disabled,.ui-widget-content .ui-state-disabled,.ui-widget-header .ui-state-disabled{opacity:.35;-ms-filter:"alpha(opacity=35)";background-image:none}.ui-state-disabled .ui-icon{-ms-filter:"alpha(opacity=35)"}.ui-icon{width:16px;height:16px}.ui-icon,.ui-widget-content .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-widget-header .ui-icon{background-image:url("images/ui-icons_444444_256x240.png")}.ui-state-hover .ui-icon,.ui-state-focus .ui-icon,.ui-button:hover .ui-icon,.ui-button:focus .ui-icon{background-image:url("images/ui-icons_555555_256x240.png")}.ui-state-active .ui-icon,.ui-button:active .ui-icon{background-image:url("images/ui-icons_ffffff_256x240.png")}.ui-state-highlight .ui-icon,.ui-button .ui-state-highlight.ui-icon{background-image:url("images/ui-icons_777620_256x240.png")}.ui-state-error .ui-icon,.ui-state-error-text .ui-icon{background-image:url("images/ui-icons_cc0000_256x240.png")}.ui-button .ui-icon{background-image:url("images/ui-icons_777777_256x240.png")}.ui-icon-blank.ui-icon-blank.ui-icon-blank{background-image:none}.ui-icon-caret-1-n{background-position:0 0}.ui-icon-caret-1-ne{background-position:-16px 0}.ui-icon-caret-1-e{background-position:-32px 0}.ui-icon-caret-1-se{background-position:-48px 0}.ui-icon-caret-1-s{background-position:-65px 0}.ui-icon-caret-1-sw{background-position:-80px 0}.ui-icon-caret-1-w{background-position:-96px 0}.ui-icon-caret-1-nw{background-position:-112px 0}.ui-icon-caret-2-n-s{background-position:-128px 0}.ui-icon-caret-2-e-w{background-position:-144px 0}.ui-icon-triangle-1-n{background-position:0 -16px}.ui-icon-triangle-1-ne{background-position:-16px -16px}.ui-icon-triangle-1-e{background-position:-32px -16px}.ui-icon-triangle-1-se{background-position:-48px -16px}.ui-icon-triangle-1-s{background-position:-65px -16px}.ui-icon-triangle-1-sw{background-position:-80px -16px}.ui-icon-triangle-1-w{background-position:-96px -16px}.ui-icon-triangle-1-nw{background-position:-112px -16px}.ui-icon-triangle-2-n-s{background-position:-128px -16px}.ui-icon-triangle-2-e-w{background-position:-144px -16px}.ui-icon-arrow-1-n{background-position:0 -32px}.ui-icon-arrow-1-ne{background-position:-16px -32px}.ui-icon-arrow-1-e{background-position:-32px -32px}.ui-icon-arrow-1-se{background-position:-48px -32px}.ui-icon-arrow-1-s{background-position:-65px -32px}.ui-icon-arrow-1-sw{background-position:-80px -32px}.ui-icon-arrow-1-w{background-position:-96px -32px}.ui-icon-arrow-1-nw{background-position:-112px -32px}.ui-icon-arrow-2-n-s{background-position:-128px -32px}.ui-icon-arrow-2-ne-sw{background-position:-144px -32px}.ui-icon-arrow-2-e-w{background-position:-160px -32px}.ui-icon-arrow-2-se-nw{background-position:-176px -32px}.ui-icon-arrowstop-1-n{background-position:-192px -32px}.ui-icon-arrowstop-1-e{background-position:-208px -32px}.ui-icon-arrowstop-1-s{background-position:-224px -32px}.ui-icon-arrowstop-1-w{background-position:-240px -32px}.ui-icon-arrowthick-1-n{background-position:1px -48px}.ui-icon-arrowthick-1-ne{background-position:-16px -48px}.ui-icon-arrowthick-1-e{background-position:-32px -48px}.ui-icon-arrowthick-1-se{background-position:-48px -48px}.ui-icon-arrowthick-1-s{background-position:-64px -48px}.ui-icon-arrowthick-1-sw{background-position:-80px -48px}.ui-icon-arrowthick-1-w{background-position:-96px -48px}.ui-icon-arrowthick-1-nw{background-position:-112px -48px}.ui-icon-arrowthick-2-n-s{background-position:-128px -48px}.ui-icon-arrowthick-2-ne-sw{background-position:-144px -48px}.ui-icon-arrowthick-2-e-w{background-position:-160px -48px}.ui-icon-arrowthick-2-se-nw{background-position:-176px -48px}.ui-icon-arrowthickstop-1-n{background-position:-192px -48px}.ui-icon-arrowthickstop-1-e{background-position:-208px -48px}.ui-icon-arrowthickstop-1-s{background-position:-224px -48px}.ui-icon-arrowthickstop-1-w{background-position:-240px -48px}.ui-icon-arrowreturnthick-1-w{background-position:0 -64px}.ui-icon-arrowreturnthick-1-n{background-position:-16px -64px}.ui-icon-arrowreturnthick-1-e{background-position:-32px -64px}.ui-icon-arrowreturnthick-1-s{background-position:-48px -64px}.ui-icon-arrowreturn-1-w{background-position:-64px -64px}.ui-icon-arrowreturn-1-n{background-position:-80px -64px}.ui-icon-arrowreturn-1-e{background-position:-96px -64px}.ui-icon-arrowreturn-1-s{background-position:-112px -64px}.ui-icon-arrowrefresh-1-w{background-position:-128px -64px}.ui-icon-arrowrefresh-1-n{background-position:-144px -64px}.ui-icon-arrowrefresh-1-e{background-position:-160px -64px}.ui-icon-arrowrefresh-1-s{background-position:-176px -64px}.ui-icon-arrow-4{background-position:0 -80px}.ui-icon-arrow-4-diag{background-position:-16px -80px}.ui-icon-extlink{background-position:-32px -80px}.ui-icon-newwin{background-position:-48px -80px}.ui-icon-refresh{background-position:-64px -80px}.ui-icon-shuffle{background-position:-80px -80px}.ui-icon-transfer-e-w{background-position:-96px -80px}.ui-icon-transferthick-e-w{background-position:-112px -80px}.ui-icon-folder-collapsed{background-position:0 -96px}.ui-icon-folder-open{background-position:-16px -96px}.ui-icon-document{background-position:-32px -96px}.ui-icon-document-b{background-position:-48px -96px}.ui-icon-note{background-position:-64px -96px}.ui-icon-mail-closed{background-position:-80px -96px}.ui-icon-mail-open{background-position:-96px -96px}.ui-icon-suitcase{background-position:-112px -96px}.ui-icon-comment{background-position:-128px -96px}.ui-icon-person{background-position:-144px -96px}.ui-icon-print{background-position:-160px -96px}.ui-icon-trash{background-position:-176px -96px}.ui-icon-locked{background-position:-192px -96px}.ui-icon-unlocked{background-position:-208px -96px}.ui-icon-bookmark{background-position:-224px -96px}.ui-icon-tag{background-position:-240px -96px}.ui-icon-home{background-position:0 -112px}.ui-icon-flag{background-position:-16px -112px}.ui-icon-calendar{background-position:-32px -112px}.ui-icon-cart{background-position:-48px -112px}.ui-icon-pencil{background-position:-64px -112px}.ui-icon-clock{background-position:-80px -112px}.ui-icon-disk{background-position:-96px -112px}.ui-icon-calculator{background-position:-112px -112px}.ui-icon-zoomin{background-position:-128px -112px}.ui-icon-zoomout{background-position:-144px -112px}.ui-icon-search{background-position:-160px -112px}.ui-icon-wrench{background-position:-176px -112px}.ui-icon-gear{background-position:-192px -112px}.ui-icon-heart{background-position:-208px -112px}.ui-icon-star{background-position:-224px -112px}.ui-icon-link{background-position:-240px -112px}.ui-icon-cancel{background-position:0 -128px}.ui-icon-plus{background-position:-16px -128px}.ui-icon-plusthick{background-position:-32px -128px}.ui-icon-minus{background-position:-48px -128px}.ui-icon-minusthick{background-position:-64px -128px}.ui-icon-close{background-position:-80px -128px}.ui-icon-closethick{background-position:-96px -128px}.ui-icon-key{background-position:-112px -128px}.ui-icon-lightbulb{background-position:-128px -128px}.ui-icon-scissors{background-position:-144px -128px}.ui-icon-clipboard{background-position:-160px -128px}.ui-icon-copy{background-position:-176px -128px}.ui-icon-contact{background-position:-192px -128px}.ui-icon-image{background-position:-208px -128px}.ui-icon-video{background-position:-224px -128px}.ui-icon-script{background-position:-240px -128px}.ui-icon-alert{background-position:0 -144px}.ui-icon-info{background-position:-16px -144px}.ui-icon-notice{background-position:-32px -144px}.ui-icon-help{background-position:-48px -144px}.ui-icon-check{background-position:-64px -144px}.ui-icon-bullet{background-position:-80px -144px}.ui-icon-radio-on{background-position:-96px -144px}.ui-icon-radio-off{background-position:-112px -144px}.ui-icon-pin-w{background-position:-128px -144px}.ui-icon-pin-s{background-position:-144px -144px}.ui-icon-play{background-position:0 -160px}.ui-icon-pause{background-position:-16px -160px}.ui-icon-seek-next{background-position:-32px -160px}.ui-icon-seek-prev{background-position:-48px -160px}.ui-icon-seek-end{background-position:-64px -160px}.ui-icon-seek-start{background-position:-80px -160px}.ui-icon-seek-first{background-position:-80px -160px}.ui-icon-stop{background-position:-96px -160px}.ui-icon-eject{background-position:-112px -160px}.ui-icon-volume-off{background-position:-128px -160px}.ui-icon-volume-on{background-position:-144px -160px}.ui-icon-power{background-position:0 -176px}.ui-icon-signal-diag{background-position:-16px -176px}.ui-icon-signal{background-position:-32px -176px}.ui-icon-battery-0{background-position:-48px -176px}.ui-icon-battery-1{background-position:-64px -176px}.ui-icon-battery-2{background-position:-80px -176px}.ui-icon-battery-3{background-position:-96px -176px}.ui-icon-circle-plus{background-position:0 -192px}.ui-icon-circle-minus{background-position:-16px -192px}.ui-icon-circle-close{background-position:-32px -192px}.ui-icon-circle-triangle-e{background-position:-48px -192px}.ui-icon-circle-triangle-s{background-position:-64px -192px}.ui-icon-circle-triangle-w{background-position:-80px -192px}.ui-icon-circle-triangle-n{background-position:-96px -192px}.ui-icon-circle-arrow-e{background-position:-112px -192px}.ui-icon-circle-arrow-s{background-position:-128px -192px}.ui-icon-circle-arrow-w{background-position:-144px -192px}.ui-icon-circle-arrow-n{background-position:-160px -192px}.ui-icon-circle-zoomin{background-position:-176px -192px}.ui-icon-circle-zoomout{background-position:-192px -192px}.ui-icon-circle-check{background-position:-208px -192px}.ui-icon-circlesmall-plus{background-position:0 -208px}.ui-icon-circlesmall-minus{background-position:-16px -208px}.ui-icon-circlesmall-close{background-position:-32px -208px}.ui-icon-squaresmall-plus{background-position:-48px -208px}.ui-icon-squaresmall-minus{background-position:-64px -208px}.ui-icon-squaresmall-close{background-position:-80px -208px}.ui-icon-grip-dotted-vertical{background-position:0 -224px}.ui-icon-grip-dotted-horizontal{background-position:-16px -224px}.ui-icon-grip-solid-vertical{background-position:-32px -224px}.ui-icon-grip-solid-horizontal{background-position:-48px -224px}.ui-icon-gripsmall-diagonal-se{background-position:-64px -224px}.ui-icon-grip-diagonal-se{background-position:-80px -224px}.ui-corner-all,.ui-corner-top,.ui-corner-left,.ui-corner-tl{border-top-left-radius:3px}.ui-corner-all,.ui-corner-top,.ui-corner-right,.ui-corner-tr{border-top-right-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-left,.ui-corner-bl{border-bottom-left-radius:3px}.ui-corner-all,.ui-corner-bottom,.ui-corner-right,.ui-corner-br{border-bottom-right-radius:3px}.ui-widget-overlay{background:#aaa;opacity:.003;-ms-filter:Alpha(Opacity=.3)}.ui-widget-shadow{-webkit-box-shadow:0 0 5px #666;box-shadow:0 0 5px #666} \ No newline at end of file diff --git a/workshop/static/css/theme-mine.css b/workshop/static/css/theme-mine.css deleted file mode 100644 index 0b03489..0000000 --- a/workshop/static/css/theme-mine.css +++ /dev/null @@ -1,185 +0,0 @@ - -:root{ - - --MAIN-TEXT-color:#323235; /* Color of text by default */ - --MAIN-TITLES-TEXT-color: #778ba5; /* Color of titles h2-h3-h4-h5 */ - --MAIN-LINK-color:#4881cd; /* Color of links */ - --MAIN-LINK-HOVER-color:#599af1; /* Color of hovered links */ - --MAIN-ANCHOR-color: #4881cd; /* color of anchors on titles */ - - --MENU-HEADER-BG-color:#283e5b; /* Background color of menu header */ - --MENU-HEADER-BORDER-color:#435c7c; /*Color of menu header border */ - - --MENU-SEARCH-BG-color:#202c3c; /* Search field background color (by default borders + icons) */ - --MENU-SEARCH-BOX-color: #4d6584; /* Override search field border color */ - --MENU-SEARCH-BOX-ICONS-color: #4d6584; /* Override search field icons color */ - - --MENU-SECTIONS-ACTIVE-BG-color:#0a0c0e; /* Background color of the active section and its childs */ - --MENU-SECTIONS-BG-color:#1c222a; /* Background color of other sections */ - --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */ - --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6; /* Color of links in menu, when hovered */ - --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */ - --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */ - - --MENU-VISITED-color: #33a1ff; /* Color of 'page visited' icons in menu */ - --MENU-SECTION-HR-color: #20272b; /* Color of
separator in menu */ - -} - -body { - color: var(--MAIN-TEXT-color) !important; -} - -textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus { - border-color: none; - box-shadow: none; -} - -h2, h3, h4, h5 { - color: var(--MAIN-TITLES-TEXT-color) !important; -} - -a { - color: var(--MAIN-LINK-color); -} - -.anchor { - color: var(--MAIN-ANCHOR-color); -} - -a:hover { - color: var(--MAIN-LINK-HOVER-color); -} - -#sidebar ul li.visited > a .read-icon { - color: var(--MENU-VISITED-color); -} - -#sidebar #footer { - padding-top: 20px !important; -} - -#sidebar #footer h2.github-title { - font-size: 20px; - color: #fd9827 !important; - margin: 10px 0px 5px; - padding: 0px; - font-weight: normal !important; - margin-top: 10px; - padding-top: 30px; - border-top: 1px dotted #384657; -} - -#sidebar #footer h3.github-title { - font-size: 14px; - margin: 10px 0px 5px; - padding: 0px; - text-transform: uppercase; - letter-spacing: .15px; -} - -#sidebar #footer h5.copyright, #sidebar #footer p.build-number { - font-size: 10px; - letter-spacing: .15px; - line-height: 150% !important; -} - -#body a.highlight:after { - display: block; - content: ""; - height: 1px; - width: 0%; - -webkit-transition: width 0.5s ease; - -moz-transition: width 0.5s ease; - -ms-transition: width 0.5s ease; - transition: width 0.5s ease; - background-color: var(--MAIN-LINK-HOVER-color); -} -#sidebar { - background-color: var(--MENU-SECTIONS-BG-color); -} -#sidebar #header-wrapper { - background: var(--MENU-HEADER-BG-color); - color: var(--MENU-SEARCH-BOX-color); - border-color: var(--MENU-HEADER-BORDER-color); -} -#sidebar .searchbox { - border-color: var(--MENU-SEARCH-BOX-color); - background: var(--MENU-SEARCH-BG-color); -} -#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active { - background: var(--MENU-SECTIONS-ACTIVE-BG-color); -} -#sidebar .searchbox * { - color: var(--MENU-SEARCH-BOX-ICONS-color); -} - -#sidebar a { - color: var(--MENU-SECTIONS-LINK-color); -} - -#sidebar a:hover { - color: var(--MENU-SECTIONS-LINK-HOVER-color); -} - -#sidebar ul li.active > a { - background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color); - color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important; -} - -#sidebar hr { - border-color: var(--MENU-SECTION-HR-color); -} - -#navigation a.nav-prev, #navigation a.nav-next { - color: #f19e39 !important; -} - -#navigation a.nav-prev:hover, #navigation a.nav-next:hover { - color: #e07d04 !important; -} - -div.notices p:first-child:before { - position: absolute; - top: 2px; - color: #fff; - font-family: 'Font Awesome\ 5 Free'; - content: #F06A; - font-weight: 900; /* Fix version 5.0.9 */ - left: 10px; -} - -.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, .ui-button, html .ui-button.ui-state-disabled:hover, html .ui-button.ui-state-disabled:active { - border: 1px solid #dddddd; - font-weight: normal; - color: #454545; -} - -.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active, a.ui-button:active, .ui-button:active, .ui-button.ui-state-active:hover { - border: 1px solid var(--MENU-HEADER-BG-color); - background: var(--MENU-HEADER-BG-color); - font-weight: normal; - color: #fff; -} - -.ui-widget.ui-widget-content { - border: 1px solid #eeeeee; -} - -.ui-widget-header { - border: 1px solid #eeeeee; -} - -.hljs { - background-color: none; -} - -pre { - background-color: var(--MENU-SECTIONS-BG-color) !important; -} - -div.notices.info p { - border-top: 30px solid #fd9827; - background: #FFF2DB; -} - diff --git a/workshop/static/images/apn-logo.jpg b/workshop/static/images/apn-logo.jpg deleted file mode 100644 index ed7c429..0000000 Binary files a/workshop/static/images/apn-logo.jpg and /dev/null differ diff --git a/workshop/static/images/aws-open-source.jpg b/workshop/static/images/aws-open-source.jpg deleted file mode 100644 index c1759f3..0000000 Binary files a/workshop/static/images/aws-open-source.jpg and /dev/null differ diff --git a/workshop/static/images/deploy-to-aws.png b/workshop/static/images/deploy-to-aws.png deleted file mode 100644 index b6dba3f..0000000 Binary files a/workshop/static/images/deploy-to-aws.png and /dev/null differ diff --git a/workshop/static/images/wild-rydes.png b/workshop/static/images/wild-rydes.png deleted file mode 100644 index a9c6f7a..0000000 Binary files a/workshop/static/images/wild-rydes.png and /dev/null differ diff --git a/workshop/static/js/jquery-ui.min.js b/workshop/static/js/jquery-ui.min.js deleted file mode 100644 index c1cbc8b..0000000 --- a/workshop/static/js/jquery-ui.min.js +++ /dev/null @@ -1,6 +0,0 @@ -/*! jQuery UI - v1.13.1 - 2022-01-20 -* http://jqueryui.com -* Includes: widget.js, position.js, data.js, disable-selection.js, effect.js, effects/effect-blind.js, effects/effect-bounce.js, effects/effect-clip.js, effects/effect-drop.js, effects/effect-explode.js, effects/effect-fade.js, effects/effect-fold.js, effects/effect-highlight.js, effects/effect-puff.js, effects/effect-pulsate.js, effects/effect-scale.js, effects/effect-shake.js, effects/effect-size.js, effects/effect-slide.js, effects/effect-transfer.js, focusable.js, form-reset-mixin.js, jquery-patch.js, keycode.js, labels.js, scroll-parent.js, tabbable.js, unique-id.js, widgets/accordion.js, widgets/autocomplete.js, widgets/button.js, widgets/checkboxradio.js, widgets/controlgroup.js, widgets/datepicker.js, widgets/dialog.js, widgets/draggable.js, widgets/droppable.js, widgets/menu.js, widgets/mouse.js, widgets/progressbar.js, widgets/resizable.js, widgets/selectable.js, widgets/selectmenu.js, widgets/slider.js, widgets/sortable.js, widgets/spinner.js, widgets/tabs.js, widgets/tooltip.js -* Copyright jQuery Foundation and other contributors; Licensed MIT */ - -!function(t){"use strict";"function"==typeof define&&define.amd?define(["jquery"],t):t(jQuery)}(function(V){"use strict";V.ui=V.ui||{};V.ui.version="1.13.1";var n,i=0,a=Array.prototype.hasOwnProperty,r=Array.prototype.slice;V.cleanData=(n=V.cleanData,function(t){for(var e,i,s=0;null!=(i=t[s]);s++)(e=V._data(i,"events"))&&e.remove&&V(i).triggerHandler("remove");n(t)}),V.widget=function(t,i,e){var s,n,o,a={},r=t.split(".")[0],l=r+"-"+(t=t.split(".")[1]);return e||(e=i,i=V.Widget),Array.isArray(e)&&(e=V.extend.apply(null,[{}].concat(e))),V.expr.pseudos[l.toLowerCase()]=function(t){return!!V.data(t,l)},V[r]=V[r]||{},s=V[r][t],n=V[r][t]=function(t,e){if(!this||!this._createWidget)return new n(t,e);arguments.length&&this._createWidget(t,e)},V.extend(n,s,{version:e.version,_proto:V.extend({},e),_childConstructors:[]}),(o=new i).options=V.widget.extend({},o.options),V.each(e,function(e,s){function n(){return i.prototype[e].apply(this,arguments)}function o(t){return i.prototype[e].apply(this,t)}a[e]="function"==typeof s?function(){var t,e=this._super,i=this._superApply;return this._super=n,this._superApply=o,t=s.apply(this,arguments),this._super=e,this._superApply=i,t}:s}),n.prototype=V.widget.extend(o,{widgetEventPrefix:s&&o.widgetEventPrefix||t},a,{constructor:n,namespace:r,widgetName:t,widgetFullName:l}),s?(V.each(s._childConstructors,function(t,e){var i=e.prototype;V.widget(i.namespace+"."+i.widgetName,n,e._proto)}),delete s._childConstructors):i._childConstructors.push(n),V.widget.bridge(t,n),n},V.widget.extend=function(t){for(var e,i,s=r.call(arguments,1),n=0,o=s.length;n",options:{classes:{},disabled:!1,create:null},_createWidget:function(t,e){e=V(e||this.defaultElement||this)[0],this.element=V(e),this.uuid=i++,this.eventNamespace="."+this.widgetName+this.uuid,this.bindings=V(),this.hoverable=V(),this.focusable=V(),this.classesElementLookup={},e!==this&&(V.data(e,this.widgetFullName,this),this._on(!0,this.element,{remove:function(t){t.target===e&&this.destroy()}}),this.document=V(e.style?e.ownerDocument:e.document||e),this.window=V(this.document[0].defaultView||this.document[0].parentWindow)),this.options=V.widget.extend({},this.options,this._getCreateOptions(),t),this._create(),this.options.disabled&&this._setOptionDisabled(this.options.disabled),this._trigger("create",null,this._getCreateEventData()),this._init()},_getCreateOptions:function(){return{}},_getCreateEventData:V.noop,_create:V.noop,_init:V.noop,destroy:function(){var i=this;this._destroy(),V.each(this.classesElementLookup,function(t,e){i._removeClass(e,t)}),this.element.off(this.eventNamespace).removeData(this.widgetFullName),this.widget().off(this.eventNamespace).removeAttr("aria-disabled"),this.bindings.off(this.eventNamespace)},_destroy:V.noop,widget:function(){return this.element},option:function(t,e){var i,s,n,o=t;if(0===arguments.length)return V.widget.extend({},this.options);if("string"==typeof t)if(o={},t=(i=t.split(".")).shift(),i.length){for(s=o[t]=V.widget.extend({},this.options[t]),n=0;n
"),i=e.children()[0];return V("body").append(e),t=i.offsetWidth,e.css("overflow","scroll"),t===(i=i.offsetWidth)&&(i=e[0].clientWidth),e.remove(),s=t-i},getScrollInfo:function(t){var e=t.isWindow||t.isDocument?"":t.element.css("overflow-x"),i=t.isWindow||t.isDocument?"":t.element.css("overflow-y"),e="scroll"===e||"auto"===e&&t.widthx(k(s),k(n))?o.important="horizontal":o.important="vertical",u.using.call(this,t,o)}),a.offset(V.extend(h,{using:t}))})},V.ui.position={fit:{left:function(t,e){var i=e.within,s=i.isWindow?i.scrollLeft:i.offset.left,n=i.width,o=t.left-e.collisionPosition.marginLeft,a=s-o,r=o+e.collisionWidth-n-s;e.collisionWidth>n?0n?0")[0],w=d.each;function P(t){return null==t?t+"":"object"==typeof t?p[e.call(t)]||"object":typeof t}function M(t,e,i){var s=v[e.type]||{};return null==t?i||!e.def?null:e.def:(t=s.floor?~~t:parseFloat(t),isNaN(t)?e.def:s.mod?(t+s.mod)%s.mod:Math.min(s.max,Math.max(0,t)))}function S(s){var n=m(),o=n._rgba=[];return s=s.toLowerCase(),w(g,function(t,e){var i=e.re.exec(s),i=i&&e.parse(i),e=e.space||"rgba";if(i)return i=n[e](i),n[_[e].cache]=i[_[e].cache],o=n._rgba=i._rgba,!1}),o.length?("0,0,0,0"===o.join()&&d.extend(o,B.transparent),n):B[s]}function H(t,e,i){return 6*(i=(i+1)%1)<1?t+(e-t)*i*6:2*i<1?e:3*i<2?t+(e-t)*(2/3-i)*6:t}y.style.cssText="background-color:rgba(1,1,1,.5)",b.rgba=-1o.mod/2?s+=o.mod:s-n>o.mod/2&&(s-=o.mod)),l[i]=M((n-s)*a+s,e)))}),this[e](l)},blend:function(t){if(1===this._rgba[3])return this;var e=this._rgba.slice(),i=e.pop(),s=m(t)._rgba;return m(d.map(e,function(t,e){return(1-i)*s[e]+i*t}))},toRgbaString:function(){var t="rgba(",e=d.map(this._rgba,function(t,e){return null!=t?t:2
").addClass("ui-effects-wrapper").css({fontSize:"100%",background:"transparent",border:"none",margin:0,padding:0}),e={width:i.width(),height:i.height()},n=document.activeElement;try{n.id}catch(t){n=document.body}return i.wrap(t),i[0]!==n&&!V.contains(i[0],n)||V(n).trigger("focus"),t=i.parent(),"static"===i.css("position")?(t.css({position:"relative"}),i.css({position:"relative"})):(V.extend(s,{position:i.css("position"),zIndex:i.css("z-index")}),V.each(["top","left","bottom","right"],function(t,e){s[e]=i.css(e),isNaN(parseInt(s[e],10))&&(s[e]="auto")}),i.css({position:"relative",top:0,left:0,right:"auto",bottom:"auto"})),i.css(e),t.css(s).show()},removeWrapper:function(t){var e=document.activeElement;return t.parent().is(".ui-effects-wrapper")&&(t.parent().replaceWith(t),t[0]!==e&&!V.contains(t[0],e)||V(e).trigger("focus")),t}}),V.extend(V.effects,{version:"1.13.1",define:function(t,e,i){return i||(i=e,e="effect"),V.effects.effect[t]=i,V.effects.effect[t].mode=e,i},scaledDimensions:function(t,e,i){if(0===e)return{height:0,width:0,outerHeight:0,outerWidth:0};var s="horizontal"!==i?(e||100)/100:1,e="vertical"!==i?(e||100)/100:1;return{height:t.height()*e,width:t.width()*s,outerHeight:t.outerHeight()*e,outerWidth:t.outerWidth()*s}},clipToBox:function(t){return{width:t.clip.right-t.clip.left,height:t.clip.bottom-t.clip.top,left:t.clip.left,top:t.clip.top}},unshift:function(t,e,i){var s=t.queue();1").insertAfter(t).css({display:/^(inline|ruby)/.test(t.css("display"))?"inline-block":"block",visibility:"hidden",marginTop:t.css("marginTop"),marginBottom:t.css("marginBottom"),marginLeft:t.css("marginLeft"),marginRight:t.css("marginRight"),float:t.css("float")}).outerWidth(t.outerWidth()).outerHeight(t.outerHeight()).addClass("ui-effects-placeholder"),t.data(j+"placeholder",e)),t.css({position:i,left:s.left,top:s.top}),e},removePlaceholder:function(t){var e=j+"placeholder",i=t.data(e);i&&(i.remove(),t.removeData(e))},cleanUp:function(t){V.effects.restoreStyle(t),V.effects.removePlaceholder(t)},setTransition:function(s,t,n,o){return o=o||{},V.each(t,function(t,e){var i=s.cssUnit(e);0
");l.appendTo("body").addClass(t.className).css({top:s.top-a,left:s.left-r,height:i.innerHeight(),width:i.innerWidth(),position:n?"fixed":"absolute"}).animate(o,t.duration,t.easing,function(){l.remove(),"function"==typeof e&&e()})}}),V.fx.step.clip=function(t){t.clipInit||(t.start=V(t.elem).cssClip(),"string"==typeof t.end&&(t.end=G(t.end,t.elem)),t.clipInit=!0),V(t.elem).cssClip({top:t.pos*(t.end.top-t.start.top)+t.start.top,right:t.pos*(t.end.right-t.start.right)+t.start.right,bottom:t.pos*(t.end.bottom-t.start.bottom)+t.start.bottom,left:t.pos*(t.end.left-t.start.left)+t.start.left})},Y={},V.each(["Quad","Cubic","Quart","Quint","Expo"],function(e,t){Y[t]=function(t){return Math.pow(t,e+2)}}),V.extend(Y,{Sine:function(t){return 1-Math.cos(t*Math.PI/2)},Circ:function(t){return 1-Math.sqrt(1-t*t)},Elastic:function(t){return 0===t||1===t?t:-Math.pow(2,8*(t-1))*Math.sin((80*(t-1)-7.5)*Math.PI/15)},Back:function(t){return t*t*(3*t-2)},Bounce:function(t){for(var e,i=4;t<((e=Math.pow(2,--i))-1)/11;);return 1/Math.pow(4,3-i)-7.5625*Math.pow((3*e-2)/22-t,2)}}),V.each(Y,function(t,e){V.easing["easeIn"+t]=e,V.easing["easeOut"+t]=function(t){return 1-e(1-t)},V.easing["easeInOut"+t]=function(t){return t<.5?e(2*t)/2:1-e(-2*t+2)/2}});y=V.effects,V.effects.define("blind","hide",function(t,e){var i={up:["bottom","top"],vertical:["bottom","top"],down:["top","bottom"],left:["right","left"],horizontal:["right","left"],right:["left","right"]},s=V(this),n=t.direction||"up",o=s.cssClip(),a={clip:V.extend({},o)},r=V.effects.createPlaceholder(s);a.clip[i[n][0]]=a.clip[i[n][1]],"show"===t.mode&&(s.cssClip(a.clip),r&&r.css(V.effects.clipToBox(a)),a.clip=o),r&&r.animate(V.effects.clipToBox(a),t.duration,t.easing),s.animate(a,{queue:!1,duration:t.duration,easing:t.easing,complete:e})}),V.effects.define("bounce",function(t,e){var i,s,n=V(this),o=t.mode,a="hide"===o,r="show"===o,l=t.direction||"up",h=t.distance,c=t.times||5,o=2*c+(r||a?1:0),u=t.duration/o,d=t.easing,p="up"===l||"down"===l?"top":"left",f="up"===l||"left"===l,g=0,t=n.queue().length;for(V.effects.createPlaceholder(n),l=n.css(p),h=h||n["top"==p?"outerHeight":"outerWidth"]()/3,r&&((s={opacity:1})[p]=l,n.css("opacity",0).css(p,f?2*-h:2*h).animate(s,u,d)),a&&(h/=Math.pow(2,c-1)),(s={})[p]=l;g").css({position:"absolute",visibility:"visible",left:-s*p,top:-i*f}).parent().addClass("ui-effects-explode").css({position:"absolute",overflow:"hidden",width:p,height:f,left:n+(u?a*p:0),top:o+(u?r*f:0),opacity:u?0:1}).animate({left:n+(u?0:a*p),top:o+(u?0:r*f),opacity:u?1:0},t.duration||500,t.easing,m)}),V.effects.define("fade","toggle",function(t,e){var i="show"===t.mode;V(this).css("opacity",i?0:1).animate({opacity:i?1:0},{queue:!1,duration:t.duration,easing:t.easing,complete:e})}),V.effects.define("fold","hide",function(e,t){var i=V(this),s=e.mode,n="show"===s,o="hide"===s,a=e.size||15,r=/([0-9]+)%/.exec(a),l=!!e.horizFirst?["right","bottom"]:["bottom","right"],h=e.duration/2,c=V.effects.createPlaceholder(i),u=i.cssClip(),d={clip:V.extend({},u)},p={clip:V.extend({},u)},f=[u[l[0]],u[l[1]]],s=i.queue().length;r&&(a=parseInt(r[1],10)/100*f[o?0:1]),d.clip[l[0]]=a,p.clip[l[0]]=a,p.clip[l[1]]=0,n&&(i.cssClip(p.clip),c&&c.css(V.effects.clipToBox(p)),p.clip=u),i.queue(function(t){c&&c.animate(V.effects.clipToBox(d),h,e.easing).animate(V.effects.clipToBox(p),h,e.easing),t()}).animate(d,h,e.easing).animate(p,h,e.easing).queue(t),V.effects.unshift(i,s,4)}),V.effects.define("highlight","show",function(t,e){var i=V(this),s={backgroundColor:i.css("backgroundColor")};"hide"===t.mode&&(s.opacity=0),V.effects.saveStyle(i),i.css({backgroundImage:"none",backgroundColor:t.color||"#ffff99"}).animate(s,{queue:!1,duration:t.duration,easing:t.easing,complete:e})}),V.effects.define("size",function(s,e){var n,i=V(this),t=["fontSize"],o=["borderTopWidth","borderBottomWidth","paddingTop","paddingBottom"],a=["borderLeftWidth","borderRightWidth","paddingLeft","paddingRight"],r=s.mode,l="effect"!==r,h=s.scale||"both",c=s.origin||["middle","center"],u=i.css("position"),d=i.position(),p=V.effects.scaledDimensions(i),f=s.from||p,g=s.to||V.effects.scaledDimensions(i,0);V.effects.createPlaceholder(i),"show"===r&&(r=f,f=g,g=r),n={from:{y:f.height/p.height,x:f.width/p.width},to:{y:g.height/p.height,x:g.width/p.width}},"box"!==h&&"both"!==h||(n.from.y!==n.to.y&&(f=V.effects.setTransition(i,o,n.from.y,f),g=V.effects.setTransition(i,o,n.to.y,g)),n.from.x!==n.to.x&&(f=V.effects.setTransition(i,a,n.from.x,f),g=V.effects.setTransition(i,a,n.to.x,g))),"content"!==h&&"both"!==h||n.from.y!==n.to.y&&(f=V.effects.setTransition(i,t,n.from.y,f),g=V.effects.setTransition(i,t,n.to.y,g)),c&&(c=V.effects.getBaseline(c,p),f.top=(p.outerHeight-f.outerHeight)*c.y+d.top,f.left=(p.outerWidth-f.outerWidth)*c.x+d.left,g.top=(p.outerHeight-g.outerHeight)*c.y+d.top,g.left=(p.outerWidth-g.outerWidth)*c.x+d.left),delete f.outerHeight,delete f.outerWidth,i.css(f),"content"!==h&&"both"!==h||(o=o.concat(["marginTop","marginBottom"]).concat(t),a=a.concat(["marginLeft","marginRight"]),i.find("*[width]").each(function(){var t=V(this),e=V.effects.scaledDimensions(t),i={height:e.height*n.from.y,width:e.width*n.from.x,outerHeight:e.outerHeight*n.from.y,outerWidth:e.outerWidth*n.from.x},e={height:e.height*n.to.y,width:e.width*n.to.x,outerHeight:e.height*n.to.y,outerWidth:e.width*n.to.x};n.from.y!==n.to.y&&(i=V.effects.setTransition(t,o,n.from.y,i),e=V.effects.setTransition(t,o,n.to.y,e)),n.from.x!==n.to.x&&(i=V.effects.setTransition(t,a,n.from.x,i),e=V.effects.setTransition(t,a,n.to.x,e)),l&&V.effects.saveStyle(t),t.css(i),t.animate(e,s.duration,s.easing,function(){l&&V.effects.restoreStyle(t)})})),i.animate(g,{queue:!1,duration:s.duration,easing:s.easing,complete:function(){var t=i.offset();0===g.opacity&&i.css("opacity",f.opacity),l||(i.css("position","static"===u?"relative":u).offset(t),V.effects.saveStyle(i)),e()}})}),V.effects.define("scale",function(t,e){var i=V(this),s=t.mode,s=parseInt(t.percent,10)||(0===parseInt(t.percent,10)||"effect"!==s?0:100),s=V.extend(!0,{from:V.effects.scaledDimensions(i),to:V.effects.scaledDimensions(i,s,t.direction||"both"),origin:t.origin||["middle","center"]},t);t.fade&&(s.from.opacity=1,s.to.opacity=0),V.effects.effect.size.call(this,s,e)}),V.effects.define("puff","hide",function(t,e){t=V.extend(!0,{},t,{fade:!0,percent:parseInt(t.percent,10)||150});V.effects.effect.scale.call(this,t,e)}),V.effects.define("pulsate","show",function(t,e){var i=V(this),s=t.mode,n="show"===s,o=2*(t.times||5)+(n||"hide"===s?1:0),a=t.duration/o,r=0,l=1,s=i.queue().length;for(!n&&i.is(":visible")||(i.css("opacity",0).show(),r=1);l li > :first-child").add(t.find("> :not(li)").even())},heightStyle:"auto",icons:{activeHeader:"ui-icon-triangle-1-s",header:"ui-icon-triangle-1-e"},activate:null,beforeActivate:null},hideProps:{borderTopWidth:"hide",borderBottomWidth:"hide",paddingTop:"hide",paddingBottom:"hide",height:"hide"},showProps:{borderTopWidth:"show",borderBottomWidth:"show",paddingTop:"show",paddingBottom:"show",height:"show"},_create:function(){var t=this.options;this.prevShow=this.prevHide=V(),this._addClass("ui-accordion","ui-widget ui-helper-reset"),this.element.attr("role","tablist"),t.collapsible||!1!==t.active&&null!=t.active||(t.active=0),this._processPanels(),t.active<0&&(t.active+=this.headers.length),this._refresh()},_getCreateEventData:function(){return{header:this.active,panel:this.active.length?this.active.next():V()}},_createIcons:function(){var t,e=this.options.icons;e&&(t=V(""),this._addClass(t,"ui-accordion-header-icon","ui-icon "+e.header),t.prependTo(this.headers),t=this.active.children(".ui-accordion-header-icon"),this._removeClass(t,e.header)._addClass(t,null,e.activeHeader)._addClass(this.headers,"ui-accordion-icons"))},_destroyIcons:function(){this._removeClass(this.headers,"ui-accordion-icons"),this.headers.children(".ui-accordion-header-icon").remove()},_destroy:function(){var t;this.element.removeAttr("role"),this.headers.removeAttr("role aria-expanded aria-selected aria-controls tabIndex").removeUniqueId(),this._destroyIcons(),t=this.headers.next().css("display","").removeAttr("role aria-hidden aria-labelledby").removeUniqueId(),"content"!==this.options.heightStyle&&t.css("height","")},_setOption:function(t,e){"active"!==t?("event"===t&&(this.options.event&&this._off(this.headers,this.options.event),this._setupEvents(e)),this._super(t,e),"collapsible"!==t||e||!1!==this.options.active||this._activate(0),"icons"===t&&(this._destroyIcons(),e&&this._createIcons())):this._activate(e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",t),this._toggleClass(null,"ui-state-disabled",!!t),this._toggleClass(this.headers.add(this.headers.next()),null,"ui-state-disabled",!!t)},_keydown:function(t){if(!t.altKey&&!t.ctrlKey){var e=V.ui.keyCode,i=this.headers.length,s=this.headers.index(t.target),n=!1;switch(t.keyCode){case e.RIGHT:case e.DOWN:n=this.headers[(s+1)%i];break;case e.LEFT:case e.UP:n=this.headers[(s-1+i)%i];break;case e.SPACE:case e.ENTER:this._eventHandler(t);break;case e.HOME:n=this.headers[0];break;case e.END:n=this.headers[i-1]}n&&(V(t.target).attr("tabIndex",-1),V(n).attr("tabIndex",0),V(n).trigger("focus"),t.preventDefault())}},_panelKeyDown:function(t){t.keyCode===V.ui.keyCode.UP&&t.ctrlKey&&V(t.currentTarget).prev().trigger("focus")},refresh:function(){var t=this.options;this._processPanels(),!1===t.active&&!0===t.collapsible||!this.headers.length?(t.active=!1,this.active=V()):!1===t.active?this._activate(0):this.active.length&&!V.contains(this.element[0],this.active[0])?this.headers.length===this.headers.find(".ui-state-disabled").length?(t.active=!1,this.active=V()):this._activate(Math.max(0,t.active-1)):t.active=this.headers.index(this.active),this._destroyIcons(),this._refresh()},_processPanels:function(){var t=this.headers,e=this.panels;"function"==typeof this.options.header?this.headers=this.options.header(this.element):this.headers=this.element.find(this.options.header),this._addClass(this.headers,"ui-accordion-header ui-accordion-header-collapsed","ui-state-default"),this.panels=this.headers.next().filter(":not(.ui-accordion-content-active)").hide(),this._addClass(this.panels,"ui-accordion-content","ui-helper-reset ui-widget-content"),e&&(this._off(t.not(this.headers)),this._off(e.not(this.panels)))},_refresh:function(){var i,t=this.options,e=t.heightStyle,s=this.element.parent();this.active=this._findActive(t.active),this._addClass(this.active,"ui-accordion-header-active","ui-state-active")._removeClass(this.active,"ui-accordion-header-collapsed"),this._addClass(this.active.next(),"ui-accordion-content-active"),this.active.next().show(),this.headers.attr("role","tab").each(function(){var t=V(this),e=t.uniqueId().attr("id"),i=t.next(),s=i.uniqueId().attr("id");t.attr("aria-controls",s),i.attr("aria-labelledby",e)}).next().attr("role","tabpanel"),this.headers.not(this.active).attr({"aria-selected":"false","aria-expanded":"false",tabIndex:-1}).next().attr({"aria-hidden":"true"}).hide(),this.active.length?this.active.attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0}).next().attr({"aria-hidden":"false"}):this.headers.eq(0).attr("tabIndex",0),this._createIcons(),this._setupEvents(t.event),"fill"===e?(i=s.height(),this.element.siblings(":visible").each(function(){var t=V(this),e=t.css("position");"absolute"!==e&&"fixed"!==e&&(i-=t.outerHeight(!0))}),this.headers.each(function(){i-=V(this).outerHeight(!0)}),this.headers.next().each(function(){V(this).height(Math.max(0,i-V(this).innerHeight()+V(this).height()))}).css("overflow","auto")):"auto"===e&&(i=0,this.headers.next().each(function(){var t=V(this).is(":visible");t||V(this).show(),i=Math.max(i,V(this).css("height","").height()),t||V(this).hide()}).height(i))},_activate:function(t){t=this._findActive(t)[0];t!==this.active[0]&&(t=t||this.active[0],this._eventHandler({target:t,currentTarget:t,preventDefault:V.noop}))},_findActive:function(t){return"number"==typeof t?this.headers.eq(t):V()},_setupEvents:function(t){var i={keydown:"_keydown"};t&&V.each(t.split(" "),function(t,e){i[e]="_eventHandler"}),this._off(this.headers.add(this.headers.next())),this._on(this.headers,i),this._on(this.headers.next(),{keydown:"_panelKeyDown"}),this._hoverable(this.headers),this._focusable(this.headers)},_eventHandler:function(t){var e=this.options,i=this.active,s=V(t.currentTarget),n=s[0]===i[0],o=n&&e.collapsible,a=o?V():s.next(),r=i.next(),a={oldHeader:i,oldPanel:r,newHeader:o?V():s,newPanel:a};t.preventDefault(),n&&!e.collapsible||!1===this._trigger("beforeActivate",t,a)||(e.active=!o&&this.headers.index(s),this.active=n?V():s,this._toggle(a),this._removeClass(i,"ui-accordion-header-active","ui-state-active"),e.icons&&(i=i.children(".ui-accordion-header-icon"),this._removeClass(i,null,e.icons.activeHeader)._addClass(i,null,e.icons.header)),n||(this._removeClass(s,"ui-accordion-header-collapsed")._addClass(s,"ui-accordion-header-active","ui-state-active"),e.icons&&(n=s.children(".ui-accordion-header-icon"),this._removeClass(n,null,e.icons.header)._addClass(n,null,e.icons.activeHeader)),this._addClass(s.next(),"ui-accordion-content-active")))},_toggle:function(t){var e=t.newPanel,i=this.prevShow.length?this.prevShow:t.oldPanel;this.prevShow.add(this.prevHide).stop(!0,!0),this.prevShow=e,this.prevHide=i,this.options.animate?this._animate(e,i,t):(i.hide(),e.show(),this._toggleComplete(t)),i.attr({"aria-hidden":"true"}),i.prev().attr({"aria-selected":"false","aria-expanded":"false"}),e.length&&i.length?i.prev().attr({tabIndex:-1,"aria-expanded":"false"}):e.length&&this.headers.filter(function(){return 0===parseInt(V(this).attr("tabIndex"),10)}).attr("tabIndex",-1),e.attr("aria-hidden","false").prev().attr({"aria-selected":"true","aria-expanded":"true",tabIndex:0})},_animate:function(t,i,e){var s,n,o,a=this,r=0,l=t.css("box-sizing"),h=t.length&&(!i.length||t.index()",delay:300,options:{icons:{submenu:"ui-icon-caret-1-e"},items:"> *",menus:"ul",position:{my:"left top",at:"right top"},role:"menu",blur:null,focus:null,select:null},_create:function(){this.activeMenu=this.element,this.mouseHandled=!1,this.lastMousePosition={x:null,y:null},this.element.uniqueId().attr({role:this.options.role,tabIndex:0}),this._addClass("ui-menu","ui-widget ui-widget-content"),this._on({"mousedown .ui-menu-item":function(t){t.preventDefault(),this._activateItem(t)},"click .ui-menu-item":function(t){var e=V(t.target),i=V(V.ui.safeActiveElement(this.document[0]));!this.mouseHandled&&e.not(".ui-state-disabled").length&&(this.select(t),t.isPropagationStopped()||(this.mouseHandled=!0),e.has(".ui-menu").length?this.expand(t):!this.element.is(":focus")&&i.closest(".ui-menu").length&&(this.element.trigger("focus",[!0]),this.active&&1===this.active.parents(".ui-menu").length&&clearTimeout(this.timer)))},"mouseenter .ui-menu-item":"_activateItem","mousemove .ui-menu-item":"_activateItem",mouseleave:"collapseAll","mouseleave .ui-menu":"collapseAll",focus:function(t,e){var i=this.active||this._menuItems().first();e||this.focus(t,i)},blur:function(t){this._delay(function(){V.contains(this.element[0],V.ui.safeActiveElement(this.document[0]))||this.collapseAll(t)})},keydown:"_keydown"}),this.refresh(),this._on(this.document,{click:function(t){this._closeOnDocumentClick(t)&&this.collapseAll(t,!0),this.mouseHandled=!1}})},_activateItem:function(t){var e,i;this.previousFilter||t.clientX===this.lastMousePosition.x&&t.clientY===this.lastMousePosition.y||(this.lastMousePosition={x:t.clientX,y:t.clientY},e=V(t.target).closest(".ui-menu-item"),i=V(t.currentTarget),e[0]===i[0]&&(i.is(".ui-state-active")||(this._removeClass(i.siblings().children(".ui-state-active"),null,"ui-state-active"),this.focus(t,i))))},_destroy:function(){var t=this.element.find(".ui-menu-item").removeAttr("role aria-disabled").children(".ui-menu-item-wrapper").removeUniqueId().removeAttr("tabIndex role aria-haspopup");this.element.removeAttr("aria-activedescendant").find(".ui-menu").addBack().removeAttr("role aria-labelledby aria-expanded aria-hidden aria-disabled tabIndex").removeUniqueId().show(),t.children().each(function(){var t=V(this);t.data("ui-menu-submenu-caret")&&t.remove()})},_keydown:function(t){var e,i,s,n=!0;switch(t.keyCode){case V.ui.keyCode.PAGE_UP:this.previousPage(t);break;case V.ui.keyCode.PAGE_DOWN:this.nextPage(t);break;case V.ui.keyCode.HOME:this._move("first","first",t);break;case V.ui.keyCode.END:this._move("last","last",t);break;case V.ui.keyCode.UP:this.previous(t);break;case V.ui.keyCode.DOWN:this.next(t);break;case V.ui.keyCode.LEFT:this.collapse(t);break;case V.ui.keyCode.RIGHT:this.active&&!this.active.is(".ui-state-disabled")&&this.expand(t);break;case V.ui.keyCode.ENTER:case V.ui.keyCode.SPACE:this._activate(t);break;case V.ui.keyCode.ESCAPE:this.collapse(t);break;default:e=this.previousFilter||"",s=n=!1,i=96<=t.keyCode&&t.keyCode<=105?(t.keyCode-96).toString():String.fromCharCode(t.keyCode),clearTimeout(this.filterTimer),i===e?s=!0:i=e+i,e=this._filterMenuItems(i),(e=s&&-1!==e.index(this.active.next())?this.active.nextAll(".ui-menu-item"):e).length||(i=String.fromCharCode(t.keyCode),e=this._filterMenuItems(i)),e.length?(this.focus(t,e),this.previousFilter=i,this.filterTimer=this._delay(function(){delete this.previousFilter},1e3)):delete this.previousFilter}n&&t.preventDefault()},_activate:function(t){this.active&&!this.active.is(".ui-state-disabled")&&(this.active.children("[aria-haspopup='true']").length?this.expand(t):this.select(t))},refresh:function(){var t,e,s=this,n=this.options.icons.submenu,i=this.element.find(this.options.menus);this._toggleClass("ui-menu-icons",null,!!this.element.find(".ui-icon").length),e=i.filter(":not(.ui-menu)").hide().attr({role:this.options.role,"aria-hidden":"true","aria-expanded":"false"}).each(function(){var t=V(this),e=t.prev(),i=V("").data("ui-menu-submenu-caret",!0);s._addClass(i,"ui-menu-icon","ui-icon "+n),e.attr("aria-haspopup","true").prepend(i),t.attr("aria-labelledby",e.attr("id"))}),this._addClass(e,"ui-menu","ui-widget ui-widget-content ui-front"),(t=i.add(this.element).find(this.options.items)).not(".ui-menu-item").each(function(){var t=V(this);s._isDivider(t)&&s._addClass(t,"ui-menu-divider","ui-widget-content")}),i=(e=t.not(".ui-menu-item, .ui-menu-divider")).children().not(".ui-menu").uniqueId().attr({tabIndex:-1,role:this._itemRole()}),this._addClass(e,"ui-menu-item")._addClass(i,"ui-menu-item-wrapper"),t.filter(".ui-state-disabled").attr("aria-disabled","true"),this.active&&!V.contains(this.element[0],this.active[0])&&this.blur()},_itemRole:function(){return{menu:"menuitem",listbox:"option"}[this.options.role]},_setOption:function(t,e){var i;"icons"===t&&(i=this.element.find(".ui-menu-icon"),this._removeClass(i,null,this.options.icons.submenu)._addClass(i,null,e.submenu)),this._super(t,e)},_setOptionDisabled:function(t){this._super(t),this.element.attr("aria-disabled",String(t)),this._toggleClass(null,"ui-state-disabled",!!t)},focus:function(t,e){var i;this.blur(t,t&&"focus"===t.type),this._scrollIntoView(e),this.active=e.first(),i=this.active.children(".ui-menu-item-wrapper"),this._addClass(i,null,"ui-state-active"),this.options.role&&this.element.attr("aria-activedescendant",i.attr("id")),i=this.active.parent().closest(".ui-menu-item").children(".ui-menu-item-wrapper"),this._addClass(i,null,"ui-state-active"),t&&"keydown"===t.type?this._close():this.timer=this._delay(function(){this._close()},this.delay),(i=e.children(".ui-menu")).length&&t&&/^mouse/.test(t.type)&&this._startOpening(i),this.activeMenu=e.parent(),this._trigger("focus",t,{item:e})},_scrollIntoView:function(t){var e,i,s;this._hasScroll()&&(i=parseFloat(V.css(this.activeMenu[0],"borderTopWidth"))||0,s=parseFloat(V.css(this.activeMenu[0],"paddingTop"))||0,e=t.offset().top-this.activeMenu.offset().top-i-s,i=this.activeMenu.scrollTop(),s=this.activeMenu.height(),t=t.outerHeight(),e<0?this.activeMenu.scrollTop(i+e):s",options:{appendTo:null,autoFocus:!1,delay:300,minLength:1,position:{my:"left top",at:"left bottom",collision:"none"},source:null,change:null,close:null,focus:null,open:null,response:null,search:null,select:null},requestIndex:0,pending:0,liveRegionTimer:null,_create:function(){var i,s,n,t=this.element[0].nodeName.toLowerCase(),e="textarea"===t,t="input"===t;this.isMultiLine=e||!t&&this._isContentEditable(this.element),this.valueMethod=this.element[e||t?"val":"text"],this.isNewMenu=!0,this._addClass("ui-autocomplete-input"),this.element.attr("autocomplete","off"),this._on(this.element,{keydown:function(t){if(this.element.prop("readOnly"))s=n=i=!0;else{s=n=i=!1;var e=V.ui.keyCode;switch(t.keyCode){case e.PAGE_UP:i=!0,this._move("previousPage",t);break;case e.PAGE_DOWN:i=!0,this._move("nextPage",t);break;case e.UP:i=!0,this._keyEvent("previous",t);break;case e.DOWN:i=!0,this._keyEvent("next",t);break;case e.ENTER:this.menu.active&&(i=!0,t.preventDefault(),this.menu.select(t));break;case e.TAB:this.menu.active&&this.menu.select(t);break;case e.ESCAPE:this.menu.element.is(":visible")&&(this.isMultiLine||this._value(this.term),this.close(t),t.preventDefault());break;default:s=!0,this._searchTimeout(t)}}},keypress:function(t){if(i)return i=!1,void(this.isMultiLine&&!this.menu.element.is(":visible")||t.preventDefault());if(!s){var e=V.ui.keyCode;switch(t.keyCode){case e.PAGE_UP:this._move("previousPage",t);break;case e.PAGE_DOWN:this._move("nextPage",t);break;case e.UP:this._keyEvent("previous",t);break;case e.DOWN:this._keyEvent("next",t)}}},input:function(t){if(n)return n=!1,void t.preventDefault();this._searchTimeout(t)},focus:function(){this.selectedItem=null,this.previous=this._value()},blur:function(t){clearTimeout(this.searching),this.close(t),this._change(t)}}),this._initSource(),this.menu=V("
- -
-
-
- - - - - - - - - - - - - - - - {{ partial "custom-footer.html" . }} - - diff --git a/workshop/themes/learn/layouts/partials/header.html b/workshop/themes/learn/layouts/partials/header.html deleted file mode 100644 index c5c3013..0000000 --- a/workshop/themes/learn/layouts/partials/header.html +++ /dev/null @@ -1,100 +0,0 @@ - - - - - - - - - - {{ .Hugo.Generator }} - {{ partial "meta.html" . }} - {{ partial "favicon.html" . }} - {{ .Title }} :: {{ .Site.Title }} - - {{ $assetBusting := not .Site.Params.disableAssetsBusting }} - - - - - - - - - - {{with .Site.Params.themeVariant}} - - {{end}} - - - - - {{ partial "custom-header.html" . }} - - - - {{ partial "menu.html" . }} -
-
-
- {{if not .IsHome}} -
-
- {{ if and (or .IsPage .IsSection) .Site.Params.editURL }} - {{ $File := .File }} - {{ $Site := .Site }} - {{with $File.Path }} - - {{ end }} - {{ end }} - {{$toc := (and (not .Params.disableToc) (not .Params.chapter))}} - - {{ if $toc }} - {{ partial "toc.html" . }} - {{ end }} -
-
- {{ end }} - - {{ if .Params.chapter }} -
- {{ end }} -
-

{{.Title}}

- - {{define "breadcrumb"}} - {{$parent := .page.Parent }} - {{ if $parent }} - {{ $value := (printf "%s > %s" $parent.Permalink $parent.Title .value) }} - {{ template "breadcrumb" dict "page" $parent "value" $value }} - {{else}} - {{.value|safeHTML}} - {{end}} - {{end}} diff --git a/workshop/themes/learn/layouts/partials/logo.html b/workshop/themes/learn/layouts/partials/logo.html deleted file mode 100644 index 9633f9c..0000000 --- a/workshop/themes/learn/layouts/partials/logo.html +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/workshop/themes/learn/layouts/partials/menu-footer.html b/workshop/themes/learn/layouts/partials/menu-footer.html deleted file mode 100644 index 3ffb457..0000000 --- a/workshop/themes/learn/layouts/partials/menu-footer.html +++ /dev/null @@ -1,5 +0,0 @@ - - -
- - diff --git a/workshop/themes/learn/layouts/partials/menu.html b/workshop/themes/learn/layouts/partials/menu.html deleted file mode 100644 index 967fc6c..0000000 --- a/workshop/themes/learn/layouts/partials/menu.html +++ /dev/null @@ -1,150 +0,0 @@ - - - -{{ define "section-tree-nav" }} -{{ $showvisitedlinks := .showvisitedlinks }} -{{ $currentNode := .currentnode }} - {{with .sect}} - {{if .IsSection}} - {{safeHTML .Params.head}} -
  • - - {{safeHTML .Params.Pre}}{{or .Params.menuTitle .LinkTitle .Title}}{{safeHTML .Params.Post}} - {{ if $showvisitedlinks}} - - {{ end }} - - {{ $numberOfPages := (add (len .Pages) (len .Sections)) }} - {{ if ne $numberOfPages 0 }} -
      - {{ $currentNode.Scratch.Set "pages" .Pages }} - {{ if .Sections}} - {{ $currentNode.Scratch.Set "pages" (.Pages | union .Sections) }} - {{end}} - {{ $pages := ($currentNode.Scratch.Get "pages") }} - - {{if eq .Site.Params.ordersectionsby "title"}} - {{ range $pages.ByTitle }} - {{ if and .Params.hidden (not $.showhidden) }} - {{else}} - {{ template "section-tree-nav" dict "sect" . "currentnode" $currentNode "showvisitedlinks" $showvisitedlinks }} - {{end}} - {{ end }} - {{else}} - {{ range $pages.ByWeight }} - {{ if and .Params.hidden (not $.showhidden) }} - {{else}} - {{ template "section-tree-nav" dict "sect" . "currentnode" $currentNode "showvisitedlinks" $showvisitedlinks }} - {{end}} - {{ end }} - {{end}} -
    - {{ end }} -
  • - {{else}} - {{ if not .Params.Hidden }} -
  • - - {{safeHTML .Params.Pre}}{{or .Params.menuTitle .LinkTitle .Title}}{{safeHTML .Params.Post}} - {{ if $showvisitedlinks}}{{end}} - -
  • - {{ end }} - {{end}} - {{ end }} -{{ end }} - diff --git a/workshop/themes/learn/layouts/partials/meta.html b/workshop/themes/learn/layouts/partials/meta.html deleted file mode 100644 index 71d9634..0000000 --- a/workshop/themes/learn/layouts/partials/meta.html +++ /dev/null @@ -1,2 +0,0 @@ - -{{ with .Site.Params.author }}{{ end }} diff --git a/workshop/themes/learn/layouts/partials/search.html b/workshop/themes/learn/layouts/partials/search.html deleted file mode 100644 index 41daf84..0000000 --- a/workshop/themes/learn/layouts/partials/search.html +++ /dev/null @@ -1,16 +0,0 @@ - -{{ $assetBusting := not .Site.Params.disableAssetsBusting }} - - - - diff --git a/workshop/themes/learn/layouts/partials/tags.html b/workshop/themes/learn/layouts/partials/tags.html deleted file mode 100644 index 48790d8..0000000 --- a/workshop/themes/learn/layouts/partials/tags.html +++ /dev/null @@ -1,7 +0,0 @@ -{{ if .Params.tags }} -
    -{{range .Params.tags}} - {{ . }} -{{end}} -
    -{{end}} \ No newline at end of file diff --git a/workshop/themes/learn/layouts/partials/toc.html b/workshop/themes/learn/layouts/partials/toc.html deleted file mode 100644 index 6b69051..0000000 --- a/workshop/themes/learn/layouts/partials/toc.html +++ /dev/null @@ -1,5 +0,0 @@ -
    -
    -{{ .TableOfContents }} -
    -
    diff --git a/workshop/themes/learn/layouts/shortcodes/attachments.html b/workshop/themes/learn/layouts/shortcodes/attachments.html deleted file mode 100644 index 8e15c6a..0000000 --- a/workshop/themes/learn/layouts/shortcodes/attachments.html +++ /dev/null @@ -1,36 +0,0 @@ -{{ $_hugo_config := `{ "version": 1 }` }} -
    - - {{if eq .Page.File.BaseFileName "index"}} - {{$.Scratch.Add "filesName" "files"}} - {{else}} - {{$.Scratch.Add "filesName" (printf "%s.files" .Page.File.BaseFileName)}} - {{end}} -
    - {{ range (readDir (printf "./content/%s%s" .Page.File.Dir ($.Scratch.Get "filesName")) ) }} - {{ $fileDir := replace $.Page.File.Dir "\\" "/" }} - {{if ($.Get "pattern")}} - {{if (findRE ($.Get "pattern") .Name)}} -
  • - - {{.Name}} - - ({{div .Size 1024 }} kb) -
  • - {{end}} - {{else}} -
  • - - {{.Name}} - - ({{div .Size 1024 }} kb) -
  • - {{end}} - {{end}} -
    - {{.Inner}} -
    - diff --git a/workshop/themes/learn/layouts/shortcodes/button.html b/workshop/themes/learn/layouts/shortcodes/button.html deleted file mode 100644 index 7cfc389..0000000 --- a/workshop/themes/learn/layouts/shortcodes/button.html +++ /dev/null @@ -1,14 +0,0 @@ -{{ $_hugo_config := `{ "version": 1 }` }} - - {{ $icon := .Get "icon" }} - {{ $iconposition := .Get "icon-position" }} - {{ if ($icon) }} - {{ if or (not ($iconposition)) (eq $iconposition "left") }} - - {{ end }} - {{ end }} - {{ .Inner }} - {{ if and ($icon) (eq $iconposition "right")}} - - {{ end }} - diff --git a/workshop/themes/learn/layouts/shortcodes/cf-download.html b/workshop/themes/learn/layouts/shortcodes/cf-download.html deleted file mode 100644 index a3b2050..0000000 --- a/workshop/themes/learn/layouts/shortcodes/cf-download.html +++ /dev/null @@ -1,6 +0,0 @@ -{{ $_hugo_config := `{ "version": 1 }` }} - - -Download - diff --git a/workshop/themes/learn/layouts/shortcodes/children.html b/workshop/themes/learn/layouts/shortcodes/children.html deleted file mode 100644 index 6432791..0000000 --- a/workshop/themes/learn/layouts/shortcodes/children.html +++ /dev/null @@ -1,101 +0,0 @@ -{{ $_hugo_config := `{ "version": 1 }` }} -{{ $showhidden := .Get "showhidden"}} -{{ $style := .Get "style" | default "li" }} -{{ $depth := .Get "depth" | default 1 }} -{{ $withDescription := .Get "description" | default false }} -{{ $sortTerm := .Get "sort" | default "Weight" }} - -
      - {{ .Scratch.Set "pages" .Page.Pages }} - - {{if .Page.IsHome}} - - {{ $rootPage := where .Page.Pages "Dir" "" }} - {{ .Scratch.Set "pages" (.Page.Sections | union $rootPage)}} - {{else}} - {{ if .Page.Sections}} - {{ .Scratch.Set "pages" (.Page.Pages | union .Page.Sections) }} - {{end}} - {{end}} - - {{ $pages := (.Scratch.Get "pages") }} - - {{if eq $sortTerm "Weight"}} - {{template "childs" dict "menu" $pages.ByWeight "style" $style "showhidden" $showhidden "count" 1 "depth" $depth "pages" .Site.Pages "description" $withDescription "sortTerm" $sortTerm}} - {{else if eq $sortTerm "Name"}} - {{template "childs" dict "menu" $pages.ByTitle "style" $style "showhidden" $showhidden "count" 1 "depth" $depth "pages" .Site.Pages "description" $withDescription "sortTerm" $sortTerm}} - {{else if eq $sortTerm "PublishDate"}} - {{template "childs" dict "menu" $pages.ByPublishDate "style" $style "showhidden" $showhidden "count" 1 "depth" $depth "pages" .Site.Pages "description" $withDescription "sortTerm" $sortTerm}} - {{else if eq $sortTerm "Date"}} - {{template "childs" dict "menu" $pages.ByDate "style" $style "showhidden" $showhidden "count" 1 "depth" $depth "pages" .Site.Pages "description" $withDescription "sortTerm" $sortTerm}} - {{else if eq $sortTerm "Length"}} - {{template "childs" dict "menu" $pages.ByLength "style" $style "showhidden" $showhidden "count" 1 "depth" $depth "pages" .Site.Pages "description" $withDescription "sortTerm" $sortTerm}} - {{else}} - {{template "childs" dict "menu" $pages "style" $style "showhidden" $showhidden "count" 1 "depth" $depth "pages" .Site.Pages "description" $withDescription "sortTerm" $sortTerm}} - {{end}} -
    - -{{.Inner|safeHTML}} - -{{ define "childs" }} - {{ range .menu }} - {{ if and .Params.hidden (not $.showhidden) }} - {{else}} - {{if not .IsHome}} - {{if hasPrefix $.style "h"}} - {{$num := sub ( int (trim $.style "h") ) 1 }} - {{$numn := add $num $.count }} - -{{(printf "" $numn)|safeHTML}} -{{ .Title }} -{{(printf "" $numn)|safeHTML}} - - {{else}} -{{(printf "<%s>" $.style)|safeHTML}} -{{ .Title }} -{{(printf "" $.style)|safeHTML}} - {{end}} - - {{if $.description}} - {{if .Description}} -

    {{.Description}}

    - {{else}} -

    {{.Summary}}

    - {{end}} - {{end}} - {{end}} - {{ if lt $.count $.depth}} - - {{if eq $.style "li"}} -
      - {{end}} - - {{ if .Sections}} - {{ .Scratch.Set "pages" (.Pages | union .Sections) }} - {{else}} - {{ .Scratch.Set "pages" .Pages }} - {{end}} - - {{ $pages := (.Scratch.Get "pages") }} - - {{if eq $.sortTerm "Weight"}} - {{template "childs" dict "menu" $pages.ByWeight "style" $.style "showhidden" $.showhidden "count" (add $.count 1) "depth" $.depth "pages" $.pages "description" $.description "sortTerm" $.sortTerm}} - {{else if eq $.sortTerm "Name"}} - {{template "childs" dict "menu" $pages.ByTitle "style" $.style "showhidden" $.showhidden "count" (add $.count 1) "depth" $.depth "pages" $.pages "description" $.description "sortTerm" $.sortTerm}} - {{else if eq $.sortTerm "PublishDate"}} - {{template "childs" dict "menu" $pages.ByPublishDate "style" $.style "showhidden" $.showhidden "count" (add $.count 1) "depth" $.depth "pages" $.pages "description" $.description "sortTerm" $.sortTerm}} - {{else if eq $.sortTerm "Date"}} - {{template "childs" dict "menu" $pages.ByDate "style" $.style "showhidden" $.showhidden "count" (add $.count 1) "depth" $.depth "pages" $.pages "description" $.description "sortTerm" $.sortTerm}} - {{else if eq $.sortTerm "Length"}} - {{template "childs" dict "menu" $pages.ByLength "style" $.style "showhidden" $.showhidden "count" (add $.count 1) "depth" $.depth "pages" $.pages "description" $.description "sortTerm" $.sortTerm}} - {{else}} - {{template "childs" dict "menu" $pages "style" $.style "showhidden" $.showhidden "count" (add $.count 1) "depth" $.depth "pages" $.pages "description" $.description "sortTerm" $.sortTerm}} - {{end}} - - {{if eq $.style "li"}} -
    - {{end}} - {{end}} - {{end}} - {{end}} -{{end}} \ No newline at end of file diff --git a/workshop/themes/learn/layouts/shortcodes/expand.html b/workshop/themes/learn/layouts/shortcodes/expand.html deleted file mode 100644 index 0e7ddb1..0000000 --- a/workshop/themes/learn/layouts/shortcodes/expand.html +++ /dev/null @@ -1,17 +0,0 @@ -{{ $_hugo_config := `{ "version": 1 }` }} -
    -
    - - - {{$expandMessage := T "Expand-title"}} - {{ if .IsNamedParams }} - {{.Get "default" | default $expandMessage}} - {{else}} - {{.Get 0 | default $expandMessage}} - {{end}} - -
    - -
    \ No newline at end of file diff --git a/workshop/themes/learn/layouts/shortcodes/img.html b/workshop/themes/learn/layouts/shortcodes/img.html deleted file mode 100644 index a7e1397..0000000 --- a/workshop/themes/learn/layouts/shortcodes/img.html +++ /dev/null @@ -1,4 +0,0 @@ -{{ $img := $.Page.Resources.GetMatch (.Get 0)}} -
    - {{(.Get 1)}} -
    \ No newline at end of file diff --git a/workshop/themes/learn/layouts/shortcodes/mermaid.html b/workshop/themes/learn/layouts/shortcodes/mermaid.html deleted file mode 100644 index 287bc38..0000000 --- a/workshop/themes/learn/layouts/shortcodes/mermaid.html +++ /dev/null @@ -1,2 +0,0 @@ -{{ $_hugo_config := `{ "version": 1 }` }} -
    {{ safeHTML .Inner }}
    diff --git a/workshop/themes/learn/layouts/shortcodes/notice.html b/workshop/themes/learn/layouts/shortcodes/notice.html deleted file mode 100644 index 0e33247..0000000 --- a/workshop/themes/learn/layouts/shortcodes/notice.html +++ /dev/null @@ -1,2 +0,0 @@ -{{ $_hugo_config := `{ "version": 1 }` }} -
    {{ .Inner }}
    diff --git a/workshop/themes/learn/layouts/shortcodes/ref.html b/workshop/themes/learn/layouts/shortcodes/ref.html deleted file mode 100644 index 7b7eb42..0000000 --- a/workshop/themes/learn/layouts/shortcodes/ref.html +++ /dev/null @@ -1,14 +0,0 @@ -{{- if in (.Get 0) "/_index.md" -}} - {{- $paths := (split (.Get 0) "_index.md") -}} - {{- $pagepath := index $paths 0 -}} - {{- $anchor := index $paths 1 -}} - {{- with .Site.GetPage "section" (trim $pagepath "/") -}} - {{- ( printf "%s%s" $pagepath $anchor ) | relLangURL -}} - {{- end -}} -{{- else -}} - {{- with .Site.GetPage "section" (.Get 0) }} - {{- .RelPermalink -}} - {{- else -}} - {{- .Get 0 | relref .Page -}} - {{- end -}} -{{- end -}} \ No newline at end of file diff --git a/workshop/themes/learn/layouts/shortcodes/relref.html b/workshop/themes/learn/layouts/shortcodes/relref.html deleted file mode 100644 index 7b7eb42..0000000 --- a/workshop/themes/learn/layouts/shortcodes/relref.html +++ /dev/null @@ -1,14 +0,0 @@ -{{- if in (.Get 0) "/_index.md" -}} - {{- $paths := (split (.Get 0) "_index.md") -}} - {{- $pagepath := index $paths 0 -}} - {{- $anchor := index $paths 1 -}} - {{- with .Site.GetPage "section" (trim $pagepath "/") -}} - {{- ( printf "%s%s" $pagepath $anchor ) | relLangURL -}} - {{- end -}} -{{- else -}} - {{- with .Site.GetPage "section" (.Get 0) }} - {{- .RelPermalink -}} - {{- else -}} - {{- .Get 0 | relref .Page -}} - {{- end -}} -{{- end -}} \ No newline at end of file diff --git a/workshop/themes/learn/layouts/shortcodes/siteparam.html b/workshop/themes/learn/layouts/shortcodes/siteparam.html deleted file mode 100644 index 20cd2ca..0000000 --- a/workshop/themes/learn/layouts/shortcodes/siteparam.html +++ /dev/null @@ -1,7 +0,0 @@ -{{- $paramName := (.Get 0) -}} -{{- $siteParams := .Site.Params -}} -{{- with $paramName -}} - {{- with $siteParams -}} - {{- index . (lower $paramName) -}} - {{- end -}} -{{- end -}} \ No newline at end of file diff --git a/workshop/themes/learn/layouts/shortcodes/siteurl.html b/workshop/themes/learn/layouts/shortcodes/siteurl.html deleted file mode 100644 index af2adbe..0000000 --- a/workshop/themes/learn/layouts/shortcodes/siteurl.html +++ /dev/null @@ -1 +0,0 @@ -{{ .Page.Site.BaseURL }} \ No newline at end of file diff --git a/workshop/themes/learn/static/css/atom-one-dark-reasonable.css b/workshop/themes/learn/static/css/atom-one-dark-reasonable.css deleted file mode 100644 index fd41c99..0000000 --- a/workshop/themes/learn/static/css/atom-one-dark-reasonable.css +++ /dev/null @@ -1,77 +0,0 @@ -/* - -Atom One Dark With support for ReasonML by Gidi Morris, based off work by Daniel Gamage - -Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax - -*/ -.hljs { - display: block; - overflow-x: auto; - padding: 0.5em; - line-height: 1.3em; - color: #abb2bf; - background: #282c34; - border-radius: 5px; -} -.hljs-keyword, .hljs-operator { - color: #F92672; -} -.hljs-pattern-match { - color: #F92672; -} -.hljs-pattern-match .hljs-constructor { - color: #61aeee; -} -.hljs-function { - color: #61aeee; -} -.hljs-function .hljs-params { - color: #A6E22E; -} -.hljs-function .hljs-params .hljs-typing { - color: #FD971F; -} -.hljs-module-access .hljs-module { - color: #7e57c2; -} -.hljs-constructor { - color: #e2b93d; -} -.hljs-constructor .hljs-string { - color: #9CCC65; -} -.hljs-comment, .hljs-quote { - color: #b18eb1; - font-style: italic; -} -.hljs-doctag, .hljs-formula { - color: #c678dd; -} -.hljs-section, .hljs-name, .hljs-selector-tag, .hljs-deletion, .hljs-subst { - color: #e06c75; -} -.hljs-literal { - color: #56b6c2; -} -.hljs-string, .hljs-regexp, .hljs-addition, .hljs-attribute, .hljs-meta-string { - color: #98c379; -} -.hljs-built_in, .hljs-class .hljs-title { - color: #e6c07b; -} -.hljs-attr, .hljs-variable, .hljs-template-variable, .hljs-type, .hljs-selector-class, .hljs-selector-attr, .hljs-selector-pseudo, .hljs-number { - color: #d19a66; -} -.hljs-symbol, .hljs-bullet, .hljs-link, .hljs-meta, .hljs-selector-id, .hljs-title { - color: #61aeee; -} -.hljs-emphasis { - font-style: italic; -} -.hljs-strong { - font-weight: bold; -} -.hljs-link { - text-decoration: underline; -} diff --git a/workshop/themes/learn/static/css/auto-complete.css b/workshop/themes/learn/static/css/auto-complete.css deleted file mode 100644 index ac6979a..0000000 --- a/workshop/themes/learn/static/css/auto-complete.css +++ /dev/null @@ -1,47 +0,0 @@ -.autocomplete-suggestions { - text-align: left; - cursor: default; - border: 1px solid #ccc; - border-top: 0; - background: #fff; - box-shadow: -1px 1px 3px rgba(0,0,0,.1); - - /* core styles should not be changed */ - position: absolute; - display: none; - z-index: 9999; - max-height: 254px; - overflow: hidden; - overflow-y: auto; - box-sizing: border-box; - -} -.autocomplete-suggestion { - position: relative; - cursor: pointer; - padding: 7px; - line-height: 23px; - white-space: nowrap; - overflow: hidden; - text-overflow: ellipsis; - color: #333; -} - -.autocomplete-suggestion b { - font-weight: normal; - color: #1f8dd6; -} - -.autocomplete-suggestion.selected { - background: #333; - color: #fff; -} - -.autocomplete-suggestion:hover { - background: #444; - color: #fff; -} - -.autocomplete-suggestion > .context { - font-size: 12px; -} diff --git a/workshop/themes/learn/static/css/featherlight.min.css b/workshop/themes/learn/static/css/featherlight.min.css deleted file mode 100644 index 058487f..0000000 --- a/workshop/themes/learn/static/css/featherlight.min.css +++ /dev/null @@ -1,8 +0,0 @@ -/** - * Featherlight - ultra slim jQuery lightbox - * Version 1.7.13 - http://noelboss.github.io/featherlight/ - * - * Copyright 2018, Noël Raoul Bossart (http://www.noelboss.com) - * MIT Licensed. -**/ -html.with-featherlight{overflow:hidden}.featherlight{display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:2147483647;text-align:center;white-space:nowrap;cursor:pointer;background:#333;background:rgba(0,0,0,0)}.featherlight:last-of-type{background:rgba(0,0,0,.8)}.featherlight:before{content:'';display:inline-block;height:100%;vertical-align:middle}.featherlight .featherlight-content{position:relative;text-align:left;vertical-align:middle;display:inline-block;overflow:auto;padding:25px 25px 0;border-bottom:25px solid transparent;margin-left:5%;margin-right:5%;max-height:95%;background:#fff;cursor:auto;white-space:normal}.featherlight .featherlight-inner{display:block}.featherlight link.featherlight-inner,.featherlight script.featherlight-inner,.featherlight style.featherlight-inner{display:none}.featherlight .featherlight-close-icon{position:absolute;z-index:9999;top:0;right:0;line-height:25px;width:25px;cursor:pointer;text-align:center;font-family:Arial,sans-serif;background:#fff;background:rgba(255,255,255,.3);color:#000;border:0;padding:0}.featherlight .featherlight-close-icon::-moz-focus-inner{border:0;padding:0}.featherlight .featherlight-image{width:100%}.featherlight-iframe .featherlight-content{border-bottom:0;padding:0;-webkit-overflow-scrolling:touch}.featherlight iframe{border:0}.featherlight *{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}@media only screen and (max-width:1024px){.featherlight .featherlight-content{margin-left:0;margin-right:0;max-height:98%;padding:10px 10px 0;border-bottom:10px solid transparent}}@media print{html.with-featherlight>*>:not(.featherlight){display:none}} \ No newline at end of file diff --git a/workshop/themes/learn/static/css/fontawesome-all.min.css b/workshop/themes/learn/static/css/fontawesome-all.min.css deleted file mode 100644 index de56473..0000000 --- a/workshop/themes/learn/static/css/fontawesome-all.min.css +++ /dev/null @@ -1 +0,0 @@ -.fa,.fab,.fal,.far,.fas{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;display:inline-block;font-style:normal;font-variant:normal;text-rendering:auto;line-height:1}.fa-lg{font-size:1.33333em;line-height:.75em;vertical-align:-.0667em}.fa-xs{font-size:.75em}.fa-sm{font-size:.875em}.fa-1x{font-size:1em}.fa-2x{font-size:2em}.fa-3x{font-size:3em}.fa-4x{font-size:4em}.fa-5x{font-size:5em}.fa-6x{font-size:6em}.fa-7x{font-size:7em}.fa-8x{font-size:8em}.fa-9x{font-size:9em}.fa-10x{font-size:10em}.fa-fw{text-align:center;width:1.25em}.fa-ul{list-style-type:none;margin-left:2.5em;padding-left:0}.fa-ul>li{position:relative}.fa-li{left:-2em;position:absolute;text-align:center;width:2em;line-height:inherit}.fa-border{border:.08em solid #eee;border-radius:.1em;padding:.2em .25em .15em}.fa-pull-left{float:left}.fa-pull-right{float:right}.fa.fa-pull-left,.fab.fa-pull-left,.fal.fa-pull-left,.far.fa-pull-left,.fas.fa-pull-left{margin-right:.3em}.fa.fa-pull-right,.fab.fa-pull-right,.fal.fa-pull-right,.far.fa-pull-right,.fas.fa-pull-right{margin-left:.3em}.fa-spin{animation:fa-spin 2s infinite linear}.fa-pulse{animation:fa-spin 1s infinite steps(8)}@keyframes fa-spin{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.fa-rotate-90{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=1)";transform:rotate(90deg)}.fa-rotate-180{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2)";transform:rotate(180deg)}.fa-rotate-270{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=3)";transform:rotate(270deg)}.fa-flip-horizontal{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=0, mirror=1)";transform:scaleX(-1)}.fa-flip-vertical{transform:scaleY(-1)}.fa-flip-horizontal.fa-flip-vertical,.fa-flip-vertical{-ms-filter:"progid:DXImageTransform.Microsoft.BasicImage(rotation=2, mirror=1)"}.fa-flip-horizontal.fa-flip-vertical{transform:scale(-1)}:root .fa-flip-horizontal,:root .fa-flip-vertical,:root .fa-rotate-90,:root .fa-rotate-180,:root .fa-rotate-270{filter:none}.fa-stack{display:inline-block;height:2em;line-height:2em;position:relative;vertical-align:middle;width:2.5em}.fa-stack-1x,.fa-stack-2x{left:0;position:absolute;text-align:center;width:100%}.fa-stack-1x{line-height:inherit}.fa-stack-2x{font-size:2em}.fa-inverse{color:#fff}.fa-500px:before{content:"\f26e"}.fa-accessible-icon:before{content:"\f368"}.fa-accusoft:before{content:"\f369"}.fa-acquisitions-incorporated:before{content:"\f6af"}.fa-ad:before{content:"\f641"}.fa-address-book:before{content:"\f2b9"}.fa-address-card:before{content:"\f2bb"}.fa-adjust:before{content:"\f042"}.fa-adn:before{content:"\f170"}.fa-adobe:before{content:"\f778"}.fa-adversal:before{content:"\f36a"}.fa-affiliatetheme:before{content:"\f36b"}.fa-air-freshener:before{content:"\f5d0"}.fa-algolia:before{content:"\f36c"}.fa-align-center:before{content:"\f037"}.fa-align-justify:before{content:"\f039"}.fa-align-left:before{content:"\f036"}.fa-align-right:before{content:"\f038"}.fa-alipay:before{content:"\f642"}.fa-allergies:before{content:"\f461"}.fa-amazon:before{content:"\f270"}.fa-amazon-pay:before{content:"\f42c"}.fa-ambulance:before{content:"\f0f9"}.fa-american-sign-language-interpreting:before{content:"\f2a3"}.fa-amilia:before{content:"\f36d"}.fa-anchor:before{content:"\f13d"}.fa-android:before{content:"\f17b"}.fa-angellist:before{content:"\f209"}.fa-angle-double-down:before{content:"\f103"}.fa-angle-double-left:before{content:"\f100"}.fa-angle-double-right:before{content:"\f101"}.fa-angle-double-up:before{content:"\f102"}.fa-angle-down:before{content:"\f107"}.fa-angle-left:before{content:"\f104"}.fa-angle-right:before{content:"\f105"}.fa-angle-up:before{content:"\f106"}.fa-angry:before{content:"\f556"}.fa-angrycreative:before{content:"\f36e"}.fa-angular:before{content:"\f420"}.fa-ankh:before{content:"\f644"}.fa-app-store:before{content:"\f36f"}.fa-app-store-ios:before{content:"\f370"}.fa-apper:before{content:"\f371"}.fa-apple:before{content:"\f179"}.fa-apple-alt:before{content:"\f5d1"}.fa-apple-pay:before{content:"\f415"}.fa-archive:before{content:"\f187"}.fa-archway:before{content:"\f557"}.fa-arrow-alt-circle-down:before{content:"\f358"}.fa-arrow-alt-circle-left:before{content:"\f359"}.fa-arrow-alt-circle-right:before{content:"\f35a"}.fa-arrow-alt-circle-up:before{content:"\f35b"}.fa-arrow-circle-down:before{content:"\f0ab"}.fa-arrow-circle-left:before{content:"\f0a8"}.fa-arrow-circle-right:before{content:"\f0a9"}.fa-arrow-circle-up:before{content:"\f0aa"}.fa-arrow-down:before{content:"\f063"}.fa-arrow-left:before{content:"\f060"}.fa-arrow-right:before{content:"\f061"}.fa-arrow-up:before{content:"\f062"}.fa-arrows-alt:before{content:"\f0b2"}.fa-arrows-alt-h:before{content:"\f337"}.fa-arrows-alt-v:before{content:"\f338"}.fa-artstation:before{content:"\f77a"}.fa-assistive-listening-systems:before{content:"\f2a2"}.fa-asterisk:before{content:"\f069"}.fa-asymmetrik:before{content:"\f372"}.fa-at:before{content:"\f1fa"}.fa-atlas:before{content:"\f558"}.fa-atlassian:before{content:"\f77b"}.fa-atom:before{content:"\f5d2"}.fa-audible:before{content:"\f373"}.fa-audio-description:before{content:"\f29e"}.fa-autoprefixer:before{content:"\f41c"}.fa-avianex:before{content:"\f374"}.fa-aviato:before{content:"\f421"}.fa-award:before{content:"\f559"}.fa-aws:before{content:"\f375"}.fa-baby:before{content:"\f77c"}.fa-baby-carriage:before{content:"\f77d"}.fa-backspace:before{content:"\f55a"}.fa-backward:before{content:"\f04a"}.fa-balance-scale:before{content:"\f24e"}.fa-ban:before{content:"\f05e"}.fa-band-aid:before{content:"\f462"}.fa-bandcamp:before{content:"\f2d5"}.fa-barcode:before{content:"\f02a"}.fa-bars:before{content:"\f0c9"}.fa-baseball-ball:before{content:"\f433"}.fa-basketball-ball:before{content:"\f434"}.fa-bath:before{content:"\f2cd"}.fa-battery-empty:before{content:"\f244"}.fa-battery-full:before{content:"\f240"}.fa-battery-half:before{content:"\f242"}.fa-battery-quarter:before{content:"\f243"}.fa-battery-three-quarters:before{content:"\f241"}.fa-bed:before{content:"\f236"}.fa-beer:before{content:"\f0fc"}.fa-behance:before{content:"\f1b4"}.fa-behance-square:before{content:"\f1b5"}.fa-bell:before{content:"\f0f3"}.fa-bell-slash:before{content:"\f1f6"}.fa-bezier-curve:before{content:"\f55b"}.fa-bible:before{content:"\f647"}.fa-bicycle:before{content:"\f206"}.fa-bimobject:before{content:"\f378"}.fa-binoculars:before{content:"\f1e5"}.fa-biohazard:before{content:"\f780"}.fa-birthday-cake:before{content:"\f1fd"}.fa-bitbucket:before{content:"\f171"}.fa-bitcoin:before{content:"\f379"}.fa-bity:before{content:"\f37a"}.fa-black-tie:before{content:"\f27e"}.fa-blackberry:before{content:"\f37b"}.fa-blender:before{content:"\f517"}.fa-blender-phone:before{content:"\f6b6"}.fa-blind:before{content:"\f29d"}.fa-blog:before{content:"\f781"}.fa-blogger:before{content:"\f37c"}.fa-blogger-b:before{content:"\f37d"}.fa-bluetooth:before{content:"\f293"}.fa-bluetooth-b:before{content:"\f294"}.fa-bold:before{content:"\f032"}.fa-bolt:before{content:"\f0e7"}.fa-bomb:before{content:"\f1e2"}.fa-bone:before{content:"\f5d7"}.fa-bong:before{content:"\f55c"}.fa-book:before{content:"\f02d"}.fa-book-dead:before{content:"\f6b7"}.fa-book-open:before{content:"\f518"}.fa-book-reader:before{content:"\f5da"}.fa-bookmark:before{content:"\f02e"}.fa-bowling-ball:before{content:"\f436"}.fa-box:before{content:"\f466"}.fa-box-open:before{content:"\f49e"}.fa-boxes:before{content:"\f468"}.fa-braille:before{content:"\f2a1"}.fa-brain:before{content:"\f5dc"}.fa-briefcase:before{content:"\f0b1"}.fa-briefcase-medical:before{content:"\f469"}.fa-broadcast-tower:before{content:"\f519"}.fa-broom:before{content:"\f51a"}.fa-brush:before{content:"\f55d"}.fa-btc:before{content:"\f15a"}.fa-bug:before{content:"\f188"}.fa-building:before{content:"\f1ad"}.fa-bullhorn:before{content:"\f0a1"}.fa-bullseye:before{content:"\f140"}.fa-burn:before{content:"\f46a"}.fa-buromobelexperte:before{content:"\f37f"}.fa-bus:before{content:"\f207"}.fa-bus-alt:before{content:"\f55e"}.fa-business-time:before{content:"\f64a"}.fa-buysellads:before{content:"\f20d"}.fa-calculator:before{content:"\f1ec"}.fa-calendar:before{content:"\f133"}.fa-calendar-alt:before{content:"\f073"}.fa-calendar-check:before{content:"\f274"}.fa-calendar-day:before{content:"\f783"}.fa-calendar-minus:before{content:"\f272"}.fa-calendar-plus:before{content:"\f271"}.fa-calendar-times:before{content:"\f273"}.fa-calendar-week:before{content:"\f784"}.fa-camera:before{content:"\f030"}.fa-camera-retro:before{content:"\f083"}.fa-campground:before{content:"\f6bb"}.fa-canadian-maple-leaf:before{content:"\f785"}.fa-candy-cane:before{content:"\f786"}.fa-cannabis:before{content:"\f55f"}.fa-capsules:before{content:"\f46b"}.fa-car:before{content:"\f1b9"}.fa-car-alt:before{content:"\f5de"}.fa-car-battery:before{content:"\f5df"}.fa-car-crash:before{content:"\f5e1"}.fa-car-side:before{content:"\f5e4"}.fa-caret-down:before{content:"\f0d7"}.fa-caret-left:before{content:"\f0d9"}.fa-caret-right:before{content:"\f0da"}.fa-caret-square-down:before{content:"\f150"}.fa-caret-square-left:before{content:"\f191"}.fa-caret-square-right:before{content:"\f152"}.fa-caret-square-up:before{content:"\f151"}.fa-caret-up:before{content:"\f0d8"}.fa-carrot:before{content:"\f787"}.fa-cart-arrow-down:before{content:"\f218"}.fa-cart-plus:before{content:"\f217"}.fa-cash-register:before{content:"\f788"}.fa-cat:before{content:"\f6be"}.fa-cc-amazon-pay:before{content:"\f42d"}.fa-cc-amex:before{content:"\f1f3"}.fa-cc-apple-pay:before{content:"\f416"}.fa-cc-diners-club:before{content:"\f24c"}.fa-cc-discover:before{content:"\f1f2"}.fa-cc-jcb:before{content:"\f24b"}.fa-cc-mastercard:before{content:"\f1f1"}.fa-cc-paypal:before{content:"\f1f4"}.fa-cc-stripe:before{content:"\f1f5"}.fa-cc-visa:before{content:"\f1f0"}.fa-centercode:before{content:"\f380"}.fa-centos:before{content:"\f789"}.fa-certificate:before{content:"\f0a3"}.fa-chair:before{content:"\f6c0"}.fa-chalkboard:before{content:"\f51b"}.fa-chalkboard-teacher:before{content:"\f51c"}.fa-charging-station:before{content:"\f5e7"}.fa-chart-area:before{content:"\f1fe"}.fa-chart-bar:before{content:"\f080"}.fa-chart-line:before{content:"\f201"}.fa-chart-pie:before{content:"\f200"}.fa-check:before{content:"\f00c"}.fa-check-circle:before{content:"\f058"}.fa-check-double:before{content:"\f560"}.fa-check-square:before{content:"\f14a"}.fa-chess:before{content:"\f439"}.fa-chess-bishop:before{content:"\f43a"}.fa-chess-board:before{content:"\f43c"}.fa-chess-king:before{content:"\f43f"}.fa-chess-knight:before{content:"\f441"}.fa-chess-pawn:before{content:"\f443"}.fa-chess-queen:before{content:"\f445"}.fa-chess-rook:before{content:"\f447"}.fa-chevron-circle-down:before{content:"\f13a"}.fa-chevron-circle-left:before{content:"\f137"}.fa-chevron-circle-right:before{content:"\f138"}.fa-chevron-circle-up:before{content:"\f139"}.fa-chevron-down:before{content:"\f078"}.fa-chevron-left:before{content:"\f053"}.fa-chevron-right:before{content:"\f054"}.fa-chevron-up:before{content:"\f077"}.fa-child:before{content:"\f1ae"}.fa-chrome:before{content:"\f268"}.fa-church:before{content:"\f51d"}.fa-circle:before{content:"\f111"}.fa-circle-notch:before{content:"\f1ce"}.fa-city:before{content:"\f64f"}.fa-clipboard:before{content:"\f328"}.fa-clipboard-check:before{content:"\f46c"}.fa-clipboard-list:before{content:"\f46d"}.fa-clock:before{content:"\f017"}.fa-clone:before{content:"\f24d"}.fa-closed-captioning:before{content:"\f20a"}.fa-cloud:before{content:"\f0c2"}.fa-cloud-download-alt:before{content:"\f381"}.fa-cloud-meatball:before{content:"\f73b"}.fa-cloud-moon:before{content:"\f6c3"}.fa-cloud-moon-rain:before{content:"\f73c"}.fa-cloud-rain:before{content:"\f73d"}.fa-cloud-showers-heavy:before{content:"\f740"}.fa-cloud-sun:before{content:"\f6c4"}.fa-cloud-sun-rain:before{content:"\f743"}.fa-cloud-upload-alt:before{content:"\f382"}.fa-cloudscale:before{content:"\f383"}.fa-cloudsmith:before{content:"\f384"}.fa-cloudversify:before{content:"\f385"}.fa-cocktail:before{content:"\f561"}.fa-code:before{content:"\f121"}.fa-code-branch:before{content:"\f126"}.fa-codepen:before{content:"\f1cb"}.fa-codiepie:before{content:"\f284"}.fa-coffee:before{content:"\f0f4"}.fa-cog:before{content:"\f013"}.fa-cogs:before{content:"\f085"}.fa-coins:before{content:"\f51e"}.fa-columns:before{content:"\f0db"}.fa-comment:before{content:"\f075"}.fa-comment-alt:before{content:"\f27a"}.fa-comment-dollar:before{content:"\f651"}.fa-comment-dots:before{content:"\f4ad"}.fa-comment-slash:before{content:"\f4b3"}.fa-comments:before{content:"\f086"}.fa-comments-dollar:before{content:"\f653"}.fa-compact-disc:before{content:"\f51f"}.fa-compass:before{content:"\f14e"}.fa-compress:before{content:"\f066"}.fa-compress-arrows-alt:before{content:"\f78c"}.fa-concierge-bell:before{content:"\f562"}.fa-confluence:before{content:"\f78d"}.fa-connectdevelop:before{content:"\f20e"}.fa-contao:before{content:"\f26d"}.fa-cookie:before{content:"\f563"}.fa-cookie-bite:before{content:"\f564"}.fa-copy:before{content:"\f0c5"}.fa-copyright:before{content:"\f1f9"}.fa-couch:before{content:"\f4b8"}.fa-cpanel:before{content:"\f388"}.fa-creative-commons:before{content:"\f25e"}.fa-creative-commons-by:before{content:"\f4e7"}.fa-creative-commons-nc:before{content:"\f4e8"}.fa-creative-commons-nc-eu:before{content:"\f4e9"}.fa-creative-commons-nc-jp:before{content:"\f4ea"}.fa-creative-commons-nd:before{content:"\f4eb"}.fa-creative-commons-pd:before{content:"\f4ec"}.fa-creative-commons-pd-alt:before{content:"\f4ed"}.fa-creative-commons-remix:before{content:"\f4ee"}.fa-creative-commons-sa:before{content:"\f4ef"}.fa-creative-commons-sampling:before{content:"\f4f0"}.fa-creative-commons-sampling-plus:before{content:"\f4f1"}.fa-creative-commons-share:before{content:"\f4f2"}.fa-creative-commons-zero:before{content:"\f4f3"}.fa-credit-card:before{content:"\f09d"}.fa-critical-role:before{content:"\f6c9"}.fa-crop:before{content:"\f125"}.fa-crop-alt:before{content:"\f565"}.fa-cross:before{content:"\f654"}.fa-crosshairs:before{content:"\f05b"}.fa-crow:before{content:"\f520"}.fa-crown:before{content:"\f521"}.fa-css3:before{content:"\f13c"}.fa-css3-alt:before{content:"\f38b"}.fa-cube:before{content:"\f1b2"}.fa-cubes:before{content:"\f1b3"}.fa-cut:before{content:"\f0c4"}.fa-cuttlefish:before{content:"\f38c"}.fa-d-and-d:before{content:"\f38d"}.fa-d-and-d-beyond:before{content:"\f6ca"}.fa-dashcube:before{content:"\f210"}.fa-database:before{content:"\f1c0"}.fa-deaf:before{content:"\f2a4"}.fa-delicious:before{content:"\f1a5"}.fa-democrat:before{content:"\f747"}.fa-deploydog:before{content:"\f38e"}.fa-deskpro:before{content:"\f38f"}.fa-desktop:before{content:"\f108"}.fa-dev:before{content:"\f6cc"}.fa-deviantart:before{content:"\f1bd"}.fa-dharmachakra:before{content:"\f655"}.fa-dhl:before{content:"\f790"}.fa-diagnoses:before{content:"\f470"}.fa-diaspora:before{content:"\f791"}.fa-dice:before{content:"\f522"}.fa-dice-d20:before{content:"\f6cf"}.fa-dice-d6:before{content:"\f6d1"}.fa-dice-five:before{content:"\f523"}.fa-dice-four:before{content:"\f524"}.fa-dice-one:before{content:"\f525"}.fa-dice-six:before{content:"\f526"}.fa-dice-three:before{content:"\f527"}.fa-dice-two:before{content:"\f528"}.fa-digg:before{content:"\f1a6"}.fa-digital-ocean:before{content:"\f391"}.fa-digital-tachograph:before{content:"\f566"}.fa-directions:before{content:"\f5eb"}.fa-discord:before{content:"\f392"}.fa-discourse:before{content:"\f393"}.fa-divide:before{content:"\f529"}.fa-dizzy:before{content:"\f567"}.fa-dna:before{content:"\f471"}.fa-dochub:before{content:"\f394"}.fa-docker:before{content:"\f395"}.fa-dog:before{content:"\f6d3"}.fa-dollar-sign:before{content:"\f155"}.fa-dolly:before{content:"\f472"}.fa-dolly-flatbed:before{content:"\f474"}.fa-donate:before{content:"\f4b9"}.fa-door-closed:before{content:"\f52a"}.fa-door-open:before{content:"\f52b"}.fa-dot-circle:before{content:"\f192"}.fa-dove:before{content:"\f4ba"}.fa-download:before{content:"\f019"}.fa-draft2digital:before{content:"\f396"}.fa-drafting-compass:before{content:"\f568"}.fa-dragon:before{content:"\f6d5"}.fa-draw-polygon:before{content:"\f5ee"}.fa-dribbble:before{content:"\f17d"}.fa-dribbble-square:before{content:"\f397"}.fa-dropbox:before{content:"\f16b"}.fa-drum:before{content:"\f569"}.fa-drum-steelpan:before{content:"\f56a"}.fa-drumstick-bite:before{content:"\f6d7"}.fa-drupal:before{content:"\f1a9"}.fa-dumbbell:before{content:"\f44b"}.fa-dumpster:before{content:"\f793"}.fa-dumpster-fire:before{content:"\f794"}.fa-dungeon:before{content:"\f6d9"}.fa-dyalog:before{content:"\f399"}.fa-earlybirds:before{content:"\f39a"}.fa-ebay:before{content:"\f4f4"}.fa-edge:before{content:"\f282"}.fa-edit:before{content:"\f044"}.fa-eject:before{content:"\f052"}.fa-elementor:before{content:"\f430"}.fa-ellipsis-h:before{content:"\f141"}.fa-ellipsis-v:before{content:"\f142"}.fa-ello:before{content:"\f5f1"}.fa-ember:before{content:"\f423"}.fa-empire:before{content:"\f1d1"}.fa-envelope:before{content:"\f0e0"}.fa-envelope-open:before{content:"\f2b6"}.fa-envelope-open-text:before{content:"\f658"}.fa-envelope-square:before{content:"\f199"}.fa-envira:before{content:"\f299"}.fa-equals:before{content:"\f52c"}.fa-eraser:before{content:"\f12d"}.fa-erlang:before{content:"\f39d"}.fa-ethereum:before{content:"\f42e"}.fa-ethernet:before{content:"\f796"}.fa-etsy:before{content:"\f2d7"}.fa-euro-sign:before{content:"\f153"}.fa-exchange-alt:before{content:"\f362"}.fa-exclamation:before{content:"\f12a"}.fa-exclamation-circle:before{content:"\f06a"}.fa-exclamation-triangle:before{content:"\f071"}.fa-expand:before{content:"\f065"}.fa-expand-arrows-alt:before{content:"\f31e"}.fa-expeditedssl:before{content:"\f23e"}.fa-external-link-alt:before{content:"\f35d"}.fa-external-link-square-alt:before{content:"\f360"}.fa-eye:before{content:"\f06e"}.fa-eye-dropper:before{content:"\f1fb"}.fa-eye-slash:before{content:"\f070"}.fa-facebook:before{content:"\f09a"}.fa-facebook-f:before{content:"\f39e"}.fa-facebook-messenger:before{content:"\f39f"}.fa-facebook-square:before{content:"\f082"}.fa-fantasy-flight-games:before{content:"\f6dc"}.fa-fast-backward:before{content:"\f049"}.fa-fast-forward:before{content:"\f050"}.fa-fax:before{content:"\f1ac"}.fa-feather:before{content:"\f52d"}.fa-feather-alt:before{content:"\f56b"}.fa-fedex:before{content:"\f797"}.fa-fedora:before{content:"\f798"}.fa-female:before{content:"\f182"}.fa-fighter-jet:before{content:"\f0fb"}.fa-figma:before{content:"\f799"}.fa-file:before{content:"\f15b"}.fa-file-alt:before{content:"\f15c"}.fa-file-archive:before{content:"\f1c6"}.fa-file-audio:before{content:"\f1c7"}.fa-file-code:before{content:"\f1c9"}.fa-file-contract:before{content:"\f56c"}.fa-file-csv:before{content:"\f6dd"}.fa-file-download:before{content:"\f56d"}.fa-file-excel:before{content:"\f1c3"}.fa-file-export:before{content:"\f56e"}.fa-file-image:before{content:"\f1c5"}.fa-file-import:before{content:"\f56f"}.fa-file-invoice:before{content:"\f570"}.fa-file-invoice-dollar:before{content:"\f571"}.fa-file-medical:before{content:"\f477"}.fa-file-medical-alt:before{content:"\f478"}.fa-file-pdf:before{content:"\f1c1"}.fa-file-powerpoint:before{content:"\f1c4"}.fa-file-prescription:before{content:"\f572"}.fa-file-signature:before{content:"\f573"}.fa-file-upload:before{content:"\f574"}.fa-file-video:before{content:"\f1c8"}.fa-file-word:before{content:"\f1c2"}.fa-fill:before{content:"\f575"}.fa-fill-drip:before{content:"\f576"}.fa-film:before{content:"\f008"}.fa-filter:before{content:"\f0b0"}.fa-fingerprint:before{content:"\f577"}.fa-fire:before{content:"\f06d"}.fa-fire-alt:before{content:"\f7e4"}.fa-fire-extinguisher:before{content:"\f134"}.fa-firefox:before{content:"\f269"}.fa-first-aid:before{content:"\f479"}.fa-first-order:before{content:"\f2b0"}.fa-first-order-alt:before{content:"\f50a"}.fa-firstdraft:before{content:"\f3a1"}.fa-fish:before{content:"\f578"}.fa-fist-raised:before{content:"\f6de"}.fa-flag:before{content:"\f024"}.fa-flag-checkered:before{content:"\f11e"}.fa-flag-usa:before{content:"\f74d"}.fa-flask:before{content:"\f0c3"}.fa-flickr:before{content:"\f16e"}.fa-flipboard:before{content:"\f44d"}.fa-flushed:before{content:"\f579"}.fa-fly:before{content:"\f417"}.fa-folder:before{content:"\f07b"}.fa-folder-minus:before{content:"\f65d"}.fa-folder-open:before{content:"\f07c"}.fa-folder-plus:before{content:"\f65e"}.fa-font:before{content:"\f031"}.fa-font-awesome:before{content:"\f2b4"}.fa-font-awesome-alt:before{content:"\f35c"}.fa-font-awesome-flag:before{content:"\f425"}.fa-font-awesome-logo-full:before{content:"\f4e6"}.fa-fonticons:before{content:"\f280"}.fa-fonticons-fi:before{content:"\f3a2"}.fa-football-ball:before{content:"\f44e"}.fa-fort-awesome:before{content:"\f286"}.fa-fort-awesome-alt:before{content:"\f3a3"}.fa-forumbee:before{content:"\f211"}.fa-forward:before{content:"\f04e"}.fa-foursquare:before{content:"\f180"}.fa-free-code-camp:before{content:"\f2c5"}.fa-freebsd:before{content:"\f3a4"}.fa-frog:before{content:"\f52e"}.fa-frown:before{content:"\f119"}.fa-frown-open:before{content:"\f57a"}.fa-fulcrum:before{content:"\f50b"}.fa-funnel-dollar:before{content:"\f662"}.fa-futbol:before{content:"\f1e3"}.fa-galactic-republic:before{content:"\f50c"}.fa-galactic-senate:before{content:"\f50d"}.fa-gamepad:before{content:"\f11b"}.fa-gas-pump:before{content:"\f52f"}.fa-gavel:before{content:"\f0e3"}.fa-gem:before{content:"\f3a5"}.fa-genderless:before{content:"\f22d"}.fa-get-pocket:before{content:"\f265"}.fa-gg:before{content:"\f260"}.fa-gg-circle:before{content:"\f261"}.fa-ghost:before{content:"\f6e2"}.fa-gift:before{content:"\f06b"}.fa-gifts:before{content:"\f79c"}.fa-git:before{content:"\f1d3"}.fa-git-square:before{content:"\f1d2"}.fa-github:before{content:"\f09b"}.fa-github-alt:before{content:"\f113"}.fa-github-square:before{content:"\f092"}.fa-gitkraken:before{content:"\f3a6"}.fa-gitlab:before{content:"\f296"}.fa-gitter:before{content:"\f426"}.fa-glass-cheers:before{content:"\f79f"}.fa-glass-martini:before{content:"\f000"}.fa-glass-martini-alt:before{content:"\f57b"}.fa-glass-whiskey:before{content:"\f7a0"}.fa-glasses:before{content:"\f530"}.fa-glide:before{content:"\f2a5"}.fa-glide-g:before{content:"\f2a6"}.fa-globe:before{content:"\f0ac"}.fa-globe-africa:before{content:"\f57c"}.fa-globe-americas:before{content:"\f57d"}.fa-globe-asia:before{content:"\f57e"}.fa-globe-europe:before{content:"\f7a2"}.fa-gofore:before{content:"\f3a7"}.fa-golf-ball:before{content:"\f450"}.fa-goodreads:before{content:"\f3a8"}.fa-goodreads-g:before{content:"\f3a9"}.fa-google:before{content:"\f1a0"}.fa-google-drive:before{content:"\f3aa"}.fa-google-play:before{content:"\f3ab"}.fa-google-plus:before{content:"\f2b3"}.fa-google-plus-g:before{content:"\f0d5"}.fa-google-plus-square:before{content:"\f0d4"}.fa-google-wallet:before{content:"\f1ee"}.fa-gopuram:before{content:"\f664"}.fa-graduation-cap:before{content:"\f19d"}.fa-gratipay:before{content:"\f184"}.fa-grav:before{content:"\f2d6"}.fa-greater-than:before{content:"\f531"}.fa-greater-than-equal:before{content:"\f532"}.fa-grimace:before{content:"\f57f"}.fa-grin:before{content:"\f580"}.fa-grin-alt:before{content:"\f581"}.fa-grin-beam:before{content:"\f582"}.fa-grin-beam-sweat:before{content:"\f583"}.fa-grin-hearts:before{content:"\f584"}.fa-grin-squint:before{content:"\f585"}.fa-grin-squint-tears:before{content:"\f586"}.fa-grin-stars:before{content:"\f587"}.fa-grin-tears:before{content:"\f588"}.fa-grin-tongue:before{content:"\f589"}.fa-grin-tongue-squint:before{content:"\f58a"}.fa-grin-tongue-wink:before{content:"\f58b"}.fa-grin-wink:before{content:"\f58c"}.fa-grip-horizontal:before{content:"\f58d"}.fa-grip-lines:before{content:"\f7a4"}.fa-grip-lines-vertical:before{content:"\f7a5"}.fa-grip-vertical:before{content:"\f58e"}.fa-gripfire:before{content:"\f3ac"}.fa-grunt:before{content:"\f3ad"}.fa-guitar:before{content:"\f7a6"}.fa-gulp:before{content:"\f3ae"}.fa-h-square:before{content:"\f0fd"}.fa-hacker-news:before{content:"\f1d4"}.fa-hacker-news-square:before{content:"\f3af"}.fa-hackerrank:before{content:"\f5f7"}.fa-hammer:before{content:"\f6e3"}.fa-hamsa:before{content:"\f665"}.fa-hand-holding:before{content:"\f4bd"}.fa-hand-holding-heart:before{content:"\f4be"}.fa-hand-holding-usd:before{content:"\f4c0"}.fa-hand-lizard:before{content:"\f258"}.fa-hand-paper:before{content:"\f256"}.fa-hand-peace:before{content:"\f25b"}.fa-hand-point-down:before{content:"\f0a7"}.fa-hand-point-left:before{content:"\f0a5"}.fa-hand-point-right:before{content:"\f0a4"}.fa-hand-point-up:before{content:"\f0a6"}.fa-hand-pointer:before{content:"\f25a"}.fa-hand-rock:before{content:"\f255"}.fa-hand-scissors:before{content:"\f257"}.fa-hand-spock:before{content:"\f259"}.fa-hands:before{content:"\f4c2"}.fa-hands-helping:before{content:"\f4c4"}.fa-handshake:before{content:"\f2b5"}.fa-hanukiah:before{content:"\f6e6"}.fa-hashtag:before{content:"\f292"}.fa-hat-wizard:before{content:"\f6e8"}.fa-haykal:before{content:"\f666"}.fa-hdd:before{content:"\f0a0"}.fa-heading:before{content:"\f1dc"}.fa-headphones:before{content:"\f025"}.fa-headphones-alt:before{content:"\f58f"}.fa-headset:before{content:"\f590"}.fa-heart:before{content:"\f004"}.fa-heart-broken:before{content:"\f7a9"}.fa-heartbeat:before{content:"\f21e"}.fa-helicopter:before{content:"\f533"}.fa-highlighter:before{content:"\f591"}.fa-hiking:before{content:"\f6ec"}.fa-hippo:before{content:"\f6ed"}.fa-hips:before{content:"\f452"}.fa-hire-a-helper:before{content:"\f3b0"}.fa-history:before{content:"\f1da"}.fa-hockey-puck:before{content:"\f453"}.fa-holly-berry:before{content:"\f7aa"}.fa-home:before{content:"\f015"}.fa-hooli:before{content:"\f427"}.fa-hornbill:before{content:"\f592"}.fa-horse:before{content:"\f6f0"}.fa-horse-head:before{content:"\f7ab"}.fa-hospital:before{content:"\f0f8"}.fa-hospital-alt:before{content:"\f47d"}.fa-hospital-symbol:before{content:"\f47e"}.fa-hot-tub:before{content:"\f593"}.fa-hotel:before{content:"\f594"}.fa-hotjar:before{content:"\f3b1"}.fa-hourglass:before{content:"\f254"}.fa-hourglass-end:before{content:"\f253"}.fa-hourglass-half:before{content:"\f252"}.fa-hourglass-start:before{content:"\f251"}.fa-house-damage:before{content:"\f6f1"}.fa-houzz:before{content:"\f27c"}.fa-hryvnia:before{content:"\f6f2"}.fa-html5:before{content:"\f13b"}.fa-hubspot:before{content:"\f3b2"}.fa-i-cursor:before{content:"\f246"}.fa-icicles:before{content:"\f7ad"}.fa-id-badge:before{content:"\f2c1"}.fa-id-card:before{content:"\f2c2"}.fa-id-card-alt:before{content:"\f47f"}.fa-igloo:before{content:"\f7ae"}.fa-image:before{content:"\f03e"}.fa-images:before{content:"\f302"}.fa-imdb:before{content:"\f2d8"}.fa-inbox:before{content:"\f01c"}.fa-indent:before{content:"\f03c"}.fa-industry:before{content:"\f275"}.fa-infinity:before{content:"\f534"}.fa-info:before{content:"\f129"}.fa-info-circle:before{content:"\f05a"}.fa-instagram:before{content:"\f16d"}.fa-intercom:before{content:"\f7af"}.fa-internet-explorer:before{content:"\f26b"}.fa-invision:before{content:"\f7b0"}.fa-ioxhost:before{content:"\f208"}.fa-italic:before{content:"\f033"}.fa-itunes:before{content:"\f3b4"}.fa-itunes-note:before{content:"\f3b5"}.fa-java:before{content:"\f4e4"}.fa-jedi:before{content:"\f669"}.fa-jedi-order:before{content:"\f50e"}.fa-jenkins:before{content:"\f3b6"}.fa-jira:before{content:"\f7b1"}.fa-joget:before{content:"\f3b7"}.fa-joint:before{content:"\f595"}.fa-joomla:before{content:"\f1aa"}.fa-journal-whills:before{content:"\f66a"}.fa-js:before{content:"\f3b8"}.fa-js-square:before{content:"\f3b9"}.fa-jsfiddle:before{content:"\f1cc"}.fa-kaaba:before{content:"\f66b"}.fa-kaggle:before{content:"\f5fa"}.fa-key:before{content:"\f084"}.fa-keybase:before{content:"\f4f5"}.fa-keyboard:before{content:"\f11c"}.fa-keycdn:before{content:"\f3ba"}.fa-khanda:before{content:"\f66d"}.fa-kickstarter:before{content:"\f3bb"}.fa-kickstarter-k:before{content:"\f3bc"}.fa-kiss:before{content:"\f596"}.fa-kiss-beam:before{content:"\f597"}.fa-kiss-wink-heart:before{content:"\f598"}.fa-kiwi-bird:before{content:"\f535"}.fa-korvue:before{content:"\f42f"}.fa-landmark:before{content:"\f66f"}.fa-language:before{content:"\f1ab"}.fa-laptop:before{content:"\f109"}.fa-laptop-code:before{content:"\f5fc"}.fa-laravel:before{content:"\f3bd"}.fa-lastfm:before{content:"\f202"}.fa-lastfm-square:before{content:"\f203"}.fa-laugh:before{content:"\f599"}.fa-laugh-beam:before{content:"\f59a"}.fa-laugh-squint:before{content:"\f59b"}.fa-laugh-wink:before{content:"\f59c"}.fa-layer-group:before{content:"\f5fd"}.fa-leaf:before{content:"\f06c"}.fa-leanpub:before{content:"\f212"}.fa-lemon:before{content:"\f094"}.fa-less:before{content:"\f41d"}.fa-less-than:before{content:"\f536"}.fa-less-than-equal:before{content:"\f537"}.fa-level-down-alt:before{content:"\f3be"}.fa-level-up-alt:before{content:"\f3bf"}.fa-life-ring:before{content:"\f1cd"}.fa-lightbulb:before{content:"\f0eb"}.fa-line:before{content:"\f3c0"}.fa-link:before{content:"\f0c1"}.fa-linkedin:before{content:"\f08c"}.fa-linkedin-in:before{content:"\f0e1"}.fa-linode:before{content:"\f2b8"}.fa-linux:before{content:"\f17c"}.fa-lira-sign:before{content:"\f195"}.fa-list:before{content:"\f03a"}.fa-list-alt:before{content:"\f022"}.fa-list-ol:before{content:"\f0cb"}.fa-list-ul:before{content:"\f0ca"}.fa-location-arrow:before{content:"\f124"}.fa-lock:before{content:"\f023"}.fa-lock-open:before{content:"\f3c1"}.fa-long-arrow-alt-down:before{content:"\f309"}.fa-long-arrow-alt-left:before{content:"\f30a"}.fa-long-arrow-alt-right:before{content:"\f30b"}.fa-long-arrow-alt-up:before{content:"\f30c"}.fa-low-vision:before{content:"\f2a8"}.fa-luggage-cart:before{content:"\f59d"}.fa-lyft:before{content:"\f3c3"}.fa-magento:before{content:"\f3c4"}.fa-magic:before{content:"\f0d0"}.fa-magnet:before{content:"\f076"}.fa-mail-bulk:before{content:"\f674"}.fa-mailchimp:before{content:"\f59e"}.fa-male:before{content:"\f183"}.fa-mandalorian:before{content:"\f50f"}.fa-map:before{content:"\f279"}.fa-map-marked:before{content:"\f59f"}.fa-map-marked-alt:before{content:"\f5a0"}.fa-map-marker:before{content:"\f041"}.fa-map-marker-alt:before{content:"\f3c5"}.fa-map-pin:before{content:"\f276"}.fa-map-signs:before{content:"\f277"}.fa-markdown:before{content:"\f60f"}.fa-marker:before{content:"\f5a1"}.fa-mars:before{content:"\f222"}.fa-mars-double:before{content:"\f227"}.fa-mars-stroke:before{content:"\f229"}.fa-mars-stroke-h:before{content:"\f22b"}.fa-mars-stroke-v:before{content:"\f22a"}.fa-mask:before{content:"\f6fa"}.fa-mastodon:before{content:"\f4f6"}.fa-maxcdn:before{content:"\f136"}.fa-medal:before{content:"\f5a2"}.fa-medapps:before{content:"\f3c6"}.fa-medium:before{content:"\f23a"}.fa-medium-m:before{content:"\f3c7"}.fa-medkit:before{content:"\f0fa"}.fa-medrt:before{content:"\f3c8"}.fa-meetup:before{content:"\f2e0"}.fa-megaport:before{content:"\f5a3"}.fa-meh:before{content:"\f11a"}.fa-meh-blank:before{content:"\f5a4"}.fa-meh-rolling-eyes:before{content:"\f5a5"}.fa-memory:before{content:"\f538"}.fa-mendeley:before{content:"\f7b3"}.fa-menorah:before{content:"\f676"}.fa-mercury:before{content:"\f223"}.fa-meteor:before{content:"\f753"}.fa-microchip:before{content:"\f2db"}.fa-microphone:before{content:"\f130"}.fa-microphone-alt:before{content:"\f3c9"}.fa-microphone-alt-slash:before{content:"\f539"}.fa-microphone-slash:before{content:"\f131"}.fa-microscope:before{content:"\f610"}.fa-microsoft:before{content:"\f3ca"}.fa-minus:before{content:"\f068"}.fa-minus-circle:before{content:"\f056"}.fa-minus-square:before{content:"\f146"}.fa-mitten:before{content:"\f7b5"}.fa-mix:before{content:"\f3cb"}.fa-mixcloud:before{content:"\f289"}.fa-mizuni:before{content:"\f3cc"}.fa-mobile:before{content:"\f10b"}.fa-mobile-alt:before{content:"\f3cd"}.fa-modx:before{content:"\f285"}.fa-monero:before{content:"\f3d0"}.fa-money-bill:before{content:"\f0d6"}.fa-money-bill-alt:before{content:"\f3d1"}.fa-money-bill-wave:before{content:"\f53a"}.fa-money-bill-wave-alt:before{content:"\f53b"}.fa-money-check:before{content:"\f53c"}.fa-money-check-alt:before{content:"\f53d"}.fa-monument:before{content:"\f5a6"}.fa-moon:before{content:"\f186"}.fa-mortar-pestle:before{content:"\f5a7"}.fa-mosque:before{content:"\f678"}.fa-motorcycle:before{content:"\f21c"}.fa-mountain:before{content:"\f6fc"}.fa-mouse-pointer:before{content:"\f245"}.fa-mug-hot:before{content:"\f7b6"}.fa-music:before{content:"\f001"}.fa-napster:before{content:"\f3d2"}.fa-neos:before{content:"\f612"}.fa-network-wired:before{content:"\f6ff"}.fa-neuter:before{content:"\f22c"}.fa-newspaper:before{content:"\f1ea"}.fa-nimblr:before{content:"\f5a8"}.fa-nintendo-switch:before{content:"\f418"}.fa-node:before{content:"\f419"}.fa-node-js:before{content:"\f3d3"}.fa-not-equal:before{content:"\f53e"}.fa-notes-medical:before{content:"\f481"}.fa-npm:before{content:"\f3d4"}.fa-ns8:before{content:"\f3d5"}.fa-nutritionix:before{content:"\f3d6"}.fa-object-group:before{content:"\f247"}.fa-object-ungroup:before{content:"\f248"}.fa-odnoklassniki:before{content:"\f263"}.fa-odnoklassniki-square:before{content:"\f264"}.fa-oil-can:before{content:"\f613"}.fa-old-republic:before{content:"\f510"}.fa-om:before{content:"\f679"}.fa-opencart:before{content:"\f23d"}.fa-openid:before{content:"\f19b"}.fa-opera:before{content:"\f26a"}.fa-optin-monster:before{content:"\f23c"}.fa-osi:before{content:"\f41a"}.fa-otter:before{content:"\f700"}.fa-outdent:before{content:"\f03b"}.fa-page4:before{content:"\f3d7"}.fa-pagelines:before{content:"\f18c"}.fa-paint-brush:before{content:"\f1fc"}.fa-paint-roller:before{content:"\f5aa"}.fa-palette:before{content:"\f53f"}.fa-palfed:before{content:"\f3d8"}.fa-pallet:before{content:"\f482"}.fa-paper-plane:before{content:"\f1d8"}.fa-paperclip:before{content:"\f0c6"}.fa-parachute-box:before{content:"\f4cd"}.fa-paragraph:before{content:"\f1dd"}.fa-parking:before{content:"\f540"}.fa-passport:before{content:"\f5ab"}.fa-pastafarianism:before{content:"\f67b"}.fa-paste:before{content:"\f0ea"}.fa-patreon:before{content:"\f3d9"}.fa-pause:before{content:"\f04c"}.fa-pause-circle:before{content:"\f28b"}.fa-paw:before{content:"\f1b0"}.fa-paypal:before{content:"\f1ed"}.fa-peace:before{content:"\f67c"}.fa-pen:before{content:"\f304"}.fa-pen-alt:before{content:"\f305"}.fa-pen-fancy:before{content:"\f5ac"}.fa-pen-nib:before{content:"\f5ad"}.fa-pen-square:before{content:"\f14b"}.fa-pencil-alt:before{content:"\f303"}.fa-pencil-ruler:before{content:"\f5ae"}.fa-penny-arcade:before{content:"\f704"}.fa-people-carry:before{content:"\f4ce"}.fa-percent:before{content:"\f295"}.fa-percentage:before{content:"\f541"}.fa-periscope:before{content:"\f3da"}.fa-person-booth:before{content:"\f756"}.fa-phabricator:before{content:"\f3db"}.fa-phoenix-framework:before{content:"\f3dc"}.fa-phoenix-squadron:before{content:"\f511"}.fa-phone:before{content:"\f095"}.fa-phone-slash:before{content:"\f3dd"}.fa-phone-square:before{content:"\f098"}.fa-phone-volume:before{content:"\f2a0"}.fa-php:before{content:"\f457"}.fa-pied-piper:before{content:"\f2ae"}.fa-pied-piper-alt:before{content:"\f1a8"}.fa-pied-piper-hat:before{content:"\f4e5"}.fa-pied-piper-pp:before{content:"\f1a7"}.fa-piggy-bank:before{content:"\f4d3"}.fa-pills:before{content:"\f484"}.fa-pinterest:before{content:"\f0d2"}.fa-pinterest-p:before{content:"\f231"}.fa-pinterest-square:before{content:"\f0d3"}.fa-place-of-worship:before{content:"\f67f"}.fa-plane:before{content:"\f072"}.fa-plane-arrival:before{content:"\f5af"}.fa-plane-departure:before{content:"\f5b0"}.fa-play:before{content:"\f04b"}.fa-play-circle:before{content:"\f144"}.fa-playstation:before{content:"\f3df"}.fa-plug:before{content:"\f1e6"}.fa-plus:before{content:"\f067"}.fa-plus-circle:before{content:"\f055"}.fa-plus-square:before{content:"\f0fe"}.fa-podcast:before{content:"\f2ce"}.fa-poll:before{content:"\f681"}.fa-poll-h:before{content:"\f682"}.fa-poo:before{content:"\f2fe"}.fa-poo-storm:before{content:"\f75a"}.fa-poop:before{content:"\f619"}.fa-portrait:before{content:"\f3e0"}.fa-pound-sign:before{content:"\f154"}.fa-power-off:before{content:"\f011"}.fa-pray:before{content:"\f683"}.fa-praying-hands:before{content:"\f684"}.fa-prescription:before{content:"\f5b1"}.fa-prescription-bottle:before{content:"\f485"}.fa-prescription-bottle-alt:before{content:"\f486"}.fa-print:before{content:"\f02f"}.fa-procedures:before{content:"\f487"}.fa-product-hunt:before{content:"\f288"}.fa-project-diagram:before{content:"\f542"}.fa-pushed:before{content:"\f3e1"}.fa-puzzle-piece:before{content:"\f12e"}.fa-python:before{content:"\f3e2"}.fa-qq:before{content:"\f1d6"}.fa-qrcode:before{content:"\f029"}.fa-question:before{content:"\f128"}.fa-question-circle:before{content:"\f059"}.fa-quidditch:before{content:"\f458"}.fa-quinscape:before{content:"\f459"}.fa-quora:before{content:"\f2c4"}.fa-quote-left:before{content:"\f10d"}.fa-quote-right:before{content:"\f10e"}.fa-quran:before{content:"\f687"}.fa-r-project:before{content:"\f4f7"}.fa-radiation:before{content:"\f7b9"}.fa-radiation-alt:before{content:"\f7ba"}.fa-rainbow:before{content:"\f75b"}.fa-random:before{content:"\f074"}.fa-raspberry-pi:before{content:"\f7bb"}.fa-ravelry:before{content:"\f2d9"}.fa-react:before{content:"\f41b"}.fa-reacteurope:before{content:"\f75d"}.fa-readme:before{content:"\f4d5"}.fa-rebel:before{content:"\f1d0"}.fa-receipt:before{content:"\f543"}.fa-recycle:before{content:"\f1b8"}.fa-red-river:before{content:"\f3e3"}.fa-reddit:before{content:"\f1a1"}.fa-reddit-alien:before{content:"\f281"}.fa-reddit-square:before{content:"\f1a2"}.fa-redhat:before{content:"\f7bc"}.fa-redo:before{content:"\f01e"}.fa-redo-alt:before{content:"\f2f9"}.fa-registered:before{content:"\f25d"}.fa-renren:before{content:"\f18b"}.fa-reply:before{content:"\f3e5"}.fa-reply-all:before{content:"\f122"}.fa-replyd:before{content:"\f3e6"}.fa-republican:before{content:"\f75e"}.fa-researchgate:before{content:"\f4f8"}.fa-resolving:before{content:"\f3e7"}.fa-restroom:before{content:"\f7bd"}.fa-retweet:before{content:"\f079"}.fa-rev:before{content:"\f5b2"}.fa-ribbon:before{content:"\f4d6"}.fa-ring:before{content:"\f70b"}.fa-road:before{content:"\f018"}.fa-robot:before{content:"\f544"}.fa-rocket:before{content:"\f135"}.fa-rocketchat:before{content:"\f3e8"}.fa-rockrms:before{content:"\f3e9"}.fa-route:before{content:"\f4d7"}.fa-rss:before{content:"\f09e"}.fa-rss-square:before{content:"\f143"}.fa-ruble-sign:before{content:"\f158"}.fa-ruler:before{content:"\f545"}.fa-ruler-combined:before{content:"\f546"}.fa-ruler-horizontal:before{content:"\f547"}.fa-ruler-vertical:before{content:"\f548"}.fa-running:before{content:"\f70c"}.fa-rupee-sign:before{content:"\f156"}.fa-sad-cry:before{content:"\f5b3"}.fa-sad-tear:before{content:"\f5b4"}.fa-safari:before{content:"\f267"}.fa-sass:before{content:"\f41e"}.fa-satellite:before{content:"\f7bf"}.fa-satellite-dish:before{content:"\f7c0"}.fa-save:before{content:"\f0c7"}.fa-schlix:before{content:"\f3ea"}.fa-school:before{content:"\f549"}.fa-screwdriver:before{content:"\f54a"}.fa-scribd:before{content:"\f28a"}.fa-scroll:before{content:"\f70e"}.fa-sd-card:before{content:"\f7c2"}.fa-search:before{content:"\f002"}.fa-search-dollar:before{content:"\f688"}.fa-search-location:before{content:"\f689"}.fa-search-minus:before{content:"\f010"}.fa-search-plus:before{content:"\f00e"}.fa-searchengin:before{content:"\f3eb"}.fa-seedling:before{content:"\f4d8"}.fa-sellcast:before{content:"\f2da"}.fa-sellsy:before{content:"\f213"}.fa-server:before{content:"\f233"}.fa-servicestack:before{content:"\f3ec"}.fa-shapes:before{content:"\f61f"}.fa-share:before{content:"\f064"}.fa-share-alt:before{content:"\f1e0"}.fa-share-alt-square:before{content:"\f1e1"}.fa-share-square:before{content:"\f14d"}.fa-shekel-sign:before{content:"\f20b"}.fa-shield-alt:before{content:"\f3ed"}.fa-ship:before{content:"\f21a"}.fa-shipping-fast:before{content:"\f48b"}.fa-shirtsinbulk:before{content:"\f214"}.fa-shoe-prints:before{content:"\f54b"}.fa-shopping-bag:before{content:"\f290"}.fa-shopping-basket:before{content:"\f291"}.fa-shopping-cart:before{content:"\f07a"}.fa-shopware:before{content:"\f5b5"}.fa-shower:before{content:"\f2cc"}.fa-shuttle-van:before{content:"\f5b6"}.fa-sign:before{content:"\f4d9"}.fa-sign-in-alt:before{content:"\f2f6"}.fa-sign-language:before{content:"\f2a7"}.fa-sign-out-alt:before{content:"\f2f5"}.fa-signal:before{content:"\f012"}.fa-signature:before{content:"\f5b7"}.fa-sim-card:before{content:"\f7c4"}.fa-simplybuilt:before{content:"\f215"}.fa-sistrix:before{content:"\f3ee"}.fa-sitemap:before{content:"\f0e8"}.fa-sith:before{content:"\f512"}.fa-skating:before{content:"\f7c5"}.fa-sketch:before{content:"\f7c6"}.fa-skiing:before{content:"\f7c9"}.fa-skiing-nordic:before{content:"\f7ca"}.fa-skull:before{content:"\f54c"}.fa-skull-crossbones:before{content:"\f714"}.fa-skyatlas:before{content:"\f216"}.fa-skype:before{content:"\f17e"}.fa-slack:before{content:"\f198"}.fa-slack-hash:before{content:"\f3ef"}.fa-slash:before{content:"\f715"}.fa-sleigh:before{content:"\f7cc"}.fa-sliders-h:before{content:"\f1de"}.fa-slideshare:before{content:"\f1e7"}.fa-smile:before{content:"\f118"}.fa-smile-beam:before{content:"\f5b8"}.fa-smile-wink:before{content:"\f4da"}.fa-smog:before{content:"\f75f"}.fa-smoking:before{content:"\f48d"}.fa-smoking-ban:before{content:"\f54d"}.fa-sms:before{content:"\f7cd"}.fa-snapchat:before{content:"\f2ab"}.fa-snapchat-ghost:before{content:"\f2ac"}.fa-snapchat-square:before{content:"\f2ad"}.fa-snowboarding:before{content:"\f7ce"}.fa-snowflake:before{content:"\f2dc"}.fa-snowman:before{content:"\f7d0"}.fa-snowplow:before{content:"\f7d2"}.fa-socks:before{content:"\f696"}.fa-solar-panel:before{content:"\f5ba"}.fa-sort:before{content:"\f0dc"}.fa-sort-alpha-down:before{content:"\f15d"}.fa-sort-alpha-up:before{content:"\f15e"}.fa-sort-amount-down:before{content:"\f160"}.fa-sort-amount-up:before{content:"\f161"}.fa-sort-down:before{content:"\f0dd"}.fa-sort-numeric-down:before{content:"\f162"}.fa-sort-numeric-up:before{content:"\f163"}.fa-sort-up:before{content:"\f0de"}.fa-soundcloud:before{content:"\f1be"}.fa-sourcetree:before{content:"\f7d3"}.fa-spa:before{content:"\f5bb"}.fa-space-shuttle:before{content:"\f197"}.fa-speakap:before{content:"\f3f3"}.fa-spider:before{content:"\f717"}.fa-spinner:before{content:"\f110"}.fa-splotch:before{content:"\f5bc"}.fa-spotify:before{content:"\f1bc"}.fa-spray-can:before{content:"\f5bd"}.fa-square:before{content:"\f0c8"}.fa-square-full:before{content:"\f45c"}.fa-square-root-alt:before{content:"\f698"}.fa-squarespace:before{content:"\f5be"}.fa-stack-exchange:before{content:"\f18d"}.fa-stack-overflow:before{content:"\f16c"}.fa-stamp:before{content:"\f5bf"}.fa-star:before{content:"\f005"}.fa-star-and-crescent:before{content:"\f699"}.fa-star-half:before{content:"\f089"}.fa-star-half-alt:before{content:"\f5c0"}.fa-star-of-david:before{content:"\f69a"}.fa-star-of-life:before{content:"\f621"}.fa-staylinked:before{content:"\f3f5"}.fa-steam:before{content:"\f1b6"}.fa-steam-square:before{content:"\f1b7"}.fa-steam-symbol:before{content:"\f3f6"}.fa-step-backward:before{content:"\f048"}.fa-step-forward:before{content:"\f051"}.fa-stethoscope:before{content:"\f0f1"}.fa-sticker-mule:before{content:"\f3f7"}.fa-sticky-note:before{content:"\f249"}.fa-stop:before{content:"\f04d"}.fa-stop-circle:before{content:"\f28d"}.fa-stopwatch:before{content:"\f2f2"}.fa-store:before{content:"\f54e"}.fa-store-alt:before{content:"\f54f"}.fa-strava:before{content:"\f428"}.fa-stream:before{content:"\f550"}.fa-street-view:before{content:"\f21d"}.fa-strikethrough:before{content:"\f0cc"}.fa-stripe:before{content:"\f429"}.fa-stripe-s:before{content:"\f42a"}.fa-stroopwafel:before{content:"\f551"}.fa-studiovinari:before{content:"\f3f8"}.fa-stumbleupon:before{content:"\f1a4"}.fa-stumbleupon-circle:before{content:"\f1a3"}.fa-subscript:before{content:"\f12c"}.fa-subway:before{content:"\f239"}.fa-suitcase:before{content:"\f0f2"}.fa-suitcase-rolling:before{content:"\f5c1"}.fa-sun:before{content:"\f185"}.fa-superpowers:before{content:"\f2dd"}.fa-superscript:before{content:"\f12b"}.fa-supple:before{content:"\f3f9"}.fa-surprise:before{content:"\f5c2"}.fa-suse:before{content:"\f7d6"}.fa-swatchbook:before{content:"\f5c3"}.fa-swimmer:before{content:"\f5c4"}.fa-swimming-pool:before{content:"\f5c5"}.fa-synagogue:before{content:"\f69b"}.fa-sync:before{content:"\f021"}.fa-sync-alt:before{content:"\f2f1"}.fa-syringe:before{content:"\f48e"}.fa-table:before{content:"\f0ce"}.fa-table-tennis:before{content:"\f45d"}.fa-tablet:before{content:"\f10a"}.fa-tablet-alt:before{content:"\f3fa"}.fa-tablets:before{content:"\f490"}.fa-tachometer-alt:before{content:"\f3fd"}.fa-tag:before{content:"\f02b"}.fa-tags:before{content:"\f02c"}.fa-tape:before{content:"\f4db"}.fa-tasks:before{content:"\f0ae"}.fa-taxi:before{content:"\f1ba"}.fa-teamspeak:before{content:"\f4f9"}.fa-teeth:before{content:"\f62e"}.fa-teeth-open:before{content:"\f62f"}.fa-telegram:before{content:"\f2c6"}.fa-telegram-plane:before{content:"\f3fe"}.fa-temperature-high:before{content:"\f769"}.fa-temperature-low:before{content:"\f76b"}.fa-tencent-weibo:before{content:"\f1d5"}.fa-tenge:before{content:"\f7d7"}.fa-terminal:before{content:"\f120"}.fa-text-height:before{content:"\f034"}.fa-text-width:before{content:"\f035"}.fa-th:before{content:"\f00a"}.fa-th-large:before{content:"\f009"}.fa-th-list:before{content:"\f00b"}.fa-the-red-yeti:before{content:"\f69d"}.fa-theater-masks:before{content:"\f630"}.fa-themeco:before{content:"\f5c6"}.fa-themeisle:before{content:"\f2b2"}.fa-thermometer:before{content:"\f491"}.fa-thermometer-empty:before{content:"\f2cb"}.fa-thermometer-full:before{content:"\f2c7"}.fa-thermometer-half:before{content:"\f2c9"}.fa-thermometer-quarter:before{content:"\f2ca"}.fa-thermometer-three-quarters:before{content:"\f2c8"}.fa-think-peaks:before{content:"\f731"}.fa-thumbs-down:before{content:"\f165"}.fa-thumbs-up:before{content:"\f164"}.fa-thumbtack:before{content:"\f08d"}.fa-ticket-alt:before{content:"\f3ff"}.fa-times:before{content:"\f00d"}.fa-times-circle:before{content:"\f057"}.fa-tint:before{content:"\f043"}.fa-tint-slash:before{content:"\f5c7"}.fa-tired:before{content:"\f5c8"}.fa-toggle-off:before{content:"\f204"}.fa-toggle-on:before{content:"\f205"}.fa-toilet:before{content:"\f7d8"}.fa-toilet-paper:before{content:"\f71e"}.fa-toolbox:before{content:"\f552"}.fa-tools:before{content:"\f7d9"}.fa-tooth:before{content:"\f5c9"}.fa-torah:before{content:"\f6a0"}.fa-torii-gate:before{content:"\f6a1"}.fa-tractor:before{content:"\f722"}.fa-trade-federation:before{content:"\f513"}.fa-trademark:before{content:"\f25c"}.fa-traffic-light:before{content:"\f637"}.fa-train:before{content:"\f238"}.fa-tram:before{content:"\f7da"}.fa-transgender:before{content:"\f224"}.fa-transgender-alt:before{content:"\f225"}.fa-trash:before{content:"\f1f8"}.fa-trash-alt:before{content:"\f2ed"}.fa-tree:before{content:"\f1bb"}.fa-trello:before{content:"\f181"}.fa-tripadvisor:before{content:"\f262"}.fa-trophy:before{content:"\f091"}.fa-truck:before{content:"\f0d1"}.fa-truck-loading:before{content:"\f4de"}.fa-truck-monster:before{content:"\f63b"}.fa-truck-moving:before{content:"\f4df"}.fa-truck-pickup:before{content:"\f63c"}.fa-tshirt:before{content:"\f553"}.fa-tty:before{content:"\f1e4"}.fa-tumblr:before{content:"\f173"}.fa-tumblr-square:before{content:"\f174"}.fa-tv:before{content:"\f26c"}.fa-twitch:before{content:"\f1e8"}.fa-twitter:before{content:"\f099"}.fa-twitter-square:before{content:"\f081"}.fa-typo3:before{content:"\f42b"}.fa-uber:before{content:"\f402"}.fa-ubuntu:before{content:"\f7df"}.fa-uikit:before{content:"\f403"}.fa-umbrella:before{content:"\f0e9"}.fa-umbrella-beach:before{content:"\f5ca"}.fa-underline:before{content:"\f0cd"}.fa-undo:before{content:"\f0e2"}.fa-undo-alt:before{content:"\f2ea"}.fa-uniregistry:before{content:"\f404"}.fa-universal-access:before{content:"\f29a"}.fa-university:before{content:"\f19c"}.fa-unlink:before{content:"\f127"}.fa-unlock:before{content:"\f09c"}.fa-unlock-alt:before{content:"\f13e"}.fa-untappd:before{content:"\f405"}.fa-upload:before{content:"\f093"}.fa-ups:before{content:"\f7e0"}.fa-usb:before{content:"\f287"}.fa-user:before{content:"\f007"}.fa-user-alt:before{content:"\f406"}.fa-user-alt-slash:before{content:"\f4fa"}.fa-user-astronaut:before{content:"\f4fb"}.fa-user-check:before{content:"\f4fc"}.fa-user-circle:before{content:"\f2bd"}.fa-user-clock:before{content:"\f4fd"}.fa-user-cog:before{content:"\f4fe"}.fa-user-edit:before{content:"\f4ff"}.fa-user-friends:before{content:"\f500"}.fa-user-graduate:before{content:"\f501"}.fa-user-injured:before{content:"\f728"}.fa-user-lock:before{content:"\f502"}.fa-user-md:before{content:"\f0f0"}.fa-user-minus:before{content:"\f503"}.fa-user-ninja:before{content:"\f504"}.fa-user-plus:before{content:"\f234"}.fa-user-secret:before{content:"\f21b"}.fa-user-shield:before{content:"\f505"}.fa-user-slash:before{content:"\f506"}.fa-user-tag:before{content:"\f507"}.fa-user-tie:before{content:"\f508"}.fa-user-times:before{content:"\f235"}.fa-users:before{content:"\f0c0"}.fa-users-cog:before{content:"\f509"}.fa-usps:before{content:"\f7e1"}.fa-ussunnah:before{content:"\f407"}.fa-utensil-spoon:before{content:"\f2e5"}.fa-utensils:before{content:"\f2e7"}.fa-vaadin:before{content:"\f408"}.fa-vector-square:before{content:"\f5cb"}.fa-venus:before{content:"\f221"}.fa-venus-double:before{content:"\f226"}.fa-venus-mars:before{content:"\f228"}.fa-viacoin:before{content:"\f237"}.fa-viadeo:before{content:"\f2a9"}.fa-viadeo-square:before{content:"\f2aa"}.fa-vial:before{content:"\f492"}.fa-vials:before{content:"\f493"}.fa-viber:before{content:"\f409"}.fa-video:before{content:"\f03d"}.fa-video-slash:before{content:"\f4e2"}.fa-vihara:before{content:"\f6a7"}.fa-vimeo:before{content:"\f40a"}.fa-vimeo-square:before{content:"\f194"}.fa-vimeo-v:before{content:"\f27d"}.fa-vine:before{content:"\f1ca"}.fa-vk:before{content:"\f189"}.fa-vnv:before{content:"\f40b"}.fa-volleyball-ball:before{content:"\f45f"}.fa-volume-down:before{content:"\f027"}.fa-volume-mute:before{content:"\f6a9"}.fa-volume-off:before{content:"\f026"}.fa-volume-up:before{content:"\f028"}.fa-vote-yea:before{content:"\f772"}.fa-vr-cardboard:before{content:"\f729"}.fa-vuejs:before{content:"\f41f"}.fa-walking:before{content:"\f554"}.fa-wallet:before{content:"\f555"}.fa-warehouse:before{content:"\f494"}.fa-water:before{content:"\f773"}.fa-weebly:before{content:"\f5cc"}.fa-weibo:before{content:"\f18a"}.fa-weight:before{content:"\f496"}.fa-weight-hanging:before{content:"\f5cd"}.fa-weixin:before{content:"\f1d7"}.fa-whatsapp:before{content:"\f232"}.fa-whatsapp-square:before{content:"\f40c"}.fa-wheelchair:before{content:"\f193"}.fa-whmcs:before{content:"\f40d"}.fa-wifi:before{content:"\f1eb"}.fa-wikipedia-w:before{content:"\f266"}.fa-wind:before{content:"\f72e"}.fa-window-close:before{content:"\f410"}.fa-window-maximize:before{content:"\f2d0"}.fa-window-minimize:before{content:"\f2d1"}.fa-window-restore:before{content:"\f2d2"}.fa-windows:before{content:"\f17a"}.fa-wine-bottle:before{content:"\f72f"}.fa-wine-glass:before{content:"\f4e3"}.fa-wine-glass-alt:before{content:"\f5ce"}.fa-wix:before{content:"\f5cf"}.fa-wizards-of-the-coast:before{content:"\f730"}.fa-wolf-pack-battalion:before{content:"\f514"}.fa-won-sign:before{content:"\f159"}.fa-wordpress:before{content:"\f19a"}.fa-wordpress-simple:before{content:"\f411"}.fa-wpbeginner:before{content:"\f297"}.fa-wpexplorer:before{content:"\f2de"}.fa-wpforms:before{content:"\f298"}.fa-wpressr:before{content:"\f3e4"}.fa-wrench:before{content:"\f0ad"}.fa-x-ray:before{content:"\f497"}.fa-xbox:before{content:"\f412"}.fa-xing:before{content:"\f168"}.fa-xing-square:before{content:"\f169"}.fa-y-combinator:before{content:"\f23b"}.fa-yahoo:before{content:"\f19e"}.fa-yandex:before{content:"\f413"}.fa-yandex-international:before{content:"\f414"}.fa-yarn:before{content:"\f7e3"}.fa-yelp:before{content:"\f1e9"}.fa-yen-sign:before{content:"\f157"}.fa-yin-yang:before{content:"\f6ad"}.fa-yoast:before{content:"\f2b1"}.fa-youtube:before{content:"\f167"}.fa-youtube-square:before{content:"\f431"}.fa-zhihu:before{content:"\f63f"}.sr-only{border:0;clip:rect(0,0,0,0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.sr-only-focusable:active,.sr-only-focusable:focus{clip:auto;height:auto;margin:0;overflow:visible;position:static;width:auto}@font-face{font-family:"Font Awesome 5 Brands";font-style:normal;font-weight:normal;src:url(../webfonts/fa-brands-400.eot);src:url(../webfonts/fa-brands-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-brands-400.woff2) format("woff2"),url(../webfonts/fa-brands-400.woff) format("woff"),url(../webfonts/fa-brands-400.ttf) format("truetype"),url(../webfonts/fa-brands-400.svg#fontawesome) format("svg")}.fab{font-family:"Font Awesome 5 Brands"}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:400;src:url(../webfonts/fa-regular-400.eot);src:url(../webfonts/fa-regular-400.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-regular-400.woff2) format("woff2"),url(../webfonts/fa-regular-400.woff) format("woff"),url(../webfonts/fa-regular-400.ttf) format("truetype"),url(../webfonts/fa-regular-400.svg#fontawesome) format("svg")}.far{font-weight:400}@font-face{font-family:"Font Awesome 5 Free";font-style:normal;font-weight:900;src:url(../webfonts/fa-solid-900.eot);src:url(../webfonts/fa-solid-900.eot?#iefix) format("embedded-opentype"),url(../webfonts/fa-solid-900.woff2) format("woff2"),url(../webfonts/fa-solid-900.woff) format("woff"),url(../webfonts/fa-solid-900.ttf) format("truetype"),url(../webfonts/fa-solid-900.svg#fontawesome) format("svg")}.fa,.far,.fas{font-family:"Font Awesome 5 Free"}.fa,.fas{font-weight:900} \ No newline at end of file diff --git a/workshop/themes/learn/static/css/hugo-theme.css b/workshop/themes/learn/static/css/hugo-theme.css deleted file mode 100644 index 741cab1..0000000 --- a/workshop/themes/learn/static/css/hugo-theme.css +++ /dev/null @@ -1,254 +0,0 @@ -/* Insert here special css for hugo theme, on top of any other imported css */ - - -/* Table of contents */ - -.progress ul { - list-style: none; - margin: 0; - padding: 0 5px; -} - -#TableOfContents { - font-size: 13px !important; - max-height: 85vh; - overflow: auto; - padding: 15px !important; -} - - -#TableOfContents > ul > li > ul > li > ul li { - margin-right: 8px; -} - -#TableOfContents > ul > li > a { - font-weight: bold; padding: 0 18px; margin: 0 2px; -} - -#TableOfContents > ul > li > ul > li > a { - font-weight: bold; -} - -#TableOfContents > ul > li > ul > li > ul > li > ul > li > ul > li { - display: none; -} - -body { - font-size: 16px !important; - color: #323232 !important; -} - -#body a.highlight, #body a.highlight:hover, #body a.highlight:focus { - text-decoration: none; - outline: none; - outline: 0; -} -#body a.highlight { - line-height: 1.1; - display: inline-block; -} -#body a.highlight:after { - display: block; - content: ""; - height: 1px; - width: 0%; - background-color: #0082a7; /*#CE3B2F*/ - -webkit-transition: width 0.5s ease; - -moz-transition: width 0.5s ease; - -ms-transition: width 0.5s ease; - transition: width 0.5s ease; -} -#body a.highlight:hover:after, #body a.highlight:focus:after { - width: 100%; -} -.progress { - position:absolute; - background-color: rgba(246, 246, 246, 0.97); - width: auto; - border: thin solid #ECECEC; - display:none; - z-index:200; -} - -#toc-menu { - border-right: thin solid #DAD8D8 !important; - padding-right: 1rem !important; - margin-right: 0.5rem !important; -} - -#sidebar-toggle-span { - border-right: thin solid #DAD8D8 !important; - padding-right: 0.5rem !important; - margin-right: 1rem !important; -} - -.btn { - display: inline-block !important; - padding: 6px 12px !important; - margin-bottom: 0 !important; - font-size: 14px !important; - font-weight: normal !important; - line-height: 1.42857143 !important; - text-align: center !important; - white-space: nowrap !important; - vertical-align: middle !important; - -ms-touch-action: manipulation !important; - touch-action: manipulation !important; - cursor: pointer !important; - -webkit-user-select: none !important; - -moz-user-select: none !important; - -ms-user-select: none !important; - user-select: none !important; - background-image: none !important; - border: 1px solid transparent !important; - border-radius: 4px !important; - -webkit-transition: all 0.15s !important; - -moz-transition: all 0.15s !important; - transition: all 0.15s !important; -} -.btn:focus { - /*outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px;*/ - outline: none !important; -} -.btn:hover, -.btn:focus { - color: #2b2b2b !important; - text-decoration: none !important; -} - -.btn-default { - color: #333 !important; - background-color: #fff !important; - border-color: #ccc !important; -} -.btn-default:hover, -.btn-default:focus, -.btn-default:active { - color: #fff !important; - background-color: #9e9e9e !important; - border-color: #9e9e9e !important; -} -.btn-default:active { - background-image: none !important; -} - -/* anchors */ -.anchor { - color: #00bdf3; - font-size: 0.5em; - cursor:pointer; - visibility:hidden; - margin-left: 0.5em; - position: absolute; - margin-top:0.1em; -} - -h2:hover .anchor, h3:hover .anchor, h4:hover .anchor, h5:hover .anchor, h6:hover .anchor { - visibility:visible; -} - -/* Redfines headers style */ - -h2, h3, h4, h5, h6 { - font-weight: 400; - line-height: 1.1; -} - -h1 a, h2 a, h3 a, h4 a, h5 a, h6 a { - font-weight: inherit; -} - -h2 { - font-size: 2.5rem; - line-height: 110% !important; - margin: 2.5rem 0 1.5rem 0; -} - -h3 { - font-size: 2rem; - line-height: 110% !important; - margin: 2rem 0 1rem 0; -} - -h4 { - font-size: 1.5rem; - line-height: 110% !important; - margin: 1.5rem 0 0.75rem 0; -} - -h5 { - font-size: 1rem; - line-height: 110% !important; - margin: 1rem 0 0.2rem 0; -} - -h6 { - font-size: 0.5rem; - line-height: 110% !important; - margin: 0.5rem 0 0.2rem 0; -} - -p { - margin: 1rem 0; -} - -figcaption h4 { - font-weight: 300 !important; - opacity: .85; - font-size: 1em; - text-align: center; - margin-top: -1.5em; -} - -.select-style { - border: 0; - width: 150px; - border-radius: 0px; - overflow: hidden; - display: inline-flex; -} - -.select-style svg { - fill: #ccc; - width: 14px; - height: 14px; - pointer-events: none; - margin: auto; -} - -.select-style svg:hover { - fill: #e6e6e6; -} - -.select-style select { - padding: 0; - width: 130%; - border: none; - box-shadow: none; - background: transparent; - background-image: none; - -webkit-appearance: none; - margin: auto; - margin-left: 0px; - margin-right: -20px; -} - -.select-style select:focus { - outline: none; -} - -.select-style :hover { - cursor: pointer; -} - -@media only all and (max-width: 47.938em) { - #breadcrumbs .links, #top-github-link-text { - display: none; - } -} - -.is-sticky #top-bar { - box-shadow: -1px 2px 5px 1px rgba(0, 0, 0, 0.1); -} \ No newline at end of file diff --git a/workshop/themes/learn/static/css/hybrid.css b/workshop/themes/learn/static/css/hybrid.css deleted file mode 100644 index 29735a1..0000000 --- a/workshop/themes/learn/static/css/hybrid.css +++ /dev/null @@ -1,102 +0,0 @@ -/* - -vim-hybrid theme by w0ng (https://github.com/w0ng/vim-hybrid) - -*/ - -/*background color*/ -.hljs { - display: block; - overflow-x: auto; - padding: 0.5em; - background: #1d1f21; -} - -/*selection color*/ -.hljs::selection, -.hljs span::selection { - background: #373b41; -} - -.hljs::-moz-selection, -.hljs span::-moz-selection { - background: #373b41; -} - -/*foreground color*/ -.hljs { - color: #c5c8c6; -} - -/*color: fg_yellow*/ -.hljs-title, -.hljs-name { - color: #f0c674; -} - -/*color: fg_comment*/ -.hljs-comment, -.hljs-meta, -.hljs-meta .hljs-keyword { - color: #707880; -} - -/*color: fg_red*/ -.hljs-number, -.hljs-symbol, -.hljs-literal, -.hljs-deletion, -.hljs-link { - color: #cc6666 -} - -/*color: fg_green*/ -.hljs-string, -.hljs-doctag, -.hljs-addition, -.hljs-regexp, -.hljs-selector-attr, -.hljs-selector-pseudo { - color: #b5bd68; -} - -/*color: fg_purple*/ -.hljs-attribute, -.hljs-code, -.hljs-selector-id { - color: #b294bb; -} - -/*color: fg_blue*/ -.hljs-keyword, -.hljs-selector-tag, -.hljs-bullet, -.hljs-tag { - color: #81a2be; -} - -/*color: fg_aqua*/ -.hljs-subst, -.hljs-variable, -.hljs-template-tag, -.hljs-template-variable { - color: #8abeb7; -} - -/*color: fg_orange*/ -.hljs-type, -.hljs-built_in, -.hljs-builtin-name, -.hljs-quote, -.hljs-section, -.hljs-selector-class { - color: #de935f; -} - -.hljs-emphasis { - font-style: italic; -} - -.hljs-strong { - font-weight: bold; -} diff --git a/workshop/themes/learn/static/css/nucleus.css b/workshop/themes/learn/static/css/nucleus.css deleted file mode 100644 index 1897fc5..0000000 --- a/workshop/themes/learn/static/css/nucleus.css +++ /dev/null @@ -1,615 +0,0 @@ -*, *::before, *::after { - -webkit-box-sizing: border-box; - -moz-box-sizing: border-box; - box-sizing: border-box; } - -@-webkit-viewport { - width: device-width; } -@-moz-viewport { - width: device-width; } -@-ms-viewport { - width: device-width; } -@-o-viewport { - width: device-width; } -@viewport { - width: device-width; } -html { - font-size: 100%; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; } - -body { - margin: 0; } - -article, -aside, -details, -figcaption, -figure, -footer, -header, -hgroup, -main, -nav, -section, -summary { - display: block; } - -audio, -canvas, -progress, -video { - display: inline-block; - vertical-align: baseline; } - -audio:not([controls]) { - display: none; - height: 0; } - -[hidden], -template { - display: none; } - -a { - background: transparent; - text-decoration: none; } - -a:active, -a:hover { - outline: 0; } - -abbr[title] { - border-bottom: 1px dotted; } - -b, -strong { - font-weight: bold; } - -dfn { - font-style: italic; } - -mark { - background: #FFFF27; - color: #333; } - -sub, -sup { - font-size: 0.8rem; - line-height: 0; - position: relative; - vertical-align: baseline; } - -sup { - top: -0.5em; } - -sub { - bottom: -0.25em; } - -img { - border: 0; - max-width: 100%; } - -svg:not(:root) { - overflow: hidden; } - -figure { - margin: 1em 40px; } - -hr { - height: 0; } - -pre { - overflow: auto; } - -button, -input, -optgroup, -select, -textarea { - color: inherit; - font: inherit; - margin: 0; } - -button { - overflow: visible; } - -button, -select { - text-transform: none; } - -button, -html input[type="button"], -input[type="reset"], -input[type="submit"] { - -webkit-appearance: button; - cursor: pointer; } - -button[disabled], -html input[disabled] { - cursor: default; } - -button::-moz-focus-inner, -input::-moz-focus-inner { - border: 0; - padding: 0; } - -input { - line-height: normal; } - -input[type="checkbox"], -input[type="radio"] { - padding: 0; } - -input[type="number"]::-webkit-inner-spin-button, -input[type="number"]::-webkit-outer-spin-button { - height: auto; } - -input[type="search"] { - -webkit-appearance: textfield; } - -input[type="search"]::-webkit-search-cancel-button, -input[type="search"]::-webkit-search-decoration { - -webkit-appearance: none; } - -legend { - border: 0; - padding: 0; } - -textarea { - overflow: auto; } - -optgroup { - font-weight: bold; } - -table { - border-collapse: collapse; - border-spacing: 0; - table-layout: fixed; - width: 100%; } - -tr, td, th { - vertical-align: middle; } - -th, td { - padding: 0.425rem 0; } - -th { - text-align: left; } - -.container { - width: 75em; - margin: 0 auto; - padding: 0; } - @media only all and (min-width: 60em) and (max-width: 74.938em) { - .container { - width: 60em; } } - @media only all and (min-width: 48em) and (max-width: 59.938em) { - .container { - width: 48em; } } - @media only all and (min-width: 30.063em) and (max-width: 47.938em) { - .container { - width: 30em; } } - @media only all and (max-width: 30em) { - .container { - width: 100%; } } - -.grid { - display: -webkit-box; - display: -moz-box; - display: box; - display: -webkit-flex; - display: -moz-flex; - display: -ms-flexbox; - display: flex; - -webkit-flex-flow: row; - -moz-flex-flow: row; - flex-flow: row; - list-style: none; - margin: 0; - padding: 0; } - @media only all and (max-width: 47.938em) { - .grid { - -webkit-flex-flow: row wrap; - -moz-flex-flow: row wrap; - flex-flow: row wrap; } } - -.block { - -webkit-box-flex: 1; - -moz-box-flex: 1; - box-flex: 1; - -webkit-flex: 1; - -moz-flex: 1; - -ms-flex: 1; - flex: 1; - min-width: 0; - min-height: 0; } - @media only all and (max-width: 47.938em) { - .block { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 100%; - -moz-flex: 0 100%; - -ms-flex: 0 100%; - flex: 0 100%; } } - -.content { - margin: 0.625rem; - padding: 0.938rem; } - -@media only all and (max-width: 47.938em) { - body [class*="size-"] { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 100%; - -moz-flex: 0 100%; - -ms-flex: 0 100%; - flex: 0 100%; } } - -.size-1-2 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 50%; - -moz-flex: 0 50%; - -ms-flex: 0 50%; - flex: 0 50%; } - -.size-1-3 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 33.33333%; - -moz-flex: 0 33.33333%; - -ms-flex: 0 33.33333%; - flex: 0 33.33333%; } - -.size-1-4 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 25%; - -moz-flex: 0 25%; - -ms-flex: 0 25%; - flex: 0 25%; } - -.size-1-5 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 20%; - -moz-flex: 0 20%; - -ms-flex: 0 20%; - flex: 0 20%; } - -.size-1-6 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 16.66667%; - -moz-flex: 0 16.66667%; - -ms-flex: 0 16.66667%; - flex: 0 16.66667%; } - -.size-1-7 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 14.28571%; - -moz-flex: 0 14.28571%; - -ms-flex: 0 14.28571%; - flex: 0 14.28571%; } - -.size-1-8 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 12.5%; - -moz-flex: 0 12.5%; - -ms-flex: 0 12.5%; - flex: 0 12.5%; } - -.size-1-9 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 11.11111%; - -moz-flex: 0 11.11111%; - -ms-flex: 0 11.11111%; - flex: 0 11.11111%; } - -.size-1-10 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 10%; - -moz-flex: 0 10%; - -ms-flex: 0 10%; - flex: 0 10%; } - -.size-1-11 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 9.09091%; - -moz-flex: 0 9.09091%; - -ms-flex: 0 9.09091%; - flex: 0 9.09091%; } - -.size-1-12 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 8.33333%; - -moz-flex: 0 8.33333%; - -ms-flex: 0 8.33333%; - flex: 0 8.33333%; } - -@media only all and (min-width: 48em) and (max-width: 59.938em) { - .size-tablet-1-2 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 50%; - -moz-flex: 0 50%; - -ms-flex: 0 50%; - flex: 0 50%; } - - .size-tablet-1-3 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 33.33333%; - -moz-flex: 0 33.33333%; - -ms-flex: 0 33.33333%; - flex: 0 33.33333%; } - - .size-tablet-1-4 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 25%; - -moz-flex: 0 25%; - -ms-flex: 0 25%; - flex: 0 25%; } - - .size-tablet-1-5 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 20%; - -moz-flex: 0 20%; - -ms-flex: 0 20%; - flex: 0 20%; } - - .size-tablet-1-6 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 16.66667%; - -moz-flex: 0 16.66667%; - -ms-flex: 0 16.66667%; - flex: 0 16.66667%; } - - .size-tablet-1-7 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 14.28571%; - -moz-flex: 0 14.28571%; - -ms-flex: 0 14.28571%; - flex: 0 14.28571%; } - - .size-tablet-1-8 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 12.5%; - -moz-flex: 0 12.5%; - -ms-flex: 0 12.5%; - flex: 0 12.5%; } - - .size-tablet-1-9 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 11.11111%; - -moz-flex: 0 11.11111%; - -ms-flex: 0 11.11111%; - flex: 0 11.11111%; } - - .size-tablet-1-10 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 10%; - -moz-flex: 0 10%; - -ms-flex: 0 10%; - flex: 0 10%; } - - .size-tablet-1-11 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 9.09091%; - -moz-flex: 0 9.09091%; - -ms-flex: 0 9.09091%; - flex: 0 9.09091%; } - - .size-tablet-1-12 { - -webkit-box-flex: 0; - -moz-box-flex: 0; - box-flex: 0; - -webkit-flex: 0 8.33333%; - -moz-flex: 0 8.33333%; - -ms-flex: 0 8.33333%; - flex: 0 8.33333%; } } -@media only all and (max-width: 47.938em) { - @supports not (flex-wrap: wrap) { - .grid { - display: block; - -webkit-box-lines: inherit; - -moz-box-lines: inherit; - box-lines: inherit; - -webkit-flex-wrap: inherit; - -moz-flex-wrap: inherit; - -ms-flex-wrap: inherit; - flex-wrap: inherit; } - - .block { - display: block; - -webkit-box-flex: inherit; - -moz-box-flex: inherit; - box-flex: inherit; - -webkit-flex: inherit; - -moz-flex: inherit; - -ms-flex: inherit; - flex: inherit; } } } -.first-block { - -webkit-box-ordinal-group: 0; - -webkit-order: -1; - -ms-flex-order: -1; - order: -1; } - -.last-block { - -webkit-box-ordinal-group: 2; - -webkit-order: 1; - -ms-flex-order: 1; - order: 1; } - -.fixed-blocks { - -webkit-flex-flow: row wrap; - -moz-flex-flow: row wrap; - flex-flow: row wrap; } - .fixed-blocks .block { - -webkit-box-flex: inherit; - -moz-box-flex: inherit; - box-flex: inherit; - -webkit-flex: inherit; - -moz-flex: inherit; - -ms-flex: inherit; - flex: inherit; - width: 25%; } - @media only all and (min-width: 60em) and (max-width: 74.938em) { - .fixed-blocks .block { - width: 33.33333%; } } - @media only all and (min-width: 48em) and (max-width: 59.938em) { - .fixed-blocks .block { - width: 50%; } } - @media only all and (max-width: 47.938em) { - .fixed-blocks .block { - width: 100%; } } - -body { - font-size: 1.05rem; - line-height: 1.7; } - -h1, h2, h3, h4, h5, h6 { - margin: 0.85rem 0 1.7rem 0; - text-rendering: optimizeLegibility; } - -h1 { - font-size: 3.25rem; } - -h2 { - font-size: 2.55rem; } - -h3 { - font-size: 2.15rem; } - -h4 { - font-size: 1.8rem; } - -h5 { - font-size: 1.4rem; } - -h6 { - font-size: 0.9rem; } - -p { - margin: 1.7rem 0; } - -ul, ol { - margin-top: 1.7rem; - margin-bottom: 1.7rem; } - ul ul, ul ol, ol ul, ol ol { - margin-top: 0; - margin-bottom: 0; } - -blockquote { - margin: 1.7rem 0; - padding-left: 0.85rem; } - -cite { - display: block; - font-size: 0.925rem; } - cite:before { - content: "\2014 \0020"; } - -pre { - margin: 1.7rem 0; - padding: 0.938rem; } - -code { - vertical-align: bottom; } - -small { - font-size: 0.925rem; } - -hr { - border-left: none; - border-right: none; - border-top: none; - margin: 1.7rem 0; } - -fieldset { - border: 0; - padding: 0.938rem; - margin: 0 0 1.7rem 0; } - -input, -label, -select { - display: block; } - -label { - margin-bottom: 0.425rem; } - label.required:after { - content: "*"; } - label abbr { - display: none; } - -textarea, input[type="email"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="url"], input[type="color"], input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="month"], input[type="time"], input[type="week"], select[multiple=multiple] { - -webkit-transition: border-color; - -moz-transition: border-color; - transition: border-color; - border-radius: 0.1875rem; - margin-bottom: 0.85rem; - padding: 0.425rem 0.425rem; - width: 100%; } - textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus { - outline: none; } - -textarea { - resize: vertical; } - -input[type="checkbox"], input[type="radio"] { - display: inline; - margin-right: 0.425rem; } - -input[type="file"] { - width: 100%; } - -select { - width: auto; - max-width: 100%; - margin-bottom: 1.7rem; } - -button, -input[type="submit"] { - cursor: pointer; - user-select: none; - vertical-align: middle; - white-space: nowrap; - border: inherit; } diff --git a/workshop/themes/learn/static/css/perfect-scrollbar.min.css b/workshop/themes/learn/static/css/perfect-scrollbar.min.css deleted file mode 100644 index ebd2cb4..0000000 --- a/workshop/themes/learn/static/css/perfect-scrollbar.min.css +++ /dev/null @@ -1,2 +0,0 @@ -/* perfect-scrollbar v0.6.13 */ -.ps-container{-ms-touch-action:auto;touch-action:auto;overflow:hidden !important;-ms-overflow-style:none}@supports (-ms-overflow-style: none){.ps-container{overflow:auto !important}}@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none){.ps-container{overflow:auto !important}}.ps-container.ps-active-x>.ps-scrollbar-x-rail,.ps-container.ps-active-y>.ps-scrollbar-y-rail{display:block;background-color:transparent}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:.9}.ps-container.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999;height:11px}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:.9}.ps-container.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999;width:11px}.ps-container>.ps-scrollbar-x-rail{display:none;position:absolute;opacity:0;-webkit-transition:background-color .2s linear, opacity .2s linear;-o-transition:background-color .2s linear, opacity .2s linear;-moz-transition:background-color .2s linear, opacity .2s linear;transition:background-color .2s linear, opacity .2s linear;bottom:0px;height:15px}.ps-container>.ps-scrollbar-x-rail>.ps-scrollbar-x{position:absolute;background-color:#aaa;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;-o-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;-moz-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;bottom:2px;height:6px}.ps-container>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x,.ps-container>.ps-scrollbar-x-rail:active>.ps-scrollbar-x{height:11px}.ps-container>.ps-scrollbar-y-rail{display:none;position:absolute;opacity:0;-webkit-transition:background-color .2s linear, opacity .2s linear;-o-transition:background-color .2s linear, opacity .2s linear;-moz-transition:background-color .2s linear, opacity .2s linear;transition:background-color .2s linear, opacity .2s linear;right:0;width:15px}.ps-container>.ps-scrollbar-y-rail>.ps-scrollbar-y{position:absolute;background-color:#aaa;-webkit-border-radius:6px;-moz-border-radius:6px;border-radius:6px;-webkit-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, -webkit-border-radius .2s ease-in-out;-o-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;-moz-transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out;transition:background-color .2s linear, height .2s linear, width .2s ease-in-out, border-radius .2s ease-in-out, -webkit-border-radius .2s ease-in-out, -moz-border-radius .2s ease-in-out;right:2px;width:6px}.ps-container>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y,.ps-container>.ps-scrollbar-y-rail:active>.ps-scrollbar-y{width:11px}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail{background-color:#eee;opacity:.9}.ps-container:hover.ps-in-scrolling.ps-x>.ps-scrollbar-x-rail>.ps-scrollbar-x{background-color:#999;height:11px}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail{background-color:#eee;opacity:.9}.ps-container:hover.ps-in-scrolling.ps-y>.ps-scrollbar-y-rail>.ps-scrollbar-y{background-color:#999;width:11px}.ps-container:hover>.ps-scrollbar-x-rail,.ps-container:hover>.ps-scrollbar-y-rail{opacity:.6}.ps-container:hover>.ps-scrollbar-x-rail:hover{background-color:#eee;opacity:.9}.ps-container:hover>.ps-scrollbar-x-rail:hover>.ps-scrollbar-x{background-color:#999}.ps-container:hover>.ps-scrollbar-y-rail:hover{background-color:#eee;opacity:.9}.ps-container:hover>.ps-scrollbar-y-rail:hover>.ps-scrollbar-y{background-color:#999} diff --git a/workshop/themes/learn/static/css/tags.css b/workshop/themes/learn/static/css/tags.css deleted file mode 100644 index 495d2f9..0000000 --- a/workshop/themes/learn/static/css/tags.css +++ /dev/null @@ -1,49 +0,0 @@ -/* Tags */ - -#head-tags{ - margin-left:1em; - margin-top:1em; -} - -#body .tags a.tag-link { - display: inline-block; - line-height: 2em; - font-size: 0.8em; - position: relative; - margin: 0 16px 8px 0; - padding: 0 10px 0 12px; - background: #8451a1; - - -webkit-border-bottom-right-radius: 3px; - border-bottom-right-radius: 3px; - -webkit-border-top-right-radius: 3px; - border-top-right-radius: 3px; - - -webkit-box-shadow: 0 1px 2px rgba(0,0,0,0.2); - box-shadow: 0 1px 2px rgba(0,0,0,0.2); - color: #fff; -} - -#body .tags a.tag-link:before { - content: ""; - position: absolute; - top:0; - left: -1em; - width: 0; - height: 0; - border-color: transparent #8451a1 transparent transparent; - border-style: solid; - border-width: 1em 1em 1em 0; -} - -#body .tags a.tag-link:after { - content: ""; - position: absolute; - top: 10px; - left: 1px; - width: 5px; - height: 5px; - -webkit-border-radius: 50%; - border-radius: 100%; - background: #fff; -} diff --git a/workshop/themes/learn/static/css/theme-aws.css b/workshop/themes/learn/static/css/theme-aws.css deleted file mode 100644 index 5f2eff7..0000000 --- a/workshop/themes/learn/static/css/theme-aws.css +++ /dev/null @@ -1,290 +0,0 @@ - -:root{ - - --MAIN-TEXT-color:#232F3E; /* Color of text by default */ - --MAIN-TITLES-TEXT-color: #161E2D; /* Color of titles h2-h3-h4-h5 */ - --MAIN-LINK-color:#95b0ff; /* Color of links */ - --MAIN-LINK-HOVER-color:#527FFF; /* Color of hovered links */ - --MAIN-ANCHOR-color: #95b0ff; /* color of anchors on titles */ - - --MENU-HEADER-BG-color:#161E2D; /* Background color of menu header */ - --MENU-HEADER-BORDER-color:#161E2D; /*Color of menu header border */ - - --MENU-SEARCH-BG-color:#202c3c; /* Search field background color (by default borders + icons) */ - --MENU-SEARCH-BOX-color: #4d6584; /* Override search field border color */ - --MENU-SEARCH-BOX-ICONS-color: #4d6584; /* Override search field icons color */ - - --MENU-SECTIONS-ACTIVE-BG-color:#232F3E; /* Background color of the active section and its childs */ - --MENU-SECTIONS-BG-color:#161E2D; /* Background color of other sections */ - --MENU-SECTIONS-TEXT-color: #FF9900; /*Color of pre text */ - --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */ - --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6; /* Color of links in menu, when hovered */ - --MENU-SECTION-ACTIVE-CATEGORY-color: #232F3E; /* Color of active category text */ - --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #FF9900; /* Color of background for the active category (only) */ - --MENU-SECTION-ACTIVE-CATEGORY-TEXT-color: #fff; /* Color of pre text when selected */ - - --MENU-VISITED-color: #527FFF; /* Color of 'page visited' icons in menu */ - --MENU-SECTION-HR-color: #20272b; /* Color of
    separator in menu */ - -} - -@font-face { - font-family: 'Amazon Ember'; - src: url("../webfonts/AmazonEmber_W_Lt.eot"); - src: url("../webfonts/AmazonEmber_W_Lt.eot?#iefix") format("embedded-opentype"), url("../webfonts/AmazonEmber_W_Lt.woff2") format("woff2"), url("../webfonts/AmazonEmber_W_Lt.woff") format("woff"); - font-style: normal; - font-weight: 200; -} - -html.js.supports.csstransforms3d body section#body div.padding.highlightable div#body-inner > table, -html.js.supports.csstransforms3d body section#body div.padding.highlightable div#body-inner > table tbody, -html.js.supports.csstransforms3d body section#body div.padding.highlightable div#body-inner > table tbody tr, -html.js.supports.csstransforms3d body section#body div.padding.highlightable div#body-inner > table tbody tr td { - border: none; - border-collapse: collapse; -} - -html.js.supports.csstransforms3d body section#body div.padding.highlightable div#body-inner > table tbody tr td a img { - padding: 1px; - margin: 1px; -} - -html.js.supports.csstransforms3d body section#body div.padding.highlightable div#body-inner > table thead tr th { - visibility: visible; -} - -body { - font-family: "Amazon Ember", "Work Sans", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif; - color: var(--MAIN-TEXT-color) !important; -} - -#chapter h3 { - font-family: "Amazon Ember","Work Sans", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif; -} - -textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus { - border-color: none; - box-shadow: none; -} - -h2, h3, h4, h5, h6 { - font-family: "Amazon Ember", "Work Sans", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif; - color: var(--MAIN-TITLES-TEXT-color) !important; -} - -h1 { - font-family: "Amazon Ember", "Novacento Sans Wide", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif; -} - -a { - color: var(--MAIN-LINK-color); -} - -.anchor { - color: var(--MAIN-ANCHOR-color); -} - -a:hover { - color: var(--MAIN-LINK-HOVER-color); -} - -#sidebar ul li.visited > a .read-icon { - color: var(--MENU-VISITED-color); -} - -#sidebar #footer { - padding-top: 20px !important; -} - -#sidebar #footer h2.github-title { - font-size: 20px; - color: #fd9827 !important; - margin: 10px 0px 5px; - padding: 0px; - font-weight: normal !important; - margin-top: 10px; - padding-top: 30px; - border-top: 1px dotted #384657; -} - -#sidebar #footer h3.github-title { - font-size: 14px; - margin: 10px 0px 5px; - padding: 0px; - text-transform: uppercase; - letter-spacing: .15px; -} - -#sidebar #footer h5.copyright, #sidebar #footer p.build-number { - color: var(--MENU-SECTIONS-LINK-color) !important; - font-size: 10px; - letter-spacing: .15px; - line-height: 150% !important; -} - -#body a.highlight:after { - display: block; - content: ""; - height: 1px; - width: 0%; - -webkit-transition: width 0.5s ease; - -moz-transition: width 0.5s ease; - -ms-transition: width 0.5s ease; - transition: width 0.5s ease; - background-color: var(--MAIN-LINK-HOVER-color); -} -#sidebar { - background-color: var(--MENU-SECTIONS-BG-color); -} -#sidebar #header-wrapper { - background: var(--MENU-HEADER-BG-color); - color: var(--MENU-SEARCH-BOX-color); - border-color: var(--MENU-HEADER-BORDER-color); -} -#sidebar .searchbox { - border-color: var(--MENU-SEARCH-BOX-color); - background: var(--MENU-SEARCH-BG-color); -} -#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active { - background: var(--MENU-SECTIONS-ACTIVE-BG-color); -} -#sidebar .searchbox * { - color: var(--MENU-SEARCH-BOX-ICONS-color); -} - -#sidebar a { - color: var(--MENU-SECTIONS-LINK-color); -} - -#sidebar a b { - color: var(--MENU-SECTIONS-TEXT-color); -} - -#sidebar a:hover { - color: var(--MENU-SECTIONS-LINK-HOVER-color); -} - -#sidebar ul li.active > a { - background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color); - color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important; -} - -#sidebar ul.topics > li > a b { - color: var(--MENU-SECTION-ACTIVE-CATEGORY-TEXT-color) !important; - opacity: 1; -} - -#sidebar hr { - border-color: var(--MENU-SECTION-HR-color); -} - -#sidebar #shortcuts h3 { - font-family: "Amazon Eber", "Novacento Sans Wide", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif; - color: white !important; - margin-top:1rem; - padding-left: 1rem; -} - -#navigation a.nav-prev, #navigation a.nav-next { - color: #f19e39 !important; -} - -#navigation a.nav-prev:hover, #navigation a.nav-next:hover { - color: #e07d04 !important; -} - -div.notices p:first-child:before { - position: absolute; - top: 2px; - color: #fff; - font-family: 'Font Awesome\ 5 Free'; - content: #F06A; - font-weight: 900; /* Fix version 5.0.9 */ - left: 10px; -} - -.ui-state-default, .ui-widget-content .ui-state-default, .ui-widget-header .ui-state-default, .ui-button, html .ui-button.ui-state-disabled:hover, html .ui-button.ui-state-disabled:active { - border: 1px solid #dddddd; - font-weight: normal; - color: #454545; -} - -.ui-state-active, .ui-widget-content .ui-state-active, .ui-widget-header .ui-state-active, a.ui-button:active, .ui-button:active, .ui-button.ui-state-active:hover { - border: 1px solid var(--MENU-HEADER-BG-color); - background: var(--MENU-HEADER-BG-color); - font-weight: normal; - color: #fff; -} - -.ui-widget.ui-widget-content { - border: 1px solid #eeeeee; -} - -.ui-widget-header { - border: 1px solid #eeeeee; -} - -.hljs { - background-color: none; -} - -pre { - background-color: var(--MENU-SECTIONS-BG-color) !important; -} - -div.notices.info p { - border-top: 30px solid #fd9827; - background: #FFF2DB; -} - -.btn { - display: inline-block !important; - padding: 6px 12px !important; - margin-bottom: 0 !important; - font-size: 14px !important; - font-weight: normal !important; - line-height: 1.42857143 !important; - text-align: center !important; - white-space: nowrap !important; - vertical-align: middle !important; - -ms-touch-action: manipulation !important; - touch-action: manipulation !important; - cursor: pointer !important; - -webkit-user-select: none !important; - -moz-user-select: none !important; - -ms-user-select: none !important; - user-select: none !important; - background-image: none !important; - border: 1px solid transparent !important; - border-radius: 4px !important; - -webkit-transition: all 0.15s !important; - -moz-transition: all 0.15s !important; - transition: all 0.15s !important; - } - .btn:focus { - /*outline: thin dotted; - outline: 5px auto -webkit-focus-ring-color; - outline-offset: -2px;*/ - outline: none !important; - } - .btn:hover, - .btn:focus { - color: #2b2b2b !important; - text-decoration: none !important; - } - - .btn-default { - color: #fff !important; - background-color: #527FFF !important; - border-color: #527FFF !important; - } - .btn-default:hover, - .btn-default:focus, - .btn-default:active { - color: #fff !important; - background-color: #95b0ff !important; - border-color: #95b0ff !important; - } - .btn-default:active { - background-image: none !important; - } \ No newline at end of file diff --git a/workshop/themes/learn/static/css/theme-blue.css b/workshop/themes/learn/static/css/theme-blue.css deleted file mode 100644 index 9771ae5..0000000 --- a/workshop/themes/learn/static/css/theme-blue.css +++ /dev/null @@ -1,111 +0,0 @@ - -:root{ - - --MAIN-TEXT-color:#323232; /* Color of text by default */ - --MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */ - --MAIN-LINK-color:#1C90F3; /* Color of links */ - --MAIN-LINK-HOVER-color:#167ad0; /* Color of hovered links */ - --MAIN-ANCHOR-color: #1C90F3; /* color of anchors on titles */ - - --MENU-HEADER-BG-color:#1C90F3; /* Background color of menu header */ - --MENU-HEADER-BORDER-color:#33a1ff; /*Color of menu header border */ - - --MENU-SEARCH-BG-color:#167ad0; /* Search field background color (by default borders + icons) */ - --MENU-SEARCH-BOX-color: #33a1ff; /* Override search field border color */ - --MENU-SEARCH-BOX-ICONS-color: #a1d2fd; /* Override search field icons color */ - - --MENU-SECTIONS-ACTIVE-BG-color:#20272b; /* Background color of the active section and its childs */ - --MENU-SECTIONS-BG-color:#252c31; /* Background color of other sections */ - --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */ - --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6; /* Color of links in menu, when hovered */ - --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */ - --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */ - - --MENU-VISITED-color: #33a1ff; /* Color of 'page visited' icons in menu */ - --MENU-SECTION-HR-color: #20272b; /* Color of
    separator in menu */ - -} - -body { - color: var(--MAIN-TEXT-color) !important; -} - -textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus { - border-color: none; - box-shadow: none; -} - -h2, h3, h4, h5 { - color: var(--MAIN-TITLES-TEXT-color) !important; -} - -a { - color: var(--MAIN-LINK-color); -} - -.anchor { - color: var(--MAIN-ANCHOR-color); -} - -a:hover { - color: var(--MAIN-LINK-HOVER-color); -} - -#sidebar ul li.visited > a .read-icon { - color: var(--MENU-VISITED-color); -} - -#body a.highlight:after { - display: block; - content: ""; - height: 1px; - width: 0%; - -webkit-transition: width 0.5s ease; - -moz-transition: width 0.5s ease; - -ms-transition: width 0.5s ease; - transition: width 0.5s ease; - background-color: var(--MAIN-LINK-HOVER-color); -} -#sidebar { - background-color: var(--MENU-SECTIONS-BG-color); -} -#sidebar #header-wrapper { - background: var(--MENU-HEADER-BG-color); - color: var(--MENU-SEARCH-BOX-color); - border-color: var(--MENU-HEADER-BORDER-color); -} -#sidebar .searchbox { - border-color: var(--MENU-SEARCH-BOX-color); - background: var(--MENU-SEARCH-BG-color); -} -#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active { - background: var(--MENU-SECTIONS-ACTIVE-BG-color); -} -#sidebar .searchbox * { - color: var(--MENU-SEARCH-BOX-ICONS-color); -} - -#sidebar a { - color: var(--MENU-SECTIONS-LINK-color); -} - -#sidebar a:hover { - color: var(--MENU-SECTIONS-LINK-HOVER-color); -} - -#sidebar ul li.active > a { - background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color); - color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important; -} - -#sidebar hr { - border-color: var(--MENU-SECTION-HR-color); -} - -#body .tags a.tag-link { - background-color: var(--MENU-HEADER-BG-color); -} - -#body .tags a.tag-link:before { - border-right-color: var(--MENU-HEADER-BG-color); -} \ No newline at end of file diff --git a/workshop/themes/learn/static/css/theme-green.css b/workshop/themes/learn/static/css/theme-green.css deleted file mode 100644 index 3b0b1f7..0000000 --- a/workshop/themes/learn/static/css/theme-green.css +++ /dev/null @@ -1,111 +0,0 @@ - -:root{ - - --MAIN-TEXT-color:#323232; /* Color of text by default */ - --MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */ - --MAIN-LINK-color:#599a3e; /* Color of links */ - --MAIN-LINK-HOVER-color:#3f6d2c; /* Color of hovered links */ - --MAIN-ANCHOR-color: #599a3e; /* color of anchors on titles */ - - --MENU-HEADER-BG-color:#74b559; /* Background color of menu header */ - --MENU-HEADER-BORDER-color:#9cd484; /*Color of menu header border */ - - --MENU-SEARCH-BG-color:#599a3e; /* Search field background color (by default borders + icons) */ - --MENU-SEARCH-BOX-color: #84c767; /* Override search field border color */ - --MENU-SEARCH-BOX-ICONS-color: #c7f7c4; /* Override search field icons color */ - - --MENU-SECTIONS-ACTIVE-BG-color:#1b211c; /* Background color of the active section and its childs */ - --MENU-SECTIONS-BG-color:#222723; /* Background color of other sections */ - --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */ - --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6; /* Color of links in menu, when hovered */ - --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */ - --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */ - - --MENU-VISITED-color: #599a3e; /* Color of 'page visited' icons in menu */ - --MENU-SECTION-HR-color: #18211c; /* Color of
    separator in menu */ - -} - -body { - color: var(--MAIN-TEXT-color) !important; -} - -textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus { - border-color: none; - box-shadow: none; -} - -h2, h3, h4, h5 { - color: var(--MAIN-TITLES-TEXT-color) !important; -} - -a { - color: var(--MAIN-LINK-color); -} - -.anchor { - color: var(--MAIN-ANCHOR-color); -} - -a:hover { - color: var(--MAIN-LINK-HOVER-color); -} - -#sidebar ul li.visited > a .read-icon { - color: var(--MENU-VISITED-color); -} - -#body a.highlight:after { - display: block; - content: ""; - height: 1px; - width: 0%; - -webkit-transition: width 0.5s ease; - -moz-transition: width 0.5s ease; - -ms-transition: width 0.5s ease; - transition: width 0.5s ease; - background-color: var(--MAIN-LINK-HOVER-color); -} -#sidebar { - background-color: var(--MENU-SECTIONS-BG-color); -} -#sidebar #header-wrapper { - background: var(--MENU-HEADER-BG-color); - color: var(--MENU-SEARCH-BOX-color); - border-color: var(--MENU-HEADER-BORDER-color); -} -#sidebar .searchbox { - border-color: var(--MENU-SEARCH-BOX-color); - background: var(--MENU-SEARCH-BG-color); -} -#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active { - background: var(--MENU-SECTIONS-ACTIVE-BG-color); -} -#sidebar .searchbox * { - color: var(--MENU-SEARCH-BOX-ICONS-color); -} - -#sidebar a { - color: var(--MENU-SECTIONS-LINK-color); -} - -#sidebar a:hover { - color: var(--MENU-SECTIONS-LINK-HOVER-color); -} - -#sidebar ul li.active > a { - background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color); - color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important; -} - -#sidebar hr { - border-color: var(--MENU-SECTION-HR-color); -} - -#body .tags a.tag-link { - background-color: var(--MENU-HEADER-BG-color); -} - -#body .tags a.tag-link:before { - border-right-color: var(--MENU-HEADER-BG-color); -} \ No newline at end of file diff --git a/workshop/themes/learn/static/css/theme-red.css b/workshop/themes/learn/static/css/theme-red.css deleted file mode 100644 index 36c9278..0000000 --- a/workshop/themes/learn/static/css/theme-red.css +++ /dev/null @@ -1,111 +0,0 @@ - -:root{ - - --MAIN-TEXT-color:#323232; /* Color of text by default */ - --MAIN-TITLES-TEXT-color: #5e5e5e; /* Color of titles h2-h3-h4-h5 */ - --MAIN-LINK-color:#f31c1c; /* Color of links */ - --MAIN-LINK-HOVER-color:#d01616; /* Color of hovered links */ - --MAIN-ANCHOR-color: #f31c1c; /* color of anchors on titles */ - - --MENU-HEADER-BG-color:#dc1010; /* Background color of menu header */ - --MENU-HEADER-BORDER-color:#e23131; /*Color of menu header border */ - - --MENU-SEARCH-BG-color:#b90000; /* Search field background color (by default borders + icons) */ - --MENU-SEARCH-BOX-color: #ef2020; /* Override search field border color */ - --MENU-SEARCH-BOX-ICONS-color: #fda1a1; /* Override search field icons color */ - - --MENU-SECTIONS-ACTIVE-BG-color:#2b2020; /* Background color of the active section and its childs */ - --MENU-SECTIONS-BG-color:#312525; /* Background color of other sections */ - --MENU-SECTIONS-LINK-color: #ccc; /* Color of links in menu */ - --MENU-SECTIONS-LINK-HOVER-color: #e6e6e6; /* Color of links in menu, when hovered */ - --MENU-SECTION-ACTIVE-CATEGORY-color: #777; /* Color of active category text */ - --MENU-SECTION-ACTIVE-CATEGORY-BG-color: #fff; /* Color of background for the active category (only) */ - - --MENU-VISITED-color: #ff3333; /* Color of 'page visited' icons in menu */ - --MENU-SECTION-HR-color: #2b2020; /* Color of
    separator in menu */ - -} - -body { - color: var(--MAIN-TEXT-color) !important; -} - -textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus { - border-color: none; - box-shadow: none; -} - -h2, h3, h4, h5 { - color: var(--MAIN-TITLES-TEXT-color) !important; -} - -a { - color: var(--MAIN-LINK-color); -} - -.anchor { - color: var(--MAIN-ANCHOR-color); -} - -a:hover { - color: var(--MAIN-LINK-HOVER-color); -} - -#sidebar ul li.visited > a .read-icon { - color: var(--MENU-VISITED-color); -} - -#body a.highlight:after { - display: block; - content: ""; - height: 1px; - width: 0%; - -webkit-transition: width 0.5s ease; - -moz-transition: width 0.5s ease; - -ms-transition: width 0.5s ease; - transition: width 0.5s ease; - background-color: var(--MAIN-LINK-HOVER-color); -} -#sidebar { - background-color: var(--MENU-SECTIONS-BG-color); -} -#sidebar #header-wrapper { - background: var(--MENU-HEADER-BG-color); - color: var(--MENU-SEARCH-BOX-color); - border-color: var(--MENU-HEADER-BORDER-color); -} -#sidebar .searchbox { - border-color: var(--MENU-SEARCH-BOX-color); - background: var(--MENU-SEARCH-BG-color); -} -#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active { - background: var(--MENU-SECTIONS-ACTIVE-BG-color); -} -#sidebar .searchbox * { - color: var(--MENU-SEARCH-BOX-ICONS-color); -} - -#sidebar a { - color: var(--MENU-SECTIONS-LINK-color); -} - -#sidebar a:hover { - color: var(--MENU-SECTIONS-LINK-HOVER-color); -} - -#sidebar ul li.active > a { - background: var(--MENU-SECTION-ACTIVE-CATEGORY-BG-color); - color: var(--MENU-SECTION-ACTIVE-CATEGORY-color) !important; -} - -#sidebar hr { - border-color: var(--MENU-SECTION-HR-color); -} - -#body .tags a.tag-link { - background-color: var(--MENU-HEADER-BG-color); -} - -#body .tags a.tag-link:before { - border-right-color: var(--MENU-HEADER-BG-color); -} \ No newline at end of file diff --git a/workshop/themes/learn/static/css/theme.css b/workshop/themes/learn/static/css/theme.css deleted file mode 100644 index 2e1f65e..0000000 --- a/workshop/themes/learn/static/css/theme.css +++ /dev/null @@ -1,1132 +0,0 @@ -@charset "UTF-8"; - -/* Tags */ -@import "tags.css"; - -#top-github-link, #body #breadcrumbs { - position: relative; - top: 50%; - -webkit-transform: translateY(-50%); - -moz-transform: translateY(-50%); - -o-transform: translateY(-50%); - -ms-transform: translateY(-50%); - transform: translateY(-50%); -} -.button, .button-secondary { - display: inline-block; - padding: 7px 12px; -} -.button:active, .button-secondary:active { - margin: 2px 0 -2px 0; -} -@font-face { - font-family: 'Novacento Sans Wide'; - src: url("../fonts/Novecentosanswide-UltraLight-webfont.eot"); - src: url("../fonts/Novecentosanswide-UltraLight-webfont.eot?#iefix") format("embedded-opentype"), url("../fonts/Novecentosanswide-UltraLight-webfont.woff2") format("woff2"), url("../fonts/Novecentosanswide-UltraLight-webfont.woff") format("woff"), url("../fonts/Novecentosanswide-UltraLight-webfont.ttf") format("truetype"), url("../fonts/Novecentosanswide-UltraLight-webfont.svg#novecento_sans_wideultralight") format("svg"); - font-style: normal; - font-weight: 200; -} -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 300; - src: url("../fonts/Work_Sans_300.eot?#iefix") format("embedded-opentype"), url("../fonts/Work_Sans_300.woff") format("woff"), url("../fonts/Work_Sans_300.woff2") format("woff2"), url("../fonts/Work_Sans_300.svg#WorkSans") format("svg"), url("../fonts/Work_Sans_300.ttf") format("truetype"); -} -@font-face { - font-family: 'Work Sans'; - font-style: normal; - font-weight: 500; - src: url("../fonts/Work_Sans_500.eot?#iefix") format("embedded-opentype"), url("../fonts/Work_Sans_500.woff") format("woff"), url("../fonts/Work_Sans_500.woff2") format("woff2"), url("../fonts/Work_Sans_500.svg#WorkSans") format("svg"), url("../fonts/Work_Sans_500.ttf") format("truetype"); -} -body { - background: #fff; - color: #777; -} -body #chapter h1 { - font-size: 3.5rem; -} -@media only all and (min-width: 48em) and (max-width: 59.938em) { - body #chapter h1 { - font-size: 3rem; - } -} -@media only all and (max-width: 47.938em) { - body #chapter h1 { - font-size: 2rem; - } -} -a { - color: #00bdf3; -} -a:hover { - color: #0082a7; -} -pre { - position: relative; - color: #ffffff; -} -.bg { - background: #fff; - border: 1px solid #eaeaea; -} -b, strong, label, th { - font-weight: 600; -} -.default-animation, #header #logo-svg, #header #logo-svg path, #sidebar, #sidebar ul, #body, #body .padding, #body .nav { - -webkit-transition: all 0.5s ease; - -moz-transition: all 0.5s ease; - transition: all 0.5s ease; -} -#grav-logo { - max-width: 60%; -} -#grav-logo path { - fill: #fff !important; -} -#sidebar { - font-weight: 300 !important; -} -fieldset { - border: 1px solid #ddd; -} -textarea, input[type="email"], input[type="number"], input[type="password"], input[type="search"], input[type="tel"], input[type="text"], input[type="url"], input[type="color"], input[type="date"], input[type="datetime"], input[type="datetime-local"], input[type="month"], input[type="time"], input[type="week"], select[multiple=multiple] { - background-color: white; - border: 1px solid #ddd; - box-shadow: inset 0 1px 3px rgba(0, 0, 0, 0.06); -} -textarea:hover, input[type="email"]:hover, input[type="number"]:hover, input[type="password"]:hover, input[type="search"]:hover, input[type="tel"]:hover, input[type="text"]:hover, input[type="url"]:hover, input[type="color"]:hover, input[type="date"]:hover, input[type="datetime"]:hover, input[type="datetime-local"]:hover, input[type="month"]:hover, input[type="time"]:hover, input[type="week"]:hover, select[multiple=multiple]:hover { - border-color: #c4c4c4; -} -textarea:focus, input[type="email"]:focus, input[type="number"]:focus, input[type="password"]:focus, input[type="search"]:focus, input[type="tel"]:focus, input[type="text"]:focus, input[type="url"]:focus, input[type="color"]:focus, input[type="date"]:focus, input[type="datetime"]:focus, input[type="datetime-local"]:focus, input[type="month"]:focus, input[type="time"]:focus, input[type="week"]:focus, select[multiple=multiple]:focus { - border-color: #00bdf3; - box-shadow: inset 0 1px 3px rgba(0,0,0,.06),0 0 5px rgba(0,169,218,.7) -} -#header-wrapper { - background: #8451a1; - color: #fff; - text-align: center; - border-bottom: 4px solid #9c6fb6; - padding: 1rem; -} -#header a { - display: inline-block; -} -#header #logo-svg { - width: 8rem; - height: 2rem; -} -#header #logo-svg path { - fill: #fff; -} -.searchbox { - margin-top: 1rem; - position: relative; - border: 1px solid #915eae; - background: #764890; - border-radius: 4px; -} -.searchbox label { - color: rgba(255, 255, 255, 0.8); - position: absolute; - left: 10px; - top: 3px; -} -.searchbox span { - color: rgba(255, 255, 255, 0.6); - position: absolute; - right: 10px; - top: 3px; - cursor: pointer; -} -.searchbox span:hover { - color: rgba(255, 255, 255, 0.9); -} -.searchbox input { - display: inline-block; - color: #fff; - width: 100%; - height: 30px; - background: transparent; - border: 0; - padding: 0 25px 0 30px; - margin: 0; - font-weight: 300; -} -.searchbox input::-webkit-input-placeholder { - color: rgba(255, 255, 255, 0.6); -} -.searchbox input::-moz-placeholder { - color: rgba(255, 255, 255, 0.6); -} -.searchbox input:-moz-placeholder { - color: rgba(255, 255, 255, 0.6); -} -.searchbox input:-ms-input-placeholder { - color: rgba(255, 255, 255, 0.6); -} -#sidebar-toggle-span { - display: none; -} -@media only all and (max-width: 47.938em) { - #sidebar-toggle-span { - display: inline; - } -} -#sidebar { - background-color: #322A38; - position: fixed; - top: 0; - width: 300px; - bottom: 0; - left: 0; - font-weight: 400; - font-size: 15px; -} -#sidebar a { - color: #ccc; -} -#sidebar a:hover { - color: #e6e6e6; -} -#sidebar a.subtitle { - color: rgba(204, 204, 204, 0.6); -} -#sidebar hr { - border-bottom: 1px solid #2a232f; -} -#sidebar a.padding { - padding: 0 1rem; -} -#sidebar h5 { - margin: 2rem 0 0; - position: relative; - line-height: 2; -} -#sidebar h5 a { - display: block; - margin-left: 0; - margin-right: 0; - padding-left: 1rem; - padding-right: 1rem; -} -#sidebar h5 i { - color: rgba(204, 204, 204, 0.6); - position: absolute; - right: 0.6rem; - top: 0.7rem; - font-size: 80%; -} -#sidebar h5.parent a { - background: #201b24; - color: #d9d9d9 !important; -} -#sidebar h5.active a { - background: #fff; - color: #777 !important; -} -#sidebar h5.active i { - color: #777 !important; -} -#sidebar h5 + ul.topics { - display: none; - margin-top: 0; -} -#sidebar h5.parent + ul.topics, #sidebar h5.active + ul.topics { - display: block; -} -#sidebar ul { - list-style: none; - padding: 0; - margin: 0; -} -#sidebar ul.searched a { - color: #999999; -} -#sidebar ul.searched .search-match a { - color: #e6e6e6; -} -#sidebar ul.searched .search-match a:hover { - color: white; -} -#sidebar ul.topics { - margin: 0 1rem; -} -#sidebar ul.topics.searched ul { - display: block; -} -#sidebar ul.topics ul { - display: none; - padding-bottom: 1rem; -} -#sidebar ul.topics ul ul { - padding-bottom: 0; -} -#sidebar ul.topics li.parent ul, #sidebar ul.topics > li.active ul { - display: block; -} -#sidebar ul.topics > li > a { - line-height: 2rem; - font-size: 1.1rem; -} -#sidebar ul.topics > li > a b { - opacity: 0.5; - font-weight: normal; -} -#sidebar ul.topics > li > a .fa { - margin-top: 9px; -} -#sidebar ul.topics > li.parent, #sidebar ul.topics > li.active { - background: #251f29; - margin-left: -1rem; - margin-right: -1rem; - padding-left: 1rem; - padding-right: 1rem; -} -#sidebar ul li.active > a { - background: #fff; - color: #777 !important; - margin-left: -1rem; - margin-right: -1rem; - padding-left: 1rem; - padding-right: 1rem; -} -#sidebar ul li { - padding: 0; -} -#sidebar ul li.visited + span { - margin-right: 16px; -} -#sidebar ul li a { - display: block; - padding: 2px 0; -} -#sidebar ul li a span { - text-overflow: ellipsis; - overflow: hidden; - white-space: nowrap; - display: block; -} -#sidebar ul li > a { - padding: 4px 0; -} -#sidebar ul li.visited > a .read-icon { - color: #9c6fb6; - display: inline; -} -#sidebar ul li li { - padding-left: 1rem; - text-indent: 0.2rem; -} -#main { - background: #f7f7f7; - margin: 0 0 1.563rem 0; -} -#body { - position: relative; - margin-left: 300px; - min-height: 100%; -} -#body img, #body .video-container { - margin: 3rem auto; - display: block; - text-align: center; -} -#body img.border, #body .video-container.border { - border: 2px solid #e6e6e6 !important; - padding: 2px; -} -#body img.shadow, #body .video-container.shadow { - box-shadow: 0 10px 30px rgba(0, 0, 0, 0.1); -} -#body img.inline { - display: inline !important; - margin: 0 !important; - vertical-align: bottom; -} -#body .bordered { - border: 1px solid #ccc; -} -#body .padding { - padding: 3rem 6rem; -} -@media only all and (max-width: 59.938em) { - #body .padding { - position: static; - padding: 15px 3rem; - } -} -@media only all and (max-width: 47.938em) { - #body .padding { - padding: 5px 1rem; - } -} -#body h1 + hr { - margin-top: -1.7rem; - margin-bottom: 3rem; -} -@media only all and (max-width: 59.938em) { - #body #navigation { - position: static; - margin-right: 0 !important; - width: 100%; - display: table; - } -} -#body .nav { - position: fixed; - top: 0; - bottom: 0; - width: 4rem; - font-size: 50px; - height: 100%; - cursor: pointer; - display: table; - text-align: center; -} -#body .nav > i { - display: table-cell; - vertical-align: middle; - text-align: center; -} -@media only all and (max-width: 59.938em) { - #body .nav { - display: table-cell; - position: static; - top: auto; - width: 50%; - text-align: center; - height: 100px; - line-height: 100px; - padding-top: 0; - } - #body .nav > i { - display: inline-block; - } -} -#body .nav:hover { - background: #F6F6F6; -} -#body .nav.nav-pref { - left: 0; -} -#body .nav.nav-next { - right: 0; -} -#body-inner { - margin-bottom: 5rem; -} -#chapter { - display: flex; - align-items: center; - justify-content: center; - height: 100%; - padding: 2rem 0; -} -#chapter #body-inner { - padding-bottom: 3rem; - max-width: 80%; -} -#chapter h3 { - font-family: "Work Sans", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif; - font-weight: 300; - text-align: center; -} -#chapter h1 { - font-size: 5rem; - border-bottom: 4px solid #F0F2F4; -} -#chapter p { - text-align: center; - font-size: 1.2rem; -} -#footer { - padding: 3rem 1rem; - color: #b3b3b3; - font-size: 13px; -} -#footer p { - margin: 0; -} -body { - font-family: "Work Sans", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif; - font-weight: 300; - line-height: 1.6; - font-size: 18px !important; -} -h2, h3, h4, h5, h6 { - font-family: "Work Sans", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif; - text-rendering: optimizeLegibility; - color: #5e5e5e; - font-weight: 400; - letter-spacing: -1px; -} -h1 { - font-family: "Novacento Sans Wide", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif; - text-align: center; - text-transform: uppercase; - color: #222; - font-weight: 200; -} -blockquote { - border-left: 10px solid #F0F2F4; -} -blockquote p { - font-size: 1.1rem; - color: #999; -} -blockquote cite { - display: block; - text-align: right; - color: #666; - font-size: 1.2rem; -} -div.notices { - margin: 2rem 0; - position: relative; -} -div.notices p { - padding: 15px; - display: block; - font-size: 1rem; - margin-top: 0rem; - margin-bottom: 0rem; - color: #666; -} -div.notices p:first-child:before { - position: absolute; - top: 2px; - color: #fff; - font-family: "Font Awesome 5 Free"; - font-weight: 900; - content: "\f06a"; - left: 10px; -} -div.notices p:first-child:after { - position: absolute; - top: 2px; - color: #fff; - left: 2rem; -} -div.notices.info p { - border-top: 30px solid #F0B37E; - background: #FFF2DB; -} -div.notices.info p:first-child:after { - content: 'Info'; -} -div.notices.warning p { - border-top: 30px solid rgba(217, 83, 79, 0.8); - background: #FAE2E2; -} -div.notices.warning p:first-child:after { - content: 'Warning'; -} -div.notices.note p { - border-top: 30px solid #6AB0DE; - background: #E7F2FA; -} -div.notices.note p:first-child:after { - content: 'Note'; -} -div.notices.tip p { - border-top: 30px solid rgba(92, 184, 92, 0.8); - background: #E6F9E6; -} -div.notices.tip p:first-child:after { - content: 'Tip'; -} - -/* attachments shortcode */ - -section.attachments { - margin: 2rem 0; - position: relative; -} - -section.attachments label { - font-weight: 400; - padding-left: 0.5em; - padding-top: 0.2em; - padding-bottom: 0.2em; - margin: 0; -} - -section.attachments .attachments-files { - padding: 15px; - display: block; - font-size: 1rem; - margin-top: 0rem; - margin-bottom: 0rem; - color: #666; -} - -section.attachments.orange label { - color: #fff; - background: #F0B37E; -} - -section.attachments.orange .attachments-files { - background: #FFF2DB; -} - -section.attachments.green label { - color: #fff; - background: rgba(92, 184, 92, 0.8); -} - -section.attachments.green .attachments-files { - background: #E6F9E6; -} - -section.attachments.blue label { - color: #fff; - background: #6AB0DE; -} - -section.attachments.blue .attachments-files { - background: #E7F2FA; -} - -section.attachments.grey label { - color: #fff; - background: #505d65; -} - -section.attachments.grey .attachments-files { - background: #f4f4f4; -} - -/* Children shortcode */ - -/* Children shortcode */ -.children p { - font-size: small; - margin-top: 0px; - padding-top: 0px; - margin-bottom: 0px; - padding-bottom: 0px; -} -.children-li p { - font-size: small; - font-style: italic; - -} -.children-h2 p, .children-h3 p { - font-size: small; - margin-top: 0px; - padding-top: 0px; - margin-bottom: 0px; - padding-bottom: 0px; -} -.children h3,.children h2 { - margin-bottom: 0px; - margin-top: 5px; -} - -code, kbd, pre, samp { - font-family: "Consolas", menlo, monospace; - font-size: 92%; -} -code { - border-radius: 2px; - white-space: nowrap; - color: #5e5e5e; - background: #FFF7DD; - border: 1px solid #fbf0cb; - padding: 0px 2px; -} -code + .copy-to-clipboard { - margin-left: -1px; - border-left: 0 !important; - font-size: inherit !important; - vertical-align: middle; - height: 21px; - top: 0; -} -pre { - padding: 1rem; - margin: 2rem 0; - background: #282c34; - border: 0; - border-radius: 2px; - line-height: 1.15; -} -pre code { - color: whitesmoke; - background: inherit; - white-space: inherit; - border: 0; - padding: 0; - margin: 0; - font-size: 15px; -} -hr { - border-bottom: 4px solid #F0F2F4; -} -.page-title { - margin-top: -25px; - padding: 25px; - float: left; - clear: both; - background: #9c6fb6; - color: #fff; -} -#body a.anchor-link { - color: #ccc; -} -#body a.anchor-link:hover { - color: #9c6fb6; -} -#body-inner .tabs-wrapper.ui-theme-badges { - background: #1d1f21; -} -#body-inner .tabs-wrapper.ui-theme-badges .tabs-nav li { - font-size: 0.9rem; - text-transform: uppercase; -} -#body-inner .tabs-wrapper.ui-theme-badges .tabs-nav li a { - background: #35393c; -} -#body-inner .tabs-wrapper.ui-theme-badges .tabs-nav li.current a { - background: #4d5257; -} -#body-inner pre { - white-space: pre-wrap; -} -.tabs-wrapper pre { - margin: 1rem 0; - border: 0; - padding: 0; - background: inherit; -} -table { - border: 1px solid #eaeaea; - table-layout: auto; -} -th { - background: #f7f7f7; - padding: 0.5rem; -} -td { - padding: 0.5rem; - border: 1px solid #eaeaea; -} -.button { - background: #9c6fb6; - color: #fff; - box-shadow: 0 3px 0 #00a5d4; -} -.button:hover { - background: #00a5d4; - box-shadow: 0 3px 0 #008db6; - color: #fff; -} -.button:active { - box-shadow: 0 1px 0 #008db6; -} -.button-secondary { - background: #F8B450; - color: #fff; - box-shadow: 0 3px 0 #f7a733; -} -.button-secondary:hover { - background: #f7a733; - box-shadow: 0 3px 0 #f69b15; - color: #fff; -} -.button-secondary:active { - box-shadow: 0 1px 0 #f69b15; -} -.bullets { - margin: 1.7rem 0; - margin-left: -0.85rem; - margin-right: -0.85rem; - overflow: auto; -} -.bullet { - float: left; - padding: 0 0.85rem; -} -.two-column-bullet { - width: 50%; -} -@media only all and (max-width: 47.938em) { - .two-column-bullet { - width: 100%; - } -} -.three-column-bullet { - width: 33.33333%; -} -@media only all and (max-width: 47.938em) { - .three-column-bullet { - width: 100%; - } -} -.four-column-bullet { - width: 25%; -} -@media only all and (max-width: 47.938em) { - .four-column-bullet { - width: 100%; - } -} -.bullet-icon { - float: left; - background: #9c6fb6; - padding: 0.875rem; - width: 3.5rem; - height: 3.5rem; - border-radius: 50%; - color: #fff; - font-size: 1.75rem; - text-align: center; -} -.bullet-icon-1 { - background: #9c6fb6; -} -.bullet-icon-2 { - background: #00f3d8; -} -.bullet-icon-3 { - background: #e6f300; -} -.bullet-content { - margin-left: 4.55rem; -} -.tooltipped { - position: relative; -} -.tooltipped:after { - position: absolute; - z-index: 1000000; - display: none; - padding: 5px 8px; - font: normal normal 11px/1.5 "Work Sans", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif; - color: #fff; - text-align: center; - text-decoration: none; - text-shadow: none; - text-transform: none; - letter-spacing: normal; - word-wrap: break-word; - white-space: pre; - pointer-events: none; - content: attr(aria-label); - background: rgba(0, 0, 0, 0.8); - border-radius: 3px; - -webkit-font-smoothing: subpixel-antialiased; -} -.tooltipped:before { - position: absolute; - z-index: 1000001; - display: none; - width: 0; - height: 0; - color: rgba(0, 0, 0, 0.8); - pointer-events: none; - content: ""; - border: 5px solid transparent; -} -.tooltipped:hover:before, .tooltipped:hover:after, .tooltipped:active:before, .tooltipped:active:after, .tooltipped:focus:before, .tooltipped:focus:after { - display: inline-block; - text-decoration: none; -} -.tooltipped-s:after, .tooltipped-se:after, .tooltipped-sw:after { - top: 100%; - right: 50%; - margin-top: 5px; -} -.tooltipped-s:before, .tooltipped-se:before, .tooltipped-sw:before { - top: auto; - right: 50%; - bottom: -5px; - margin-right: -5px; - border-bottom-color: rgba(0, 0, 0, 0.8); -} -.tooltipped-se:after { - right: auto; - left: 50%; - margin-left: -15px; -} -.tooltipped-sw:after { - margin-right: -15px; -} -.tooltipped-n:after, .tooltipped-ne:after, .tooltipped-nw:after { - right: 50%; - bottom: 100%; - margin-bottom: 5px; -} -.tooltipped-n:before, .tooltipped-ne:before, .tooltipped-nw:before { - top: -5px; - right: 50%; - bottom: auto; - margin-right: -5px; - border-top-color: rgba(0, 0, 0, 0.8); -} -.tooltipped-ne:after { - right: auto; - left: 50%; - margin-left: -15px; -} -.tooltipped-nw:after { - margin-right: -15px; -} -.tooltipped-s:after, .tooltipped-n:after { - transform: translateX(50%); -} -.tooltipped-w:after { - right: 100%; - bottom: 50%; - margin-right: 5px; - transform: translateY(50%); -} -.tooltipped-w:before { - top: 50%; - bottom: 50%; - left: -5px; - margin-top: -5px; - border-left-color: rgba(0, 0, 0, 0.8); -} -.tooltipped-e:after { - bottom: 50%; - left: 100%; - margin-left: 5px; - transform: translateY(50%); -} -.tooltipped-e:before { - top: 50%; - right: -5px; - bottom: 50%; - margin-top: -5px; - border-right-color: rgba(0, 0, 0, 0.8); -} -.highlightable { - padding: 1rem 0 1rem; - overflow: auto; - position: relative; -} -.hljs::selection, .hljs span::selection { - background: #b7b7b7; -} -.lightbox-active #body { - overflow: visible; -} -.lightbox-active #body .padding { - overflow: visible; -} -#github-contrib i { - vertical-align: middle; -} -.featherlight img { - margin: 0 !important; -} -.lifecycle #body-inner ul { - list-style: none; - margin: 0; - padding: 2rem 0 0; - position: relative; -} -.lifecycle #body-inner ol { - margin: 1rem 0 1rem 0; - padding: 2rem; - position: relative; -} -.lifecycle #body-inner ol li { - margin-left: 1rem; -} -.lifecycle #body-inner ol strong, .lifecycle #body-inner ol label, .lifecycle #body-inner ol th { - text-decoration: underline; -} -.lifecycle #body-inner ol ol { - margin-left: -1rem; -} -.lifecycle #body-inner h3[class*='level'] { - font-size: 20px; - position: absolute; - margin: 0; - padding: 4px 10px; - right: 0; - z-index: 1000; - color: #fff; - background: #1ABC9C; -} -.lifecycle #body-inner ol h3 { - margin-top: 1rem !important; - right: 2rem !important; -} -.lifecycle #body-inner .level-1 + ol { - background: #f6fefc; - border: 4px solid #1ABC9C; - color: #16A085; -} -.lifecycle #body-inner .level-1 + ol h3 { - background: #2ECC71; -} -.lifecycle #body-inner .level-2 + ol { - background: #f7fdf9; - border: 4px solid #2ECC71; - color: #27AE60; -} -.lifecycle #body-inner .level-2 + ol h3 { - background: #3498DB; -} -.lifecycle #body-inner .level-3 + ol { - background: #f3f9fd; - border: 4px solid #3498DB; - color: #2980B9; -} -.lifecycle #body-inner .level-3 + ol h3 { - background: #34495E; -} -.lifecycle #body-inner .level-4 + ol { - background: #e4eaf0; - border: 4px solid #34495E; - color: #2C3E50; -} -.lifecycle #body-inner .level-4 + ol h3 { - background: #34495E; -} -#top-bar { - background: #F6F6F6; - border-radius: 2px; - padding: 0 1rem; - height: 0; - min-height: 3rem; -} -#top-github-link { - position: relative; - z-index: 1; - float: right; - display: block; -} -#body #breadcrumbs { - height: auto; - margin-bottom: 0; - padding-left: 0; - line-height: 1.4; - overflow: hidden; - white-space: nowrap; - text-overflow: ellipsis; - width: 70%; - display: inline-block; - float: left; -} -#body #breadcrumbs span { - padding: 0 0.1rem; -} -@media only all and (max-width: 59.938em) { - #sidebar { - width: 230px; - } - #body { - margin-left: 230px; - } -} -@media only all and (max-width: 47.938em) { - #sidebar { - width: 230px; - left: -230px; - } - #body { - margin-left: 0; - width: 100%; - } - .sidebar-hidden { - overflow: hidden; - } - .sidebar-hidden #sidebar { - left: 0; - } - .sidebar-hidden #body { - margin-left: 230px; - overflow: hidden; - } - .sidebar-hidden #overlay { - position: absolute; - left: 0; - right: 0; - top: 0; - bottom: 0; - z-index: 10; - background: rgba(255, 255, 255, 0.5); - cursor: pointer; - } -} -.copy-to-clipboard { - background-image: url(../images/clippy.svg); - background-position: 50% 50%; - background-size: 16px 16px; - background-repeat: no-repeat; - width: 27px; - height: 1.45rem; - top: -1px; - display: inline-block; - vertical-align: middle; - position: relative; - color: #5e5e5e; - background-color: #FFF7DD; - margin-left: -.2rem; - cursor: pointer; - border-radius: 0 2px 2px 0; - margin-bottom: 1px; -} -.copy-to-clipboard:hover { - background-color: #E8E2CD; -} -pre .copy-to-clipboard { - position: absolute; - right: 4px; - top: 4px; - background-color: #949bab; - color: #ccc; - border-radius: 2px; -} -pre .copy-to-clipboard:hover { - background-color: #656c72; - color: #fff; -} -.parent-element { - -webkit-transform-style: preserve-3d; - -moz-transform-style: preserve-3d; - transform-style: preserve-3d; -} - -#sidebar ul.topics > li > a .read-icon { - margin-top: 9px; -} - -#sidebar ul { - list-style: none; - padding: 0; - margin: 0; -} - -#sidebar #shortcuts li { - padding: 2px 0; - list-style: none; -} - -#sidebar ul li .read-icon { - display: none; - float: right; - font-size: 13px; - min-width: 16px; - margin: 4px 0 0 0; - text-align: right; -} -#sidebar ul li.visited > a .read-icon { - color: #00bdf3; - display: inline; -} - -#sidebar #shortcuts h3 { - font-family: "Novacento Sans Wide", "Helvetica", "Tahoma", "Geneva", "Arial", sans-serif; - color: white ; - margin-top:1rem; - padding-left: 1rem; -} - -#searchResults { - text-align: left; -} diff --git a/workshop/themes/learn/static/fonts/Inconsolata.eot b/workshop/themes/learn/static/fonts/Inconsolata.eot deleted file mode 100644 index 0a705d6..0000000 Binary files a/workshop/themes/learn/static/fonts/Inconsolata.eot and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Inconsolata.svg b/workshop/themes/learn/static/fonts/Inconsolata.svg deleted file mode 100644 index b7f97c8..0000000 --- a/workshop/themes/learn/static/fonts/Inconsolata.svg +++ /dev/null @@ -1,359 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/workshop/themes/learn/static/fonts/Inconsolata.ttf b/workshop/themes/learn/static/fonts/Inconsolata.ttf deleted file mode 100644 index 4b8a36d..0000000 Binary files a/workshop/themes/learn/static/fonts/Inconsolata.ttf and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Inconsolata.woff b/workshop/themes/learn/static/fonts/Inconsolata.woff deleted file mode 100644 index 6f39625..0000000 Binary files a/workshop/themes/learn/static/fonts/Inconsolata.woff and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.eot b/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.eot deleted file mode 100644 index 9984682..0000000 Binary files a/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.eot and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.svg b/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.svg deleted file mode 100644 index c412ea8..0000000 --- a/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.svg +++ /dev/null @@ -1,1019 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.ttf b/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.ttf deleted file mode 100644 index 8cfb62d..0000000 Binary files a/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.ttf and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.woff b/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.woff deleted file mode 100644 index d5c4290..0000000 Binary files a/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.woff and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.woff2 b/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.woff2 deleted file mode 100644 index eefb4a3..0000000 Binary files a/workshop/themes/learn/static/fonts/Novecentosanswide-Normal-webfont.woff2 and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.eot b/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.eot deleted file mode 100644 index 2a26561..0000000 Binary files a/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.eot and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.svg b/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.svg deleted file mode 100644 index e642ab0..0000000 --- a/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.svg +++ /dev/null @@ -1,918 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.ttf b/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.ttf deleted file mode 100644 index 9ce9c7f..0000000 Binary files a/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.ttf and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.woff b/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.woff deleted file mode 100644 index 381650c..0000000 Binary files a/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.woff and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.woff2 b/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.woff2 deleted file mode 100644 index 7e65954..0000000 Binary files a/workshop/themes/learn/static/fonts/Novecentosanswide-UltraLight-webfont.woff2 and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_200.eot b/workshop/themes/learn/static/fonts/Work_Sans_200.eot deleted file mode 100644 index 4052e4f..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_200.eot and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_200.svg b/workshop/themes/learn/static/fonts/Work_Sans_200.svg deleted file mode 100644 index 58ab4ba..0000000 --- a/workshop/themes/learn/static/fonts/Work_Sans_200.svg +++ /dev/null @@ -1,332 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/workshop/themes/learn/static/fonts/Work_Sans_200.ttf b/workshop/themes/learn/static/fonts/Work_Sans_200.ttf deleted file mode 100644 index 68019e1..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_200.ttf and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_200.woff b/workshop/themes/learn/static/fonts/Work_Sans_200.woff deleted file mode 100644 index a1bd9e4..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_200.woff and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_200.woff2 b/workshop/themes/learn/static/fonts/Work_Sans_200.woff2 deleted file mode 100644 index 20c68a7..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_200.woff2 and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_300.eot b/workshop/themes/learn/static/fonts/Work_Sans_300.eot deleted file mode 100644 index ace7993..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_300.eot and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_300.svg b/workshop/themes/learn/static/fonts/Work_Sans_300.svg deleted file mode 100644 index f29d0c8..0000000 --- a/workshop/themes/learn/static/fonts/Work_Sans_300.svg +++ /dev/null @@ -1,331 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/workshop/themes/learn/static/fonts/Work_Sans_300.ttf b/workshop/themes/learn/static/fonts/Work_Sans_300.ttf deleted file mode 100644 index 35387c2..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_300.ttf and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_300.woff b/workshop/themes/learn/static/fonts/Work_Sans_300.woff deleted file mode 100644 index 8d789ea..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_300.woff and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_300.woff2 b/workshop/themes/learn/static/fonts/Work_Sans_300.woff2 deleted file mode 100644 index f6e216d..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_300.woff2 and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_500.eot b/workshop/themes/learn/static/fonts/Work_Sans_500.eot deleted file mode 100644 index 9df6929..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_500.eot and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_500.svg b/workshop/themes/learn/static/fonts/Work_Sans_500.svg deleted file mode 100644 index 4b030b7..0000000 --- a/workshop/themes/learn/static/fonts/Work_Sans_500.svg +++ /dev/null @@ -1,333 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/workshop/themes/learn/static/fonts/Work_Sans_500.ttf b/workshop/themes/learn/static/fonts/Work_Sans_500.ttf deleted file mode 100644 index 5b8cc53..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_500.ttf and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_500.woff b/workshop/themes/learn/static/fonts/Work_Sans_500.woff deleted file mode 100644 index df05851..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_500.woff and /dev/null differ diff --git a/workshop/themes/learn/static/fonts/Work_Sans_500.woff2 b/workshop/themes/learn/static/fonts/Work_Sans_500.woff2 deleted file mode 100644 index b06c54d..0000000 Binary files a/workshop/themes/learn/static/fonts/Work_Sans_500.woff2 and /dev/null differ diff --git a/workshop/themes/learn/static/images/clippy.svg b/workshop/themes/learn/static/images/clippy.svg deleted file mode 100644 index e786900..0000000 --- a/workshop/themes/learn/static/images/clippy.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/workshop/themes/learn/static/images/logo.png b/workshop/themes/learn/static/images/logo.png deleted file mode 100644 index 7de3126..0000000 Binary files a/workshop/themes/learn/static/images/logo.png and /dev/null differ diff --git a/workshop/themes/learn/static/js/auto-complete.js b/workshop/themes/learn/static/js/auto-complete.js deleted file mode 100644 index 7fbde99..0000000 --- a/workshop/themes/learn/static/js/auto-complete.js +++ /dev/null @@ -1,223 +0,0 @@ -/* - JavaScript autoComplete v1.0.4 - Copyright (c) 2014 Simon Steinberger / Pixabay - GitHub: https://github.com/Pixabay/JavaScript-autoComplete - License: http://www.opensource.org/licenses/mit-license.php -*/ - -var autoComplete = (function(){ - // "use strict"; - function autoComplete(options){ - if (!document.querySelector) return; - - // helpers - function hasClass(el, className){ return el.classList ? el.classList.contains(className) : new RegExp('\\b'+ className+'\\b').test(el.className); } - - function addEvent(el, type, handler){ - if (el.attachEvent) el.attachEvent('on'+type, handler); else el.addEventListener(type, handler); - } - function removeEvent(el, type, handler){ - // if (el.removeEventListener) not working in IE11 - if (el.detachEvent) el.detachEvent('on'+type, handler); else el.removeEventListener(type, handler); - } - function live(elClass, event, cb, context){ - addEvent(context || document, event, function(e){ - var found, el = e.target || e.srcElement; - while (el && !(found = hasClass(el, elClass))) el = el.parentElement; - if (found) cb.call(el, e); - }); - } - - var o = { - selector: 0, - source: 0, - minChars: 3, - delay: 150, - offsetLeft: 0, - offsetTop: 1, - cache: 1, - menuClass: '', - renderItem: function (item, search){ - // escape special characters - search = search.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); - var re = new RegExp("(" + search.split(' ').join('|') + ")", "gi"); - return '
    ' + item.replace(re, "$1") + '
    '; - }, - onSelect: function(e, term, item){} - }; - for (var k in options) { if (options.hasOwnProperty(k)) o[k] = options[k]; } - - // init - var elems = typeof o.selector == 'object' ? [o.selector] : document.querySelectorAll(o.selector); - for (var i=0; i 0) - that.sc.scrollTop = selTop + that.sc.suggestionHeight + scrTop - that.sc.maxHeight; - else if (selTop < 0) - that.sc.scrollTop = selTop + scrTop; - } - } - } - addEvent(window, 'resize', that.updateSC); - document.body.appendChild(that.sc); - - live('autocomplete-suggestion', 'mouseleave', function(e){ - var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); - if (sel) setTimeout(function(){ sel.className = sel.className.replace('selected', ''); }, 20); - }, that.sc); - - live('autocomplete-suggestion', 'mouseover', function(e){ - var sel = that.sc.querySelector('.autocomplete-suggestion.selected'); - if (sel) sel.className = sel.className.replace('selected', ''); - this.className += ' selected'; - }, that.sc); - - live('autocomplete-suggestion', 'mousedown', function(e){ - if (hasClass(this, 'autocomplete-suggestion')) { // else outside click - var v = this.getAttribute('data-val'); - that.value = v; - o.onSelect(e, v, this); - that.sc.style.display = 'none'; - } - }, that.sc); - - that.blurHandler = function(){ - try { var over_sb = document.querySelector('.autocomplete-suggestions:hover'); } catch(e){ var over_sb = 0; } - if (!over_sb) { - that.last_val = that.value; - that.sc.style.display = 'none'; - setTimeout(function(){ that.sc.style.display = 'none'; }, 350); // hide suggestions on fast input - } else if (that !== document.activeElement) setTimeout(function(){ that.focus(); }, 20); - }; - addEvent(that, 'blur', that.blurHandler); - - var suggest = function(data){ - var val = that.value; - that.cache[val] = data; - if (data.length && val.length >= o.minChars) { - var s = ''; - for (var i=0;i 40) && key != 13 && key != 27) { - var val = that.value; - if (val.length >= o.minChars) { - if (val != that.last_val) { - that.last_val = val; - clearTimeout(that.timer); - if (o.cache) { - if (val in that.cache) { suggest(that.cache[val]); return; } - // no requests if previous suggestions were empty - for (var i=1; i https://github.com/noelboss/featherlight/issues/317 -!function(u){"use strict";if(void 0!==u)if(u.fn.jquery.match(/-ajax/))"console"in window&&window.console.info("Featherlight needs regular jQuery, not the slim version.");else{var r=[],i=function(t){return r=u.grep(r,function(e){return e!==t&&0','
    ','",'
    '+n.loading+"
    ","
    ","
    "].join("")),o="."+n.namespace+"-close"+(n.otherClose?","+n.otherClose:"");return n.$instance=i.clone().addClass(n.variant),n.$instance.on(n.closeTrigger+"."+n.namespace,function(e){if(!e.isDefaultPrevented()){var t=u(e.target);("background"===n.closeOnClick&&t.is("."+n.namespace)||"anywhere"===n.closeOnClick||t.closest(o).length)&&(n.close(e),e.preventDefault())}}),this},getContent:function(){if(!1!==this.persist&&this.$content)return this.$content;var t=this,e=this.constructor.contentFilters,n=function(e){return t.$currentTarget&&t.$currentTarget.attr(e)},r=n(t.targetAttr),i=t.target||r||"",o=e[t.type];if(!o&&i in e&&(o=e[i],i=t.target&&r),i=i||n("href")||"",!o)for(var a in e)t[a]&&(o=e[a],i=t[a]);if(!o){var s=i;if(i=null,u.each(t.contentFilters,function(){return(o=e[this]).test&&(i=o.test(s)),!i&&o.regex&&s.match&&s.match(o.regex)&&(i=s),!i}),!i)return"console"in window&&window.console.error("Featherlight: no content filter found "+(s?' for "'+s+'"':" (no target specified)")),!1}return o.process.call(t,i)},setContent:function(e){return this.$instance.removeClass(this.namespace+"-loading"),this.$instance.toggleClass(this.namespace+"-iframe",e.is("iframe")),this.$instance.find("."+this.namespace+"-inner").not(e).slice(1).remove().end().replaceWith(u.contains(this.$instance[0],e[0])?"":e),this.$content=e.addClass(this.namespace+"-inner"),this},open:function(t){var n=this;if(n.$instance.hide().appendTo(n.root),!(t&&t.isDefaultPrevented()||!1===n.beforeOpen(t))){t&&t.preventDefault();var e=n.getContent();if(e)return r.push(n),s(!0),n.$instance.fadeIn(n.openSpeed),n.beforeContent(t),u.when(e).always(function(e){n.setContent(e),n.afterContent(t)}).then(n.$instance.promise()).done(function(){n.afterOpen(t)})}return n.$instance.detach(),u.Deferred().reject().promise()},close:function(e){var t=this,n=u.Deferred();return!1===t.beforeClose(e)?n.reject():(0===i(t).length&&s(!1),t.$instance.fadeOut(t.closeSpeed,function(){t.$instance.detach(),t.afterClose(e),n.resolve()})),n.promise()},resize:function(e,t){if(e&&t&&(this.$content.css("width","").css("height",""),this.$content.parent().width()');return n.onload=function(){r.naturalWidth=n.width,r.naturalHeight=n.height,t.resolve(r)},n.onerror=function(){t.reject(r)},n.src=e,t.promise()}},html:{regex:/^\s*<[\w!][^<]*>/,process:function(e){return u(e)}},ajax:{regex:/./,process:function(e){var n=u.Deferred(),r=u("
    ").load(e,function(e,t){"error"!==t&&n.resolve(r.contents()),n.fail()});return n.promise()}},iframe:{process:function(e){var t=new u.Deferred,n=u("