1656597180
Soss
Soss is a library for probabilistic programming.
Let's look at an example. First we'll load things:
using MeasureTheory
using Soss
MeasureTheory.jl is designed specifically with PPLs like Soss in mind, though you can also use Distributions.jl.
Now for a model. Here's a linear regression:
m = @model x begin
α ~ Lebesgue(ℝ)
β ~ Normal()
σ ~ Exponential()
y ~ For(x) do xj
Normal(α + β * xj, σ)
end
return y
end
Next we'll generate some fake data to work with. For x
-values, let's use
x = randn(20)
Now loosely speaking, Lebesgue(ℝ)
is uniform over the real numbers, so we can't really sample from it. Instead, let's transform the model and make α
an argument:
julia> predα = predictive(m, :α)
@model (x, α) begin
σ ~ Exponential()
β ~ Normal()
y ~ For(x) do xj
Normal(α + β * xj, σ)
end
return y
end
Now we can do
julia> y = rand(predα(x=x,α=10.0))
20-element Vector{Float64}:
10.554133456468438
9.378065258831002
12.873667041657287
8.940799408080496
10.737189595204965
9.500536439014208
11.327606120726893
10.899892855024445
10.18488773139243
10.386969795947177
10.382195272387214
8.358407507910297
10.727173015711768
10.452311211064654
11.076232496702387
11.362009520020141
9.539433052406448
10.61851691333643
11.586170856832645
9.197496058151618
Now for inference! Let's use DynamicHMC
, which we have wrapped in SampleChainsDynamicHMC
.
julia> using SampleChainsDynamicHMC
[ Info: Precompiling SampleChainsDynamicHMC [6d9fd711-e8b2-4778-9c70-c1dfb499d4c4]
julia> post = sample(m(x=x) | (y=y,), dynamichmc())
4000-element MultiChain with 4 chains and schema (σ = Float64, β = Float64, α = Float64)
(σ = 1.0±0.15, β = 0.503±0.26, α = 10.2±0.25)
First, a fine point: When people say "the Turing PPL" they usually mean what's technically called "DynamicPPL".
Soss and DynamicPPL are both maturing and becoming more complete, so the above will change over time. It's also worth noting that we (the Turing team and I) hope to move toward a natural way of using these systems together to arrive at the best of both.
I'm glad you asked! Lots of things:
For more details, please see the documentation.
Author: cscherrer
Source Code: https://github.com/cscherrer/Soss.jl
License: MIT license
1656572160
Chronos aims to be a drop-in replacement for nesbot/carbon
. It focuses on providing immutable date/datetime objects. Immutable objects help ensure that datetime objects aren't accidentally modified keeping data more predictable.
Installing with composer:
$ composer require cakephp/chronos
You can then use Chronos:
<?php
require 'vendor/autoload.php';
use Cake\Chronos\Chronos;
printf("Now: %s", Chronos::now());
Differences with nesbot/carbon
The biggest and main difference is that Chronos
extends DateTimeImmutable
instead of DateTime
. Immutability for date values has proven to be a great way of avoiding bugs and reduce the amount of code, since developers don't have to manually copy the instance every time they need a change.
Another important feature it offers is the Date
class, which is used for representing dates without time (calendar dates). Any time method called on this type of object is basically a no-op.
There are other implementation changes, but one that users might not notice is Chronos
considers Monday as the start of the week instead of Sunday. This follows the ISO-8601 and current versions of PHP 5.6 and PHP 7.
A minor but still noticeable difference is that Chronos
has no external dependencies, it is completely standalone.
Finally, Chronos is faster than Carbon as it has been optimized for the creation of hundreds of instances with minimal overhead.
Migrating from Carbon
First add cakephp/chronos
to your composer.json
:
php composer.phar require cakephp/chronos
By default Chronos includes a compatibility script that creates aliases for the relevant Carbon classes. This will let most applications upgrade with very little effort. If you'd like to permanently update your code, you will need to update imports and typehints. Assuming src
contains the files you want to migrate, we could use the following to update files:
# Replace imports
find ./src -type f -name '*.php' -exec sed -i '' 's/use Carbon\\CarbonInterval/use Cake\\Chronos\\ChronosInterval/g' {} \;
find ./src -type f -name '*.php' -exec sed -i '' 's/use Carbon\\CarbonImmutable/use Cake\\Chronos\\Chronos/g' {} \;
find ./src -type f -name '*.php' -exec sed -i '' 's/use Carbon\\Carbon/use Cake\\Chronos\\Chronos/g' {} \;
# Replace typehints and extensions
find ./src -type f -name '*.php' -exec sed -i '' 's/CarbonInterval/ChronosInterval/g' {} \;
find ./src -type f -name '*.php' -exec sed -i '' 's/CarbonImmutable/Chronos/g' {} \;
find ./src -type f -name '*.php' -exec sed -i '' 's/Carbon/Chronos/g' {} \;
At this point your code should mostly work as it did before. The biggest difference is that Chronos instances are immutable.
Immutable objects have a number of advantages:
With those benefits in mind, there are a few things you need to keep in mind when modifying immutable objects:
// This will lose modifications
$date = new Chronos('2015-10-21 16:29:00');
$date->modify('+2 hours');
// This will keep modifications
$date = new Chronos('2015-10-21 16:29:00');
$date = $date->modify('+2 hours');
In the case that you need a mutable instance you can get one:
$time = new Chronos('2015-10-21 16:29:00');
$mutable = $time->toMutable();
$date = new Date('2015-10-21');
$mutable = $date->toMutable();
If you have a mutable object and want an immutable variant you can do the following:
$time = new MutableDateTime('2015-10-21 16:29:00');
$fixed = $time->toImmutable();
$date = new MutableDate('2015-10-21');
$fixed = $date->toImmutable();
Calendar Dates
PHP only offers datetime objects as part of the native extensions. Chronos adds a number of conveniences to the traditional DateTime object and introduces a Date
object. Date
instances offer compatibility with the ChronosInterface
, but have their time frozen to 00:00:00
and the timezone set to the server default timezone. This makes them ideal when working with calendar dates as the time components will always match.
use Cake\Chronos\Date;
$today = new Date();
echo $today;
// Outputs '2015-10-21'
echo $today->modify('+3 hours');
// Outputs '2015-10-21'
Like instances of Chronos
, Date
objects are also immutable. The MutableDate
class provides a mutable variant of Date
.
A more descriptive documentation can be found at book.cakephp.org/chronos/2/en/.
API Documentation
API documentation can be found on api.cakephp.org/chronos.
Author: Cakephp
Source Code: https://github.com/cakephp/chronos
License: MIT license
1656250740
Simply add the nv.d3
assets to your project and include them in your HTML.
<link href="nv.d3.min.css" rel="stylesheet">
<script src="nv.d3.min.js"></script>
nv.d3.js
should appear after d3.js
is included..min
) for production.NVD3 is recommended to go with d3.js version 3.5.3 and later, but NOT d3 4.x yet. version 3.5.17 is the most recent d3 v3 release.
Minimum D3 version required: 3.4.4
For a D3v4 Version, see the work in progress at the nvd3 organization
Along with pieChart
options padAngle
and cornerRadius
, the interactive guideline tooltip now requires these later versions of D3 (3.4.4+, specifically, to get interactive tooltips). The interactive guide lines rely on the more recent d3.bisector()
method which treats accessors taking two parameters (the second being the element index) as comparators (see d3.bisector()).
NVD3 runs best on WebKit based browsers.
No, we do not... we are very interested in taking this on but could use some help. Please let us know if you'd like to help make this a reality! :)
1.8.6 Changes:
1.8.5 Changes:
1.8.4 Changes:
1.8.3 Changes:
1.8.2 Changes:
1.8.1 Changes:
1.7.1 Changes:
1.7.0 Changes:
1.6.0 Changes:
Current development focus
Bugs
Found a bug? Check out the latest from the master
branch and make sure it's not already fixed first! If you don't see a related fix, please open an issue.
Optional dependencies
Including Fastdom in your project can greatly increase the performance of the line chart (particularly in Firefox and Internet Explorer) by batching DOM read and write operations to avoid layout thrashing. NVD3 will take advantage of Fastdom if present.
Contributing
If one of the existing models doesn't meet your needs, fork the project, implement the model and an example using it, send us a pull request, for consideration for inclusion in the project.
If you'd like to contribute consistently, show me what you've got with some good pull requests and you may get added to the nvd3-community org!
master
branchbuild
directory, it clutters up the commit and just gets overwritten later.If you want to test your changes using the example pages, you'll have to run grunt production
to build the items into the build
directory. You must do this before your changes show up in the examples, as they link to the build directory in order to properly show off the finished product. Please remember to NOT include the build files in your commit though, only include the source files you changed!
bower install
to get bower dependencies.grunt
to start the unit tests.tinytest
and Spacejamspacejam
can be installed by running npm install -g spacejam
.spacejam test-packages ./
from this project's root.master
branchnodejs
is installed via your system's package manager.grunt
, grunt-cli
, and bower
: npm install -g grunt grunt-cli bower
have node download nvd3's required modules with:
npm install
build with:
grunt production
You should now have a build
directory with the js and css files within.
Inspired by the work of Mike Bostock's Towards Reusable Charts, and supported by a combined effort of Novus and the NVD3 community.
View Examples | NEW Documentation! | Development build status:
Author: novus
Source Code: https://github.com/novus/nvd3
License: View license
1655886240
dynamicform
create your form with easier way
Add the following to your pubspec.yaml
file:
dependencies:
dynamic_form: ^0.23.0
SimpleDynamicForm
: SimpleDynamicForm(
controller: controller,
groupElements: [
GroupElement(
directionGroup: DirectionGroup.Vertical,
textElements: [
TextElement(
id:"name",
label: "name",
),
TextElement(
id:"password",
label: "password",
typeInput: TypeInput.Password,
)
],
)
],
);
Properties in SimpleDynamicForm
Properties | Description |
---|---|
groupElements | list of element to build your form |
padding | The amount of space by which to inset the form |
controller | The FormController to get values and validate your form |
submitButton | (Widget) custom submit Widget that you want to add to the form |
FormController controller = FormController();
you can access to controller from your submit button
FormController controller = SimpleDynamicForm.of(context);
controller.validate();
controller.addErrorToField(String idField,String errorMessage);
controller.getAllValues();
if you are used ids in element, you can recuperate values with their ids
Map values = controller.getByIds();
you recuperate by id
controller.getValueById(id);
you can change field value using id of that field
controller.setFieldValueById(id,value);
controller.clearValues();
pre-existing login form to make easy for you to build
LoginForm
:
LoginForm(
controller:controller
submitLogin:RaisedButton(
onPressed: () {
final email = controller.email;
final password = controller.password;
print("$email,$password");
},
child: Text("Log In"),
),
onlyEmail: false,
textButton: Text("Log IN"),
paddingFields: const EdgeInsets.all(0),
decorationLoginForm: DecorationLoginForm(
commonDecoration: decoration,
decorationEmailElement: OutlineDecorationElement(
contentPadding: EdgeInsets.only(
left: 12.0,
),
),
decorationPasswordElement: OutlinePasswordElementDecoration(
contentPadding: EdgeInsets.only(left: 8),
prefix: Padding(
padding: EdgeInsets.all(6.0),
child: Icon(
Icons.lock,
size: 20,
),
),
enableVisibilityPassword: false
),
)
LoginFormController controller = LoginFormController();
final email = controller.email;
final password = controller.password;
LoginFormController controller = LoginForm.of(context)
controller.addEmailError("invalid Email not found");
controller.addPasswordError("invalid Email not found");
Properties | Description |
---|---|
controller | LoginFormController to validate login form and get data |
decorationLoginForm | (DecorationLoginForm) contain configuration of the inputs decoration of email/password fields in form |
directionGroup | Direction of form (Vertical/Horizontal) |
paddingFields | padding between fields |
onlyEmail | enable only email type textField |
passwordError | messages errors to show when password field not validate |
usernameEmailError | messages errors to show when email/username not validate |
submitLogin | (Widget) Button of submit form |
PaymentForm
: PaymentForm(
controller:controller,
decorationElement: OutlineDecorationElement(),
errorMessageCVV: "cvv is invalid",
errorMessageDateExpiration: "date expiration is invalid",
errorIsRequiredMessage: "This field is required",
labelCVV: "cvv",
labelDateExpiration: "date expiration",
labelCardNumber: "card number",
submitButton: ElevatedButton(
onPressed: () {
controller.validate();
},
child: Text("pay"),
),
)
PaymentController controller = PaymentController();
bool isValid = controller.validate();
final cardNumber = controller.cardNumber;
final cvv = controller.cvv;
final dateExpiration = controller.dateExpiration;
PaymentController controller = PaymentForm.of(context);
controller.addCardNumberError(errorMessage);
controller.addCVVError(errorMessage);
controller.addDateExpirationError(errorMessage);
Properties | Description |
---|---|
controller | (PaymentController) controller to validate form,setError fields,clear values |
entryModeDateExpiration | (DateExpirationEntryMode) input type of card date expiration can be dropdown or input(textField) |
decorationElement | decoration of all input field in form |
buttonDecoration | decoration of button that contain radius,backgroundColor,width |
errorMessageDateExpiration | messages errors to show when Date Expiration field not validate |
errorMessageCVV | messages errors to show when cvv field is invalidate |
errorMessageCardNumber | messages errors to show when credit card number is invalidate |
errorIsRequiredMessage | messages errors to show when at least one field not filled |
labelCardNumber | text label of credit card number field |
labelDateExpiration | text label of date expiration field |
labelCVV | text label of cvv field |
submitButton | (widget) submit button widget |
textElement is small element in dynamicForm
GroupElement is group of TextElement
GroupElement
Properties | Description |
---|---|
directionGroup | Direction of form (Vertical/Horizontal) |
sizeElements | size of each textElement of form When direction Horizontal,sum of values should be egal a 1 |
textElements | group of textElement. |
padding | padding of groups. |
decoration | decoration of container groups. |
backgroundColor | color of the container groups. |
textElement
Properties | Description |
---|---|
typeInput | Enumerate to specifie type of TextField. |
label | text label of TextField. |
DecorationElement | input decoration of TextField. |
onTap | callback when you click on TextField . |
hint | text hint of textField. |
errorMsg | message to show when TextField isn't validate. |
labelStyle | style of label TextField |
errorStyle | style of error message TextField |
hintStyle | style of hint TextFieldcolor |
readOnly | enable TextField uneditable |
validator | callback validation of TextField |
padding | padding of TextField |
visibility | enable visibility of element |
EmailElement
Pre-exsiting element
check validation of email
Pre-initialized values
extends from TextElement
Properties | Description |
---|---|
DecorationElement | input decoration of TextField. |
label | text label of TextField. |
hint | text hint of textField. |
isRequired | make textField required in validation |
errorEmailIsRequired | error message for textField when it's required |
errorEmailPattern | error message for textField input when it's not email in validation |
labelStyle | style of label TextField |
errorStyle | style of error message TextField |
hintStyle | style of hint TextFieldcolor |
readOnly | enable TextField uneditable |
padding | padding of TextField |
PasswordElement
Pre-exsiting element
check validation of password
Pre-initialized values
show/hide password
extends from TextElement
Properties | Description |
---|---|
DecorationElement | input decoration of TextField. |
label | text label of TextField. |
hint | text hint of textField. |
errorMsg | message to show when TextField isn't validate. |
labelStyle | style of label TextField |
errorStyle | style of error message TextField |
hintStyle | style of hint TextFieldcolor |
readOnly | enable TextField uneditable |
padding | padding of TextField |
enableShowPassword | enable eye icon,make password text visible |
isRequired | make passwordField required |
minLength | minimun length accepted by password |
hasUppercase | make password contains at least one upperCase character |
hasSpecialCharacter | make password contains at least one special character |
hasDigits | make password contains at least one digits |
requiredErrorMsg | message error to show when password is required |
minLengthErrorMsg | message error to show when password length is less then the specified |
uppercaseErrorMsg | message error to show when password doesn't contain any upperCase character |
specialCharacterErrorMsg | message error to show when password doesn't contain any special character |
NumberElement
Pre-exsiting element for Number input
Pre-initialized values
enabled digitsOnly
extends from TextElement
Properties | Description |
---|---|
label | text label of TextField. |
hint | text hint of textField. |
DecorationElement | input decoration of TextField. |
errorMsg | message to show when TextField isn't validate. |
labelStyle | style of label TextField |
errorStyle | style of error message TextField |
hintStyle | style of hint TextFieldcolor |
readOnly | enable TextField uneditable |
padding | padding of TextField |
isDigits | enable only digit number |
CountryElement
Pre-exsiting element for Country input
Pre-initialized values
pick country via BottomSheet
show flag of countries
Properties | Description |
---|---|
DecorationElement | input decoration of TextField. |
label | text label of TextField. |
initValue | Initiale Value to country input. |
labelModalSheet | Title of modalSheet |
labelSearchModalSheet | hint search textfield in BottomSheet |
countryTextResult | enumeration get result of selection countries |
showFlag | show flag of countris in modalsheet |
padding | padding of TextField |
readonly | when enable TextField to be unmodified |
PhoneNumberElement
Pre-exsiting element for phone number input
Pre-initialized values
To Do
in PhoneNumberElement
[ ] pick calling phone via BottomSheet
[ ] show flag of countries for each calling code
Properties
Properties | Description |
---|---|
DecorationElement | input decoration of TextField. |
label | text label of TextField. |
hint | text placeholder for phone number input. |
initValue | initial Value to phone input. |
errorMsg | text error message |
validator | callback validation of TextField |
showPrefixFlag | enable flag country to be visible at left of TextField |
showSuffixFlag | enable flag country to be visible at rigth of TextField |
padding | padding of TextField |
showPrefix | show calling phone number(get current calling phone of user) |
readOnly | bool make TextField readOnly |
initPrefix | (String) initial calling code of the specific country |
labelModalSheet | (String) title of bottom sheet that shown list of calling code of countries |
TextAreaElement
Pre-exsiting element for multiLine input (like commentField) Pre-initialized values
Properties | Description |
---|---|
maxLines | maximum line to span in textField. |
showCounter | enable visibility of counterText. |
maxCharacter | The limit on the number of characters that you can type in textField |
DateElement
Pre-exsiting element for date field input Pre-initialized values
Properties | Description |
---|---|
id | String,should be unique, |
initDate | (DateTime) initialize the input field |
firstDate] | (DateTime) represent earliest allowable Date in date picker |
lastDate | (DateTime) represent latest allowable Date in date picker |
format | (DateFormat) for format the date that you pick (default :DateFormat.yMd()) |
selectableDayPredicate | (SelectableDayPredicate) to enable dates to be selected |
label | (String) text label of TextField |
decorationElement | input decoration of TextField |
hint | (String) hint text of textField |
isRequired | (bool) if true,make this field required |
errorMsg | (String) show error message when the field isn't validate |
padding | (EdgeInsets) padding of textField |
RadioGroupElement
Pre-exsiting element for radioGroup field input Pre-initialized values
Properties | Description |
---|---|
id | String,should be unique, |
initValue | (String) initialized select value of the radio group field |
label | (String) text label of the radio group field |
labelAlignment | (AlignmentGeometry) label text alignment |
activeSelectedColor | (Color) active select radio in the radio group field |
decorationElement | input decoration of TextField |
errorMsg | (String) error message that will show when error |
values | (List |
valuesLabel | (List |
padding | (EdgeInsets) padding of textField |
DecorationElement
abstract class
Pre-exsiting inputDecoration for TextFormField
Pre-initialized values
Typically one of
UnderlineDecorationElement
orOutlineDecorationElement
orRoundedDecorationElement
can be used.
UnderlineDecorationElement
Properties | Description |
---|---|
borderColor | The border Color to display when the InputDecorator does not have the focus. |
errorBorderColor | The borwidthLineder Color to display when the InputDecorator does have the error. |
focusBorderColor | The border Color to display when the InputDecorator does have the focus. |
disabledBorderColor | The border Color to display when the InputDecorator is disabled. |
radius | radius of the border. |
widthSide | The width of this line of the border |
filledColor | base fill color of the decoration |
focusColor | focused fill color of the decoration |
OutlineDecorationElement
Properties | Description |
---|---|
borderColor | The border Color to display when the InputDecorator does not have the focus. |
errorBorderColor | The borwidthLineder Color to display when the InputDecorator does have the error. |
focusBorderColor | The border Color to display when the InputDecorator does have the focus. |
disabledBorderColor | The border Color to display when the InputDecorator is disabled. |
radius | radius of the border. |
widthSide | The width of this line of the border |
filledColor | base fill color of the decoration |
focusColor | focused fill color of the decoration |
RoundedDecorationElement
without BorderSide
Properties | Description |
---|---|
radius | radius of the border. |
filledColor | base fill color of the decoration |
focusColor | focused fill color of the decoration |
ButtonLoginDecorationElement
decoration for button login
Properties | Description |
---|---|
shapeButtonLogin | shape of the login button. |
backgroundColorButton | ackground color of the login button |
widthSubmitButton | width size of the login button |
elevation | elevation of the button |
///decoration Element
final decoration = OutlineDecorationElement(
filledColor: Colors.white,
radius: BorderRadius.only(
topLeft: Radius.circular(5.0),
topRight: Radius.circular(5.0),
),
widthSide: 0.6,
);
PasswordControls
define an validation rules for password input
Properties | Description |
---|---|
minLength | minimum length accepted by password |
hasUppercase | make password contains at least one upperCase character |
hasSpecialCharacter | make password contains at least one special character |
hasDigits | make password contains at least one digits |
Run this command:
With Flutter:
$ flutter pub add dynamic_form
This will add a line like this to your package's pubspec.yaml (and run an implicit flutter pub get
):
dependencies:
dynamic_form: ^0.23.0
Alternatively, your editor might support flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:dynamic_form/dynamic_form.dart';
example/lib/main.dart
import 'package:dynamic_form/dynamic_form.dart';
import 'package:flutter/material.dart';
import 'package:formdynamic/login_page.dart';
import 'payment_example.dart';
void main() => runApp(MyApp());
class MyApp extends StatefulWidget {
@override
State<StatefulWidget> createState() => _MyAppState();
// This widget is the root of your application.
}
class _MyAppState extends State<MyApp> with TickerProviderStateMixin {
TabController tabController;
@override
void initState() {
super.initState();
tabController = TabController(
length: 3,
initialIndex: 1,
vsync: this,
);
}
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Dynamic Form Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
backgroundColor: Colors.grey[300],
),
home: Scaffold(
appBar: AppBar(
title: Text("Demo"),
bottom: TabBar(
controller: tabController,
tabs: <Widget>[
GestureDetector(
onTap: () {
tabController.index = 0;
},
child: Text("Basic Example"),
),
GestureDetector(
onTap: () {
tabController.index = 1;
},
child: Text("Login form "),
),
GestureDetector(
onTap: () {
tabController.index = 2;
},
child: Text("payment form "),
),
],
),
actions: [],
),
body: TabBarView(
controller: tabController,
children: <Widget>[
MyHomePage(),
LoginPage(),
PaymentExample(),
],
),
),
);
}
}
class MyHomePage extends StatelessWidget {
// controller.clearValues()
@override
Widget build(BuildContext context) {
final controller = FormController();
return Stack(
children: [
SingleChildScrollView(
child: Column(
children: <Widget>[
SimpleDynamicForm(
controller: controller,
groupElements: [
GroupElement(
margin: EdgeInsets.only(bottom: 5.0),
directionGroup: DirectionGroup.Horizontal,
sizeElements: [0.3],
textElements: [
TextElement(
initValue: "",
label: "first name",
hint: "first name",
validator: (v) {
if (v.isEmpty) {
return "err";
}
return null;
}),
TextElement(
label: "last name",
isRequired: true,
initValue: "your name",
validator: (v) {
if (v != "your name") {
return "name not accepted";
}
return null;
}),
],
),
GroupElement(
directionGroup: DirectionGroup.Vertical,
textElements: [
SelectChoiceElement(
values: ["Male","Female"],
initValue: "Male",
label: "Gender",
id: "gender",
decorationElement: OutlineDecorationElement()
),
RadioGroupElement(
id: "mode",
label: "Mode",
values: ["dark","light"],
valuesLabel: ["Dark Mode","Light Mode"],
initValue: "dark",
activeSelectedColor: Colors.red,
onSelected: (v){
print(v);
}
),
PhoneNumberElement(
//label: "",
hint: "Phone Number",
errorMsg: "invalid phone number",
initValue: "1234567",
showPrefix: true,
showPrefixFlag: true,
readOnly: false,
visibility: false,
decorationElement: OutlineDecorationElement(
borderColor: Colors.grey,
),
),
DateElement(
id: "date",
hint: "date",
label: "date",
isRequired: true,
errorMsg: "this field is required",
),
TextElement(
label: "last name",
isRequired: true,
initValue: "your name",
error: "this field is required",
validator: (v) {
if (v != "your name") {
return "name not accepted";
}
return null;
},
),
],
),
GroupElement(
directionGroup: DirectionGroup.Vertical,
commonDecorationElements: OutlineDecorationElement(
contentPadding: EdgeInsets.only(left: 5, right: 3),
radius: BorderRadius.circular(4),
),
padding: EdgeInsets.symmetric(vertical: 6, horizontal: 8),
textElements: [
CountryElement(
id: "countries",
label: "Pays",
labelModalSheet: "Pays",
labelSearchModalSheet: "search",
// decorationElement: OutlineDecorationElement(
// radius: BorderRadius.circular(4),
// ),
initValue: "",
countryTextResult: CountryTextResult.countryCode,
showFlag: true,
),
PhoneNumberElement(
label: "Phone",
showPrefix: true,
showSuffixFlag: true,
showPrefixFlag: false,
hint: "Phone",
initPrefix: "+216",
),
TextAreaElement(
maxCharacter: 300,
maxLines: 4,
showCounter: false,
),
],
),
],
submitButton: SubmitForm(),
),
],
),
),
Positioned(
bottom: 16,
right: 8,
child: FloatingActionButton(
heroTag: "clearForm",
child: Icon(Icons.delete),
onPressed: () => controller.clearValues(),
),
),
],
);
}
}
class SubmitForm extends StatelessWidget {
@override
Widget build(BuildContext context) {
final controller = SimpleDynamicForm.of(context);
return ElevatedButton(
onPressed: () {
print(controller.validate());
print(controller.getAllValues());
print(controller.getAllValuesByIds());
print(controller.getValueById("countries"));
},
child: Text("Validate"),
);
}
}
Author: liodali
Source Code: https://github.com/liodali/DynamicFormFlutter
License: MIT license
1655655360
uiprogress
A Go library to render progress bars in terminal applications. It provides a set of flexible features with a customizable API.
Progress bars improve readability for terminal applications with long outputs by providing a concise feedback loop.
To start listening for progress bars, call uiprogress.Start()
and add a progress bar using uiprogress.AddBar(total int)
. Update the progress using bar.Incr()
or bar.Set(n int)
. Full source code for the below example is available at example/simple/simple.go
uiprogress.Start() // start rendering
bar := uiprogress.AddBar(100) // Add a new bar
// optionally, append and prepend completion and elapsed time
bar.AppendCompleted()
bar.PrependElapsed()
for bar.Incr() {
time.Sleep(time.Millisecond * 20)
}
This will render the below in the terminal
You can also add a custom decorator function in addition to default bar.AppendCompleted()
and bar.PrependElapsed()
decorators. The below example tracks the current step for an application deploy progress. Source code for the below example is available at example/full/full.go
var steps = []string{"downloading source", "installing deps", "compiling", "packaging", "seeding database", "deploying", "staring servers"}
bar := uiprogress.AddBar(len(steps))
// prepend the current step to the bar
bar.PrependFunc(func(b *uiprogress.Bar) string {
return "app: " + steps[b.Current()-1]
})
for bar.Incr() {
time.Sleep(time.Millisecond * 10)
}
You can add multiple bars using uiprogress.AddBar(n)
. The below example demonstrates updating multiple bars concurrently and adding a new bar later in the pipeline. Source for this example is available at example/multi/multi.go
waitTime := time.Millisecond * 100
uiprogress.Start()
// start the progress bars in go routines
var wg sync.WaitGroup
bar1 := uiprogress.AddBar(20).AppendCompleted().PrependElapsed()
wg.Add(1)
go func() {
defer wg.Done()
for bar1.Incr() {
time.Sleep(waitTime)
}
}()
bar2 := uiprogress.AddBar(40).AppendCompleted().PrependElapsed()
wg.Add(1)
go func() {
defer wg.Done()
for bar2.Incr() {
time.Sleep(waitTime)
}
}()
time.Sleep(time.Second)
bar3 := uiprogress.AddBar(20).PrependElapsed().AppendCompleted()
wg.Add(1)
go func() {
defer wg.Done()
for i := 1; i <= bar3.Total; i++ {
bar3.Set(i)
time.Sleep(waitTime)
}
}()
// wait for all the go routines to finish
wg.Wait()
This will produce
Incr
counterBar.Incr() is an atomic counter and can be used as a general tracker, making it ideal for tracking progress of work fanned out to a lots of go routines. The source code for the below example is available at example/incr/incr.go
runtime.GOMAXPROCS(runtime.NumCPU()) // use all available cpu cores
// create a new bar and prepend the task progress to the bar and fanout into 1k go routines
count := 1000
bar := uiprogress.AddBar(count).AppendCompleted().PrependElapsed()
bar.PrependFunc(func(b *uiprogress.Bar) string {
return fmt.Sprintf("Task (%d/%d)", b.Current(), count)
})
uiprogress.Start()
var wg sync.WaitGroup
// fanout into go routines
for i := 0; i < count; i++ {
wg.Add(1)
go func() {
defer wg.Done()
time.Sleep(time.Millisecond * time.Duration(rand.Intn(500)))
bar.Incr()
}()
}
time.Sleep(time.Second) // wait for a second for all the go routines to finish
wg.Wait()
uiprogress.Stop()
$ go get -v github.com/gosuri/uiprogress
Author: Gosuri
Source Code: https://github.com/gosuri/uiprogress
License: MIT license
1655640180
progressbar
A very simple thread-safe progress bar which should work on every OS without problems. I needed a progressbar for croc and everything I tried had problems, so I made another one. In order to be OS agnostic I do not plan to support multi-line outputs.
go get -u github.com/schollz/progressbar/v3
bar := progressbar.Default(100)
for i := 0; i < 100; i++ {
bar.Add(1)
time.Sleep(40 * time.Millisecond)
}
which looks like:
The progressbar
implements an io.Writer
so it can automatically detect the number of bytes written to a stream, so you can use it as a progressbar for an io.Reader
.
req, _ := http.NewRequest("GET", "https://dl.google.com/go/go1.14.2.src.tar.gz", nil)
resp, _ := http.DefaultClient.Do(req)
defer resp.Body.Close()
f, _ := os.OpenFile("go1.14.2.src.tar.gz", os.O_CREATE|os.O_WRONLY, 0644)
defer f.Close()
bar := progressbar.DefaultBytes(
resp.ContentLength,
"downloading",
)
io.Copy(io.MultiWriter(f, bar), resp.Body)
which looks like:
A progressbar with unknown length is a spinner. Any bar with -1 length will automatically convert it to a spinner with a customizable spinner type. For example, the above code can be run and set the resp.ContentLength
to -1
.
which looks like:
There is a lot of customization that you can do - change the writer, the color, the width, description, theme, etc. See all the options.
bar := progressbar.NewOptions(1000,
progressbar.OptionSetWriter(ansi.NewAnsiStdout()),
progressbar.OptionEnableColorCodes(true),
progressbar.OptionShowBytes(true),
progressbar.OptionSetWidth(15),
progressbar.OptionSetDescription("[cyan][1/3][reset] Writing moshable file..."),
progressbar.OptionSetTheme(progressbar.Theme{
Saucer: "[green]=[reset]",
SaucerHead: "[green]>[reset]",
SaucerPadding: " ",
BarStart: "[",
BarEnd: "]",
}))
for i := 0; i < 1000; i++ {
bar.Add(1)
time.Sleep(5 * time.Millisecond)
}
which looks like:
Pull requests are welcome. Feel free to...
Thanks @Dynom for massive improvements in version 2.0!
Thanks @CrushedPixel for adding descriptions and color code support!
Thanks @MrMe42 for adding some minor features!
Thanks @tehstun for some great PRs!
Thanks @Benzammour and @haseth for helping create v3!
Thanks @briandowns for compiling the list of spinners.
Author: Schollz
Source Code: https://github.com/schollz/progressbar
License: MIT license
1655592960
Echotron is a concurrent library for telegram bots written in pure Go.
Fetch with
go get github.com/NicoNex/echotron/v3
Echotron is heavily based on concurrency: for example, every call to the Update
method of each bot is executed on a different goroutine. This makes sure that, even if one instance of the bot is deadlocked, the other ones keep running just fine, making the bot work for other users without any issues and/or slowdowns.
Echotron is designed to be as similar to the official Telegram API as possible, but there are some things to take into account before starting to work with this library.
sendMessage
becomes SendMessage
chat_id
(or, in this case, chatID
) type supported is int64
, instead of the "Integer or String" requirement of the official API. That's because numeric IDs can't change in any way, which isn't the case with text-based usernames.InputFile
type parameter. InputFile
is a struct with unexported fields, since only three combination of fields are valid, which can be obtained through the methods NewInputFileID
, NewInputFilePath
and NewInputFileBytes
.MessageIDOptions
type parameter. MessageIDOptions
is another struct with unexported fields, since only two combination of field are valid, which can be obtained through the methods NewMessageID
and NewInlineMessageID
.nil
is more than enough. Refer to the docs to check for each method's optional parameters struct: it's the type of the opts
parameter.ParseMode
, ChatAction
and InlineQueryType
. For a full list of custom hardcoded parameters, refer to the docs for each custom type: by clicking on the type's name, you'll get the source which contains the possible values for that type.A very simple implementation:
package main
import (
"log"
"github.com/NicoNex/echotron/v3"
)
// Struct useful for managing internal states in your bot, but it could be of
// any type such as `type bot int64` if you only need to store the chatID.
type bot struct {
chatID int64
echotron.API
}
const token = "YOUR TELEGRAM TOKEN"
// This function needs to be of type 'echotron.NewBotFn' and is called by
// the echotron dispatcher upon any new message from a chatID that has never
// interacted with the bot before.
// This means that echotron keeps one instance of the echotron.Bot implementation
// for each chat where the bot is used.
func newBot(chatID int64) echotron.Bot {
return &bot{
chatID,
echotron.NewAPI(token),
}
}
// This method is needed to implement the echotron.Bot interface.
func (b *bot) Update(update *echotron.Update) {
if update.Message.Text == "/start" {
b.SendMessage("Hello world", b.chatID, nil)
}
}
func main() {
// This is the entry point of echotron library.
dsp := echotron.NewDispatcher(token, newBot)
log.Println(dsp.Poll())
}
Functional example with bot internal states:
package main
import (
"log"
"strings"
"github.com/NicoNex/echotron/v3"
)
// Recursive type definition of the bot state function.
type stateFn func(*echotron.Update) stateFn
type bot struct {
chatID int64
state stateFn
name string
echotron.API
}
const token = "YOUR TELEGRAM TOKEN"
func newBot(chatID int64) echotron.Bot {
bot := &bot{
chatID: chatID,
API: echotron.NewAPI(token),
}
// We set the default state to the bot.handleMessage method.
bot.state = bot.handleMessage
return bot
}
func (b *bot) Update(update *echotron.Update) {
// Here we execute the current state and set the next one.
b.state = b.state(update)
}
func (b *bot) handleMessage(update *echotron.Update) stateFn {
if strings.HasPrefix(update.Message.Text, "/set_name") {
b.SendMessage("Send me my new name!", b.chatID, nil)
// Here we return b.handleName since next time we receive a message it
// will be the new name.
return b.handleName
}
return b.handleMessage
}
func (b *bot) handleName(update *echotron.Update) stateFn {
b.name = update.Message.Text
b.SendMessage(fmt.Sprintf("My new name is %q", b.name), b.chatID, nil)
// Here we return b.handleMessage since the next time we receive a message
// it will be handled in the default way.
return b.handleMessage
}
func main() {
dsp := echotron.NewDispatcher(token, newBot)
log.Println(dsp.Poll())
}
Example with self destruction for lower RAM usage:
package main
import (
"log"
"time"
"github.com/NicoNex/echotron/v3"
)
type bot struct {
chatID int64
echotron.API
}
const token = "YOUR TELEGRAM TOKEN"
var dsp echotron.Dispatcher
func newBot(chatID int64) echotron.Bot {
bot := &bot{
chatID,
echotron.NewAPI(token),
}
go bot.selfDestruct(time.After(time.Hour))
return bot
}
func (b *bot) selfDestruct(timech <- chan time.Time) {
<-timech
b.SendMessage("goodbye", b.chatID, nil)
dsp.DelSession(b.chatID)
}
func (b *bot) Update(update *echotron.Update) {
if update.Message.Text == "/start" {
b.SendMessage("Hello world", b.chatId, nil)
}
}
func main() {
dsp = echotron.NewDispatcher(token, newBot)
log.Println(dsp.Poll())
}
package main
import "github.com/NicoNex/echotron/v3"
type bot struct {
chatID int64
echotron.API
}
const token = "YOUR TELEGRAM TOKEN"
func newBot(chatID int64) echotron.Bot {
return &bot{
chatID,
echotron.NewAPI(token),
}
}
func (b *bot) Update(update *echotron.Update) {
if update.Message.Text == "/start" {
b.SendMessage("Hello world", b.chatID, nil)
}
}
func main() {
dsp := echotron.NewDispatcher(token, newBot)
dsp.ListenWebhook("https://example.com:443/my_bot_token")
}
This is an example for a custom http.Server which handles your own specified routes and also the webhook route which is specified by ListenWebhook.
package main
import (
"github.com/NicoNex/echotron/v3"
"context"
"log"
"net/http"
)
type bot struct {
chatID int64
echotron.API
}
const token = "YOUR TELEGRAM TOKEN"
func newBot(chatID int64) echotron.Bot {
return &bot{
chatID,
echotron.NewAPI(token),
}
}
func (b *bot) Update(update *echotron.Update) {
if update.Message.Text == "/start" {
b.SendMessage("Hello world", b.chatID, nil)
}
}
func main() {
termChan := make(chan os.Signal, 1) // Channel for terminating the app via os.Interrupt signal
signal.Notify(termChan, syscall.SIGINT, syscall.SIGTERM)
mux := http.NewServeMux()
mux.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
// Handle user login
})
mux.HandleFunc("/logout", func(w http.ResponseWriter, r *http.Request) {
// Handle user logout
})
mux.HandleFunc("/about", func(w http.ResponseWriter, r *http.Request) {
// Tell something about your awesome telegram bot
})
// Set custom http.Server
server := &http.Server{Addr: ":8080", Handler: mux}
go func() {
<-termChan
// Perform some cleanup..
if err := server.Shutdown(context.Background()); err != nil {
log.Print(err)
}
}()
// Capture the interrupt signal for app termination handling
dsp := echotron.NewDispatcher(token, newBot)
dsp.SetHTTPServer(server)
// Start your custom http.Server with a registered /my_bot_token handler.
log.Println(dsp.ListenWebhook("https://example.com/my_bot_token"))
}
Author: NicoNex
Source Code: https://github.com/NicoNex/echotron
License: LGPL-3.0 license
1654932420
Plate.js -- A Template Library
Plate is a Django Template Language implementation in Javascript. Super exciting!
var plate = require('plate')
var template = new plate.Template('hello {{ world }}')
template.render({world:'everyone'}, function(err, data) {
console.log(data)
})
// outputs "hello everyone"
Plate follows the Node.js style of taking callbacks that receive an error object and a data object. If there's no error, err
will be null.
<script type="text/javascript" src="plate.min.js">
<script type="text/html" id="template">
hello {{ world }}.
</script>
<script type="text/javascript">
var source = $('#template').text()
, template = new plate.Template(source)
template.render({world: 'everyone'}, function(err, data) {
console.log(data)
})
</script>
require(['plate.min'], function(plate) {
var template = new plate.Template('hello {{ world }}')
})
Plate is documented on its github wiki. There are "Getting Started" guides for both in-browser as well as in-node environments.
Got a feature you'd like to add? I'd love to see it. The workflow is pretty standard Github fare:
The minimum requirements for a pull request to be merged are:
docs/
folder in Markdown format.In node:
$ npm install plate
$ npm test plate
Yes. Plate was designed to work well in the standard suite of browsers. Each minor point release will target compatibility with IE7+, FF3+, Chrome, and Safari 4+.
You can download a minified, precompiled version here.
If you're having trouble, try using the debug version, with source maps.
Author: Chrisdickinson
Source Code: https://github.com/chrisdickinson/plate
License: MIT
1654893480
Hoy vamos a repasar 9 bibliotecas de animación gratuitas y bien codificadas que se adaptan mejor al trabajo de diseño de interfaz de usuario, cubriendo sus fortalezas y debilidades, y cuándo elegir cada una.
El diseño web front-end ha experimentado una revolución en la última década. A finales de los 2000, la mayoría de nosotros todavía estábamos diseñando diseños estáticos para revistas. Hoy en día, estamos construyendo “máquinas digitales” con miles de partes móviles, coordinadas y redimensionadas.
En pocas palabras, los grandes diseñadores de UI también deben ser grandes animadores , con una sólida comprensión de las técnicas y la tecnología de animación web.
Tenga en cuenta que estamos analizando cada biblioteca desde la perspectiva de un diseñador de interfaz de usuario experto en código, no como un desarrollador "gurú del código". Algunas de estas bibliotecas son CSS puro. Otros son JavaScript, pero ninguno requiere nada más que conocimientos básicos de HTML/CSS y/o JavaScript para ser útil.
Seamos claros: Lottiejs es un tipo de biblioteca de animación muy diferente a los otros ocho en esta lista. Sin embargo, no creemos que los diseñadores de UI/UX puedan darse el lujo de ignorarlo.
Crear una animación de Lottie es más parecido a crear una producción de video. Necesitará una herramienta de animación de terceros que pueda exportar un archivo JSON 'listo para Lottie'. De hecho, el formato Lottie fue diseñado específicamente para hacer que las animaciones de Adobe After Effects funcionen de manera eficiente en la web y en dispositivos móviles. Esto hace que las animaciones de Lottie sean rápidas, eficientes, fáciles de escribir y, a menudo, bastante hermosas.
Aunque Lottie se concibió como una extensión de Adobe After Effects , hay muchas (posiblemente mejores) alternativas 'nativas de Lottie' para crear animaciones de Lottie. Éstos incluyen:
Lottie usa 'reproductores de animación' separados optimizados para Web, iOS y Android respectivamente. El código base de Lottie es desarrollado y mantenido por AirBnb y cuenta con una comunidad súper entusiasta y apasionada que crece detrás de él.
Animate.css es una de las bibliotecas de animación CSS más pequeñas y fáciles de usar. Es refinado, eficiente y bien mantenido desde su lanzamiento en 2013.
Aplicar la biblioteca de Animate a su proyecto es tan simple como vincular el CSS y agregar las clases de CSS requeridas a sus elementos HTML. Por supuesto, también puede usar jQuery o Vanilla JS para activar las animaciones en un evento en particular si lo prefiere.
En el momento de escribir este artículo, sigue siendo una de las bibliotecas de animación CSS más populares y ampliamente utilizadas y su archivo minificado es lo suficientemente pequeño como para incluirlo también en sitios web móviles.
Animate.css todavía está en desarrollo activo. Tenga cuidado con la versión 4, que admitirá propiedades personalizadas de CSS (también conocidas como variables de CSS). Esta es una de las bibliotecas de animación más simples y robustas y no dudaríamos en usarla en cualquier proyecto.
GreenSock (o GSAP - GreenSock Animation Platform) es la navaja suiza de la animación web. Para animaciones elegantes y sofisticadas que funcionan sin problemas, GSAP es ideal. Puede animar cualquier cosa, desde elementos DOM hasta SVG, y su ecosistema incluye algunos complementos increíbles que le permiten hacer todo tipo de cosas divertidas, por ejemplo, transformar SVG, dibujar trazos SVG, funcionalidad de desplazamiento, codificar texto y mucho más. Es rápido, compatible con varios navegadores y su sintaxis es sencilla e intuitiva.
GSAP es modular, por lo tanto, puede elegir qué partes de la biblioteca necesita para su proyecto, lo cual es excelente para mantener el tamaño del archivo bajo control.
Si está buscando algo poderoso pero intuitivo con una documentación increíble y soporte de la comunidad, definitivamente le recomendaría que pruebe esta biblioteca de animación en su próximo proyecto. Estarás entusiasmado.
AnimeJS es la última incorporación a nuestra lista, pero ha ganado muchos adeptos desde su creación. Es increíblemente versátil y potente, y no estaría fuera de lugar para potenciar las animaciones de juegos HTML. La única pregunta real es " ¿es excesivo para aplicaciones web simples?" ”
Quizás. Pero como también es rápido, pequeño y relativamente fácil de aprender, es difícil encontrar fallas en él.
AnimeJS se describe como una “ biblioteca de animación de JavaScript ligera con una API simple pero potente. Funciona con propiedades CSS, SVG, atributos DOM y Objetos JavaScript ”. Bastante impresionante.
Este proyecto está disponible en GitHub .
Lo más impresionante es que Anime.JS tiene una "documentación" impresionante que muestra HTML, código JavaScript y ejemplos de trabajo en un hermoso entorno de aplicación.
En resumen, si se siente cómodo con una solución de animación de JavaScript, es difícil encontrar razones para ignorar AnimeJS.
Magic Animations ha sido una de las bibliotecas de animación más impresionantes disponibles. Tiene muchas animaciones diferentes, muchas de las cuales son bastante exclusivas de esta biblioteca. Al igual que con Animate.css, puede implementar Magic simplemente importando el archivo CSS. También puede implementar las animaciones usando jQuery. Este proyecto ofrece una aplicación de demostración particularmente interesante.
El tamaño de archivo de Magic Animation es moderado en comparación con Animate.css y es conocido por sus animaciones exclusivas, como los efectos mágicos, los efectos tontos y los efectos de bomba.
Si estás buscando algo un poco fuera de lo común, hazlo. No te decepcionará.
Zdog es una biblioteca de JavaScript para crear diseños y animaciones en 3D de David DeSandro. Con su ayuda, puede dibujar sus diseños usando el <canvas>
elemento o SVG y darles vida en animaciones fluidas con un elegante efecto 3D.
Si está familiarizado con JavaScript, aprenderá los conceptos básicos de Zdog con bastante rapidez: tiene una API declarativa sencilla, excelentes documentos y muchos recursos de aprendizaje. Consulte mi introducción a Zdog en SitePoint.
CSShake ofrece exactamente lo que dice en la caja: una biblioteca de CSS diseñada específicamente para agitar elementos dentro de su página web. Como era de esperar, hay una serie de variaciones disponibles para agitar sus componentes web.
Apple popularizó el tropo de la interfaz de usuario de sacudir vigorosamente un elemento de la interfaz de usuario (un cuadro de diálogo, modal o de texto) cuando un usuario ingresa una respuesta incorrecta, imitando a una persona que sacude la cabeza. CSShake proporciona una variedad de interesantes animaciones de "sacudidas" y no faltan variaciones en esta biblioteca.
Hover.css es una biblioteca de animación CSS diseñada para usarse con botones y otros elementos de la interfaz de usuario en su sitio web. Tiene transiciones 2D realmente agradables, junto con una gran cantidad de otras animaciones bien diseñadas.
Hover.css es más adecuado para animar elementos de página discretos como botones, logotipos, componentes SVG o imágenes destacadas en lugar de animaciones de página más grandes y complejas. Podría decirse que sus efectos de animación más notables son sus burbujas de discurso y rizos distintivos.
Nuestra biblioteca final es interesante por su enfoque único. AniJS es una biblioteca de animación que le permite agregar animaciones a elementos en una estructura simple 'similar a una oración'. Toma el siguiente formato:
Si hace clic, On Square, Do wobble animado a .container-box
<div data-anijs="if: click, do: flipInY, to: .container-box"></div>
Si no está muy familiarizado con JavaScript, esta puede ser una excelente manera de ingresar a los movimientos coreografiados por JS.
AniJS es una biblioteca con un tamaño muy razonable teniendo en cuenta su funcionalidad. El formato que utiliza para la implementación es bastante original y diferente en comparación con otras bibliotecas de animación (que muchos otros pueden encontrar poco convencionales).
Sin embargo, vale la pena probar esta biblioteca, al menos una vez para sus proyectos.
Hay muchas bibliotecas de animación listas y esperando para ser implementadas en su proyecto. Los enumerados anteriormente son algunos con la mejor combinación de sofisticación y estabilidad.
Si está buscando una solución CSS bien probada y fácil de implementar, Animate.css es probablemente la opción disponible más versátil y rentable.
Si está buscando una base de JavaScript más completa y potente para impulsar juegos, simuladores, modelos y otras aplicaciones sofisticadas en línea, GreenSock y AnimeJS son muy difíciles de dividir.
Si su estilo de arte está fuertemente basado en vectores y tiene una herramienta de animación compatible con Lottie, es difícil ignorar el movimiento suave y la eficiencia de Lottie.
Si bien el uso de una biblioteca de animación en su aplicación web sin duda puede mejorar la interactividad, exagerar anula el propósito y, a menudo, confunde al usuario. Tenga cuidado y use las animaciones con criterio.
¿Utiliza bibliotecas de animación para sus proyectos? ¿Cuáles son tus bibliotecas de animación favoritas?
Esta historia se publicó originalmente en https://www.sitepoint.com/our-top-9-animation-libraries/
1654893300
今日は、UIデザイン作業に最適な9つの無料の適切にコーディングされたアニメーションライブラリを実行します。それらの長所と短所、およびそれぞれをいつ選択するかについて説明します。
フロントエンドWebデザインは、過去10年間で革命を遂げてきました。後期の2000年代には、私たちのほとんどはまだ静的な雑誌のレイアウトを設計していました。今日、私たちは何千ものサイズ変更、調整、可動部品を備えた「デジタルマシン」を構築しています。
簡単に言うと、優れたUIデザイナーは、優れたアニメーターである必要があります。Webアニメーションの手法と技術をしっかりと理解している必要があります。
各ライブラリは、「コードの第一人者」の開発者としてではなく、コードに精通したUIデザイナーの観点から見ていることに注意してください。これらのライブラリのいくつかは純粋なCSSです。その他はJavaScriptですが、有用であるために基本的なHTML/CSSおよび/またはJavaScriptの理解以上のものを必要とするものはありません。
明確にしましょう。Lottiejsは、このリストの他の8つとは非常に異なるタイプのアニメーションライブラリです。それにもかかわらず、UI/UXデザイナーはそれを無視する余裕はないと思います。
Lottieアニメーションの作成は、ビデオ作品の作成に似ています。'Lottie-ready'JSONファイルをエクスポートできるサードパーティのアニメーションツールが必要になります。実際、Lottie形式は、AdobeAfterEffectsアニメーションがWebおよびモバイルで効率的に機能するように特別に設計されています。これにより、Lottieアニメーションは高速で効率的で、スクリプトが簡単になり、多くの場合非常に美しくなります。
LottieはAdobeAfterEffectsの拡張機能として考案されましたが、Lottieアニメーションを作成するための(おそらくより優れた)「Lottieネイティブ」の代替手段がたくさんあります。これらには以下が含まれます:
Lottieは、それぞれWeb、iOS、Android用に最適化された個別の「アニメーションプレーヤー」を使用しています。LottieコードベースはAirBnbによって開発および保守されており、その背後で非常に熱心で情熱的なコミュニティが成長しています。
Animate.cssは、最小で最も使いやすいCSSアニメーションライブラリの1つです。2013年のリリース以来、洗練され、効率的で、手入れが行き届いています。
Animateライブラリをプロジェクトに適用するのは、CSSをリンクし、必要なCSSクラスをHTML要素に追加するのと同じくらい簡単です。もちろん、必要に応じて、jQueryまたはvanillaJSを使用して特定のイベントのアニメーションをトリガーすることもできます。
これを書いている時点では、それは今でも最も人気があり広く使用されているCSSアニメーションライブラリの1つであり、その縮小されたファイルはモバイルWebサイトにも含めるのに十分小さいです。
Animate.cssはまだ活発に開発中です。CSSカスタムプロパティ(別名CSS変数)をサポートするバージョン4に注意してください。これは最もシンプルで堅牢なアニメーションライブラリの1つであり、どのプロジェクトでもこれを使用することを躊躇しません。
GreenSock(またはGSAP – GreenSock Animation Platform)は、Webアニメーションのスイスアーミーナイフです。スムーズに実行される洗練された洗練されたアニメーションには、GSAPが理想的です。DOM要素からSVGまで、あらゆるものをアニメーション化できます。そのエコシステムには、SVGのモーフィング、SVGストロークの描画、スクロール機能、テキストのスクランブルなど、あらゆる種類の楽しいことを実行できるすばらしいプラグインが含まれています。高速でクロスブラウザ互換であり、構文は単純で直感的です。
GSAPはモジュール式であるため、プロジェクトに必要なライブラリの部分を選択できます。これは、ファイルサイズを制御するのに最適です。
優れたドキュメントとコミュニティサポートを備えた強力で直感的なものをお探しの場合は、次のプロジェクトでこのアニメーションライブラリを試してみることをお勧めします。あなたは熱狂的になります。
AnimeJSは私たちのリストに新しく追加されたものですが、作成以来、非常に多くのコンバージョンを獲得しています。それは信じられないほど用途が広く強力であり、HTMLゲームアニメーションを強化するのに場違いではありません。唯一の本当の質問は、「単純なWebアプリにとってはやり過ぎですか?」
多分。しかし、それはまた速く、小さく、そして比較的簡単に学ぶことができるので、それの欠点を見つけるのは難しいです。
AnimeJSは、「シンプルでありながら強力なAPIを備えた軽量のJavaScriptアニメーションライブラリ」と呼ばれています。これは、CSSプロパティ、SVG、DOM属性、およびJavaScriptオブジェクトで機能します。めっちゃすごい。
このプロジェクトはGitHubで入手できます。
最も印象的なことに、Anime.JSには、美しいアプリ環境でHTML、JavaScriptコード、および実用的な例を示す見事な「ドキュメント」があります。
つまり、JavaScriptアニメーションソリューションに慣れている場合、AnimeJSを無視する理由を見つけるのは困難です。
Magic Animationsは、利用可能な最も印象的なアニメーションライブラリの1つです。さまざまなアニメーションがあり、その多くはこのライブラリに非常に固有のものです。Animate.cssと同様に、CSSファイルをインポートするだけでMagicを実装できます。jQueryを使用してアニメーションを実装することもできます。このプロジェクトは、特にクールなデモアプリケーションを提供します。
Magic AnimationのファイルサイズはAnimate.cssに比べて適度であり、魔法の効果、愚かな効果、爆弾の効果などの特徴的なアニメーションで知られています。
少し変わったものを探しているなら、それを探してください。がっかりすることはありません。
Zdogは、DavidDeSandroによる3Dデザインとアニメーションを作成するためのJavaScriptライブラリです。その助けを借りて、<canvas>
要素またはSVGを使用してデザインを描画し、滑らかな3D効果を備えた滑らかなアニメーションでそれらを生き生きとさせることができます。
JavaScriptに精通している場合は、Zdogの基本をすぐに学ぶことができます。JavaScriptには、わかりやすい宣言型API、優れたドキュメント、および豊富な学習リソースがあります。SitePointでZdogの紹介をご覧ください。
CSShakeは、ボックスに記載されている内容を正確に提供します。これは、Webページ内の要素をシェイクするために特別に設計されたCSSライブラリです。ご想像のとおり、Webコンポーネントを振るにはさまざまなバリエーションがあります。
Appleは、ユーザーが誤った応答を入力したときにUI要素(ダイアログ、モーダル、またはテキストボックス)を激しく振るというUIの傾向を普及させました。これは、頭を振る人を模倣したものです。CSShakeは、さまざまな興味深い「シェイク」アニメーションを提供し、このライブラリにはバリエーションが不足していません。
Hover.cssは、Webサイトのボタンやその他のUI要素で使用するために設計されたCSSアニメーションライブラリです。他の多くの巧妙に作成されたアニメーションとともに、それは本当に素晴らしい2Dトランジションを持っています。
Hover.cssは、大きくて複雑なページアニメーションではなく、ボタン、ロゴ、SVGコンポーネント、注目の画像などの個別のページ要素をアニメーション化するのに最適です。間違いなく、その最も注目すべきアニメーション効果は、独特の吹き出しとカールです。
私たちの最終的なライブラリは、そのユニークなアプローチで興味深いものです。AniJSは、単純な「文のような」構造で要素にアニメーションを追加できるアニメーションライブラリです。次の形式を取ります。
クリックすると、正方形上で、.container -boxにアニメーション化されたウォブルを実行します
<div data-anijs="if: click, do: flipInY, to: .container-box"></div>
JavaScriptにあまり詳しくない場合は、JSで振り付けられた動きに足を踏み入れるのに最適な方法かもしれません。
AniJSは、機能を考慮した非常に妥当なサイズのライブラリです。実装に使用する形式は非常に独創的で、他のアニメーションライブラリ(他の多くの人が型にはまらないと感じるかもしれません)と比較して異なります。
それでも、このライブラリは、プロジェクトで少なくとも1回は試してみる価値があります。
プロジェクトに実装される準備ができて待機している多くのアニメーションライブラリがあります。上記にリストされているものは、洗練と安定性の最良の組み合わせを備えたいくつかです。
実装が簡単で、十分にテストされたCSSソリューションを探している場合、Animate.cssは、おそらく最も用途の広い「バングフォーバック」オプションです。
オンラインゲーム、シミュレーター、モデル、およびその他の高度なアプリケーションを強化するための、より完全で強力なJavaScriptベースを探している場合、GreenSockとAnimeJSを分割するのは非常に困難です。
アートスタイルが強力なベクターベースであり、Lottie対応のアニメーションツールを使用している場合、Lottieのスムーズな動きと効率は無視できません。
Webアプリケーションでアニメーションライブラリを使用すると、対話性を確実に向上させることができますが、それをやりすぎると、目的が損なわれ、ユーザーを混乱させることがよくあります。注意して、アニメーションを慎重に使用してください。
プロジェクトにアニメーションライブラリを使用していますか?お気に入りのアニメーションライブラリは何ですか?
このストーリーは、もともとhttps://www.sitepoint.com/our-top-9-animation-libraries/で公開されました
1654853760
lzma-native
Node.js interface to the native liblzma compression library (.xz file format, among others)
This package provides interfaces for compression and decompression of .xz
(and legacy .lzma
) files, both stream-based and string-based.
Simply install lzma-native
via npm:
$ npm install --save lzma-native
Note: As of version 1.0.0, this module provides pre-built binaries for multiple Node.js versions and all major OS using node-pre-gyp, so for 99 % of users no compiler toolchain is necessary. Please create an issue here if you have any trouble installing this module.
Note: lzma-native@2.x
requires a Node version >= 4. If you want to support Node 0.10
or 0.12
, you can feel free to use lzma-native@1.x
.
If you don’t have any fancy requirements, using this library is quite simple:
var lzma = require('lzma-native');
var compressor = lzma.createCompressor();
var input = fs.createReadStream('README.md');
var output = fs.createWriteStream('README.md.xz');
input.pipe(compressor).pipe(output);
For decompression, you can simply use lzma.createDecompressor()
.
Both functions return a stream where you can pipe your input in and read your (de)compressed output from.
If you want your input/output to be Buffers (strings will be accepted as input), this even gets a little simpler:
lzma.compress('Banana', function(result) {
console.log(result); // <Buffer fd 37 7a 58 5a 00 00 01 69 22 de 36 02 00 21 ...>
});
Again, replace lzma.compress
with lzma.decompress
and you’ll get the inverse transformation.
lzma.compress()
and lzma.decompress()
will return promises and you don’t need to provide any kind of callback (Example code).
Apart from the API described here, lzma-native
implements the APIs of the following other LZMA libraries so you can use it nearly as a drop-in replacement:
lzma.Compressor
and lzma.Decompressor
lzma.LZMA().compress
and lzma.LZMA().decompress
, though without actual support for progress functions and returning Buffer
objects instead of integer arrays. (This produces output in the .lzma
file format, not the .xz
format!)Since version 1.5.0
, lzma-native supports liblzma’s built-in multi-threading encoding capabilities. To make use of them, set the threads
option to an integer value: lzma.createCompressor({ threads: n });
. You can use value of 0
to use the number of processor cores. This option is only available for the easyEncoder
(the default) and streamEncoder
encoders.
Note that, by default, encoding will take place in Node’s libuv thread pool regardless of this option, and setting it when multiple encoders are running is likely to affect performance negatively.
Encoding strings and Buffer objects
compress()
– Compress strings and Buffersdecompress()
– Decompress strings and BuffersLZMA().compress()
(LZMA-JS compatibility)LZMA().decompress()
(LZMA-JS compatibility)createCompressor()
– Compress streamscreateDecompressor()
– Decompress streamscreateStream()
– (De-)Compression with advanced optionsCompressor()
(node-xz compatibility)Decompressor()
(node-xz compatibility)isXZ()
– Test Buffer for .xz
file formatparseFileIndex()
– Read .xz
file metadataparseFileIndexFD()
– Read .xz
metadata from a file descriptorcrc32()
– Calculate CRC32 checksumcheckSize()
– Return required size for specific checksum typeeasyDecoderMemusage()
– Expected memory usageeasyEncoderMemusage()
– Expected memory usagerawDecoderMemusage()
– Expected memory usagerawEncoderMemusage()
– Expected memory usageversionString()
– Native library version stringversionNumber()
– Native library numerical version identifierlzma.compress()
, lzma.decompress()
lzma.compress(string, [opt, ]on_finish)
lzma.decompress(string, [opt, ]on_finish)
Param | Type | Description |
---|---|---|
string | Buffer / String | Any string or buffer to be (de)compressed (that can be passed to stream.end(…) ) |
[opt ] | Options / int | Optional. See options |
on_finish | Callback | Will be invoked with the resulting Buffer as the first parameter when encoding is finished, and as on_finish(null, err) in case of an error. |
These methods will also return a promise that you can use directly.
Example code:
lzma.compress('Bananas', 6, function(result) {
lzma.decompress(result, function(decompressedResult) {
assert.equal(decompressedResult.toString(), 'Bananas');
});
});
Example code for promises:
lzma.compress('Bananas', 6).then(function(result) {
return lzma.decompress(result);
}).then(function(decompressedResult) {
assert.equal(decompressedResult.toString(), 'Bananas');
}).catch(function(err) {
// ...
});
lzma.LZMA().compress()
, lzma.LZMA().decompress()
lzma.LZMA().compress(string, mode, on_finish[, on_progress])
lzma.LZMA().decompress(string, on_finish[, on_progress])
(Compatibility; See LZMA-JS for the original specs.)
Note that the result of compression is in the older LZMA1 format (.lzma
files). This is different from the more universally used LZMA2 format (.xz
files) and you will have to take care of possible compatibility issues with systems expecting .xz
files.
Param | Type | Description |
---|---|---|
string | Buffer / String / Array | Any string, buffer, or array of integers or typed integers (e.g. Uint8Array ) |
mode | int | A number between 0 and 9, indicating compression level |
on_finish | Callback | Will be invoked with the resulting Buffer as the first parameter when encoding is finished, and as on_finish(null, err) in case of an error. |
on_progress | Callback | Indicates progress by passing a number in [0.0, 1.0]. Currently, this package only invokes the callback with 0.0 and 1.0. |
These methods will also return a promise that you can use directly.
This does not work exactly as described in the original LZMA-JS specification:
Buffer
objects, not integer arrays. This just makes a lot more sense in a Node.js environment.on_progress
is currently only called with 0.0
and 1.0
.Example code:
lzma.LZMA().compress('Bananas', 4, function(result) {
lzma.LZMA().decompress(result, function(decompressedResult) {
assert.equal(decompressedResult.toString(), 'Bananas');
});
});
For an example using promises, see compress()
.
lzma.createCompressor()
, lzma.createDecompressor()
lzma.createCompressor([options])
lzma.createDecompressor([options])
Param | Type | Description |
---|---|---|
[options ] | Options / int | Optional. See options |
Return a duplex stream, i.e. a both readable and writable stream. Input will be read, (de)compressed and written out. You can use this to pipe input through this stream, i.e. to mimick the xz
command line util, you can write:
var compressor = lzma.createCompressor();
process.stdin.pipe(compressor).pipe(process.stdout);
The output of compression will be in LZMA2 format (.xz
files), while decompression will accept either format via automatic detection.
lzma.Compressor()
, lzma.Decompressor()
lzma.Compressor([preset], [options])
lzma.Decompressor([options])
(Compatibility; See node-xz for the original specs.)
These methods handle the .xz
file format.
Param | Type | Description |
---|---|---|
[preset ] | int | Optional. See options.preset |
[options ] | Options | Optional. See options |
Return a duplex stream, i.e. a both readable and writable stream. Input will be read, (de)compressed and written out. You can use this to pipe input through this stream, i.e. to mimick the xz
command line util, you can write:
var compressor = lzma.Compressor();
process.stdin.pipe(compressor).pipe(process.stdout);
lzma.createStream()
lzma.createStream(coder, options)
Param | Type | Description |
---|---|---|
[coder ] | string | Any of the supported coder names, e.g. "easyEncoder" (default) or "autoDecoder" . |
[options ] | Options / int | Optional. See options |
Return a duplex stream for (de-)compression. You can use this to pipe input through this stream.
The available coders are (the most interesting ones first):
easyEncoder
Standard LZMA2 (.xz
file format) encoder. Supports options.preset
and options.check
options.autoDecoder
Standard LZMA1/2 (both .xz
and .lzma
) decoder with auto detection of file format. Supports options.memlimit
and options.flags
options.aloneEncoder
Encoder which only uses the legacy .lzma
format. Supports the whole range of LZMA options.Less likely to be of interest to you, but also available:
aloneDecoder
Decoder which only uses the legacy .lzma
format. Supports the options.memlimit
option.rawEncoder
Custom encoder corresponding to lzma_raw_encoder
(See the native library docs for details). Supports the options.filters
option.rawDecoder
Custom decoder corresponding to lzma_raw_decoder
(See the native library docs for details). Supports the options.filters
option.streamEncoder
Custom encoder corresponding to lzma_stream_encoder
(See the native library docs for details). Supports options.filters
and options.check
options.streamDecoder
Custom decoder corresponding to lzma_stream_decoder
(See the native library docs for details). Supports options.memlimit
and options.flags
options.Option name | Type | Description |
---|---|---|
check | check | Any of lzma.CHECK_CRC32 , lzma.CHECK_CRC64 , lzma.CHECK_NONE , lzma.CHECK_SHA256 |
memlimit | float | A memory limit for (de-)compression in bytes |
preset | int | A number from 0 to 9, 0 being the fastest and weakest compression, 9 the slowest and highest compression level. (Please also see the [xz(1) manpage][xz-manpage] for notes – don’t just blindly use 9!) You can also OR this with lzma.PRESET_EXTREME (the -e option to the xz command line utility). |
flags | int | A bitwise or of lzma.LZMA_TELL_NO_CHECK , lzma.LZMA_TELL_UNSUPPORTED_CHECK , lzma.LZMA_TELL_ANY_CHECK , lzma.LZMA_CONCATENATED |
synchronous | bool | If true, forces synchronous coding (i.e. no usage of threading) |
bufsize | int | The default size for allocated buffers |
threads | int | Set to an integer to use liblzma’s multi-threading support. 0 will choose the number of CPU cores. |
blockSize | int | Maximum uncompressed size of a block in multi-threading mode |
timeout | int | Timeout for a single encoding operation in multi-threading mode |
options.filters
can, if the coder supports it, be an array of filter objects, each with the following properties:
.id
Any of lzma.FILTERS_MAX
, lzma.FILTER_ARM
, lzma.FILTER_ARMTHUMB
, lzma.FILTER_IA64
, lzma.FILTER_POWERPC
, lzma.FILTER_SPARC
, lzma.FILTER_X86
or lzma.FILTER_DELTA
, lzma.FILTER_LZMA1
, lzma.FILTER_LZMA2
The delta filter supports the additional option .dist
for a distance between bytes (see the xz(1) manpage).
The LZMA filter supports the additional options .dict_size
, .lp
, .lc
, pb
, .mode
, nice_len
, .mf
, .depth
and .preset
. See the xz(1) manpage for meaning of these parameters and additional information.
lzma.crc32()
lzma.crc32(input[, encoding[, previous]])
Compute the CRC32 checksum of a Buffer or string.
Param | Type | Description |
---|---|---|
input | string / Buffer | Any string or Buffer. |
[encoding ] | string | Optional. If input is a string, an encoding to use when converting into binary. |
[previous ] | int | The result of a previous CRC32 calculation so that you can compute the checksum per each chunk |
Example usage:
lzma.crc32('Banana') // => 69690105
lzma.checkSize()
lzma.checkSize(check)
Return the byte size of a check sum.
Param | Type | Description |
---|---|---|
check | check | Any supported check constant. |
Example usage:
lzma.checkSize(lzma.CHECK_SHA256) // => 16
lzma.checkSize(lzma.CHECK_CRC32) // => 4
lzma.easyDecoderMemusage()
lzma.easyDecoderMemusage(preset)
Returns the approximate memory usage when decoding using easyDecoder for a given preset.
Param | Type | Description |
---|---|---|
preset | preset | A compression level from 0 to 9 |
Example usage:
lzma.easyDecoderMemusage(6) // => 8454192
lzma.easyEncoderMemusage()
lzma.easyEncoderMemusage(preset)
Returns the approximate memory usage when encoding using easyEncoder for a given preset.
Param | Type | Description |
---|---|---|
preset | preset | A compression level from 0 to 9 |
Example usage:
lzma.easyEncoderMemusage(6) // => 97620499
lzma.rawDecoderMemusage()
lzma.rawDecoderMemusage(filters)
Returns the approximate memory usage when decoding using rawDecoder for a given filter list.
Param | Type | Description |
---|---|---|
filters | array | An array of filters |
lzma.rawEncoderMemusage()
lzma.rawEncoderMemusage(filters)
Returns the approximate memory usage when encoding using rawEncoder for a given filter list.
Param | Type | Description |
---|---|---|
filters | array | An array of filters |
lzma.versionString()
lzma.versionString()
Returns the version of the underlying C library.
Example usage:
lzma.versionString() // => '5.2.3'
lzma.versionNumber()
lzma.versionNumber()
Returns the version of the underlying C library.
Example usage:
lzma.versionNumber() // => 50020012
lzma.isXZ()
lzma.isXZ(input)
Tells whether an input buffer is an XZ file (.xz
, LZMA2 format) using the file format’s magic number. This is not a complete test, i.e. the data following the file header may still be invalid in some way.
Param | Type | Description |
---|---|---|
input | string / Buffer | Any string or Buffer (integer arrays accepted). |
Example usage:
lzma.isXZ(fs.readFileSync('test/hamlet.txt.xz')); // => true
lzma.isXZ(fs.readFileSync('test/hamlet.txt.lzma')); // => false
lzma.isXZ('Banana'); // => false
(The magic number of XZ files is hex fd 37 7a 58 5a 00
at position 0.)
lzma.parseFileIndex()
lzma.parseFileIndex(options[, callback])
Read .xz
file metadata.
options.fileSize
needs to be an integer indicating the size of the file being inspected, e.g. obtained by fs.stat()
.
options.read(count, offset, cb)
must be a function that reads count
bytes from the underlying file, starting at position offset
. If that is not possible, e.g. because the file does not have enough bytes, the file should be considered corrupt. On success, cb
should be called with a Buffer
containing the read data. cb
can be invoked as cb(err, buffer)
, in which case err
will be passed along to the original callback
argument when set.
callback
will be called with err
and info
as its arguments.
If no callback
is provided, options.read()
must work synchronously and the file info will be returned from lzma.parseFileIndex()
.
Example usage:
fs.readFile('test/hamlet.txt.xz', function(err, content) {
// handle error
lzma.parseFileIndex({
fileSize: content.length,
read: function(count, offset, cb) {
cb(content.slice(offset, offset + count));
}
}, function(err, info) {
// handle error
// do something with e.g. info.uncompressedSize
});
});
lzma.parseFileIndexFD()
lzma.parseFileIndexFD(fd, callback)
Read .xz
metadata from a file descriptor.
This is like parseFileIndex()
, but lets you pass an file descriptor in fd
. The file will be inspected using fs.stat()
and fs.read()
. The file descriptor will not be opened or closed by this call.
Example usage:
fs.open('test/hamlet.txt.xz', 'r', function(err, fd) {
// handle error
lzma.parseFileIndexFD(fd, function(err, info) {
// handle error
// do something with e.g. info.uncompressedSize
fs.close(fd, function(err) { /* handle error */ });
});
});
This package includes the native C library, so there is no need to install it separately.
Other implementations of the LZMA algorithms for node.js and/or web clients include:
Note that LZMA has been designed to have much faster decompression than compression, which is something you may want to take into account when choosing an compression algorithm for large files. Almost always, LZMA achieves higher compression ratios than other algorithms, though.
Initial development of this project was financially supported by Tradity.
Author: Addaleax
Source Code: https://github.com/addaleax/lzma-native
License: MIT license
1654508220
Mojang's Yggdrasil authentication for Dart.
Add this as dependency in your pubspec.yaml
...
dependencies:
mcauthlib: (version goes here)
...
Run this command:
With Dart:
$ dart pub add mcauthlib
With Flutter:
$ flutter pub add mcauthlib
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get
):
dependencies:
mcauthlib: ^1.0.0
Alternatively, your editor might support dart pub get
or flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:mcauthlib/mcauthlib.dart';
example/mcauthlib_example.dart
import 'package:mcauthlib/mcauthlib.dart';
void main() async {
//This example is how to authenticate with this library.
//First create MojangAuth instance.
final auth = MojangAuth();
//Then, create User with authtype keyword.
//The first parameter is email and the second one is password.
var user = User.authType("lorem@ipsum.com", "dolorsitamet");
//await until authentication return map with
//Response type, clientToken, accessToken, player uuid.
var result = await auth.authenticate(user);
//If a request was successful the response type should be
//ResponseType.success
//if not, it will return ResponseType.failure with error Type.
if(result['responseType'] == ResponseType.success){
user.clientToken = result['clientToken'];
user.accessToken = result['accessToken'];
}
}
https://wiki.vg/Authentication
Author: GiftShower
Source Code: https://github.com/GiftShower/mcauthlib
License: GPL-3.0 license
1654459020
A package for creating an awesome progress bar in the terminal. Handy while developing a CLI or a desktop utility in dart.
Options:
total
: Total number of stepsdesc
: Simple text shown before the bar (optional)space
: Character denoting empty space (default : '.')fill
: Character denoting filled space (default : '█')time
: Toggle timing mode (default : false)percentage
: Toggle percentage display (default : false)scale
: Scale of the bar relative to width (between: 0 and 1, default: 0.5, Irrelavant if width is specified)width
: Width of the bar (If not specified, it will be automatically calculated using the terminal width and scale)Code:
final p = FillingBar(desc: "Loading", total: 1000, time: true, percentage:true);
for (var i = 0; i < 1000; i++) {
p.increment();
sleep(Duration(milliseconds: 10));
}
Result:
Loading : ████████████████████████████████████████.................... 673/1000 67.3% [ 0:00:13.28 / 0:00:06.45 ]
Run this command:
With Dart:
$ dart pub add console_bars
With Flutter:
$ flutter pub add console_bars
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get
):
dependencies:
console_bars: ^1.0.4
Alternatively, your editor might support dart pub get
or flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:console_bars/console_bars.dart';
example/console_bars_example.dart
import 'dart:io';
import 'package:console_bars/console_bars.dart';
void main(List<String> args) {
// A bar that looks like
//
// Loading : ████████████████████████████████████████.................... 673/1000 67.3% [ 0:00:13.28 / 0:00:06.45 ]
//
final p = FillingBar(
desc: "Loading", total: 1000, time: true, percentage: true, scale: 0.2);
for (var i = 0; i < 1000; i++) {
p.increment();
sleep(Duration(milliseconds: 10));
}
print("\nDone");
}
Author: RohitEdathil
Source Code: https://github.com/RohitEdathil/ConsoleBars
License: GPL-3.0 license
1654406640
Majority Judgment for Dart
This Dart package helps to resolve polls using Majority Judgment.
dart test
)
import 'package:majority_judgment/majority_judgment.dart';
void main() {
final pollTally = PollTally([
[1, 2, 4, 2, 1], // Proposal A, from "worst" grade to "best" grade
[1, 2, 4, 1, 2], // Proposal B
[3, 1, 3, 1, 2], // Proposal C
[1, 2, 4, 2, 1], // Proposal D (equal to A)
]);
final mj = MajorityJudgmentResolver();
final result = mj.resolve(pollTally);
print(result.proposalsResults.map((ProposalResult p) => p.rank));
//> (2, 1, 4, 2)
print(result.sortedProposalsResults.map((ProposalResult p) => p.index));
//> (1, 0, 3, 2)
}
Run this command:
With Dart:
$ dart pub add majority_judgment
With Flutter:
$ flutter pub add majority_judgment
This will add a line like this to your package's pubspec.yaml (and run an implicit dart pub get
):
dependencies:
majority_judgment: ^0.2.0
Alternatively, your editor might support dart pub get
or flutter pub get
. Check the docs for your editor to learn more.
Now in your Dart code, you can use:
import 'package:majority_judgment/majority_judgment.dart';
example/example.dart
// ignore_for_file: avoid_print
import 'package:majority_judgment/majority_judgment.dart';
void main() {
final pollTally = PollTally([
[1, 2, 4, 2, 1], // Proposal A, from "worst" grade to "best" grade
[1, 2, 4, 1, 2], // Proposal B
[3, 1, 3, 1, 2], // Proposal C
[1, 2, 4, 2, 1], // Proposal D (equal to A)
]);
//pollTally.balanceWithStaticDefault(); // use a balancer if necessary
final mj = MajorityJudgmentResolver();
final result = mj.resolve(pollTally);
print(result.proposalsResults.map((ProposalResult p) => p.rank));
//> (2, 1, 4, 2)
print(result.sortedProposalsResults.map((ProposalResult p) => p.index));
//> (1, 0, 3, 2)
}
Usual git flow: clone, tinker, request a merge.
Author: MieuxVoter
Source Code: https://github.com/MieuxVoter/majority-judgment-library-dart
License: MIT license
1654347180
Bellt
Simple Golang HTTP router
Bellt Package implements a request router with the aim of managing controller actions based on fixed and parameterized routes.
The project so far has the following functionalities:
Install
To get Bellt
> Go CLI
go get -u github.com/GuilhermeCaruso/bellt
> Go DEP
dep ensure -add github.com/GuilhermeCaruso/bellt
> Govendor
govendor fetch github.com/GuilhermeCaruso/bellt
Guide
To initialize our router
var router = bellt.NewRouter()
package main
import (
"fmt"
"log"
"net/http"
"github.com/GuilhermeCaruso/bellt"
)
func main() {
router := bellt.NewRouter()
log.Fatal(http.ListenAndServe(":8080", nil))
}
HandleFunc function responsible for initializing a common route or built through the Router. All non-grouped routes must be initialized by this method.
/*
[path] - Endpoint string
[handlerFunc] - Function that will be called on the request
[methods] - Slice for endpoint methods ("GET", "POST", "PUT", "DELETE")
*/
router.HandleFunc(path, handlerFunc, methods)
package main
import (
"fmt"
"log"
"net/http"
"github.com/GuilhermeCaruso/bellt"
)
func main() {
router := bellt.NewRouter()
router.HandleFunc("/bellt", belltHandler, "GET")
log.Fatal(http.ListenAndServe(":8080", nil))
}
func belltHandle(w http.ResponseWriter, r *http.Request){
w.WriteHeader(http.StatusOK)
w.Write([]byte("Simple Golang HTTP router")
}
HandleGroup is responsible for creating a group of routes. The main path can be set for all other routes.
/*
[mainPath] - Main route used in all subr-outes
[subHandleFunc] - SubHandleFunc function responsiblefor initializing a common route or
built through the Router. All grouped routes must be initialized by this method
*/
router.HandleGroup(mainPath, ...SubHandleFunc)
SubHandleFunc is responsible for initializing a common or built route. Its use must be made within the scope of the HandleGroup method, where the main path will be declared.
/*
[path] - Endpoint string
[handlerFunc] - Function that will be called on the request
[methods] - Slice for endpoint methods ("GET", "POST", "PUT", "DELETE")
*/
router.SubHandleFunc(path, handlerFunc, methods)
package main
import (
"fmt"
"log"
"net/http"
"github.com/GuilhermeCaruso/bellt"
)
func main() {
router := bellt.NewRouter()
router.HandleGroup("/api",
router.SubHandleFunc("/bellt", belltHandle, "GET"),
router.SubHandleFunc("/check", checkHandle, "GET"),
)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func belltHandle(w http.ResponseWriter, r *http.Request){
w.WriteHeader(http.StatusOK)
w.Write([]byte("Simple Golang HTTP router")
}
func checkHandle(w http.ResponseWriter, r *http.Request){
w.WriteHeader(http.StatusOK)
w.Write([]byte("Ok!")
}
The declaration of middlewares in HandleFunc or SubHandleFunc should be done using the Use method
/*
handlerFunc - Function that will be called on the request
middlewareList - Slice of middleware that will be used in the request (Middleware)
*/
bellt.Use(handlerFunc, ...middlewareList)
The middleware type has a following signature
type Middleware func(http.HandlerFunc) http.HandlerFunc
Applying middlewares to routes
package main
import (
"fmt"
"log"
"net/http"
"github.com/GuilhermeCaruso/bellt"
)
func main() {
router := bellt.NewRouter()
router.HandleFunc("/hello", bellt.Use(
exampleHandler,
middlewareOne,
middlewareTwo,
), "GET")
router.HandleGroup("/api",
router.SubHandleFunc("/hello", bellt.Use(
exampleHandler,
middlewareOne,
middlewareTwo,
), "GET"),
)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func exampleHandler(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
w.Write([]byte(`Hello Middleware!`))
}
func middlewareOne(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Step One")
next.ServeHTTP(w, r)
}
}
func middlewareTwo(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Step Two")
next.ServeHTTP(w, r)
}
}
Route parameters must be passed using {}
as scope limiter
router.HandleFunc("/hello/{name}", handlerFunc, "GET")
router.HandleGroup("/api",
SubHandleFunc("/item/{id}", handlerFunc, "GET")
)
RouteVariables used to capture and store parameters passed to built routes.
Need to pass the *Request of the HandlerFunc used in the HandleFunc method.
/*
r = *Request of the HandlerFunc
*/
rv := bellt.RouteVariables(r)
The declaration must be made within the HandlerFunc
func exampleHandler(w http.ResponseWriter, r *http.Request) {
rv := bellt.RouteVariables(r)
/*[...]*/
w.WriteHeader(http.StatusOK)
w.Write([]byte("Hello!"))
}
GetVar returns the parameter value of the route
/*
r = *Request of the HandlerFunc
param = Parameter name string
*/
rv := bellt.RouteVariables(r)
rv.GetVar(param)
func exampleHandler(w http.ResponseWriter, r *http.Request) {
rv := bellt.RouteVariables(r)
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf(`Hello %v gopher!`, rv.GetVar("color")))))
}
The complete implementation of parameterized routes should look like this:
package main
import (
"fmt"
"log"
"net/http"
"github.com/GuilhermeCaruso/bellt"
)
func main() {
router := bellt.NewRouter()
router.HandleFunc("/contact/{id}/{user}", exampleHandler, "GET")
router.HandleGroup("/api",
router.SubHandleFunc("/check/{id}/{user}", exampleHandler, "GET"),
)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func exampleHandler(w http.ResponseWriter, r *http.Request) {
rv := bellt.RouteVariables(r)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf(`{"id": %v, "user": %v}`, rv.GetVar("user"), rv.GetVar("id"))))
}
Full Example
package main
import (
"fmt"
"log"
"net/http"
"github.com/GuilhermeCaruso/bellt"
)
func main() {
router := bellt.NewRouter()
router.HandleFunc("/contact/{id}/{user}", bellt.Use(
exampleHandler,
middlewareOne,
middlewareTwo,
), "GET")
router.HandleFunc("/contact", bellt.Use(
exampleNewHandler,
middlewareOne,
middlewareTwo,
), "GET")
router.HandleGroup("/api",
router.SubHandleFunc("/check", bellt.Use(
exampleNewHandler,
middlewareOne,
middlewareTwo,
), "GET"),
router.SubHandleFunc("/check/{id}/{user}", bellt.Use(
exampleHandler,
middlewareOne,
middlewareTwo,
), "GET"),
)
log.Fatal(http.ListenAndServe(":8080", nil))
}
func exampleHandler(w http.ResponseWriter, r *http.Request) {
rv := bellt.RouteVariables(r)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(fmt.Sprintf(`{"id": %v, "user": %v}`, rv.GetVar("user"), rv.GetVar("id"))))
}
func exampleNewHandler(w http.ResponseWriter, r *http.Request) {
rv := bellt.RouteVariables(r)
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusOK)
w.Write([]byte(`{"msg": "Works"}`))
}
func middlewareOne(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Step One")
next.ServeHTTP(w, r)
}
}
func middlewareTwo(next http.HandlerFunc) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
fmt.Println("Step Two")
next.ServeHTTP(w, r)
}
}
Benchmark
Applying requisition performance tests, the following results were obtained, showing the initial potency of the Bellt package.
Presentation
Guilherme Caruso - Cabify- GolangSP Meetup 2 - 21/03/2019 - São Paulo /Brazil
Slides - Construindo Rotas Parametrizadas em GO
Video - GolangSP Meetup 2
Author: GuilhermeCaruso
Source Code: https://github.com/GuilhermeCaruso/bellt
License: MIT license